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:
authorAntonio Vazquez <blendergit@gmail.com>2019-10-02 14:15:37 +0300
committerAntonio Vazquez <blendergit@gmail.com>2019-10-02 14:15:37 +0300
commit386ba094988fc793f8e060d15438566e5e2d2cae (patch)
tree4cbde50b5d1d7a45c89ee99c29dd1b86d1d97b59 /source/blender
parent6129e20cec4639aebf335ff13b2ba0c59670662d (diff)
parentf97a64aa9b7b384f8221a1ef4f2eef9cde1238db (diff)
Merge branch 'master' into temp-gpencil-drw-engine
Conflicts: source/blender/draw/engines/gpencil/gpencil_engine.c
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/CMakeLists.txt4
-rw-r--r--source/blender/alembic/ABC_alembic.h5
-rw-r--r--source/blender/alembic/intern/abc_archive.cc20
-rw-r--r--source/blender/alembic/intern/abc_archive.h4
-rw-r--r--source/blender/alembic/intern/abc_curves.cc26
-rw-r--r--source/blender/alembic/intern/abc_customdata.cc34
-rw-r--r--source/blender/alembic/intern/abc_exporter.cc15
-rw-r--r--source/blender/alembic/intern/abc_exporter.h2
-rw-r--r--source/blender/alembic/intern/abc_hair.cc22
-rw-r--r--source/blender/alembic/intern/abc_mesh.cc69
-rw-r--r--source/blender/alembic/intern/abc_nurbs.cc14
-rw-r--r--source/blender/alembic/intern/abc_object.cc16
-rw-r--r--source/blender/alembic/intern/abc_transform.cc2
-rw-r--r--source/blender/alembic/intern/abc_util.cc8
-rw-r--r--source/blender/alembic/intern/alembic_capi.cc23
-rw-r--r--source/blender/avi/intern/avi_options.c4
-rw-r--r--source/blender/blendthumb/CMakeLists.txt38
-rw-r--r--source/blender/blendthumb/src/BlendThumb.def5
-rw-r--r--source/blender/blendthumb/src/BlendThumb.rc26
-rw-r--r--source/blender/blendthumb/src/BlenderThumb.cpp321
-rw-r--r--source/blender/blendthumb/src/Dll.cpp280
-rw-r--r--source/blender/blenfont/intern/blf.c36
-rw-r--r--source/blender/blenfont/intern/blf_font.c269
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c65
-rw-r--r--source/blender/blenfont/intern/blf_internal.h16
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h7
-rw-r--r--source/blender/blenfont/intern/blf_thumbs.c2
-rw-r--r--source/blender/blenkernel/BKE_action.h1
-rw-r--r--source/blender/blenkernel/BKE_animsys.h3
-rw-r--r--source/blender/blenkernel/BKE_armature.h1
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h4
-rw-r--r--source/blender/blenkernel/BKE_brush.h6
-rw-r--r--source/blender/blenkernel/BKE_callbacks.h84
-rw-r--r--source/blender/blenkernel/BKE_camera.h2
-rw-r--r--source/blender/blenkernel/BKE_collection.h6
-rw-r--r--source/blender/blenkernel/BKE_context.h4
-rw-r--r--source/blender/blenkernel/BKE_curve.h9
-rw-r--r--source/blender/blenkernel/BKE_editmesh.h5
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h3
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h18
-rw-r--r--source/blender/blenkernel/BKE_gpencil_modifier.h5
-rw-r--r--source/blender/blenkernel/BKE_layer.h5
-rw-r--r--source/blender/blenkernel/BKE_library.h3
-rw-r--r--source/blender/blenkernel/BKE_library_override.h8
-rw-r--r--source/blender/blenkernel/BKE_library_remap.h2
-rw-r--r--source/blender/blenkernel/BKE_material.h4
-rw-r--r--source/blender/blenkernel/BKE_mesh.h40
-rw-r--r--source/blender/blenkernel/BKE_mesh_remesh_voxel.h21
-rw-r--r--source/blender/blenkernel/BKE_mirror.h45
-rw-r--r--source/blender/blenkernel/BKE_multires.h4
-rw-r--r--source/blender/blenkernel/BKE_node.h24
-rw-r--r--source/blender/blenkernel/BKE_object.h14
-rw-r--r--source/blender/blenkernel/BKE_object_facemap.h5
-rw-r--r--source/blender/blenkernel/BKE_paint.h22
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h76
-rw-r--r--source/blender/blenkernel/BKE_scene.h3
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h27
-rw-r--r--source/blender/blenkernel/BKE_shrinkwrap.h10
-rw-r--r--source/blender/blenkernel/BKE_studiolight.h25
-rw-r--r--source/blender/blenkernel/BKE_subdiv.h2
-rw-r--r--source/blender/blenkernel/BKE_subdiv_ccg.h2
-rw-r--r--source/blender/blenkernel/BKE_subdiv_deform.h40
-rw-r--r--source/blender/blenkernel/BKE_subdiv_eval.h7
-rw-r--r--source/blender/blenkernel/BKE_subdiv_topology.h31
-rw-r--r--source/blender/blenkernel/CMakeLists.txt25
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c4
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c14
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c50
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c16
-rw-r--r--source/blender/blenkernel/intern/appdir.c2
-rw-r--r--source/blender/blenkernel/intern/armature.c114
-rw-r--r--source/blender/blenkernel/intern/blender.c4
-rw-r--r--source/blender/blenkernel/intern/brush.c693
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c2
-rw-r--r--source/blender/blenkernel/intern/cachefile.c2
-rw-r--r--source/blender/blenkernel/intern/callbacks.c (renamed from source/blender/blenlib/intern/callbacks.c)56
-rw-r--r--source/blender/blenkernel/intern/camera.c21
-rw-r--r--source/blender/blenkernel/intern/collection.c35
-rw-r--r--source/blender/blenkernel/intern/collision.c16
-rw-r--r--source/blender/blenkernel/intern/constraint.c238
-rw-r--r--source/blender/blenkernel/intern/context.c8
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c80
-rw-r--r--source/blender/blenkernel/intern/curve.c132
-rw-r--r--source/blender/blenkernel/intern/customdata.c150
-rw-r--r--source/blender/blenkernel/intern/editlattice.c31
-rw-r--r--source/blender/blenkernel/intern/editmesh.c21
-rw-r--r--source/blender/blenkernel/intern/fcurve.c90
-rw-r--r--source/blender/blenkernel/intern/gpencil.c500
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c23
-rw-r--r--source/blender/blenkernel/intern/icons.c10
-rw-r--r--source/blender/blenkernel/intern/image.c49
-rw-r--r--source/blender/blenkernel/intern/lattice.c6
-rw-r--r--source/blender/blenkernel/intern/layer.c137
-rw-r--r--source/blender/blenkernel/intern/library.c60
-rw-r--r--source/blender/blenkernel/intern/library_override.c117
-rw-r--r--source/blender/blenkernel/intern/library_remap.c12
-rw-r--r--source/blender/blenkernel/intern/light.c43
-rw-r--r--source/blender/blenkernel/intern/lightprobe.c15
-rw-r--r--source/blender/blenkernel/intern/linestyle.c37
-rw-r--r--source/blender/blenkernel/intern/material.c54
-rw-r--r--source/blender/blenkernel/intern/mball.c8
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c2
-rw-r--r--source/blender/blenkernel/intern/mesh.c203
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.c20
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c18
-rw-r--r--source/blender/blenkernel/intern/mesh_remesh_voxel.c259
-rw-r--r--source/blender/blenkernel/intern/mirror.c413
-rw-r--r--source/blender/blenkernel/intern/multires.c156
-rw-r--r--source/blender/blenkernel/intern/multires_reshape.c4
-rw-r--r--source/blender/blenkernel/intern/node.c94
-rw-r--r--source/blender/blenkernel/intern/object.c111
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c27
-rw-r--r--source/blender/blenkernel/intern/object_facemap.c38
-rw-r--r--source/blender/blenkernel/intern/object_update.c1
-rw-r--r--source/blender/blenkernel/intern/ocean.c58
-rw-r--r--source/blender/blenkernel/intern/packedFile.c17
-rw-r--r--source/blender/blenkernel/intern/paint.c44
-rw-r--r--source/blender/blenkernel/intern/particle.c16
-rw-r--r--source/blender/blenkernel/intern/particle_child.c6
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c12
-rw-r--r--source/blender/blenkernel/intern/particle_system.c6
-rw-r--r--source/blender/blenkernel/intern/pbvh.c583
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c21
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h5
-rw-r--r--source/blender/blenkernel/intern/pointcache.c61
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c2
-rw-r--r--source/blender/blenkernel/intern/scene.c441
-rw-r--r--source/blender/blenkernel/intern/screen.c19
-rw-r--r--source/blender/blenkernel/intern/seqcache.c104
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c24
-rw-r--r--source/blender/blenkernel/intern/seqprefetch.c453
-rw-r--r--source/blender/blenkernel/intern/sequencer.c36
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c62
-rw-r--r--source/blender/blenkernel/intern/smoke.c10
-rw-r--r--source/blender/blenkernel/intern/softbody.c10
-rw-r--r--source/blender/blenkernel/intern/speaker.c14
-rw-r--r--source/blender/blenkernel/intern/studiolight.c314
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg.c49
-rw-r--r--source/blender/blenkernel/intern/subdiv_converter_mesh.c2
-rw-r--r--source/blender/blenkernel/intern/subdiv_deform.c237
-rw-r--r--source/blender/blenkernel/intern/subdiv_eval.c23
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c23
-rw-r--r--source/blender/blenkernel/intern/subdiv_topology.c34
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c12
-rw-r--r--source/blender/blenkernel/intern/texture.c124
-rw-r--r--source/blender/blenkernel/intern/tracking.c6
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c20
-rw-r--r--source/blender/blenkernel/intern/tracking_solver.c2
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c18
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c6
-rw-r--r--source/blender/blenkernel/intern/undo_system.c2
-rw-r--r--source/blender/blenkernel/intern/world.c20
-rw-r--r--source/blender/blenlib/BLI_allocator.h129
-rw-r--r--source/blender/blenlib/BLI_array.h5
-rw-r--r--source/blender/blenlib/BLI_array_cxx.h197
-rw-r--r--source/blender/blenlib/BLI_array_ref.h426
-rw-r--r--source/blender/blenlib/BLI_callbacks.h73
-rw-r--r--source/blender/blenlib/BLI_fileops.h9
-rw-r--r--source/blender/blenlib/BLI_gsqueue.h6
-rw-r--r--source/blender/blenlib/BLI_hash_cxx.h111
-rw-r--r--source/blender/blenlib/BLI_index_range.h196
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h22
-rw-r--r--source/blender/blenlib/BLI_kdtree_impl.h10
-rw-r--r--source/blender/blenlib/BLI_listbase.h1
-rw-r--r--source/blender/blenlib/BLI_listbase_wrapper.h100
-rw-r--r--source/blender/blenlib/BLI_map.h724
-rw-r--r--source/blender/blenlib/BLI_math_base.h5
-rw-r--r--source/blender/blenlib/BLI_math_geom.h19
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h10
-rw-r--r--source/blender/blenlib/BLI_math_rotation.h2
-rw-r--r--source/blender/blenlib/BLI_math_vector.h5
-rw-r--r--source/blender/blenlib/BLI_memblock.h11
-rw-r--r--source/blender/blenlib/BLI_memory_utils_cxx.h84
-rw-r--r--source/blender/blenlib/BLI_open_addressing.h305
-rw-r--r--source/blender/blenlib/BLI_polyfill_2d_beautify.h5
-rw-r--r--source/blender/blenlib/BLI_set.h483
-rw-r--r--source/blender/blenlib/BLI_sort.h2
-rw-r--r--source/blender/blenlib/BLI_stack_cxx.h145
-rw-r--r--source/blender/blenlib/BLI_string.h2
-rw-r--r--source/blender/blenlib/BLI_string_map.h425
-rw-r--r--source/blender/blenlib/BLI_string_ref.h247
-rw-r--r--source/blender/blenlib/BLI_system.h9
-rw-r--r--source/blender/blenlib/BLI_temporary_allocator.h64
-rw-r--r--source/blender/blenlib/BLI_temporary_allocator_cxx.h38
-rw-r--r--source/blender/blenlib/BLI_timer.h4
-rw-r--r--source/blender/blenlib/BLI_vector.h607
-rw-r--r--source/blender/blenlib/BLI_vector_set.h425
-rw-r--r--source/blender/blenlib/CMakeLists.txt23
-rw-r--r--source/blender/blenlib/intern/BLI_filelist.c82
-rw-r--r--source/blender/blenlib/intern/BLI_index_range.cc60
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c212
-rw-r--r--source/blender/blenlib/intern/BLI_linklist.c2
-rw-r--r--source/blender/blenlib/intern/BLI_memblock.c23
-rw-r--r--source/blender/blenlib/intern/BLI_temporary_allocator.cc115
-rw-r--r--source/blender/blenlib/intern/BLI_timer.c39
-rw-r--r--source/blender/blenlib/intern/delaunay_2d.c136
-rw-r--r--source/blender/blenlib/intern/fileops.c5
-rw-r--r--source/blender/blenlib/intern/gsqueue.c216
-rw-r--r--source/blender/blenlib/intern/hash_md5.c4
-rw-r--r--source/blender/blenlib/intern/list_sort_impl.h4
-rw-r--r--source/blender/blenlib/intern/listbase.c23
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c24
-rw-r--r--source/blender/blenlib/intern/math_geom.c121
-rw-r--r--source/blender/blenlib/intern/math_interp.c4
-rw-r--r--source/blender/blenlib/intern/math_matrix.c144
-rw-r--r--source/blender/blenlib/intern/math_rotation.c44
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c34
-rw-r--r--source/blender/blenlib/intern/path_util.c8
-rw-r--r--source/blender/blenlib/intern/polyfill_2d_beautify.c34
-rw-r--r--source/blender/blenlib/intern/sort.c2
-rw-r--r--source/blender/blenlib/intern/stack.c15
-rw-r--r--source/blender/blenlib/intern/storage.c6
-rw-r--r--source/blender/blenlib/intern/string.c20
-rw-r--r--source/blender/blenlib/intern/string_utf8.c10
-rw-r--r--source/blender/blenlib/intern/system.c13
-rw-r--r--source/blender/blenlib/intern/task.c56
-rw-r--r--source/blender/blenlib/intern/voronoi_2d.c2
-rw-r--r--source/blender/blenlib/intern/winstuff.c12
-rw-r--r--source/blender/blenloader/intern/readfile.c198
-rw-r--r--source/blender/blenloader/intern/versioning_250.c3
-rw-r--r--source/blender/blenloader/intern/versioning_260.c11
-rw-r--r--source/blender/blenloader/intern/versioning_270.c8
-rw-r--r--source/blender/blenloader/intern/versioning_280.c227
-rw-r--r--source/blender/blenloader/intern/versioning_cycles.c480
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c138
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c2
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c20
-rw-r--r--source/blender/blenloader/intern/writefile.c25
-rw-r--r--source/blender/bmesh/CMakeLists.txt2
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c23
-rw-r--r--source/blender/bmesh/intern/bmesh_operators_private.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon_edgenet.c6
-rw-r--r--source/blender/bmesh/intern/bmesh_query.c28
-rw-r--r--source/blender/bmesh/intern/bmesh_query.h7
-rw-r--r--source/blender/bmesh/operators/bmo_bridge.c4
-rw-r--r--source/blender/bmesh/operators/bmo_inset.c2
-rw-r--r--source/blender/bmesh/operators/bmo_removedoubles.c31
-rw-r--r--source/blender/bmesh/tools/bmesh_beautify.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect_edges.c911
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect_edges.h29
-rw-r--r--source/blender/collada/AnimationExporter.cpp2
-rw-r--r--source/blender/collada/AnimationImporter.cpp2
-rw-r--r--source/blender/collada/BCAnimationCurve.cpp4
-rw-r--r--source/blender/collada/BCAnimationSampler.cpp4
-rw-r--r--source/blender/collada/BlenderContext.cpp2
-rw-r--r--source/blender/collada/DocumentImporter.cpp12
-rw-r--r--source/blender/collada/SceneExporter.cpp2
-rw-r--r--source/blender/compositor/intern/COM_Debug.cpp14
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.cpp6
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.cpp4
-rw-r--r--source/blender/compositor/nodes/COM_CornerPinNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_CryptomatteNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.h5
-rw-r--r--source/blender/compositor/nodes/COM_KeyingNode.h5
-rw-r--r--source/blender/compositor/nodes/COM_KeyingScreenNode.h5
-rw-r--r--source/blender/compositor/nodes/COM_OutputFileNode.cpp4
-rw-r--r--source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h5
-rw-r--r--source/blender/compositor/nodes/COM_RenderLayersNode.h5
-rw-r--r--source/blender/compositor/nodes/COM_TextureNode.h5
-rw-r--r--source/blender/compositor/nodes/COM_TrackPositionNode.h5
-rw-r--r--source/blender/compositor/operations/COM_BlurBaseOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_DenoiseOperation.cpp111
-rw-r--r--source/blender/compositor/operations/COM_DenoiseOperation.h9
-rw-r--r--source/blender/compositor/operations/COM_DilateErodeOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_DisplaceOperation.cpp8
-rw-r--r--source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp18
-rw-r--r--source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp16
-rw-r--r--source/blender/compositor/operations/COM_GlareStreaksOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_KeyingBlurOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_KeyingClipOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_MapUVOperation.cpp8
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp8
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.cpp10
-rw-r--r--source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp8
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp2
-rw-r--r--source/blender/depsgraph/CMakeLists.txt2
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h14
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h7
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h12
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.h10
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.cc4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc42
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h136
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc87
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h180
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.cc8
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_transitive.cc2
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc4
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc17
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h5
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc151
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.cc12
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc3
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_foreach.cc26
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_iter.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_registry.cc74
-rw-r--r--source/blender/depsgraph/intern/depsgraph_registry.h38
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc46
-rw-r--r--source/blender/draw/CMakeLists.txt10
-rw-r--r--source/blender/draw/engines/basic/basic_engine.c3
-rw-r--r--source/blender/draw/engines/eevee/eevee_bloom.c12
-rw-r--r--source/blender/draw/engines/eevee/eevee_data.c21
-rw-r--r--source/blender/draw/engines/eevee/eevee_depth_of_field.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c26
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.c34
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c24
-rw-r--r--source/blender/draw/engines/eevee/eevee_lights.c1438
-rw-r--r--source/blender/draw/engines/eevee/eevee_lookdev.c5
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c207
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h261
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c17
-rw-r--r--source/blender/draw/engines/eevee/eevee_sampling.c129
-rw-r--r--source/blender/draw/engines/eevee/eevee_screen_raytrace.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_shadows.c412
-rw-r--r--source/blender/draw/engines/eevee/eevee_shadows_cascade.c439
-rw-r--r--source/blender/draw/engines/eevee/eevee_shadows_cube.c225
-rw-r--r--source/blender/draw/engines/eevee/eevee_subsurface.c136
-rw-r--r--source/blender/draw/engines/eevee/eevee_temporal_sampling.c6
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c49
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl102
-rw-r--r--source/blender/draw/engines/eevee/shaders/default_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/default_world_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl43
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl165
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/lights_lib.glsl407
-rw-r--r--source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl54
-rw-r--r--source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl199
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_process_geom.glsl36
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_process_vert.glsl32
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl322
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl22
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl2
-rw-r--r--source/blender/draw/engines/external/external_engine.c5
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c6
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_utils.c374
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c94
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h11
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_render.c7
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl4
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl18
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl4
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl19
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl5
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl19
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl3
-rw-r--r--source/blender/draw/engines/select/select_draw_utils.c21
-rw-r--r--source/blender/draw/engines/select/select_engine.c4
-rw-r--r--source/blender/draw/engines/select/select_private.h2
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl14
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl6
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl8
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl38
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl12
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl12
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl10
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl7
-rw-r--r--source/blender/draw/engines/workbench/workbench_deferred.c42
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_dof.c6
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_taa.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_forward.c84
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.c147
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.h32
-rw-r--r--source/blender/draw/engines/workbench/workbench_render.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_studiolight.c18
-rw-r--r--source/blender/draw/engines/workbench/workbench_volume.c10
-rw-r--r--source/blender/draw/intern/DRW_render.h47
-rw-r--r--source/blender/draw/intern/draw_anim_viz.c11
-rw-r--r--source/blender/draw/intern/draw_cache.c91
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h22
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.c74
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h6
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curve.c24
-rw-r--r--source/blender/draw/intern/draw_cache_impl_lattice.c4
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c126
-rw-r--r--source/blender/draw/intern/draw_cache_impl_metaball.c2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c41
-rw-r--r--source/blender/draw/intern/draw_common.c39
-rw-r--r--source/blender/draw/intern/draw_common.h4
-rw-r--r--source/blender/draw/intern/draw_debug.c4
-rw-r--r--source/blender/draw/intern/draw_hair.c51
-rw-r--r--source/blender/draw/intern/draw_instance_data.c12
-rw-r--r--source/blender/draw/intern/draw_instance_data.h2
-rw-r--r--source/blender/draw/intern/draw_manager.c287
-rw-r--r--source/blender/draw/intern/draw_manager.h320
-rw-r--r--source/blender/draw/intern/draw_manager_data.c916
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c719
-rw-r--r--source/blender/draw/intern/draw_manager_profiling.c6
-rw-r--r--source/blender/draw/modes/edit_armature_mode.c2
-rw-r--r--source/blender/draw/modes/edit_curve_mode.c12
-rw-r--r--source/blender/draw/modes/edit_mesh_mode.c18
-rw-r--r--source/blender/draw/modes/object_mode.c385
-rw-r--r--source/blender/draw/modes/overlay_mode.c38
-rw-r--r--source/blender/draw/modes/pose_mode.c2
-rw-r--r--source/blender/draw/modes/shaders/common_view_lib.glsl70
-rw-r--r--source/blender/draw/modes/shaders/object_color_axes_vert.glsl35
-rw-r--r--source/blender/draw/modes/shaders/object_empty_image_frag.glsl6
-rw-r--r--source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl12
-rw-r--r--source/blender/draw/modes/shaders/object_outline_detect_frag.glsl40
-rw-r--r--source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl14
-rw-r--r--source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl7
-rw-r--r--source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl17
-rw-r--r--source/blender/draw/modes/shaders/paint_face_vert.glsl2
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c3
-rw-r--r--source/blender/editors/animation/anim_draw.c2
-rw-r--r--source/blender/editors/animation/anim_filter.c5
-rw-r--r--source/blender/editors/animation/anim_markers.c2
-rw-r--r--source/blender/editors/animation/anim_motion_paths.c269
-rw-r--r--source/blender/editors/animation/drivers.c53
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c4
-rw-r--r--source/blender/editors/animation/keyframes_draw.c1
-rw-r--r--source/blender/editors/armature/armature_edit.c6
-rw-r--r--source/blender/editors/armature/armature_select.c9
-rw-r--r--source/blender/editors/armature/armature_skinning.c4
-rw-r--r--source/blender/editors/armature/armature_utils.c2
-rw-r--r--source/blender/editors/armature/pose_edit.c47
-rw-r--r--source/blender/editors/armature/pose_select.c3
-rw-r--r--source/blender/editors/armature/pose_slide.c2
-rw-r--r--source/blender/editors/armature/pose_transform.c253
-rw-r--r--source/blender/editors/armature/pose_utils.c3
-rw-r--r--source/blender/editors/curve/curve_ops.c3
-rw-r--r--source/blender/editors/curve/editcurve.c11
-rw-r--r--source/blender/editors/curve/editcurve_add.c1
-rw-r--r--source/blender/editors/curve/editcurve_paint.c8
-rw-r--r--source/blender/editors/curve/editcurve_select.c14
-rw-r--r--source/blender/editors/curve/editcurve_undo.c2
-rw-r--r--source/blender/editors/curve/editfont.c4
-rw-r--r--source/blender/editors/curve/editfont_undo.c2
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt6
-rw-r--r--source/blender/editors/gizmo_library/gizmo_draw_utils.c3
-rw-r--r--source/blender/editors/gizmo_library/gizmo_library_presets.c7
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c1
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c1
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c4
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c16
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c4
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c2
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c3
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c4
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c8
-rw-r--r--source/blender/editors/gpencil/gpencil_add_monkey.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_add_stroke.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c90
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c146
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c110
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c34
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h5
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_merge.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c581
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c30
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c108
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c56
-rw-r--r--source/blender/editors/include/ED_anim_api.h20
-rw-r--r--source/blender/editors/include/ED_armature.h11
-rw-r--r--source/blender/editors/include/ED_datafiles.h6
-rw-r--r--source/blender/editors/include/ED_fileselect.h56
-rw-r--r--source/blender/editors/include/ED_gpencil.h10
-rw-r--r--source/blender/editors/include/ED_image.h2
-rw-r--r--source/blender/editors/include/ED_keyframing.h13
-rw-r--r--source/blender/editors/include/ED_mesh.h43
-rw-r--r--source/blender/editors/include/ED_object.h10
-rw-r--r--source/blender/editors/include/ED_paint.h33
-rw-r--r--source/blender/editors/include/ED_particle.h10
-rw-r--r--source/blender/editors/include/ED_screen.h9
-rw-r--r--source/blender/editors/include/ED_sculpt.h5
-rw-r--r--source/blender/editors/include/ED_transform.h5
-rw-r--r--source/blender/editors/include/ED_view3d.h8
-rw-r--r--source/blender/editors/include/UI_icons.h22
-rw-r--r--source/blender/editors/include/UI_interface.h17
-rw-r--r--source/blender/editors/include/UI_resources.h3
-rw-r--r--source/blender/editors/interface/interface.c268
-rw-r--r--source/blender/editors/interface/interface_anim.c2
-rw-r--r--source/blender/editors/interface/interface_context_menu.c47
-rw-r--r--source/blender/editors/interface/interface_draw.c18
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c4
-rw-r--r--source/blender/editors/interface/interface_eyedropper_colorband.c2
-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_driver.c2
-rw-r--r--source/blender/editors/interface/interface_handlers.c205
-rw-r--r--source/blender/editors/interface/interface_icons.c18
-rw-r--r--source/blender/editors/interface/interface_icons_event.c2
-rw-r--r--source/blender/editors/interface/interface_intern.h29
-rw-r--r--source/blender/editors/interface/interface_layout.c91
-rw-r--r--source/blender/editors/interface/interface_ops.c63
-rw-r--r--source/blender/editors/interface/interface_query.c48
-rw-r--r--source/blender/editors/interface/interface_region_menu_popup.c2
-rw-r--r--source/blender/editors/interface/interface_region_popup.c2
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c18
-rw-r--r--source/blender/editors/interface/interface_templates.c277
-rw-r--r--source/blender/editors/interface/interface_widgets.c342
-rw-r--r--source/blender/editors/interface/resources.c14
-rw-r--r--source/blender/editors/interface/view2d.c72
-rw-r--r--source/blender/editors/interface/view2d_gizmo_navigate.c8
-rw-r--r--source/blender/editors/interface/view2d_ops.c12
-rw-r--r--source/blender/editors/io/io_alembic.c7
-rw-r--r--source/blender/editors/lattice/editlattice_select.c6
-rw-r--r--source/blender/editors/mask/mask_add.c2
-rw-r--r--source/blender/editors/mask/mask_draw.c3
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt2
-rw-r--r--source/blender/editors/mesh/editface.c2
-rw-r--r--source/blender/editors/mesh/editmesh_add_gizmo.c2
-rw-r--r--source/blender/editors/mesh/editmesh_automerge.c160
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c3
-rw-r--r--source/blender/editors/mesh/editmesh_bisect.c2
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c8
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c32
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c6
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c20
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c4
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c273
-rw-r--r--source/blender/editors/mesh/editmesh_path.c9
-rw-r--r--source/blender/editors/mesh/editmesh_polybuild.c189
-rw-r--r--source/blender/editors/mesh/editmesh_preselect_elem.c206
-rw-r--r--source/blender/editors/mesh/editmesh_select.c597
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c23
-rw-r--r--source/blender/editors/mesh/mesh_intern.h10
-rw-r--r--source/blender/editors/mesh/mesh_ops.c23
-rw-r--r--source/blender/editors/mesh/meshtools.c40
-rw-r--r--source/blender/editors/metaball/mball_edit.c6
-rw-r--r--source/blender/editors/object/object_add.c29
-rw-r--r--source/blender/editors/object/object_bake.c4
-rw-r--r--source/blender/editors/object/object_bake_api.c2
-rw-r--r--source/blender/editors/object/object_collection.c8
-rw-r--r--source/blender/editors/object/object_constraint.c4
-rw-r--r--source/blender/editors/object/object_edit.c133
-rw-r--r--source/blender/editors/object/object_intern.h3
-rw-r--r--source/blender/editors/object/object_modifier.c8
-rw-r--r--source/blender/editors/object/object_ops.c3
-rw-r--r--source/blender/editors/object/object_relations.c41
-rw-r--r--source/blender/editors/object/object_remesh.c535
-rw-r--r--source/blender/editors/object/object_transform.c13
-rw-r--r--source/blender/editors/object/object_vgroup.c6
-rw-r--r--source/blender/editors/object/object_warp.c6
-rw-r--r--source/blender/editors/physics/particle_edit.c362
-rw-r--r--source/blender/editors/physics/particle_edit_undo.c27
-rw-r--r--source/blender/editors/physics/particle_object.c15
-rw-r--r--source/blender/editors/physics/rigidbody_constraint.c9
-rw-r--r--source/blender/editors/render/render_internal.c2
-rw-r--r--source/blender/editors/render/render_preview.c2
-rw-r--r--source/blender/editors/render/render_update.c2
-rw-r--r--source/blender/editors/render/render_view.c11
-rw-r--r--source/blender/editors/scene/scene_edit.c7
-rw-r--r--source/blender/editors/screen/area.c40
-rw-r--r--source/blender/editors/screen/area_query.c2
-rw-r--r--source/blender/editors/screen/area_utils.c1
-rw-r--r--source/blender/editors/screen/glutil.c7
-rw-r--r--source/blender/editors/screen/screen_context.c8
-rw-r--r--source/blender/editors/screen/screen_draw.c6
-rw-r--r--source/blender/editors/screen/screen_edit.c175
-rw-r--r--source/blender/editors/screen/screen_ops.c113
-rw-r--r--source/blender/editors/screen/screen_user_menu.c24
-rw-r--r--source/blender/editors/screen/workspace_edit.c10
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt2
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c461
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve_undo.c1
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c23
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c20
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c15
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c80
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_undo.c625
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h31
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c63
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c10
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c206
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c12
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c44
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_ops.c14
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_utils.c30
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c17
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c3712
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h97
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c15
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c9
-rw-r--r--source/blender/editors/sound/sound_ops.c2
-rw-r--r--source/blender/editors/space_action/action_edit.c8
-rw-r--r--source/blender/editors/space_action/action_select.c42
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c1
-rw-r--r--source/blender/editors/space_clip/clip_dopesheet_draw.c1
-rw-r--r--source/blender/editors/space_clip/clip_draw.c288
-rw-r--r--source/blender/editors/space_clip/clip_intern.h3
-rw-r--r--source/blender/editors/space_clip/clip_ops.c184
-rw-r--r--source/blender/editors/space_clip/clip_utils.c1
-rw-r--r--source/blender/editors/space_clip/space_clip.c2
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c8
-rw-r--r--source/blender/editors/space_clip/tracking_ops_plane.c4
-rw-r--r--source/blender/editors/space_clip/tracking_ops_solve.c6
-rw-r--r--source/blender/editors/space_clip/tracking_ops_track.c14
-rw-r--r--source/blender/editors/space_clip/tracking_ops_utils.c4
-rw-r--r--source/blender/editors/space_clip/tracking_select.c4
-rw-r--r--source/blender/editors/space_console/console_ops.c2
-rw-r--r--source/blender/editors/space_console/space_console.c7
-rw-r--r--source/blender/editors/space_file/file_draw.c680
-rw-r--r--source/blender/editors/space_file/file_intern.h23
-rw-r--r--source/blender/editors/space_file/file_ops.c218
-rw-r--r--source/blender/editors/space_file/file_panels.c116
-rw-r--r--source/blender/editors/space_file/filelist.c177
-rw-r--r--source/blender/editors/space_file/filelist.h6
-rw-r--r--source/blender/editors/space_file/filesel.c369
-rw-r--r--source/blender/editors/space_file/fsmenu.c19
-rw-r--r--source/blender/editors/space_file/space_file.c169
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c17
-rw-r--r--source/blender/editors/space_graph/graph_draw.c11
-rw-r--r--source/blender/editors/space_graph/graph_edit.c12
-rw-r--r--source/blender/editors/space_image/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_image/image_edit.c18
-rw-r--r--source/blender/editors/space_image/image_intern.h3
-rw-r--r--source/blender/editors/space_image/image_ops.c366
-rw-r--r--source/blender/editors/space_image/image_undo.c1032
-rw-r--r--source/blender/editors/space_image/space_image.c2
-rw-r--r--source/blender/editors/space_info/info_stats.c10
-rw-r--r--source/blender/editors/space_nla/nla_draw.c1
-rw-r--r--source/blender/editors/space_node/drawnode.c87
-rw-r--r--source/blender/editors/space_node/node_add.c2
-rw-r--r--source/blender/editors/space_node/node_draw.c23
-rw-r--r--source/blender/editors/space_node/node_edit.c5
-rw-r--r--source/blender/editors/space_node/node_group.c20
-rw-r--r--source/blender/editors/space_node/node_relationships.c14
-rw-r--r--source/blender/editors/space_node/node_select.c60
-rw-r--r--source/blender/editors/space_node/node_templates.c14
-rw-r--r--source/blender/editors/space_node/space_node.c8
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c8
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.c6
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c20
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c3
-rw-r--r--source/blender/editors/space_outliner/outliner_sync.c45
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c28
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c8
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c5
-rw-r--r--source/blender/editors/space_script/script_edit.c3
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c16
-rw-r--r--source/blender/editors/space_sequencer/sequencer_buttons.c1
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c14
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c2
-rw-r--r--source/blender/editors/space_text/space_text.c7
-rw-r--r--source/blender/editors/space_text/text_ops.c6
-rw-r--r--source/blender/editors/space_userpref/space_userpref.c2
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt6
-rw-r--r--source/blender/editors/space_view3d/drawobject.c4
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c69
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_camera_control.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_draw_legacy.c14
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate.c24
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c126
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_ruler.c5
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c12
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c20
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c142
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c2
-rw-r--r--source/blender/editors/transform/CMakeLists.txt21
-rw-r--r--source/blender/editors/transform/transform.c503
-rw-r--r--source/blender/editors/transform/transform.h135
-rw-r--r--source/blender/editors/transform/transform_conversions.c9925
-rw-r--r--source/blender/editors/transform/transform_convert.c2743
-rw-r--r--source/blender/editors/transform/transform_convert.h141
-rw-r--r--source/blender/editors/transform/transform_convert_action.c575
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c933
-rw-r--r--source/blender/editors/transform/transform_convert_cursor.c129
-rw-r--r--source/blender/editors/transform/transform_convert_curve.c422
-rw-r--r--source/blender/editors/transform/transform_convert_gpencil.c371
-rw-r--r--source/blender/editors/transform/transform_convert_graph.c700
-rw-r--r--source/blender/editors/transform/transform_convert_lattice.c113
-rw-r--r--source/blender/editors/transform/transform_convert_mask.c442
-rw-r--r--source/blender/editors/transform/transform_convert_mball.c130
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c1645
-rw-r--r--source/blender/editors/transform/transform_convert_nla.c265
-rw-r--r--source/blender/editors/transform/transform_convert_node.c195
-rw-r--r--source/blender/editors/transform/transform_convert_object.c949
-rw-r--r--source/blender/editors/transform/transform_convert_paintcurve.c227
-rw-r--r--source/blender/editors/transform/transform_convert_particle.c248
-rw-r--r--source/blender/editors/transform/transform_convert_sculpt.c105
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c769
-rw-r--r--source/blender/editors/transform/transform_convert_tracking.c692
-rw-r--r--source/blender/editors/transform/transform_generics.c89
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c35
-rw-r--r--source/blender/editors/transform/transform_input.c4
-rw-r--r--source/blender/editors/transform/transform_ops.c8
-rw-r--r--source/blender/editors/transform/transform_snap.c12
-rw-r--r--source/blender/editors/transform/transform_snap_object.c297
-rw-r--r--source/blender/editors/undo/ed_undo.c12
-rw-r--r--source/blender/editors/util/ed_util.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_buttons.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c168
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c10
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c14
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp9
-rw-r--r--source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp11
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c16
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h14
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c62
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c6
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c2
-rw-r--r--source/blender/gpu/CMakeLists.txt92
-rw-r--r--source/blender/gpu/GPU_batch.h11
-rw-r--r--source/blender/gpu/GPU_buffers.h20
-rw-r--r--source/blender/gpu/GPU_shader_interface.h9
-rw-r--r--source/blender/gpu/GPU_viewport.h10
-rw-r--r--source/blender/gpu/intern/gpu_attr_binding.c4
-rw-r--r--source/blender/gpu/intern/gpu_batch.c257
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c249
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c133
-rw-r--r--source/blender/gpu/intern/gpu_codegen.h3
-rw-r--r--source/blender/gpu/intern/gpu_draw.c11
-rw-r--r--source/blender/gpu/intern/gpu_element.c6
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c23
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.c19
-rw-r--r--source/blender/gpu/intern/gpu_immediate.c38
-rw-r--r--source/blender/gpu/intern/gpu_immediate_util.c21
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c5
-rw-r--r--source/blender/gpu/intern/gpu_material.c21
-rw-r--r--source/blender/gpu/intern/gpu_material_library.h655
-rw-r--r--source/blender/gpu/intern/gpu_private.h4
-rw-r--r--source/blender/gpu/intern/gpu_select.c1
-rw-r--r--source/blender/gpu/intern/gpu_select_pick.c1
-rw-r--r--source/blender/gpu/intern/gpu_select_sample_query.c1
-rw-r--r--source/blender/gpu/intern/gpu_shader.c23
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.c21
-rw-r--r--source/blender/gpu/intern/gpu_texture.c12
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer.c2
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format.c8
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c30
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl20
-rw-r--r--source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl19
-rw-r--r--source/blender/gpu/shaders/gpu_shader_geometry.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl7
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl7
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl10
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_vert.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl3874
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl13
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl15
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl6
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_background.glsl11
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_bevel.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_blackbody.glsl13
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_bright_contrast.glsl10
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl44
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl6
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_clamp.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_color_ramp.glsl28
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl111
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_combine_rgb.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_combine_xyz.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl13
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl12
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl41
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl10
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl111
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl37
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl14
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl46
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl32
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl16
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl21
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl217
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl8
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl14
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_invert.glsl5
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl19
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl7
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl31
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl10
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl27
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_math.glsl130
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl151
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl291
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl294
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_normal.glsl5
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl22
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl16
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl8
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl11
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl23
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl418
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl16
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_rgb_curves.glsl73
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_rgb_to_bw.glsl5
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl9
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_separate_rgb.glsl6
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_separate_xyz.glsl6
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_set.glsl44
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl21
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_squeeze.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl27
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl25
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl78
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_checker.glsl17
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl44
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_gradient.glsl47
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl355
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl61
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl887
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl99
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl1064
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl42
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl21
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl92
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl9
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl13
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl11
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_uv_map.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl8
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl30
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl100
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl9
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vertex_color.glsl5
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl8
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl88
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl67
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl8
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl31
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl25
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp22
-rw-r--r--source/blender/imbuf/IMB_imbuf.h36
-rw-r--r--source/blender/imbuf/intern/IMB_anim.h2
-rw-r--r--source/blender/imbuf/intern/IMB_filetype.h2
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c4
-rw-r--r--source/blender/imbuf/intern/anim_movie.c61
-rw-r--r--source/blender/imbuf/intern/colormanagement.c3
-rw-r--r--source/blender/imbuf/intern/dds/FlipDXT.cpp8
-rw-r--r--source/blender/imbuf/intern/filetype.c4
-rw-r--r--source/blender/imbuf/intern/indexer.c8
-rw-r--r--source/blender/imbuf/intern/jp2.c2
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp6
-rw-r--r--source/blender/imbuf/intern/rectop.c90
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c4
-rw-r--r--source/blender/imbuf/intern/targa.c4
-rw-r--r--source/blender/imbuf/intern/util.c4
-rw-r--r--source/blender/makesdna/DNA_ID.h15
-rw-r--r--source/blender/makesdna/DNA_anim_types.h30
-rw-r--r--source/blender/makesdna/DNA_armature_types.h19
-rw-r--r--source/blender/makesdna/DNA_brush_defaults.h105
-rw-r--r--source/blender/makesdna/DNA_brush_types.h44
-rw-r--r--source/blender/makesdna/DNA_cachefile_defaults.h49
-rw-r--r--source/blender/makesdna/DNA_camera_defaults.h67
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h87
-rw-r--r--source/blender/makesdna/DNA_curve_defaults.h59
-rw-r--r--source/blender/makesdna/DNA_curve_types.h7
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h3
-rw-r--r--source/blender/makesdna/DNA_defaults.h46
-rw-r--r--source/blender/makesdna/DNA_genfile.h2
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h9
-rw-r--r--source/blender/makesdna/DNA_image_defaults.h46
-rw-r--r--source/blender/makesdna/DNA_lattice_defaults.h44
-rw-r--r--source/blender/makesdna/DNA_layer_types.h6
-rw-r--r--source/blender/makesdna/DNA_light_defaults.h76
-rw-r--r--source/blender/makesdna/DNA_light_types.h10
-rw-r--r--source/blender/makesdna/DNA_lightprobe_defaults.h51
-rw-r--r--source/blender/makesdna/DNA_linestyle_defaults.h61
-rw-r--r--source/blender/makesdna/DNA_material_defaults.h55
-rw-r--r--source/blender/makesdna/DNA_mesh_defaults.h45
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h16
-rw-r--r--source/blender/makesdna/DNA_meta_defaults.h44
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h20
-rw-r--r--source/blender/makesdna/DNA_movieclip_types.h2
-rw-r--r--source/blender/makesdna/DNA_node_types.h55
-rw-r--r--source/blender/makesdna/DNA_object_defaults.h77
-rw-r--r--source/blender/makesdna/DNA_object_types.h20
-rw-r--r--source/blender/makesdna/DNA_scene_defaults.h368
-rw-r--r--source/blender/makesdna/DNA_scene_types.h23
-rw-r--r--source/blender/makesdna/DNA_screen_types.h12
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h4
-rw-r--r--source/blender/makesdna/DNA_space_types.h27
-rw-r--r--source/blender/makesdna/DNA_speaker_defaults.h51
-rw-r--r--source/blender/makesdna/DNA_texture_defaults.h155
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h151
-rw-r--r--source/blender/makesdna/DNA_vec_defaults.h55
-rw-r--r--source/blender/makesdna/DNA_view3d_defaults.h116
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h16
-rw-r--r--source/blender/makesdna/DNA_world_defaults.h49
-rw-r--r--source/blender/makesdna/intern/CMakeLists.txt21
-rw-r--r--source/blender/makesdna/intern/dna_defaults.c273
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c23
-rw-r--r--source/blender/makesrna/RNA_access.h29
-rw-r--r--source/blender/makesrna/RNA_enum_types.h2
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt11
-rw-r--r--source/blender/makesrna/intern/makesrna.c39
-rw-r--r--source/blender/makesrna/intern/rna_ID.c21
-rw-r--r--source/blender/makesrna/intern/rna_access.c158
-rw-r--r--source/blender/makesrna/intern/rna_access_compare_override.c4
-rw-r--r--source/blender/makesrna/intern/rna_animation.c3
-rw-r--r--source/blender/makesrna/intern/rna_animviz.c4
-rw-r--r--source/blender/makesrna/intern/rna_armature.c159
-rw-r--r--source/blender/makesrna/intern/rna_armature_api.c5
-rw-r--r--source/blender/makesrna/intern/rna_boid.c4
-rw-r--r--source/blender/makesrna/intern/rna_brush.c115
-rw-r--r--source/blender/makesrna/intern/rna_camera.c12
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c169
-rw-r--r--source/blender/makesrna/intern/rna_curve.c17
-rw-r--r--source/blender/makesrna/intern/rna_define.c380
-rw-r--r--source/blender/makesrna/intern/rna_dynamicpaint.c4
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c36
-rw-r--r--source/blender/makesrna/intern/rna_fluidsim.c2
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c27
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c21
-rw-r--r--source/blender/makesrna/intern/rna_internal.h12
-rw-r--r--source/blender/makesrna/intern/rna_layer.c34
-rw-r--r--source/blender/makesrna/intern/rna_light.c59
-rw-r--r--source/blender/makesrna/intern/rna_lightprobe.c12
-rw-r--r--source/blender/makesrna/intern/rna_linestyle.c2
-rw-r--r--source/blender/makesrna/intern/rna_material.c2
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c87
-rw-r--r--source/blender/makesrna/intern/rna_meta.c2
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c54
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c224
-rw-r--r--source/blender/makesrna/intern/rna_object.c71
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c85
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c125
-rw-r--r--source/blender/makesrna/intern/rna_particle.c8
-rw-r--r--source/blender/makesrna/intern/rna_pose.c50
-rw-r--r--source/blender/makesrna/intern/rna_rna.c5
-rw-r--r--source/blender/makesrna/intern/rna_scene.c228
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c34
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c41
-rw-r--r--source/blender/makesrna/intern/rna_shader_fx.c4
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c6
-rw-r--r--source/blender/makesrna/intern/rna_space.c293
-rw-r--r--source/blender/makesrna/intern/rna_space_api.c3
-rw-r--r--source/blender/makesrna/intern/rna_texture.c49
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c6
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c7
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c104
-rw-r--r--source/blender/makesrna/intern/rna_wm.c36
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c46
-rw-r--r--source/blender/modifiers/CMakeLists.txt4
-rw-r--r--source/blender/modifiers/intern/MOD_armature.c2
-rw-r--r--source/blender/modifiers/intern/MOD_array.c8
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c2
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c4
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c2
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c112
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c2
-rw-r--r--source/blender/modifiers/intern/MOD_datatransfer.c2
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c6
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c5
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c2
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c22
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim_util.c6
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c4
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciandeform.c10
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciansmooth.c8
-rw-r--r--source/blender/modifiers/intern/MOD_lattice.c2
-rw-r--r--source/blender/modifiers/intern/MOD_mask.c10
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache_mdd.c4
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache_pc2.c4
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c2
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c375
-rw-r--r--source/blender/modifiers/intern/MOD_multires.c37
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c5
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c2
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c2
-rw-r--r--source/blender/modifiers/intern/MOD_remesh.c1
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c75
-rw-r--r--source/blender/modifiers/intern/MOD_shrinkwrap.c6
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c10
-rw-r--r--source/blender/modifiers/intern/MOD_smooth.c148
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c70
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c36
-rw-r--r--source/blender/modifiers/intern/MOD_surface.c2
-rw-r--r--source/blender/modifiers/intern/MOD_surfacedeform.c68
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c2
-rw-r--r--source/blender/modifiers/intern/MOD_util.c12
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c42
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.c4
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c4
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c2
-rw-r--r--source/blender/nodes/CMakeLists.txt3
-rw-r--r--source/blender/nodes/NOD_shader.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorbalance.c4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cryptomatte.c4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_denoise.c2
-rw-r--r--source/blender/nodes/intern/node_exec.c10
-rw-r--r--source/blender/nodes/intern/node_util.c10
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c433
-rw-r--r--source/blender/nodes/shader/node_shader_util.c30
-rw-r--r--source/blender/nodes/shader/node_shader_util.h6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_attribute.c9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bump.c35
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_common.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_curves.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_geometry.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_hueSatVal.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mapping.c102
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mixRgb.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal_map.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_brick.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_checker.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_coord.c31
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.c7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_gradient.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.c11
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_magic.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c91
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.c41
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c145
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_wave.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_uvmap.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vectTransform.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vertex_color.c58
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_common.c4
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_proc.c146
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp14
-rw-r--r--source/blender/physics/intern/ConstrainedConjugateGradient.h2
-rw-r--r--source/blender/physics/intern/eigen_utils.h26
-rw-r--r--source/blender/physics/intern/hair_volume.cpp84
-rw-r--r--source/blender/physics/intern/implicit_blender.c24
-rw-r--r--source/blender/physics/intern/implicit_eigen.cpp44
-rw-r--r--source/blender/python/generic/bgl.c2
-rw-r--r--source/blender/python/generic/idprop_py_api.c3
-rw-r--r--source/blender/python/generic/imbuf_py_api.c122
-rw-r--r--source/blender/python/generic/py_capi_utils.c31
-rw-r--r--source/blender/python/generic/py_capi_utils.h11
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.c3
-rw-r--r--source/blender/python/gpu/gpu_py_shader.c1
-rw-r--r--source/blender/python/intern/CMakeLists.txt4
-rw-r--r--source/blender/python/intern/bpy.c98
-rw-r--r--source/blender/python/intern/bpy_app_build_options.c7
-rw-r--r--source/blender/python/intern/bpy_app_handlers.c64
-rw-r--r--source/blender/python/intern/bpy_props.c12
-rw-r--r--source/blender/python/intern/bpy_rna.c87
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c4
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c48
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c21
-rw-r--r--source/blender/python/mathutils/mathutils_noise.c4
-rw-r--r--source/blender/python/rna_dump.py6
-rw-r--r--source/blender/render/intern/source/bake_api.c10
-rw-r--r--source/blender/render/intern/source/external_engine.c2
-rw-r--r--source/blender/render/intern/source/imagetexture.c4
-rw-r--r--source/blender/render/intern/source/pipeline.c70
-rw-r--r--source/blender/render/intern/source/pointdensity.c10
-rw-r--r--source/blender/windowmanager/WM_api.h19
-rw-r--r--source/blender/windowmanager/WM_types.h16
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo.c1
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c1
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c1645
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c2
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c22
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c198
-rw-r--r--source/blender/windowmanager/intern/wm_files.c79
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c9
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c28
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c49
-rw-r--r--source/blender/windowmanager/intern/wm_operator_type.c35
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c112
-rw-r--r--source/blender/windowmanager/intern/wm_splash_screen.c20
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c1
-rw-r--r--source/blender/windowmanager/intern/wm_window.c50
-rw-r--r--source/blender/windowmanager/wm_cursors.h117
-rw-r--r--source/blender/windowmanager/wm_event_system.h4
1089 files changed, 60441 insertions, 30875 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index 76442048594..203543b0ef0 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -153,3 +153,7 @@ endif()
if(WITH_ALEMBIC)
add_subdirectory(alembic)
endif()
+
+if(WIN32)
+ add_subdirectory(blendthumb)
+endif()
diff --git a/source/blender/alembic/ABC_alembic.h b/source/blender/alembic/ABC_alembic.h
index 696e0ff1810..7c5efaf309d 100644
--- a/source/blender/alembic/ABC_alembic.h
+++ b/source/blender/alembic/ABC_alembic.h
@@ -27,6 +27,7 @@ extern "C" {
struct CacheReader;
struct ListBase;
+struct Main;
struct Mesh;
struct Object;
struct Scene;
@@ -103,7 +104,9 @@ bool ABC_import(struct bContext *C,
bool validate_meshes,
bool as_background_job);
-AbcArchiveHandle *ABC_create_handle(const char *filename, struct ListBase *object_paths);
+AbcArchiveHandle *ABC_create_handle(struct Main *bmain,
+ const char *filename,
+ struct ListBase *object_paths);
void ABC_free_handle(AbcArchiveHandle *handle);
diff --git a/source/blender/alembic/intern/abc_archive.cc b/source/blender/alembic/intern/abc_archive.cc
index c4252d20d48..bb527c23b20 100644
--- a/source/blender/alembic/intern/abc_archive.cc
+++ b/source/blender/alembic/intern/abc_archive.cc
@@ -24,6 +24,10 @@
#include "abc_archive.h"
extern "C" {
#include "BKE_blender_version.h"
+#include "BKE_main.h"
+
+#include "BLI_path_util.h"
+#include "BLI_string.h"
}
#ifdef WIN32
@@ -95,20 +99,24 @@ static IArchive open_archive(const std::string &filename,
return IArchive();
}
-ArchiveReader::ArchiveReader(const char *filename)
+ArchiveReader::ArchiveReader(struct Main *bmain, const char *filename)
{
+ char abs_filename[FILE_MAX];
+ BLI_strncpy(abs_filename, filename, FILE_MAX);
+ BLI_path_abs(abs_filename, BKE_main_blendfile_path(bmain));
+
#ifdef WIN32
- UTF16_ENCODE(filename);
- std::wstring wstr(filename_16);
+ UTF16_ENCODE(abs_filename);
+ std::wstring wstr(abs_filename_16);
m_infile.open(wstr.c_str(), std::ios::in | std::ios::binary);
- UTF16_UN_ENCODE(filename);
+ UTF16_UN_ENCODE(abs_filename);
#else
- m_infile.open(filename, std::ios::in | std::ios::binary);
+ m_infile.open(abs_filename, std::ios::in | std::ios::binary);
#endif
m_streams.push_back(&m_infile);
- m_archive = open_archive(filename, m_streams, m_is_hdf5);
+ m_archive = open_archive(abs_filename, m_streams, m_is_hdf5);
/* We can't open an HDF5 file from a stream, so close it. */
if (m_is_hdf5) {
diff --git a/source/blender/alembic/intern/abc_archive.h b/source/blender/alembic/intern/abc_archive.h
index 343a8112aa2..a64de742cdf 100644
--- a/source/blender/alembic/intern/abc_archive.h
+++ b/source/blender/alembic/intern/abc_archive.h
@@ -34,6 +34,8 @@
#include <fstream>
+struct Main;
+
/* Wrappers around input and output archives. The goal is to be able to use
* streams so that unicode paths work on Windows (T49112), and to make sure that
* the stream objects remain valid as long as the archives are open.
@@ -46,7 +48,7 @@ class ArchiveReader {
bool m_is_hdf5;
public:
- explicit ArchiveReader(const char *filename);
+ ArchiveReader(struct Main *bmain, const char *filename);
bool valid() const;
diff --git a/source/blender/alembic/intern/abc_curves.cc b/source/blender/alembic/intern/abc_curves.cc
index 13872618d74..50aa13bea4f 100644
--- a/source/blender/alembic/intern/abc_curves.cc
+++ b/source/blender/alembic/intern/abc_curves.cc
@@ -111,7 +111,7 @@ void AbcCurveWriter::do_write()
const BPoint *point = nurbs->bp;
- for (int i = 0; i < totpoint; ++i, ++point) {
+ for (int i = 0; i < totpoint; i++, point++) {
copy_yup_from_zup(temp_vert.getValue(), point->vec);
verts.push_back(temp_vert);
weights.push_back(point->vec[3]);
@@ -127,7 +127,7 @@ void AbcCurveWriter::do_write()
const BezTriple *bezier = nurbs->bezt;
/* TODO(kevin): store info about handles, Alembic doesn't have this. */
- for (int i = 0; i < totpoint; ++i, ++bezier) {
+ for (int i = 0; i < totpoint; i++, bezier++) {
copy_yup_from_zup(temp_vert.getValue(), bezier->vec[1]);
verts.push_back(temp_vert);
widths.push_back(bezier->radius);
@@ -144,7 +144,7 @@ void AbcCurveWriter::do_write()
* cyclic since other software need those.
*/
- for (int i = 0; i < nurbs->orderu; ++i) {
+ for (int i = 0; i < nurbs->orderu; i++) {
verts.push_back(verts[i]);
}
}
@@ -156,7 +156,7 @@ void AbcCurveWriter::do_write()
* require/expect them. */
knots.resize(num_knots + 2);
- for (int i = 0; i < num_knots; ++i) {
+ for (int i = 0; i < num_knots; i++) {
knots[i + 1] = nurbs->knotsu[i];
}
@@ -316,7 +316,7 @@ void AbcCurveReader::read_curve_sample(Curve *cu,
int knot_offset = 0;
size_t idx = 0;
- for (size_t i = 0; i < num_vertices->size(); ++i) {
+ for (size_t i = 0; i < num_vertices->size(); i++) {
const int num_verts = (*num_vertices)[i];
Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "abc_getnurb"));
@@ -357,7 +357,7 @@ void AbcCurveReader::read_curve_sample(Curve *cu,
const int end = idx + num_verts;
int overlap = 0;
- for (int j = start, k = end - nu->orderu; j < nu->orderu; ++j, ++k) {
+ for (int j = start, k = end - nu->orderu; j < nu->orderu; j++, k++) {
const Imath::V3f &p1 = (*positions)[j];
const Imath::V3f &p2 = (*positions)[k];
@@ -365,7 +365,7 @@ void AbcCurveReader::read_curve_sample(Curve *cu,
break;
}
- ++overlap;
+ overlap++;
}
/* TODO: Special case, need to figure out how it coincides with knots. */
@@ -393,7 +393,7 @@ void AbcCurveReader::read_curve_sample(Curve *cu,
nu->bp = static_cast<BPoint *>(MEM_callocN(sizeof(BPoint) * nu->pntsu, "abc_getnurb"));
BPoint *bp = nu->bp;
- for (int j = 0; j < nu->pntsu; ++j, ++bp, ++idx) {
+ for (int j = 0; j < nu->pntsu; j++, bp++, idx++) {
const Imath::V3f &pos = (*positions)[idx];
if (do_radius) {
@@ -418,7 +418,7 @@ void AbcCurveReader::read_curve_sample(Curve *cu,
/* TODO: second check is temporary, for until the check for cycles is rock solid. */
if (periodicity == Alembic::AbcGeom::kPeriodic && (KNOTSU(nu) == knots->size() - 2)) {
/* Skip first and last knots. */
- for (size_t i = 1; i < knots->size() - 1; ++i) {
+ for (size_t i = 1; i < knots->size() - 1; i++) {
nu->knotsu[i - 1] = (*knots)[knot_offset + i];
}
}
@@ -476,7 +476,7 @@ Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh,
if (same_topology) {
Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
- for (curve_idx = 0; nurbs; nurbs = nurbs->next, ++curve_idx) {
+ for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
const int num_in_alembic = (*num_vertices)[curve_idx];
const int num_in_blender = nurbs->pntsu;
@@ -493,13 +493,13 @@ Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh,
}
else {
Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
- for (curve_idx = 0; nurbs; nurbs = nurbs->next, ++curve_idx) {
+ for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
const int totpoint = (*num_vertices)[curve_idx];
if (nurbs->bp) {
BPoint *point = nurbs->bp;
- for (int i = 0; i < totpoint; ++i, ++point, ++vertex_idx) {
+ for (int i = 0; i < totpoint; i++, point++, vertex_idx++) {
const Imath::V3f &pos = (*positions)[vertex_idx];
copy_zup_from_yup(point->vec, pos.getValue());
}
@@ -507,7 +507,7 @@ Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh,
else if (nurbs->bezt) {
BezTriple *bezier = nurbs->bezt;
- for (int i = 0; i < totpoint; ++i, ++bezier, ++vertex_idx) {
+ for (int i = 0; i < totpoint; i++, bezier++, vertex_idx++) {
const Imath::V3f &pos = (*positions)[vertex_idx];
copy_zup_from_yup(bezier->vec[1], pos.getValue());
}
diff --git a/source/blender/alembic/intern/abc_customdata.cc b/source/blender/alembic/intern/abc_customdata.cc
index 63887d36381..7f04bb77052 100644
--- a/source/blender/alembic/intern/abc_customdata.cc
+++ b/source/blender/alembic/intern/abc_customdata.cc
@@ -72,12 +72,12 @@ static void get_uvs(const CDStreamConfig &config,
uvs.resize(config.totloop);
/* Iterate in reverse order to match exported polygons. */
- for (int i = 0; i < num_poly; ++i) {
+ for (int i = 0; i < num_poly; i++) {
MPoly &current_poly = polygons[i];
MLoopUV *loopuv = mloopuv_array + current_poly.loopstart + current_poly.totloop;
- for (int j = 0; j < current_poly.totloop; ++j, ++cnt) {
- --loopuv;
+ for (int j = 0; j < current_poly.totloop; j++, cnt++) {
+ loopuv--;
uvidx[cnt] = cnt;
uvs[cnt][0] = loopuv->uv[0];
@@ -90,14 +90,14 @@ static void get_uvs(const CDStreamConfig &config,
std::vector<std::vector<uint32_t>> idx_map(config.totvert);
int idx_count = 0;
- for (int i = 0; i < num_poly; ++i) {
+ for (int i = 0; i < num_poly; i++) {
MPoly &current_poly = polygons[i];
MLoop *looppoly = mloop + current_poly.loopstart + current_poly.totloop;
MLoopUV *loopuv = mloopuv_array + current_poly.loopstart + current_poly.totloop;
- for (int j = 0; j < current_poly.totloop; ++j) {
- --looppoly;
- --loopuv;
+ for (int j = 0; j < current_poly.totloop; j++) {
+ looppoly--;
+ loopuv--;
Imath::V2f uv(loopuv->uv[0], loopuv->uv[1]);
bool found_same = false;
@@ -188,12 +188,12 @@ static void write_mcol(const OCompoundProperty &prop,
Imath::C4f col;
- for (int i = 0; i < config.totpoly; ++i) {
+ for (int i = 0; i < config.totpoly; i++) {
MPoly *p = &polys[i];
MCol *cface = &cfaces[p->loopstart + p->totloop];
MLoop *mloop = &mloops[p->loopstart + p->totloop];
- for (int j = 0; j < p->totloop; ++j) {
+ for (int j = 0; j < p->totloop; j++) {
cface--;
mloop--;
@@ -230,7 +230,7 @@ void write_custom_data(const OCompoundProperty &prop,
const int active_layer = CustomData_get_active_layer(data, cd_data_type);
const int tot_layers = CustomData_number_of_layers(data, cd_data_type);
- for (int i = 0; i < tot_layers; ++i) {
+ for (int i = 0; i < tot_layers; i++) {
void *cd_data = CustomData_get_layer_n(data, cd_data_type, i);
const char *name = CustomData_get_layer_name(data, cd_data_type, i);
@@ -268,11 +268,11 @@ static void read_uvs(const CDStreamConfig &config,
unsigned int uv_index, loop_index, rev_loop_index;
- for (int i = 0; i < config.totpoly; ++i) {
+ for (int i = 0; i < config.totpoly; i++) {
MPoly &poly = mpolys[i];
unsigned int rev_loop_offset = poly.loopstart + poly.totloop - 1;
- for (int f = 0; f < poly.totloop; ++f) {
+ for (int f = 0; f < poly.totloop; f++) {
loop_index = poly.loopstart + f;
rev_loop_index = rev_loop_offset - f;
uv_index = (*indices)[loop_index];
@@ -368,14 +368,14 @@ static void read_custom_data_mcols(const std::string &iobject_full_name,
* is why we have to check for indices->size() > 0 */
bool use_dual_indexing = is_facevarying && indices->size() > 0;
- for (int i = 0; i < config.totpoly; ++i) {
+ for (int i = 0; i < config.totpoly; i++) {
MPoly *poly = &mpolys[i];
MCol *cface = &cfaces[poly->loopstart + poly->totloop];
MLoop *mloop = &mloops[poly->loopstart + poly->totloop];
- for (int j = 0; j < poly->totloop; ++j, ++face_index) {
- --cface;
- --mloop;
+ for (int j = 0; j < poly->totloop; j++, face_index++) {
+ cface--;
+ mloop--;
color_index = is_facevarying ? face_index : mloop->v;
if (use_dual_indexing) {
@@ -456,7 +456,7 @@ void read_custom_data(const std::string &iobject_full_name,
const size_t num_props = prop.getNumProperties();
- for (size_t i = 0; i < num_props; ++i) {
+ for (size_t i = 0; i < num_props; i++) {
const Alembic::Abc::PropertyHeader &prop_header = prop.getPropertyHeader(i);
/* Read UVs according to convention. */
diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc
index f19e0257b1b..69a376d00b0 100644
--- a/source/blender/alembic/intern/abc_exporter.cc
+++ b/source/blender/alembic/intern/abc_exporter.cc
@@ -202,7 +202,7 @@ AbcExporter::~AbcExporter()
}
/* Free shapes vector */
- for (int i = 0, e = m_shapes.size(); i != e; ++i) {
+ for (int i = 0, e = m_shapes.size(); i != e; i++) {
delete m_shapes[i];
}
@@ -223,7 +223,7 @@ void AbcExporter::getShutterSamples(unsigned int nr_of_samples,
double time_inc = (shutter_close - shutter_open) / nr_of_samples;
/* sample between shutter open & close */
- for (int sample = 0; sample < nr_of_samples; ++sample) {
+ for (int sample = 0; sample < nr_of_samples; sample++) {
double sample_time = shutter_open + time_inc * sample;
double time = (frame_offset + sample_time) / time_factor;
@@ -257,13 +257,13 @@ void AbcExporter::getFrameSet(unsigned int nr_of_samples, std::set<double> &fram
getShutterSamples(nr_of_samples, false, shutter_samples);
for (double frame = m_settings.frame_start; frame <= m_settings.frame_end; frame += 1.0) {
- for (size_t j = 0; j < nr_of_samples; ++j) {
+ for (size_t j = 0; j < nr_of_samples; j++) {
frames.insert(frame + shutter_samples[j]);
}
}
}
-void AbcExporter::operator()(float &progress, bool &was_canceled)
+void AbcExporter::operator()(short *do_update, float *progress, bool *was_canceled)
{
std::string scene_name;
@@ -332,10 +332,11 @@ void AbcExporter::operator()(float &progress, bool &was_canceled)
size_t i = 0;
for (; begin != end; ++begin) {
- progress = (++i / size);
+ *progress = (++i / size);
+ *do_update = 1;
if (G.is_break) {
- was_canceled = true;
+ *was_canceled = true;
break;
}
@@ -345,7 +346,7 @@ void AbcExporter::operator()(float &progress, bool &was_canceled)
setCurrentFrame(m_bmain, frame);
if (shape_frames.count(frame) != 0) {
- for (int i = 0, e = m_shapes.size(); i != e; ++i) {
+ for (int i = 0, e = m_shapes.size(); i != e; i++) {
m_shapes[i]->write();
}
}
diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h
index e6a7a3fc7f4..a73289fcf95 100644
--- a/source/blender/alembic/intern/abc_exporter.h
+++ b/source/blender/alembic/intern/abc_exporter.h
@@ -104,7 +104,7 @@ class AbcExporter {
AbcExporter(Main *bmain, const char *filename, ExportSettings &settings);
~AbcExporter();
- void operator()(float &progress, bool &was_canceled);
+ void operator()(short *do_update, float *progress, bool *was_canceled);
protected:
void getShutterSamples(unsigned int nr_of_samples,
diff --git a/source/blender/alembic/intern/abc_hair.cc b/source/blender/alembic/intern/abc_hair.cc
index b2489169856..98387be2e61 100644
--- a/source/blender/alembic/intern/abc_hair.cc
+++ b/source/blender/alembic/intern/abc_hair.cc
@@ -79,10 +79,14 @@ void AbcHairWriter::do_write()
if (m_psys->pathcache) {
ParticleSettings *part = m_psys->part;
+ bool export_children = m_settings.export_child_hairs && m_psys->childcache &&
+ part->childtype != 0;
- write_hair_sample(mesh, part, verts, norm_values, uv_values, hvertices);
+ if (!export_children || part->draw & PART_DRAW_PARENT) {
+ write_hair_sample(mesh, part, verts, norm_values, uv_values, hvertices);
+ }
- if (m_settings.export_child_hairs && m_psys->childcache) {
+ if (export_children) {
write_hair_child_sample(mesh, part, verts, norm_values, uv_values, hvertices);
}
}
@@ -139,7 +143,7 @@ void AbcHairWriter::write_hair_sample(Mesh *mesh,
float normal[3];
Imath::V3f tmp_nor;
- for (int p = 0; p < m_psys->totpart; ++p, ++pa) {
+ for (int p = 0; p < m_psys->totpart; p++, pa++) {
/* underlying info for faces-only emission */
path = cache[p];
@@ -173,7 +177,7 @@ void AbcHairWriter::write_hair_sample(Mesh *mesh,
const int num = (pa->num_dmcache >= 0) ? pa->num_dmcache : pa->num;
/* iterate over all faces to find a corresponding underlying UV */
- for (int n = 0; n < mesh->totface; ++n) {
+ for (int n = 0; n < mesh->totface; n++) {
MFace *face = &mface[n];
MTFace *tface = mtface + n;
unsigned int vtx[4];
@@ -183,7 +187,7 @@ void AbcHairWriter::write_hair_sample(Mesh *mesh,
vtx[3] = face->v4;
bool found = false;
- for (int o = 0; o < 4; ++o) {
+ for (int o = 0; o < 4; o++) {
if (o > 2 && vtx[o] == 0) {
break;
}
@@ -210,7 +214,7 @@ void AbcHairWriter::write_hair_sample(Mesh *mesh,
int steps = path->segments + 1;
hvertices.push_back(steps);
- for (k = 0; k < steps; ++k, ++path) {
+ for (k = 0; k < steps; k++, path++) {
float vert[3];
copy_v3_v3(vert, path->co);
mul_m4_v3(inv_mat, vert);
@@ -240,7 +244,7 @@ void AbcHairWriter::write_hair_child_sample(Mesh *mesh,
ChildParticle *pc = m_psys->child;
- for (int p = 0; p < m_psys->totchild; ++p, ++pc) {
+ for (int p = 0; p < m_psys->totchild; p++, pc++) {
path = cache[p];
if (part->from == PART_FROM_FACE && part->childtype != PART_CHILD_PARTICLES && mtface) {
@@ -278,7 +282,7 @@ void AbcHairWriter::write_hair_child_sample(Mesh *mesh,
int steps = path->segments + 1;
hvertices.push_back(steps);
- for (int k = 0; k < steps; ++k) {
+ for (int k = 0; k < steps; k++) {
float vert[3];
copy_v3_v3(vert, path->co);
mul_m4_v3(inv_mat, vert);
@@ -286,7 +290,7 @@ void AbcHairWriter::write_hair_child_sample(Mesh *mesh,
/* Convert Z-up to Y-up. */
verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1]));
- ++path;
+ path++;
}
}
}
diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc
index 8728303923a..12c59964a8c 100644
--- a/source/blender/alembic/intern/abc_mesh.cc
+++ b/source/blender/alembic/intern/abc_mesh.cc
@@ -116,7 +116,7 @@ static void get_vertices(struct Mesh *mesh, std::vector<Imath::V3f> &points)
MVert *verts = mesh->mvert;
- for (int i = 0, e = mesh->totvert; i < e; ++i) {
+ for (int i = 0, e = mesh->totvert; i < e; i++) {
copy_yup_from_zup(points[i].getValue(), verts[i].co);
}
}
@@ -137,7 +137,7 @@ static void get_topology(struct Mesh *mesh,
loop_counts.reserve(num_poly);
/* NOTE: data needs to be written in the reverse order. */
- for (int i = 0; i < num_poly; ++i) {
+ for (int i = 0; i < num_poly; i++) {
MPoly &poly = mpoly[i];
loop_counts.push_back(poly.totloop);
@@ -145,7 +145,7 @@ static void get_topology(struct Mesh *mesh,
MLoop *loop = mloop + poly.loopstart + (poly.totloop - 1);
- for (int j = 0; j < poly.totloop; ++j, --loop) {
+ for (int j = 0; j < poly.totloop; j++, loop--) {
poly_verts.push_back(loop->v);
}
}
@@ -164,7 +164,7 @@ static void get_creases(struct Mesh *mesh,
MEdge *edge = mesh->medge;
- for (int i = 0, e = mesh->totedge; i < e; ++i) {
+ for (int i = 0, e = mesh->totedge; i < e; i++) {
const float sharpness = static_cast<float>(edge[i].crease) * factor;
if (sharpness != 0.0f) {
@@ -185,7 +185,7 @@ static void get_vertex_normals(struct Mesh *mesh, std::vector<Imath::V3f> &norma
MVert *verts = mesh->mvert;
float no[3];
- for (int i = 0, e = mesh->totvert; i < e; ++i) {
+ for (int i = 0, e = mesh->totvert; i < e; i++) {
normal_short_to_float_v3(no, verts[i].no);
copy_yup_from_zup(normals[i].getValue(), no);
}
@@ -209,8 +209,8 @@ static void get_loop_normals(struct Mesh *mesh, std::vector<Imath::V3f> &normals
int abc_index = 0;
if (lnors) {
- for (int i = 0, e = mesh->totpoly; i < e; ++i, ++mp) {
- for (int j = mp->totloop - 1; j >= 0; --j, ++abc_index) {
+ for (int i = 0, e = mesh->totpoly; i < e; i++, mp++) {
+ for (int j = mp->totloop - 1; j >= 0; j--, abc_index++) {
int blender_index = mp->loopstart + j;
copy_yup_from_zup(normals[abc_index].getValue(), lnors[blender_index]);
}
@@ -219,20 +219,20 @@ static void get_loop_normals(struct Mesh *mesh, std::vector<Imath::V3f> &normals
else {
float no[3];
- for (int i = 0, e = mesh->totpoly; i < e; ++i, ++mp) {
+ for (int i = 0, e = mesh->totpoly; i < e; i++, mp++) {
ml = mloop + mp->loopstart + (mp->totloop - 1);
/* Flat shaded, use common normal for all verts. */
if ((mp->flag & ME_SMOOTH) == 0) {
BKE_mesh_calc_poly_normal(mp, ml - (mp->totloop - 1), verts, no);
- for (int j = 0; j < mp->totloop; --ml, ++j, ++abc_index) {
+ for (int j = 0; j < mp->totloop; ml--, j++, abc_index++) {
copy_yup_from_zup(normals[abc_index].getValue(), no);
}
}
else {
/* Smooth shaded, use individual vert normals. */
- for (int j = 0; j < mp->totloop; --ml, ++j, ++abc_index) {
+ for (int j = 0; j < mp->totloop; ml--, j++, abc_index++) {
normal_short_to_float_v3(no, verts[ml->v].no);
copy_yup_from_zup(normals[abc_index].getValue(), no);
}
@@ -561,7 +561,7 @@ Mesh *AbcGenericMeshWriter::getFinalMesh(bool &r_needsfree)
BM_mesh_triangulate(bm, quad_method, ngon_method, 4, tag_only, NULL, NULL, NULL);
- Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
if (r_needsfree) {
@@ -615,7 +615,7 @@ void AbcGenericMeshWriter::getVelocities(struct Mesh *mesh, std::vector<Imath::V
if (fss->meshVelocities) {
float *mesh_vels = reinterpret_cast<float *>(fss->meshVelocities);
- for (int i = 0; i < totverts; ++i) {
+ for (int i = 0; i < totverts; i++) {
copy_yup_from_zup(vels[i].getValue(), mesh_vels);
mesh_vels += 3;
}
@@ -631,7 +631,7 @@ void AbcGenericMeshWriter::getGeoGroups(struct Mesh *mesh,
const int num_poly = mesh->totpoly;
MPoly *polygons = mesh->mpoly;
- for (int i = 0; i < num_poly; ++i) {
+ for (int i = 0; i < num_poly; i++) {
MPoly &current_poly = polygons[i];
short mnr = current_poly.mat_nr;
@@ -658,7 +658,7 @@ void AbcGenericMeshWriter::getGeoGroups(struct Mesh *mesh,
std::vector<int32_t> faceArray;
- for (int i = 0, e = mesh->totface; i < e; ++i) {
+ for (int i = 0, e = mesh->totface; i < e; i++) {
faceArray.push_back(i);
}
@@ -707,7 +707,7 @@ static void assign_materials(Main *bmain,
std::map<std::string, int>::const_iterator it = mat_index_map.begin();
int matcount = 0;
- for (; it != mat_index_map.end(); ++it, ++matcount) {
+ for (; it != mat_index_map.end(); ++it, matcount++) {
if (!BKE_object_material_slot_add(bmain, ob)) {
can_assign = false;
break;
@@ -770,7 +770,7 @@ static void read_mverts_interp(MVert *mverts,
const float weight)
{
float tmp[3];
- for (int i = 0; i < positions->size(); ++i) {
+ for (int i = 0; i < positions->size(); i++) {
MVert &mvert = mverts[i];
const Imath::V3f &floor_pos = (*positions)[i];
const Imath::V3f &ceil_pos = (*ceil_positions)[i];
@@ -801,7 +801,7 @@ void read_mverts(MVert *mverts,
const P3fArraySamplePtr &positions,
const N3fArraySamplePtr &normals)
{
- for (int i = 0; i < positions->size(); ++i) {
+ for (int i = 0; i < positions->size(); i++) {
MVert &mvert = mverts[i];
Imath::V3f pos_in = (*positions)[i];
@@ -839,7 +839,7 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
unsigned int rev_loop_index = 0;
unsigned int uv_index = 0;
- for (int i = 0; i < face_counts->size(); ++i) {
+ for (int i = 0; i < face_counts->size(); i++) {
const int face_size = (*face_counts)[i];
MPoly &poly = mpolys[i];
@@ -856,7 +856,7 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
/* NOTE: Alembic data is stored in the reverse order. */
rev_loop_index = loop_index + (face_size - 1);
- for (int f = 0; f < face_size; ++f, ++loop_index, --rev_loop_index) {
+ for (int f = 0; f < face_size; f++, loop_index++, rev_loop_index--) {
MLoop &loop = mloops[rev_loop_index];
loop.v = (*face_indices)[loop_index];
@@ -899,9 +899,9 @@ static void process_normals(CDStreamConfig &config, const AbcMeshData &mesh_data
MPoly *mpoly = mesh->mpoly;
int abc_index = 0;
- for (int i = 0, e = mesh->totpoly; i < e; ++i, ++mpoly) {
+ for (int i = 0, e = mesh->totpoly; i < e; i++, mpoly++) {
/* As usual, ABC orders the loops in reverse. */
- for (int j = mpoly->totloop - 1; j >= 0; --j, ++abc_index) {
+ for (int j = mpoly->totloop - 1; j >= 0; j--, abc_index++) {
int blender_index = mpoly->loopstart + j;
copy_zup_from_yup(lnors[blender_index], loop_normals[abc_index].getValue());
}
@@ -1192,8 +1192,6 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
existing_mesh, positions->size(), 0, 0, face_indices->size(), face_counts->size());
settings.read_flag |= MOD_MESHSEQ_READ_ALL;
- /* XXX fixme after 2.80; mesh->flag isn't copied by BKE_mesh_new_nomain_from_template() */
- new_mesh->flag |= (existing_mesh->flag & ME_AUTOSMOOTH);
}
else {
/* If the face count changed (e.g. by triangulation), only read points.
@@ -1246,7 +1244,7 @@ void AbcMeshReader::assign_facesets_to_mpoly(const ISampleSelector &sample_sel,
int current_mat = 0;
- for (int i = 0; i < face_sets.size(); ++i) {
+ for (int i = 0; i < face_sets.size(); i++) {
const std::string &grp_name = face_sets[i];
if (r_mat_map.find(grp_name) == r_mat_map.end()) {
@@ -1292,7 +1290,7 @@ void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const ISampleSel
ABC_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2)
{
- for (int i = 0, e = totedge; i < e; ++i) {
+ for (int i = 0, e = totedge; i < e; i++) {
MEdge &edge = edges[i];
if (edge.v1 == v1 && edge.v2 == v2) {
@@ -1416,11 +1414,24 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
Int32ArraySamplePtr indices = sample.getCreaseIndices();
Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses();
- MEdge *edges = mesh->medge;
-
if (indices && sharpnesses) {
- for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, ++s) {
- MEdge *edge = find_edge(edges, mesh->totedge, (*indices)[i], (*indices)[i + 1]);
+ MEdge *edges = mesh->medge;
+ int totedge = mesh->totedge;
+
+ for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, s++) {
+ int v1 = (*indices)[i];
+ int v2 = (*indices)[i + 1];
+
+ if (v2 < v1) {
+ /* It appears to be common to store edges with the smallest index first, in which case this
+ * prevents us from doing the second search below. */
+ std::swap(v1, v2);
+ }
+
+ MEdge *edge = find_edge(edges, totedge, v1, v2);
+ if (edge == NULL) {
+ edge = find_edge(edges, totedge, v2, v1);
+ }
if (edge) {
edge->crease = unit_float_to_uchar_clamp((*sharpnesses)[s]);
diff --git a/source/blender/alembic/intern/abc_nurbs.cc b/source/blender/alembic/intern/abc_nurbs.cc
index c78cc4570c9..739276dffa6 100644
--- a/source/blender/alembic/intern/abc_nurbs.cc
+++ b/source/blender/alembic/intern/abc_nurbs.cc
@@ -74,7 +74,7 @@ AbcNurbsWriter::AbcNurbsWriter(Object *ob,
Curve *curve = static_cast<Curve *>(m_object->data);
size_t numNurbs = BLI_listbase_count(&curve->nurb);
- for (size_t i = 0; i < numNurbs; ++i) {
+ for (size_t i = 0; i < numNurbs; i++) {
std::stringstream str;
str << m_name << '_' << i;
@@ -106,7 +106,7 @@ static void get_knots(std::vector<float> &knots, const int num_knots, float *nu_
knots.push_back(0.0f);
- for (int i = 0; i < num_knots; ++i) {
+ for (int i = 0; i < num_knots; i++) {
knots.push_back(nu_knots[i]);
}
@@ -136,7 +136,7 @@ void AbcNurbsWriter::do_write()
}
size_t count = 0;
- for (Nurb *nu = static_cast<Nurb *>(nulb->first); nu; nu = nu->next, ++count) {
+ for (Nurb *nu = static_cast<Nurb *>(nulb->first); nu; nu = nu->next, count++) {
std::vector<float> knotsU;
get_knots(knotsU, KNOTSU(nu), nu->knotsu);
@@ -149,7 +149,7 @@ void AbcNurbsWriter::do_write()
const BPoint *bp = nu->bp;
- for (int i = 0; i < size; ++i, ++bp) {
+ for (int i = 0; i < size; i++, bp++) {
copy_yup_from_zup(positions[i].getValue(), bp->vec);
weights[i] = bp->vec[3];
}
@@ -229,7 +229,7 @@ static bool set_knots(const FloatArraySamplePtr &knots, float *&nu_knots)
const size_t num_knots = knots->size() - 2;
nu_knots = static_cast<float *>(MEM_callocN(num_knots * sizeof(float), "abc_setsplineknotsu"));
- for (size_t i = 0; i < num_knots; ++i) {
+ for (size_t i = 0; i < num_knots; i++) {
nu_knots[i] = (*knots)[i + 1];
}
@@ -281,7 +281,7 @@ void AbcNurbsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSele
BPoint *bp = nu->bp;
float posw_in = 1.0f;
- for (int i = 0; i < num_points; ++i, ++bp) {
+ for (int i = 0; i < num_points; i++, bp++) {
const Imath::V3f &pos_in = (*positions)[i];
if (weights) {
@@ -349,7 +349,7 @@ void AbcNurbsReader::getNurbsPatches(const IObject &obj)
return;
}
- for (int i = 0; i < num_children; ++i) {
+ for (int i = 0; i < num_children; i++) {
bool ok = true;
IObject child(obj, obj.getChildHeader(i).getName());
diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_object.cc
index ebebbc0da1e..b05246371fa 100644
--- a/source/blender/alembic/intern/abc_object.cc
+++ b/source/blender/alembic/intern/abc_object.cc
@@ -195,14 +195,14 @@ static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1,
* the matrices manually.
*/
- for (int i = 0; i < 4; ++i) {
- for (int j = 0; j < 4; ++j) {
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
mat0[i][j] = static_cast<float>(m0[i][j]);
}
}
- for (int i = 0; i < 4; ++i) {
- for (int j = 0; j < 4; ++j) {
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
mat1[i][j] = static_cast<float>(m1[i][j]);
}
}
@@ -211,8 +211,8 @@ static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1,
Imath::M44d m;
- for (int i = 0; i < 4; ++i) {
- for (int j = 0; j < 4; ++j) {
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
m[i][j] = ret[i][j];
}
}
@@ -389,11 +389,11 @@ int AbcObjectReader::refcount() const
void AbcObjectReader::incref()
{
- ++m_refcount;
+ m_refcount++;
}
void AbcObjectReader::decref()
{
- --m_refcount;
+ m_refcount--;
BLI_assert(m_refcount >= 0);
}
diff --git a/source/blender/alembic/intern/abc_transform.cc b/source/blender/alembic/intern/abc_transform.cc
index 08f8eb8bd8f..505acfc164a 100644
--- a/source/blender/alembic/intern/abc_transform.cc
+++ b/source/blender/alembic/intern/abc_transform.cc
@@ -122,7 +122,7 @@ Imath::Box3d AbcTransformWriter::bounds()
{
Imath::Box3d bounds;
- for (int i = 0; i < m_children.size(); ++i) {
+ for (int i = 0; i < m_children.size(); i++) {
Imath::Box3d box(m_children[i]->bounds());
bounds.extendBy(box);
}
diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc
index 2fc340f73ce..b6743c8b363 100644
--- a/source/blender/alembic/intern/abc_util.cc
+++ b/source/blender/alembic/intern/abc_util.cc
@@ -90,8 +90,8 @@ Imath::M44d convert_matrix(float mat[4][4])
{
Imath::M44d m;
- for (int i = 0; i < 4; ++i) {
- for (int j = 0; j < 4; ++j) {
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
m[i][j] = mat[i][j];
}
}
@@ -226,8 +226,8 @@ void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMod
void convert_matrix(const Imath::M44d &xform, Object *ob, float r_mat[4][4])
{
- for (int i = 0; i < 4; ++i) {
- for (int j = 0; j < 4; ++j) {
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
r_mat[i][j] = static_cast<float>(xform[i][j]);
}
}
diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc
index dc525e0c46c..1034c5b319f 100644
--- a/source/blender/alembic/intern/alembic_capi.cc
+++ b/source/blender/alembic/intern/alembic_capi.cc
@@ -129,7 +129,7 @@ static bool gather_objects_paths(const IObject &object, ListBase *object_paths)
size_t children_claiming_this_object = 0;
size_t num_children = object.getNumChildren();
- for (size_t i = 0; i < num_children; ++i) {
+ for (size_t i = 0; i < num_children; i++) {
bool child_claims_this_object = gather_objects_paths(object.getChild(i), object_paths);
children_claiming_this_object += child_claims_this_object ? 1 : 0;
}
@@ -173,9 +173,11 @@ static bool gather_objects_paths(const IObject &object, ListBase *object_paths)
return parent_is_part_of_this_object;
}
-AbcArchiveHandle *ABC_create_handle(const char *filename, ListBase *object_paths)
+AbcArchiveHandle *ABC_create_handle(struct Main *bmain,
+ const char *filename,
+ ListBase *object_paths)
{
- ArchiveReader *archive = new ArchiveReader(filename);
+ ArchiveReader *archive = new ArchiveReader(bmain, filename);
if (!archive->valid()) {
delete archive;
@@ -222,6 +224,7 @@ static void find_iobject(const IObject &object, IObject &ret, const std::string
struct ExportJobData {
ViewLayer *view_layer;
Main *bmain;
+ wmWindowManager *wm;
char filename[1024];
ExportSettings settings;
@@ -246,8 +249,7 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo
* scene frame in separate threads
*/
G.is_rendering = true;
- BKE_spacedata_draw_locks(true);
-
+ WM_set_locked_interface(data->wm, true);
G.is_break = false;
DEG_graph_build_from_view_layer(
@@ -261,7 +263,7 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo
const int orig_frame = CFRA;
data->was_canceled = false;
- exporter(*data->progress, data->was_canceled);
+ exporter(do_update, progress, &data->was_canceled);
if (CFRA != orig_frame) {
CFRA = orig_frame;
@@ -296,7 +298,7 @@ static void export_endjob(void *customdata)
}
G.is_rendering = false;
- BKE_spacedata_draw_locks(false);
+ WM_set_locked_interface(data->wm, false);
}
bool ABC_export(Scene *scene,
@@ -310,6 +312,7 @@ bool ABC_export(Scene *scene,
job->view_layer = CTX_data_view_layer(C);
job->bmain = CTX_data_main(C);
+ job->wm = CTX_wm_manager(C);
job->export_ok = false;
BLI_strncpy(job->filename, filepath, 1024);
@@ -330,7 +333,7 @@ bool ABC_export(Scene *scene,
* hardcore refactoring. */
new (&job->settings) ExportSettings();
job->settings.scene = scene;
- job->settings.depsgraph = DEG_graph_new(scene, job->view_layer, DAG_EVAL_RENDER);
+ job->settings.depsgraph = DEG_graph_new(job->bmain, scene, job->view_layer, DAG_EVAL_RENDER);
/* TODO(Sybren): for now we only export the active scene layer.
* Later in the 2.8 development process this may be replaced by using
@@ -452,7 +455,7 @@ static std::pair<bool, AbcObjectReader *> visit_object(
AbcObjectReader::ptr_vector claiming_child_readers;
AbcObjectReader::ptr_vector nonclaiming_child_readers;
AbcObjectReader::ptr_vector assign_as_parent;
- for (size_t i = 0; i < num_children; ++i) {
+ for (size_t i = 0; i < num_children; i++) {
const IObject ichild = object.getChild(i);
/* TODO: When we only support C++11, use std::tie() instead. */
@@ -649,7 +652,7 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
WM_set_locked_interface(data->wm, true);
- ArchiveReader *archive = new ArchiveReader(data->filename);
+ ArchiveReader *archive = new ArchiveReader(data->bmain, data->filename);
if (!archive->valid()) {
#ifndef WITH_ALEMBIC_HDF5
diff --git a/source/blender/avi/intern/avi_options.c b/source/blender/avi/intern/avi_options.c
index 4f7e26c874c..65db8c19397 100644
--- a/source/blender/avi/intern/avi_options.c
+++ b/source/blender/avi/intern/avi_options.c
@@ -42,8 +42,8 @@ AviError AVI_set_compress_option(
(void)stream; /* unused */
- if (movie->header->TotalFrames !=
- 0) { /* Can't change params after we have already started writing frames */
+ if (movie->header->TotalFrames != 0) {
+ /* Can't change params after we have already started writing frames. */
return AVI_ERROR_OPTION;
}
diff --git a/source/blender/blendthumb/CMakeLists.txt b/source/blender/blendthumb/CMakeLists.txt
new file mode 100644
index 00000000000..6c786dfcc7a
--- /dev/null
+++ b/source/blender/blendthumb/CMakeLists.txt
@@ -0,0 +1,38 @@
+# ***** 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) 2006, Blender Foundation
+# All rights reserved.
+# ***** END GPL LICENSE BLOCK *****
+
+#-----------------------------------------------------------------------------
+include_directories(${ZLIB_INCLUDE_DIRS})
+
+set(SRC
+ src/BlenderThumb.cpp
+ src/BlendThumb.def
+ src/BlendThumb.rc
+ src/Dll.cpp
+)
+
+add_library(BlendThumb SHARED ${SRC})
+target_link_libraries(BlendThumb ${ZLIB_LIBRARIES})
+
+install(
+ FILES $<TARGET_FILE:BlendThumb>
+ COMPONENT Blender
+ DESTINATION "."
+)
diff --git a/source/blender/blendthumb/src/BlendThumb.def b/source/blender/blendthumb/src/BlendThumb.def
new file mode 100644
index 00000000000..71f9236735f
--- /dev/null
+++ b/source/blender/blendthumb/src/BlendThumb.def
@@ -0,0 +1,5 @@
+EXPORTS
+ DllGetClassObject PRIVATE
+ DllCanUnloadNow PRIVATE
+ DllRegisterServer PRIVATE
+ DllUnregisterServer PRIVATE \ No newline at end of file
diff --git a/source/blender/blendthumb/src/BlendThumb.rc b/source/blender/blendthumb/src/BlendThumb.rc
new file mode 100644
index 00000000000..5dfd416b0c5
--- /dev/null
+++ b/source/blender/blendthumb/src/BlendThumb.rc
@@ -0,0 +1,26 @@
+#define IDR_VERSION1 1
+
+IDR_VERSION1 VERSIONINFO
+FILEVERSION 1,4,0,0
+PRODUCTVERSION 2,78,0,0
+FILEOS 0x00000004
+FILETYPE 0x00000002
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "FFFF04B0"
+ BEGIN
+ VALUE "FileVersion", "1.4\0"
+ VALUE "ProductVersion", "2.78\0"
+ VALUE "FileDescription", "Blender Thumbnail Handler\0"
+ VALUE "OriginalFilename", "BlendThumb.dll\0"
+ VALUE "ProductName", "Blender\0"
+ VALUE "LegalCopyright", "GPL2, 2016\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0409, 0x04B0
+ END
+END
+
diff --git a/source/blender/blendthumb/src/BlenderThumb.cpp b/source/blender/blendthumb/src/BlenderThumb.cpp
new file mode 100644
index 00000000000..be0adffbdfd
--- /dev/null
+++ b/source/blender/blendthumb/src/BlenderThumb.cpp
@@ -0,0 +1,321 @@
+/*
+ * 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 <shlwapi.h>
+#include <thumbcache.h> // For IThumbnailProvider.
+#include <new>
+
+#pragma comment(lib, "shlwapi.lib")
+
+// this thumbnail provider implements IInitializeWithStream to enable being hosted
+// in an isolated process for robustness
+
+class CBlendThumb : public IInitializeWithStream, public IThumbnailProvider {
+ public:
+ CBlendThumb() : _cRef(1), _pStream(NULL)
+ {
+ }
+
+ virtual ~CBlendThumb()
+ {
+ if (_pStream) {
+ _pStream->Release();
+ }
+ }
+
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv)
+ {
+ static const QITAB qit[] = {
+ QITABENT(CBlendThumb, IInitializeWithStream),
+ QITABENT(CBlendThumb, IThumbnailProvider),
+ {0},
+ };
+ return QISearch(this, qit, riid, ppv);
+ }
+
+ IFACEMETHODIMP_(ULONG) AddRef()
+ {
+ return InterlockedIncrement(&_cRef);
+ }
+
+ IFACEMETHODIMP_(ULONG) Release()
+ {
+ ULONG cRef = InterlockedDecrement(&_cRef);
+ if (!cRef) {
+ delete this;
+ }
+ return cRef;
+ }
+
+ // IInitializeWithStream
+ IFACEMETHODIMP Initialize(IStream *pStream, DWORD grfMode);
+
+ // IThumbnailProvider
+ IFACEMETHODIMP GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha);
+
+ private:
+ long _cRef;
+ IStream *_pStream; // provided during initialization.
+};
+
+HRESULT CBlendThumb_CreateInstance(REFIID riid, void **ppv)
+{
+ CBlendThumb *pNew = new (std::nothrow) CBlendThumb();
+ HRESULT hr = pNew ? S_OK : E_OUTOFMEMORY;
+ if (SUCCEEDED(hr)) {
+ hr = pNew->QueryInterface(riid, ppv);
+ pNew->Release();
+ }
+ return hr;
+}
+
+// IInitializeWithStream
+IFACEMETHODIMP CBlendThumb::Initialize(IStream *pStream, DWORD)
+{
+ HRESULT hr = E_UNEXPECTED; // can only be inited once
+ if (_pStream == NULL) {
+ // take a reference to the stream if we have not been inited yet
+ hr = pStream->QueryInterface(&_pStream);
+ }
+ return hr;
+}
+
+#include <math.h>
+#include <zlib.h>
+#include "Wincodec.h"
+const unsigned char gzip_magic[3] = {0x1f, 0x8b, 0x08};
+
+// IThumbnailProvider
+IFACEMETHODIMP CBlendThumb::GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha)
+{
+ ULONG BytesRead;
+ HRESULT hr = S_FALSE;
+ LARGE_INTEGER SeekPos;
+
+ // Compressed?
+ unsigned char in_magic[3];
+ _pStream->Read(&in_magic, 3, &BytesRead);
+ bool gzipped = true;
+ for (int i = 0; i < 3; i++)
+ if (in_magic[i] != gzip_magic[i]) {
+ gzipped = false;
+ break;
+ }
+
+ if (gzipped) {
+ // Zlib inflate
+ z_stream stream;
+ stream.zalloc = Z_NULL;
+ stream.zfree = Z_NULL;
+ stream.opaque = Z_NULL;
+
+ // Get compressed file length
+ SeekPos.QuadPart = 0;
+ _pStream->Seek(SeekPos, STREAM_SEEK_END, NULL);
+
+ // Get compressed and uncompressed size
+ uLong source_size;
+ uLongf dest_size;
+ // SeekPos.QuadPart = -4; // last 4 bytes define size of uncompressed file
+ // ULARGE_INTEGER Tell;
+ //_pStream->Seek(SeekPos,STREAM_SEEK_END,&Tell);
+ // source_size = (uLong)Tell.QuadPart + 4; // src
+ //_pStream->Read(&dest_size,4,&BytesRead); // dest
+ dest_size = 1024 * 70; // thumbnail is currently always inside the first 65KB...if it moves or
+ // enlargens this line will have to change or go!
+ source_size = (uLong)max(SeekPos.QuadPart, dest_size); // for safety, assume no compression
+
+ // Input
+ Bytef *src = new Bytef[source_size];
+ stream.next_in = (Bytef *)src;
+ stream.avail_in = (uInt)source_size;
+
+ // Output
+ Bytef *dest = new Bytef[dest_size];
+ stream.next_out = (Bytef *)dest;
+ stream.avail_out = dest_size;
+
+ // IStream to src
+ SeekPos.QuadPart = 0;
+ _pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
+ _pStream->Read(src, source_size, &BytesRead);
+
+ // Do the inflation
+ int err;
+ err = inflateInit2(&stream, 16); // 16 means "gzip"...nice!
+ err = inflate(&stream, Z_FINISH);
+ err = inflateEnd(&stream);
+
+ // Replace the IStream, which is read-only
+ _pStream->Release();
+ _pStream = SHCreateMemStream(dest, dest_size);
+
+ delete[] src;
+ delete[] dest;
+ }
+
+ // Blender version, early out if sub 2.5
+ SeekPos.QuadPart = 9;
+ _pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
+ char version[4];
+ version[3] = '\0';
+ _pStream->Read(&version, 3, &BytesRead);
+ if (BytesRead != 3) {
+ return E_UNEXPECTED;
+ }
+ int iVersion = atoi(version);
+ if (iVersion < 250) {
+ return S_FALSE;
+ }
+
+ // 32 or 64 bit blend?
+ SeekPos.QuadPart = 7;
+ _pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
+
+ char _PointerSize;
+ _pStream->Read(&_PointerSize, 1, &BytesRead);
+
+ int PointerSize = _PointerSize == '_' ? 4 : 8;
+ int HeaderSize = 16 + PointerSize;
+
+ // Find and read thumbnail ("TEST") block
+ SeekPos.QuadPart = 12;
+ _pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
+ int BlockOffset = 12;
+ while (_pStream) {
+ // Scan current block
+ char BlockName[5];
+ BlockName[4] = '\0';
+ int BlockSize = 0;
+
+ if (_pStream->Read(BlockName, 4, &BytesRead) == S_OK &&
+ _pStream->Read((void *)&BlockSize, 4, &BytesRead) == S_OK) {
+ if (strcmp(BlockName, "TEST") != 0) {
+ SeekPos.QuadPart = BlockOffset += HeaderSize + BlockSize;
+ _pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
+ continue;
+ }
+ }
+ else {
+ break; // eof
+ }
+
+ // Found the block
+ SeekPos.QuadPart = BlockOffset + HeaderSize;
+ _pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
+
+ int width, height;
+ _pStream->Read((char *)&width, 4, &BytesRead);
+ _pStream->Read((char *)&height, 4, &BytesRead);
+ BlockSize -= 8;
+
+ // Isolate RGBA data
+ char *pRGBA = new char[BlockSize];
+ _pStream->Read(pRGBA, BlockSize, &BytesRead);
+
+ if (BytesRead != (ULONG)BlockSize) {
+ return E_UNEXPECTED;
+ }
+
+ // Convert to BGRA for Windows
+ for (int i = 0; i < BlockSize; i += 4) {
+#define RED_BYTE pRGBA[i]
+#define BLUE_BYTE pRGBA[i + 2]
+
+ char red = RED_BYTE;
+ RED_BYTE = BLUE_BYTE;
+ BLUE_BYTE = red;
+ }
+
+ // Flip vertically (Blender stores it upside-down)
+ unsigned int LineSize = width * 4;
+ char *FlippedImage = new char[BlockSize];
+ for (int i = 0; i < height; i++) {
+ if (0 != memcpy_s(&FlippedImage[(height - i - 1) * LineSize],
+ LineSize,
+ &pRGBA[i * LineSize],
+ LineSize)) {
+ return E_UNEXPECTED;
+ }
+ }
+ delete[] pRGBA;
+ pRGBA = FlippedImage;
+
+ // Create image
+ *phbmp = CreateBitmap(width, height, 1, 32, pRGBA);
+ if (!*phbmp) {
+ return E_FAIL;
+ }
+ *pdwAlpha = WTSAT_ARGB; // it's actually BGRA, not sure why this works
+
+ // Scale down if required
+ if ((unsigned)width > cx || (unsigned)height > cx) {
+ float scale = 1.0f / (max(width, height) / (float)cx);
+ LONG NewWidth = (LONG)(width * scale);
+ LONG NewHeight = (LONG)(height * scale);
+
+#ifdef _DEBUG
+# if 0
+ MessageBox(0, "Attach now", "Debugging", MB_OK);
+# endif
+#endif
+ IWICImagingFactory *pImgFac;
+ hr = CoCreateInstance(
+ CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pImgFac));
+
+ IWICBitmap *WICBmp;
+ hr = pImgFac->CreateBitmapFromHBITMAP(*phbmp, 0, WICBitmapUseAlpha, &WICBmp);
+
+ BITMAPINFO bmi = {};
+ bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
+ bmi.bmiHeader.biWidth = NewWidth;
+ bmi.bmiHeader.biHeight = -NewHeight;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+
+ BYTE *pBits;
+ HBITMAP ResizedHBmp = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void **)&pBits, NULL, 0);
+ hr = ResizedHBmp ? S_OK : E_OUTOFMEMORY;
+ if (SUCCEEDED(hr)) {
+ IWICBitmapScaler *pIScaler;
+ hr = pImgFac->CreateBitmapScaler(&pIScaler);
+ hr = pIScaler->Initialize(WICBmp, NewWidth, NewHeight, WICBitmapInterpolationModeFant);
+
+ WICRect rect = {0, 0, NewWidth, NewHeight};
+ hr = pIScaler->CopyPixels(&rect, NewWidth * 4, NewWidth * NewHeight * 4, pBits);
+
+ if (SUCCEEDED(hr)) {
+ DeleteObject(*phbmp);
+ *phbmp = ResizedHBmp;
+ }
+ else {
+ DeleteObject(ResizedHBmp);
+ }
+
+ pIScaler->Release();
+ }
+ WICBmp->Release();
+ pImgFac->Release();
+ }
+ else {
+ hr = S_OK;
+ }
+ break;
+ }
+ return hr;
+}
diff --git a/source/blender/blendthumb/src/Dll.cpp b/source/blender/blendthumb/src/Dll.cpp
new file mode 100644
index 00000000000..08b3d253be8
--- /dev/null
+++ b/source/blender/blendthumb/src/Dll.cpp
@@ -0,0 +1,280 @@
+/*
+ * 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 <objbase.h>
+#include <shlwapi.h>
+#include <thumbcache.h> // For IThumbnailProvider.
+#include <shlobj.h> // For SHChangeNotify
+#include <new>
+
+extern HRESULT CBlendThumb_CreateInstance(REFIID riid, void **ppv);
+
+#define SZ_CLSID_BLENDTHUMBHANDLER L"{D45F043D-F17F-4e8a-8435-70971D9FA46D}"
+#define SZ_BLENDTHUMBHANDLER L"Blender Thumbnail Handler"
+const CLSID CLSID_BlendThumbHandler = {
+ 0xd45f043d, 0xf17f, 0x4e8a, {0x84, 0x35, 0x70, 0x97, 0x1d, 0x9f, 0xa4, 0x6d}};
+
+typedef HRESULT (*PFNCREATEINSTANCE)(REFIID riid, void **ppvObject);
+struct CLASS_OBJECT_INIT {
+ const CLSID *pClsid;
+ PFNCREATEINSTANCE pfnCreate;
+};
+
+// add classes supported by this module here
+const CLASS_OBJECT_INIT c_rgClassObjectInit[] = {
+ {&CLSID_BlendThumbHandler, CBlendThumb_CreateInstance}};
+
+long g_cRefModule = 0;
+
+// Handle the DLL's module
+HINSTANCE g_hInst = NULL;
+
+// Standard DLL functions
+STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, void *)
+{
+ if (dwReason == DLL_PROCESS_ATTACH) {
+ g_hInst = hInstance;
+ DisableThreadLibraryCalls(hInstance);
+ }
+ return TRUE;
+}
+
+STDAPI DllCanUnloadNow()
+{
+ // Only allow the DLL to be unloaded after all outstanding references have been released
+ return (g_cRefModule == 0) ? S_OK : S_FALSE;
+}
+
+void DllAddRef()
+{
+ InterlockedIncrement(&g_cRefModule);
+}
+
+void DllRelease()
+{
+ InterlockedDecrement(&g_cRefModule);
+}
+
+class CClassFactory : public IClassFactory {
+ public:
+ static HRESULT CreateInstance(REFCLSID clsid,
+ const CLASS_OBJECT_INIT *pClassObjectInits,
+ size_t cClassObjectInits,
+ REFIID riid,
+ void **ppv)
+ {
+ *ppv = NULL;
+ HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
+ for (size_t i = 0; i < cClassObjectInits; i++) {
+ if (clsid == *pClassObjectInits[i].pClsid) {
+ IClassFactory *pClassFactory = new (std::nothrow)
+ CClassFactory(pClassObjectInits[i].pfnCreate);
+ hr = pClassFactory ? S_OK : E_OUTOFMEMORY;
+ if (SUCCEEDED(hr)) {
+ hr = pClassFactory->QueryInterface(riid, ppv);
+ pClassFactory->Release();
+ }
+ break; // match found
+ }
+ }
+ return hr;
+ }
+
+ CClassFactory(PFNCREATEINSTANCE pfnCreate) : _cRef(1), _pfnCreate(pfnCreate)
+ {
+ DllAddRef();
+ }
+
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv)
+ {
+ static const QITAB qit[] = {QITABENT(CClassFactory, IClassFactory), {0}};
+ return QISearch(this, qit, riid, ppv);
+ }
+
+ IFACEMETHODIMP_(ULONG) AddRef()
+ {
+ return InterlockedIncrement(&_cRef);
+ }
+
+ IFACEMETHODIMP_(ULONG) Release()
+ {
+ long cRef = InterlockedDecrement(&_cRef);
+ if (cRef == 0) {
+ delete this;
+ }
+ return cRef;
+ }
+
+ // IClassFactory
+ IFACEMETHODIMP CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
+ {
+ return punkOuter ? CLASS_E_NOAGGREGATION : _pfnCreate(riid, ppv);
+ }
+
+ IFACEMETHODIMP LockServer(BOOL fLock)
+ {
+ if (fLock) {
+ DllAddRef();
+ }
+ else {
+ DllRelease();
+ }
+ return S_OK;
+ }
+
+ private:
+ ~CClassFactory()
+ {
+ DllRelease();
+ }
+
+ long _cRef;
+ PFNCREATEINSTANCE _pfnCreate;
+};
+
+STDAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **ppv)
+{
+ return CClassFactory::CreateInstance(
+ clsid, c_rgClassObjectInit, ARRAYSIZE(c_rgClassObjectInit), riid, ppv);
+}
+
+// A struct to hold the information required for a registry entry
+
+struct REGISTRY_ENTRY {
+ HKEY hkeyRoot;
+ PCWSTR pszKeyName;
+ PCWSTR pszValueName;
+ DWORD dwValueType;
+ PCWSTR pszData;
+};
+
+// Creates a registry key (if needed) and sets the default value of the key
+
+HRESULT CreateRegKeyAndSetValue(const REGISTRY_ENTRY *pRegistryEntry)
+{
+ HKEY hKey;
+ HRESULT hr = HRESULT_FROM_WIN32(RegCreateKeyExW(pRegistryEntry->hkeyRoot,
+ pRegistryEntry->pszKeyName,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_SET_VALUE,
+ NULL,
+ &hKey,
+ NULL));
+ if (SUCCEEDED(hr)) {
+ // All this just to support REG_DWORD...
+ DWORD size;
+ DWORD data;
+ BYTE *lpData = (LPBYTE)pRegistryEntry->pszData;
+ switch (pRegistryEntry->dwValueType) {
+ case REG_SZ:
+ size = ((DWORD)wcslen(pRegistryEntry->pszData) + 1) * sizeof(WCHAR);
+ break;
+ case REG_DWORD:
+ size = sizeof(DWORD);
+ data = (DWORD)pRegistryEntry->pszData;
+ lpData = (BYTE *)&data;
+ break;
+ default:
+ return E_INVALIDARG;
+ }
+
+ hr = HRESULT_FROM_WIN32(RegSetValueExW(
+ hKey, pRegistryEntry->pszValueName, 0, pRegistryEntry->dwValueType, lpData, size));
+ RegCloseKey(hKey);
+ }
+ return hr;
+}
+
+//
+// Registers this COM server
+//
+STDAPI DllRegisterServer()
+{
+ HRESULT hr;
+
+ WCHAR szModuleName[MAX_PATH];
+
+ if (!GetModuleFileNameW(g_hInst, szModuleName, ARRAYSIZE(szModuleName))) {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ else {
+ const REGISTRY_ENTRY rgRegistryEntries[] = {
+ // RootKey KeyName ValueName ValueType Data
+ {HKEY_CURRENT_USER,
+ L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER,
+ NULL,
+ REG_SZ,
+ SZ_BLENDTHUMBHANDLER},
+ {HKEY_CURRENT_USER,
+ L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER L"\\InProcServer32",
+ NULL,
+ REG_SZ,
+ szModuleName},
+ {HKEY_CURRENT_USER,
+ L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER L"\\InProcServer32",
+ L"ThreadingModel",
+ REG_SZ,
+ L"Apartment"},
+ {HKEY_CURRENT_USER,
+ L"Software\\Classes\\.blend\\",
+ L"Treatment",
+ REG_DWORD,
+ 0}, // doesn't appear to do anything...
+ {HKEY_CURRENT_USER,
+ L"Software\\Classes\\.blend\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}",
+ NULL,
+ REG_SZ,
+ SZ_CLSID_BLENDTHUMBHANDLER},
+ };
+
+ hr = S_OK;
+ for (int i = 0; i < ARRAYSIZE(rgRegistryEntries) && SUCCEEDED(hr); i++) {
+ hr = CreateRegKeyAndSetValue(&rgRegistryEntries[i]);
+ }
+ }
+ if (SUCCEEDED(hr)) {
+ // This tells the shell to invalidate the thumbnail cache. This is important because any
+ // .blend files viewed before registering this handler would otherwise show cached blank
+ // thumbnails.
+ SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
+ }
+ return hr;
+}
+
+//
+// Unregisters this COM server
+//
+STDAPI DllUnregisterServer()
+{
+ HRESULT hr = S_OK;
+
+ const PCWSTR rgpszKeys[] = {
+ L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER,
+ L"Software\\Classes\\.blend\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}"};
+
+ // Delete the registry entries
+ for (int i = 0; i < ARRAYSIZE(rgpszKeys) && SUCCEEDED(hr); i++) {
+ hr = HRESULT_FROM_WIN32(RegDeleteTreeW(HKEY_CURRENT_USER, rgpszKeys[i]));
+ if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) {
+ // If the registry entry has already been deleted, say S_OK.
+ hr = S_OK;
+ }
+ }
+ return hr;
+}
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index 793e9805899..8e1ff77b1c7 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -608,7 +608,7 @@ void BLF_draw_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_in
BLF_RESULT_CHECK_INIT(r_info);
- if (font && font->glyph_cache) {
+ if (font) {
blf_draw_gl__start(font);
if (font->flags & BLF_WORD_WRAP) {
blf_font_draw__wrap(font, str, len, r_info);
@@ -634,7 +634,7 @@ void BLF_draw_ascii_ex(int fontid, const char *str, size_t len, struct ResultBLF
BLF_RESULT_CHECK_INIT(r_info);
- if (font && font->glyph_cache) {
+ if (font) {
blf_draw_gl__start(font);
if (font->flags & BLF_WORD_WRAP) {
/* use non-ascii draw function for word-wrap */
@@ -646,6 +646,7 @@ void BLF_draw_ascii_ex(int fontid, const char *str, size_t len, struct ResultBLF
blf_draw_gl__end(font);
}
}
+
void BLF_draw_ascii(int fontid, const char *str, size_t len)
{
if (len == 0 || str[0] == '\0') {
@@ -664,7 +665,7 @@ int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth)
FontBLF *font = blf_get(fontid);
int columns = 0;
- if (font && font->glyph_cache) {
+ if (font) {
blf_draw_gl__start(font);
columns = blf_font_draw_mono(font, str, len, cwidth);
blf_draw_gl__end(font);
@@ -729,6 +730,7 @@ void BLF_boundbox_ex(
}
}
}
+
void BLF_boundbox(int fontid, const char *str, size_t len, rctf *r_box)
{
BLF_boundbox_ex(fontid, str, len, r_box, NULL);
@@ -738,7 +740,7 @@ void BLF_width_and_height(int fontid, const char *str, size_t len, float *r_widt
{
FontBLF *font = blf_get(fontid);
- if (font && font->glyph_cache) {
+ if (font) {
blf_font_width_and_height(font, str, len, r_width, r_height, NULL);
}
else {
@@ -752,12 +754,13 @@ float BLF_width_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_
BLF_RESULT_CHECK_INIT(r_info);
- if (font && font->glyph_cache) {
+ if (font) {
return blf_font_width(font, str, len, r_info);
}
return 0.0f;
}
+
float BLF_width(int fontid, const char *str, size_t len)
{
return BLF_width_ex(fontid, str, len, NULL);
@@ -767,7 +770,7 @@ float BLF_fixed_width(int fontid)
{
FontBLF *font = blf_get(fontid);
- if (font && font->glyph_cache) {
+ if (font) {
return blf_font_fixed_width(font);
}
@@ -780,12 +783,13 @@ float BLF_height_ex(int fontid, const char *str, size_t len, struct ResultBLF *r
BLF_RESULT_CHECK_INIT(r_info);
- if (font && font->glyph_cache) {
+ if (font) {
return blf_font_height(font, str, len, r_info);
}
return 0.0f;
}
+
float BLF_height(int fontid, const char *str, size_t len)
{
return BLF_height_ex(fontid, str, len, NULL);
@@ -795,8 +799,8 @@ int BLF_height_max(int fontid)
{
FontBLF *font = blf_get(fontid);
- if (font && font->glyph_cache) {
- return font->glyph_cache->glyph_height_max;
+ if (font) {
+ return blf_font_height_max(font);
}
return 0;
@@ -806,8 +810,8 @@ float BLF_width_max(int fontid)
{
FontBLF *font = blf_get(fontid);
- if (font && font->glyph_cache) {
- return font->glyph_cache->glyph_width_max;
+ if (font) {
+ return blf_font_width_max(font);
}
return 0.0f;
@@ -817,8 +821,8 @@ float BLF_descender(int fontid)
{
FontBLF *font = blf_get(fontid);
- if (font && font->glyph_cache) {
- return font->glyph_cache->descender;
+ if (font) {
+ return blf_font_descender(font);
}
return 0.0f;
@@ -828,8 +832,8 @@ float BLF_ascender(int fontid)
{
FontBLF *font = blf_get(fontid);
- if (font && font->glyph_cache) {
- return font->glyph_cache->ascender;
+ if (font) {
+ return blf_font_ascender(font);
}
return 0.0f;
@@ -939,7 +943,7 @@ void BLF_draw_buffer_ex(int fontid, const char *str, size_t len, struct ResultBL
{
FontBLF *font = blf_get(fontid);
- if (font && font->glyph_cache && (font->buf_info.fbuf || font->buf_info.cbuf)) {
+ if (font && (font->buf_info.fbuf || font->buf_info.cbuf)) {
blf_draw_buffer__start(font);
if (font->flags & BLF_WORD_WRAP) {
blf_font_draw_buffer__wrap(font, str, len, r_info);
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index 6748a5324ac..e0dfa6a2223 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -50,7 +50,6 @@
#include "UI_interface.h"
-#include "GPU_immediate.h"
#include "GPU_matrix.h"
#include "GPU_batch.h"
@@ -69,6 +68,7 @@ BatchBLF g_batch;
/* freetype2 handle ONLY for this file!. */
static FT_Library ft_lib;
static SpinLock ft_lib_mutex;
+static SpinLock blf_glyph_cache_mutex;
/* -------------------------------------------------------------------- */
/** \name Glyph Batching
@@ -217,6 +217,7 @@ int blf_font_init(void)
{
memset(&g_batch, 0, sizeof(g_batch));
BLI_spin_init(&ft_lib_mutex);
+ BLI_spin_init(&blf_glyph_cache_mutex);
return FT_Init_FreeType(&ft_lib);
}
@@ -224,6 +225,7 @@ void blf_font_exit(void)
{
FT_Done_FreeType(ft_lib);
BLI_spin_end(&ft_lib_mutex);
+ BLI_spin_end(&blf_glyph_cache_mutex);
blf_batch_draw_exit();
}
@@ -232,11 +234,14 @@ void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi)
GlyphCacheBLF *gc;
FT_Error err;
+ blf_glyph_cache_acquire(font);
+
gc = blf_glyph_cache_find(font, size, dpi);
if (gc) {
font->glyph_cache = gc;
/* Optimization: do not call FT_Set_Char_Size if size did not change. */
if (font->size == size && font->dpi == dpi) {
+ blf_glyph_cache_release(font);
return;
}
}
@@ -245,6 +250,8 @@ void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi)
if (err) {
/* FIXME: here we can go through the fixed size and choice a close one */
printf("The current font don't support the size, %u and dpi, %u\n", size, dpi);
+
+ blf_glyph_cache_release(font);
return;
}
@@ -260,28 +267,35 @@ void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi)
font->glyph_cache = NULL;
}
}
+ blf_glyph_cache_release(font);
}
-static void blf_font_ensure_ascii_table(FontBLF *font)
+static GlyphBLF **blf_font_ensure_ascii_table(FontBLF *font, GlyphCacheBLF *gc)
{
- GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
+ GlyphBLF **glyph_ascii_table;
+
+ glyph_ascii_table = gc->glyph_ascii_table;
/* build ascii on demand */
if (glyph_ascii_table['0'] == NULL) {
GlyphBLF *g;
unsigned int i;
for (i = 0; i < 256; i++) {
- g = blf_glyph_search(font->glyph_cache, i);
+ g = blf_glyph_search(gc, i);
if (!g) {
FT_UInt glyph_index = FT_Get_Char_Index(font->face, i);
- g = blf_glyph_add(font, glyph_index, i);
+ g = blf_glyph_add(font, gc, glyph_index, i);
}
glyph_ascii_table[i] = g;
}
}
+
+ return glyph_ascii_table;
}
-static void blf_font_ensure_ascii_kerning(FontBLF *font, const FT_UInt kern_mode)
+static void blf_font_ensure_ascii_kerning(FontBLF *font,
+ GlyphCacheBLF *gc,
+ const FT_UInt kern_mode)
{
KerningCacheBLF *kc = font->kerning_cache;
@@ -290,7 +304,7 @@ static void blf_font_ensure_ascii_kerning(FontBLF *font, const FT_UInt kern_mode
if (!kc || kc->mode != kern_mode) {
font->kerning_cache = kc = blf_kerning_cache_find(font);
if (!kc) {
- font->kerning_cache = kc = blf_kerning_cache_new(font);
+ font->kerning_cache = kc = blf_kerning_cache_new(font, gc);
}
}
}
@@ -301,18 +315,21 @@ static void blf_font_ensure_ascii_kerning(FontBLF *font, const FT_UInt kern_mode
*/
/* Note,
- * blf_font_ensure_ascii_table(font); must be called before this macro */
+ * blf_font_ensure_ascii_table(font, gc); must be called before this macro */
-#define BLF_UTF8_NEXT_FAST(_font, _g, _str, _i, _c, _glyph_ascii_table) \
+#define BLF_UTF8_NEXT_FAST(_font, _gc, _g, _str, _i, _c, _glyph_ascii_table) \
if (((_c) = (_str)[_i]) < 0x80) { \
_g = (_glyph_ascii_table)[_c]; \
_i++; \
} \
else if ((_c = BLI_str_utf8_as_unicode_step(_str, &(_i))) != BLI_UTF8_ERR) { \
- if ((_g = blf_glyph_search((_font)->glyph_cache, _c)) == NULL) { \
- _g = blf_glyph_add(_font, FT_Get_Char_Index((_font)->face, _c), _c); \
+ if ((_g = blf_glyph_search(_gc, _c)) == NULL) { \
+ _g = blf_glyph_add(_font, _gc, FT_Get_Char_Index((_font)->face, _c), _c); \
} \
} \
+ else { \
+ _g = NULL; \
+ } \
(void)0
#define BLF_KERNING_VARS(_font, _has_kerning, _kern_mode) \
@@ -323,7 +340,7 @@ static void blf_font_ensure_ascii_kerning(FontBLF *font, const FT_UInt kern_mode
(FT_UInt)FT_KERNING_UNFITTED)
/* Note,
- * blf_font_ensure_ascii_kerning(font, kern_mode); must be called before this macro */
+ * blf_font_ensure_ascii_kerning(font, gc, kern_mode); must be called before this macro */
#define BLF_KERNING_STEP_FAST(_font, _kern_mode, _g_prev, _g, _c_prev, _c, _pen_x) \
{ \
@@ -351,29 +368,33 @@ static void blf_font_ensure_ascii_kerning(FontBLF *font, const FT_UInt kern_mode
} \
(void)0
-static void blf_font_draw_ex(
- FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info, int pen_y)
+static void blf_font_draw_ex(FontBLF *font,
+ GlyphCacheBLF *gc,
+ const char *str,
+ size_t len,
+ struct ResultBLF *r_info,
+ int pen_y)
{
unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
int pen_x = 0;
size_t i = 0;
- GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
if (len == 0) {
/* early output, don't do any IMM OpenGL. */
return;
}
+ GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
+
BLF_KERNING_VARS(font, has_kerning, kern_mode);
- blf_font_ensure_ascii_table(font);
- blf_font_ensure_ascii_kerning(font, kern_mode);
+ blf_font_ensure_ascii_kerning(font, gc, kern_mode);
blf_batch_draw_begin(font);
while ((i < len) && str[i]) {
- BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
+ BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
if (UNLIKELY(c == BLI_UTF8_ERR)) {
break;
@@ -386,7 +407,7 @@ static void blf_font_draw_ex(
}
/* do not return this loop if clipped, we want every character tested */
- blf_glyph_render(font, g, (float)pen_x, (float)pen_y);
+ blf_glyph_render(font, gc, g, (float)pen_x, (float)pen_y);
pen_x += g->advance_i;
g_prev = g;
@@ -402,7 +423,9 @@ static void blf_font_draw_ex(
}
void blf_font_draw(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info)
{
- blf_font_draw_ex(font, str, len, r_info, 0);
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ blf_font_draw_ex(font, gc, str, len, r_info, 0);
+ blf_glyph_cache_release(font);
}
/* faster version of blf_font_draw, ascii only for view dimensions */
@@ -412,12 +435,13 @@ static void blf_font_draw_ascii_ex(
unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
int pen_x = 0;
- GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
+
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
BLF_KERNING_VARS(font, has_kerning, kern_mode);
- blf_font_ensure_ascii_table(font);
- blf_font_ensure_ascii_kerning(font, kern_mode);
+ blf_font_ensure_ascii_kerning(font, gc, kern_mode);
blf_batch_draw_begin(font);
@@ -431,7 +455,7 @@ static void blf_font_draw_ascii_ex(
}
/* do not return this loop if clipped, we want every character tested */
- blf_glyph_render(font, g, (float)pen_x, (float)pen_y);
+ blf_glyph_render(font, gc, g, (float)pen_x, (float)pen_y);
pen_x += g->advance_i;
g_prev = g;
@@ -444,7 +468,10 @@ static void blf_font_draw_ascii_ex(
r_info->lines = 1;
r_info->width = pen_x;
}
+
+ blf_glyph_cache_release(font);
}
+
void blf_font_draw_ascii(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info)
{
blf_font_draw_ascii_ex(font, str, len, r_info, 0);
@@ -458,14 +485,14 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth)
int col, columns = 0;
int pen_x = 0, pen_y = 0;
size_t i = 0;
- GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
- blf_font_ensure_ascii_table(font);
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
blf_batch_draw_begin(font);
while ((i < len) && str[i]) {
- BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
+ BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
if (UNLIKELY(c == BLI_UTF8_ERR)) {
break;
@@ -475,7 +502,7 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth)
}
/* do not return this loop if clipped, we want every character tested */
- blf_glyph_render(font, g, (float)pen_x, (float)pen_y);
+ blf_glyph_render(font, gc, g, (float)pen_x, (float)pen_y);
col = BLI_wcwidth((wchar_t)c);
if (col < 0) {
@@ -488,19 +515,25 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth)
blf_batch_draw_end();
+ blf_glyph_cache_release(font);
return columns;
}
/* Sanity checks are done by BLF_draw_buffer() */
-static void blf_font_draw_buffer_ex(
- FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info, int pen_y)
+static void blf_font_draw_buffer_ex(FontBLF *font,
+ GlyphCacheBLF *gc,
+ const char *str,
+ size_t len,
+ struct ResultBLF *r_info,
+ int pen_y)
{
unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
int pen_x = (int)font->pos[0];
int pen_y_basis = (int)font->pos[1] + pen_y;
size_t i = 0;
- GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
+
+ GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
/* buffer specific vars */
FontBufInfoBLF *buf_info = &font->buf_info;
@@ -511,13 +544,12 @@ static void blf_font_draw_buffer_ex(
BLF_KERNING_VARS(font, has_kerning, kern_mode);
- blf_font_ensure_ascii_table(font);
- blf_font_ensure_ascii_kerning(font, kern_mode);
+ blf_font_ensure_ascii_kerning(font, gc, kern_mode);
/* another buffer specific call for color conversion */
while ((i < len) && str[i]) {
- BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
+ BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
if (UNLIKELY(c == BLI_UTF8_ERR)) {
break;
@@ -645,9 +677,12 @@ static void blf_font_draw_buffer_ex(
r_info->width = pen_x;
}
}
+
void blf_font_draw_buffer(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info)
{
- blf_font_draw_buffer_ex(font, str, len, r_info, 0);
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ blf_font_draw_buffer_ex(font, gc, str, len, r_info, 0);
+ blf_glyph_cache_release(font);
}
static bool blf_font_width_to_strlen_glyph_process(FontBLF *font,
@@ -678,23 +713,24 @@ static bool blf_font_width_to_strlen_glyph_process(FontBLF *font,
size_t blf_font_width_to_strlen(
FontBLF *font, const char *str, size_t len, float width, float *r_width)
{
- unsigned int c, c_prev;
+ unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev;
int pen_x, width_new;
size_t i, i_prev;
- GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
+
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
const int width_i = (int)width;
BLF_KERNING_VARS(font, has_kerning, kern_mode);
- blf_font_ensure_ascii_table(font);
if (has_kerning) {
- blf_font_ensure_ascii_kerning(font, kern_mode);
+ blf_font_ensure_ascii_kerning(font, gc, kern_mode);
}
for (i_prev = i = 0, width_new = pen_x = 0, g_prev = NULL, c_prev = 0; (i < len) && str[i];
i_prev = i, width_new = pen_x, c_prev = c, g_prev = g) {
- BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
+ BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
if (blf_font_width_to_strlen_glyph_process(
font, has_kerning, kern_mode, c_prev, c, g_prev, g, &pen_x, width_i)) {
@@ -706,25 +742,27 @@ size_t blf_font_width_to_strlen(
*r_width = (float)width_new;
}
+ blf_glyph_cache_release(font);
return i_prev;
}
size_t blf_font_width_to_rstrlen(
FontBLF *font, const char *str, size_t len, float width, float *r_width)
{
- unsigned int c, c_prev;
+ unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev;
int pen_x, width_new;
size_t i, i_prev, i_tmp;
char *s, *s_prev;
- GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
+
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
const int width_i = (int)width;
BLF_KERNING_VARS(font, has_kerning, kern_mode);
- blf_font_ensure_ascii_table(font);
if (has_kerning) {
- blf_font_ensure_ascii_kerning(font, kern_mode);
+ blf_font_ensure_ascii_kerning(font, gc, kern_mode);
}
i = BLI_strnlen(str, len);
@@ -734,7 +772,7 @@ size_t blf_font_width_to_rstrlen(
i_prev = (size_t)((s_prev != NULL) ? s_prev - str : 0);
i_tmp = i;
- BLF_UTF8_NEXT_FAST(font, g, str, i_tmp, c, glyph_ascii_table);
+ BLF_UTF8_NEXT_FAST(font, gc, g, str, i_tmp, c, glyph_ascii_table);
for (width_new = pen_x = 0; (s != NULL);
i = i_prev, s = s_prev, c = c_prev, g = g_prev, g_prev = NULL, width_new = pen_x) {
s_prev = BLI_str_find_prev_char_utf8(str, s);
@@ -742,7 +780,7 @@ size_t blf_font_width_to_rstrlen(
if (s_prev != NULL) {
i_tmp = i_prev;
- BLF_UTF8_NEXT_FAST(font, g_prev, str, i_tmp, c_prev, glyph_ascii_table);
+ BLF_UTF8_NEXT_FAST(font, gc, g_prev, str, i_tmp, c_prev, glyph_ascii_table);
BLI_assert(i_tmp == i);
}
@@ -756,17 +794,24 @@ size_t blf_font_width_to_rstrlen(
*r_width = (float)width_new;
}
+ blf_glyph_cache_release(font);
return i;
}
-static void blf_font_boundbox_ex(
- FontBLF *font, const char *str, size_t len, rctf *box, struct ResultBLF *r_info, int pen_y)
+static void blf_font_boundbox_ex(FontBLF *font,
+ GlyphCacheBLF *gc,
+ const char *str,
+ size_t len,
+ rctf *box,
+ struct ResultBLF *r_info,
+ int pen_y)
{
unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
int pen_x = 0;
size_t i = 0;
- GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
+
+ GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
rctf gbox;
@@ -777,11 +822,10 @@ static void blf_font_boundbox_ex(
box->ymin = 32000.0f;
box->ymax = -32000.0f;
- blf_font_ensure_ascii_table(font);
- blf_font_ensure_ascii_kerning(font, kern_mode);
+ blf_font_ensure_ascii_kerning(font, gc, kern_mode);
while ((i < len) && str[i]) {
- BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
+ BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
if (UNLIKELY(c == BLI_UTF8_ERR)) {
break;
@@ -832,7 +876,9 @@ static void blf_font_boundbox_ex(
void blf_font_boundbox(
FontBLF *font, const char *str, size_t len, rctf *r_box, struct ResultBLF *r_info)
{
- blf_font_boundbox_ex(font, str, len, r_box, r_info, 0);
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ blf_font_boundbox_ex(font, gc, str, len, r_box, r_info, 0);
+ blf_glyph_cache_release(font);
}
/* -------------------------------------------------------------------- */
@@ -848,23 +894,29 @@ void blf_font_boundbox(
* \note If we want rich text - we better have a higher level API to handle that
* (color, bold, switching fonts... etc).
*/
-static void blf_font_wrap_apply(
- FontBLF *font,
- const char *str,
- size_t len,
- struct ResultBLF *r_info,
- void (*callback)(FontBLF *font, const char *str, size_t len, int pen_y, void *userdata),
- void *userdata)
+static void blf_font_wrap_apply(FontBLF *font,
+ const char *str,
+ size_t len,
+ struct ResultBLF *r_info,
+ void (*callback)(FontBLF *font,
+ GlyphCacheBLF *gc,
+ const char *str,
+ size_t len,
+ int pen_y,
+ void *userdata),
+ void *userdata)
{
unsigned int c;
GlyphBLF *g, *g_prev = NULL;
FT_Vector delta;
int pen_x = 0, pen_y = 0;
size_t i = 0;
- GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
int lines = 0;
int pen_x_next = 0;
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
+
BLF_KERNING_VARS(font, has_kerning, kern_mode);
struct WordWrapVars {
@@ -872,7 +924,6 @@ static void blf_font_wrap_apply(
size_t start, last[2];
} wrap = {font->wrap_width != -1 ? font->wrap_width : INT_MAX, 0, {0, 0}};
- blf_font_ensure_ascii_table(font);
// printf("%s wrapping (%d, %d) `%s`:\n", __func__, len, strlen(str), str);
while ((i < len) && str[i]) {
@@ -880,7 +931,7 @@ static void blf_font_wrap_apply(
size_t i_curr = i;
bool do_draw = false;
- BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
+ BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
if (UNLIKELY(c == BLI_UTF8_ERR)) {
break;
@@ -924,11 +975,11 @@ static void blf_font_wrap_apply(
// printf("(%03d..%03d) `%.*s`\n",
// wrap.start, wrap.last[0], (wrap.last[0] - wrap.start) - 1, &str[wrap.start]);
- callback(font, &str[wrap.start], (wrap.last[0] - wrap.start) - 1, pen_y, userdata);
+ callback(font, gc, &str[wrap.start], (wrap.last[0] - wrap.start) - 1, pen_y, userdata);
wrap.start = wrap.last[0];
i = wrap.last[1];
pen_x = 0;
- pen_y -= font->glyph_cache->glyph_height_max;
+ pen_y -= gc->glyph_height_max;
g_prev = NULL;
lines += 1;
continue;
@@ -945,13 +996,19 @@ static void blf_font_wrap_apply(
/* width of last line only (with wrapped lines) */
r_info->width = pen_x_next;
}
+
+ blf_glyph_cache_release(font);
}
/* blf_font_draw__wrap */
-static void blf_font_draw__wrap_cb(
- FontBLF *font, const char *str, size_t len, int pen_y, void *UNUSED(userdata))
+static void blf_font_draw__wrap_cb(FontBLF *font,
+ GlyphCacheBLF *gc,
+ const char *str,
+ size_t len,
+ int pen_y,
+ void *UNUSED(userdata))
{
- blf_font_draw_ex(font, str, len, NULL, pen_y);
+ blf_font_draw_ex(font, gc, str, len, NULL, pen_y);
}
void blf_font_draw__wrap(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info)
{
@@ -960,12 +1017,12 @@ void blf_font_draw__wrap(FontBLF *font, const char *str, size_t len, struct Resu
/* blf_font_boundbox__wrap */
static void blf_font_boundbox_wrap_cb(
- FontBLF *font, const char *str, size_t len, int pen_y, void *userdata)
+ FontBLF *font, GlyphCacheBLF *gc, const char *str, size_t len, int pen_y, void *userdata)
{
rctf *box = userdata;
rctf box_single;
- blf_font_boundbox_ex(font, str, len, &box_single, NULL, pen_y);
+ blf_font_boundbox_ex(font, gc, str, len, &box_single, NULL, pen_y);
BLI_rctf_union(box, &box_single);
}
void blf_font_boundbox__wrap(
@@ -980,10 +1037,14 @@ void blf_font_boundbox__wrap(
}
/* blf_font_draw_buffer__wrap */
-static void blf_font_draw_buffer__wrap_cb(
- FontBLF *font, const char *str, size_t len, int pen_y, void *UNUSED(userdata))
+static void blf_font_draw_buffer__wrap_cb(FontBLF *font,
+ GlyphCacheBLF *gc,
+ const char *str,
+ size_t len,
+ int pen_y,
+ void *UNUSED(userdata))
{
- blf_font_draw_buffer_ex(font, str, len, NULL, pen_y);
+ blf_font_draw_buffer_ex(font, gc, str, len, NULL, pen_y);
}
void blf_font_draw_buffer__wrap(FontBLF *font,
const char *str,
@@ -1069,16 +1130,22 @@ float blf_font_height(FontBLF *font, const char *str, size_t len, struct ResultB
float blf_font_fixed_width(FontBLF *font)
{
const unsigned int c = ' ';
- GlyphBLF *g = blf_glyph_search(font->glyph_cache, c);
+
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ blf_font_ensure_ascii_table(font, gc);
+
+ GlyphBLF *g = blf_glyph_search(gc, c);
if (!g) {
- g = blf_glyph_add(font, FT_Get_Char_Index(font->face, c), c);
+ g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, c), c);
/* if we don't find the glyph. */
if (!g) {
+ blf_glyph_cache_release(font);
return 0.0f;
}
}
+ blf_glyph_cache_release(font);
return g->advance;
}
@@ -1109,6 +1176,7 @@ int blf_font_count_missing_chars(FontBLF *font,
void blf_font_free(FontBLF *font)
{
+ BLI_spin_lock(&blf_glyph_cache_mutex);
GlyphCacheBLF *gc;
font->glyph_cache = NULL;
@@ -1126,6 +1194,8 @@ void blf_font_free(FontBLF *font)
MEM_freeN(font->name);
}
MEM_freeN(font);
+
+ BLI_spin_unlock(&blf_glyph_cache_mutex);
}
static void blf_font_fill(FontBLF *font)
@@ -1175,6 +1245,7 @@ static void blf_font_fill(FontBLF *font)
font->ft_lib = ft_lib;
font->ft_lib_mutex = &ft_lib_mutex;
+ font->glyph_cache_mutex = &blf_glyph_cache_mutex;
}
FontBLF *blf_font_new(const char *name, const char *filename)
@@ -1248,3 +1319,51 @@ FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int m
blf_font_fill(font);
return font;
}
+
+int blf_font_height_max(FontBLF *font)
+{
+ int height_max;
+
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ blf_font_ensure_ascii_table(font, gc);
+ height_max = gc->glyph_height_max;
+
+ blf_glyph_cache_release(font);
+ return height_max;
+}
+
+int blf_font_width_max(FontBLF *font)
+{
+ int width_max;
+
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ blf_font_ensure_ascii_table(font, gc);
+ width_max = gc->glyph_width_max;
+
+ blf_glyph_cache_release(font);
+ return width_max;
+}
+
+float blf_font_descender(FontBLF *font)
+{
+ float descender;
+
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ blf_font_ensure_ascii_table(font, gc);
+ descender = gc->descender;
+
+ blf_glyph_cache_release(font);
+ return descender;
+}
+
+float blf_font_ascender(FontBLF *font)
+{
+ float ascender;
+
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ blf_font_ensure_ascii_table(font, gc);
+ ascender = gc->ascender;
+
+ blf_glyph_cache_release(font);
+ return ascender;
+}
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index c0a53cbf282..535366b78fa 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -72,7 +72,7 @@ KerningCacheBLF *blf_kerning_cache_find(FontBLF *font)
}
/* Create a new glyph cache for the current kerning mode. */
-KerningCacheBLF *blf_kerning_cache_new(FontBLF *font)
+KerningCacheBLF *blf_kerning_cache_new(FontBLF *font, GlyphCacheBLF *gc)
{
KerningCacheBLF *kc;
@@ -84,13 +84,13 @@ KerningCacheBLF *blf_kerning_cache_new(FontBLF *font)
unsigned int i, j;
for (i = 0; i < 0x80; i++) {
for (j = 0; j < 0x80; j++) {
- GlyphBLF *g = blf_glyph_search(font->glyph_cache, i);
+ GlyphBLF *g = blf_glyph_search(gc, i);
if (!g) {
FT_UInt glyph_index = FT_Get_Char_Index(font->face, i);
- g = blf_glyph_add(font, glyph_index, i);
+ g = blf_glyph_add(font, gc, glyph_index, i);
}
/* Can fail on certain fonts */
- GlyphBLF *g_prev = blf_glyph_search(font->glyph_cache, j);
+ GlyphBLF *g_prev = blf_glyph_search(gc, j);
FT_Vector delta = {
.x = 0,
@@ -180,14 +180,43 @@ GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
return gc;
}
+GlyphCacheBLF *blf_glyph_cache_acquire(FontBLF *font)
+{
+ BLI_spin_lock(font->glyph_cache_mutex);
+
+ GlyphCacheBLF *gc;
+
+ if (!font->glyph_cache) {
+ gc = blf_glyph_cache_new(font);
+ if (gc) {
+ font->glyph_cache = gc;
+ }
+ else {
+ font->glyph_cache = NULL;
+ return NULL;
+ }
+ }
+
+ return font->glyph_cache;
+}
+
+void blf_glyph_cache_release(FontBLF *font)
+{
+ BLI_spin_unlock(font->glyph_cache_mutex);
+}
+
void blf_glyph_cache_clear(FontBLF *font)
{
GlyphCacheBLF *gc;
+ BLI_spin_lock(font->glyph_cache_mutex);
+
while ((gc = BLI_pophead(&font->cache))) {
blf_glyph_cache_free(gc);
}
font->glyph_cache = NULL;
+
+ BLI_spin_unlock(font->glyph_cache_mutex);
}
void blf_glyph_cache_free(GlyphCacheBLF *gc)
@@ -264,7 +293,7 @@ GlyphBLF *blf_glyph_search(GlyphCacheBLF *gc, unsigned int c)
return NULL;
}
-GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
+GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, unsigned int c)
{
FT_GlyphSlot slot;
GlyphBLF *g;
@@ -273,7 +302,7 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
FT_BBox bbox;
unsigned int key;
- g = blf_glyph_search(font->glyph_cache, c);
+ g = blf_glyph_search(gc, c);
if (g) {
return g;
}
@@ -285,7 +314,7 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
BLI_spin_lock(font->ft_lib_mutex);
/* search again after locking */
- g = blf_glyph_search(font->glyph_cache, c);
+ g = blf_glyph_search(gc, c);
if (g) {
BLI_spin_unlock(font->ft_lib_mutex);
return g;
@@ -380,7 +409,7 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
g->box.ymax = ((float)bbox.yMax) / 64.0f;
key = blf_hash(g->c);
- BLI_addhead(&(font->glyph_cache->bucket[key]), g);
+ BLI_addhead(&(gc->bucket[key]), g);
BLI_spin_unlock(font->ft_lib_mutex);
@@ -483,15 +512,13 @@ static void blf_glyph_calc_rect_shadow(rctf *rect, GlyphBLF *g, float x, float y
blf_glyph_calc_rect(rect, g, x + (float)font->shadow_x, y + (float)font->shadow_y);
}
-void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
+void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, float y)
{
if ((!g->width) || (!g->height)) {
return;
}
if (g->build_tex == 0) {
- GlyphCacheBLF *gc = font->glyph_cache;
-
if (font->tex_size_max == -1) {
font->tex_size_max = GPU_max_texture_size();
}
@@ -578,8 +605,8 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
}
else if (font->shadow <= 4) {
blf_texture3_draw(font->shadow_color,
- font->glyph_cache->p2_width,
- font->glyph_cache->p2_height,
+ gc->p2_width,
+ gc->p2_height,
g->uv,
rect_ofs.xmin,
rect_ofs.ymin,
@@ -588,8 +615,8 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
}
else {
blf_texture5_draw(font->shadow_color,
- font->glyph_cache->p2_width,
- font->glyph_cache->p2_height,
+ gc->p2_width,
+ gc->p2_height,
g->uv,
rect_ofs.xmin,
rect_ofs.ymin,
@@ -605,8 +632,8 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
switch (font->blur) {
case 3:
blf_texture3_draw(font->color,
- font->glyph_cache->p2_width,
- font->glyph_cache->p2_height,
+ gc->p2_width,
+ gc->p2_height,
g->uv,
rect.xmin,
rect.ymin,
@@ -615,8 +642,8 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
break;
case 5:
blf_texture5_draw(font->color,
- font->glyph_cache->p2_width,
- font->glyph_cache->p2_height,
+ gc->p2_width,
+ gc->p2_height,
g->uv,
rect.xmin,
rect.ymin,
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index cfc1d245a11..efcf9e15100 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -93,6 +93,10 @@ void blf_font_width_and_height(struct FontBLF *font,
float blf_font_width(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info);
float blf_font_height(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info);
float blf_font_fixed_width(struct FontBLF *font);
+int blf_font_height_max(struct FontBLF *font);
+int blf_font_width_max(struct FontBLF *font);
+float blf_font_descender(struct FontBLF *font);
+float blf_font_ascender(struct FontBLF *font);
int blf_font_count_missing_chars(struct FontBLF *font,
const char *str,
@@ -102,21 +106,27 @@ int blf_font_count_missing_chars(struct FontBLF *font,
void blf_font_free(struct FontBLF *font);
struct KerningCacheBLF *blf_kerning_cache_find(struct FontBLF *font);
-struct KerningCacheBLF *blf_kerning_cache_new(struct FontBLF *font);
+struct KerningCacheBLF *blf_kerning_cache_new(struct FontBLF *font, struct GlyphCacheBLF *gc);
void blf_kerning_cache_clear(struct FontBLF *font);
struct GlyphCacheBLF *blf_glyph_cache_find(struct FontBLF *font,
unsigned int size,
unsigned int dpi);
struct GlyphCacheBLF *blf_glyph_cache_new(struct FontBLF *font);
+struct GlyphCacheBLF *blf_glyph_cache_acquire(struct FontBLF *font);
+void blf_glyph_cache_release(struct FontBLF *font);
void blf_glyph_cache_clear(struct FontBLF *font);
void blf_glyph_cache_free(struct GlyphCacheBLF *gc);
struct GlyphBLF *blf_glyph_search(struct GlyphCacheBLF *gc, unsigned int c);
-struct GlyphBLF *blf_glyph_add(struct FontBLF *font, unsigned int index, unsigned int c);
+struct GlyphBLF *blf_glyph_add(struct FontBLF *font,
+ struct GlyphCacheBLF *gc,
+ unsigned int index,
+ unsigned int c);
void blf_glyph_free(struct GlyphBLF *g);
-void blf_glyph_render(struct FontBLF *font, struct GlyphBLF *g, float x, float y);
+void blf_glyph_render(
+ struct FontBLF *font, struct GlyphCacheBLF *gc, struct GlyphBLF *g, float x, float y);
#ifdef WIN32
/* blf_font_win32_compat.c */
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index 22950c26b6b..0294a6219b9 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -249,7 +249,9 @@ typedef struct FontBLF {
/* list of glyph cache for this font. */
ListBase cache;
- /* current glyph cache, size and dpi. */
+ /* current glyph cache, size and dpi.
+ * Use blf_glyph_cache_acquire(font) and blf_glyph_cache_release(font) to access cache!
+ */
GlyphCacheBLF *glyph_cache;
/* list of kerning cache for this font. */
@@ -272,6 +274,9 @@ typedef struct FontBLF {
/* data for buffer usage (drawing into a texture buffer) */
FontBufInfoBLF buf_info;
+
+ /* Mutex lock for glyph cache. */
+ SpinLock *glyph_cache_mutex;
} FontBLF;
typedef struct DirBLF {
diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c
index d6710b91539..4e44a85443d 100644
--- a/source/blender/blenfont/intern/blf_thumbs.c
+++ b/source/blender/blenfont/intern/blf_thumbs.c
@@ -109,7 +109,7 @@ void BLF_thumb_preview(const char *filename,
font->pos[1] -= font->glyph_cache->ascender * 1.1f;
/* We fallback to default english strings in case not enough chars are available in current
- * font for given translated string (useful in non-latin i18n context, like chinese,
+ * font for given translated string (useful in non-latin i18n context, like Chinese,
* since many fonts will then show nothing but ugly 'missing char' in their preview).
* Does not handle all cases, but much better than nothing.
*/
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index a4863780d2e..868c5a69593 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -19,6 +19,7 @@
#ifndef __BKE_ACTION_H__
#define __BKE_ACTION_H__
+
/** \file
* \ingroup bke
* \brief Blender kernel action and pose functionality.
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index a2a14011595..4e4528ff92b 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -25,7 +25,6 @@
*/
struct AnimData;
-struct ChannelDriver;
struct Depsgraph;
struct FCurve;
struct ID;
@@ -289,7 +288,7 @@ void BKE_animsys_eval_animdata(struct Depsgraph *depsgraph, struct ID *id);
void BKE_animsys_eval_driver(struct Depsgraph *depsgraph,
struct ID *id,
int driver_index,
- struct ChannelDriver *driver_orig);
+ struct FCurve *fcu_orig);
void BKE_animsys_update_driver_array(struct ID *id);
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index 3beae7a1f9d..b255500272a 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -182,6 +182,7 @@ void BKE_bone_parent_transform_apply(const struct BoneParentTransform *bpt,
void BKE_bone_parent_transform_calc_from_pchan(const struct bPoseChannel *pchan,
struct BoneParentTransform *r_bpt);
void BKE_bone_parent_transform_calc_from_matrices(int bone_flag,
+ int inherit_scale_mode,
const float offs_bone[4][4],
const float parent_arm_mat[4][4],
const float parent_pose_mat[4][4],
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 09900651dad..21ef70b7bcd 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -27,7 +27,7 @@
* \note Use #STRINGIFY() rather than defining with quotes.
*/
#define BLENDER_VERSION 281
-#define BLENDER_SUBVERSION 3
+#define BLENDER_SUBVERSION 12
/** Several breakages with 280, e.g. collections vs layers. */
#define BLENDER_MINVERSION 280
#define BLENDER_MINSUBVERSION 0
@@ -37,6 +37,8 @@
#define BLENDER_VERSION_CHAR
/** alpha/beta/rc/release, docs use this. */
#define BLENDER_VERSION_CYCLE alpha
+/** Optionally set to 1,2,... for example to to get alpha1 or rc2. */
+#define BLENDER_VERSION_CYCLE_NUMBER
/** Defined in from blender.c */
extern char versionstr[];
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 26ab7f8ba0c..891247f8127 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -56,7 +56,7 @@ void BKE_brush_make_local(struct Main *bmain, struct Brush *brush, const bool li
void BKE_brush_free(struct Brush *brush);
void BKE_brush_sculpt_reset(struct Brush *brush);
-void BKE_brush_gpencil_presets(struct bContext *C);
+void BKE_brush_gpencil_presets(struct Main *bmain, struct ToolSettings *ts);
/* image icon function */
struct ImBuf *get_brush_icon(struct Brush *brush);
@@ -90,7 +90,9 @@ float BKE_brush_sample_masktex(const struct Scene *scene,
unsigned int *BKE_brush_gen_texture_cache(struct Brush *br, int half_side, bool use_secondary);
/* radial control */
-struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br, bool secondary);
+struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br,
+ bool secondary,
+ bool display_gradient);
/* unified strength size and color */
diff --git a/source/blender/blenkernel/BKE_callbacks.h b/source/blender/blenkernel/BKE_callbacks.h
new file mode 100644
index 00000000000..e15cf7fed18
--- /dev/null
+++ b/source/blender/blenkernel/BKE_callbacks.h
@@ -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 bke
+ */
+
+#ifndef __BKE_CALLBACKS_H__
+#define __BKE_CALLBACKS_H__
+
+struct Depsgraph;
+struct ID;
+struct Main;
+struct PointerRNA;
+
+/**
+ * Common suffix uses:
+ * - ``_PRE/_POST``:
+ * For handling discrete non-interactive events.
+ * - ``_INIT/_COMPLETE/_CANCEL``:
+ * For handling jobs (which may in turn cause other handlers to be called).
+ */
+typedef enum {
+ BKE_CB_EVT_FRAME_CHANGE_PRE,
+ BKE_CB_EVT_FRAME_CHANGE_POST,
+ BKE_CB_EVT_RENDER_PRE,
+ BKE_CB_EVT_RENDER_POST,
+ BKE_CB_EVT_RENDER_WRITE,
+ BKE_CB_EVT_RENDER_STATS,
+ BKE_CB_EVT_RENDER_INIT,
+ BKE_CB_EVT_RENDER_COMPLETE,
+ BKE_CB_EVT_RENDER_CANCEL,
+ BKE_CB_EVT_LOAD_PRE,
+ BKE_CB_EVT_LOAD_POST,
+ BKE_CB_EVT_SAVE_PRE,
+ BKE_CB_EVT_SAVE_POST,
+ BKE_CB_EVT_UNDO_PRE,
+ BKE_CB_EVT_UNDO_POST,
+ BKE_CB_EVT_REDO_PRE,
+ BKE_CB_EVT_REDO_POST,
+ BKE_CB_EVT_DEPSGRAPH_UPDATE_PRE,
+ BKE_CB_EVT_DEPSGRAPH_UPDATE_POST,
+ BKE_CB_EVT_VERSION_UPDATE,
+ BKE_CB_EVT_LOAD_FACTORY_USERDEF_POST,
+ BKE_CB_EVT_LOAD_FACTORY_STARTUP_POST,
+ BKE_CB_EVT_TOT,
+} eCbEvent;
+
+typedef struct bCallbackFuncStore {
+ struct bCallbackFuncStore *next, *prev;
+ void (*func)(struct Main *, struct PointerRNA **, const int num_pointers, void *arg);
+ void *arg;
+ short alloc;
+} bCallbackFuncStore;
+
+void BKE_callback_exec(struct Main *bmain,
+ struct PointerRNA **pointers,
+ const int num_pointers,
+ eCbEvent evt);
+void BKE_callback_exec_null(struct Main *bmain, eCbEvent evt);
+void BKE_callback_exec_id(struct Main *bmain, struct ID *id, eCbEvent evt);
+void BKE_callback_exec_id_depsgraph(struct Main *bmain,
+ struct ID *id,
+ struct Depsgraph *depsgraph,
+ eCbEvent evt);
+void BKE_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt);
+
+void BKE_callback_global_init(void);
+void BKE_callback_global_finalize(void);
+
+#endif /* __BKE_CALLBACKS_H__ */
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index da80b3d5032..d1c133c79b5 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -28,8 +28,6 @@
extern "C" {
#endif
-#include "DNA_vec_types.h"
-
struct Camera;
struct Depsgraph;
struct Main;
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h
index 757b1c64db3..0d33d86ec16 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -70,13 +70,9 @@ struct Collection *BKE_collection_duplicate(struct Main *bmain,
const bool do_hierarchy,
const bool do_objects,
const bool do_obdata);
-struct Collection *BKE_collection_copy_master(struct Main *bmain,
- struct Collection *collection,
- const int flag);
/* Master Collection for Scene */
-struct Collection *BKE_collection_master(const struct Scene *scene);
struct Collection *BKE_collection_master_add(void);
struct Scene *BKE_collection_master_scene_search(const struct Main *bmain,
const struct Collection *master_collection);
@@ -225,7 +221,7 @@ void BKE_scene_objects_iterator_end(struct BLI_Iterator *iter);
bool is_scene_collection = (_scene) != NULL; \
\
if (_scene) { \
- _instance_next = BKE_collection_master(_scene); \
+ _instance_next = _scene->master_collection; \
} \
else { \
_instance_next = (_bmain)->collections.first; \
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index 6bd7440eeea..105f8e82343 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -96,7 +96,7 @@ typedef struct bContextStore {
/* for the context's rna mode enum
* keep aligned with data_mode_strings in context.c */
-enum eContextObjectMode {
+typedef enum eContextObjectMode {
CTX_MODE_EDIT_MESH = 0,
CTX_MODE_EDIT_CURVE,
CTX_MODE_EDIT_SURFACE,
@@ -115,7 +115,7 @@ enum eContextObjectMode {
CTX_MODE_EDIT_GPENCIL,
CTX_MODE_SCULPT_GPENCIL,
CTX_MODE_WEIGHT_GPENCIL,
-};
+} eContextObjectMode;
#define CTX_MODE_NUM (CTX_MODE_WEIGHT_GPENCIL + 1)
/* Context */
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index be49ca150b2..630c5fa1856 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -72,7 +72,7 @@ typedef struct CVKeyIndex {
/* ** Curve ** */
void BKE_curve_free(struct Curve *cu);
void BKE_curve_editfont_free(struct Curve *cu);
-void BKE_curve_init(struct Curve *cu);
+void BKE_curve_init(struct Curve *cu, const short curve_type);
struct Curve *BKE_curve_add(struct Main *bmain, const char *name, int type);
void BKE_curve_copy_data(struct Main *bmain,
struct Curve *cu_dst,
@@ -86,11 +86,10 @@ void BKE_curve_curve_dimension_update(struct Curve *cu);
void BKE_curve_boundbox_calc(struct Curve *cu, float r_loc[3], float r_size[3]);
struct BoundBox *BKE_curve_boundbox_get(struct Object *ob);
+
void BKE_curve_texspace_calc(struct Curve *cu);
-struct BoundBox *BKE_curve_texspace_get(struct Curve *cu,
- float r_loc[3],
- float r_rot[3],
- float r_size[3]);
+void BKE_curve_texspace_ensure(struct Curve *cu);
+void BKE_curve_texspace_get(struct Curve *cu, float r_loc[3], float r_size[3]);
bool BKE_curve_minmax(struct Curve *cu, bool use_radius, float min[3], float max[3]);
bool BKE_curve_center_median(struct Curve *cu, float cent[3]);
diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h
index 062968eddfc..47c8f31ead3 100644
--- a/source/blender/blenkernel/BKE_editmesh.h
+++ b/source/blender/blenkernel/BKE_editmesh.h
@@ -30,6 +30,7 @@
struct BMLoop;
struct BMesh;
+struct BoundBox;
struct Depsgraph;
struct EditMeshData;
struct Mesh;
@@ -59,6 +60,9 @@ typedef struct BMEditMesh {
struct Mesh *mesh_eval_final, *mesh_eval_cage;
+ /** Cached cage bounding box for selection. */
+ struct BoundBox *bb_cage;
+
/*derivedmesh stuff*/
CustomData_MeshMasks lastDataMask;
unsigned char (*derivedVertColor)[4];
@@ -90,6 +94,7 @@ void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype);
float (*BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em, int *r_vert_len))[3];
void BKE_editmesh_lnorspace_update(BMEditMesh *em);
void BKE_editmesh_ensure_autosmooth(BMEditMesh *em);
+struct BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em);
/* editderivedmesh.c */
/* should really be defined in editmesh.c, but they use 'EditDerivedBMesh' */
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index 4c1a115eb23..5be9a35b168 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -89,6 +89,9 @@ struct ChannelDriver *fcurve_copy_driver(const struct ChannelDriver *driver);
void driver_variables_copy(struct ListBase *dst_list, const struct ListBase *src_list);
+void BKE_driver_target_matrix_to_rot_channels(
+ float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4]);
+
void driver_free_variable(struct ListBase *variables, struct DriverVar *dvar);
void driver_free_variable_ex(struct ChannelDriver *driver, struct DriverVar *dvar);
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index f1cf87ea1b5..d09917a9e41 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -32,6 +32,7 @@ struct ListBase;
struct Main;
struct Material;
struct Object;
+struct Scene;
struct ToolSettings;
struct bDeformGroup;
struct bGPDframe;
@@ -58,6 +59,9 @@ struct MDeformVert;
#define GPENCIL_SIMPLIFY_BLEND(scene, playing) \
((GPENCIL_SIMPLIFY_ONPLAY(playing) && (GPENCIL_SIMPLIFY(scene)) && \
(scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_BLEND)))
+#define GPENCIL_SIMPLIFY_TINT(scene, playing) \
+ ((GPENCIL_SIMPLIFY_ONPLAY(playing) && (GPENCIL_SIMPLIFY(scene)) && \
+ (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_TINT)))
/* ------------ Grease-Pencil API ------------------ */
@@ -149,13 +153,14 @@ bool BKE_gpencil_layer_delframe(struct bGPDlayer *gpl, struct bGPDframe *gpf);
struct bGPDlayer *BKE_gpencil_layer_getactive(struct bGPdata *gpd);
void BKE_gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active);
void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
+void BKE_gpencil_layer_autolock_set(struct bGPdata *gpd, const bool unlock);
/* Brush */
struct Material *BKE_gpencil_brush_material_get(struct Brush *brush);
void BKE_gpencil_brush_material_set(struct Brush *brush, struct Material *material);
/* Object */
-struct Material *BKE_gpencil_object_material_ensure_active(struct Main *bmain, struct Object *ob);
+struct Material *BKE_gpencil_object_material_ensure_active(struct Object *ob);
struct Material *BKE_gpencil_object_material_ensure_from_brush(struct Main *bmain,
struct Object *ob,
struct Brush *brush);
@@ -179,8 +184,7 @@ struct Material *BKE_gpencil_object_material_ensure_from_active_input_toolsettin
struct Material *BKE_gpencil_object_material_ensure_from_active_input_brush(struct Main *bmain,
struct Object *ob,
struct Brush *brush);
-struct Material *BKE_gpencil_object_material_ensure_from_active_input_material(struct Main *bmain,
- struct Object *ob);
+struct Material *BKE_gpencil_object_material_ensure_from_active_input_material(struct Object *ob);
/* object boundbox */
bool BKE_gpencil_data_minmax(const struct bGPdata *gpd, float r_min[3], float r_max[3]);
@@ -238,6 +242,14 @@ void BKE_gpencil_get_range_selected(struct bGPDlayer *gpl, int *r_initframe, int
float BKE_gpencil_multiframe_falloff_calc(
struct bGPDframe *gpf, int actnum, int f_init, int f_end, struct CurveMapping *cur_falloff);
+void BKE_gpencil_convert_curve(struct Main *bmain,
+ struct Scene *scene,
+ struct Object *ob_gp,
+ struct Object *ob_cu,
+ const bool gpencil_lines,
+ const bool use_collections,
+ const bool only_stroke);
+
extern void (*BKE_gpencil_batch_cache_dirty_tag_cb)(struct bGPdata *gpd);
extern void (*BKE_gpencil_batch_cache_free_cb)(struct bGPdata *gpd);
diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h
index 36f38996c36..918f85d146c 100644
--- a/source/blender/blenkernel/BKE_gpencil_modifier.h
+++ b/source/blender/blenkernel/BKE_gpencil_modifier.h
@@ -21,8 +21,6 @@
*/
#include "DNA_gpencil_modifier_types.h" /* needed for all enum typdefs */
-#include "BLI_compiler_attrs.h"
-#include "BKE_customdata.h"
struct Depsgraph;
struct GpencilModifierData;
@@ -33,7 +31,7 @@ struct ModifierUpdateDepsgraphContext;
struct Object;
struct Scene;
/* NOTE: bakeModifier() called from UI:
- * needs to create new databloc-ks, hence the need for this. */
+ * needs to create new data-blocks, hence the need for this. */
struct bGPDframe;
struct bGPDlayer;
struct bGPDstroke;
@@ -299,6 +297,7 @@ void BKE_gpencil_modifiers_foreachTexLink(struct Object *ob,
bool BKE_gpencil_has_geometry_modifiers(struct Object *ob);
bool BKE_gpencil_has_time_modifiers(struct Object *ob);
+bool BKE_gpencil_has_transform_modifiers(struct Object *ob);
void BKE_gpencil_stroke_modifiers(struct Depsgraph *depsgraph,
struct Object *ob,
diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
index eb65b7641e1..535980840c1 100644
--- a/source/blender/blenkernel/BKE_layer.h
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -90,6 +90,7 @@ int BKE_layer_collection_findindex(struct ViewLayer *view_layer, const struct La
void BKE_main_collection_sync(const struct Main *bmain);
void BKE_scene_collection_sync(const struct Scene *scene);
void BKE_layer_collection_sync(const struct Scene *scene, struct ViewLayer *view_layer);
+void BKE_layer_collection_local_sync(struct ViewLayer *view_layer, struct View3D *v3d);
void BKE_main_collection_sync_remap(const struct Main *bmain);
@@ -117,6 +118,10 @@ void BKE_layer_collection_isolate(struct Scene *scene,
struct ViewLayer *view_layer,
struct LayerCollection *lc,
bool extend);
+void BKE_layer_collection_local_isolate(struct ViewLayer *view_layer,
+ struct View3D *v3d,
+ struct LayerCollection *lc,
+ bool extend);
void BKE_layer_collection_set_visible(struct ViewLayer *view_layer,
struct LayerCollection *lc,
const bool visible,
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index c8d85cd0c87..71799bf74f6 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -117,7 +117,7 @@ enum {
void BKE_libblock_copy_ex(struct Main *bmain,
const struct ID *id,
struct ID **r_newid,
- const int flag);
+ const int orig_flag);
void *BKE_libblock_copy(struct Main *bmain, const struct ID *id) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
/* Special version. sued by datablock localization. */
@@ -175,6 +175,7 @@ void BKE_libblock_management_usercounts_clear(struct Main *bmain, void *idv);
void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id);
void id_lib_extern(struct ID *id);
+void id_lib_indirect_weak_link(struct ID *id);
void BKE_library_filepath_set(struct Main *bmain, struct Library *lib, const char *filepath);
void id_us_ensure_real(struct ID *id);
void id_us_clear_real(struct ID *id);
diff --git a/source/blender/blenkernel/BKE_library_override.h b/source/blender/blenkernel/BKE_library_override.h
index 5440b0ebe63..5cffabd333f 100644
--- a/source/blender/blenkernel/BKE_library_override.h
+++ b/source/blender/blenkernel/BKE_library_override.h
@@ -35,10 +35,12 @@ bool BKE_override_library_is_enabled(void);
struct IDOverrideLibrary *BKE_override_library_init(struct ID *local_id, struct ID *reference_id);
void BKE_override_library_copy(struct ID *dst_id, const struct ID *src_id);
-void BKE_override_library_clear(struct IDOverrideLibrary *override);
-void BKE_override_library_free(struct IDOverrideLibrary **override);
+void BKE_override_library_clear(struct IDOverrideLibrary *override, const bool do_id_user);
+void BKE_override_library_free(struct IDOverrideLibrary **override, const bool do_id_user);
-struct ID *BKE_override_library_create_from_id(struct Main *bmain, struct ID *reference_id);
+struct ID *BKE_override_library_create_from_id(struct Main *bmain,
+ struct ID *reference_id,
+ const bool do_tagged_remap);
bool BKE_override_library_create_from_tag(struct Main *bmain);
struct IDOverrideLibraryProperty *BKE_override_library_property_find(
diff --git a/source/blender/blenkernel/BKE_library_remap.h b/source/blender/blenkernel/BKE_library_remap.h
index 917582e385a..784e1a570c5 100644
--- a/source/blender/blenkernel/BKE_library_remap.h
+++ b/source/blender/blenkernel/BKE_library_remap.h
@@ -85,7 +85,7 @@ void BKE_libblock_relink_ex(struct Main *bmain,
void *idv,
void *old_idv,
void *new_idv,
- const bool us_min_never_null) ATTR_NONNULL(1, 2);
+ const short remap_flags) ATTR_NONNULL(1, 2);
void BKE_libblock_relink_to_newid(struct ID *id) ATTR_NONNULL();
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index 44a8f98e994..7ff9c4e6376 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -38,6 +38,7 @@ struct bNode;
/* materials */
void init_def_material(void);
+void BKE_material_gpencil_default_free(void);
void BKE_material_free(struct Material *ma);
void test_object_materials(struct Main *bmain, struct Object *ob, struct ID *id);
void test_all_objects_materials(struct Main *bmain, struct ID *id);
@@ -46,6 +47,7 @@ void BKE_material_resize_object(struct Main *bmain,
const short totcol,
bool do_id_user);
void BKE_material_init(struct Material *ma);
+void BKE_material_gpencil_init(struct Material *ma);
void BKE_material_remap_object(struct Object *ob, const unsigned int *remap);
void BKE_material_remap_object_calc(struct Object *ob_dst,
struct Object *ob_src,
@@ -92,6 +94,7 @@ bool BKE_object_material_slot_add(struct Main *bmain, struct Object *ob);
bool BKE_object_material_slot_remove(struct Main *bmain, struct Object *ob);
bool BKE_object_material_slot_used(struct ID *id, short actcol);
+struct Material *BKE_material_gpencil_get(struct Object *ob, short act);
struct MaterialGPencilStyle *BKE_material_gpencil_settings_get(struct Object *ob, short act);
void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma);
@@ -123,6 +126,7 @@ struct Depsgraph;
void BKE_material_eval(struct Depsgraph *depsgraph, struct Material *material);
extern struct Material defmaterial;
+extern struct Material defgpencil_material;
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 15df0cff6fc..90afec54561 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -26,9 +26,6 @@
/* defines BLI_INLINE */
#include "BLI_compiler_compat.h"
-/* defines CustomDataMask */
-//#include "BKE_customdata.h"
-
struct BLI_Stack;
struct BMEditMesh;
struct BMesh;
@@ -81,12 +78,18 @@ struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me,
const bool add_key_index,
const struct BMeshCreateParams *params);
-struct Mesh *BKE_mesh_from_bmesh_nomain(struct BMesh *bm, const struct BMeshToMeshParams *params);
+struct Mesh *BKE_mesh_from_bmesh_nomain(struct BMesh *bm,
+ const struct BMeshToMeshParams *params,
+ const struct Mesh *me_settings);
struct Mesh *BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm,
- const struct CustomData_MeshMasks *cd_mask_extra);
+ const struct CustomData_MeshMasks *cd_mask_extra,
+ const struct Mesh *me_settings);
struct Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(
- struct BMEditMesh *em, const struct CustomData_MeshMasks *data_mask, float (*vertexCos)[3]);
+ struct BMEditMesh *em,
+ const struct CustomData_MeshMasks *data_mask,
+ float (*vertexCos)[3],
+ const struct Mesh *me_settings);
int poly_find_loop_from_vert(const struct MPoly *poly,
const struct MLoop *loopstart,
@@ -110,6 +113,7 @@ void BKE_mesh_copy_data(struct Main *bmain,
const struct Mesh *me_src,
const int flag);
struct Mesh *BKE_mesh_copy(struct Main *bmain, const struct Mesh *me);
+void BKE_mesh_copy_settings(struct Mesh *me_dst, const struct Mesh *me_src);
void BKE_mesh_update_customdata_pointers(struct Mesh *me, const bool do_ensure_tess_cd);
void BKE_mesh_ensure_skin_customdata(struct Mesh *me);
@@ -121,6 +125,13 @@ struct Mesh *BKE_mesh_new_nomain_from_template(const struct Mesh *me_src,
int tessface_len,
int loops_len,
int polys_len);
+struct Mesh *BKE_mesh_new_nomain_from_template_ex(const struct Mesh *me_src,
+ int verts_len,
+ int edges_len,
+ int tessface_len,
+ int loops_len,
+ int polys_len,
+ CustomData_MeshMasks mask);
void BKE_mesh_eval_delete(struct Mesh *me_eval);
@@ -137,8 +148,6 @@ bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me);
bool BKE_mesh_clear_facemap_customdata(struct Mesh *me);
void BKE_mesh_make_local(struct Main *bmain, struct Mesh *me, const bool lib_local);
-void BKE_mesh_boundbox_calc(struct Mesh *me, float r_loc[3], float r_size[3]);
-void BKE_mesh_texspace_calc(struct Mesh *me);
float (*BKE_mesh_orco_verts_get(struct Object *ob))[3];
void BKE_mesh_orco_verts_transform(struct Mesh *me, float (*orco)[3], int totvert, int invert);
int test_index_face(struct MFace *mface, struct CustomData *mfdata, int mfindex, int nr);
@@ -188,12 +197,14 @@ void BKE_mesh_smooth_flag_set(struct Mesh *me, const bool use_smooth);
const char *BKE_mesh_cmp(struct Mesh *me1, struct Mesh *me2, float thresh);
struct BoundBox *BKE_mesh_boundbox_get(struct Object *ob);
-struct BoundBox *BKE_mesh_texspace_get(struct Mesh *me,
- float r_loc[3],
- float r_rot[3],
- float r_size[3]);
-void BKE_mesh_texspace_get_reference(
- struct Mesh *me, short **r_texflag, float **r_loc, float **r_rot, float **r_size);
+
+void BKE_mesh_texspace_calc(struct Mesh *me);
+void BKE_mesh_texspace_ensure(struct Mesh *me);
+void BKE_mesh_texspace_get(struct Mesh *me, float r_loc[3], float r_size[3]);
+void BKE_mesh_texspace_get_reference(struct Mesh *me,
+ short **r_texflag,
+ float **r_loc,
+ float **r_size);
void BKE_mesh_texspace_copy_from_object(struct Mesh *me, struct Object *ob);
void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals);
@@ -473,6 +484,7 @@ void BKE_mesh_calc_poly_center(const struct MPoly *mpoly,
float BKE_mesh_calc_poly_area(const struct MPoly *mpoly,
const struct MLoop *loopstart,
const struct MVert *mvarray);
+float BKE_mesh_calc_area(const struct Mesh *me);
float BKE_mesh_calc_poly_uv_area(const struct MPoly *mpoly, const struct MLoopUV *uv_array);
void BKE_mesh_calc_poly_angles(const struct MPoly *mpoly,
const struct MLoop *loopstart,
diff --git a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h
index 089e4de4709..cc4a3a01892 100644
--- a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h
+++ b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h
@@ -16,8 +16,9 @@
* The Original Code is Copyright (C) 2019 by Blender Foundation
* All rights reserved.
*/
-#ifndef __BKE_REMESH_H__
-#define __BKE_REMESH_H__
+
+#ifndef __BKE_MESH_REMESH_VOXEL_H__
+#define __BKE_MESH_REMESH_VOXEL_H__
/** \file
* \ingroup bke
@@ -38,9 +39,21 @@ struct Mesh *BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(struct OpenVDBLeve
double adaptivity,
bool relax_disoriented_triangles);
#endif
-struct Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(struct Mesh *mesh, float voxel_size);
+
+struct Mesh *BKE_mesh_remesh_voxel_fix_poles(struct Mesh *mesh);
+struct Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(struct Mesh *mesh,
+ float voxel_size,
+ float adaptivity);
+struct Mesh *BKE_mesh_remesh_quadriflow_to_mesh_nomain(struct Mesh *mesh,
+ int target_faces,
+ int seed,
+ bool preserve_sharp,
+ bool preserve_boundary,
+ bool adaptive_scale,
+ void *update_cb,
+ void *update_cb_data);
/* Data reprojection functions */
void BKE_remesh_reproject_paint_mask(struct Mesh *target, struct Mesh *source);
-#endif /* __BKE_REMESH_H__ */
+#endif /* __BKE_MESH_REMESH_VOXEL_H__ */
diff --git a/source/blender/blenkernel/BKE_mirror.h b/source/blender/blenkernel/BKE_mirror.h
new file mode 100644
index 00000000000..20eb8a920fc
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mirror.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#ifndef __BKE_MIRROR_H__
+#define __BKE_MIRROR_H__
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BLI_utildefines.h"
+
+struct MirrorModifierData;
+struct ModifierEvalContext;
+struct Object;
+
+struct Mesh *BKE_mirror_bisect_on_mirror_plane(struct MirrorModifierData *mmd,
+ const struct Mesh *mesh,
+ int axis,
+ const float plane_co[3],
+ float plane_no[3]);
+
+struct Mesh *BKE_mirror_apply_mirror_on_axis(struct MirrorModifierData *mmd,
+ const struct ModifierEvalContext *UNUSED(ctx),
+ struct Object *ob,
+ const struct Mesh *mesh,
+ int axis);
+
+#endif /* __BKE_MIRROR_H__ */
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h
index c5955a9af8d..7513717df41 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -53,8 +53,8 @@ void multires_mark_as_modified(struct Depsgraph *depsgraph,
struct Object *object,
enum MultiresModifiedFlags flags);
-void multires_force_update(struct Object *ob);
-void multires_force_render_update(struct Object *ob);
+void multires_flush_sculpt_updates(struct Object *ob);
+void multires_force_sculpt_rebuild(struct Object *ob);
void multires_force_external_reload(struct Object *ob);
/* internal, only called in subsurf_ccg.c */
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index efc4e4fdc12..06fd7915476 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -30,13 +30,7 @@
#include "DNA_listBase.h"
/* for FOREACH_NODETREE_BEGIN */
-#include "DNA_light_types.h"
-#include "DNA_material_types.h"
#include "DNA_node_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_texture_types.h"
-#include "DNA_world_types.h"
-#include "DNA_linestyle_types.h"
#include "RNA_types.h"
@@ -46,19 +40,23 @@
struct ARegion;
struct ColorManagedDisplaySettings;
struct ColorManagedViewSettings;
+struct FreestyleLineStyle;
struct GPUMaterial;
struct GPUNodeStack;
struct ID;
struct ImBuf;
struct ImageFormatData;
+struct Light;
struct ListBase;
struct MTex;
struct Main;
+struct Material;
struct PointerRNA;
struct RenderData;
struct Scene;
struct SpaceNode;
struct Tex;
+struct World;
struct bContext;
struct bNode;
struct bNodeExecContext;
@@ -384,6 +382,7 @@ void ntreeUserIncrefID(struct bNodeTree *ntree);
void ntreeUserDecrefID(struct bNodeTree *ntree);
struct bNodeTree *ntreeFromID(const struct ID *id);
+struct ID *BKE_node_tree_find_owner_ID(struct Main *bmain, struct bNodeTree *ntree);
void ntreeMakeLocal(struct Main *bmain,
struct bNodeTree *ntree,
@@ -592,6 +591,10 @@ void nodeChainIter(const bNodeTree *ntree,
bool (*callback)(bNode *, bNode *, void *, const bool),
void *userdata,
const bool reversed);
+void nodeChainIterBackwards(const bNodeTree *ntree,
+ const bNode *node_start,
+ bool (*callback)(bNode *, bNode *, void *),
+ void *userdata);
void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata);
struct bNodeLink *nodeFindLink(struct bNodeTree *ntree,
@@ -831,11 +834,11 @@ void BKE_node_tree_unlink_id(ID *id, struct bNodeTree *ntree);
struct NodeTreeIterStore {
bNodeTree *ngroup;
Scene *scene;
- Material *mat;
+ struct Material *mat;
Tex *tex;
- Light *light;
- World *world;
- FreestyleLineStyle *linestyle;
+ struct Light *light;
+ struct World *world;
+ struct FreestyleLineStyle *linestyle;
};
void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *bmain);
@@ -979,6 +982,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
#define SH_NODE_CLAMP 703
#define SH_NODE_TEX_WHITE_NOISE 704
#define SH_NODE_VOLUME_INFO 705
+#define SH_NODE_VERTEX_COLOR 706
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index cf4bce3a209..ffdcb9cd2c0 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -110,7 +110,7 @@ typedef enum eObjectVisibilityResult {
int BKE_object_visibility(const struct Object *ob, const int dag_eval_mode);
-void BKE_object_init(struct Object *ob);
+void BKE_object_init(struct Object *ob, const short ob_type);
struct Object *BKE_object_add_only_object(struct Main *bmain, int type, const char *name)
ATTR_NONNULL(1) ATTR_RETURNS_NONNULL;
struct Object *BKE_object_add(struct Main *bmain,
@@ -222,7 +222,13 @@ void BKE_boundbox_minmax(const struct BoundBox *bb,
struct BoundBox *BKE_object_boundbox_get(struct Object *ob);
void BKE_object_dimensions_get(struct Object *ob, float vec[3]);
+void BKE_object_dimensions_set_ex(struct Object *ob,
+ const float value[3],
+ int axis_mask,
+ const float ob_scale_orig[3],
+ const float ob_obmat_orig[4][4]);
void BKE_object_dimensions_set(struct Object *ob, const float value[3], int axis_mask);
+
void BKE_object_empty_draw_type_set(struct Object *ob, const int value);
void BKE_object_boundbox_flag(struct Object *ob, int flag, const bool set);
void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval);
@@ -315,8 +321,10 @@ void BKE_object_handle_update_ex(struct Depsgraph *depsgraph,
void BKE_object_sculpt_data_create(struct Object *ob);
-int BKE_object_obdata_texspace_get(
- struct Object *ob, short **r_texflag, float **r_loc, float **r_size, float **r_rot);
+int BKE_object_obdata_texspace_get(struct Object *ob,
+ short **r_texflag,
+ float **r_loc,
+ float **r_size);
struct Mesh *BKE_object_get_evaluated_mesh(const struct Depsgraph *depsgraph, struct Object *ob);
struct Mesh *BKE_object_get_final_mesh(struct Object *object);
diff --git a/source/blender/blenkernel/BKE_object_facemap.h b/source/blender/blenkernel/BKE_object_facemap.h
index ef0cbaa2ae6..83780d8fad5 100644
--- a/source/blender/blenkernel/BKE_object_facemap.h
+++ b/source/blender/blenkernel/BKE_object_facemap.h
@@ -40,6 +40,11 @@ void BKE_object_facemap_unique_name(struct Object *ob, struct bFaceMap *fmap);
struct bFaceMap *BKE_object_facemap_find_name(struct Object *ob, const char *name);
void BKE_object_facemap_copy_list(struct ListBase *outbase, const struct ListBase *inbase);
+int *BKE_object_facemap_index_map_create(struct Object *ob_src,
+ struct Object *ob_dst,
+ int *r_map_len);
+void BKE_object_facemap_index_map_apply(int *fmap, int fmap_len, const int *map, int map_len);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 8db27bd4118..8580aefcfbc 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -256,9 +256,31 @@ typedef struct SculptSession {
float (*layer_co)[3]; /* Copy of the mesh vertices' locations */
struct StrokeCache *cache;
+ struct FilterCache *filter_cache;
+ /* Cursor data and active vertex for tools */
int active_vertex_index;
+ float cursor_radius;
+ float cursor_location[3];
+ float cursor_normal[3];
+ float cursor_view_normal[3];
+ struct RegionView3D *rv3d;
+
+ /* Dynamic mesh preview */
+ int *preview_vert_index_list;
+ int preview_vert_index_count;
+ float pose_origin[3];
+
+ /* Transform operator */
+ float pivot_pos[3];
+ float pivot_rot[4];
+ float pivot_scale[3];
+
+ float init_pivot_pos[3];
+ float init_pivot_rot[4];
+ float init_pivot_scale[3];
+
union {
struct {
struct SculptVertexPaintGeomMap gmap;
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 93a826f3324..dedf76ee839 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -24,7 +24,9 @@
#include "BLI_bitmap.h"
#include "BLI_ghash.h"
-#include "BLI_utildefines.h"
+
+/* For embedding CCGKey in iterator. */
+#include "BKE_ccg.h"
struct BMLog;
struct BMesh;
@@ -41,6 +43,7 @@ struct MVert;
struct PBVH;
struct PBVHNode;
struct SubdivCCG;
+struct TaskParallelSettings;
typedef struct PBVH PBVH;
typedef struct PBVHNode PBVHNode;
@@ -50,20 +53,28 @@ typedef struct {
} PBVHProxyNode;
typedef enum {
- PBVH_Leaf = 1,
+ PBVH_Leaf = 1 << 0,
- PBVH_UpdateNormals = 2,
- PBVH_UpdateBB = 4,
- PBVH_UpdateOriginalBB = 8,
- PBVH_UpdateDrawBuffers = 16,
- PBVH_UpdateRedraw = 32,
+ PBVH_UpdateNormals = 1 << 1,
+ PBVH_UpdateBB = 1 << 2,
+ PBVH_UpdateOriginalBB = 1 << 3,
+ PBVH_UpdateDrawBuffers = 1 << 4,
+ PBVH_UpdateRedraw = 1 << 5,
+ PBVH_UpdateMask = 1 << 6,
- PBVH_RebuildDrawBuffers = 64,
- PBVH_FullyHidden = 128,
+ PBVH_RebuildDrawBuffers = 1 << 7,
+ PBVH_FullyHidden = 1 << 8,
+ PBVH_FullyMasked = 1 << 9,
+ PBVH_FullyUnmasked = 1 << 10,
- PBVH_UpdateTopology = 256,
+ PBVH_UpdateTopology = 1 << 11,
} PBVHNodeFlags;
+typedef struct PBVHFrustumPlanes {
+ float (*planes)[4];
+ int num_planes;
+} PBVHFrustumPlanes;
+
/* Callbacks */
/* returns 1 if the search should continue from this node, 0 otherwise */
@@ -132,8 +143,11 @@ bool BKE_pbvh_node_raycast(PBVH *bvh,
float (*origco)[3],
bool use_origco,
const float ray_start[3],
+ const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
- float *depth);
+ float *depth,
+ int *active_vertex_index,
+ float *face_normal);
bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
const float ray_start[3],
@@ -165,7 +179,9 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *bvh,
/* Drawing */
void BKE_pbvh_draw_cb(PBVH *bvh,
- float (*planes)[4],
+ bool show_vcol,
+ bool update_only_visible,
+ PBVHFrustumPlanes *frustum,
void (*draw_fn)(void *user_data, struct GPU_PBVH_Buffers *buffers),
void *user_data);
@@ -196,9 +212,10 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
int gridsize);
/* multires level, only valid for type == PBVH_GRIDS */
-void BKE_pbvh_get_grid_key(const PBVH *pbvh, struct CCGKey *key);
+const struct CCGKey *BKE_pbvh_get_grid_key(const PBVH *pbvh);
-struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh, int *num_grids);
+struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh);
+int BKE_pbvh_get_grid_num_vertices(const PBVH *pbvh);
/* Only valid for type == PBVH_BMESH */
struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh);
@@ -219,11 +236,16 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh,
/* Node Access */
void BKE_pbvh_node_mark_update(PBVHNode *node);
+void BKE_pbvh_node_mark_update_mask(PBVHNode *node);
void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node);
void BKE_pbvh_node_mark_redraw(PBVHNode *node);
void BKE_pbvh_node_mark_normals_update(PBVHNode *node);
void BKE_pbvh_node_mark_topology_update(PBVHNode *node);
void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden);
+void BKE_pbvh_node_fully_masked_set(PBVHNode *node, int fully_masked);
+bool BKE_pbvh_node_fully_masked_get(PBVHNode *node);
+void BKE_pbvh_node_fully_unmasked_set(PBVHNode *node, int fully_masked);
+bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node);
void BKE_pbvh_node_get_grids(PBVH *bvh,
PBVHNode *node,
@@ -243,10 +265,10 @@ void BKE_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max
float BKE_pbvh_node_get_tmin(PBVHNode *node);
-/* test if AABB is at least partially inside the planes' volume */
-bool BKE_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data);
-/* test if AABB is at least partially outside the planes' volume */
-bool BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data);
+/* test if AABB is at least partially inside the PBVHFrustumPlanes volume */
+bool BKE_pbvh_node_frustum_contain_AABB(PBVHNode *node, void *frustum);
+/* test if AABB is at least partially outside the PBVHFrustumPlanes volume */
+bool BKE_pbvh_node_frustum_exclude_AABB(PBVHNode *node, void *frustum);
struct GSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node);
struct GSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node);
@@ -257,8 +279,8 @@ void BKE_pbvh_bmesh_after_stroke(PBVH *bvh);
/* Update Bounding Box/Redraw and clear flags */
void BKE_pbvh_update_bounds(PBVH *bvh, int flags);
+void BKE_pbvh_update_vertex_data(PBVH *bvh, int flags);
void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg);
-void BKE_pbvh_update_draw_buffers(PBVH *bvh, bool show_vcol);
void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]);
void BKE_pbvh_get_grid_updates(PBVH *bvh, bool clear, void ***r_gridfaces, int *r_totface);
void BKE_pbvh_grids_update(PBVH *bvh,
@@ -302,9 +324,9 @@ typedef struct PBVHVertexIter {
int index;
/* grid */
+ struct CCGKey key;
struct CCGElem **grids;
struct CCGElem *grid;
- struct CCGKey *key;
BLI_bitmap **grid_hidden, *gh;
int *grid_indices;
int totgrid;
@@ -341,6 +363,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo
if (vi.grids) { \
vi.width = vi.gridsize; \
vi.height = vi.gridsize; \
+ vi.index = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \
vi.grid = vi.grids[vi.grid_indices[vi.g]]; \
if (mode == PBVH_ITER_UNIQUE) \
vi.gh = vi.grid_hidden[vi.grid_indices[vi.g]]; \
@@ -353,10 +376,11 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo
for (vi.gy = 0; vi.gy < vi.height; vi.gy++) { \
for (vi.gx = 0; vi.gx < vi.width; vi.gx++, vi.i++) { \
if (vi.grid) { \
- vi.co = CCG_elem_co(vi.key, vi.grid); \
- vi.fno = CCG_elem_no(vi.key, vi.grid); \
- vi.mask = vi.key->has_mask ? CCG_elem_mask(vi.key, vi.grid) : NULL; \
- vi.grid = CCG_elem_next(vi.key, vi.grid); \
+ vi.co = CCG_elem_co(&vi.key, vi.grid); \
+ vi.fno = CCG_elem_no(&vi.key, vi.grid); \
+ vi.mask = vi.key.has_mask ? CCG_elem_mask(&vi.key, vi.grid) : NULL; \
+ vi.grid = CCG_elem_next(&vi.key, vi.grid); \
+ vi.index++; \
if (vi.gh) { \
if (BLI_BITMAP_TEST(vi.gh, vi.gy * vi.gridsize + vi.gx)) \
continue; \
@@ -406,6 +430,10 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node);
+void BKE_pbvh_parallel_range_settings(struct TaskParallelSettings *settings,
+ bool use_threading,
+ int totnode);
+
// void BKE_pbvh_node_BB_reset(PBVHNode *node);
// void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]);
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index d25288fc240..846b8d21f28 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -220,7 +220,8 @@ void BKE_scene_allocate_depsgraph_hash(struct Scene *scene);
void BKE_scene_ensure_depsgraph_hash(struct Scene *scene);
void BKE_scene_free_depsgraph_hash(struct Scene *scene);
-struct Depsgraph *BKE_scene_get_depsgraph(struct Scene *scene,
+struct Depsgraph *BKE_scene_get_depsgraph(struct Main *bmain,
+ struct Scene *scene,
struct ViewLayer *view_layer,
bool allocate);
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index e1bc16702d5..16f766ae8bb 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -82,6 +82,11 @@ void BKE_sequence_iterator_end(SeqIterator *iter);
} \
((void)0)
+typedef enum eSeqTaskId {
+ SEQ_TASK_MAIN_RENDER,
+ SEQ_TASK_PREFETCH_RENDER,
+} eSeqTaskId;
+
typedef struct SeqRenderData {
struct Main *bmain;
struct Depsgraph *depsgraph;
@@ -94,7 +99,10 @@ typedef struct SeqRenderData {
float motion_blur_shutter;
bool skip_cache;
bool is_proxy_render;
+ bool is_prefetch_render;
int view_id;
+ /* ID of task for asigning temp cache entries to particular task(thread, etc.) */
+ eSeqTaskId task_id;
/* special case for OpenGL render */
struct GPUOffScreen *gpu_offscreen;
@@ -290,7 +298,7 @@ void BKE_sequencer_proxy_rebuild_context(struct Main *bmain,
void BKE_sequencer_proxy_rebuild(struct SeqIndexBuildContext *context,
short *stop,
short *do_update,
- float *progress);
+ float *num_frames_prefetched);
void BKE_sequencer_proxy_rebuild_finish(struct SeqIndexBuildContext *context, bool stop);
void BKE_sequencer_proxy_set(struct Sequence *seq, bool value);
@@ -318,6 +326,7 @@ bool BKE_sequencer_cache_put_if_possible(const SeqRenderData *context,
int type,
struct ImBuf *nval,
float cost);
+bool BKE_sequencer_cache_recycle_item(struct Scene *scene);
void BKE_sequencer_cache_free_temp_cache(struct Scene *scene, short id, int cfra);
void BKE_sequencer_cache_destruct(struct Scene *scene);
void BKE_sequencer_cache_cleanup_all(struct Main *bmain);
@@ -330,6 +339,22 @@ void BKE_sequencer_cache_iterate(
struct Scene *scene,
void *userdata,
bool callback(void *userdata, struct Sequence *seq, int cfra, int cache_type, float cost));
+bool BKE_sequencer_cache_is_full(struct Scene *scene);
+
+/* **********************************************************************
+ * seqprefetch.c
+ *
+ * Sequencer frame prefetching
+ * ********************************************************************** */
+
+void BKE_sequencer_prefetch_start(const SeqRenderData *context, float cfra, float cost);
+void BKE_sequencer_prefetch_stop(struct Scene *scene);
+void BKE_sequencer_prefetch_free(struct Scene *scene);
+bool BKE_sequencer_prefetch_need_redraw(struct Main *bmain, struct Scene *scene);
+void BKE_sequencer_prefetch_get_time_range(struct Scene *scene, int *start, int *end);
+SeqRenderData *BKE_sequencer_prefetch_get_original_context(const SeqRenderData *context);
+struct Sequence *BKE_sequencer_prefetch_get_original_sequence(struct Sequence *seq,
+ struct Scene *scene);
/* **********************************************************************
* seqeffects.c
diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h
index 9ec75c39fcf..e90b1429c9d 100644
--- a/source/blender/blenkernel/BKE_shrinkwrap.h
+++ b/source/blender/blenkernel/BKE_shrinkwrap.h
@@ -110,6 +110,16 @@ void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd,
float (*vertexCos)[3],
int numVerts);
+/* Used in editmesh_mask_extract.c to shrinkwrap the extracted mesh to the sculpt */
+void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C,
+ struct Object *ob_source,
+ struct Object *ob_target);
+
+/* Used in object_remesh.c to preserve the details and volume in the voxel remesher */
+void BKE_shrinkwrap_remesh_target_project(struct Mesh *src_me,
+ struct Mesh *target_me,
+ struct Object *ob_target);
+
/*
* This function casts a ray in the given BVHTree.
* but it takes into consideration the space_transform, that is:
diff --git a/source/blender/blenkernel/BKE_studiolight.h b/source/blender/blenkernel/BKE_studiolight.h
index d6fff528348..c6d1e61fb47 100644
--- a/source/blender/blenkernel/BKE_studiolight.h
+++ b/source/blender/blenkernel/BKE_studiolight.h
@@ -26,14 +26,13 @@
* Studio lighting for the 3dview
*/
-#include "BKE_context.h"
-
#include "BLI_sys_types.h"
-#include "DNA_space_types.h"
+#include "BLI_path_util.h"
+
#include "DNA_userdef_types.h"
-#include "IMB_imbuf_types.h"
+struct ImBuf;
/*
* These defines are the indexes in the StudioLight.diffuse_light
@@ -87,6 +86,11 @@ enum StudioLightFlag {
STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED = (1 << 11),
STUDIOLIGHT_USER_DEFINED = (1 << 12),
STUDIOLIGHT_UI_EXPANDED = (1 << 13),
+
+ STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE = (1 << 14),
+ STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE = (1 << 15),
+ /* Is set for studio lights and matcaps with specular highlight pass. */
+ STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS = (1 << 16),
};
#define STUDIOLIGHT_FLAG_ALL (STUDIOLIGHT_INTERNAL | STUDIOLIGHT_EXTERNAL_FILE)
@@ -97,6 +101,11 @@ enum StudioLightFlag {
typedef void StudioLightFreeFunction(struct StudioLight *, void *data);
+typedef struct StudioLightImage {
+ struct ImBuf *ibuf;
+ struct GPUTexture *gputexture;
+} StudioLightImage;
+
typedef struct StudioLight {
struct StudioLight *next, *prev;
@@ -112,9 +121,11 @@ typedef struct StudioLight {
int icon_id_matcap_flipped;
float spherical_harmonics_coefs[STUDIOLIGHT_SH_EFFECTIVE_COEFS_LEN][3];
float light_direction[3];
- ImBuf *equirect_radiance_buffer;
- ImBuf *equirect_irradiance_buffer;
- ImBuf *radiance_cubemap_buffers[6];
+ StudioLightImage matcap_diffuse;
+ StudioLightImage matcap_specular;
+ struct ImBuf *equirect_radiance_buffer;
+ struct ImBuf *equirect_irradiance_buffer;
+ struct ImBuf *radiance_cubemap_buffers[6];
struct GPUTexture *equirect_radiance_gputexture;
struct GPUTexture *equirect_irradiance_gputexture;
SolidLight light[STUDIOLIGHT_MAX_LIGHT];
diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h
index 700bf5139e0..267a03da25c 100644
--- a/source/blender/blenkernel/BKE_subdiv.h
+++ b/source/blender/blenkernel/BKE_subdiv.h
@@ -140,7 +140,7 @@ typedef struct SubdivDisplacement {
/* This structure contains everything needed to construct subdivided surface.
* It does not specify storage, memory layout or anything else.
- * It is possible to create different storages (like, grid based CPU side
+ * It is possible to create different storage's (like, grid based CPU side
* buffers, GPU subdivision mesh, CPU side fully qualified mesh) from the same
* Subdiv structure. */
typedef struct Subdiv {
diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h
index 2e9ccb8b39d..e235193a486 100644
--- a/source/blender/blenkernel/BKE_subdiv_ccg.h
+++ b/source/blender/blenkernel/BKE_subdiv_ccg.h
@@ -150,7 +150,7 @@ typedef struct SubdivCCG {
struct CCGElem **edges;
int num_edges;
/* Loose vertices. Every element corresponds to a loose vertex from a coarse
- * mesh, every coarse loose vertex corresponds to a single sundivided
+ * mesh, every coarse loose vertex corresponds to a single subdivided
* element. */
struct CCGElem *vertices;
int num_vertices;
diff --git a/source/blender/blenkernel/BKE_subdiv_deform.h b/source/blender/blenkernel/BKE_subdiv_deform.h
new file mode 100644
index 00000000000..f1a56aa9cde
--- /dev/null
+++ b/source/blender/blenkernel/BKE_subdiv_deform.h
@@ -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.
+ *
+ * The Original Code is Copyright (C) 2019 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifndef __BKE_SUBDIV_DEFORM_H__
+#define __BKE_SUBDIV_DEFORM_H__
+
+#include "BLI_sys_types.h"
+
+struct Mesh;
+struct Subdiv;
+
+/* Special version of subdivision surface which calculates final positions for coarse vertices.
+ *
+ * vertex_cos are supposed to hold coordinates of the coarse mesh. */
+void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv,
+ const struct Mesh *coarse_mesh,
+ float (*vertex_cos)[3],
+ int num_verts);
+
+#endif /* __BKE_SUBDIV_DEFORM_H__ */
diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h
index 1d794e4d61a..c8d672c2524 100644
--- a/source/blender/blenkernel/BKE_subdiv_eval.h
+++ b/source/blender/blenkernel/BKE_subdiv_eval.h
@@ -31,7 +31,12 @@ struct Subdiv;
/* Returns true if evaluator is ready for use. */
bool BKE_subdiv_eval_begin(struct Subdiv *subdiv);
-bool BKE_subdiv_eval_update_from_mesh(struct Subdiv *subdiv, const struct Mesh *mesh);
+
+/* coarse_vertex_cos is an optional argument which allows to override coordinates of the coarse
+ * mesh. */
+bool BKE_subdiv_eval_update_from_mesh(struct Subdiv *subdiv,
+ const struct Mesh *mesh,
+ const float (*coarse_vertex_cos)[3]);
/* Makes sure displacement evaluator is initialized.
*
diff --git a/source/blender/blenkernel/BKE_subdiv_topology.h b/source/blender/blenkernel/BKE_subdiv_topology.h
new file mode 100644
index 00000000000..dd057d88fb6
--- /dev/null
+++ b/source/blender/blenkernel/BKE_subdiv_topology.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.
+ *
+ * The Original Code is Copyright (C) 2019 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifndef __BKE_SUBDIV_TOPOLOGY_H__
+#define __BKE_SUBDIV_TOPOLOGY_H__
+
+struct Subdiv;
+
+int BKE_subdiv_topology_num_fvar_layers_get(const struct Subdiv *subdiv);
+
+#endif /* __BKE_SUBDIV_TOPOLOGY_H__ */
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 669abff6599..47b44c3828a 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -50,6 +50,9 @@ set(INC
../../../intern/opensubdiv
../../../extern/curve_fit_nd
../../../intern/smoke/extern
+
+ # dna_type_offsets.h
+ ${CMAKE_CURRENT_BINARY_DIR}/../makesdna/intern
)
set(INC_SYS
@@ -83,6 +86,7 @@ set(SRC
intern/brush.c
intern/bvhutils.c
intern/cachefile.c
+ intern/callbacks.c
intern/camera.c
intern/cdderivedmesh.c
intern/cloth.c
@@ -155,6 +159,7 @@ set(SRC
intern/mesh_runtime.c
intern/mesh_tangent.c
intern/mesh_validate.c
+ intern/mirror.c
intern/modifier.c
intern/movieclip.c
intern/multires.c
@@ -186,6 +191,7 @@ set(SRC
intern/seqcache.c
intern/seqeffects.c
intern/seqmodifier.c
+ intern/seqprefetch.c
intern/sequencer.c
intern/shader_fx.c
intern/shrinkwrap.c
@@ -200,12 +206,14 @@ set(SRC
intern/subdiv_ccg_material.c
intern/subdiv_converter.c
intern/subdiv_converter_mesh.c
+ intern/subdiv_deform.c
intern/subdiv_displacement.c
intern/subdiv_displacement_multires.c
intern/subdiv_eval.c
intern/subdiv_foreach.c
intern/subdiv_mesh.c
intern/subdiv_stats.c
+ intern/subdiv_topology.c
intern/subsurf_ccg.c
intern/suggestions.c
intern/text.c
@@ -243,6 +251,7 @@ set(SRC
BKE_brush.h
BKE_bvhutils.h
BKE_cachefile.h
+ BKE_callbacks.h
BKE_camera.h
BKE_ccg.h
BKE_cdderivedmesh.h
@@ -304,6 +313,7 @@ set(SRC
BKE_mesh_remesh_voxel.h
BKE_mesh_runtime.h
BKE_mesh_tangent.h
+ BKE_mirror.h
BKE_modifier.h
BKE_movieclip.h
BKE_multires.h
@@ -333,9 +343,11 @@ set(SRC
BKE_studiolight.h
BKE_subdiv.h
BKE_subdiv_ccg.h
+ BKE_subdiv_deform.h
BKE_subdiv_eval.h
BKE_subdiv_foreach.h
BKE_subdiv_mesh.h
+ BKE_subdiv_topology.h
BKE_subsurf.h
BKE_suggestions.h
BKE_text.h
@@ -615,9 +627,22 @@ if(WITH_OPENVDB)
endif()
endif()
+if(WITH_QUADRIFLOW)
+ list(APPEND INC
+ ../../../intern/quadriflow
+ )
+ list(APPEND LIB
+ bf_intern_quadriflow
+ )
+ add_definitions(-DWITH_QUADRIFLOW)
+endif()
+
## Warnings as errors, this is too strict!
#if(MSVC)
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
#endif()
blender_add_lib(bf_blenkernel "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+# Needed so we can use dna_type_offsets.h for defaults initialization.
+add_dependencies(bf_blenkernel bf_dna)
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
index 973d5415567..699075f6cff 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
@@ -697,7 +697,7 @@ static void opensubdiv_evaluateNGonFaceGrids(CCGSubSurf *ss,
int x, S0 = 0, S1 = 0;
bool flip;
- for (x = 0; x < face->numVerts; ++x) {
+ for (x = 0; x < face->numVerts; x++) {
if (all_verts[x] == edge->v0) {
S0 = x;
}
@@ -806,7 +806,7 @@ void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, DerivedMesh *dm)
const MPoly *mpoly = dm->getPolyArray(dm);
int poly;
ss->numGrids = 0;
- for (poly = 0; poly < num_polys; ++poly) {
+ for (poly = 0; poly < num_polys; poly++) {
ss->numGrids += mpoly[poly].totloop;
}
}
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
index eb04d13d4a0..e77b65eca25 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
@@ -172,7 +172,7 @@ static int conv_dm_get_num_edge_faces(const OpenSubdiv_Converter *converter, int
for (loop = 0; loop < mpoly->totloop; loop++) {
const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
if (mloop->e == edge) {
- ++num;
+ num++;
break;
}
}
@@ -226,7 +226,7 @@ static int conv_dm_get_num_vert_edges(const OpenSubdiv_Converter *converter, int
for (edge = 0; edge < dm->getNumEdges(dm); edge++) {
const MEdge *medge = &user_data->medge[edge];
if (medge->v1 == vert || medge->v2 == vert) {
- ++num;
+ num++;
}
}
return num;
@@ -268,7 +268,7 @@ static int conv_dm_get_num_vert_faces(const OpenSubdiv_Converter *converter, int
for (loop = 0; loop < mpoly->totloop; loop++) {
const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
if (mloop->v == vert) {
- ++num;
+ num++;
break;
}
}
@@ -357,23 +357,23 @@ static void conv_dm_precalc_uv_layer(const OpenSubdiv_Converter *converter, int
* The idea here is that we need to pass individual islands to OpenSubdiv.
*/
storage->num_uvs = 0;
- for (int island = 0; island < storage->island_store.islands_num; ++island) {
+ for (int island = 0; island < storage->island_store.islands_num; island++) {
MeshElemMap *island_poly_map = storage->island_store.islands[island];
- for (int poly = 0; poly < island_poly_map->count; ++poly) {
+ for (int poly = 0; poly < island_poly_map->count; poly++) {
int poly_index = island_poly_map->indices[poly];
/* Within the same UV island we should share UV points across
* loops. Otherwise each poly will be subdivided individually
* which we don't really want.
*/
const MPoly *mpoly = &storage->mpoly[poly_index];
- for (int loop = 0; loop < mpoly->totloop; ++loop) {
+ for (int loop = 0; loop < mpoly->totloop; loop++) {
const MLoopUV *luv = &mloopuv[mpoly->loopstart + loop];
bool found = false;
/* TODO(sergey): Quite bad loop, which gives us O(N^2)
* complexity here. But how can we do it smarter, hopefully
* without requiring lots of additional memory.
*/
- for (int i = 0; i < storage->num_uvs; ++i) {
+ for (int i = 0; i < storage->num_uvs; i++) {
if (equals_v2v2(luv->uv, &storage->uvs[2 * i])) {
storage->face_uvs[mpoly->loopstart + loop] = i;
found = true;
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 010e162f49d..4849d631493 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -729,7 +729,7 @@ static Mesh *create_orco_mesh(Object *ob, Mesh *me, BMEditMesh *em, int layer)
int free;
if (em) {
- mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL);
+ mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, me);
}
else {
mesh = BKE_mesh_copy_for_eval(me, true);
@@ -797,14 +797,6 @@ static void editmesh_update_statvis_color(const Scene *scene, Object *ob)
BKE_editmesh_statvis_calc(em, me->runtime.edit_data, &scene->toolsettings->statvis);
}
-static void mesh_copy_autosmooth(Mesh *me, Mesh *me_orig)
-{
- if (me_orig->flag & ME_AUTOSMOOTH) {
- me->flag |= ME_AUTOSMOOTH;
- me->smoothresh = me_orig->smoothresh;
- }
-}
-
static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
const CustomData_MeshMasks *final_datamask,
const bool sculpt_dyntopo,
@@ -881,18 +873,8 @@ static void mesh_calc_finalize(const Mesh *mesh_input, Mesh *mesh_eval)
/* Make sure the name is the same. This is because mesh allocation from template does not
* take care of naming. */
BLI_strncpy(mesh_eval->id.name, mesh_input->id.name, sizeof(mesh_eval->id.name));
- /* Make sure materials are preserved from the input. */
- if (mesh_eval->mat != NULL) {
- MEM_freeN(mesh_eval->mat);
- }
- mesh_eval->mat = MEM_dupallocN(mesh_input->mat);
- mesh_eval->totcol = mesh_input->totcol;
/* Make evaluated mesh to share same edit mesh pointer as original and copied meshes. */
mesh_eval->edit_mesh = mesh_input->edit_mesh;
- /* Copy auth-smooth settings which are also not taken care about by mesh allocation from a
- * template. */
- mesh_eval->flag |= (mesh_input->flag & ME_AUTOSMOOTH);
- mesh_eval->smoothresh = mesh_input->smoothresh;
}
static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
@@ -1220,8 +1202,6 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
MEM_freeN(deformed_verts);
deformed_verts = NULL;
}
-
- mesh_copy_autosmooth(mesh_final, mesh_input);
}
/* create an orco mesh in parallel */
@@ -1533,8 +1513,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Evaluate modifiers up to certain index to get the mesh cage. */
int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
if (r_cage && cageIndex == -1) {
- mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(em_input, &final_datamask, NULL);
- mesh_copy_autosmooth(mesh_cage, mesh_input);
+ mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(
+ em_input, &final_datamask, NULL, mesh_input);
}
/* Clear errors before evaluation. */
@@ -1574,9 +1554,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
if (mesh_final == NULL) {
- mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL);
+ mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL, mesh_input);
ASSERT_IS_VALID_MESH(mesh_final);
- mesh_copy_autosmooth(mesh_final, mesh_input);
}
BLI_assert(deformed_verts != NULL);
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
@@ -1607,11 +1586,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
}
else {
- mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL);
+ mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL, mesh_input);
ASSERT_IS_VALID_MESH(mesh_final);
- mesh_copy_autosmooth(mesh_final, mesh_input);
-
if (deformed_verts) {
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
}
@@ -1674,8 +1651,6 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
MEM_freeN(deformed_verts);
deformed_verts = NULL;
}
-
- mesh_copy_autosmooth(mesh_final, mesh_input);
}
mesh_final->runtime.deformed_only = false;
}
@@ -1695,8 +1670,10 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
me_orig->runtime.edit_data->vertexCos = MEM_dupallocN(deformed_verts);
}
mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(
- em_input, &final_datamask, deformed_verts ? MEM_dupallocN(deformed_verts) : NULL);
- mesh_copy_autosmooth(mesh_cage, mesh_input);
+ em_input,
+ &final_datamask,
+ deformed_verts ? MEM_dupallocN(deformed_verts) : NULL,
+ mesh_input);
}
}
@@ -1730,11 +1707,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
else {
/* this is just a copy of the editmesh, no need to calc normals */
mesh_final = BKE_mesh_from_editmesh_with_coords_thin_wrap(
- em_input, &final_datamask, deformed_verts);
+ em_input, &final_datamask, deformed_verts, mesh_input);
deformed_verts = NULL;
- mesh_copy_autosmooth(mesh_final, mesh_input);
-
/* In this case, we should never have weight-modifying modifiers in stack... */
if (do_init_statvis) {
editmesh_update_statvis_color(scene, ob);
@@ -1854,11 +1829,6 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
&ob->runtime.mesh_eval);
BKE_object_boundbox_calc_from_mesh(ob, ob->runtime.mesh_eval);
- /* Only copy texspace from orig mesh if some modifier (hint: smoke sim, see T58492)
- * did not re-enable that flag (which always get disabled for eval mesh as a start). */
- if (!(ob->runtime.mesh_eval->texflag & ME_AUTOSPACE)) {
- BKE_mesh_texspace_copy_from_object(ob->runtime.mesh_eval, ob);
- }
assign_object_mesh_eval(ob);
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index ab8ea37377d..2e655452a21 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -305,8 +305,9 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
/* make a copy of action - at worst, user has to delete copies... */
if (do_action) {
BLI_assert(bmain != NULL);
- BKE_id_copy(bmain, (ID *)dadt->action, (ID **)&dadt->action);
- BKE_id_copy(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact);
+ BLI_assert(dadt->action == NULL || dadt->action != dadt->tmpact);
+ BKE_id_copy_ex(bmain, (ID *)dadt->action, (ID **)&dadt->action, flag);
+ BKE_id_copy_ex(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact, flag);
}
else if (do_id_user) {
id_us_plus((ID *)dadt->action);
@@ -4081,11 +4082,10 @@ void BKE_animsys_update_driver_array(ID *id)
}
}
-void BKE_animsys_eval_driver(Depsgraph *depsgraph,
- ID *id,
- int driver_index,
- ChannelDriver *driver_orig)
+void BKE_animsys_eval_driver(Depsgraph *depsgraph, ID *id, int driver_index, FCurve *fcu_orig)
{
+ BLI_assert(fcu_orig != NULL);
+
/* TODO(sergey): De-duplicate with BKE animsys. */
PointerRNA id_ptr;
bool ok = false;
@@ -4110,6 +4110,7 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph,
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
/* check if driver itself is tagged for recalculation */
/* XXX driver recalc flag is not set yet by depsgraph! */
+ ChannelDriver *driver_orig = fcu_orig->driver;
if ((driver_orig) && !(driver_orig->flag & DRIVER_FLAG_INVALID)) {
/* evaluate this using values set already in other places
* NOTE: for 'layering' option later on, we should check if we should remove old value before
@@ -4120,7 +4121,7 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph,
if (animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
/* Evaluate driver, and write results to COW-domain destination */
const float ctime = DEG_get_ctime(depsgraph);
- const float curval = evaluate_fcurve_driver(&anim_rna, fcu, driver_orig, ctime);
+ const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
ok = animsys_write_rna_setting(&anim_rna, curval);
/* Flush results & status codes to original data for UI (T59984) */
@@ -4128,6 +4129,7 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph,
animsys_write_orig_anim_rna(&id_ptr, fcu->rna_path, fcu->array_index, curval);
/* curval is displayed in the UI, and flag contains error-status codes */
+ fcu_orig->curval = fcu->curval;
driver_orig->curval = fcu->driver->curval;
driver_orig->flag = fcu->driver->flag;
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index 3b64a9520ca..fbac9e6b773 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -110,7 +110,7 @@ const char *BKE_appdir_folder_default(void)
// #define PATH_DEBUG
-/* returns a formatted representation of the specified version number. Non-reentrant! */
+/* returns a formatted representation of the specified version number. Non-re-entrant! */
static char *blender_version_decimal(const int ver)
{
static char version_str[5];
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 168422a4454..3215b3d7b40 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -1005,9 +1005,9 @@ void BKE_pchan_bbone_handles_compute(const BBoneSplineParameters *param,
}
static void make_bbone_spline_matrix(BBoneSplineParameters *param,
- float scalemats[2][4][4],
- float pos[3],
- float axis[3],
+ const float scalemats[2][4][4],
+ const float pos[3],
+ const float axis[3],
float roll,
float scalex,
float scaley,
@@ -1257,9 +1257,9 @@ void BKE_pchan_bbone_deform_segment_index(const bPoseChannel *pchan,
float pre_blend = pos * (float)segments;
int index = (int)floorf(pre_blend);
- float blend = pre_blend - index;
+ CLAMP(index, 0, segments - 1);
- CLAMP(index, 0, segments);
+ float blend = pre_blend - index;
CLAMP(blend, 0.0f, 1.0f);
*r_index = index;
@@ -1867,11 +1867,16 @@ void BKE_bone_parent_transform_calc_from_pchan(const bPoseChannel *pchan,
/* yoffs(b-1) + root(b) + bonemat(b). */
BKE_bone_offset_matrix_get(bone, offs_bone);
- BKE_bone_parent_transform_calc_from_matrices(
- bone->flag, offs_bone, parbone->arm_mat, parchan->pose_mat, r_bpt);
+ BKE_bone_parent_transform_calc_from_matrices(bone->flag,
+ bone->inherit_scale_mode,
+ offs_bone,
+ parbone->arm_mat,
+ parchan->pose_mat,
+ r_bpt);
}
else {
- BKE_bone_parent_transform_calc_from_matrices(bone->flag, bone->arm_mat, NULL, NULL, r_bpt);
+ BKE_bone_parent_transform_calc_from_matrices(
+ bone->flag, bone->inherit_scale_mode, bone->arm_mat, NULL, NULL, r_bpt);
}
}
@@ -1882,39 +1887,90 @@ void BKE_bone_parent_transform_calc_from_pchan(const bPoseChannel *pchan,
* parent_arm_mat, parent_pose_mat: arm_mat and pose_mat of parent, or NULL
* r_bpt: OUTPUT parent transform */
void BKE_bone_parent_transform_calc_from_matrices(int bone_flag,
+ int inherit_scale_mode,
const float offs_bone[4][4],
const float parent_arm_mat[4][4],
const float parent_pose_mat[4][4],
BoneParentTransform *r_bpt)
{
if (parent_pose_mat) {
+ const bool use_rotation = (bone_flag & BONE_HINGE) == 0;
+ const bool full_transform = use_rotation && inherit_scale_mode == BONE_INHERIT_SCALE_FULL;
+
/* Compose the rotscale matrix for this bone. */
- if ((bone_flag & BONE_HINGE) && (bone_flag & BONE_NO_SCALE)) {
- /* Parent rest rotation and scale. */
- mul_m4_m4m4(r_bpt->rotscale_mat, parent_arm_mat, offs_bone);
+ if (full_transform) {
+ /* Parent pose rotation and scale. */
+ mul_m4_m4m4(r_bpt->rotscale_mat, parent_pose_mat, offs_bone);
}
- else if (bone_flag & BONE_HINGE) {
- /* Parent rest rotation and pose scale. */
+ else {
float tmat[4][4], tscale[3];
- /* Extract the scale of the parent pose matrix. */
- mat4_to_size(tscale, parent_pose_mat);
- size_to_mat4(tmat, tscale);
+ /* If using parent pose rotation: */
+ if (use_rotation) {
+ copy_m4_m4(tmat, parent_pose_mat);
+
+ /* Normalize the matrix when needed. */
+ switch (inherit_scale_mode) {
+ case BONE_INHERIT_SCALE_FULL:
+ case BONE_INHERIT_SCALE_FIX_SHEAR:
+ /* Keep scale and shear. */
+ break;
+
+ case BONE_INHERIT_SCALE_NONE:
+ case BONE_INHERIT_SCALE_AVERAGE:
+ /* Remove scale and shear from parent. */
+ orthogonalize_m4_stable(tmat, 1, true);
+ break;
+
+ case BONE_INHERIT_SCALE_NONE_LEGACY:
+ /* Remove only scale - bad legacy way. */
+ normalize_m4(tmat);
+ break;
+
+ default:
+ BLI_assert(false);
+ }
+ }
+ /* If removing parent pose rotation: */
+ else {
+ copy_m4_m4(tmat, parent_arm_mat);
+
+ /* Copy the parent scale when needed. */
+ switch (inherit_scale_mode) {
+ case BONE_INHERIT_SCALE_FULL:
+ /* Ignore effects of shear. */
+ mat4_to_size(tscale, parent_pose_mat);
+ rescale_m4(tmat, tscale);
+ break;
+
+ case BONE_INHERIT_SCALE_FIX_SHEAR:
+ /* Take the effects of parent shear into account to get exact volume. */
+ mat4_to_size_fix_shear(tscale, parent_pose_mat);
+ rescale_m4(tmat, tscale);
+ break;
+
+ case BONE_INHERIT_SCALE_NONE:
+ case BONE_INHERIT_SCALE_AVERAGE:
+ case BONE_INHERIT_SCALE_NONE_LEGACY:
+ /* Keep unscaled. */
+ break;
+
+ default:
+ BLI_assert(false);
+ }
+ }
- /* Applies the parent pose scale to the rest matrix. */
- mul_m4_m4m4(tmat, tmat, parent_arm_mat);
+ /* Apply the average parent scale when needed. */
+ if (inherit_scale_mode == BONE_INHERIT_SCALE_AVERAGE) {
+ mul_mat3_m4_fl(tmat, cbrtf(fabsf(mat4_to_volume_scale(parent_pose_mat))));
+ }
mul_m4_m4m4(r_bpt->rotscale_mat, tmat, offs_bone);
- }
- else if (bone_flag & BONE_NO_SCALE) {
- /* Parent pose rotation and rest scale (i.e. no scaling). */
- float tmat[4][4];
- copy_m4_m4(tmat, parent_pose_mat);
- normalize_m4(tmat);
- mul_m4_m4m4(r_bpt->rotscale_mat, tmat, offs_bone);
- }
- else {
- mul_m4_m4m4(r_bpt->rotscale_mat, parent_pose_mat, offs_bone);
+
+ /* Remove remaining shear when needed, preserving volume. */
+ if (inherit_scale_mode == BONE_INHERIT_SCALE_FIX_SHEAR) {
+ orthogonalize_m4_stable(r_bpt->rotscale_mat, 1, false);
+ }
}
/* Compose the loc matrix for this bone. */
@@ -1938,7 +1994,7 @@ void BKE_bone_parent_transform_calc_from_matrices(int bone_flag,
mul_m4_m4m4(r_bpt->loc_mat, bone_loc, tmat4);
}
/* Those flags do not affect position, use plain parent transform space! */
- else if (bone_flag & (BONE_HINGE | BONE_NO_SCALE)) {
+ else if (!full_transform) {
mul_m4_m4m4(r_bpt->loc_mat, parent_pose_mat, offs_bone);
}
/* Else (i.e. default, usual case),
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index 805c098d238..ac432bf0b64 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -32,7 +32,6 @@
#include "BLI_string.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
-#include "BLI_callbacks.h"
#include "IMB_imbuf.h"
#include "IMB_moviecache.h"
@@ -44,6 +43,7 @@
#include "BKE_blendfile.h"
#include "BKE_brush.h"
#include "BKE_cachefile.h"
+#include "BKE_callbacks.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
@@ -95,7 +95,7 @@ void BKE_blender_free(void)
BKE_brush_system_exit();
RE_texture_rng_exit();
- BLI_callback_global_finalize();
+ BKE_callback_global_finalize();
IMB_moviecache_destruct();
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index b2d3ccfebc3..4187dfa68ad 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -24,7 +24,9 @@
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_defaults.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rand.h"
@@ -35,6 +37,7 @@
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
#include "BKE_main.h"
+#include "BKE_material.h"
#include "BKE_paint.h"
#include "BKE_texture.h"
#include "BKE_icons.h"
@@ -60,73 +63,48 @@ void BKE_brush_system_exit(void)
static void brush_defaults(Brush *brush)
{
- brush->blend = 0;
- brush->flag = 0;
-
- brush->ob_mode = OB_MODE_ALL_PAINT;
-
- /* BRUSH SCULPT TOOL SETTINGS */
- brush->weight = 1.0f; /* weight of brush 0 - 1.0 */
- brush->size = 35; /* radius of the brush in pixels */
- brush->alpha = 0.5f; /* brush strength/intensity probably variable should be renamed? */
- brush->autosmooth_factor = 0.0f;
- brush->topology_rake_factor = 0.0f;
- brush->crease_pinch_factor = 0.5f;
- brush->sculpt_plane = SCULPT_DISP_DIR_AREA;
- /* How far above or below the plane that is found by averaging the faces. */
- brush->plane_offset = 0.0f;
- brush->plane_trim = 0.5f;
- brush->clone.alpha = 0.5f;
- brush->normal_weight = 0.0f;
- brush->fill_threshold = 0.2f;
- brush->flag |= BRUSH_ALPHA_PRESSURE;
-
- /* BRUSH PAINT TOOL SETTINGS */
- /* Default rgb color of the brush when painting - white. */
- brush->rgb[0] = 1.0f;
- brush->rgb[1] = 1.0f;
- brush->rgb[2] = 1.0f;
-
- zero_v3(brush->secondary_rgb);
-
- /* BRUSH STROKE SETTINGS */
- brush->flag |= (BRUSH_SPACE | BRUSH_SPACE_ATTEN);
- /* How far each brush dot should be spaced as a percentage of brush diameter. */
- brush->spacing = 10;
-
- brush->smooth_stroke_radius = 75;
- brush->smooth_stroke_factor = 0.9f;
-
- /* Time delay between dots of paint or sculpting when doing airbrush mode. */
- brush->rate = 0.1f;
-
- brush->jitter = 0.0f;
-
- /* BRUSH TEXTURE SETTINGS */
- BKE_texture_mtex_default(&brush->mtex);
- BKE_texture_mtex_default(&brush->mask_mtex);
-
- brush->texture_sample_bias = 0; /* value to added to texture samples */
- brush->texture_overlay_alpha = 33;
- brush->mask_overlay_alpha = 33;
- brush->cursor_overlay_alpha = 33;
- brush->overlay_flags = 0;
-
- /* brush appearance */
-
- brush->add_col[0] = 1.00; /* add mode color is light red */
- brush->add_col[1] = 0.39;
- brush->add_col[2] = 0.39;
-
- brush->sub_col[0] = 0.39; /* subtract mode color is light blue */
- brush->sub_col[1] = 0.39;
- brush->sub_col[2] = 1.00;
-
- brush->stencil_pos[0] = 256;
- brush->stencil_pos[1] = 256;
-
- brush->stencil_dimension[0] = 256;
- brush->stencil_dimension[1] = 256;
+
+ const Brush *brush_def = DNA_struct_default_get(Brush);
+
+#define FROM_DEFAULT(member) memcpy(&brush->member, &brush_def->member, sizeof(brush->member))
+#define FROM_DEFAULT_PTR(member) memcpy(brush->member, brush_def->member, sizeof(brush->member))
+
+ FROM_DEFAULT(blend);
+ FROM_DEFAULT(flag);
+ FROM_DEFAULT(weight);
+ FROM_DEFAULT(size);
+ FROM_DEFAULT(alpha);
+ FROM_DEFAULT(autosmooth_factor);
+ FROM_DEFAULT(topology_rake_factor);
+ FROM_DEFAULT(crease_pinch_factor);
+ FROM_DEFAULT(normal_radius_factor);
+ FROM_DEFAULT(sculpt_plane);
+ FROM_DEFAULT(plane_offset);
+ FROM_DEFAULT(clone.alpha);
+ FROM_DEFAULT(normal_weight);
+ FROM_DEFAULT(fill_threshold);
+ FROM_DEFAULT(flag);
+ FROM_DEFAULT_PTR(rgb);
+ FROM_DEFAULT_PTR(secondary_rgb);
+ FROM_DEFAULT(spacing);
+ FROM_DEFAULT(smooth_stroke_radius);
+ FROM_DEFAULT(smooth_stroke_factor);
+ FROM_DEFAULT(rate);
+ FROM_DEFAULT(jitter);
+ FROM_DEFAULT(texture_sample_bias);
+ FROM_DEFAULT(texture_overlay_alpha);
+ FROM_DEFAULT(mask_overlay_alpha);
+ FROM_DEFAULT(cursor_overlay_alpha);
+ FROM_DEFAULT(overlay_flags);
+ FROM_DEFAULT_PTR(add_col);
+ FROM_DEFAULT_PTR(sub_col);
+ FROM_DEFAULT(stencil_pos);
+ FROM_DEFAULT(stencil_dimension);
+ FROM_DEFAULT(mtex);
+ FROM_DEFAULT(mask_mtex);
+
+#undef FROM_DEFAULT
+#undef FROM_DEFAULT_PTR
}
/* Datablock add/copy/free/make_local */
@@ -135,16 +113,11 @@ void BKE_brush_init(Brush *brush)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(brush, id));
+ MEMCPY_STRUCT_AFTER(brush, DNA_struct_default_get(Brush), id);
+
/* enable fake user by default */
id_fake_user_set(&brush->id);
- brush_defaults(brush);
-
- brush->sculpt_tool = SCULPT_TOOL_DRAW; /* sculpting defaults to the draw tool for new brushes */
-
- /* A kernel radius of 1 has almost no effect (T63233). */
- brush->blur_kernel_radius = 2;
-
/* the default alpha falloff curve */
BKE_brush_curve_preset(brush, CURVE_PRESET_SMOOTH);
}
@@ -268,306 +241,383 @@ static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset)
}
}
-/* create a set of grease pencil presets */
-void BKE_brush_gpencil_presets(bContext *C)
+/* create a set of grease pencil presets. */
+void BKE_brush_gpencil_presets(Main *bmain, ToolSettings *ts)
{
#define SMOOTH_STROKE_RADIUS 40
#define SMOOTH_STROKE_FACTOR 0.9f
- ToolSettings *ts = CTX_data_tool_settings(C);
Paint *paint = &ts->gp_paint->paint;
- Main *bmain = CTX_data_main(C);
Brush *brush, *deft;
CurveMapping *custom_curve;
- /* Pencil brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pencil");
- brush->size = 25.0f;
+ /* Airbrush brush. */
+ brush = BLI_findstring(&bmain->brushes, "Airbrush", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Airbrush");
+ }
+
+ brush->size = 300.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.0f;
- brush->gpencil_settings->draw_strength = 0.6f;
+ brush->gpencil_settings->draw_strength = 0.4f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
- brush->gpencil_settings->draw_random_press = 0.0f;
-
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.98f;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
+ brush->gpencil_settings->gradient_f = 0.211f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
+
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
- brush->gpencil_settings->draw_smoothfac = 0.1f;
- brush->gpencil_settings->draw_smoothlvl = 1;
- brush->gpencil_settings->thick_smoothfac = 1.0f;
- brush->gpencil_settings->thick_smoothlvl = 3;
- brush->gpencil_settings->draw_subdivide = 1;
- brush->gpencil_settings->draw_random_sub = 0.0f;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL;
brush->gpencil_tool = GPAINT_TOOL_DRAW;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_AIRBRUSH;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Pen brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pen");
- deft = brush; /* save default brush */
- brush->size = 30.0f;
+ /* Create and link Black Dots material to brush.
+ * This material is required because the brush uses the material to define how the stroke is
+ * drawn. */
+ Material *ma = BLI_findstring(&bmain->materials, "Black Dots", offsetof(ID, name) + 2);
+ if (ma == NULL) {
+ ma = BKE_material_add_gpencil(bmain, "Black Dots");
+ }
+ brush->gpencil_settings->material = ma;
+ /* Pin the matterial to the brush. */
+ brush->gpencil_settings->flag |= GP_BRUSH_MATERIAL_PINNED;
+
+ /* Ink Pen brush. */
+ brush = BLI_findstring(&bmain->brushes, "Ink Pen", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Ink Pen");
+ }
+ brush->size = 60.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.0f;
brush->gpencil_settings->draw_strength = 1.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
-
- brush->gpencil_settings->draw_random_press = 0.0f;
- brush->gpencil_settings->draw_random_strength = 0.0f;
-
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.7f;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
brush->gpencil_settings->draw_smoothfac = 0.1f;
brush->gpencil_settings->draw_smoothlvl = 1;
- brush->gpencil_settings->draw_subdivide = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 0;
brush->gpencil_settings->draw_random_sub = 0.0f;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
- brush->gpencil_tool = GPAINT_TOOL_DRAW;
-
- brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
- brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
-
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Ink brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Ink");
- brush->size = 60.0f;
- brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.6f;
-
- brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->simplify_f = 0.002f;
brush->gpencil_settings->draw_random_press = 0.0f;
-
brush->gpencil_settings->draw_jitter = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
- brush->gpencil_settings->draw_angle = 0.0f;
- brush->gpencil_settings->draw_angle_factor = 0.0f;
+ /* Curve. */
+ custom_curve = brush->gpencil_settings->curve_sensitivity;
+ BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
+ BKE_curvemapping_initialize(custom_curve);
+ brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INK);
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
- brush->gpencil_settings->draw_smoothfac = 0.1f;
- brush->gpencil_settings->draw_smoothlvl = 1;
- brush->gpencil_settings->thick_smoothfac = 1.0f;
- brush->gpencil_settings->thick_smoothlvl = 3;
- brush->gpencil_settings->draw_subdivide = 1;
- brush->gpencil_settings->draw_random_sub = 0.0f;
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INK;
brush->gpencil_tool = GPAINT_TOOL_DRAW;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Curve */
- custom_curve = brush->gpencil_settings->curve_sensitivity;
- BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
- BKE_curvemapping_initialize(custom_curve);
- brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INK);
+ /* Ink Pen Rough brush. */
+ brush = BLI_findstring(&bmain->brushes, "Ink Pen Rough", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Ink Pen Rough");
+ }
- /* Ink Noise brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Noise");
brush->size = 60.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.0f;
brush->gpencil_settings->draw_strength = 1.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
- brush->gpencil_settings->draw_random_press = 0.7f;
- brush->gpencil_settings->draw_random_strength = 0.0f;
-
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.5f;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
- brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.0f;
brush->gpencil_settings->draw_smoothlvl = 2;
- brush->gpencil_settings->thick_smoothfac = 0.5f;
+ brush->gpencil_settings->thick_smoothfac = 0.0f;
brush->gpencil_settings->thick_smoothlvl = 2;
- brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_subdivide = 0;
brush->gpencil_settings->draw_random_sub = 0.0f;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE;
- brush->gpencil_tool = GPAINT_TOOL_DRAW;
+ brush->gpencil_settings->simplify_f = 0.000f;
- brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
- brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
+ brush->gpencil_settings->draw_random_press = 1.0f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
- /* Curve */
+ /* Curve. */
custom_curve = brush->gpencil_settings->curve_sensitivity;
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemapping_initialize(custom_curve);
brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INKNOISE);
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Block Basic brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Block");
- brush->size = 150.0f;
- brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
- brush->gpencil_settings->draw_strength = 1.0f;
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- brush->gpencil_settings->draw_random_press = 0.0f;
+ /* Marker Bold brush. */
+ brush = BLI_findstring(&bmain->brushes, "Marker Bold", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Marker Bold");
+ }
+ brush->size = 150.0f;
+ brush->gpencil_settings->flag &= ~GP_BRUSH_USE_PRESSURE;
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_strength = 0.3f;
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.6f;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
brush->gpencil_settings->draw_smoothfac = 0.1f;
brush->gpencil_settings->draw_smoothlvl = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
brush->gpencil_settings->draw_subdivide = 0;
- brush->gpencil_settings->draw_random_sub = 0;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_BLOCK;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->simplify_f = 0.002f;
+
+ brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_RANDOM;
+ brush->gpencil_settings->draw_random_press = 0.0f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ /* Curve. */
+ custom_curve = brush->gpencil_settings->curve_sensitivity;
+ BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
+ BKE_curvemapping_initialize(custom_curve);
+ brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_MARKER);
+
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER;
brush->gpencil_tool = GPAINT_TOOL_DRAW;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Marker brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Marker");
+ /* Marker Chisel brush. */
+ brush = BLI_findstring(&bmain->brushes, "Marker Chisel", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Marker Chisel");
+ }
brush->size = 80.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.0f;
brush->gpencil_settings->draw_strength = 1.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
- brush->gpencil_settings->draw_random_press = 0.374f;
- brush->gpencil_settings->draw_random_strength = 0.0f;
-
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.5f;
brush->gpencil_settings->draw_angle = DEG2RAD(20.0f);
brush->gpencil_settings->draw_angle_factor = 1.0f;
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
- brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothfac = 0.0f;
brush->gpencil_settings->draw_smoothlvl = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
- brush->gpencil_settings->draw_subdivide = 1;
- brush->gpencil_settings->draw_random_sub = 0.0f;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER;
+ brush->gpencil_settings->draw_subdivide = 0;
+ brush->gpencil_settings->draw_random_sub = 0;
+ brush->gpencil_settings->simplify_f = 0.002f;
+
+ brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_RANDOM;
+ brush->gpencil_settings->draw_random_press = 0.0f;
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_CHISEL;
brush->gpencil_tool = GPAINT_TOOL_DRAW;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- /* Curve */
- custom_curve = brush->gpencil_settings->curve_sensitivity;
- BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
- BKE_curvemapping_initialize(custom_curve);
- brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_MARKER);
+ /* Pen brush. */
+ brush = BLI_findstring(&bmain->brushes, "Pen", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Pen");
+ }
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.3f;
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
brush->gpencil_settings->gradient_f = 1.0f;
brush->gpencil_settings->gradient_s[0] = 1.0f;
brush->gpencil_settings->gradient_s[1] = 1.0f;
- /* Soft brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Soft");
- deft = brush; /* save default brush */
- brush->size = 300.0f;
- brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.0f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 1;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->simplify_f = 0.002f;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
brush->gpencil_settings->draw_sensitivity = 1.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Pencil Soft brush. */
+ brush = BLI_findstring(&bmain->brushes, "Pencil Soft", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Pencil Soft");
+ }
+
+ brush->size = 80.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+
brush->gpencil_settings->draw_strength = 0.4f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.64f;
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+ brush->gpencil_settings->gradient_f = 0.8f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.0f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 0;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->simplify_f = 0.000f;
+
brush->gpencil_settings->draw_random_press = 0.0f;
brush->gpencil_settings->draw_random_strength = 0.0f;
-
brush->gpencil_settings->draw_jitter = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Pencil brush. */
+ brush = BLI_findstring(&bmain->brushes, "Pencil", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Pencil");
+ }
+ deft = brush; /* save default brush. */
+
+ brush->size = 25.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+
+ brush->gpencil_settings->draw_strength = 0.6f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.55f;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
- brush->gpencil_settings->input_samples = 10;
- brush->gpencil_settings->active_smooth = 0.98f;
- brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.0f;
brush->gpencil_settings->draw_smoothlvl = 1;
- brush->gpencil_settings->draw_subdivide = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 0;
brush->gpencil_settings->draw_random_sub = 0.0f;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER;
+ brush->gpencil_settings->simplify_f = 0.002f;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL;
brush->gpencil_tool = GPAINT_TOOL_DRAW;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- brush->gpencil_settings->gradient_f = 0.211f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 0.91f;
-
- /* Fill brush */
+ /* Fill brush. */
brush = BKE_brush_add_gpencil(bmain, ts, "Fill Area");
brush->size = 20.0f;
brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
- brush->gpencil_settings->draw_sensitivity = 1.0f;
+
brush->gpencil_settings->fill_leak = 3;
brush->gpencil_settings->fill_threshold = 0.1f;
brush->gpencil_settings->fill_simplylvl = 1;
brush->gpencil_settings->fill_factor = 1;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL;
- brush->gpencil_tool = GPAINT_TOOL_FILL;
+ brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
brush->gpencil_settings->draw_smoothfac = 0.1f;
brush->gpencil_settings->draw_smoothlvl = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
brush->gpencil_settings->draw_subdivide = 1;
- brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
- brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
- brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL;
+ brush->gpencil_tool = GPAINT_TOOL_FILL;
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- /* Soft Eraser brush */
+ /* Soft Eraser brush. */
brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Soft");
brush->size = 30.0f;
brush->gpencil_settings->draw_strength = 0.5f;
@@ -580,34 +630,37 @@ void BKE_brush_gpencil_presets(bContext *C)
brush->gpencil_settings->era_strength_f = 100.0f;
brush->gpencil_settings->era_thickness_f = 10.0f;
- /* Hard Eraser brush */
+ /* Hard Eraser brush. */
brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Hard");
brush->size = 30.0f;
brush->gpencil_settings->draw_strength = 1.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
- brush->gpencil_tool = GPAINT_TOOL_ERASE;
brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
brush->gpencil_settings->era_strength_f = 100.0f;
brush->gpencil_settings->era_thickness_f = 50.0f;
- /* Point Eraser brush */
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
+ brush->gpencil_tool = GPAINT_TOOL_ERASE;
+
+ /* Point Eraser brush. */
brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Point");
brush->size = 30.0f;
brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD;
+
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
brush->gpencil_tool = GPAINT_TOOL_ERASE;
- brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD;
- /* Stroke Eraser brush */
+ /* Stroke Eraser brush. */
brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Stroke");
brush->size = 30.0f;
brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE;
+
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE;
brush->gpencil_tool = GPAINT_TOOL_ERASE;
- brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE;
- /* set default brush */
+ /* set default brush. */
BKE_paint_brush_set(paint, deft);
}
@@ -839,7 +892,20 @@ void BKE_brush_sculpt_reset(Brush *br)
brush_defaults(br);
BKE_brush_curve_preset(br, CURVE_PRESET_SMOOTH);
+ /* Use the curve presets by default */
+ br->curve_preset = BRUSH_CURVE_SMOOTH;
+
+ /* Note that sculpt defaults where set when 0.5 was the default (now it's 1.0)
+ * assign this so logic below can remain the same. */
+ br->alpha = 0.5f;
+
+ /* Brush settings */
switch (br->sculpt_tool) {
+ case SCULPT_TOOL_DRAW_SHARP:
+ br->flag |= BRUSH_DIR_IN;
+ br->curve_preset = BRUSH_CURVE_POW4;
+ br->spacing = 5;
+ break;
case SCULPT_TOOL_CLAY:
br->flag |= BRUSH_FRONTFACE;
break;
@@ -847,41 +913,10 @@ void BKE_brush_sculpt_reset(Brush *br)
br->flag |= BRUSH_DIR_IN;
br->alpha = 0.25;
break;
- case SCULPT_TOOL_FILL:
- br->add_col[1] = 1;
- br->sub_col[0] = 0.25;
- br->sub_col[1] = 1;
- break;
- case SCULPT_TOOL_FLATTEN:
- br->add_col[1] = 1;
- br->sub_col[0] = 0.25;
- br->sub_col[1] = 1;
- break;
- case SCULPT_TOOL_INFLATE:
- br->add_col[0] = 0.750000;
- br->add_col[1] = 0.750000;
- br->add_col[2] = 0.750000;
- br->sub_col[0] = 0.250000;
- br->sub_col[1] = 0.250000;
- br->sub_col[2] = 0.250000;
- break;
- case SCULPT_TOOL_NUDGE:
- br->add_col[0] = 0.250000;
- br->add_col[1] = 1.000000;
- br->add_col[2] = 0.250000;
- break;
- case SCULPT_TOOL_PINCH:
- br->add_col[0] = 0.750000;
- br->add_col[1] = 0.750000;
- br->add_col[2] = 0.750000;
- br->sub_col[0] = 0.250000;
- br->sub_col[1] = 0.250000;
- br->sub_col[2] = 0.250000;
- break;
case SCULPT_TOOL_SCRAPE:
- br->add_col[1] = 1.000000;
- br->sub_col[0] = 0.250000;
- br->sub_col[1] = 1.000000;
+ br->alpha = 1.0f;
+ br->spacing = 7;
+ br->flag |= BRUSH_ACCUMULATE;
break;
case SCULPT_TOOL_ROTATE:
br->alpha = 1.0;
@@ -889,20 +924,94 @@ void BKE_brush_sculpt_reset(Brush *br)
case SCULPT_TOOL_SMOOTH:
br->flag &= ~BRUSH_SPACE_ATTEN;
br->spacing = 5;
- br->add_col[0] = 0.750000;
- br->add_col[1] = 0.750000;
- br->add_col[2] = 0.750000;
+ br->alpha = 0.7f;
break;
- case SCULPT_TOOL_GRAB:
case SCULPT_TOOL_SNAKE_HOOK:
+ br->alpha = 1.0f;
+ break;
case SCULPT_TOOL_THUMB:
br->size = 75;
br->flag &= ~BRUSH_ALPHA_PRESSURE;
br->flag &= ~BRUSH_SPACE;
br->flag &= ~BRUSH_SPACE_ATTEN;
- br->add_col[0] = 0.250000;
- br->add_col[1] = 1.000000;
- br->add_col[2] = 0.250000;
+ break;
+ case SCULPT_TOOL_ELASTIC_DEFORM:
+ br->elastic_deform_volume_preservation = 0.4f;
+ br->elastic_deform_type = BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE;
+ br->flag &= ~BRUSH_ALPHA_PRESSURE;
+ br->flag &= ~BRUSH_SPACE;
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ break;
+ case SCULPT_TOOL_POSE:
+ br->flag &= ~BRUSH_ALPHA_PRESSURE;
+ br->flag &= ~BRUSH_SPACE;
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ break;
+ case SCULPT_TOOL_GRAB:
+ br->alpha = 0.4f;
+ br->size = 75;
+ br->flag &= ~BRUSH_ALPHA_PRESSURE;
+ br->flag &= ~BRUSH_SPACE;
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ break;
+ default:
+ break;
+ }
+
+ /* Cursor colors */
+ switch (br->sculpt_tool) {
+ case SCULPT_TOOL_DRAW:
+ case SCULPT_TOOL_DRAW_SHARP:
+ case SCULPT_TOOL_CLAY:
+ case SCULPT_TOOL_CLAY_STRIPS:
+ case SCULPT_TOOL_LAYER:
+ case SCULPT_TOOL_INFLATE:
+ case SCULPT_TOOL_BLOB:
+ case SCULPT_TOOL_CREASE:
+ br->add_col[0] = 0.65f;
+ br->add_col[1] = 0.85f;
+ br->add_col[2] = 0.9f;
+ br->sub_col[0] = 0.65f;
+ br->sub_col[1] = 0.85f;
+ br->sub_col[2] = 0.9f;
+ break;
+
+ case SCULPT_TOOL_SMOOTH:
+ case SCULPT_TOOL_FLATTEN:
+ case SCULPT_TOOL_FILL:
+ case SCULPT_TOOL_SCRAPE:
+ br->add_col[0] = 1.0f;
+ br->add_col[1] = 0.39f;
+ br->add_col[2] = 0.39f;
+ br->sub_col[0] = 1.0f;
+ br->sub_col[1] = 0.39f;
+ br->sub_col[2] = 0.39f;
+ break;
+
+ case SCULPT_TOOL_PINCH:
+ case SCULPT_TOOL_GRAB:
+ case SCULPT_TOOL_SNAKE_HOOK:
+ case SCULPT_TOOL_THUMB:
+ case SCULPT_TOOL_NUDGE:
+ case SCULPT_TOOL_ROTATE:
+ case SCULPT_TOOL_ELASTIC_DEFORM:
+ case SCULPT_TOOL_POSE:
+ br->add_col[0] = 1.0f;
+ br->add_col[1] = 1.0f;
+ br->add_col[2] = 0.39f;
+ br->sub_col[0] = 1.0f;
+ br->sub_col[1] = 1.0f;
+ br->sub_col[2] = 0.39f;
+ break;
+
+ case SCULPT_TOOL_SIMPLIFY:
+ case SCULPT_TOOL_MASK:
+ br->add_col[0] = 0.750000;
+ br->add_col[1] = 0.750000;
+ br->add_col[2] = 0.750000;
+ br->sub_col[0] = 0.750000;
+ br->sub_col[1] = 0.750000;
+ br->sub_col[2] = 0.750000;
break;
default:
break;
@@ -1264,6 +1373,7 @@ bool BKE_brush_sculpt_has_secondary_color(const Brush *brush)
return ELEM(brush->sculpt_tool,
SCULPT_TOOL_BLOB,
SCULPT_TOOL_DRAW,
+ SCULPT_TOOL_DRAW_SHARP,
SCULPT_TOOL_INFLATE,
SCULPT_TOOL_CLAY,
SCULPT_TOOL_CLAY_STRIPS,
@@ -1490,11 +1600,11 @@ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_sec
}
/**** Radial Control ****/
-struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary)
+struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary, bool display_gradient)
{
ImBuf *im = MEM_callocN(sizeof(ImBuf), "radial control texture");
unsigned int *texcache;
- int side = 128;
+ int side = 512;
int half = side / 2;
int i, j;
@@ -1503,24 +1613,25 @@ struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary)
im->rect_float = MEM_callocN(sizeof(float) * side * side, "radial control rect");
im->x = im->y = side;
- for (i = 0; i < side; ++i) {
- for (j = 0; j < side; ++j) {
- float magn = sqrtf(pow2f(i - half) + pow2f(j - half));
- im->rect_float[i * side + j] = BKE_brush_curve_strength_clamped(br, magn, half);
+ if (display_gradient || texcache) {
+ for (i = 0; i < side; i++) {
+ for (j = 0; j < side; j++) {
+ float magn = sqrtf(pow2f(i - half) + pow2f(j - half));
+ im->rect_float[i * side + j] = BKE_brush_curve_strength_clamped(br, magn, half);
+ }
}
}
- /* Modulate curve with texture */
if (texcache) {
- for (i = 0; i < side; ++i) {
- for (j = 0; j < side; ++j) {
+ /* Modulate curve with texture */
+ for (i = 0; i < side; i++) {
+ for (j = 0; j < side; j++) {
const int col = texcache[i * side + j];
im->rect_float[i * side + j] *= (((char *)&col)[0] + ((char *)&col)[1] +
((char *)&col)[2]) /
3.0f / 255.0f;
}
}
-
MEM_freeN(texcache);
}
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index 85a12027bf2..0a5952e1b47 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -1395,7 +1395,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
else {
/* Setup BVHTreeFromMesh */
bvhtree_from_mesh_edges_setup_data(
- data, tree, false, mesh->mvert, false, mesh->medge, false);
+ data, tree, true, mesh->mvert, false, mesh->medge, false);
}
break;
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index 2d6256f12e2..3b0f4d9c2aa 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -246,7 +246,7 @@ void BKE_cachefile_eval(Main *bmain, Depsgraph *depsgraph, CacheFile *cache_file
BLI_freelistN(&cache_file->object_paths);
#ifdef WITH_ALEMBIC
- cache_file->handle = ABC_create_handle(filepath, &cache_file->object_paths);
+ cache_file->handle = ABC_create_handle(bmain, filepath, &cache_file->object_paths);
BLI_strncpy(cache_file->handle_filepath, filepath, FILE_MAX);
#endif
diff --git a/source/blender/blenlib/intern/callbacks.c b/source/blender/blenkernel/intern/callbacks.c
index c4f93a9831d..367fed818af 100644
--- a/source/blender/blenlib/intern/callbacks.c
+++ b/source/blender/blenkernel/intern/callbacks.c
@@ -15,43 +15,81 @@
*/
/** \file
- * \ingroup bli
+ * \ingroup bke
*/
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
-#include "BLI_callbacks.h"
+
+#include "BKE_callbacks.h"
#include "MEM_guardedalloc.h"
-static ListBase callback_slots[BLI_CB_EVT_TOT] = {{NULL}};
+#include "RNA_types.h"
+#include "RNA_access.h"
+
+static ListBase callback_slots[BKE_CB_EVT_TOT] = {{NULL}};
-void BLI_callback_exec(struct Main *bmain, struct ID *self, eCbEvent evt)
+void BKE_callback_exec(struct Main *bmain,
+ struct PointerRNA **pointers,
+ const int num_pointers,
+ eCbEvent evt)
{
ListBase *lb = &callback_slots[evt];
bCallbackFuncStore *funcstore;
for (funcstore = lb->first; funcstore; funcstore = funcstore->next) {
- funcstore->func(bmain, self, funcstore->arg);
+ funcstore->func(bmain, pointers, num_pointers, funcstore->arg);
}
}
-void BLI_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt)
+void BKE_callback_exec_null(struct Main *bmain, eCbEvent evt)
+{
+ BKE_callback_exec(bmain, NULL, 0, evt);
+}
+
+void BKE_callback_exec_id(struct Main *bmain, struct ID *id, eCbEvent evt)
+{
+ PointerRNA id_ptr;
+ RNA_id_pointer_create(id, &id_ptr);
+
+ PointerRNA *pointers[1] = {&id_ptr};
+
+ BKE_callback_exec(bmain, pointers, 1, evt);
+}
+
+void BKE_callback_exec_id_depsgraph(struct Main *bmain,
+ struct ID *id,
+ struct Depsgraph *depsgraph,
+ eCbEvent evt)
+{
+ PointerRNA id_ptr;
+ RNA_id_pointer_create(id, &id_ptr);
+
+ PointerRNA depsgraph_ptr;
+ RNA_pointer_create(NULL, &RNA_Depsgraph, depsgraph, &depsgraph_ptr);
+
+ PointerRNA *pointers[2] = {&id_ptr, &depsgraph_ptr};
+
+ BKE_callback_exec(bmain, pointers, 2, evt);
+}
+
+void BKE_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt)
{
ListBase *lb = &callback_slots[evt];
BLI_addtail(lb, funcstore);
}
-void BLI_callback_global_init(void)
+void BKE_callback_global_init(void)
{
/* do nothing */
}
/* call on application exit */
-void BLI_callback_global_finalize(void)
+void BKE_callback_global_finalize(void)
{
eCbEvent evt;
- for (evt = 0; evt < BLI_CB_EVT_TOT; evt++) {
+ for (evt = 0; evt < BKE_CB_EVT_TOT; evt++) {
ListBase *lb = &callback_slots[evt];
bCallbackFuncStore *funcstore;
bCallbackFuncStore *funcstore_next;
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index a563a8d581c..f70c5bb99d6 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -30,6 +30,7 @@
#include "DNA_scene_types.h"
#include "DNA_view3d_types.h"
#include "DNA_ID.h"
+#include "DNA_defaults.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
@@ -56,25 +57,7 @@ void BKE_camera_init(Camera *cam)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(cam, id));
- cam->lens = 50.0f;
- cam->sensor_x = DEFAULT_SENSOR_WIDTH;
- cam->sensor_y = DEFAULT_SENSOR_HEIGHT;
- cam->clip_start = 0.1f;
- cam->clip_end = 1000.0f;
- cam->drawsize = 1.0f;
- cam->ortho_scale = 6.0;
- cam->flag |= CAM_SHOWPASSEPARTOUT;
- cam->passepartalpha = 0.5f;
-
- cam->dof.aperture_fstop = 2.8f;
- cam->dof.aperture_ratio = 1.0f;
- cam->dof.focus_distance = 10.0f;
-
- /* stereoscopy 3d */
- cam->stereo.interocular_distance = 0.065f;
- cam->stereo.convergence_distance = 30.f * 0.065f;
- cam->stereo.pole_merge_angle_from = DEG2RADF(60.0f);
- cam->stereo.pole_merge_angle_to = DEG2RADF(75.0f);
+ MEMCPY_STRUCT_AFTER(cam, DNA_struct_default_get(Camera), id);
}
void *BKE_camera_add(Main *bmain, const char *name)
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 2031576190e..f2098cc2430 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -203,6 +203,9 @@ void BKE_collection_copy_data(Main *bmain,
const Collection *collection_src,
const int flag)
{
+ BLI_assert(((collection_src->flag & COLLECTION_IS_MASTER) != 0) ==
+ ((collection_src->id.flag & LIB_PRIVATE_DATA) != 0));
+
/* Do not copy collection's preview (same behavior as for objects). */
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */
BKE_previewimg_id_copy(&collection_dst->id, &collection_src->id);
@@ -338,8 +341,9 @@ Collection *BKE_collection_duplicate(Main *bmain,
const bool do_obdata)
{
/* It's not allowed to copy the master collection. */
+ BLI_assert((collection->id.flag & LIB_PRIVATE_DATA) == 0);
+ BLI_assert((collection->flag & COLLECTION_IS_MASTER) == 0);
if (collection->flag & COLLECTION_IS_MASTER) {
- BLI_assert("!Master collection can't be duplicated");
return NULL;
}
@@ -365,15 +369,6 @@ Collection *BKE_collection_duplicate(Main *bmain,
return collection_new;
}
-Collection *BKE_collection_copy_master(Main *bmain, Collection *collection, const int flag)
-{
- BLI_assert(collection->flag & COLLECTION_IS_MASTER);
-
- Collection *collection_dst = MEM_dupallocN(collection);
- BKE_collection_copy_data(bmain, collection_dst, collection, flag);
- return collection_dst;
-}
-
void BKE_collection_make_local(Main *bmain, Collection *collection, const bool lib_local)
{
BKE_id_make_local_generic(bmain, &collection->id, true, lib_local);
@@ -499,15 +494,11 @@ Collection *BKE_collection_master_add()
/* Not an actual datablock, but owned by scene. */
Collection *master_collection = MEM_callocN(sizeof(Collection), "Master Collection");
STRNCPY(master_collection->id.name, "GRMaster Collection");
+ master_collection->id.flag |= LIB_PRIVATE_DATA;
master_collection->flag |= COLLECTION_IS_MASTER;
return master_collection;
}
-Collection *BKE_collection_master(const Scene *scene)
-{
- return scene->master_collection;
-}
-
Scene *BKE_collection_master_scene_search(const Main *bmain, const Collection *master_collection)
{
BLI_assert((master_collection->flag & COLLECTION_IS_MASTER) != 0);
@@ -584,7 +575,7 @@ bool BKE_collection_has_object_recursive(Collection *collection, Object *ob)
static Collection *collection_next_find(Main *bmain, Scene *scene, Collection *collection)
{
- if (scene && collection == BKE_collection_master(scene)) {
+ if (scene && collection == scene->master_collection) {
return bmain->collections.first;
}
else {
@@ -601,7 +592,7 @@ Collection *BKE_collection_object_find(Main *bmain,
collection = collection_next_find(bmain, scene, collection);
}
else if (scene) {
- collection = BKE_collection_master(scene);
+ collection = scene->master_collection;
}
else {
collection = bmain->collections.first;
@@ -743,7 +734,7 @@ void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, O
if (!is_instantiated) {
/* In case we could not find any non-linked collections in which instantiate our ob_dst,
* fallback to scene's master collection... */
- collection_object_add(bmain, BKE_collection_master(scene), ob_dst, 0, true);
+ collection_object_add(bmain, scene->master_collection, ob_dst, 0, true);
}
BKE_main_collection_sync(bmain);
@@ -885,7 +876,7 @@ void BKE_collections_child_remove_nulls(Main *bmain, Collection *collection)
collection_null_children_remove(collection);
}
for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
- collection_null_children_remove(BKE_collection_master(scene));
+ collection_null_children_remove(scene->master_collection);
}
for (collection = bmain->collections.first; collection != NULL;
@@ -893,7 +884,7 @@ void BKE_collections_child_remove_nulls(Main *bmain, Collection *collection)
collection_missing_parents_remove(collection);
}
for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
- collection_missing_parents_remove(BKE_collection_master(scene));
+ collection_missing_parents_remove(scene->master_collection);
}
}
else {
@@ -1169,7 +1160,7 @@ static Collection *collection_from_index_recursive(Collection *collection,
Collection *BKE_collection_from_index(Scene *scene, const int index)
{
int index_current = 0;
- Collection *master_collection = BKE_collection_master(scene);
+ Collection *master_collection = scene->master_collection;
return collection_from_index_recursive(master_collection, index, &index_current);
}
@@ -1363,7 +1354,7 @@ static void scene_collections_array(Scene *scene, Collection ***collections_arra
return;
}
- collection = BKE_collection_master(scene);
+ collection = scene->master_collection;
BLI_assert(collection != NULL);
scene_collection_callback(collection, scene_collections_count, tot);
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 69afda9997a..91d66e16dde 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -188,11 +188,11 @@ BLI_INLINE int next_ind(int i)
}
static float compute_collision_point(float a1[3],
- float a2[3],
- float a3[3],
- float b1[3],
- float b2[3],
- float b3[3],
+ const float a2[3],
+ const float a3[3],
+ const float b1[3],
+ const float b2[3],
+ const float b3[3],
bool culling,
bool use_normal,
float r_a[3],
@@ -419,7 +419,7 @@ static float compute_collision_point(float a1[3],
// w3 is not perfect
static void collision_compute_barycentric(
- float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3)
+ const float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3)
{
/* dot_v3v3 */
#define INPR(v1, v2) ((v1)[0] * (v2)[0] + (v1)[1] * (v2)[1] + (v1)[2] * (v2)[2])
@@ -1499,7 +1499,7 @@ BLI_INLINE bool cloth_point_face_collision_params(const float p1[3],
}
static CollPair *cloth_point_collpair(float p1[3],
- float p2[3],
+ const float p2[3],
const MVert *mverts,
int bp1,
int bp2,
@@ -1742,7 +1742,7 @@ void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders)
{
if (collider_contacts) {
int i;
- for (i = 0; i < totcolliders; ++i) {
+ for (i = 0; i < totcolliders; i++) {
ColliderContacts *ct = collider_contacts + i;
if (ct->collisions) {
MEM_freeN(ct->collisions);
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index e1e4d138fd9..d59849695ff 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -62,6 +62,7 @@
#include "BKE_deform.h"
#include "BKE_displist.h"
#include "BKE_editmesh.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
@@ -1801,25 +1802,47 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
bConstraintTarget *ct = targets->first;
if (VALID_CONS_TARGET(ct)) {
- float loc[3];
- float eul[3], obeul[3];
- float size[3];
+ float loc[3], size[3], oldrot[3][3], newrot[3][3];
+ float eul[3], obeul[3], defeul[3];
- copy_v3_v3(loc, cob->matrix[3]);
- mat4_to_size(size, cob->matrix);
+ mat4_to_loc_rot_size(loc, oldrot, size, cob->matrix);
+
+ /* Select the Euler rotation order, defaulting to the owner. */
+ short rot_order = cob->rotOrder;
+
+ if (data->euler_order != CONSTRAINT_EULER_AUTO) {
+ rot_order = data->euler_order;
+ }
/* To allow compatible rotations, must get both rotations in the order of the owner... */
- mat4_to_eulO(obeul, cob->rotOrder, cob->matrix);
+ mat4_to_eulO(obeul, rot_order, cob->matrix);
/* We must get compatible eulers from the beginning because
* some of them can be modified below (see bug T21875). */
- mat4_to_compatible_eulO(eul, obeul, cob->rotOrder, ct->matrix);
+ mat4_to_compatible_eulO(eul, obeul, rot_order, ct->matrix);
+
+ /* Prepare the copied euler rotation. */
+ bool legacy_offset = false;
+
+ switch (data->mix_mode) {
+ case ROTLIKE_MIX_OFFSET:
+ legacy_offset = true;
+ copy_v3_v3(defeul, obeul);
+ break;
+
+ case ROTLIKE_MIX_REPLACE:
+ copy_v3_v3(defeul, obeul);
+ break;
+
+ default:
+ zero_v3(defeul);
+ }
if ((data->flag & ROTLIKE_X) == 0) {
- eul[0] = obeul[0];
+ eul[0] = defeul[0];
}
else {
- if (data->flag & ROTLIKE_OFFSET) {
- rotate_eulO(eul, cob->rotOrder, 'X', obeul[0]);
+ if (legacy_offset) {
+ rotate_eulO(eul, rot_order, 'X', obeul[0]);
}
if (data->flag & ROTLIKE_X_INVERT) {
@@ -1828,11 +1851,11 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
}
if ((data->flag & ROTLIKE_Y) == 0) {
- eul[1] = obeul[1];
+ eul[1] = defeul[1];
}
else {
- if (data->flag & ROTLIKE_OFFSET) {
- rotate_eulO(eul, cob->rotOrder, 'Y', obeul[1]);
+ if (legacy_offset) {
+ rotate_eulO(eul, rot_order, 'Y', obeul[1]);
}
if (data->flag & ROTLIKE_Y_INVERT) {
@@ -1841,11 +1864,11 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
}
if ((data->flag & ROTLIKE_Z) == 0) {
- eul[2] = obeul[2];
+ eul[2] = defeul[2];
}
else {
- if (data->flag & ROTLIKE_OFFSET) {
- rotate_eulO(eul, cob->rotOrder, 'Z', obeul[2]);
+ if (legacy_offset) {
+ rotate_eulO(eul, rot_order, 'Z', obeul[2]);
}
if (data->flag & ROTLIKE_Z_INVERT) {
@@ -1853,10 +1876,36 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
}
}
+ /* Add the euler components together if needed. */
+ if (data->mix_mode == ROTLIKE_MIX_ADD) {
+ add_v3_v3(eul, obeul);
+ }
+
/* Good to make eulers compatible again,
* since we don't know how much they were changed above. */
compatible_eul(eul, obeul);
- loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, cob->rotOrder);
+ eulO_to_mat3(newrot, eul, rot_order);
+
+ /* Mix the rotation matrices: */
+ switch (data->mix_mode) {
+ case ROTLIKE_MIX_REPLACE:
+ case ROTLIKE_MIX_OFFSET:
+ case ROTLIKE_MIX_ADD:
+ break;
+
+ case ROTLIKE_MIX_BEFORE:
+ mul_m3_m3m3(newrot, newrot, oldrot);
+ break;
+
+ case ROTLIKE_MIX_AFTER:
+ mul_m3_m3m3(newrot, oldrot, newrot);
+ break;
+
+ default:
+ BLI_assert(false);
+ }
+
+ loc_rot_size_to_mat4(cob->matrix, loc, newrot, size);
}
}
@@ -1927,9 +1976,39 @@ static void sizelike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *ta
if (VALID_CONS_TARGET(ct)) {
float obsize[3], size[3];
- mat4_to_size(size, ct->matrix);
mat4_to_size(obsize, cob->matrix);
+ /* Compute one uniform scale factor to apply to all three axes. */
+ if (data->flag & SIZELIKE_UNIFORM) {
+ const int all_axes = SIZELIKE_X | SIZELIKE_Y | SIZELIKE_Z;
+ float total = 1.0f;
+
+ /* If all axes are selected, use the determinant. */
+ if ((data->flag & all_axes) == all_axes) {
+ total = fabsf(mat4_to_volume_scale(ct->matrix));
+ }
+ /* Otherwise multiply individual values. */
+ else {
+ mat4_to_size(size, ct->matrix);
+
+ if (data->flag & SIZELIKE_X) {
+ total *= size[0];
+ }
+ if (data->flag & SIZELIKE_Y) {
+ total *= size[1];
+ }
+ if (data->flag & SIZELIKE_Z) {
+ total *= size[2];
+ }
+ }
+
+ copy_v3_fl(size, cbrt(total));
+ }
+ /* Regular per-axis scaling. */
+ else {
+ mat4_to_size(size, ct->matrix);
+ }
+
for (int i = 0; i < 3; i++) {
size[i] = powf(size[i], data->power);
}
@@ -1948,13 +2027,13 @@ static void sizelike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *ta
}
}
- if ((data->flag & SIZELIKE_X) && (obsize[0] != 0)) {
+ if ((data->flag & (SIZELIKE_X | SIZELIKE_UNIFORM)) && (obsize[0] != 0)) {
mul_v3_fl(cob->matrix[0], size[0] / obsize[0]);
}
- if ((data->flag & SIZELIKE_Y) && (obsize[1] != 0)) {
+ if ((data->flag & (SIZELIKE_Y | SIZELIKE_UNIFORM)) && (obsize[1] != 0)) {
mul_v3_fl(cob->matrix[1], size[1] / obsize[1]);
}
- if ((data->flag & SIZELIKE_Z) && (obsize[2] != 0)) {
+ if ((data->flag & (SIZELIKE_Z | SIZELIKE_UNIFORM)) && (obsize[2] != 0)) {
mul_v3_fl(cob->matrix[2], size[2] / obsize[2]);
}
}
@@ -2011,13 +2090,43 @@ static void translike_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
}
}
-static void translike_evaluate(bConstraint *UNUSED(con), bConstraintOb *cob, ListBase *targets)
+static void translike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
+ bTransLikeConstraint *data = con->data;
bConstraintTarget *ct = targets->first;
if (VALID_CONS_TARGET(ct)) {
- /* just copy the entire transform matrix of the target */
- copy_m4_m4(cob->matrix, ct->matrix);
+ if (data->mix_mode == TRANSLIKE_MIX_REPLACE) {
+ /* just copy the entire transform matrix of the target */
+ copy_m4_m4(cob->matrix, ct->matrix);
+ }
+ else {
+ float old_loc[3], old_rot[3][3], old_size[3];
+ float new_loc[3], new_rot[3][3], new_size[3];
+
+ /* Separate matrices so they can be combined in a way that avoids shear. */
+ mat4_to_loc_rot_size(old_loc, old_rot, old_size, cob->matrix);
+ mat4_to_loc_rot_size(new_loc, new_rot, new_size, ct->matrix);
+
+ switch (data->mix_mode) {
+ case TRANSLIKE_MIX_BEFORE:
+ mul_v3_m4v3(new_loc, ct->matrix, old_loc);
+ mul_m3_m3m3(new_rot, new_rot, old_rot);
+ mul_v3_v3(new_size, old_size);
+ break;
+
+ case TRANSLIKE_MIX_AFTER:
+ mul_v3_m4v3(new_loc, cob->matrix, new_loc);
+ mul_m3_m3m3(new_rot, old_rot, new_rot);
+ mul_v3_v3(new_size, old_size);
+ break;
+
+ default:
+ BLI_assert(false);
+ }
+
+ loc_rot_size_to_mat4(cob->matrix, new_loc, new_rot, new_size);
+ }
}
}
@@ -2301,9 +2410,9 @@ static void armdef_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
}
static void armdef_accumulate_matrix(float obmat[4][4],
- float iobmat[4][4],
- float basemat[4][4],
- float bonemat[4][4],
+ const float iobmat[4][4],
+ const float basemat[4][4],
+ const float bonemat[4][4],
float weight,
float r_sum_mat[4][4],
DualQuat *r_sum_dq)
@@ -3644,6 +3753,11 @@ static void transform_new_data(void *cdata)
data->map[0] = 0;
data->map[1] = 1;
data->map[2] = 2;
+
+ for (int i = 0; i < 3; i++) {
+ data->from_min_scale[i] = data->from_max_scale[i] = 1.0f;
+ data->to_min_scale[i] = data->to_max_scale[i] = 1.0f;
+ }
}
static void transform_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
@@ -3688,8 +3802,10 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
/* only evaluate if there is a target */
if (VALID_CONS_TARGET(ct)) {
float *from_min, *from_max, *to_min, *to_max;
- float loc[3], eul[3], size[3];
- float dvec[3], sval[3];
+ float loc[3], rot[3][3], oldeul[3], size[3];
+ float newloc[3], newrot[3][3], neweul[3], newsize[3];
+ float dbuf[4], sval[3];
+ float *const dvec = dbuf + 1;
int i;
/* obtain target effect */
@@ -3708,7 +3824,8 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
from_max = data->from_max_scale;
break;
case TRANS_ROTATION:
- mat4_to_eulO(dvec, cob->rotOrder, ct->matrix);
+ BKE_driver_target_matrix_to_rot_channels(
+ ct->matrix, cob->rotOrder, data->from_rotation_mode, -1, true, dbuf);
from_min = data->from_min_rot;
from_max = data->from_max_rot;
break;
@@ -3720,10 +3837,15 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
break;
}
+ /* Select the output Euler rotation order, defaulting to the owner. */
+ short rot_order = cob->rotOrder;
+
+ if (data->to == TRANS_ROTATION && data->to_euler_order != CONSTRAINT_EULER_AUTO) {
+ rot_order = data->to_euler_order;
+ }
+
/* extract components of owner's matrix */
- copy_v3_v3(loc, cob->matrix[3]);
- mat4_to_eulO(eul, cob->rotOrder, cob->matrix);
- mat4_to_size(size, cob->matrix);
+ mat4_to_loc_rot_size(loc, rot, size, cob->matrix);
/* determine where in range current transforms lie */
if (data->expo) {
@@ -3755,18 +3877,42 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
to_min = data->to_min_scale;
to_max = data->to_max_scale;
for (i = 0; i < 3; i++) {
- /* multiply with original scale (so that it can still be scaled) */
- /* size[i] *= to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])); */
- /* Stay absolute, else it breaks existing rigs... sigh. */
- size[i] = to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]));
+ newsize[i] = to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]));
+ }
+ switch (data->mix_mode_scale) {
+ case TRANS_MIXSCALE_MULTIPLY:
+ mul_v3_v3(size, newsize);
+ break;
+ case TRANS_MIXSCALE_REPLACE:
+ default:
+ copy_v3_v3(size, newsize);
+ break;
}
break;
case TRANS_ROTATION:
to_min = data->to_min_rot;
to_max = data->to_max_rot;
for (i = 0; i < 3; i++) {
- /* add to original rotation (so that it can still be rotated) */
- eul[i] += to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]));
+ neweul[i] = to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]));
+ }
+ switch (data->mix_mode_rot) {
+ case TRANS_MIXROT_REPLACE:
+ eulO_to_mat3(rot, neweul, rot_order);
+ break;
+ case TRANS_MIXROT_BEFORE:
+ eulO_to_mat3(newrot, neweul, rot_order);
+ mul_m3_m3m3(rot, newrot, rot);
+ break;
+ case TRANS_MIXROT_AFTER:
+ eulO_to_mat3(newrot, neweul, rot_order);
+ mul_m3_m3m3(rot, rot, newrot);
+ break;
+ case TRANS_MIXROT_ADD:
+ default:
+ mat3_to_eulO(oldeul, rot_order, rot);
+ add_v3_v3(neweul, oldeul);
+ eulO_to_mat3(rot, neweul, rot_order);
+ break;
}
break;
case TRANS_LOCATION:
@@ -3774,14 +3920,22 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
to_min = data->to_min;
to_max = data->to_max;
for (i = 0; i < 3; i++) {
- /* add to original location (so that it can still be moved) */
- loc[i] += (to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])));
+ newloc[i] = (to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])));
+ }
+ switch (data->mix_mode_loc) {
+ case TRANS_MIXLOC_REPLACE:
+ copy_v3_v3(loc, newloc);
+ break;
+ case TRANS_MIXLOC_ADD:
+ default:
+ add_v3_v3(loc, newloc);
+ break;
}
break;
}
/* apply to matrix */
- loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, cob->rotOrder);
+ loc_rot_size_to_mat4(cob->matrix, loc, rot, size);
}
}
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index f536f21c3e5..7f2f04d7eb5 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -1053,7 +1053,7 @@ Collection *CTX_data_collection(const bContext *C)
/* fallback */
Scene *scene = CTX_data_scene(C);
- return BKE_collection_master(scene);
+ return scene->master_collection;
}
enum eContextObjectMode CTX_data_mode_enum_ex(const Object *obedit,
@@ -1351,9 +1351,10 @@ int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list)
Depsgraph *CTX_data_depsgraph_pointer(const bContext *C)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
/* Dependency graph might have been just allocated, and hence it will not be marked.
* This confuses redo system due to the lack of flushing changes back to the original data.
* In the future we would need to check whether the CTX_wm_window(C) is in editing mode (as an
@@ -1381,7 +1382,8 @@ Depsgraph *CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Depsgraph *CTX_data_depsgraph_on_load(const bContext *C)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- return BKE_scene_get_depsgraph(scene, view_layer, false);
+ return BKE_scene_get_depsgraph(bmain, scene, view_layer, false);
}
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index fcbebd24b4a..6740fc985e9 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -261,7 +261,8 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra
float (**deformcos)[3])
{
ModifierData *md;
- Mesh *me;
+ Mesh *me_input = ob->data;
+ Mesh *me = NULL;
int i, a, numleft = 0, numVerts = 0;
int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
float(*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
@@ -270,7 +271,6 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra
modifiers_clearErrors(ob);
- me = NULL;
md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
/* compute the deformation matrices and coordinates for the first
@@ -292,7 +292,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra
data_mask = datamasks->mask;
BLI_linklist_free((LinkNode *)datamasks, NULL);
- me = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, &data_mask, NULL);
+ me = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, &data_mask, NULL, me_input);
deformedVerts = editbmesh_vert_coords_alloc(em, &numVerts);
defmats = MEM_mallocN(sizeof(*defmats) * numVerts, "defmats");
@@ -342,6 +342,28 @@ static void crazyspace_init_object_for_eval(struct Depsgraph *depsgraph,
}
}
+static void crazyspace_init_verts_and_matrices(const Mesh *mesh,
+ float (**deformmats)[3][3],
+ float (**deformcos)[3])
+{
+ int num_verts;
+ *deformcos = BKE_mesh_vert_coords_alloc(mesh, &num_verts);
+ *deformmats = MEM_callocN(sizeof(**deformmats) * num_verts, "defmats");
+ for (int a = 0; a < num_verts; a++) {
+ unit_m3((*deformmats)[a]);
+ }
+ BLI_assert(num_verts == mesh->totvert);
+}
+
+static bool crazyspace_modifier_supports_deform(ModifierData *md)
+{
+ if (ELEM(md->type, eModifierType_Subsurf, eModifierType_Multires)) {
+ return true;
+ }
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ return (mti->type == eModifierTypeType_OnlyDeform);
+}
+
int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph,
Scene *scene,
Object *object,
@@ -349,25 +371,23 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph,
float (**deformcos)[3])
{
ModifierData *md;
- Mesh *me_eval;
- int a, numVerts = 0;
+ Mesh *me_eval = NULL;
float(*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
int numleft = 0;
VirtualModifierData virtualModifierData;
Object object_eval;
crazyspace_init_object_for_eval(depsgraph, object, &object_eval);
MultiresModifierData *mmd = get_multires_modifier(scene, &object_eval, 0);
+ const bool is_sculpt_mode = (object->mode & OB_MODE_SCULPT) != 0;
const bool has_multires = mmd != NULL && mmd->sculptlvl > 0;
const ModifierEvalContext mectx = {depsgraph, &object_eval, 0};
- if (has_multires) {
+ if (is_sculpt_mode && has_multires) {
*deformmats = NULL;
*deformcos = NULL;
return numleft;
}
- me_eval = NULL;
-
md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData);
for (; md; md = md->next) {
@@ -378,41 +398,37 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph,
}
if (mti->type == eModifierTypeType_OnlyDeform) {
- if (!defmats) {
+ if (defmats == NULL) {
/* NOTE: Evaluated object si re-set to its original undeformed
* state. */
Mesh *me = object_eval.data;
me_eval = BKE_mesh_copy_for_eval(me, true);
- deformedVerts = BKE_mesh_vert_coords_alloc(me, &numVerts);
- defmats = MEM_callocN(sizeof(*defmats) * numVerts, "defmats");
-
- for (a = 0; a < numVerts; a++) {
- unit_m3(defmats[a]);
- }
+ crazyspace_init_verts_and_matrices(me_eval, &defmats, &deformedVerts);
}
if (mti->deformMatrices) {
- mti->deformMatrices(md, &mectx, me_eval, deformedVerts, defmats, numVerts);
+ mti->deformMatrices(md, &mectx, me_eval, deformedVerts, defmats, me_eval->totvert);
}
else {
break;
}
}
+ else {
+ break;
+ }
}
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
continue;
}
- if (mti->type == eModifierTypeType_OnlyDeform) {
+ if (crazyspace_modifier_supports_deform(md)) {
numleft++;
}
}
- if (me_eval) {
+ if (me_eval != NULL) {
BKE_id_free(NULL, me_eval);
}
@@ -435,6 +451,13 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
/* there are deformation modifier which doesn't support deformation matrices
* calculation. Need additional crazyspace correction */
+ Mesh *mesh = (Mesh *)object->data;
+ Mesh *mesh_eval = NULL;
+
+ if (*deformcos == NULL) {
+ crazyspace_init_verts_and_matrices(mesh, deformmats, deformcos);
+ }
+
float(*deformedVerts)[3] = *deformcos;
float(*origVerts)[3] = MEM_dupallocN(deformedVerts);
float(*quats)[4];
@@ -444,23 +467,26 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
crazyspace_init_object_for_eval(depsgraph, object, &object_eval);
ModifierData *md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData);
const ModifierEvalContext mectx = {depsgraph, &object_eval, 0};
- Mesh *mesh = (Mesh *)object->data;
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
continue;
}
- if (mti->type == eModifierTypeType_OnlyDeform) {
+ if (crazyspace_modifier_supports_deform(md)) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
/* skip leading modifiers which have been already
* handled in sculpt_get_first_deform_matrices */
if (mti->deformMatrices && !deformed) {
continue;
}
- mti->deformVerts(md, &mectx, NULL, deformedVerts, mesh->totvert);
+ if (mesh_eval == NULL) {
+ mesh_eval = BKE_mesh_copy_for_eval(mesh, true);
+ }
+
+ mti->deformVerts(md, &mectx, mesh_eval, deformedVerts, mesh_eval->totvert);
deformed = 1;
}
}
@@ -479,6 +505,10 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
MEM_freeN(origVerts);
MEM_freeN(quats);
+
+ if (mesh_eval != NULL) {
+ BKE_id_free(NULL, mesh_eval);
+ }
}
if (*deformmats == NULL) {
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 0126c261fa1..d81d250a305 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -36,6 +36,7 @@
#include "DNA_anim_types.h"
#include "DNA_curve_types.h"
#include "DNA_material_types.h"
+#include "DNA_defaults.h"
/* for dereferencing pointers */
#include "DNA_key_types.h"
@@ -141,34 +142,16 @@ void BKE_curve_free(Curve *cu)
MEM_SAFE_FREE(cu->mat);
MEM_SAFE_FREE(cu->str);
MEM_SAFE_FREE(cu->strinfo);
- MEM_SAFE_FREE(cu->bb);
MEM_SAFE_FREE(cu->tb);
}
-void BKE_curve_init(Curve *cu)
+void BKE_curve_init(Curve *cu, const short curve_type)
{
- /* BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(cu, id)); */ /* cu->type is already initialized... */
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(cu, id));
- copy_v3_fl(cu->size, 1.0f);
- cu->flag = CU_DEFORM_BOUNDS_OFF | CU_PATH_RADIUS;
- cu->pathlen = 100;
- cu->resolu = cu->resolv = (cu->type == OB_SURF) ? 4 : 12;
- cu->width = 1.0;
- cu->wordspace = 1.0;
- cu->spacing = cu->linedist = 1.0;
- cu->fsize = 1.0;
- cu->ulheight = 0.05;
- cu->texflag = CU_AUTOSPACE;
- cu->smallcaps_scale = 0.75f;
- /* XXX: this one seems to be the best one in most cases, at least for curve deform... */
- cu->twist_mode = CU_TWIST_MINIMUM;
- cu->bevfac1 = 0.0f;
- cu->bevfac2 = 1.0f;
- cu->bevfac1_mapping = CU_BEVFAC_MAP_RESOLU;
- cu->bevfac2_mapping = CU_BEVFAC_MAP_RESOLU;
- cu->bevresol = 4;
+ MEMCPY_STRUCT_AFTER(cu, DNA_struct_default_get(Curve), id);
- cu->bb = BKE_boundbox_alloc_unit();
+ cu->type = curve_type;
if (cu->type == OB_FONT) {
cu->flag |= CU_FRONT | CU_BACK;
@@ -182,6 +165,9 @@ void BKE_curve_init(Curve *cu)
cu->tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "textbox");
cu->tb[0].w = cu->tb[0].h = 0.0;
}
+ else if (cu->type == OB_SURF) {
+ cu->resolv = 4;
+ }
}
Curve *BKE_curve_add(Main *bmain, const char *name, int type)
@@ -189,9 +175,8 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type)
Curve *cu;
cu = BKE_libblock_alloc(bmain, ID_CU, name, 0);
- cu->type = type;
- BKE_curve_init(cu);
+ BKE_curve_init(cu, type);
return cu;
}
@@ -216,7 +201,6 @@ void BKE_curve_copy_data(Main *bmain, Curve *cu_dst, const Curve *cu_src, const
cu_dst->str = MEM_dupallocN(cu_src->str);
cu_dst->strinfo = MEM_dupallocN(cu_src->strinfo);
cu_dst->tb = MEM_dupallocN(cu_src->tb);
- cu_dst->bb = MEM_dupallocN(cu_src->bb);
cu_dst->batch_cache = NULL;
if (cu_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
@@ -303,41 +287,6 @@ void BKE_curve_type_test(Object *ob)
}
}
-void BKE_curve_boundbox_calc(Curve *cu, float r_loc[3], float r_size[3])
-{
- BoundBox *bb;
- float min[3], max[3];
- float mloc[3], msize[3];
-
- if (cu->bb == NULL) {
- cu->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
- }
- bb = cu->bb;
-
- if (!r_loc) {
- r_loc = mloc;
- }
- if (!r_size) {
- r_size = msize;
- }
-
- INIT_MINMAX(min, max);
- if (!BKE_curve_minmax(cu, true, min, max)) {
- min[0] = min[1] = min[2] = -1.0f;
- max[0] = max[1] = max[2] = 1.0f;
- }
-
- mid_v3_v3v3(r_loc, min, max);
-
- r_size[0] = (max[0] - min[0]) / 2.0f;
- r_size[1] = (max[1] - min[1]) / 2.0f;
- r_size[2] = (max[2] - min[2]) / 2.0f;
-
- BKE_boundbox_init_from_minmax(bb, min, max);
-
- bb->flag &= ~BOUNDBOX_DIRTY;
-}
-
BoundBox *BKE_curve_boundbox_get(Object *ob)
{
/* This is Object-level data access,
@@ -361,13 +310,23 @@ BoundBox *BKE_curve_boundbox_get(Object *ob)
void BKE_curve_texspace_calc(Curve *cu)
{
- float loc[3], size[3];
- int a;
+ if (cu->texflag & CU_AUTOSPACE) {
+ float min[3], max[3];
- BKE_curve_boundbox_calc(cu, loc, size);
+ INIT_MINMAX(min, max);
+ if (!BKE_curve_minmax(cu, true, min, max)) {
+ min[0] = min[1] = min[2] = -1.0f;
+ max[0] = max[1] = max[2] = 1.0f;
+ }
- if (cu->texflag & CU_AUTOSPACE) {
- for (a = 0; a < 3; a++) {
+ float loc[3], size[3];
+ mid_v3_v3v3(loc, min, max);
+
+ size[0] = (max[0] - min[0]) / 2.0f;
+ size[1] = (max[1] - min[1]) / 2.0f;
+ size[2] = (max[2] - min[2]) / 2.0f;
+
+ for (int a = 0; a < 3; a++) {
if (size[a] == 0.0f) {
size[a] = 1.0f;
}
@@ -381,27 +340,28 @@ void BKE_curve_texspace_calc(Curve *cu)
copy_v3_v3(cu->loc, loc);
copy_v3_v3(cu->size, size);
- zero_v3(cu->rot);
+
+ cu->texflag |= CU_AUTOSPACE_EVALUATED;
}
}
-BoundBox *BKE_curve_texspace_get(Curve *cu, float r_loc[3], float r_rot[3], float r_size[3])
+void BKE_curve_texspace_ensure(Curve *cu)
{
- if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
+ if ((cu->texflag & CU_AUTOSPACE) && !(cu->texflag & CU_AUTOSPACE_EVALUATED)) {
BKE_curve_texspace_calc(cu);
}
+}
+
+void BKE_curve_texspace_get(Curve *cu, float r_loc[3], float r_size[3])
+{
+ BKE_curve_texspace_ensure(cu);
if (r_loc) {
copy_v3_v3(r_loc, cu->loc);
}
- if (r_rot) {
- copy_v3_v3(r_rot, cu->rot);
- }
if (r_size) {
copy_v3_v3(r_size, cu->size);
}
-
- return cu->bb;
}
bool BKE_nurbList_index_get_co(ListBase *nurb, const int index, float r_co[3])
@@ -697,7 +657,7 @@ float BKE_nurb_calc_length(const Nurb *nu, int resolution)
a = nu->pntsu - 1;
bp = nu->bp;
if (nu->flagu & CU_NURB_CYCLIC) {
- ++a;
+ a++;
prevbp = nu->bp + (nu->pntsu - 1);
}
else {
@@ -708,7 +668,7 @@ float BKE_nurb_calc_length(const Nurb *nu, int resolution)
while (a--) {
length += len_v3v3(prevbp->vec, bp->vec);
prevbp = bp;
- ++bp;
+ bp++;
}
}
else if (nu->type == CU_BEZIER) {
@@ -716,12 +676,12 @@ float BKE_nurb_calc_length(const Nurb *nu, int resolution)
a = nu->pntsu - 1;
bezt = nu->bezt;
if (nu->flagu & CU_NURB_CYCLIC) {
- ++a;
+ a++;
prevbezt = nu->bezt + (nu->pntsu - 1);
}
else {
prevbezt = bezt;
- ++bezt;
+ bezt++;
}
while (a--) {
@@ -748,7 +708,7 @@ float BKE_nurb_calc_length(const Nurb *nu, int resolution)
}
}
prevbezt = bezt;
- ++bezt;
+ bezt++;
}
MEM_freeN(points);
@@ -2157,8 +2117,8 @@ static void tilt_bezpart(BezTriple *prevbezt,
for (a = 0; a < resolu; a++, fac += dfac) {
if (tilt_array) {
- if (nu->tilt_interp ==
- KEY_CU_EASE) { /* May as well support for tilt also 2.47 ease interp */
+ if (nu->tilt_interp == KEY_CU_EASE) {
+ /* May as well support for tilt also 2.47 ease interp. */
*tilt_array = prevbezt->tilt +
(bezt->tilt - prevbezt->tilt) * (3.0f * fac * fac - 2.0f * fac * fac * fac);
}
@@ -2382,7 +2342,7 @@ static void make_bevel_list_3D_minimum_twist(BevList *bl)
nr = bl->nr;
while (nr--) {
- if (nr + 4 > bl->nr) { /* first time and second time, otherwise first point adjusts last */
+ if (nr + 3 > bl->nr) { /* first time and second time, otherwise first point adjusts last */
vec_to_quat(bevp1->quat, bevp1->dir, 5, 1);
}
else {
@@ -4630,6 +4590,7 @@ void BKE_curve_nurbs_vert_coords_get(ListBase *lb, float (*vert_coords)[3], int
}
}
BLI_assert(co == vert_coords[vert_len]);
+ UNUSED_VARS_NDEBUG(vert_len);
}
float (*BKE_curve_nurbs_vert_coords_alloc(ListBase *lb, int *r_vert_len))[3]
@@ -5512,15 +5473,10 @@ void BKE_curve_eval_geometry(Depsgraph *depsgraph, Curve *curve)
BKE_curve_texspace_calc(curve);
if (DEG_is_active(depsgraph)) {
Curve *curve_orig = (Curve *)DEG_get_original_id(&curve->id);
- BoundBox *bb = curve->bb;
- if (bb != NULL) {
- if (curve_orig->bb == NULL) {
- curve_orig->bb = MEM_mallocN(sizeof(*curve_orig->bb), __func__);
- }
- *curve_orig->bb = *bb;
+ if (curve->texflag & CU_AUTOSPACE_EVALUATED) {
+ curve_orig->texflag |= CU_AUTOSPACE_EVALUATED;
copy_v3_v3(curve_orig->loc, curve->loc);
copy_v3_v3(curve_orig->size, curve->size);
- copy_v3_v3(curve_orig->rot, curve->rot);
}
}
}
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index db0ed0dc0fb..8ac0f71cd7e 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -173,7 +173,7 @@ static void layerCopy_mdeformvert(const void *source, void *dest, int count)
memcpy(dest, source, count * size);
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
MDeformVert *dvert = POINTER_OFFSET(dest, i * size);
if (dvert->totweight) {
@@ -193,7 +193,7 @@ static void layerFree_mdeformvert(void *data, int count, int size)
{
int i;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
MDeformVert *dvert = POINTER_OFFSET(data, i * size);
if (dvert->dw) {
@@ -209,7 +209,7 @@ static void layerCopy_bmesh_elem_py_ptr(const void *UNUSED(source), void *dest,
{
int i, size = sizeof(void *);
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
void **ptr = POINTER_OFFSET(dest, i * size);
*ptr = NULL;
}
@@ -226,7 +226,7 @@ static void layerFree_bmesh_elem_py_ptr(void *data, int count, int size)
{
int i;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
void **ptr = POINTER_OFFSET(data, i * size);
if (*ptr) {
bpy_bm_generic_invalidate(*ptr);
@@ -258,11 +258,11 @@ static void layerInterp_mdeformvert(const void **sources,
/* build a list of unique def_nrs for dest */
totweight = 0;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
const MDeformVert *source = sources[i];
float interp_weight = weights ? weights[i] : 1.0f;
- for (j = 0; j < source->totweight; ++j) {
+ for (j = 0; j < source->totweight; j++) {
MDeformWeight *dw = &source->dw[j];
float weight = dw->weight * interp_weight;
@@ -407,7 +407,7 @@ static void layerCopy_tface(const void *source, void *dest, int count)
MTFace *dest_tf = (MTFace *)dest;
int i;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
dest_tf[i] = source_tf[i];
}
}
@@ -425,13 +425,13 @@ static void layerInterp_tface(
}
sub_weight = sub_weights;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
float weight = weights ? weights[i] : 1;
const MTFace *src = sources[i];
- for (j = 0; j < 4; ++j) {
+ for (j = 0; j < 4; j++) {
if (sub_weights) {
- for (k = 0; k < 4; ++k, ++sub_weight) {
+ for (k = 0; k < 4; k++, sub_weight++) {
madd_v2_v2fl(uv[j], src->uv[k], (*sub_weight) * weight);
}
}
@@ -452,7 +452,7 @@ static void layerSwap_tface(void *data, const int *corner_indices)
float uv[4][2];
int j;
- for (j = 0; j < 4; ++j) {
+ for (j = 0; j < 4; j++) {
const int source_index = corner_indices[j];
copy_v2_v2(uv[j], tf->uv[source_index]);
}
@@ -514,7 +514,7 @@ static void layerCopy_origspace_face(const void *source, void *dest, int count)
OrigSpaceFace *dest_tf = (OrigSpaceFace *)dest;
int i;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
dest_tf[i] = source_tf[i];
}
}
@@ -532,13 +532,13 @@ static void layerInterp_origspace_face(
}
sub_weight = sub_weights;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
float weight = weights ? weights[i] : 1;
const OrigSpaceFace *src = sources[i];
- for (j = 0; j < 4; ++j) {
+ for (j = 0; j < 4; j++) {
if (sub_weights) {
- for (k = 0; k < 4; ++k, ++sub_weight) {
+ for (k = 0; k < 4; k++, sub_weight++) {
madd_v2_v2fl(uv[j], src->uv[k], (*sub_weight) * weight);
}
}
@@ -558,7 +558,7 @@ static void layerSwap_origspace_face(void *data, const int *corner_indices)
float uv[4][2];
int j;
- for (j = 0; j < 4; ++j) {
+ for (j = 0; j < 4; j++) {
copy_v2_v2(uv[j], osf->uv[corner_indices[j]]);
}
memcpy(osf->uv, uv, sizeof(osf->uv));
@@ -613,7 +613,7 @@ static void layerCopy_mdisps(const void *source, void *dest, int count)
const MDisps *s = source;
MDisps *d = dest;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
if (s[i].disps) {
d[i].disps = MEM_dupallocN(s[i].disps);
d[i].hidden = MEM_dupallocN(s[i].hidden);
@@ -634,7 +634,7 @@ static void layerFree_mdisps(void *data, int count, int UNUSED(size))
int i;
MDisps *d = data;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
if (d[i].disps) {
MEM_freeN(d[i].disps);
}
@@ -653,7 +653,7 @@ static int layerRead_mdisps(CDataFile *cdf, void *data, int count)
MDisps *d = data;
int i;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
if (!d[i].disps) {
d[i].disps = MEM_calloc_arrayN(d[i].totdisp, 3 * sizeof(float), "mdisps read");
}
@@ -672,7 +672,7 @@ static int layerWrite_mdisps(CDataFile *cdf, const void *data, int count)
const MDisps *d = data;
int i;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
if (!cdf_write_data(cdf, d[i].totdisp * 3 * sizeof(float), d[i].disps)) {
CLOG_ERROR(&LOG, "failed to write multires displacement %d/%d %d", i, count, d[i].totdisp);
return 0;
@@ -688,7 +688,7 @@ static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), const void *data, int
size_t size = 0;
int i;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
size += d[i].totdisp * 3 * sizeof(float);
}
@@ -701,7 +701,7 @@ static void layerCopy_grid_paint_mask(const void *source, void *dest, int count)
const GridPaintMask *s = source;
GridPaintMask *d = dest;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
if (s[i].data) {
d[i].data = MEM_dupallocN(s[i].data);
d[i].level = s[i].level;
@@ -718,7 +718,7 @@ static void layerFree_grid_paint_mask(void *data, int count, int UNUSED(size))
int i;
GridPaintMask *gpm = data;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
if (gpm[i].data) {
MEM_freeN(gpm[i].data);
}
@@ -887,7 +887,7 @@ static void layerInterp_mloopcol(
} col = {0};
const float *sub_weight = sub_weights;
- for (int i = 0; i < count; ++i) {
+ for (int i = 0; i < count; i++) {
float weight = weights ? weights[i] : 1;
const MLoopCol *src = sources[i];
if (sub_weights) {
@@ -1128,13 +1128,13 @@ static void layerInterp_mcol(
}
sub_weight = sub_weights;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
float weight = weights ? weights[i] : 1;
- for (j = 0; j < 4; ++j) {
+ for (j = 0; j < 4; j++) {
if (sub_weights) {
const MCol *src = sources[i];
- for (k = 0; k < 4; ++k, ++sub_weight, ++src) {
+ for (k = 0; k < 4; k++, sub_weight++, src++) {
const float w = (*sub_weight) * weight;
col[j].a += src->a * w;
col[j].r += src->r * w;
@@ -1153,7 +1153,7 @@ static void layerInterp_mcol(
}
/* Delay writing to the destination in case dest is in sources. */
- for (j = 0; j < 4; ++j) {
+ for (j = 0; j < 4; j++) {
/* Subdivide smooth or fractal can cause problems without clamping
* although weights should also not cause this situation */
@@ -1170,7 +1170,7 @@ static void layerSwap_mcol(void *data, const int *corner_indices)
MCol col[4];
int j;
- for (j = 0; j < 4; ++j) {
+ for (j = 0; j < 4; j++) {
col[j] = mcol[corner_indices[j]];
}
@@ -1210,12 +1210,12 @@ static void layerInterp_bweight(const void **sources,
f = 0.0f;
if (weights) {
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
f += *in[i] * weights[i];
}
}
else {
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
f += *in[i];
}
}
@@ -1241,12 +1241,12 @@ static void layerInterp_shapekey(const void **sources,
zero_v3(co);
if (weights) {
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
madd_v3_v3fl(co, in[i], weights[i]);
}
}
else {
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
add_v3_v3(co, in[i]);
}
}
@@ -1862,7 +1862,7 @@ bool CustomData_merge(const struct CustomData *source,
int number = 0, maxnumber = -1;
bool changed = false;
- for (i = 0; i < source->totlayer; ++i) {
+ for (i = 0; i < source->totlayer; i++) {
layer = &source->layers[i];
/*typeInfo = layerType_getInfo(layer->type);*/ /*UNUSED*/
@@ -1934,7 +1934,7 @@ bool CustomData_merge(const struct CustomData *source,
void CustomData_realloc(CustomData *data, int totelem)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
CustomDataLayer *layer = &data->layers[i];
const LayerTypeInfo *typeInfo;
if (layer->flag & CD_FLAG_NOFREE) {
@@ -1995,7 +1995,7 @@ void CustomData_free(CustomData *data, int totelem)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
customData_free_layer__internal(&data->layers[i], totelem);
}
@@ -2011,7 +2011,7 @@ void CustomData_free_typemask(struct CustomData *data, int totelem, CustomDataMa
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
CustomDataLayer *layer = &data->layers[i];
if (!(mask & CD_TYPE_AS_MASK(layer->type))) {
continue;
@@ -2032,7 +2032,7 @@ static void customData_update_offsets(CustomData *data)
const LayerTypeInfo *typeInfo;
int i, offset = 0;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
typeInfo = layerType_getInfo(data->layers[i].type);
data->layers[i].offset = offset;
@@ -2048,7 +2048,7 @@ static int CustomData_get_layer_index__notypemap(const CustomData *data, int typ
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
return i;
}
@@ -2082,7 +2082,7 @@ int CustomData_get_named_layer_index(const CustomData *data, int type, const cha
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
if (STREQ(data->layers[i].name, name)) {
return i;
@@ -2164,7 +2164,7 @@ void CustomData_set_layer_active(CustomData *data, int type, int n)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
data->layers[i].active = n;
}
@@ -2175,7 +2175,7 @@ void CustomData_set_layer_render(CustomData *data, int type, int n)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
data->layers[i].active_rnd = n;
}
@@ -2186,7 +2186,7 @@ void CustomData_set_layer_clone(CustomData *data, int type, int n)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
data->layers[i].active_clone = n;
}
@@ -2197,7 +2197,7 @@ void CustomData_set_layer_stencil(CustomData *data, int type, int n)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
data->layers[i].active_mask = n;
}
@@ -2210,7 +2210,7 @@ void CustomData_set_layer_active_index(CustomData *data, int type, int n)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
data->layers[i].active = n - i;
}
@@ -2221,7 +2221,7 @@ void CustomData_set_layer_render_index(CustomData *data, int type, int n)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
data->layers[i].active_rnd = n - i;
}
@@ -2232,7 +2232,7 @@ void CustomData_set_layer_clone_index(CustomData *data, int type, int n)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
data->layers[i].active_clone = n - i;
}
@@ -2243,7 +2243,7 @@ void CustomData_set_layer_stencil_index(CustomData *data, int type, int n)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
data->layers[i].active_mask = n - i;
}
@@ -2254,7 +2254,7 @@ void CustomData_set_layer_flag(struct CustomData *data, int type, int flag)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
data->layers[i].flag |= flag;
}
@@ -2265,7 +2265,7 @@ void CustomData_clear_layer_flag(struct CustomData *data, int type, int flag)
{
const int nflag = ~flag;
- for (int i = 0; i < data->totlayer; ++i) {
+ for (int i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
data->layers[i].flag &= nflag;
}
@@ -2355,7 +2355,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
data->totlayer++;
/* keep layers ordered by type */
- for (; index > 0 && data->layers[index - 1].type > type; --index) {
+ for (; index > 0 && data->layers[index - 1].type > type; index--) {
data->layers[index] = data->layers[index - 1];
}
@@ -2447,7 +2447,7 @@ bool CustomData_free_layer(CustomData *data, int type, int totelem, int index)
customData_free_layer__internal(&data->layers[index], totelem);
- for (i = index + 1; i < data->totlayer; ++i) {
+ for (i = index + 1; i < data->totlayer; i++) {
data->layers[i - 1] = data->layers[i];
}
@@ -2628,7 +2628,7 @@ void CustomData_free_temporary(CustomData *data, int totelem)
int i, j;
bool changed = false;
- for (i = 0, j = 0; i < data->totlayer; ++i) {
+ for (i = 0, j = 0; i < data->totlayer; i++) {
layer = &data->layers[i];
if (i != j) {
@@ -2660,7 +2660,7 @@ void CustomData_set_only_copy(const struct CustomData *data, CustomDataMask mask
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (!(mask & CD_TYPE_AS_MASK(data->layers[i].type))) {
data->layers[i].flag |= CD_FLAG_NOCOPY;
}
@@ -2725,7 +2725,7 @@ void CustomData_copy_data_named(
int src_i, dest_i;
/* copies a layer at a time */
- for (src_i = 0; src_i < source->totlayer; ++src_i) {
+ for (src_i = 0; src_i < source->totlayer; src_i++) {
dest_i = CustomData_get_named_layer_index(
dest, source->layers[src_i].type, source->layers[src_i].name);
@@ -2744,7 +2744,7 @@ void CustomData_copy_data(
/* copies a layer at a time */
dest_i = 0;
- for (src_i = 0; src_i < source->totlayer; ++src_i) {
+ for (src_i = 0; src_i < source->totlayer; src_i++) {
/* find the first dest layer with type >= the source type
* (this should work because layers are ordered by type)
@@ -2800,7 +2800,7 @@ void CustomData_free_elem(CustomData *data, int index, int count)
int i;
const LayerTypeInfo *typeInfo;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
typeInfo = layerType_getInfo(data->layers[i].type);
@@ -2835,7 +2835,7 @@ void CustomData_interp(const CustomData *source,
/* interpolates a layer at a time */
dest_i = 0;
- for (src_i = 0; src_i < source->totlayer; ++src_i) {
+ for (src_i = 0; src_i < source->totlayer; src_i++) {
const LayerTypeInfo *typeInfo = layerType_getInfo(source->layers[src_i].type);
if (!typeInfo->interp) {
continue;
@@ -2857,7 +2857,7 @@ void CustomData_interp(const CustomData *source,
if (dest->layers[dest_i].type == source->layers[src_i].type) {
void *src_data = source->layers[src_i].data;
- for (j = 0; j < count; ++j) {
+ for (j = 0; j < count; j++) {
sources[j] = POINTER_OFFSET(src_data, (size_t)src_indices[j] * typeInfo->size);
}
@@ -2893,7 +2893,7 @@ void CustomData_swap_corners(struct CustomData *data, int index, const int *corn
const LayerTypeInfo *typeInfo;
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
typeInfo = layerType_getInfo(data->layers[i].type);
if (typeInfo->swap) {
@@ -2916,7 +2916,7 @@ void CustomData_swap(struct CustomData *data, const int index_a, const int index
return;
}
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type);
const size_t size = typeInfo->size;
const size_t offset_a = size * index_a;
@@ -3392,7 +3392,7 @@ void CustomData_bmesh_free_block(CustomData *data, void **block)
return;
}
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
typeInfo = layerType_getInfo(data->layers[i].type);
@@ -3422,7 +3422,7 @@ void CustomData_bmesh_free_block_data(CustomData *data, void *block)
return;
}
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
typeInfo = layerType_getInfo(data->layers[i].type);
@@ -3476,7 +3476,7 @@ void CustomData_bmesh_set_default(CustomData *data, void **block)
CustomData_bmesh_alloc_block(data, block);
}
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
CustomData_bmesh_set_default_n(data, block, i);
}
}
@@ -3498,7 +3498,7 @@ void CustomData_bmesh_copy_data(const CustomData *source,
/* copies a layer at a time */
dest_i = 0;
- for (src_i = 0; src_i < source->totlayer; ++src_i) {
+ for (src_i = 0; src_i < source->totlayer; src_i++) {
/* find the first dest layer with type >= the source type
* (this should work because layers are ordered by type)
@@ -3609,7 +3609,7 @@ bool CustomData_has_math(const struct CustomData *data)
int i;
/* interpolates a layer at a time */
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (CustomData_layer_has_math(data, i)) {
return true;
}
@@ -3624,7 +3624,7 @@ bool CustomData_bmesh_has_free(const struct CustomData *data)
const LayerTypeInfo *typeInfo;
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
typeInfo = layerType_getInfo(data->layers[i].type);
if (typeInfo->free) {
@@ -3640,7 +3640,7 @@ bool CustomData_has_interp(const struct CustomData *data)
int i;
/* interpolates a layer at a time */
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (CustomData_layer_has_interp(data, i)) {
return true;
}
@@ -3652,7 +3652,7 @@ bool CustomData_has_interp(const struct CustomData *data)
bool CustomData_has_referenced(const struct CustomData *data)
{
int i;
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
if (data->layers[i].flag & CD_FLAG_NOFREE) {
return true;
}
@@ -3832,11 +3832,11 @@ void CustomData_bmesh_interp(CustomData *data,
}
/* interpolates a layer at a time */
- for (i = 0; i < data->totlayer; ++i) {
+ for (i = 0; i < data->totlayer; i++) {
CustomDataLayer *layer = &data->layers[i];
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
if (typeInfo->interp) {
- for (j = 0; j < count; ++j) {
+ for (j = 0; j < count; j++) {
sources[j] = POINTER_OFFSET(src_blocks[j], layer->offset);
}
CustomData_bmesh_interp_n(
@@ -3869,7 +3869,7 @@ void CustomData_to_bmesh_block(const CustomData *source,
/* copies a layer at a time */
dest_i = 0;
- for (src_i = 0; src_i < source->totlayer; ++src_i) {
+ for (src_i = 0; src_i < source->totlayer; src_i++) {
/* find the first dest layer with type >= the source type
* (this should work because layers are ordered by type)
@@ -3927,7 +3927,7 @@ void CustomData_from_bmesh_block(const CustomData *source,
/* copies a layer at a time */
dest_i = 0;
- for (src_i = 0; src_i < source->totlayer; ++src_i) {
+ for (src_i = 0; src_i < source->totlayer; src_i++) {
/* find the first dest layer with type >= the source type
* (this should work because layers are ordered by type)
@@ -4181,7 +4181,7 @@ bool CustomData_verify_versions(struct CustomData *data, int index)
if (!typeInfo->defaultname && (index > 0) && data->layers[index - 1].type == layer->type) {
keeplayer = false; /* multiple layers of which we only support one */
}
- /* This is a pre-emptive fix for cases that should not happen
+ /* This is a preemptive fix for cases that should not happen
* (layers that should not be written in .blend files),
* but can happen due to bugs (see e.g. T62318).
* Also for forward compatibility, in future,
@@ -4198,7 +4198,7 @@ bool CustomData_verify_versions(struct CustomData *data, int index)
}
if (!keeplayer) {
- for (i = index + 1; i < data->totlayer; ++i) {
+ for (i = index + 1; i < data->totlayer; i++) {
data->layers[i - 1] = data->layers[i];
}
data->totlayer--;
diff --git a/source/blender/blenkernel/intern/editlattice.c b/source/blender/blenkernel/intern/editlattice.c
index 12e737bbaa8..2d71b847b5b 100644
--- a/source/blender/blenkernel/intern/editlattice.c
+++ b/source/blender/blenkernel/intern/editlattice.c
@@ -92,6 +92,21 @@ void BKE_editlattice_load(Object *obedit)
lt = obedit->data;
editlt = lt->editlatt->latt;
+ MEM_freeN(lt->def);
+
+ lt->def = MEM_dupallocN(editlt->def);
+
+ lt->flag = editlt->flag;
+
+ lt->pntsu = editlt->pntsu;
+ lt->pntsv = editlt->pntsv;
+ lt->pntsw = editlt->pntsw;
+
+ lt->typeu = editlt->typeu;
+ lt->typev = editlt->typev;
+ lt->typew = editlt->typew;
+ lt->actbp = editlt->actbp;
+
if (lt->editlatt->shapenr) {
actkey = BLI_findlink(&lt->key->block, lt->editlatt->shapenr - 1);
@@ -112,22 +127,6 @@ void BKE_editlattice_load(Object *obedit)
bp++;
}
}
- else {
- MEM_freeN(lt->def);
-
- lt->def = MEM_dupallocN(editlt->def);
-
- lt->flag = editlt->flag;
-
- lt->pntsu = editlt->pntsu;
- lt->pntsv = editlt->pntsv;
- lt->pntsw = editlt->pntsw;
-
- lt->typeu = editlt->typeu;
- lt->typev = editlt->typev;
- lt->typew = editlt->typew;
- lt->actbp = editlt->actbp;
- }
if (lt->dvert) {
BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index 866c494d354..d929c953b89 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -32,6 +32,8 @@
#include "BKE_editmesh.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate)
{
@@ -51,6 +53,7 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
*em_copy = *em;
em_copy->mesh_eval_cage = em_copy->mesh_eval_final = NULL;
+ em_copy->bb_cage = NULL;
em_copy->derivedVertColor = NULL;
em_copy->derivedVertColorLen = 0;
@@ -151,6 +154,8 @@ void BKE_editmesh_free_derivedmesh(BMEditMesh *em)
BKE_id_free(NULL, em->mesh_eval_final);
}
em->mesh_eval_cage = em->mesh_eval_final = NULL;
+
+ MEM_SAFE_FREE(em->bb_cage);
}
/*does not free the BMEditMesh struct itself*/
@@ -257,3 +262,19 @@ void BKE_editmesh_ensure_autosmooth(BMEditMesh *em)
BKE_editmesh_lnorspace_update(em);
}
}
+
+BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em)
+{
+ if (em->bb_cage == NULL) {
+ float min[3], max[3];
+ INIT_MINMAX(min, max);
+ if (em->mesh_eval_cage) {
+ BKE_mesh_minmax(em->mesh_eval_cage, min, max);
+ }
+
+ em->bb_cage = MEM_callocN(sizeof(BoundBox), "BMEditMesh.bb_cage");
+ BKE_boundbox_init_from_minmax(em->bb_cage, min, max);
+ }
+
+ return em->bb_cage;
+}
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 657a08877b0..b596eeb9e35 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -1714,7 +1714,10 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
* of scale over all three axes unless the matrix includes shear. */
return cbrtf(mat4_to_volume_scale(mat));
}
- else if (dtar->transChan >= DTAR_TRANSCHAN_SCALEX) {
+ else if (ELEM(dtar->transChan,
+ DTAR_TRANSCHAN_SCALEX,
+ DTAR_TRANSCHAN_SCALEY,
+ DTAR_TRANSCHAN_SCALEZ)) {
/* Extract scale, and choose the right axis,
* inline 'mat4_to_size'. */
return len_v3(mat[dtar->transChan - DTAR_TRANSCHAN_SCALEX]);
@@ -1728,15 +1731,25 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
* b) [NOT USED] directly use the original values (no decomposition)
* - only an option for "transform space", if quality is really bad with a)
*/
- float eul[3];
+ float quat[4];
+ int channel;
- mat4_to_eulO(eul, rot_order, mat);
+ if (dtar->transChan == DTAR_TRANSCHAN_ROTW) {
+ channel = 0;
+ }
+ else {
+ channel = 1 + dtar->transChan - DTAR_TRANSCHAN_ROTX;
+ BLI_assert(channel < 4);
+ }
- if (use_eulers) {
- compatible_eul(eul, oldEul);
+ BKE_driver_target_matrix_to_rot_channels(
+ mat, rot_order, dtar->rotation_mode, channel, false, quat);
+
+ if (use_eulers && dtar->rotation_mode == DTAR_ROTMODE_AUTO) {
+ compatible_eul(quat + 1, oldEul);
}
- return eul[dtar->transChan - DTAR_TRANSCHAN_ROTX];
+ return quat[channel];
}
else {
/* extract location and choose right axis */
@@ -1744,6 +1757,71 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
}
}
+/* Convert a quaternion to pseudo-angles representing the weighted amount of rotation. */
+static void quaternion_to_angles(float quat[4], int channel)
+{
+ if (channel < 0) {
+ quat[0] = 2.0f * saacosf(quat[0]);
+
+ for (int i = 1; i < 4; i++) {
+ quat[i] = 2.0f * saasinf(quat[i]);
+ }
+ }
+ else if (channel == 0) {
+ quat[0] = 2.0f * saacosf(quat[0]);
+ }
+ else {
+ quat[channel] = 2.0f * saasinf(quat[channel]);
+ }
+}
+
+/* Compute channel values for a rotational Transform Channel driver variable. */
+void BKE_driver_target_matrix_to_rot_channels(
+ float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4])
+{
+ float *const quat = r_buf;
+ float *const eul = r_buf + 1;
+
+ zero_v4(r_buf);
+
+ if (rotation_mode == DTAR_ROTMODE_AUTO) {
+ mat4_to_eulO(eul, auto_order, mat);
+ }
+ else if (rotation_mode >= DTAR_ROTMODE_EULER_MIN && rotation_mode <= DTAR_ROTMODE_EULER_MAX) {
+ mat4_to_eulO(eul, rotation_mode, mat);
+ }
+ else if (rotation_mode == DTAR_ROTMODE_QUATERNION) {
+ mat4_to_quat(quat, mat);
+
+ /* For Transformation constraint convenience, convert to pseudo-angles. */
+ if (angles) {
+ quaternion_to_angles(quat, channel);
+ }
+ }
+ else if (rotation_mode >= DTAR_ROTMODE_SWING_TWIST_X &&
+ rotation_mode <= DTAR_ROTMODE_SWING_TWIST_Z) {
+ int axis = rotation_mode - DTAR_ROTMODE_SWING_TWIST_X;
+ float raw_quat[4], twist;
+
+ mat4_to_quat(raw_quat, mat);
+
+ if (channel == axis + 1) {
+ /* If only the twist angle is needed, skip computing swing. */
+ twist = quat_split_swing_and_twist(raw_quat, axis, NULL, NULL);
+ }
+ else {
+ twist = quat_split_swing_and_twist(raw_quat, axis, quat, NULL);
+
+ quaternion_to_angles(quat, channel);
+ }
+
+ quat[axis + 1] = twist;
+ }
+ else {
+ BLI_assert(false);
+ }
+}
+
/* ......... */
/* Table of Driver Variable Type Info Data */
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index d4bf76ea44a..f78833a0ebe 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -48,14 +48,18 @@
#include "BKE_action.h"
#include "BKE_animsys.h"
+#include "BKE_curve.h"
+#include "BKE_collection.h"
+#include "BKE_colortools.h"
#include "BKE_deform.h"
#include "BKE_gpencil.h"
-#include "BKE_colortools.h"
#include "BKE_icons.h"
#include "BKE_library.h"
#include "BKE_main.h"
-#include "BKE_object.h"
#include "BKE_material.h"
+#include "BKE_object.h"
+
+#include "BLI_math_color.h"
#include "DEG_depsgraph.h"
@@ -263,7 +267,8 @@ bGPDframe *BKE_gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
/* check whether frame was added successfully */
if (state == -1) {
- CLOG_ERROR(&LOG, "Frame (%d) existed already for this layer. Using existing frame", cframe);
+ CLOG_ERROR(
+ &LOG, "Frame (%d) existed already for this layer_active. Using existing frame", cframe);
/* free the newly created one, and use the old one instead */
MEM_freeN(gpf);
@@ -422,9 +427,9 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
/* grid settings */
- ARRAY_SET_ITEMS(gpd->grid.color, 0.5f, 0.5f, 0.5f); // Color
- ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); // Scale
- gpd->grid.lines = GP_DEFAULT_GRID_LINES; // Number of lines
+ ARRAY_SET_ITEMS(gpd->grid.color, 0.5f, 0.5f, 0.5f); /* Color */
+ ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); /* Scale */
+ gpd->grid.lines = GP_DEFAULT_GRID_LINES; /* Number of lines */
/* onion-skinning settings (datablock level) */
gpd->onion_flag |= (GP_ONION_GHOST_PREVCOL | GP_ONION_GHOST_NEXTCOL);
@@ -659,7 +664,7 @@ bGPdata *BKE_gpencil_copy(Main *bmain, const bGPdata *gpd)
}
/* make a copy of a given gpencil datablock */
-// XXX: Should this be deprecated?
+/* XXX: Should this be deprecated? */
bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy)
{
bGPdata *gpd_dst;
@@ -802,7 +807,7 @@ bGPDframe *BKE_gpencil_layer_find_frame(bGPDlayer *gpl, int cframe)
bGPDframe *BKE_gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
{
bGPDframe *gpf = NULL;
- short found = 0;
+ bool found = false;
/* error checking */
if (gpl == NULL) {
@@ -828,11 +833,11 @@ bGPDframe *BKE_gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_M
if (gpf->framenum < cframe) {
for (; gpf; gpf = gpf->next) {
if (gpf->framenum == cframe) {
- found = 1;
+ found = true;
break;
}
else if ((gpf->next) && (gpf->next->framenum > cframe)) {
- found = 1;
+ found = true;
break;
}
}
@@ -859,7 +864,7 @@ bGPDframe *BKE_gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_M
else {
for (; gpf; gpf = gpf->prev) {
if (gpf->framenum <= cframe) {
- found = 1;
+ found = true;
break;
}
}
@@ -893,7 +898,7 @@ bGPDframe *BKE_gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_M
/* find gp-frame which is less than or equal to cframe */
for (gpf = gpl->frames.last; gpf; gpf = gpf->prev) {
if (gpf->framenum <= cframe) {
- found = 1;
+ found = true;
break;
}
}
@@ -902,7 +907,7 @@ bGPDframe *BKE_gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_M
/* find gp-frame which is less than or equal to cframe */
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
if (gpf->framenum <= cframe) {
- found = 1;
+ found = true;
break;
}
}
@@ -1011,6 +1016,39 @@ void BKE_gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active)
}
}
+/* Set locked layers for autolock mode. */
+void BKE_gpencil_layer_autolock_set(bGPdata *gpd, const bool unlock)
+{
+ BLI_assert(gpd != NULL);
+
+ bGPDlayer *gpl;
+
+ if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) {
+ bGPDlayer *layer_active = BKE_gpencil_layer_getactive(gpd);
+
+ /* Lock all other layers */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* unlock active layer */
+ if (gpl == layer_active) {
+ gpl->flag &= ~GP_LAYER_LOCKED;
+ }
+ else {
+ gpl->flag |= GP_LAYER_LOCKED;
+ }
+ }
+ }
+ else {
+ /* If disable is better unlock all layers by default or it looks there is
+ * a problem in the UI because the user expects all layers will be unlocked
+ */
+ if (unlock) {
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpl->flag &= ~GP_LAYER_LOCKED;
+ }
+ }
+ }
+}
+
/* delete the active gp-layer */
void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
{
@@ -1161,38 +1199,34 @@ Material *BKE_gpencil_object_material_ensure_from_active_input_brush(Main *bmain
brush->gpencil_settings->flag &= ~GP_BRUSH_MATERIAL_PINNED;
}
}
- return BKE_gpencil_object_material_ensure_from_active_input_material(bmain, ob);
+ return BKE_gpencil_object_material_ensure_from_active_input_material(ob);
}
/**
* Guaranteed to return a material assigned to object. Returns never NULL.
* Only use this for materials unrelated to user input.
*/
-Material *BKE_gpencil_object_material_ensure_from_active_input_material(Main *bmain, Object *ob)
+Material *BKE_gpencil_object_material_ensure_from_active_input_material(Object *ob)
{
Material *ma = give_current_material(ob, ob->actcol);
if (ma) {
return ma;
}
- /* If the slot is empty, remove because will be added again,
- * if not, we will get an empty slot. */
- if ((ob->totcol > 0) && (ob->actcol == ob->totcol)) {
- BKE_object_material_slot_remove(bmain, ob);
- }
- return BKE_gpencil_object_material_new(bmain, ob, "Material", NULL);
+
+ return &defgpencil_material;
}
/* Get active color, and add all default settings if we don't find anything */
-Material *BKE_gpencil_object_material_ensure_active(Main *bmain, Object *ob)
+Material *BKE_gpencil_object_material_ensure_active(Object *ob)
{
Material *ma = NULL;
/* sanity checks */
- if (ELEM(NULL, bmain, ob)) {
+ if (ob == NULL) {
return NULL;
}
- ma = BKE_gpencil_object_material_ensure_from_active_input_material(bmain, ob);
+ ma = BKE_gpencil_object_material_ensure_from_active_input_material(ob);
if (ma->gp_style == NULL) {
BKE_material_init_gpencil_settings(ma);
}
@@ -1421,11 +1455,11 @@ static void stroke_defvert_create_nr_list(MDeformVert *dv_list,
/* find def_nr in list, if not exist, then create one */
for (j = 0; j < dv->totweight; j++) {
- int found = 0;
+ bool found = false;
dw = &dv->dw[j];
for (ld = result->first; ld; ld = ld->next) {
if (ld->data == POINTER_FROM_INT(dw->def_nr)) {
- found = 1;
+ found = true;
break;
}
}
@@ -1447,10 +1481,9 @@ static MDeformVert *stroke_defvert_new_count(int count, int totweight, ListBase
LinkData *ld;
MDeformVert *dst = MEM_mallocN(count * sizeof(MDeformVert), "new_deformVert");
- dst->totweight = totweight;
-
for (i = 0; i < count; i++) {
dst[i].dw = MEM_mallocN(sizeof(MDeformWeight) * totweight, "new_deformWeight");
+ dst[i].totweight = totweight;
j = 0;
/* re-assign deform groups */
for (ld = def_nr_list->first; ld; ld = ld->next) {
@@ -1640,7 +1673,7 @@ bool BKE_gpencil_sample_stroke(bGPDstroke *gps, const float dist, const bool sel
int result_totweight;
if (gps->dvert != NULL) {
- stroke_defvert_create_nr_list(gps->dvert, count, &def_nr_list, &result_totweight);
+ stroke_defvert_create_nr_list(gps->dvert, gps->totpoints, &def_nr_list, &result_totweight);
new_dv = stroke_defvert_new_count(count, result_totweight, &def_nr_list);
}
@@ -1696,17 +1729,22 @@ bool BKE_gpencil_sample_stroke(bGPDstroke *gps, const float dist, const bool sel
}
gps->points = new_pt;
- gps->totpoints = i;
- MEM_freeN(pt); /* original */
+ /* Free original vertex list. */
+ MEM_freeN(pt);
if (new_dv) {
+ /* Free original weight data. */
BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
while ((ld = BLI_pophead(&def_nr_list))) {
MEM_freeN(ld);
}
+
gps->dvert = new_dv;
}
+ gps->totpoints = i;
+
gps->flag |= GP_STROKE_RECALC_GEOMETRY;
gps->tot_triangles = 0;
@@ -1722,7 +1760,6 @@ bool BKE_gpencil_sample_stroke(bGPDstroke *gps, const float dist, const bool sel
bool BKE_gpencil_smooth_stroke(bGPDstroke *gps, int i, float inf)
{
bGPDspoint *pt = &gps->points[i];
- // float pressure = 0.0f;
float sco[3] = {0.0f};
/* Do nothing if not enough points to smooth out */
@@ -2008,6 +2045,7 @@ void BKE_gpencil_material_index_reassign(bGPdata *gpd, int totcol, int index)
/* reassign strokes */
if ((gps->mat_nr > index) || (gps->mat_nr > totcol - 1)) {
gps->mat_nr--;
+ CLAMP_MIN(gps->mat_nr, 0);
}
}
}
@@ -2575,3 +2613,401 @@ void BKE_gpencil_merge_distance_stroke(bGPDframe *gpf,
BKE_gpencil_dissolve_points(gpf, gps, GP_SPOINT_TAG);
}
}
+
+/* Helper: Check materials with same color. */
+static int gpencil_check_same_material_color(Object *ob_gp, float color[4], Material **r_mat)
+{
+ Material *ma = NULL;
+ float color_cu[4];
+ linearrgb_to_srgb_v3_v3(color_cu, color);
+ float hsv1[4];
+ rgb_to_hsv_v(color_cu, hsv1);
+ hsv1[3] = color[3];
+
+ for (int i = 1; i <= ob_gp->totcol; i++) {
+ ma = give_current_material(ob_gp, i);
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ /* Check color with small tolerance (better in HSV). */
+ float hsv2[4];
+ rgb_to_hsv_v(gp_style->fill_rgba, hsv2);
+ hsv2[3] = gp_style->fill_rgba[3];
+ if ((gp_style->fill_style == GP_STYLE_FILL_STYLE_SOLID) && (compare_v4v4(hsv1, hsv2, 0.01f))) {
+ *r_mat = ma;
+ return i - 1;
+ }
+ }
+
+ *r_mat = NULL;
+ return -1;
+}
+
+/* Helper: Add gpencil material using curve material as base. */
+static Material *gpencil_add_from_curve_material(Main *bmain,
+ Object *ob_gp,
+ const float cu_color[4],
+ const bool gpencil_lines,
+ const bool fill,
+ int *r_idx)
+{
+ Material *mat_gp = BKE_gpencil_object_material_new(
+ bmain, ob_gp, (fill) ? "Material" : "Unassigned", r_idx);
+ MaterialGPencilStyle *gp_style = mat_gp->gp_style;
+
+ /* Stroke color. */
+ if (gpencil_lines) {
+ ARRAY_SET_ITEMS(gp_style->stroke_rgba, 0.0f, 0.0f, 0.0f, 1.0f);
+ gp_style->flag |= GP_STYLE_STROKE_SHOW;
+ }
+ else {
+ linearrgb_to_srgb_v4(gp_style->stroke_rgba, cu_color);
+ gp_style->flag &= ~GP_STYLE_STROKE_SHOW;
+ }
+
+ /* Fill color. */
+ linearrgb_to_srgb_v4(gp_style->fill_rgba, cu_color);
+ /* Fill is false if the original curve hasn't material assigned, so enable it. */
+ if (fill) {
+ gp_style->flag |= GP_STYLE_FILL_SHOW;
+ }
+
+ /* Check at least one is enabled. */
+ if (((gp_style->flag & GP_STYLE_STROKE_SHOW) == 0) &&
+ ((gp_style->flag & GP_STYLE_FILL_SHOW) == 0)) {
+ gp_style->flag |= GP_STYLE_STROKE_SHOW;
+ }
+
+ return mat_gp;
+}
+
+/* Helper: Create new stroke section. */
+static void gpencil_add_new_points(bGPDstroke *gps,
+ float *coord_array,
+ float pressure,
+ int init,
+ int totpoints,
+ const float init_co[3],
+ bool last)
+{
+ for (int i = 0; i < totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i + init];
+ copy_v3_v3(&pt->x, &coord_array[3 * i]);
+ /* Be sure the last point is not on top of the first point of the curve or
+ * the close of the stroke will produce glitches. */
+ if ((last) && (i > 0) && (i == totpoints - 1)) {
+ float dist = len_v3v3(init_co, &pt->x);
+ if (dist < 0.1f) {
+ /* Interpolate between previous point and current to back slightly. */
+ bGPDspoint *pt_prev = &gps->points[i + init - 1];
+ interp_v3_v3v3(&pt->x, &pt_prev->x, &pt->x, 0.95f);
+ }
+ }
+
+ pt->pressure = pressure;
+ pt->strength = 1.0f;
+ }
+}
+
+/* Helper: Get the first collection that includes the object. */
+static Collection *gpencil_get_parent_collection(Scene *scene, Object *ob)
+{
+ Collection *mycol = NULL;
+ FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ if ((mycol == NULL) && (cob->ob == ob)) {
+ mycol = collection;
+ }
+ }
+ }
+ FOREACH_SCENE_COLLECTION_END;
+
+ return mycol;
+}
+
+/* Helper: Convert one spline to grease pencil stroke. */
+static void gpencil_convert_spline(Main *bmain,
+ Object *ob_gp,
+ Object *ob_cu,
+ const bool gpencil_lines,
+ const bool only_stroke,
+ bGPDframe *gpf,
+ Nurb *nu)
+{
+ Curve *cu = (Curve *)ob_cu->data;
+ bool cyclic = true;
+
+ /* Create Stroke. */
+ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
+ gps->thickness = 1.0f;
+ gps->gradient_f = 1.0f;
+ ARRAY_SET_ITEMS(gps->gradient_s, 1.0f, 1.0f);
+ ARRAY_SET_ITEMS(gps->caps, GP_STROKE_CAP_ROUND, GP_STROKE_CAP_ROUND);
+ gps->inittime = 0.0f;
+
+ /* Enable recalculation flag by default. */
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps->flag &= ~GP_STROKE_SELECT;
+ gps->flag |= GP_STROKE_3DSPACE;
+
+ gps->mat_nr = 0;
+ /* Count total points
+ * The total of points must consider that last point of each segment is equal to the first
+ * point of next segment.
+ */
+ int totpoints = 0;
+ int segments = 0;
+ int resolu = nu->resolu + 1;
+ segments = nu->pntsu;
+ if (((nu->flagu & CU_NURB_CYCLIC) == 0) || (nu->pntsu == 2)) {
+ segments--;
+ cyclic = false;
+ }
+ totpoints = (resolu * segments) - (segments - 1);
+
+ /* Initialize triangle memory to dummy data. */
+ gps->tot_triangles = 0;
+ gps->triangles = NULL;
+
+ /* Materials
+ * Notice: The color of the material is the color of viewport and not the final shader color.
+ */
+ Material *mat_gp = NULL;
+ bool fill = true;
+ /* Check if grease pencil has a material with same color.*/
+ float color[4];
+ if ((cu->mat) && (*cu->mat)) {
+ Material *mat_cu = *cu->mat;
+ copy_v4_v4(color, &mat_cu->r);
+ }
+ else {
+ /* Gray (unassigned from SVG add-on) */
+ zero_v4(color);
+ add_v3_fl(color, 0.6f);
+ color[3] = 1.0f;
+ fill = false;
+ }
+
+ /* Special case: If the color was created by the SVG add-on and the name contains '_stroke' and
+ * there is only one color, the stroke must not be closed, fill to false and use for
+ * stroke the fill color.
+ */
+ bool do_stroke = false;
+ if (ob_cu->totcol == 1) {
+ Material *ma_stroke = give_current_material(ob_cu, 1);
+ if ((ma_stroke) && (strstr(ma_stroke->id.name, "_stroke") != NULL)) {
+ do_stroke = true;
+ }
+ }
+
+ int r_idx = gpencil_check_same_material_color(ob_gp, color, &mat_gp);
+ if ((ob_cu->totcol > 0) && (r_idx < 0)) {
+ Material *mat_curve = give_current_material(ob_cu, 1);
+ mat_gp = gpencil_add_from_curve_material(bmain, ob_gp, color, gpencil_lines, fill, &r_idx);
+
+ if ((mat_curve) && (mat_curve->gp_style != NULL)) {
+ MaterialGPencilStyle *gp_style_cur = mat_curve->gp_style;
+ MaterialGPencilStyle *gp_style_gp = mat_gp->gp_style;
+
+ copy_v4_v4(gp_style_gp->mix_rgba, gp_style_cur->mix_rgba);
+ gp_style_gp->fill_style = gp_style_cur->fill_style;
+ gp_style_gp->mix_factor = gp_style_cur->mix_factor;
+ gp_style_gp->gradient_angle = gp_style_cur->gradient_angle;
+ }
+
+ /* If object has more than 1 material, use second material for stroke color. */
+ if ((!only_stroke) && (ob_cu->totcol > 1) && (give_current_material(ob_cu, 2))) {
+ mat_curve = give_current_material(ob_cu, 2);
+ if (mat_curve) {
+ linearrgb_to_srgb_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r);
+ mat_gp->gp_style->stroke_rgba[3] = mat_curve->a;
+ }
+ }
+ else if ((only_stroke) || (do_stroke)) {
+ /* Also use the first color if the fill is none for stroke color. */
+ if (ob_cu->totcol > 0) {
+ mat_curve = give_current_material(ob_cu, 1);
+ if (mat_curve) {
+ linearrgb_to_srgb_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r);
+ mat_gp->gp_style->stroke_rgba[3] = mat_curve->a;
+ /* Set fill and stroke depending of curve type (3D or 2D). */
+ if ((cu->flag & CU_3D) || ((cu->flag & (CU_FRONT | CU_BACK)) == 0)) {
+ mat_gp->gp_style->flag |= GP_STYLE_STROKE_SHOW;
+ mat_gp->gp_style->flag &= ~GP_STYLE_FILL_SHOW;
+ }
+ else {
+ mat_gp->gp_style->flag &= ~GP_STYLE_STROKE_SHOW;
+ mat_gp->gp_style->flag |= GP_STYLE_FILL_SHOW;
+ }
+ }
+ }
+ }
+ }
+ CLAMP_MIN(r_idx, 0);
+
+ /* Assign material index to stroke. */
+ gps->mat_nr = r_idx;
+
+ /* Add stroke to frame.*/
+ BLI_addtail(&gpf->strokes, gps);
+
+ float *coord_array = NULL;
+ float init_co[3];
+
+ switch (nu->type) {
+ case CU_POLY: {
+ /* Allocate memory for storage points. */
+ gps->totpoints = nu->pntsu;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ /* Increase thickness for this type. */
+ gps->thickness = 10.0f;
+
+ /* Get all curve points */
+ for (int s = 0; s < gps->totpoints; s++) {
+ BPoint *bp = &nu->bp[s];
+ bGPDspoint *pt = &gps->points[s];
+ copy_v3_v3(&pt->x, bp->vec);
+ pt->pressure = bp->radius;
+ pt->strength = 1.0f;
+ }
+ break;
+ }
+ case CU_BEZIER: {
+ /* Allocate memory for storage points. */
+ gps->totpoints = totpoints;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+
+ int init = 0;
+ resolu = nu->resolu + 1;
+ segments = nu->pntsu;
+ if (((nu->flagu & CU_NURB_CYCLIC) == 0) || (nu->pntsu == 2)) {
+ segments--;
+ }
+ /* Get all interpolated curve points of Beziert */
+ for (int s = 0; s < segments; s++) {
+ int inext = (s + 1) % nu->pntsu;
+ BezTriple *prevbezt = &nu->bezt[s];
+ BezTriple *bezt = &nu->bezt[inext];
+ bool last = (bool)(s == segments - 1);
+
+ coord_array = MEM_callocN((size_t)3 * resolu * sizeof(float), __func__);
+
+ for (int j = 0; j < 3; j++) {
+ BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
+ prevbezt->vec[2][j],
+ bezt->vec[0][j],
+ bezt->vec[1][j],
+ coord_array + j,
+ resolu - 1,
+ 3 * sizeof(float));
+ }
+ /* Save first point coordinates. */
+ if (s == 0) {
+ copy_v3_v3(init_co, &coord_array[0]);
+ }
+ /* Add points to the stroke */
+ gpencil_add_new_points(gps, coord_array, bezt->radius, init, resolu, init_co, last);
+ /* Free memory. */
+ MEM_SAFE_FREE(coord_array);
+
+ /* As the last point of segment is the first point of next segment, back one array
+ * element to avoid duplicated points on the same location.
+ */
+ init += resolu - 1;
+ }
+ break;
+ }
+ case CU_NURBS: {
+ if (nu->pntsv == 1) {
+
+ int nurb_points;
+ if (nu->flagu & CU_NURB_CYCLIC) {
+ resolu++;
+ nurb_points = nu->pntsu * resolu;
+ }
+ else {
+ nurb_points = (nu->pntsu - 1) * resolu;
+ }
+ /* Get all curve points. */
+ coord_array = MEM_callocN(sizeof(float[3]) * nurb_points, __func__);
+ BKE_nurb_makeCurve(nu, coord_array, NULL, NULL, NULL, resolu, sizeof(float[3]));
+
+ /* Allocate memory for storage points. */
+ gps->totpoints = nurb_points - 1;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+
+ /* Add points. */
+ gpencil_add_new_points(gps, coord_array, 1.0f, 0, gps->totpoints, init_co, false);
+
+ MEM_SAFE_FREE(coord_array);
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ /* Cyclic curve, close stroke. */
+ if ((cyclic) && (!do_stroke)) {
+ BKE_gpencil_close_stroke(gps);
+ }
+}
+
+/* Convert a curve object to grease pencil stroke.
+ *
+ * \param bmain: Main thread pointer
+ * \param scene: Original scene.
+ * \param ob_gp: Grease pencil object to add strokes.
+ * \param ob_cu: Curve to convert.
+ * \param gpencil_lines: Use lines for strokes.
+ * \param use_collections: Create layers using collection names.
+ * \param only_stroke: The material must be only stroke without fill.
+ */
+void BKE_gpencil_convert_curve(Main *bmain,
+ Scene *scene,
+ Object *ob_gp,
+ Object *ob_cu,
+ const bool gpencil_lines,
+ const bool use_collections,
+ const bool only_stroke)
+{
+ if (ELEM(NULL, ob_gp, ob_cu) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == NULL)) {
+ return;
+ }
+
+ Curve *cu = (Curve *)ob_cu->data;
+ bGPdata *gpd = (bGPdata *)ob_gp->data;
+ bGPDlayer *gpl = NULL;
+
+ /* If the curve is empty, cancel. */
+ if (cu->nurb.first == NULL) {
+ return;
+ }
+
+ /* Check if there is an active layer. */
+ if (use_collections) {
+ Collection *collection = gpencil_get_parent_collection(scene, ob_cu);
+ if (collection != NULL) {
+ gpl = BLI_findstring(&gpd->layers, collection->id.name + 2, offsetof(bGPDlayer, info));
+ if (gpl == NULL) {
+ gpl = BKE_gpencil_layer_addnew(gpd, collection->id.name + 2, true);
+ }
+ }
+ }
+
+ if (gpl == NULL) {
+ gpl = BKE_gpencil_layer_getactive(gpd);
+ if (gpl == NULL) {
+ gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
+ }
+ }
+
+ /* Check if there is an active frame and add if needed. */
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+
+ /* Read all splines of the curve and create a stroke for each. */
+ for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) {
+ gpencil_convert_spline(bmain, ob_gp, ob_cu, gpencil_lines, only_stroke, gpf, nu);
+ }
+
+ /* Tag for recalculation */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+}
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index daa63515c3d..fe087256d25 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -340,6 +340,23 @@ bool BKE_gpencil_has_time_modifiers(Object *ob)
return false;
}
+/* Check if exist transform stroke modifiers (to rotate sculpt or edit). */
+bool BKE_gpencil_has_transform_modifiers(Object *ob)
+{
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ /* Only if enabled in edit mode. */
+ if (!GPENCIL_MODIFIER_EDIT(md, true) && GPENCIL_MODIFIER_ACTIVE(md, false)) {
+ if ((md->type == eGpencilModifierType_Armature) || (md->type == eGpencilModifierType_Hook) ||
+ (md->type == eGpencilModifierType_Lattice) ||
+ (md->type == eGpencilModifierType_Offset)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
/* apply stroke modifiers */
void BKE_gpencil_stroke_modifiers(Depsgraph *depsgraph,
Object *ob,
@@ -797,8 +814,10 @@ static void gpencil_frame_copy_noalloc(Object *ob, bGPDframe *gpf, bGPDframe *gp
/* copy color to temp fields to apply temporal changes in the stroke */
MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps_src->mat_nr + 1);
- copy_v4_v4(gps_dst->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
- copy_v4_v4(gps_dst->runtime.tmp_fill_rgba, gp_style->fill_rgba);
+ if (gp_style) {
+ copy_v4_v4(gps_dst->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
+ copy_v4_v4(gps_dst->runtime.tmp_fill_rgba, gp_style->fill_rgba);
+ }
/* Save original pointers for using in edit and select operators. */
gps_dst->runtime.gps_orig = gps_src;
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index 8a5a36481cf..90dba4bc737 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -224,7 +224,7 @@ static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
prv_img->tag |= PRV_TAG_DEFFERED;
}
- for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ for (i = 0; i < NUM_ICON_SIZES; i++) {
prv_img->flag[i] |= PRV_CHANGED;
prv_img->changed_timestamp[i] = 0;
}
@@ -242,7 +242,7 @@ void BKE_previewimg_freefunc(void *link)
if (prv) {
int i;
- for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ for (i = 0; i < NUM_ICON_SIZES; i++) {
if (prv->rect[i]) {
MEM_freeN(prv->rect[i]);
}
@@ -278,7 +278,7 @@ void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size)
void BKE_previewimg_clear(struct PreviewImage *prv)
{
int i;
- for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ for (i = 0; i < NUM_ICON_SIZES; i++) {
BKE_previewimg_clear_single(prv, i);
}
}
@@ -290,7 +290,7 @@ PreviewImage *BKE_previewimg_copy(const PreviewImage *prv)
if (prv) {
prv_img = MEM_dupallocN(prv);
- for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ for (i = 0; i < NUM_ICON_SIZES; i++) {
if (prv->rect[i]) {
prv_img->rect[i] = MEM_dupallocN(prv->rect[i]);
}
@@ -545,7 +545,7 @@ void BKE_icon_changed(const int icon_id)
/* If we have previews, they all are now invalid changed. */
if (p_prv && *p_prv) {
int i;
- for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ for (i = 0; i < NUM_ICON_SIZES; i++) {
(*p_prv)->flag[i] |= PRV_CHANGED;
(*p_prv)->changed_timestamp[i]++;
}
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index a99407b9bf9..bc682ffb8c8 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -55,6 +55,9 @@
#include "DNA_brush_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_light_types.h"
+#include "DNA_world_types.h"
+#include "DNA_defaults.h"
#include "BLI_blenlib.h"
#include "BLI_math_vector.h"
@@ -294,12 +297,9 @@ static void image_init(Image *ima, short source, short type)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(ima, id));
- ima->ok = IMA_OK;
+ MEMCPY_STRUCT_AFTER(ima, DNA_struct_default_get(Image), id);
- ima->aspx = ima->aspy = 1.0;
- ima->gen_x = 1024;
- ima->gen_y = 1024;
- ima->gen_type = IMA_GENTYPE_GRID;
+ ima->ok = IMA_OK;
ima->source = source;
ima->type = type;
@@ -316,8 +316,6 @@ static void image_init(Image *ima, short source, short type)
BKE_color_managed_colorspace_settings_init(&ima->colorspace_settings);
ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo Format");
-
- ima->gpuframenr = INT_MAX;
}
void BKE_image_init(struct Image *image)
@@ -1863,13 +1861,13 @@ static void stampdata(
}
}
-/* Will always add prefix. */
static void stampdata_from_template(StampData *stamp_data,
const Scene *scene,
- const StampData *stamp_data_template)
+ const StampData *stamp_data_template,
+ bool do_prefix)
{
if (scene->r.stamp & R_STAMP_FILENAME) {
- SNPRINTF(stamp_data->file, "File %s", stamp_data_template->file);
+ SNPRINTF(stamp_data->file, do_prefix ? "File %s" : "%s", stamp_data_template->file);
}
else {
stamp_data->file[0] = '\0';
@@ -1881,67 +1879,71 @@ static void stampdata_from_template(StampData *stamp_data,
stamp_data->note[0] = '\0';
}
if (scene->r.stamp & R_STAMP_DATE) {
- SNPRINTF(stamp_data->date, "Date %s", stamp_data_template->date);
+ SNPRINTF(stamp_data->date, do_prefix ? "Date %s" : "%s", stamp_data_template->date);
}
else {
stamp_data->date[0] = '\0';
}
if (scene->r.stamp & R_STAMP_MARKER) {
- SNPRINTF(stamp_data->marker, "Marker %s", stamp_data_template->marker);
+ SNPRINTF(stamp_data->marker, do_prefix ? "Marker %s" : "%s", stamp_data_template->marker);
}
else {
stamp_data->marker[0] = '\0';
}
if (scene->r.stamp & R_STAMP_TIME) {
- SNPRINTF(stamp_data->time, "Timecode %s", stamp_data_template->time);
+ SNPRINTF(stamp_data->time, do_prefix ? "Timecode %s" : "%s", stamp_data_template->time);
}
else {
stamp_data->time[0] = '\0';
}
if (scene->r.stamp & R_STAMP_FRAME) {
- SNPRINTF(stamp_data->frame, "Frame %s", stamp_data_template->frame);
+ SNPRINTF(stamp_data->frame, do_prefix ? "Frame %s" : "%s", stamp_data_template->frame);
}
else {
stamp_data->frame[0] = '\0';
}
if (scene->r.stamp & R_STAMP_CAMERA) {
- SNPRINTF(stamp_data->camera, "Camera %s", stamp_data_template->camera);
+ SNPRINTF(stamp_data->camera, do_prefix ? "Camera %s" : "%s", stamp_data_template->camera);
}
else {
stamp_data->camera[0] = '\0';
}
if (scene->r.stamp & R_STAMP_CAMERALENS) {
- SNPRINTF(stamp_data->cameralens, "Lens %s", stamp_data_template->cameralens);
+ SNPRINTF(
+ stamp_data->cameralens, do_prefix ? "Lens %s" : "%s", stamp_data_template->cameralens);
}
else {
stamp_data->cameralens[0] = '\0';
}
if (scene->r.stamp & R_STAMP_SCENE) {
- SNPRINTF(stamp_data->scene, "Scene %s", stamp_data_template->scene);
+ SNPRINTF(stamp_data->scene, do_prefix ? "Scene %s" : "%s", stamp_data_template->scene);
}
else {
stamp_data->scene[0] = '\0';
}
if (scene->r.stamp & R_STAMP_SEQSTRIP) {
- SNPRINTF(stamp_data->strip, "Strip %s", stamp_data_template->strip);
+ SNPRINTF(stamp_data->strip, do_prefix ? "Strip %s" : "%s", stamp_data_template->strip);
}
else {
stamp_data->strip[0] = '\0';
}
if (scene->r.stamp & R_STAMP_RENDERTIME) {
- SNPRINTF(stamp_data->rendertime, "RenderTime %s", stamp_data_template->rendertime);
+ SNPRINTF(stamp_data->rendertime,
+ do_prefix ? "RenderTime %s" : "%s",
+ stamp_data_template->rendertime);
}
else {
stamp_data->rendertime[0] = '\0';
}
if (scene->r.stamp & R_STAMP_MEMORY) {
- SNPRINTF(stamp_data->memory, "Peak Memory %s", stamp_data_template->memory);
+ SNPRINTF(stamp_data->memory, do_prefix ? "Peak Memory %s" : "%s", stamp_data_template->memory);
}
else {
stamp_data->memory[0] = '\0';
}
if (scene->r.stamp & R_STAMP_HOSTNAME) {
- SNPRINTF(stamp_data->hostname, "Hostname %s", stamp_data_template->hostname);
+ SNPRINTF(
+ stamp_data->hostname, do_prefix ? "Hostname %s" : "%s", stamp_data_template->hostname);
}
else {
stamp_data->hostname[0] = '\0';
@@ -1993,11 +1995,12 @@ void BKE_image_stamp_buf(Scene *scene,
display_device = scene->display_settings.display_device;
display = IMB_colormanagement_display_get_named(display_device);
+ bool do_prefix = (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0;
if (stamp_data_template == NULL) {
- stampdata(scene, camera, &stamp_data, (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0, true);
+ stampdata(scene, camera, &stamp_data, do_prefix, true);
}
else {
- stampdata_from_template(&stamp_data, scene, stamp_data_template);
+ stampdata_from_template(&stamp_data, scene, stamp_data_template, do_prefix);
}
/* TODO, do_versions */
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index e46b7ca5130..72b531c446a 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -41,6 +41,7 @@
#include "DNA_lattice_types.h"
#include "DNA_curve_types.h"
#include "DNA_key_types.h"
+#include "DNA_defaults.h"
#include "BKE_animsys.h"
#include "BKE_anim.h"
@@ -248,13 +249,10 @@ void BKE_lattice_init(Lattice *lt)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(lt, id));
- lt->flag = LT_GRID;
-
- lt->typeu = lt->typev = lt->typew = KEY_BSPLINE;
+ MEMCPY_STRUCT_AFTER(lt, DNA_struct_default_get(Lattice), id);
lt->def = MEM_callocN(sizeof(BPoint), "lattvert"); /* temporary */
BKE_lattice_resize(lt, 2, 2, 2, NULL); /* creates a uniform lattice */
- lt->actbp = LT_ACTBP_NONE;
}
Lattice *BKE_lattice_add(Main *bmain, const char *name)
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index de105b9b62a..9b18052ef1e 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -32,6 +32,7 @@
#include "BKE_freestyle.h"
#include "BKE_idprop.h"
#include "BKE_layer.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_object.h"
@@ -68,6 +69,7 @@ static LayerCollection *layer_collection_add(ListBase *lb_parent, Collection *co
{
LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base");
lc->collection = collection;
+ lc->local_collections_bits = ~(0);
BLI_addtail(lb_parent, lc);
return lc;
@@ -90,6 +92,7 @@ static Base *object_base_new(Object *ob)
{
Base *base = MEM_callocN(sizeof(Base), "Object Base");
base->object = ob;
+ base->local_view_bits = ~(0);
if (ob->base_flag & BASE_SELECTED) {
base->flag |= BASE_SELECTED;
}
@@ -651,7 +654,8 @@ static short layer_collection_sync(ViewLayer *view_layer,
ListBase *new_object_bases,
short parent_exclude,
short parent_restrict,
- short parent_layer_restrict)
+ short parent_layer_restrict,
+ unsigned short parent_local_collections_bits)
{
/* TODO: support recovery after removal of intermediate collections, reordering, ..
* For local edits we can make editing operating do the appropriate thing, but for
@@ -697,6 +701,13 @@ static short layer_collection_sync(ViewLayer *view_layer,
lc->flag = parent_exclude;
}
+ unsigned short local_collections_bits = parent_local_collections_bits &
+ lc->local_collections_bits;
+
+ /* Tag linked collection as a weak reference so we keep the layer
+ * collection pointer on file load and remember exclude state. */
+ id_lib_indirect_weak_link(&collection->id);
+
/* Collection restrict is inherited. */
short child_restrict = parent_restrict;
short child_layer_restrict = parent_layer_restrict;
@@ -712,7 +723,8 @@ static short layer_collection_sync(ViewLayer *view_layer,
new_object_bases,
lc->flag,
child_restrict,
- child_layer_restrict);
+ child_layer_restrict,
+ local_collections_bits);
/* Layer collection exclude is not inherited. */
if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
@@ -734,6 +746,10 @@ static short layer_collection_sync(ViewLayer *view_layer,
continue;
}
+ /* Tag linked object as a weak reference so we keep the object
+ * base pointer on file load and remember hidden state. */
+ id_lib_indirect_weak_link(&cob->ob->id);
+
void **base_p;
Base *base;
if (BLI_ghash_ensure_p(view_layer->object_bases_hash, cob->ob, &base_p)) {
@@ -749,6 +765,7 @@ static short layer_collection_sync(ViewLayer *view_layer,
else {
/* Create new base. */
base = object_base_new(cob->ob);
+ base->local_collections_bits = local_collections_bits;
*base_p = base;
BLI_addtail(new_object_bases, base);
}
@@ -826,7 +843,8 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
&new_object_bases,
parent_exclude,
parent_restrict,
- parent_layer_restrict);
+ parent_layer_restrict,
+ ~(0));
/* Any remaining object bases are to be removed. */
for (Base *base = view_layer->object_bases.first; base; base = base->next) {
@@ -1083,6 +1101,119 @@ void BKE_layer_collection_isolate(Scene *scene,
BKE_layer_collection_sync(scene, view_layer);
}
+static void layer_collection_local_visibility_set_recursive(LayerCollection *layer_collection,
+ const int local_collections_uuid)
+{
+ layer_collection->local_collections_bits |= local_collections_uuid;
+ for (LayerCollection *child = layer_collection->layer_collections.first; child;
+ child = child->next) {
+ layer_collection_local_visibility_set_recursive(child, local_collections_uuid);
+ }
+}
+
+static void layer_collection_local_visibility_unset_recursive(LayerCollection *layer_collection,
+ const int local_collections_uuid)
+{
+ layer_collection->local_collections_bits &= ~local_collections_uuid;
+ for (LayerCollection *child = layer_collection->layer_collections.first; child;
+ child = child->next) {
+ layer_collection_local_visibility_unset_recursive(child, local_collections_uuid);
+ }
+}
+
+static void layer_collection_local_sync(ViewLayer *view_layer,
+ LayerCollection *layer_collection,
+ const unsigned short local_collections_uuid,
+ bool visible)
+{
+ if ((layer_collection->local_collections_bits & local_collections_uuid) == 0) {
+ visible = false;
+ }
+
+ if (visible) {
+ for (CollectionObject *cob = layer_collection->collection->gobject.first; cob;
+ cob = cob->next) {
+ BLI_assert(cob->ob);
+ Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
+ base->local_collections_bits |= local_collections_uuid;
+ }
+ }
+
+ LISTBASE_FOREACH (LayerCollection *, child, &layer_collection->layer_collections) {
+ if ((child->flag & LAYER_COLLECTION_EXCLUDE) == 0) {
+ layer_collection_local_sync(view_layer, child, local_collections_uuid, visible);
+ }
+ }
+}
+
+void BKE_layer_collection_local_sync(ViewLayer *view_layer, View3D *v3d)
+{
+ const unsigned short local_collections_uuid = v3d->local_collections_uuid;
+
+ /* Reset flags and set the bases visible by default. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ base->local_collections_bits &= ~local_collections_uuid;
+ }
+
+ LISTBASE_FOREACH (LayerCollection *, layer_collection, &view_layer->layer_collections) {
+ layer_collection_local_sync(view_layer, layer_collection, local_collections_uuid, true);
+ }
+}
+
+/**
+ * Isolate the collection locally
+ *
+ * Same as BKE_layer_collection_local_isolate but for a viewport
+ */
+void BKE_layer_collection_local_isolate(ViewLayer *view_layer,
+ View3D *v3d,
+ LayerCollection *lc,
+ bool extend)
+{
+ LayerCollection *lc_master = view_layer->layer_collections.first;
+ bool hide_it = extend && ((v3d->local_collections_uuid & lc->local_collections_bits) != 0);
+
+ if (!extend) {
+ /* Hide all collections. */
+ for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter;
+ lc_iter = lc_iter->next) {
+ layer_collection_local_visibility_unset_recursive(lc_iter, v3d->local_collections_uuid);
+ }
+ }
+
+ /* Make all the direct parents visible. */
+ if (hide_it) {
+ lc->local_collections_bits &= ~(v3d->local_collections_uuid);
+ }
+ else {
+ LayerCollection *lc_parent = lc;
+ for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter;
+ lc_iter = lc_iter->next) {
+ if (BKE_layer_collection_has_layer_collection(lc_iter, lc)) {
+ lc_parent = lc_iter;
+ break;
+ }
+ }
+
+ while (lc_parent != lc) {
+ lc_parent->local_collections_bits |= v3d->local_collections_uuid;
+
+ for (LayerCollection *lc_iter = lc_parent->layer_collections.first; lc_iter;
+ lc_iter = lc_iter->next) {
+ if (BKE_layer_collection_has_layer_collection(lc_iter, lc)) {
+ lc_parent = lc_iter;
+ break;
+ }
+ }
+ }
+
+ /* Make all the children visible. */
+ layer_collection_local_visibility_set_recursive(lc, v3d->local_collections_uuid);
+ }
+
+ BKE_layer_collection_local_sync(view_layer, v3d);
+}
+
static void layer_collection_bases_show_recursive(ViewLayer *view_layer, LayerCollection *lc)
{
if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) {
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 2dbca3b4db1..468d0e97ece 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -165,12 +165,23 @@ void id_lib_extern(ID *id)
BLI_assert(BKE_idcode_is_linkable(GS(id->name)));
if (id->tag & LIB_TAG_INDIRECT) {
id->tag &= ~LIB_TAG_INDIRECT;
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
id->tag |= LIB_TAG_EXTERN;
id->lib->parent = NULL;
}
}
}
+void id_lib_indirect_weak_link(ID *id)
+{
+ if (id && ID_IS_LINKED(id)) {
+ BLI_assert(BKE_idcode_is_linkable(GS(id->name)));
+ if (id->tag & LIB_TAG_INDIRECT) {
+ id->flag |= LIB_INDIRECT_WEAK_LINK;
+ }
+ }
+}
+
/**
* Ensure we have a real user
*
@@ -851,8 +862,8 @@ void BKE_id_swap(Main *bmain, ID *id_a, ID *id_b)
id_b->properties = id_a_back.properties;
/* Swap will have broken internal references to itself, restore them. */
- BKE_libblock_relink_ex(bmain, id_a, id_b, id_a, false);
- BKE_libblock_relink_ex(bmain, id_b, id_a, id_b, false);
+ BKE_libblock_relink_ex(bmain, id_a, id_b, id_a, ID_REMAP_SKIP_NEVER_NULL_USAGE);
+ BKE_libblock_relink_ex(bmain, id_b, id_a, id_b, ID_REMAP_SKIP_NEVER_NULL_USAGE);
}
/** Does *not* set ID->newid pointer. */
@@ -1264,15 +1275,14 @@ void BKE_libblock_init_empty(ID *id)
break;
case ID_OB: {
Object *ob = (Object *)id;
- ob->type = OB_EMPTY;
- BKE_object_init(ob);
+ BKE_object_init(ob, OB_EMPTY);
break;
}
case ID_ME:
BKE_mesh_init((Mesh *)id);
break;
case ID_CU:
- BKE_curve_init((Curve *)id);
+ BKE_curve_init((Curve *)id, 0);
break;
case ID_MB:
BKE_mball_init((MetaBall *)id);
@@ -1408,21 +1418,32 @@ void *BKE_id_new_nomain(const short type, const char *name)
return id;
}
-void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
+void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int orig_flag)
{
ID *new_id = *r_newid;
+ int flag = orig_flag;
- /* Grrrrrrrrr... Not adding 'root' nodetrees to bmain.... grrrrrrrrrrrrrrrrrrrr! */
- /* This is taken from original ntree copy code, might be weak actually? */
- const bool use_nodetree_alloc_exception = ((GS(id->name) == ID_NT) && (bmain != NULL) &&
- (BLI_findindex(&bmain->nodetrees, id) < 0));
+ const bool is_private_id_data = (id->flag & LIB_PRIVATE_DATA) != 0;
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || bmain != NULL);
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || (flag & LIB_ID_CREATE_NO_ALLOCATE) == 0);
- BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 || (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) != 0);
+ if (!is_private_id_data) {
+ /* When we are handling private ID data, we might still want to manage usercounts, even though
+ * that ID data-block is actually outside of Main... */
+ BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 ||
+ (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) != 0);
+ }
/* Never implicitly copy shapekeys when generating temp data outside of Main database. */
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 || (flag & LIB_ID_COPY_SHAPEKEY) == 0);
+ /* 'Private ID' data handling. */
+ if ((bmain != NULL) && is_private_id_data) {
+ flag |= LIB_ID_CREATE_NO_MAIN;
+ }
+
+ /* The id->flag bits to copy over. */
+ const int copy_idflag_mask = LIB_PRIVATE_DATA;
+
if ((flag & LIB_ID_CREATE_NO_ALLOCATE) != 0) {
/* r_newid already contains pointer to allocated memory. */
/* TODO do we want to memset(0) whole mem before filling it? */
@@ -1432,10 +1453,7 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int fla
/* TODO Do we want/need to copy more from ID struct itself? */
}
else {
- new_id = BKE_libblock_alloc(bmain,
- GS(id->name),
- id->name + 2,
- flag | (use_nodetree_alloc_exception ? LIB_ID_CREATE_NO_MAIN : 0));
+ new_id = BKE_libblock_alloc(bmain, GS(id->name), id->name + 2, flag);
}
BLI_assert(new_id != NULL);
@@ -1448,6 +1466,8 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int fla
memcpy(cpn + id_offset, cp + id_offset, id_len - id_offset);
}
+ new_id->flag = (new_id->flag & ~copy_idflag_mask) | (id->flag & copy_idflag_mask);
+
if (id->properties) {
new_id->properties = IDP_CopyProperty_ex(id->properties, flag);
}
@@ -1466,8 +1486,12 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int fla
/* the duplicate should get a copy of the animdata */
if ((flag & LIB_ID_COPY_NO_ANIMDATA) == 0) {
- BLI_assert((flag & LIB_ID_COPY_ACTIONS) == 0 || (flag & LIB_ID_CREATE_NO_MAIN) == 0);
- iat->adt = BKE_animdata_copy(bmain, iat->adt, flag);
+ /* Note that even though horrors like root nodetrees are not in bmain, the actions they use
+ * in their anim data *are* in bmain... super-mega-hooray. */
+ int animdata_flag = orig_flag;
+ BLI_assert((animdata_flag & LIB_ID_COPY_ACTIONS) == 0 ||
+ (animdata_flag & LIB_ID_CREATE_NO_MAIN) == 0);
+ iat->adt = BKE_animdata_copy(bmain, iat->adt, animdata_flag);
}
else {
iat->adt = NULL;
@@ -1755,6 +1779,7 @@ void id_clear_lib_data_ex(Main *bmain, ID *id, const bool id_in_mainlist)
id->lib = NULL;
id->tag &= ~(LIB_TAG_INDIRECT | LIB_TAG_EXTERN);
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
if (id_in_mainlist) {
if (BKE_id_new_name_validate(which_libbase(bmain, GS(id->name)), id, NULL)) {
bmain->is_memfile_undo_written = false;
@@ -1968,6 +1993,7 @@ void BKE_library_make_local(Main *bmain,
if (id->lib == NULL) {
id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
}
/* The check on the fourth line (LIB_TAG_PRE_EXISTING) is done so it's possible to tag data
* you don't want to be made local, used for appending data,
diff --git a/source/blender/blenkernel/intern/library_override.c b/source/blender/blenkernel/intern/library_override.c
index ce368575492..4f10a5bca6b 100644
--- a/source/blender/blenkernel/intern/library_override.c
+++ b/source/blender/blenkernel/intern/library_override.c
@@ -57,7 +57,7 @@ static void bke_override_property_operation_clear(IDOverrideLibraryPropertyOpera
/* Temp, for until library override is ready and tested enough to go 'public',
* we hide it by default in UI and such. */
-static bool _override_library_enabled = false;
+static bool _override_library_enabled = true;
void BKE_override_library_enable(const bool do_enable)
{
@@ -111,11 +111,11 @@ void BKE_override_library_copy(ID *dst_id, const ID *src_id)
if (dst_id->override_library != NULL) {
if (src_id->override_library == NULL) {
- BKE_override_library_free(&dst_id->override_library);
+ BKE_override_library_free(&dst_id->override_library, true);
return;
}
else {
- BKE_override_library_clear(dst_id->override_library);
+ BKE_override_library_clear(dst_id->override_library, true);
}
}
else if (src_id->override_library == NULL) {
@@ -144,7 +144,7 @@ void BKE_override_library_copy(ID *dst_id, const ID *src_id)
}
/** Clear any overriding data from given \a override. */
-void BKE_override_library_clear(IDOverrideLibrary *override)
+void BKE_override_library_clear(IDOverrideLibrary *override, const bool do_id_user)
{
BLI_assert(override != NULL);
@@ -153,16 +153,18 @@ void BKE_override_library_clear(IDOverrideLibrary *override)
}
BLI_freelistN(&override->properties);
- id_us_min(override->reference);
- /* override->storage should never be refcounted... */
+ if (do_id_user) {
+ id_us_min(override->reference);
+ /* override->storage should never be refcounted... */
+ }
}
/** Free given \a override. */
-void BKE_override_library_free(struct IDOverrideLibrary **override)
+void BKE_override_library_free(struct IDOverrideLibrary **override, const bool do_id_user)
{
BLI_assert(*override != NULL);
- BKE_override_library_clear(*override);
+ BKE_override_library_clear(*override, do_id_user);
MEM_freeN(*override);
*override = NULL;
}
@@ -183,19 +185,28 @@ static ID *override_library_create_from(Main *bmain, ID *reference_id)
}
/** Create an overridden local copy of linked reference. */
-ID *BKE_override_library_create_from_id(Main *bmain, ID *reference_id)
+ID *BKE_override_library_create_from_id(Main *bmain, ID *reference_id, const bool do_tagged_remap)
{
BLI_assert(reference_id != NULL);
BLI_assert(reference_id->lib != NULL);
ID *local_id = override_library_create_from(bmain, reference_id);
- /* Remapping, we obviously only want to affect local data
- * (and not our own reference pointer to overridden ID). */
- BKE_libblock_remap(bmain,
- reference_id,
- local_id,
- ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY);
+ if (do_tagged_remap) {
+ ID *other_id;
+ FOREACH_MAIN_ID_BEGIN (bmain, other_id) {
+ if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib == NULL) {
+ /* Note that using ID_REMAP_SKIP_INDIRECT_USAGE below is superfluous, as we only remap
+ * local IDs usages anyway... */
+ BKE_libblock_relink_ex(bmain,
+ other_id,
+ reference_id,
+ local_id,
+ ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY);
+ }
+ }
+ FOREACH_MAIN_ID_END;
+ }
return local_id;
}
@@ -205,6 +216,11 @@ ID *BKE_override_library_create_from_id(Main *bmain, ID *reference_id)
* \note Set id->newid of overridden libs with newly created overrides,
* caller is responsible to clean those pointers before/after usage as needed.
*
+ * \note By default, it will only remap newly created local overriding data-blocks between
+ * themselves, to avoid 'enforcing' those overrides into all other usages of the linked data in
+ * main. You can add more local IDs to be remapped to use new overriding ones by setting their
+ * LIB_TAG_DOIT tag.
+ *
* \return \a true on success, \a false otherwise.
*/
bool BKE_override_library_create_from_tag(Main *bmain)
@@ -212,26 +228,59 @@ bool BKE_override_library_create_from_tag(Main *bmain)
ID *reference_id;
bool ret = true;
+ ListBase todo_ids = {NULL};
+ LinkData *todo_id_iter;
+
+ /* Get all IDs we want to override. */
FOREACH_MAIN_ID_BEGIN (bmain, reference_id) {
if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL) {
- if ((reference_id->newid = override_library_create_from(bmain, reference_id)) == NULL) {
- ret = false;
- }
+ todo_id_iter = MEM_callocN(sizeof(*todo_id_iter), __func__);
+ todo_id_iter->data = reference_id;
+ BLI_addtail(&todo_ids, todo_id_iter);
}
}
FOREACH_MAIN_ID_END;
- FOREACH_MAIN_ID_BEGIN (bmain, reference_id) {
- if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL &&
- reference_id->newid != NULL) {
- ID *local_id = reference_id->newid;
- BKE_libblock_remap(bmain,
- reference_id,
- local_id,
- ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY);
+ /* Override the IDs. */
+ for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) {
+ reference_id = todo_id_iter->data;
+ if ((reference_id->newid = override_library_create_from(bmain, reference_id)) == NULL) {
+ ret = false;
+ }
+ else {
+ /* We also tag the new IDs so that in next step we can remap their pointers too. */
+ reference_id->newid->tag |= LIB_TAG_DOIT;
}
}
- FOREACH_MAIN_ID_END;
+
+ /* Only remap new local ID's pointers, we don't want to force our new overrides onto our whole
+ * existing linked IDs usages. */
+ for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) {
+ ID *other_id;
+ reference_id = todo_id_iter->data;
+
+ if (reference_id->newid == NULL) {
+ continue;
+ }
+
+ /* Still checking the whole Main, that way we can tag other local IDs as needing to be remapped
+ * to use newly created overriding IDs, if needed. */
+ FOREACH_MAIN_ID_BEGIN (bmain, other_id) {
+ if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib == NULL) {
+ ID *local_id = reference_id->newid;
+ /* Note that using ID_REMAP_SKIP_INDIRECT_USAGE below is superfluous, as we only remap
+ * local IDs usages anyway... */
+ BKE_libblock_relink_ex(bmain,
+ other_id,
+ reference_id,
+ local_id,
+ ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY);
+ }
+ }
+ FOREACH_MAIN_ID_END;
+ }
+
+ BLI_freelistN(&todo_ids);
return ret;
}
@@ -592,6 +641,13 @@ bool BKE_override_library_operations_create(Main *bmain, ID *local, const bool f
bool ret = false;
if (!is_template && (force_auto || local->override_library->flag & OVERRIDE_LIBRARY_AUTO)) {
+ /* Do not attempt to generate overriding rules from an empty place-holder generated by link
+ * code when it cannot find to actual library/ID. Much better to keep the local datablock as
+ * is in the file in that case, until broken lib is fixed. */
+ if (ID_MISSING(local->override_library->reference)) {
+ return ret;
+ }
+
PointerRNA rnaptr_local, rnaptr_reference;
RNA_id_pointer_create(local, &rnaptr_local);
RNA_id_pointer_create(local->override_library->reference, &rnaptr_reference);
@@ -644,6 +700,13 @@ void BKE_override_library_update(Main *bmain, ID *local)
return;
}
+ /* Do not attempt to apply overriding rules over an empty place-holder generated by link code
+ * when it cannot find to actual library/ID. Much better to keep the local datablock as loaded
+ * from the file in that case, until broken lib is fixed. */
+ if (ID_MISSING(local->override_library->reference)) {
+ return;
+ }
+
/* Recursively do 'ancestors' overrides first, if any. */
if (local->override_library->reference->override_library &&
(local->override_library->reference->tag & LIB_TAG_OVERRIDE_LIBRARY_REFOK) == 0) {
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index 8fe2552c03f..45dbb4b6ec1 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -389,7 +389,7 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *o
if (ob->data == new_id) {
switch (GS(new_id->name)) {
case ID_ME:
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
break;
case ID_CU:
BKE_curve_type_test(ob);
@@ -497,6 +497,7 @@ static void libblock_remap_data(
if (new_id && (new_id->tag & LIB_TAG_INDIRECT) &&
(r_id_remap_data->status & ID_REMAP_IS_LINKED_DIRECT)) {
new_id->tag &= ~LIB_TAG_INDIRECT;
+ new_id->flag &= ~LIB_INDIRECT_WEAK_LINK;
new_id->tag |= LIB_TAG_EXTERN;
}
@@ -652,12 +653,11 @@ void BKE_libblock_unlink(Main *bmain,
* ... sigh
*/
void BKE_libblock_relink_ex(
- Main *bmain, void *idv, void *old_idv, void *new_idv, const bool us_min_never_null)
+ Main *bmain, void *idv, void *old_idv, void *new_idv, const short remap_flags)
{
ID *id = idv;
ID *old_id = old_idv;
ID *new_id = new_idv;
- int remap_flags = us_min_never_null ? 0 : ID_REMAP_SKIP_NEVER_NULL_USAGE;
/* No need to lock here, we are only affecting given ID, not bmain database. */
@@ -757,7 +757,7 @@ void BKE_libblock_free_data(ID *id, const bool do_id_user)
}
if (id->override_library) {
- BKE_override_library_free(&id->override_library);
+ BKE_override_library_free(&id->override_library, do_id_user);
}
/* XXX TODO remove animdata handling from each type's freeing func,
@@ -945,7 +945,7 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
#endif
if ((flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0) {
- BKE_libblock_relink_ex(bmain, id, NULL, NULL, true);
+ BKE_libblock_relink_ex(bmain, id, NULL, NULL, 0);
}
BKE_libblock_free_datablock(id, flag);
@@ -1091,7 +1091,7 @@ static void id_delete(Main *bmain, const bool do_tagged_deletion)
bmain, id, NULL, ID_REMAP_FLAG_NEVER_NULL_USAGE | ID_REMAP_FORCE_NEVER_NULL_USAGE);
/* 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, true);
+ BKE_libblock_relink_ex(bmain, id, NULL, NULL, 0);
/* Now we can safely mark that ID as not being in Main database anymore. */
id->tag |= LIB_TAG_NO_MAIN;
/* This is needed because we may not have remapped usages
diff --git a/source/blender/blenkernel/intern/light.c b/source/blender/blenkernel/intern/light.c
index 75c9e0e42a5..ea728f61733 100644
--- a/source/blender/blenkernel/intern/light.c
+++ b/source/blender/blenkernel/intern/light.c
@@ -32,6 +32,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_texture_types.h"
+#include "DNA_defaults.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -48,40 +49,9 @@ void BKE_light_init(Light *la)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(la, id));
- la->r = la->g = la->b = la->k = 1.0f;
- la->energy = 10.0f;
- la->dist = 25.0f;
- la->spotsize = DEG2RADF(45.0f);
- la->spotblend = 0.15f;
- la->att2 = 1.0f;
- la->mode = LA_SHADOW;
- la->bufsize = 512;
- la->clipsta = 0.05f;
- la->clipend = 40.0f;
- la->bleedexp = 2.5f;
- la->samp = 3;
- la->bias = 1.0f;
- la->soft = 3.0f;
- la->area_size = la->area_sizey = la->area_sizez = 0.25f;
- la->buffers = 1;
- la->preview = NULL;
- la->falloff_type = LA_FALLOFF_INVSQUARE;
- la->coeff_const = 1.0f;
- la->coeff_lin = 0.0f;
- la->coeff_quad = 0.0f;
- la->curfalloff = BKE_curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f);
- la->cascade_max_dist = 200.0f;
- la->cascade_count = 4;
- la->cascade_exponent = 0.8f;
- la->cascade_fade = 0.1f;
- la->contact_dist = 0.2f;
- la->contact_bias = 0.03f;
- la->contact_spread = 0.2f;
- la->contact_thickness = 0.2f;
- la->spec_fac = 1.0f;
- la->att_dist = 40.0f;
- la->sun_angle = DEG2RADF(0.526f);
+ MEMCPY_STRUCT_AFTER(la, DNA_struct_default_get(Light), id);
+ la->curfalloff = BKE_curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f);
BKE_curvemapping_initialize(la->curfalloff);
}
@@ -108,12 +78,13 @@ Light *BKE_light_add(Main *bmain, const char *name)
*/
void BKE_light_copy_data(Main *bmain, Light *la_dst, const Light *la_src, const int flag)
{
+ /* We always need allocation of our private ID data. */
+ const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
+
la_dst->curfalloff = BKE_curvemapping_copy(la_src->curfalloff);
if (la_src->nodetree) {
- /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
- * (see BKE_libblock_copy_ex()). */
- BKE_id_copy_ex(bmain, (ID *)la_src->nodetree, (ID **)&la_dst->nodetree, flag);
+ BKE_id_copy_ex(bmain, (ID *)la_src->nodetree, (ID **)&la_dst->nodetree, flag_private_id_data);
}
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c
index 1c2f8d22f3e..06f1ee5050b 100644
--- a/source/blender/blenkernel/intern/lightprobe.c
+++ b/source/blender/blenkernel/intern/lightprobe.c
@@ -21,8 +21,11 @@
* \ingroup bke
*/
+#include <string.h>
+
#include "DNA_object_types.h"
#include "DNA_lightprobe_types.h"
+#include "DNA_defaults.h"
#include "BLI_utildefines.h"
@@ -35,17 +38,7 @@ void BKE_lightprobe_init(LightProbe *probe)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(probe, id));
- probe->grid_resolution_x = probe->grid_resolution_y = probe->grid_resolution_z = 4;
- probe->distinf = 2.5f;
- probe->distpar = 2.5f;
- probe->falloff = 0.2f;
- probe->clipsta = 0.8f;
- probe->clipend = 40.0f;
- probe->vis_bias = 1.0f;
- probe->vis_blur = 0.2f;
- probe->intensity = 1.0f;
-
- probe->flag = LIGHTPROBE_FLAG_SHOW_INFLUENCE;
+ MEMCPY_STRUCT_AFTER(probe, DNA_struct_default_get(LightProbe), id);
}
void *BKE_lightprobe_add(Main *bmain, const char *name)
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index 7bfe5a7c8ff..3efc493b43e 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -30,6 +30,7 @@
#include "DNA_object_types.h"
#include "DNA_material_types.h" /* for ramp blend */
#include "DNA_texture_types.h"
+#include "DNA_defaults.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
@@ -76,34 +77,9 @@ void BKE_linestyle_init(FreestyleLineStyle *linestyle)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(linestyle, id));
- linestyle->panel = LS_PANEL_STROKES;
- linestyle->r = linestyle->g = linestyle->b = 0.0f;
- linestyle->alpha = 1.0f;
- linestyle->thickness = 3.0f;
- linestyle->thickness_position = LS_THICKNESS_CENTER;
- linestyle->thickness_ratio = 0.5f;
- linestyle->flag = LS_SAME_OBJECT | LS_NO_SORTING | LS_TEXTURE;
- linestyle->chaining = LS_CHAINING_PLAIN;
- linestyle->rounds = 3;
- linestyle->min_angle = DEG2RADF(0.0f);
- linestyle->max_angle = DEG2RADF(0.0f);
- linestyle->min_length = 0.0f;
- linestyle->max_length = 10000.0f;
- linestyle->split_length = 100;
- linestyle->chain_count = 10;
- linestyle->sort_key = LS_SORT_KEY_DISTANCE_FROM_CAMERA;
- linestyle->integration_type = LS_INTEGRATION_MEAN;
- linestyle->texstep = 1.0f;
- linestyle->pr_texture = TEX_PR_TEXTURE;
-
- BLI_listbase_clear(&linestyle->color_modifiers);
- BLI_listbase_clear(&linestyle->alpha_modifiers);
- BLI_listbase_clear(&linestyle->thickness_modifiers);
- BLI_listbase_clear(&linestyle->geometry_modifiers);
+ MEMCPY_STRUCT_AFTER(linestyle, DNA_struct_default_get(FreestyleLineStyle), id);
BKE_linestyle_geometry_modifier_add(linestyle, NULL, LS_MODIFIER_SAMPLING);
-
- linestyle->caps = LS_CAPS_BUTT;
}
FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name)
@@ -167,6 +143,8 @@ void BKE_linestyle_copy_data(struct Main *bmain,
{
/* We never handle usercount here for own data. */
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
+ /* We always need allocation of our private ID data. */
+ const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
for (int a = 0; a < MAX_MTEX; a++) {
if (linestyle_src->mtex[a]) {
@@ -176,9 +154,10 @@ void BKE_linestyle_copy_data(struct Main *bmain,
}
if (linestyle_src->nodetree) {
- /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
- * (see BKE_libblock_copy_ex()). */
- BKE_id_copy_ex(bmain, (ID *)linestyle_src->nodetree, (ID **)&linestyle_dst->nodetree, flag);
+ BKE_id_copy_ex(bmain,
+ (ID *)linestyle_src->nodetree,
+ (ID **)&linestyle_dst->nodetree,
+ flag_private_id_data);
}
LineStyleModifier *m;
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 1545ae4f48f..73c278a0ab6 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -42,6 +42,7 @@
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_defaults.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
@@ -71,6 +72,7 @@
/* used in UI and render */
Material defmaterial;
+Material defgpencil_material;
static CLG_LogRef LOG = {"bke.material"};
@@ -78,6 +80,13 @@ static CLG_LogRef LOG = {"bke.material"};
void init_def_material(void)
{
BKE_material_init(&defmaterial);
+ BKE_material_gpencil_init(&defgpencil_material);
+}
+
+/* Free the GPencil data of the default material, creator.c */
+void BKE_material_gpencil_default_free(void)
+{
+ MEM_SAFE_FREE(defgpencil_material.gp_style);
}
/** Free (or release) any data used by this material (does not free the material itself). */
@@ -128,20 +137,17 @@ void BKE_material_init(Material *ma)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(ma, id));
- ma->r = ma->g = ma->b = 0.8;
- ma->specr = ma->specg = ma->specb = 1.0;
- ma->a = 1.0f;
- ma->spec = 0.5;
-
- ma->roughness = 0.4f;
-
- ma->pr_type = MA_SPHERE;
-
- ma->preview = NULL;
+ MEMCPY_STRUCT_AFTER(ma, DNA_struct_default_get(Material), id);
+}
- ma->alpha_threshold = 0.5f;
+void BKE_material_gpencil_init(Material *ma)
+{
+ BKE_material_init(ma);
- ma->blend_shadow = MA_BS_SOLID;
+ /* grease pencil settings */
+ strcpy(ma->id.name, "MADefault GPencil");
+ BKE_material_init_gpencil_settings(ma);
+ add_v3_fl(&ma->gp_style->stroke_rgba[0], 0.6f);
}
Material *BKE_material_add(Main *bmain, const char *name)
@@ -180,10 +186,11 @@ Material *BKE_material_add_gpencil(Main *bmain, const char *name)
*/
void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_src, const int flag)
{
+ /* We always need allocation of our private ID data. */
+ const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
+
if (ma_src->nodetree) {
- /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
- * (see BKE_libblock_copy_ex()). */
- BKE_id_copy_ex(bmain, (ID *)ma_src->nodetree, (ID **)&ma_dst->nodetree, flag);
+ BKE_id_copy_ex(bmain, (ID *)ma_src->nodetree, (ID **)&ma_dst->nodetree, flag_private_id_data);
}
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
@@ -580,6 +587,17 @@ Material *give_current_material(Object *ob, short act)
return ma_p ? *ma_p : NULL;
}
+Material *BKE_material_gpencil_get(Object *ob, short act)
+{
+ Material *ma = give_current_material(ob, act);
+ if (ma != NULL) {
+ return ma;
+ }
+ else {
+ return &defgpencil_material;
+ }
+}
+
MaterialGPencilStyle *BKE_material_gpencil_settings_get(Object *ob, short act)
{
Material *ma = give_current_material(ob, act);
@@ -591,7 +609,7 @@ MaterialGPencilStyle *BKE_material_gpencil_settings_get(Object *ob, short act)
return ma->gp_style;
}
else {
- return NULL;
+ return defgpencil_material.gp_style;
}
}
@@ -1070,10 +1088,6 @@ bool BKE_object_material_slot_remove(Main *bmain, Object *ob)
}
/* check indices from gpencil */
else if (ob->type == OB_GPENCIL) {
- /* need one color */
- if (ob->totcol == 0) {
- BKE_gpencil_object_material_ensure_from_active_input_material(bmain, ob);
- }
BKE_gpencil_material_index_reassign((bGPdata *)ob->data, ob->totcol, actcol - 1);
}
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 19009322975..b127d5d4d0e 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -39,6 +39,7 @@
#include "DNA_object_types.h"
#include "DNA_meta_types.h"
#include "DNA_scene_types.h"
+#include "DNA_defaults.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
@@ -79,12 +80,7 @@ void BKE_mball_init(MetaBall *mb)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(mb, id));
- mb->size[0] = mb->size[1] = mb->size[2] = 1.0;
- mb->texflag = MB_AUTOSPACE;
-
- mb->wiresize = 0.4f;
- mb->rendersize = 0.2f;
- mb->thresh = 0.6f;
+ MEMCPY_STRUCT_AFTER(mb, DNA_struct_default_get(MetaBall), id);
}
MetaBall *BKE_mball_add(Main *bmain, const char *name)
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index 687bd0a32c5..ca1ca2618d8 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -1405,7 +1405,7 @@ void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBa
process.converge_res = 2;
}
- if (is_render && (mb->flag == MB_UPDATE_NEVER)) {
+ if (!is_render && (mb->flag == MB_UPDATE_NEVER)) {
return;
}
if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_FAST) {
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 71fd65d1f23..ba139c654d3 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -27,6 +27,7 @@
#include "DNA_key_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_defaults.h"
#include "BLI_utildefines.h"
#include "BLI_bitmap.h"
@@ -495,7 +496,6 @@ void BKE_mesh_clear_geometry(Mesh *mesh)
CustomData_free(&mesh->ldata, mesh->totloop);
CustomData_free(&mesh->pdata, mesh->totpoly);
- MEM_SAFE_FREE(mesh->bb);
MEM_SAFE_FREE(mesh->mselect);
MEM_SAFE_FREE(mesh->edit_mesh);
@@ -533,10 +533,7 @@ void BKE_mesh_init(Mesh *me)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(me, id));
- me->size[0] = me->size[1] = me->size[2] = 1.0;
- me->smoothresh = DEG2RADF(30);
- me->texflag = ME_AUTOSPACE;
- me->remesh_voxel_size = 0.1f;
+ MEMCPY_STRUCT_AFTER(me, DNA_struct_default_get(Mesh), id);
CustomData_reset(&me->vdata);
CustomData_reset(&me->edata);
@@ -607,7 +604,6 @@ void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int
me_dst->edit_mesh = NULL;
me_dst->mselect = MEM_dupallocN(me_dst->mselect);
- me_dst->bb = MEM_dupallocN(me_dst->bb);
/* TODO Do we want to add flag to prevent this? */
if (me_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
@@ -661,20 +657,44 @@ Mesh *BKE_mesh_new_nomain(
return mesh;
}
-static Mesh *mesh_new_nomain_from_template_ex(const Mesh *me_src,
- int verts_len,
- int edges_len,
- int tessface_len,
- int loops_len,
- int polys_len,
- CustomData_MeshMasks mask)
+/* Copy user editable settings that we want to preserve through the modifier stack
+ * or operations where a mesh with new topology is created based on another mesh. */
+void BKE_mesh_copy_settings(Mesh *me_dst, const Mesh *me_src)
+{
+ /* Copy general settings. */
+ me_dst->editflag = me_src->editflag;
+ me_dst->flag = me_src->flag;
+ me_dst->smoothresh = me_src->smoothresh;
+ me_dst->remesh_voxel_size = me_src->remesh_voxel_size;
+ me_dst->remesh_voxel_adaptivity = me_src->remesh_voxel_adaptivity;
+ me_dst->remesh_mode = me_src->remesh_mode;
+
+ /* Copy texture space. */
+ me_dst->texflag = me_src->texflag;
+ copy_v3_v3(me_dst->loc, me_src->loc);
+ copy_v3_v3(me_dst->size, me_src->size);
+
+ /* Copy materials. */
+ if (me_dst->mat != NULL) {
+ MEM_freeN(me_dst->mat);
+ }
+ me_dst->mat = MEM_dupallocN(me_src->mat);
+ me_dst->totcol = me_src->totcol;
+}
+
+Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src,
+ int verts_len,
+ int edges_len,
+ int tessface_len,
+ int loops_len,
+ int polys_len,
+ CustomData_MeshMasks mask)
{
/* Only do tessface if we are creating tessfaces or copying from mesh with only tessfaces. */
const bool do_tessface = (tessface_len || ((me_src->totface != 0) && (me_src->totpoly == 0)));
Mesh *me_dst = BKE_id_new_nomain(ID_ME, NULL);
- me_dst->mat = MEM_dupallocN(me_src->mat);
me_dst->mselect = MEM_dupallocN(me_dst->mselect);
me_dst->totvert = verts_len;
@@ -684,8 +704,7 @@ static Mesh *mesh_new_nomain_from_template_ex(const Mesh *me_src,
me_dst->totpoly = polys_len;
me_dst->cd_flag = me_src->cd_flag;
- me_dst->editflag = me_src->editflag;
- me_dst->texflag = me_src->texflag;
+ BKE_mesh_copy_settings(me_dst, me_src);
CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_CALLOC, verts_len);
CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, CD_CALLOC, edges_len);
@@ -713,7 +732,7 @@ Mesh *BKE_mesh_new_nomain_from_template(const Mesh *me_src,
int loops_len,
int polys_len)
{
- return mesh_new_nomain_from_template_ex(
+ return BKE_mesh_new_nomain_from_template_ex(
me_src, verts_len, edges_len, tessface_len, loops_len, polys_len, CD_MASK_EVERYTHING);
}
@@ -774,18 +793,24 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me,
});
}
-Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm, const struct BMeshToMeshParams *params)
+Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm,
+ const struct BMeshToMeshParams *params,
+ const Mesh *me_settings)
{
BLI_assert(params->calc_object_remap == false);
Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
BM_mesh_bm_to_me(NULL, bm, mesh, params);
+ BKE_mesh_copy_settings(mesh, me_settings);
return mesh;
}
-Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks *cd_mask_extra)
+Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm,
+ const CustomData_MeshMasks *cd_mask_extra,
+ const Mesh *me_settings)
{
Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
BM_mesh_bm_to_me_for_eval(bm, mesh, cd_mask_extra);
+ BKE_mesh_copy_settings(mesh, me_settings);
return mesh;
}
@@ -794,9 +819,10 @@ Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks
*/
Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(BMEditMesh *em,
const CustomData_MeshMasks *data_mask,
- float (*vertexCos)[3])
+ float (*vertexCos)[3],
+ const Mesh *me_settings)
{
- Mesh *me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, data_mask);
+ Mesh *me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, data_mask, me_settings);
/* Use editmesh directly where possible. */
me->runtime.is_original = true;
if (vertexCos) {
@@ -813,50 +839,49 @@ void BKE_mesh_make_local(Main *bmain, Mesh *me, const bool lib_local)
BKE_id_make_local_generic(bmain, &me->id, true, lib_local);
}
-void BKE_mesh_boundbox_calc(Mesh *me, float r_loc[3], float r_size[3])
+BoundBox *BKE_mesh_boundbox_get(Object *ob)
{
- BoundBox *bb;
- float min[3], max[3];
- float mloc[3], msize[3];
-
- if (me->bb == NULL) {
- me->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
- }
- bb = me->bb;
+ /* This is Object-level data access,
+ * DO NOT touch to Mesh's bb, would be totally thread-unsafe. */
+ if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
+ Mesh *me = ob->data;
+ float min[3], max[3];
- if (!r_loc) {
- r_loc = mloc;
- }
- if (!r_size) {
- r_size = msize;
- }
+ INIT_MINMAX(min, max);
+ if (!BKE_mesh_minmax(me, min, max)) {
+ min[0] = min[1] = min[2] = -1.0f;
+ max[0] = max[1] = max[2] = 1.0f;
+ }
- INIT_MINMAX(min, max);
- if (!BKE_mesh_minmax(me, min, max)) {
- min[0] = min[1] = min[2] = -1.0f;
- max[0] = max[1] = max[2] = 1.0f;
+ if (ob->runtime.bb == NULL) {
+ ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
+ }
+ BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
+ ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
}
- mid_v3_v3v3(r_loc, min, max);
-
- r_size[0] = (max[0] - min[0]) / 2.0f;
- r_size[1] = (max[1] - min[1]) / 2.0f;
- r_size[2] = (max[2] - min[2]) / 2.0f;
-
- BKE_boundbox_init_from_minmax(bb, min, max);
-
- bb->flag &= ~BOUNDBOX_DIRTY;
+ return ob->runtime.bb;
}
void BKE_mesh_texspace_calc(Mesh *me)
{
- float loc[3], size[3];
- int a;
+ if (me->texflag & ME_AUTOSPACE) {
+ float min[3], max[3];
- BKE_mesh_boundbox_calc(me, loc, size);
+ INIT_MINMAX(min, max);
+ if (!BKE_mesh_minmax(me, min, max)) {
+ min[0] = min[1] = min[2] = -1.0f;
+ max[0] = max[1] = max[2] = 1.0f;
+ }
- if (me->texflag & ME_AUTOSPACE) {
- for (a = 0; a < 3; a++) {
+ float loc[3], size[3];
+ mid_v3_v3v3(loc, min, max);
+
+ size[0] = (max[0] - min[0]) / 2.0f;
+ size[1] = (max[1] - min[1]) / 2.0f;
+ size[2] = (max[2] - min[2]) / 2.0f;
+
+ for (int a = 0; a < 3; a++) {
if (size[a] == 0.0f) {
size[a] = 1.0f;
}
@@ -870,59 +895,33 @@ void BKE_mesh_texspace_calc(Mesh *me)
copy_v3_v3(me->loc, loc);
copy_v3_v3(me->size, size);
- zero_v3(me->rot);
+
+ me->texflag |= ME_AUTOSPACE_EVALUATED;
}
}
-BoundBox *BKE_mesh_boundbox_get(Object *ob)
+void BKE_mesh_texspace_ensure(Mesh *me)
{
- /* This is Object-level data access,
- * DO NOT touch to Mesh's bb, would be totally thread-unsafe. */
- if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
- Mesh *me = ob->data;
- float min[3], max[3];
-
- INIT_MINMAX(min, max);
- if (!BKE_mesh_minmax(me, min, max)) {
- min[0] = min[1] = min[2] = -1.0f;
- max[0] = max[1] = max[2] = 1.0f;
- }
-
- if (ob->runtime.bb == NULL) {
- ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
- }
- BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
- ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
+ if ((me->texflag & ME_AUTOSPACE) && !(me->texflag & ME_AUTOSPACE_EVALUATED)) {
+ BKE_mesh_texspace_calc(me);
}
-
- return ob->runtime.bb;
}
-BoundBox *BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_rot[3], float r_size[3])
+void BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_size[3])
{
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
+ BKE_mesh_texspace_ensure(me);
if (r_loc) {
copy_v3_v3(r_loc, me->loc);
}
- if (r_rot) {
- copy_v3_v3(r_rot, me->rot);
- }
if (r_size) {
copy_v3_v3(r_size, me->size);
}
-
- return me->bb;
}
-void BKE_mesh_texspace_get_reference(
- Mesh *me, short **r_texflag, float **r_loc, float **r_rot, float **r_size)
+void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc, float **r_size)
{
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
+ BKE_mesh_texspace_ensure(me);
if (r_texflag != NULL) {
*r_texflag = &me->texflag;
@@ -930,9 +929,6 @@ void BKE_mesh_texspace_get_reference(
if (r_loc != NULL) {
*r_loc = me->loc;
}
- if (r_rot != NULL) {
- *r_rot = me->rot;
- }
if (r_size != NULL) {
*r_size = me->size;
}
@@ -940,14 +936,13 @@ void BKE_mesh_texspace_get_reference(
void BKE_mesh_texspace_copy_from_object(Mesh *me, Object *ob)
{
- float *texloc, *texrot, *texsize;
+ float *texloc, *texsize;
short *texflag;
- if (BKE_object_obdata_texspace_get(ob, &texflag, &texloc, &texsize, &texrot)) {
+ if (BKE_object_obdata_texspace_get(ob, &texflag, &texloc, &texsize)) {
me->texflag = *texflag;
copy_v3_v3(me->loc, texloc);
copy_v3_v3(me->size, texsize);
- copy_v3_v3(me->rot, texrot);
}
}
@@ -976,7 +971,7 @@ void BKE_mesh_orco_verts_transform(Mesh *me, float (*orco)[3], int totvert, int
float loc[3], size[3];
int a;
- BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, NULL, size);
+ BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, size);
if (invert) {
for (a = 0; a < totvert; a++) {
@@ -1082,12 +1077,12 @@ void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me)
{
Mesh *old = NULL;
- multires_force_update(ob);
-
if (ob == NULL) {
return;
}
+ multires_force_sculpt_rebuild(ob);
+
if (ob->type == OB_MESH) {
old = ob->data;
if (old) {
@@ -1951,9 +1946,6 @@ void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh)
{
DEG_debug_print_eval(depsgraph, __func__, mesh->id.name, mesh);
BKE_mesh_texspace_calc(mesh);
- /* Clear autospace flag in evaluated mesh, so that texspace does not get recomputed when bbox is
- * (e.g. after modifiers, etc.) */
- mesh->texflag &= ~ME_AUTOSPACE;
/* We are here because something did change in the mesh. This means we can not trust the existing
* evaluated mesh, and we don't know what parts of the mesh did change. So we simply delete the
* evaluated mesh and let objects to re-create it with updated settings. */
@@ -1964,15 +1956,10 @@ void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh)
}
if (DEG_is_active(depsgraph)) {
Mesh *mesh_orig = (Mesh *)DEG_get_original_id(&mesh->id);
- BoundBox *bb = mesh->bb;
- if (bb != NULL) {
- if (mesh_orig->bb == NULL) {
- mesh_orig->bb = MEM_mallocN(sizeof(*mesh_orig->bb), __func__);
- }
- *mesh_orig->bb = *bb;
+ if (mesh->texflag & ME_AUTOSPACE_EVALUATED) {
+ mesh_orig->texflag |= ME_AUTOSPACE_EVALUATED;
copy_v3_v3(mesh_orig->loc, mesh->loc);
copy_v3_v3(mesh_orig->size, mesh->size);
- copy_v3_v3(mesh_orig->rot, mesh->rot);
}
}
}
diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c
index e072a37acee..2ade368284c 100644
--- a/source/blender/blenkernel/intern/mesh_convert.c
+++ b/source/blender/blenkernel/intern/mesh_convert.c
@@ -265,9 +265,11 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob,
const float *data;
int a, b, ofs, vertcount, startvert, totvert = 0, totedge = 0, totloop = 0, totpoly = 0;
int p1, p2, p3, p4, *index;
- const bool conv_polys = ((CU_DO_2DFILL(cu) ==
- false) || /* 2d polys are filled with DL_INDEX3 displists */
- (ob->type == OB_SURF)); /* surf polys are never filled */
+ const bool conv_polys = (
+ /* 2d polys are filled with DL_INDEX3 displists */
+ (CU_DO_2DFILL(cu) == false) ||
+ /* surf polys are never filled */
+ (ob->type == OB_SURF));
/* count */
dl = dispbase->first;
@@ -554,7 +556,7 @@ Mesh *BKE_mesh_new_nomain_from_curve_displist(Object *ob, ListBase *dispbase)
memcpy(mesh->mpoly, allpoly, totpoly * sizeof(MPoly));
if (alluv) {
- const char *uvname = "Orco";
+ const char *uvname = "UVMap";
CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, totloop, uvname);
}
@@ -633,7 +635,7 @@ void BKE_mesh_from_nurbs_displist(Main *bmain,
me->mpoly = CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, allpoly, me->totpoly);
if (alluv) {
- const char *uvname = "Orco";
+ const char *uvname = "UVMap";
me->mloopuv = CustomData_add_layer_named(
&me->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, me->totloop, uvname);
}
@@ -665,7 +667,6 @@ void BKE_mesh_from_nurbs_displist(Main *bmain,
me->texflag = cu->texflag & ~CU_AUTOSPACE;
copy_v3_v3(me->loc, cu->loc);
copy_v3_v3(me->size, cu->size);
- copy_v3_v3(me->rot, cu->rot);
BKE_mesh_texspace_calc(me);
cu->mat = NULL;
@@ -1078,6 +1079,7 @@ static Mesh *mesh_new_from_mball_object(Object *object)
Mesh *mesh_result = BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2);
BKE_mesh_from_metaball(&object->runtime.curve_cache->disp, mesh_result);
+ BKE_mesh_texspace_copy_from_object(mesh_result, object);
/* Copy materials. */
mesh_result->totcol = mball->totcol;
@@ -1573,11 +1575,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
/* Clear selection history */
MEM_SAFE_FREE(tmp.mselect);
tmp.totselect = 0;
- BLI_assert(ELEM(tmp.bb, NULL, mesh_dst->bb));
- if (mesh_dst->bb) {
- MEM_freeN(mesh_dst->bb);
- tmp.bb = NULL;
- }
+ tmp.texflag &= ~ME_AUTOSPACE_EVALUATED;
/* skip the listbase */
MEMCPY_STRUCT_AFTER(mesh_dst, &tmp, id.prev);
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 38762109167..7a1dcb4a5fd 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -2320,6 +2320,24 @@ float BKE_mesh_calc_poly_area(const MPoly *mpoly, const MLoop *loopstart, const
}
}
+float BKE_mesh_calc_area(const Mesh *me)
+{
+ MVert *mvert = me->mvert;
+ MLoop *mloop = me->mloop;
+ MPoly *mpoly = me->mpoly;
+
+ MPoly *mp;
+ int i = me->totpoly;
+ float total_area = 0;
+
+ for (mp = mpoly; i--; mp++) {
+ MLoop *ml_start = &mloop[mp->loopstart];
+
+ total_area += BKE_mesh_calc_poly_area(mp, ml_start, mvert);
+ }
+ return total_area;
+}
+
float BKE_mesh_calc_poly_uv_area(const MPoly *mpoly, const MLoopUV *uv_array)
{
diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.c b/source/blender/blenkernel/intern/mesh_remesh_voxel.c
index a5136311a22..8419a72f97e 100644
--- a/source/blender/blenkernel/intern/mesh_remesh_voxel.c
+++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.c
@@ -38,6 +38,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BKE_editmesh.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_library.h"
@@ -45,10 +46,16 @@
#include "BKE_bvhutils.h"
#include "BKE_mesh_remesh_voxel.h" /* own include */
+#include "bmesh_tools.h"
+
#ifdef WITH_OPENVDB
# include "openvdb_capi.h"
#endif
+#ifdef WITH_QUADRIFLOW
+# include "quadriflow_capi.hpp"
+#endif
+
#ifdef WITH_OPENVDB
struct OpenVDBLevelSet *BKE_mesh_remesh_voxel_ovdb_mesh_to_level_set_create(
Mesh *mesh, struct OpenVDBTransform *transform)
@@ -146,7 +153,149 @@ Mesh *BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(struct OpenVDBLevelSet *l
}
#endif
-Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(Mesh *mesh, float voxel_size)
+#ifdef WITH_QUADRIFLOW
+static Mesh *BKE_mesh_remesh_quadriflow(Mesh *input_mesh,
+ int target_faces,
+ int seed,
+ bool preserve_sharp,
+ bool preserve_boundary,
+ bool adaptive_scale,
+ void *update_cb,
+ void *update_cb_data)
+{
+ /* Ensure that the triangulated mesh data is up to data */
+ BKE_mesh_runtime_looptri_recalc(input_mesh);
+ const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(input_mesh);
+
+ /* Gather the required data for export to the internal quadiflow mesh format */
+ MVertTri *verttri = MEM_callocN(sizeof(*verttri) * BKE_mesh_runtime_looptri_len(input_mesh),
+ "remesh_looptri");
+ BKE_mesh_runtime_verttri_from_looptri(
+ verttri, input_mesh->mloop, looptri, BKE_mesh_runtime_looptri_len(input_mesh));
+
+ unsigned int totfaces = BKE_mesh_runtime_looptri_len(input_mesh);
+ unsigned int totverts = input_mesh->totvert;
+ float *verts = (float *)MEM_malloc_arrayN(totverts * 3, sizeof(float), "remesh_input_verts");
+ unsigned int *faces = (unsigned int *)MEM_malloc_arrayN(
+ totfaces * 3, sizeof(unsigned int), "remesh_intput_faces");
+
+ for (unsigned int i = 0; i < totverts; i++) {
+ MVert *mvert = &input_mesh->mvert[i];
+ verts[i * 3] = mvert->co[0];
+ verts[i * 3 + 1] = mvert->co[1];
+ verts[i * 3 + 2] = mvert->co[2];
+ }
+
+ for (unsigned int i = 0; i < totfaces; i++) {
+ MVertTri *vt = &verttri[i];
+ faces[i * 3] = vt->tri[0];
+ faces[i * 3 + 1] = vt->tri[1];
+ faces[i * 3 + 2] = vt->tri[2];
+ }
+
+ /* Fill out the required input data */
+ QuadriflowRemeshData qrd;
+
+ qrd.totfaces = totfaces;
+ qrd.totverts = totverts;
+ qrd.verts = verts;
+ qrd.faces = faces;
+ qrd.target_faces = target_faces;
+
+ qrd.preserve_sharp = preserve_sharp;
+ qrd.preserve_boundary = preserve_boundary;
+ qrd.adaptive_scale = adaptive_scale;
+ qrd.minimum_cost_flow = 0;
+ qrd.aggresive_sat = 0;
+ qrd.rng_seed = seed;
+
+ qrd.out_faces = NULL;
+
+ /* Run the remesher */
+ QFLOW_quadriflow_remesh(&qrd, update_cb, update_cb_data);
+
+ MEM_freeN(verts);
+ MEM_freeN(faces);
+ MEM_freeN(verttri);
+
+ if (qrd.out_faces == NULL) {
+ /* The remeshing was canceled */
+ return NULL;
+ }
+
+ if (qrd.out_totfaces == 0) {
+ /* Meshing failed */
+ MEM_freeN(qrd.out_faces);
+ MEM_freeN(qrd.out_verts);
+ return NULL;
+ }
+
+ /* Construct the new output mesh */
+ Mesh *mesh = BKE_mesh_new_nomain(
+ qrd.out_totverts, 0, 0, (qrd.out_totfaces * 4), qrd.out_totfaces);
+
+ for (int i = 0; i < qrd.out_totverts; i++) {
+ copy_v3_v3(mesh->mvert[i].co, &qrd.out_verts[i * 3]);
+ }
+
+ MPoly *mp = mesh->mpoly;
+ MLoop *ml = mesh->mloop;
+ for (int i = 0; i < qrd.out_totfaces; i++, mp++, ml += 4) {
+ mp->loopstart = (int)(ml - mesh->mloop);
+ mp->totloop = 4;
+
+ ml[0].v = qrd.out_faces[i * 4];
+ ml[1].v = qrd.out_faces[i * 4 + 1];
+ ml[2].v = qrd.out_faces[i * 4 + 2];
+ ml[3].v = qrd.out_faces[i * 4 + 3];
+ }
+
+ BKE_mesh_calc_edges(mesh, false, false);
+ BKE_mesh_calc_normals(mesh);
+
+ MEM_freeN(qrd.out_faces);
+ MEM_freeN(qrd.out_verts);
+
+ return mesh;
+}
+#endif
+
+Mesh *BKE_mesh_remesh_quadriflow_to_mesh_nomain(Mesh *mesh,
+ int target_faces,
+ int seed,
+ bool preserve_sharp,
+ bool preserve_boundary,
+ bool adaptive_scale,
+ void *update_cb,
+ void *update_cb_data)
+{
+ Mesh *new_mesh = NULL;
+#ifdef WITH_QUADRIFLOW
+ if (target_faces <= 0) {
+ target_faces = -1;
+ }
+ new_mesh = BKE_mesh_remesh_quadriflow(mesh,
+ target_faces,
+ seed,
+ preserve_sharp,
+ preserve_boundary,
+ adaptive_scale,
+ update_cb,
+ update_cb_data);
+#else
+ UNUSED_VARS(mesh,
+ target_faces,
+ seed,
+ preserve_sharp,
+ preserve_boundary,
+ adaptive_scale,
+ update_cb,
+ update_cb_data);
+#endif
+ return new_mesh;
+}
+
+Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(Mesh *mesh, float voxel_size, float adaptivity)
{
Mesh *new_mesh = NULL;
#ifdef WITH_OPENVDB
@@ -154,11 +303,12 @@ Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(Mesh *mesh, float voxel_size)
struct OpenVDBTransform *xform = OpenVDBTransform_create();
OpenVDBTransform_create_linear_transform(xform, (double)voxel_size);
level_set = BKE_mesh_remesh_voxel_ovdb_mesh_to_level_set_create(mesh, xform);
- new_mesh = BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(level_set, 0.0, 0.0, false);
+ new_mesh = BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(
+ level_set, 0.0, (float)adaptivity, false);
OpenVDBLevelSet_free(level_set);
OpenVDBTransform_free(xform);
#else
- UNUSED_VARS(mesh, voxel_size);
+ UNUSED_VARS(mesh, voxel_size, adaptivity);
#endif
return new_mesh;
}
@@ -202,3 +352,106 @@ void BKE_remesh_reproject_paint_mask(Mesh *target, Mesh *source)
}
free_bvhtree_from_mesh(&bvhtree);
}
+
+struct Mesh *BKE_mesh_remesh_voxel_fix_poles(struct Mesh *mesh)
+{
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
+ BMesh *bm;
+ bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = true,
+ }));
+
+ BM_mesh_bm_from_me(bm,
+ mesh,
+ (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
+
+ BMVert *v;
+ BMEdge *ed, *ed_next;
+ BMFace *f, *f_next;
+ BMIter iter_a, iter_b;
+
+ /* Merge 3 edge poles vertices that exist in the same face */
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ BM_ITER_MESH_MUTABLE (f, f_next, &iter_a, bm, BM_FACES_OF_MESH) {
+ BMVert *v1, *v2;
+ v1 = NULL;
+ v2 = NULL;
+ BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) {
+ if (BM_vert_edge_count(v) == 3) {
+ if (v1) {
+ v2 = v;
+ }
+ else {
+ v1 = v;
+ }
+ }
+ }
+ if (v1 && v2 && (v1 != v2) && !BM_edge_exists(v1, v2)) {
+ BM_face_kill(bm, f);
+ BMEdge *e = BM_edge_create(bm, v1, v2, NULL, BM_CREATE_NOP);
+ BM_elem_flag_set(e, BM_ELEM_TAG, true);
+ }
+ }
+
+ BM_ITER_MESH_MUTABLE (ed, ed_next, &iter_a, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(ed, BM_ELEM_TAG)) {
+ float co[3];
+ mid_v3_v3v3(co, ed->v1->co, ed->v2->co);
+ BMVert *vc = BM_edge_collapse(bm, ed, ed->v1, true, true);
+ copy_v3_v3(vc->co, co);
+ }
+ }
+
+ /* Delete faces with a 3 edge pole in all their vertices */
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ BM_ITER_MESH (f, &iter_a, bm, BM_FACES_OF_MESH) {
+ bool dissolve = true;
+ BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) {
+ if (BM_vert_edge_count(v) != 3) {
+ dissolve = false;
+ }
+ }
+ if (dissolve) {
+ BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) {
+ BM_elem_flag_set(v, BM_ELEM_TAG, true);
+ }
+ }
+ }
+ BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_VERTS);
+
+ BM_ITER_MESH (ed, &iter_a, bm, BM_EDGES_OF_MESH) {
+ if (BM_edge_face_count(ed) != 2) {
+ BM_elem_flag_set(ed, BM_ELEM_TAG, true);
+ }
+ }
+ BM_mesh_edgenet(bm, false, true);
+
+ /* Smooth the result */
+ for (int i = 0; i < 4; i++) {
+ BM_ITER_MESH (v, &iter_a, bm, BM_VERTS_OF_MESH) {
+ float co[3];
+ zero_v3(co);
+ BM_ITER_ELEM (ed, &iter_b, v, BM_EDGES_OF_VERT) {
+ BMVert *vert = BM_edge_other_vert(ed, v);
+ add_v3_v3(co, vert->co);
+ }
+ mul_v3_fl(co, 1.0f / (float)BM_vert_edge_count(v));
+ mid_v3_v3v3(v->co, v->co, co);
+ }
+ }
+
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+
+ Mesh *result = BKE_mesh_from_bmesh_nomain(bm,
+ (&(struct BMeshToMeshParams){
+ .calc_object_remap = false,
+ }),
+ mesh);
+
+ BKE_id_free(NULL, mesh);
+ BM_mesh_free(bm);
+ return result;
+}
diff --git a/source/blender/blenkernel/intern/mirror.c b/source/blender/blenkernel/intern/mirror.c
new file mode 100644
index 00000000000..c429b953015
--- /dev/null
+++ b/source/blender/blenkernel/intern/mirror.c
@@ -0,0 +1,413 @@
+/*
+ * 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) Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BLI_math.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_mesh.h"
+#include "BKE_mirror.h"
+#include "BKE_modifier.h"
+#include "BKE_deform.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "MOD_modifiertypes.h"
+
+Mesh *BKE_mirror_bisect_on_mirror_plane(MirrorModifierData *mmd,
+ const Mesh *mesh,
+ int axis,
+ const float plane_co[3],
+ float plane_no[3])
+{
+ bool do_bisect_flip_axis = ((axis == 0 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_X) ||
+ (axis == 1 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Y) ||
+ (axis == 2 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Z));
+
+ const float bisect_distance = 0.001f;
+
+ Mesh *result;
+ BMesh *bm;
+ BMIter viter;
+ BMVert *v, *v_next;
+
+ bm = BKE_mesh_to_bmesh_ex(mesh,
+ &(struct BMeshCreateParams){0},
+ &(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX,
+ .emask = CD_MASK_ORIGINDEX,
+ .pmask = CD_MASK_ORIGINDEX},
+ });
+
+ /* Define bisecting plane (aka mirror plane). */
+ float plane[4];
+ if (!do_bisect_flip_axis) {
+ /* That reversed condition is a tad weird, but for some reason that's how you keep
+ * the part of the mesh which is on the non-mirrored side when flip option is disabled,
+ * think that that is the expected behavior. */
+ negate_v3(plane_no);
+ }
+ plane_from_point_normal_v3(plane, plane_co, plane_no);
+
+ BM_mesh_bisect_plane(bm, plane, false, false, 0, 0, bisect_distance);
+
+ /* Plane definitions for vert killing. */
+ float plane_offset[4];
+ copy_v3_v3(plane_offset, plane);
+ plane_offset[3] = plane[3] - bisect_distance;
+
+ /* Delete verts across the mirror plane. */
+ BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) {
+ if (plane_point_side_v3(plane_offset, v->co) > 0.0f) {
+ BM_vert_kill(bm, v);
+ }
+ }
+
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
+ BM_mesh_free(bm);
+
+ return result;
+}
+
+Mesh *BKE_mirror_apply_mirror_on_axis(MirrorModifierData *mmd,
+ const ModifierEvalContext *UNUSED(ctx),
+ Object *ob,
+ const Mesh *mesh,
+ int axis)
+{
+ const float tolerance_sq = mmd->tolerance * mmd->tolerance;
+ const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0;
+ int tot_vtargetmap = 0; /* total merge vertices */
+
+ const bool do_bisect = ((axis == 0 && mmd->flag & MOD_MIR_BISECT_AXIS_X) ||
+ (axis == 1 && mmd->flag & MOD_MIR_BISECT_AXIS_Y) ||
+ (axis == 2 && mmd->flag & MOD_MIR_BISECT_AXIS_Z));
+
+ Mesh *result;
+ MVert *mv, *mv_prev;
+ MEdge *me;
+ MLoop *ml;
+ MPoly *mp;
+ float mtx[4][4];
+ float plane_co[3], plane_no[3];
+ int i;
+ int a, totshape;
+ int *vtargetmap = NULL, *vtmap_a = NULL, *vtmap_b = NULL;
+
+ /* mtx is the mirror transformation */
+ unit_m4(mtx);
+ mtx[axis][axis] = -1.0f;
+
+ Object *mirror_ob = mmd->mirror_ob;
+ if (mirror_ob != NULL) {
+ float tmp[4][4];
+ float itmp[4][4];
+
+ /* tmp is a transform from coords relative to the object's own origin,
+ * to coords relative to the mirror object origin */
+ invert_m4_m4(tmp, mirror_ob->obmat);
+ mul_m4_m4m4(tmp, tmp, ob->obmat);
+
+ /* itmp is the reverse transform back to origin-relative coordinates */
+ invert_m4_m4(itmp, tmp);
+
+ /* combine matrices to get a single matrix that translates coordinates into
+ * mirror-object-relative space, does the mirror, and translates back to
+ * origin-relative space */
+ mul_m4_series(mtx, itmp, mtx, tmp);
+
+ if (do_bisect) {
+ copy_v3_v3(plane_co, itmp[3]);
+ copy_v3_v3(plane_no, itmp[axis]);
+ }
+ }
+ else if (do_bisect) {
+ copy_v3_v3(plane_co, mtx[3]);
+ /* Need to negate here, since that axis is inverted (for mirror transform). */
+ negate_v3_v3(plane_no, mtx[axis]);
+ }
+
+ Mesh *mesh_bisect = NULL;
+ if (do_bisect) {
+ mesh_bisect = BKE_mirror_bisect_on_mirror_plane(mmd, mesh, axis, plane_co, plane_no);
+ mesh = mesh_bisect;
+ }
+
+ const int maxVerts = mesh->totvert;
+ const int maxEdges = mesh->totedge;
+ const int maxLoops = mesh->totloop;
+ const int maxPolys = mesh->totpoly;
+
+ result = BKE_mesh_new_nomain_from_template(
+ mesh, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2);
+
+ /*copy customdata to original geometry*/
+ CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, maxVerts);
+ CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, maxEdges);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, maxLoops);
+ CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, maxPolys);
+
+ /* Subsurf for eg won't have mesh data in the custom data arrays.
+ * now add mvert/medge/mpoly layers. */
+ if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) {
+ memcpy(result->mvert, mesh->mvert, sizeof(*result->mvert) * mesh->totvert);
+ }
+ if (!CustomData_has_layer(&mesh->edata, CD_MEDGE)) {
+ memcpy(result->medge, mesh->medge, sizeof(*result->medge) * mesh->totedge);
+ }
+ if (!CustomData_has_layer(&mesh->pdata, CD_MPOLY)) {
+ memcpy(result->mloop, mesh->mloop, sizeof(*result->mloop) * mesh->totloop);
+ memcpy(result->mpoly, mesh->mpoly, sizeof(*result->mpoly) * mesh->totpoly);
+ }
+
+ /* copy customdata to new geometry,
+ * copy from its self because this data may have been created in the checks above */
+ CustomData_copy_data(&result->vdata, &result->vdata, 0, maxVerts, maxVerts);
+ CustomData_copy_data(&result->edata, &result->edata, 0, maxEdges, maxEdges);
+ /* loops are copied later */
+ CustomData_copy_data(&result->pdata, &result->pdata, 0, maxPolys, maxPolys);
+
+ if (do_vtargetmap) {
+ /* second half is filled with -1 */
+ vtargetmap = MEM_malloc_arrayN(maxVerts, 2 * sizeof(int), "MOD_mirror tarmap");
+
+ vtmap_a = vtargetmap;
+ vtmap_b = vtargetmap + maxVerts;
+ }
+
+ /* mirror vertex coordinates */
+ mv_prev = result->mvert;
+ mv = mv_prev + maxVerts;
+ for (i = 0; i < maxVerts; i++, mv++, mv_prev++) {
+ mul_m4_v3(mtx, mv->co);
+
+ if (do_vtargetmap) {
+ /* compare location of the original and mirrored vertex, to see if they
+ * should be mapped for merging */
+ if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
+ *vtmap_a = maxVerts + i;
+ tot_vtargetmap++;
+
+ /* average location */
+ mid_v3_v3v3(mv->co, mv_prev->co, mv->co);
+ copy_v3_v3(mv_prev->co, mv->co);
+ }
+ else {
+ *vtmap_a = -1;
+ }
+
+ *vtmap_b = -1; /* fill here to avoid 2x loops */
+
+ vtmap_a++;
+ vtmap_b++;
+ }
+ }
+
+ /* handle shape keys */
+ totshape = CustomData_number_of_layers(&result->vdata, CD_SHAPEKEY);
+ for (a = 0; a < totshape; a++) {
+ float(*cos)[3] = CustomData_get_layer_n(&result->vdata, CD_SHAPEKEY, a);
+ for (i = maxVerts; i < result->totvert; i++) {
+ mul_m4_v3(mtx, cos[i]);
+ }
+ }
+
+ /* adjust mirrored edge vertex indices */
+ me = result->medge + maxEdges;
+ for (i = 0; i < maxEdges; i++, me++) {
+ me->v1 += maxVerts;
+ me->v2 += maxVerts;
+ }
+
+ /* adjust mirrored poly loopstart indices, and reverse loop order (normals) */
+ mp = result->mpoly + maxPolys;
+ ml = result->mloop;
+ for (i = 0; i < maxPolys; i++, mp++) {
+ MLoop *ml2;
+ int j, e;
+
+ /* reverse the loop, but we keep the first vertex in the face the same,
+ * to ensure that quads are split the same way as on the other side */
+ CustomData_copy_data(
+ &result->ldata, &result->ldata, mp->loopstart, mp->loopstart + maxLoops, 1);
+
+ for (j = 1; j < mp->totloop; j++) {
+ CustomData_copy_data(&result->ldata,
+ &result->ldata,
+ mp->loopstart + j,
+ mp->loopstart + maxLoops + mp->totloop - j,
+ 1);
+ }
+
+ ml2 = ml + mp->loopstart + maxLoops;
+ e = ml2[0].e;
+ for (j = 0; j < mp->totloop - 1; j++) {
+ ml2[j].e = ml2[j + 1].e;
+ }
+ ml2[mp->totloop - 1].e = e;
+
+ mp->loopstart += maxLoops;
+ }
+
+ /* adjust mirrored loop vertex and edge indices */
+ ml = result->mloop + maxLoops;
+ for (i = 0; i < maxLoops; i++, ml++) {
+ ml->v += maxVerts;
+ ml->e += maxEdges;
+ }
+
+ /* handle uvs,
+ * let tessface recalc handle updating the MTFace data */
+ if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V) ||
+ (is_zero_v2(mmd->uv_offset_copy) == false)) {
+ const bool do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0;
+ const bool do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0;
+
+ const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV);
+
+ for (a = 0; a < totuv; a++) {
+ MLoopUV *dmloopuv = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, a);
+ int j = maxLoops;
+ dmloopuv += j; /* second set of loops only */
+ for (; j-- > 0; dmloopuv++) {
+ if (do_mirr_u) {
+ dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0] + mmd->uv_offset[0];
+ }
+ if (do_mirr_v) {
+ dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1] + mmd->uv_offset[1];
+ }
+ dmloopuv->uv[0] += mmd->uv_offset_copy[0];
+ dmloopuv->uv[1] += mmd->uv_offset_copy[1];
+ }
+ }
+ }
+
+ /* handle custom split normals */
+ if (ob->type == OB_MESH && (((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) &&
+ CustomData_has_layer(&result->ldata, CD_CUSTOMLOOPNORMAL)) {
+ const int totloop = result->totloop;
+ const int totpoly = result->totpoly;
+ float(*loop_normals)[3] = MEM_calloc_arrayN((size_t)totloop, sizeof(*loop_normals), __func__);
+ CustomData *ldata = &result->ldata;
+ short(*clnors)[2] = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
+ MLoopNorSpaceArray lnors_spacearr = {NULL};
+ float(*poly_normals)[3] = MEM_mallocN(sizeof(*poly_normals) * totpoly, __func__);
+
+ /* calculate custom normals into loop_normals, then mirror first half into second half */
+
+ BKE_mesh_calc_normals_poly(result->mvert,
+ NULL,
+ result->totvert,
+ result->mloop,
+ result->mpoly,
+ totloop,
+ totpoly,
+ poly_normals,
+ false);
+
+ BKE_mesh_normals_loop_split(result->mvert,
+ result->totvert,
+ result->medge,
+ result->totedge,
+ result->mloop,
+ loop_normals,
+ totloop,
+ result->mpoly,
+ poly_normals,
+ totpoly,
+ true,
+ mesh->smoothresh,
+ &lnors_spacearr,
+ clnors,
+ NULL);
+
+ /* mirroring has to account for loops being reversed in polys in second half */
+ mp = result->mpoly;
+ for (i = 0; i < maxPolys; i++, mp++) {
+ MPoly *mpmirror = result->mpoly + maxPolys + i;
+ int j;
+
+ for (j = mp->loopstart; j < mp->loopstart + mp->totloop; j++) {
+ int mirrorj = mpmirror->loopstart;
+ if (j > mp->loopstart) {
+ mirrorj += mpmirror->totloop - (j - mp->loopstart);
+ }
+ copy_v3_v3(loop_normals[mirrorj], loop_normals[j]);
+ loop_normals[mirrorj][axis] = -loop_normals[j][axis];
+ BKE_lnor_space_custom_normal_to_data(
+ lnors_spacearr.lspacearr[mirrorj], loop_normals[mirrorj], clnors[mirrorj]);
+ }
+ }
+
+ MEM_freeN(poly_normals);
+ MEM_freeN(loop_normals);
+ BKE_lnor_spacearr_free(&lnors_spacearr);
+ }
+
+ /* handle vgroup stuff */
+ if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&result->vdata, CD_MDEFORMVERT)) {
+ MDeformVert *dvert = (MDeformVert *)CustomData_get_layer(&result->vdata, CD_MDEFORMVERT) +
+ maxVerts;
+ int *flip_map = NULL, flip_map_len = 0;
+
+ flip_map = defgroup_flip_map(ob, &flip_map_len, false);
+
+ if (flip_map) {
+ for (i = 0; i < maxVerts; dvert++, i++) {
+ /* merged vertices get both groups, others get flipped */
+ if (do_vtargetmap && (vtargetmap[i] != -1)) {
+ defvert_flip_merged(dvert, flip_map, flip_map_len);
+ }
+ else {
+ defvert_flip(dvert, flip_map, flip_map_len);
+ }
+ }
+
+ MEM_freeN(flip_map);
+ }
+ }
+
+ if (do_vtargetmap) {
+ /* slow - so only call if one or more merge verts are found,
+ * users may leave this on and not realize there is nothing to merge - campbell */
+ if (tot_vtargetmap) {
+ result = BKE_mesh_merge_verts(
+ result, vtargetmap, tot_vtargetmap, MESH_MERGE_VERTS_DUMP_IF_MAPPED);
+ }
+ MEM_freeN(vtargetmap);
+ }
+
+ if (mesh_bisect != NULL) {
+ BKE_id_free(NULL, mesh_bisect);
+ }
+
+ return result;
+}
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index bbae1f4d3bc..6a5e31bd2a2 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -406,25 +406,38 @@ void multires_mark_as_modified(Depsgraph *depsgraph, Object *object, MultiresMod
multires_ccg_mark_as_modified(subdiv_ccg, flags);
}
-void multires_force_update(Object *ob)
+void multires_flush_sculpt_updates(Object *ob)
{
- if (ob == NULL) {
- return;
- }
- SculptSession *sculpt_session = ob->sculpt;
- if (sculpt_session != NULL && sculpt_session->pbvh != NULL) {
- PBVH *pbvh = sculpt_session->pbvh;
- if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) {
+ if (ob && ob->sculpt && ob->sculpt->pbvh != NULL) {
+ SculptSession *sculpt_session = ob->sculpt;
+ if (BKE_pbvh_type(sculpt_session->pbvh) == PBVH_GRIDS) {
Mesh *mesh = ob->data;
multiresModifier_reshapeFromCCG(
sculpt_session->multires->totlvl, mesh, sculpt_session->subdiv_ccg);
}
- else {
- /* NOTE: Disabled for until OpenSubdiv is enabled by default. */
- // BLI_assert(!"multires_force_update is used on non-grids PBVH");
+ }
+}
+
+void multires_force_sculpt_rebuild(Object *ob)
+{
+ multires_flush_sculpt_updates(ob);
+
+ if (ob && ob->sculpt) {
+ SculptSession *ss = ob->sculpt;
+ if (ss->pbvh) {
+ BKE_pbvh_free(ss->pbvh);
+ ob->sculpt->pbvh = NULL;
+ }
+
+ if (ss->pmap) {
+ MEM_freeN(ss->pmap);
+ ss->pmap = NULL;
+ }
+
+ if (ss->pmap_mem) {
+ MEM_freeN(ss->pmap_mem);
+ ss->pmap_mem = NULL;
}
- BKE_pbvh_free(pbvh);
- ob->sculpt->pbvh = NULL;
}
}
@@ -433,14 +446,7 @@ void multires_force_external_reload(Object *ob)
Mesh *me = BKE_mesh_from_object(ob);
CustomData_external_reload(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
- multires_force_update(ob);
-}
-
-void multires_force_render_update(Object *ob)
-{
- if (ob && (ob->mode & OB_MODE_SCULPT) && modifiers_findByType(ob, eModifierType_Multires)) {
- multires_force_update(ob);
- }
+ multires_force_sculpt_rebuild(ob);
}
/* reset the multires levels to match the number of mdisps */
@@ -452,7 +458,7 @@ static int get_levels_from_disps(Object *ob)
mdisp = CustomData_get_layer(&me->ldata, CD_MDISPS);
- for (i = 0; i < me->totpoly; ++i) {
+ for (i = 0; i < me->totpoly; i++) {
md = mdisp + me->mpoly[i].loopstart;
for (j = 0; j < me->mpoly[i].totloop; j++, md++) {
@@ -520,7 +526,7 @@ static void multires_reallocate_mdisps(int totloop, MDisps *mdisps, int lvl)
int i;
/* reallocate displacements to be filled in */
- for (i = 0; i < totloop; ++i) {
+ for (i = 0; i < totloop; i++) {
int totdisp = multires_grid_tot[lvl];
float(*disps)[3] = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disps");
@@ -624,7 +630,7 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl)
mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
gpm = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK);
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
if (mdisps && levels > 0) {
if (lvl > 0) {
@@ -633,7 +639,7 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl)
int hsize = multires_side_tot[mmd->totlvl];
int i, j;
- for (i = 0; i < me->totpoly; ++i) {
+ for (i = 0; i < me->totpoly; i++) {
for (j = 0; j < me->mpoly[i].totloop; j++) {
int g = me->mpoly[i].loopstart + j;
MDisps *mdisp = &mdisps[g];
@@ -689,7 +695,7 @@ void multiresModifier_del_levels(MultiresModifierData *mmd,
CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
if (mdisps && levels > 0 && direction == 1) {
multires_del_higher(mmd, ob, lvl);
@@ -781,7 +787,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object
float(*origco)[3];
int i, j, k, offset, totlvl;
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
me = BKE_mesh_from_object(ob);
totlvl = mmd->totlvl;
@@ -802,7 +808,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object
/* copy the new locations of the base verts into the mesh */
offset = dispdm->getNumVerts(dispdm) - me->totvert;
- for (i = 0; i < me->totvert; ++i) {
+ for (i = 0; i < me->totvert; i++) {
dispdm->getVertCo(dispdm, offset + i, me->mvert[i].co);
}
@@ -811,11 +817,11 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object
cddm = CDDM_from_mesh(me);
pmap = cddm->getPolyMap(ob, cddm);
origco = MEM_calloc_arrayN(me->totvert, 3 * sizeof(float), "multires apply base origco");
- for (i = 0; i < me->totvert; ++i) {
+ for (i = 0; i < me->totvert; i++) {
copy_v3_v3(origco[i], me->mvert[i].co);
}
- for (i = 0; i < me->totvert; ++i) {
+ for (i = 0; i < me->totvert; i++) {
float avg_no[3] = {0, 0, 0}, center[3] = {0, 0, 0}, push[3];
float dist;
int tot = 0;
@@ -830,7 +836,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object
const MPoly *p = &me->mpoly[pmap[i].indices[j]];
/* this double counts, not sure if that's bad or good */
- for (k = 0; k < p->totloop; ++k) {
+ for (k = 0; k < p->totloop; k++) {
int vndx = me->mloop[p->loopstart + k].v;
if (vndx != i) {
add_v3_v3(center, origco[vndx]);
@@ -855,7 +861,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object
fake_loops = MEM_malloc_arrayN(p->totloop, sizeof(MLoop), "fake_loops");
fake_co = MEM_malloc_arrayN(p->totloop, 3 * sizeof(float), "fake_co");
- for (k = 0; k < p->totloop; ++k) {
+ for (k = 0; k < p->totloop; k++) {
int vndx = me->mloop[p->loopstart + k].v;
fake_loops[k].v = k;
@@ -928,7 +934,7 @@ static void multires_subdivide(
BLI_assert(totlvl > lvl);
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
if (!mdisps) {
@@ -975,7 +981,7 @@ static void multires_subdivide(
subGridData = MEM_calloc_arrayN(numGrids, sizeof(float *), "subGridData*");
- for (i = 0; i < numGrids; ++i) {
+ for (i = 0; i < numGrids; i++) {
/* backup subsurf grids */
subGridData[i] = MEM_calloc_arrayN(
highGridKey.elem_size, highGridSize * highGridSize, "subGridData");
@@ -1000,7 +1006,7 @@ static void multires_subdivide(
/* free */
highdm->release(highdm);
- for (i = 0; i < numGrids; ++i) {
+ for (i = 0; i < numGrids; i++) {
MEM_freeN(subGridData[i]);
}
MEM_freeN(subGridData);
@@ -1097,7 +1103,7 @@ static void multires_disp_run_cb(void *__restrict userdata,
const int numVerts = mpoly[pidx].totloop;
int S, x, y, gIndex = gridOffset[pidx];
- for (S = 0; S < numVerts; ++S, ++gIndex) {
+ for (S = 0; S < numVerts; S++, gIndex++) {
GridPaintMask *gpm = grid_paint_mask ? &grid_paint_mask[gIndex] : NULL;
MDisps *mdisp = &mdisps[mpoly[pidx].loopstart + S];
CCGElem *grid = gridData[gIndex];
@@ -1223,7 +1229,7 @@ static void multiresModifier_disp_run(
}
/* when adding new faces in edit mode, need to allocate disps */
- for (i = 0; i < totloop; ++i) {
+ for (i = 0; i < totloop; i++) {
if (mdisps[i].disps == NULL) {
multires_reallocate_mdisps(totloop, mdisps, totlvl);
break;
@@ -1324,7 +1330,7 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene)
subGridData = MEM_calloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*");
diffGrid = MEM_calloc_arrayN(lowGridKey.elem_size, lowGridSize * lowGridSize, "diff");
- for (i = 0; i < numGrids; ++i) {
+ for (i = 0; i < numGrids; i++) {
/* backup subsurf grids */
subGridData[i] = MEM_calloc_arrayN(
highGridKey.elem_size, highGridSize * highGridSize, "subGridData");
@@ -1332,7 +1338,7 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene)
subGridData[i], highGridData[i], highGridKey.elem_size * highGridSize * highGridSize);
/* write difference of subsurf and displaced low level into high subsurf */
- for (j = 0; j < lowGridSize * lowGridSize; ++j) {
+ for (j = 0; j < lowGridSize * lowGridSize; j++) {
sub_v4_v4v4(CCG_elem_offset_co(&lowGridKey, diffGrid, j),
CCG_elem_offset_co(&lowGridKey, gridData[i], j),
CCG_elem_offset_co(&lowGridKey, lowGridData[i], j));
@@ -1354,7 +1360,7 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene)
/* free */
highdm->release(highdm);
- for (i = 0; i < numGrids; ++i) {
+ for (i = 0; i < numGrids; i++) {
MEM_freeN(subGridData[i]);
}
MEM_freeN(subGridData);
@@ -1617,8 +1623,8 @@ static void old_mdisps_convert(MFace *mface, MDisps *mdisp)
out = disps;
for (S = 0; S < nvert; S++) {
- for (y = 0; y < newside; ++y) {
- for (x = 0; x < newside; ++x, ++out) {
+ for (y = 0; y < newside; y++) {
+ for (x = 0; x < newside; x++, out++) {
old_mdisps_rotate(S, newside, oldside, x, y, &u, &v);
old_mdisps_bilinear(*out, mdisp->disps, oldside, u, v);
@@ -1749,8 +1755,8 @@ static void create_old_vert_face_map(ListBase **map,
node = *mem;
/* Find the users */
- for (i = 0; i < totface; ++i) {
- for (j = 0; j < (mface[i].v[3] ? 4 : 3); ++j, ++node) {
+ for (i = 0; i < totface; i++) {
+ for (j = 0; j < (mface[i].v[3] ? 4 : 3); j++, node++) {
node->index = i;
BLI_addtail(&(*map)[mface[i].v[j]], node);
}
@@ -1771,8 +1777,8 @@ static void create_old_vert_edge_map(ListBase **map,
node = *mem;
/* Find the users */
- for (i = 0; i < totedge; ++i) {
- for (j = 0; j < 2; ++j, ++node) {
+ for (i = 0; i < totedge; i++) {
+ for (j = 0; j < 2; j++, node++) {
node->index = i;
BLI_addtail(&(*map)[medge[i].v[j]], node);
}
@@ -1793,8 +1799,8 @@ static MultiresFace *find_old_face(
for (n1 = map[v1].first; n1; n1 = n1->next) {
int fnd[4] = {0, 0, 0, 0};
- for (i = 0; i < 4; ++i) {
- for (j = 0; j < 4; ++j) {
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
if (v[i] == faces[n1->index].v[j]) {
fnd[i] = 1;
}
@@ -2006,24 +2012,24 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
lvl1 = mr->levels.first;
/* Load base verts */
- for (i = 0; i < lvl1->totvert; ++i) {
+ for (i = 0; i < lvl1->totvert; i++) {
vvmap[totvert - lvl1->totvert + i] = src;
src++;
}
/* Original edges */
dst = totvert - lvl1->totvert - extedgelen * lvl1->totedge;
- for (i = 0; i < lvl1->totedge; ++i) {
+ for (i = 0; i < lvl1->totedge; i++) {
int ldst = dst + extedgelen * i;
int lsrc = src;
lvl = lvl1->next;
- for (j = 2; j <= mr->level_count; ++j) {
+ for (j = 2; j <= mr->level_count; j++) {
int base = multires_side_tot[totlvl - j + 1] - 2;
int skip = multires_side_tot[totlvl - j + 2] - 1;
int st = multires_side_tot[j - 1] - 1;
- for (x = 0; x < st; ++x) {
+ for (x = 0; x < st; x++) {
vvmap[ldst + base + x * skip] = lsrc + st * i + x;
}
@@ -2034,7 +2040,7 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
/* Center points */
dst = 0;
- for (i = 0; i < lvl1->totface; ++i) {
+ for (i = 0; i < lvl1->totface; i++) {
int sides = lvl1->faces[i].v[3] ? 4 : 3;
vvmap[dst] = src + lvl1->totedge + i;
@@ -2050,13 +2056,13 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
tottri = totquad = 0;
crossedgelen = multires_side_tot[totlvl - 1] - 2;
dst = 0;
- for (i = 0; i < lvl1->totface; ++i) {
+ for (i = 0; i < lvl1->totface; i++) {
int sides = lvl1->faces[i].v[3] ? 4 : 3;
lvl = lvl1->next->next;
dst++;
- for (j = 3; j <= mr->level_count; ++j) {
+ for (j = 3; j <= mr->level_count; j++) {
int base = multires_side_tot[totlvl - j + 1] - 2;
int skip = multires_side_tot[totlvl - j + 2] - 1;
int st = pow(2, j - 2);
@@ -2069,8 +2075,8 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
/* Skip earlier face edge crosses */
lsrc += st2 * (tottri * 3 + totquad * 4);
- for (s = 0; s < sides; ++s) {
- for (x = 0; x < st2; ++x) {
+ for (s = 0; s < sides; s++) {
+ for (x = 0; x < st2; x++) {
vvmap[dst + crossedgelen * (s + 1) - base - x * skip - 1] = lsrc;
lsrc++;
}
@@ -2082,10 +2088,10 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
dst += sides * (st_last - 1) * st_last;
if (sides == 4) {
- ++totquad;
+ totquad++;
}
else {
- ++tottri;
+ tottri++;
}
}
@@ -2095,7 +2101,7 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
fmem = MEM_calloc_arrayN((mr->level_count - 1), sizeof(IndexNode *), "multires fmem");
emem = MEM_calloc_arrayN((mr->level_count - 1), sizeof(IndexNode *), "multires emem");
lvl = lvl1;
- for (i = 0; i < (unsigned int)mr->level_count - 1; ++i) {
+ for (i = 0; i < (unsigned int)mr->level_count - 1; i++) {
create_old_vert_face_map(fmap + i, fmem + i, lvl->faces, lvl->totvert, lvl->totface);
create_old_vert_edge_map(emap + i, emem + i, lvl->edges, lvl->totvert, lvl->totedge);
lvl = lvl->next;
@@ -2104,11 +2110,11 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
/* Interior face verts */
/* lvl = lvl1->next->next; */ /* UNUSED */
dst = 0;
- for (j = 0; j < lvl1->totface; ++j) {
+ for (j = 0; j < lvl1->totface; j++) {
int sides = lvl1->faces[j].v[3] ? 4 : 3;
int ldst = dst + 1 + sides * (st_last - 1);
- for (s = 0; s < sides; ++s) {
+ for (s = 0; s < sides; s++) {
int st2 = multires_side_tot[totlvl - 1] - 2;
int st3 = multires_side_tot[totlvl - 2] - 2;
int st4 = st3 == 0 ? 1 : (st3 + 1) / 2;
@@ -2137,7 +2143,7 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
/*lvl = lvl->next;*/ /*UNUSED*/
- for (i = 0; i < (unsigned int)(mr->level_count - 1); ++i) {
+ for (i = 0; i < (unsigned int)(mr->level_count - 1); i++) {
MEM_freeN(fmap[i]);
MEM_freeN(fmem[i]);
MEM_freeN(emap[i]);
@@ -2151,7 +2157,7 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
}
/* Transfer verts */
- for (i = 0; i < totvert; ++i) {
+ for (i = 0; i < totvert; i++) {
copy_v3_v3(vdst[i].co, vsrc[vvmap[i]].co);
}
@@ -2183,8 +2189,8 @@ static void multires_load_old_vcols(Mesh *me)
return;
}
- for (i = 0; i < me->totface; ++i) {
- for (j = 0; j < 4; ++j) {
+ for (i = 0; i < me->totface; i++) {
+ for (j = 0; j < 4; j++) {
mcol[i * 4 + j].a = colface[i].col[j].a;
mcol[i * 4 + j].r = colface[i].col[j].r;
mcol[i * 4 + j].g = colface[i].col[j].g;
@@ -2208,7 +2214,7 @@ static void multires_load_old_face_flags(Mesh *me)
return;
}
- for (i = 0; i < me->totface; ++i) {
+ for (i = 0; i < me->totface; i++) {
me->mface[i].flag = faces[i].flag;
}
}
@@ -2234,11 +2240,11 @@ void multires_load_old(Object *ob, Mesh *me)
me->medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, me->totedge);
me->mface = CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface);
memcpy(me->mvert, me->mr->verts, sizeof(MVert) * me->totvert);
- for (i = 0; i < me->totedge; ++i) {
+ for (i = 0; i < me->totedge; i++) {
me->medge[i].v1 = lvl->edges[i].v[0];
me->medge[i].v2 = lvl->edges[i].v[1];
}
- for (i = 0; i < me->totface; ++i) {
+ for (i = 0; i < me->totface; i++) {
me->mface[i].v1 = lvl->faces[i].v[0];
me->mface[i].v2 = lvl->faces[i].v[1];
me->mface[i].v3 = lvl->faces[i].v[2];
@@ -2248,10 +2254,10 @@ void multires_load_old(Object *ob, Mesh *me)
/* Copy the first-level data to the mesh */
/* XXX We must do this before converting tessfaces to polys/lopps! */
- for (i = 0, l = me->mr->vdata.layers; i < me->mr->vdata.totlayer; ++i, ++l) {
+ for (i = 0, l = me->mr->vdata.layers; i < me->mr->vdata.totlayer; i++, l++) {
CustomData_add_layer(&me->vdata, l->type, CD_REFERENCE, l->data, me->totvert);
}
- for (i = 0, l = me->mr->fdata.layers; i < me->mr->fdata.totlayer; ++i, ++l) {
+ for (i = 0, l = me->mr->fdata.layers; i < me->mr->fdata.totlayer; i++, l++) {
CustomData_add_layer(&me->fdata, l->type, CD_REFERENCE, l->data, me->totface);
}
CustomData_reset(&me->mr->vdata);
@@ -2271,7 +2277,7 @@ void multires_load_old(Object *ob, Mesh *me)
mmd = (MultiresModifierData *)modifier_new(eModifierType_Multires);
BLI_insertlinkbefore(&ob->modifiers, md, mmd);
- for (i = 0; i < me->mr->level_count - 1; ++i) {
+ for (i = 0; i < me->mr->level_count - 1; i++) {
multiresModifier_subdivide(mmd, NULL, ob, 1, 0);
}
@@ -2337,9 +2343,9 @@ static void multires_apply_uniform_scale(Object *object, const float scale)
{
Mesh *mesh = (Mesh *)object->data;
MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS);
- for (int i = 0; i < mesh->totloop; ++i) {
+ for (int i = 0; i < mesh->totloop; i++) {
MDisps *grid = &mdisps[i];
- for (int j = 0; j < grid->totdisp; ++j) {
+ for (int j = 0; j < grid->totdisp; j++) {
mul_v3_fl(grid->disps[j], scale);
}
}
@@ -2348,7 +2354,7 @@ static void multires_apply_uniform_scale(Object *object, const float scale)
static void multires_apply_smat(struct Depsgraph *UNUSED(depsgraph),
Scene *scene,
Object *object,
- float smat[3][3])
+ const float smat[3][3])
{
const MultiresModifierData *mmd = get_multires_modifier(scene, object, true);
if (mmd == NULL || mmd->totlvl == 0) {
diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c
index 9947b96105d..4e4a8831518 100644
--- a/source/blender/blenkernel/intern/multires_reshape.c
+++ b/source/blender/blenkernel/intern/multires_reshape.c
@@ -650,7 +650,7 @@ static void multires_reshape_neighour_boundary_vertices(MultiresReshapeContext *
const int start_ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
const bool is_quad = (coarse_poly->totloop == 4);
if (corner_u == 1.0f && corner_v == 1.0f) {
- for (int current_corner = 0; current_corner < num_corners; ++current_corner) {
+ for (int current_corner = 0; current_corner < num_corners; current_corner++) {
if (current_corner == coarse_corner) {
continue;
}
@@ -795,7 +795,7 @@ static Subdiv *multires_create_subdiv_for_reshape(struct Depsgraph *depsgraph,
SubdivSettings subdiv_settings;
BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, deformed_mesh);
- if (!BKE_subdiv_eval_update_from_mesh(subdiv, deformed_mesh)) {
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, deformed_mesh, NULL)) {
BKE_subdiv_free(subdiv);
return NULL;
}
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 206c59c110a..0ef35bd3d06 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -947,6 +947,57 @@ void nodeChainIter(const bNodeTree *ntree,
}
}
+static void iter_backwards_ex(const bNodeTree *ntree,
+ const bNode *node_start,
+ bool (*callback)(bNode *, bNode *, void *),
+ void *userdata)
+{
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node_start->inputs) {
+ bNodeLink *link = sock->link;
+ if (link == NULL) {
+ continue;
+ }
+ if ((link->flag & NODE_LINK_VALID) == 0) {
+ /* Skip links marked as cyclic. */
+ continue;
+ }
+ if (link->fromnode->iter_flag) {
+ /* Only iter on nodes once. */
+ continue;
+ }
+ else {
+ link->fromnode->iter_flag = 1;
+ }
+
+ if (!callback(link->fromnode, link->tonode, userdata)) {
+ return;
+ }
+ iter_backwards_ex(ntree, link->fromnode, callback, userdata);
+ }
+}
+
+/**
+ * Iterate over a chain of nodes, starting with \a node_start, executing
+ * \a callback for each node (which can return false to end iterator).
+ *
+ * Faster than nodeChainIter. Iter only once per node.
+ *
+ * \note Needs updated socket links (ntreeUpdateTree).
+ * \note Recursive
+ */
+void nodeChainIterBackwards(const bNodeTree *ntree,
+ const bNode *node_start,
+ bool (*callback)(bNode *, bNode *, void *),
+ void *userdata)
+{
+ /* Reset flag. */
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ node->iter_flag = 0;
+ }
+
+ iter_backwards_ex(ntree, node_start, callback, userdata);
+}
+
/**
* Iterate over all parents of \a node, executing \a callback for each parent
* (which can return false to end iterator)
@@ -1406,6 +1457,7 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
}
else {
ntree = MEM_callocN(sizeof(bNodeTree), "new node tree");
+ ntree->id.flag |= LIB_PRIVATE_DATA;
*((short *)ntree->id.name) = ID_NT;
BLI_strncpy(ntree->id.name + 2, name, sizeof(ntree->id.name));
}
@@ -2172,6 +2224,7 @@ void ntreeSetOutput(bNodeTree *ntree)
* might be different for editor or for "real" use... */
}
+/* Returns the private NodeTree object of the datablock, if it has one. */
bNodeTree *ntreeFromID(const ID *id)
{
switch (GS(id->name)) {
@@ -2192,6 +2245,28 @@ bNodeTree *ntreeFromID(const ID *id)
}
}
+/* Finds and returns the datablock that privately owns the given tree, or NULL. */
+ID *BKE_node_tree_find_owner_ID(Main *bmain, struct bNodeTree *ntree)
+{
+ ListBase *lists[] = {&bmain->materials,
+ &bmain->lights,
+ &bmain->worlds,
+ &bmain->textures,
+ &bmain->scenes,
+ &bmain->linestyles,
+ NULL};
+
+ for (int i = 0; lists[i] != NULL; i++) {
+ LISTBASE_FOREACH (ID *, id, lists[i]) {
+ if (ntreeFromID(id) == ntree) {
+ return id;
+ }
+ }
+ }
+
+ return NULL;
+}
+
void ntreeMakeLocal(Main *bmain, bNodeTree *ntree, bool id_in_mainlist, const bool lib_local)
{
BKE_id_make_local_generic(bmain, &ntree->id, id_in_mainlist, lib_local);
@@ -3122,7 +3197,7 @@ void BKE_node_instance_hash_remove_untagged(bNodeInstanceHash *hash,
}
}
- for (i = 0; i < num_untagged; ++i) {
+ for (i = 0; i < num_untagged; i++) {
BKE_node_instance_hash_remove(hash, untagged[i], valfreefp);
}
@@ -3324,7 +3399,7 @@ void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
return;
}
- /* avoid reentrant updates, can be caused by RNA update callbacks */
+ /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
if (ntree->is_updating) {
return;
}
@@ -3385,7 +3460,7 @@ void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
void nodeUpdate(bNodeTree *ntree, bNode *node)
{
- /* avoid reentrant updates, can be caused by RNA update callbacks */
+ /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
if (ntree->is_updating) {
return;
}
@@ -3412,7 +3487,7 @@ bool nodeUpdateID(bNodeTree *ntree, ID *id)
return changed;
}
- /* avoid reentrant updates, can be caused by RNA update callbacks */
+ /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
if (ntree->is_updating) {
return changed;
}
@@ -3547,7 +3622,7 @@ static bool unique_socket_template_identifier_check(void *arg, const char *name)
bNodeSocketTemplate *ntemp;
} *data = arg;
- for (ntemp = data->list; ntemp->type >= 0; ++ntemp) {
+ for (ntemp = data->list; ntemp->type >= 0; ntemp++) {
if (ntemp != data->ntemp) {
if (STREQ(ntemp->identifier, name)) {
return true;
@@ -3590,22 +3665,22 @@ void node_type_socket_templates(struct bNodeType *ntype,
/* automatically generate unique identifiers */
if (inputs) {
/* clear identifier strings (uninitialized memory) */
- for (ntemp = inputs; ntemp->type >= 0; ++ntemp) {
+ for (ntemp = inputs; ntemp->type >= 0; ntemp++) {
ntemp->identifier[0] = '\0';
}
- for (ntemp = inputs; ntemp->type >= 0; ++ntemp) {
+ for (ntemp = inputs; ntemp->type >= 0; ntemp++) {
BLI_strncpy(ntemp->identifier, ntemp->name, sizeof(ntemp->identifier));
unique_socket_template_identifier(inputs, ntemp, ntemp->identifier, '_');
}
}
if (outputs) {
/* clear identifier strings (uninitialized memory) */
- for (ntemp = outputs; ntemp->type >= 0; ++ntemp) {
+ for (ntemp = outputs; ntemp->type >= 0; ntemp++) {
ntemp->identifier[0] = '\0';
}
- for (ntemp = outputs; ntemp->type >= 0; ++ntemp) {
+ for (ntemp = outputs; ntemp->type >= 0; ntemp++) {
BLI_strncpy(ntemp->identifier, ntemp->name, sizeof(ntemp->identifier));
unique_socket_template_identifier(outputs, ntemp, ntemp->identifier, '_');
}
@@ -3890,6 +3965,7 @@ static void registerShaderNodes(void)
register_node_type_sh_tex_coord();
register_node_type_sh_particle_info();
register_node_type_sh_bump();
+ register_node_type_sh_vertex_color();
register_node_type_sh_background();
register_node_type_sh_bsdf_anisotropic();
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index ae091f32fbf..f10930a2ba7 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -55,6 +55,7 @@
#include "DNA_object_types.h"
#include "DNA_lightprobe_types.h"
#include "DNA_rigidbody_types.h"
+#include "DNA_defaults.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
@@ -803,38 +804,16 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name)
}
}
-void BKE_object_init(Object *ob)
+void BKE_object_init(Object *ob, const short ob_type)
{
- /* BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(ob, id)); */ /* ob->type is already initialized... */
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(ob, id));
- copy_v4_fl(ob->color, 1.0f);
+ MEMCPY_STRUCT_AFTER(ob, DNA_struct_default_get(Object), id);
- ob->scale[0] = ob->scale[1] = ob->scale[2] = 1.0;
- ob->dscale[0] = ob->dscale[1] = ob->dscale[2] = 1.0;
+ ob->type = ob_type;
- /* objects should default to having Euler XYZ rotations,
- * but rotations default to quaternions
- */
- ob->rotmode = ROT_MODE_EUL;
-
- unit_axis_angle(ob->rotAxis, &ob->rotAngle);
- unit_axis_angle(ob->drotAxis, &ob->drotAngle);
-
- unit_qt(ob->quat);
- unit_qt(ob->dquat);
-
- /* rotation locks should be 4D for 4 component rotations by default... */
- ob->protectflag = OB_LOCK_ROT4D;
-
- unit_m4(ob->constinv);
- unit_m4(ob->parentinv);
- unit_m4(ob->obmat);
- ob->dt = OB_TEXTURE;
- ob->empty_drawtype = OB_PLAINAXES;
- ob->empty_drawsize = 1.0;
- ob->empty_image_depth = OB_EMPTY_IMAGE_DEPTH_DEFAULT;
- if (ob->type == OB_EMPTY) {
- copy_v2_fl(ob->ima_ofs, -0.5f);
+ if (ob->type != OB_EMPTY) {
+ zero_v2(ob->ima_ofs);
}
if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
@@ -846,18 +825,6 @@ void BKE_object_init(Object *ob)
ob->upflag = OB_POSZ;
}
- ob->instance_faces_scale = 1.0;
-
- ob->col_group = 0x01;
- ob->col_mask = 0xffff;
- ob->preview = NULL;
- ob->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER;
-
- /* NT fluid sim defaults */
- ob->fluidsimSettings = NULL;
-
- BLI_listbase_clear(&ob->pc_ids);
-
/* Animation Visualization defaults */
animviz_settings_init(&ob->avs);
}
@@ -877,9 +844,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
id_us_min(&ob->id);
/* default object vars */
- ob->type = type;
-
- BKE_object_init(ob);
+ BKE_object_init(ob, type);
return ob;
}
@@ -2799,6 +2764,12 @@ void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval)
ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
}
+/* -------------------------------------------------------------------- */
+/** \name Object Dimension Get/Set
+ *
+ * \warning Setting dimensions is prone to feedback loops in evaluation.
+ * \{ */
+
void BKE_object_dimensions_get(Object *ob, float vec[3])
{
BoundBox *bb = NULL;
@@ -2818,7 +2789,19 @@ void BKE_object_dimensions_get(Object *ob, float vec[3])
}
}
-void BKE_object_dimensions_set(Object *ob, const float value[3], int axis_mask)
+/**
+ * The original scale and object matrix can be passed in so any difference
+ * of the objects matrix and the final matrix can be accounted for,
+ * typically this caused by parenting, constraints or delta-scale.
+ *
+ * Re-using these values from the object causes a feedback loop
+ * when multiple values are modified at once in some situations. see: T69536.
+ */
+void BKE_object_dimensions_set_ex(Object *ob,
+ const float value[3],
+ int axis_mask,
+ const float ob_scale_orig[3],
+ const float ob_obmat_orig[4][4])
{
BoundBox *bb = NULL;
@@ -2832,7 +2815,16 @@ void BKE_object_dimensions_set(Object *ob, const float value[3], int axis_mask)
for (int i = 0; i < 3; i++) {
if (((1 << i) & axis_mask) == 0) {
+
+ if (ob_scale_orig != NULL) {
+ const float scale_delta = len_v3(ob_obmat_orig[i]) / ob_scale_orig[i];
+ if (isfinite(scale_delta)) {
+ len[i] *= scale_delta;
+ }
+ }
+
if (len[i] > 0.0f) {
+
ob->scale[i] = copysignf(value[i] / len[i], ob->scale[i]);
}
}
@@ -2840,6 +2832,11 @@ void BKE_object_dimensions_set(Object *ob, const float value[3], int axis_mask)
}
}
+void BKE_object_dimensions_set(Object *ob, const float value[3], int axis_mask)
+{
+ BKE_object_dimensions_set_ex(ob, value, axis_mask, NULL, NULL);
+}
+
void BKE_object_minmax(Object *ob, float min_r[3], float max_r[3], const bool use_hidden)
{
BoundBox bb;
@@ -2985,6 +2982,15 @@ bool BKE_object_empty_image_data_is_visible_in_view3d(const Object *ob, const Re
}
}
+ if (visibility_flag & OB_EMPTY_IMAGE_HIDE_NON_AXIS_ALIGNED) {
+ float proj[3];
+ project_plane_v3_v3v3(proj, ob->obmat[2], rv3d->viewinv[2]);
+ const float proj_length_sq = len_squared_v3(proj);
+ if (proj_length_sq > 1e-5f) {
+ return false;
+ }
+ }
+
return true;
}
@@ -3263,8 +3269,7 @@ void BKE_object_sculpt_data_create(Object *ob)
ob->sculpt->mode_type = ob->mode;
}
-int BKE_object_obdata_texspace_get(
- Object *ob, short **r_texflag, float **r_loc, float **r_size, float **r_rot)
+int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc, float **r_size)
{
if (ob->data == NULL) {
@@ -3273,14 +3278,12 @@ int BKE_object_obdata_texspace_get(
switch (GS(((ID *)ob->data)->name)) {
case ID_ME: {
- BKE_mesh_texspace_get_reference((Mesh *)ob->data, r_texflag, r_loc, r_rot, r_size);
+ BKE_mesh_texspace_get_reference((Mesh *)ob->data, r_texflag, r_loc, r_size);
break;
}
case ID_CU: {
Curve *cu = ob->data;
- if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_curve_texspace_calc(cu);
- }
+ BKE_curve_texspace_ensure(cu);
if (r_texflag) {
*r_texflag = &cu->texflag;
}
@@ -3290,9 +3293,6 @@ int BKE_object_obdata_texspace_get(
if (r_size) {
*r_size = cu->size;
}
- if (r_rot) {
- *r_rot = cu->rot;
- }
break;
}
case ID_MB: {
@@ -3306,9 +3306,6 @@ int BKE_object_obdata_texspace_get(
if (r_size) {
*r_size = mb->size;
}
- if (r_rot) {
- *r_rot = mb->rot;
- }
break;
}
default:
@@ -3871,7 +3868,7 @@ int BKE_object_scenes_users_get(Main *bmain, Object *ob)
{
int num_scenes = 0;
for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
- if (BKE_collection_has_object_recursive(BKE_collection_master(scene), ob)) {
+ if (BKE_collection_has_object_recursive(scene->master_collection, ob)) {
num_scenes++;
}
}
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 7983fe54be5..6b6c68b197e 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -93,8 +93,11 @@ typedef struct DupliGenerator {
static const DupliGenerator *get_dupli_generator(const DupliContext *ctx);
/* create initial context for root object */
-static void init_context(
- DupliContext *r_ctx, Depsgraph *depsgraph, Scene *scene, Object *ob, float space_mat[4][4])
+static void init_context(DupliContext *r_ctx,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ const float space_mat[4][4])
{
r_ctx->depsgraph = depsgraph;
r_ctx->scene = scene;
@@ -118,7 +121,7 @@ static void init_context(
/* create sub-context for recursive duplis */
static void copy_dupli_context(
- DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index)
+ DupliContext *r_ctx, const DupliContext *ctx, Object *ob, const float mat[4][4], int index)
{
*r_ctx = *ctx;
@@ -204,7 +207,7 @@ static DupliObject *make_dupli(const DupliContext *ctx, Object *ob, float mat[4]
*/
static void make_recursive_duplis(const DupliContext *ctx,
Object *ob,
- float space_mat[4][4],
+ const float space_mat[4][4],
int index)
{
/* simple preventing of too deep nested collections with MAX_DUPLI_RECUR */
@@ -398,12 +401,8 @@ static void make_child_duplis_verts(const DupliContext *ctx, void *userdata, Obj
mul_m4_m4m4(vdd->child_imat, child->imat, ctx->object->obmat);
const MVert *mvert = me_eval->mvert;
- const int *origindex = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
-
- for (int i = 0, j = 0; i < me_eval->totvert; i++) {
- if (origindex == NULL || origindex[i] != ORIGINDEX_NONE) {
- vertex_dupli(vdd, j++, mvert[i].co, mvert[i].no);
- }
+ for (int i = 0; i < me_eval->totvert; i++) {
+ vertex_dupli(vdd, i, mvert[i].co, mvert[i].no);
}
}
@@ -822,8 +821,10 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
/* gather list of objects or single object */
int totcollection = 0;
+ const bool use_whole_collection = part->draw & PART_DRAW_WHOLE_GR;
+ const bool use_collection_count = part->draw & PART_DRAW_COUNT_GR && !use_whole_collection;
if (part->ren_as == PART_DRAW_GR) {
- if (part->draw & PART_DRAW_COUNT_GR) {
+ if (use_collection_count) {
psys_find_group_weights(part);
for (dw = part->instance_weights.first; dw; dw = dw->next) {
@@ -848,7 +849,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
oblist = MEM_callocN((size_t)totcollection * sizeof(Object *), "dupcollection object list");
- if (part->draw & PART_DRAW_COUNT_GR) {
+ if (use_collection_count) {
a = 0;
for (dw = part->instance_weights.first; dw; dw = dw->next) {
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (
@@ -916,7 +917,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
}
/* for collections, pick the object based on settings */
- if (part->draw & PART_DRAW_RAND_GR) {
+ if (part->draw & PART_DRAW_RAND_GR && !use_whole_collection) {
b = BLI_rng_get_int(rng) % totcollection;
}
else {
diff --git a/source/blender/blenkernel/intern/object_facemap.c b/source/blender/blenkernel/intern/object_facemap.c
index b3ebe9b5ffa..be96927ed63 100644
--- a/source/blender/blenkernel/intern/object_facemap.c
+++ b/source/blender/blenkernel/intern/object_facemap.c
@@ -261,3 +261,41 @@ bFaceMap *BKE_object_facemap_find_name(Object *ob, const char *name)
{
return BLI_findstring(&ob->fmaps, name, offsetof(bFaceMap, name));
}
+
+int *BKE_object_facemap_index_map_create(Object *ob_src, Object *ob_dst, int *r_map_len)
+{
+ /* Build src to merged mapping of facemap indices. */
+ if (BLI_listbase_is_empty(&ob_src->fmaps) || BLI_listbase_is_empty(&ob_dst->fmaps)) {
+ *r_map_len = 0;
+ return NULL;
+ }
+
+ *r_map_len = BLI_listbase_count(&ob_src->fmaps);
+ int *fmap_index_map = MEM_malloc_arrayN(
+ *r_map_len, sizeof(*fmap_index_map), "defgroup index map create");
+ bool is_fmap_remap_needed = false;
+
+ int i = 0;
+ for (bFaceMap *fmap_src = ob_src->fmaps.first; fmap_src; fmap_src = fmap_src->next, i++) {
+ fmap_index_map[i] = BKE_object_facemap_name_index(ob_dst, fmap_src->name);
+ is_fmap_remap_needed = is_fmap_remap_needed || (fmap_index_map[i] != i);
+ }
+
+ if (!is_fmap_remap_needed) {
+ MEM_freeN(fmap_index_map);
+ fmap_index_map = NULL;
+ *r_map_len = 0;
+ }
+
+ return fmap_index_map;
+}
+
+void BKE_object_facemap_index_map_apply(int *fmap, int fmap_len, const int *map, int map_len)
+{
+ if (map == NULL || map_len == 0) {
+ return;
+ }
+ for (int i = 0; i < fmap_len; i++, fmap++) {
+ *fmap = (*fmap < map_len && *fmap != -1) ? map[*fmap] : -1;
+ }
+}
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 3a330ea0d5a..01f3f2e309b 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -453,6 +453,7 @@ void BKE_object_eval_eval_base_flags(Depsgraph *depsgraph,
object->base_flag &= ~(BASE_SELECTED | BASE_SELECTABLE);
}
object->base_local_view_bits = base->local_view_bits;
+ object->runtime.local_collections_bits = base->local_collections_bits;
if (object->mode == OB_MODE_PARTICLE_EDIT) {
for (ParticleSystem *psys = object->particlesystem.first; psys != NULL; psys = psys->next) {
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index fcceebc3913..9faa61f986d 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -521,7 +521,7 @@ static void ocean_compute_htilda(void *__restrict userdata,
/* Note the <= _N/2 here, see the FFTW documentation
* about the mechanics of the complex->real fft storage. */
- for (j = 0; j <= o->_N / 2; ++j) {
+ for (j = 0; j <= o->_N / 2; j++) {
fftw_complex exp_param1;
fftw_complex exp_param2;
fftw_complex conj_param;
@@ -560,8 +560,8 @@ static void ocean_compute_displacement_x(TaskPool *__restrict pool,
const float chop_amount = osd->chop_amount;
int i, j;
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j <= o->_N / 2; j++) {
fftw_complex mul_param;
fftw_complex minus_i;
@@ -591,8 +591,8 @@ static void ocean_compute_displacement_z(TaskPool *__restrict pool,
const float chop_amount = osd->chop_amount;
int i, j;
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j <= o->_N / 2; j++) {
fftw_complex mul_param;
fftw_complex minus_i;
@@ -621,8 +621,8 @@ static void ocean_compute_jacobian_jxx(TaskPool *__restrict pool,
const float chop_amount = osd->chop_amount;
int i, j;
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j <= o->_N / 2; j++) {
fftw_complex mul_param;
/* init_complex(mul_param, -scale, 0); */
@@ -640,8 +640,8 @@ static void ocean_compute_jacobian_jxx(TaskPool *__restrict pool,
}
fftw_execute(o->_Jxx_plan);
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j < o->_N; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j < o->_N; j++) {
o->_Jxx[i * o->_N + j] += 1.0;
}
}
@@ -656,8 +656,8 @@ static void ocean_compute_jacobian_jzz(TaskPool *__restrict pool,
const float chop_amount = osd->chop_amount;
int i, j;
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j <= o->_N / 2; j++) {
fftw_complex mul_param;
/* init_complex(mul_param, -scale, 0); */
@@ -675,8 +675,8 @@ static void ocean_compute_jacobian_jzz(TaskPool *__restrict pool,
}
fftw_execute(o->_Jzz_plan);
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j < o->_N; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j < o->_N; j++) {
o->_Jzz[i * o->_N + j] += 1.0;
}
}
@@ -691,8 +691,8 @@ static void ocean_compute_jacobian_jxz(TaskPool *__restrict pool,
const float chop_amount = osd->chop_amount;
int i, j;
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j <= o->_N / 2; j++) {
fftw_complex mul_param;
/* init_complex(mul_param, -scale, 0); */
@@ -719,8 +719,8 @@ static void ocean_compute_normal_x(TaskPool *__restrict pool,
const Ocean *o = osd->o;
int i, j;
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j <= o->_N / 2; j++) {
fftw_complex mul_param;
init_complex(mul_param, 0.0, -1.0);
@@ -740,8 +740,8 @@ static void ocean_compute_normal_z(TaskPool *__restrict pool,
const Ocean *o = osd->o;
int i, j;
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j <= o->_N / 2; j++) {
fftw_complex mul_param;
init_complex(mul_param, 0.0, -1.0);
@@ -829,8 +829,8 @@ static void set_height_normalize_factor(struct Ocean *oc)
BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ);
- for (i = 0; i < oc->_M; ++i) {
- for (j = 0; j < oc->_N; ++j) {
+ for (i = 0; i < oc->_M; i++) {
+ for (j = 0; j < oc->_N; j++) {
if (max_h < fabs(oc->_disp_y[i * oc->_N + j])) {
max_h = fabs(oc->_disp_y[i * oc->_N + j]);
}
@@ -959,28 +959,28 @@ void BKE_ocean_init(struct Ocean *o,
}
/* the +ve components and DC */
- for (i = 0; i <= o->_M / 2; ++i) {
+ for (i = 0; i <= o->_M / 2; i++) {
o->_kx[i] = 2.0f * (float)M_PI * i / o->_Lx;
}
/* the -ve components */
- for (i = o->_M - 1, ii = 0; i > o->_M / 2; --i, ++ii) {
+ for (i = o->_M - 1, ii = 0; i > o->_M / 2; i--, ii++) {
o->_kx[i] = -2.0f * (float)M_PI * ii / o->_Lx;
}
/* the +ve components and DC */
- for (i = 0; i <= o->_N / 2; ++i) {
+ for (i = 0; i <= o->_N / 2; i++) {
o->_kz[i] = 2.0f * (float)M_PI * i / o->_Lz;
}
/* the -ve components */
- for (i = o->_N - 1, ii = 0; i > o->_N / 2; --i, ++ii) {
+ for (i = o->_N - 1, ii = 0; i > o->_N / 2; i--, ii++) {
o->_kz[i] = -2.0f * (float)M_PI * ii / o->_Lz;
}
/* pre-calculate the k matrix */
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j <= o->_N / 2; j++) {
o->_k[i * (1 + o->_N / 2) + j] = sqrt(o->_kx[i] * o->_kx[i] + o->_kz[j] * o->_kz[j]);
}
}
@@ -988,8 +988,8 @@ void BKE_ocean_init(struct Ocean *o,
/*srand(seed);*/
rng = BLI_rng_new(seed);
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j < o->_N; ++j) {
+ for (i = 0; i < o->_M; i++) {
+ for (j = 0; j < o->_N; j++) {
float r1 = gaussRand(rng);
float r2 = gaussRand(rng);
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 8e647757b40..cc3b10b1207 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -141,7 +141,9 @@ int BKE_packedfile_count_all(Main *bmain)
void BKE_packedfile_free(PackedFile *pf)
{
if (pf) {
- MEM_freeN(pf->data);
+ BLI_assert(pf->data != NULL);
+
+ MEM_SAFE_FREE(pf->data);
MEM_freeN(pf);
}
else {
@@ -151,6 +153,9 @@ void BKE_packedfile_free(PackedFile *pf)
PackedFile *BKE_packedfile_duplicate(const PackedFile *pf_src)
{
+ BLI_assert(pf_src != NULL);
+ BLI_assert(pf_src->data != NULL);
+
PackedFile *pf_dst;
pf_dst = MEM_dupallocN(pf_src);
@@ -161,6 +166,8 @@ PackedFile *BKE_packedfile_duplicate(const PackedFile *pf_src)
PackedFile *BKE_packedfile_new_from_memory(void *mem, int memlen)
{
+ BLI_assert(mem != NULL);
+
PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
pf->data = mem;
pf->size = memlen;
@@ -178,7 +185,7 @@ PackedFile *BKE_packedfile_new(ReportList *reports, const char *filename, const
/* render result has no filename and can be ignored
* any other files with no name can be ignored too */
if (filename[0] == '\0') {
- return NULL;
+ return pf;
}
// XXX waitcursor(1);
@@ -260,7 +267,11 @@ void BKE_packedfile_pack_all(Main *bmain, ReportList *reports, bool verbose)
}
if (tot > 0) {
- BKE_reportf(reports, RPT_INFO, "Packed %d files", tot);
+ BKE_reportf(reports,
+ RPT_INFO,
+ tot == 1 ? "Packed %d file" :
+ "Packed %d files",
+ tot);
}
else if (verbose) {
BKE_report(reports, RPT_INFO, "No new files have been packed");
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index a46bb36c883..983127372ca 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -992,10 +992,24 @@ static void sculptsession_free_pbvh(Object *object)
{
SculptSession *ss = object->sculpt;
- if (ss && ss->pbvh) {
+ if (!ss) {
+ return;
+ }
+
+ if (ss->pbvh) {
BKE_pbvh_free(ss->pbvh);
ss->pbvh = NULL;
}
+
+ if (ss->pmap) {
+ MEM_freeN(ss->pmap);
+ ss->pmap = NULL;
+ }
+
+ if (ss->pmap_mem) {
+ MEM_freeN(ss->pmap_mem);
+ ss->pmap_mem = NULL;
+ }
}
void BKE_sculptsession_bm_to_me_for_render(Object *object)
@@ -1060,6 +1074,10 @@ void BKE_sculptsession_free(Object *ob)
MEM_freeN(ss->deform_imats);
}
+ if (ss->preview_vert_index_list) {
+ MEM_freeN(ss->preview_vert_index_list);
+ }
+
BKE_sculptsession_free_vwpaint_data(ob->sculpt);
MEM_freeN(ss);
@@ -1086,6 +1104,12 @@ MultiresModifierData *BKE_sculpt_multires_active(Scene *scene, Object *ob)
return NULL;
}
+ /* Weight paint operates on original vertices, and needs to treat multires as regular modifier
+ * to make it so that PBVH vertices are at the multires surface. */
+ if ((ob->mode & OB_MODE_SCULPT) == 0) {
+ return NULL;
+ }
+
for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); md; md = md->next) {
if (md->type == eModifierType_Multires) {
MultiresModifierData *mmd = (MultiresModifierData *)md;
@@ -1131,7 +1155,10 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
continue;
}
- if (ELEM(md->type, eModifierType_ShapeKey, eModifierType_Multires)) {
+ if (md->type == eModifierType_Multires && (ob->mode & OB_MODE_SCULPT)) {
+ continue;
+ }
+ if (md->type == eModifierType_ShapeKey) {
continue;
}
@@ -1181,8 +1208,9 @@ static void sculpt_update_object(
ss->kb = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL;
- /* VWPaint require mesh info for loop lookup, so require sculpt mode here */
- if (mmd && ob->mode & OB_MODE_SCULPT) {
+ /* NOTE: Weight pPaint require mesh info for loop lookup, but it never uses multires code path,
+ * so no extra checks is needed here. */
+ if (mmd) {
ss->multires = mmd;
ss->totvert = me_eval->totvert;
ss->totpoly = me_eval->totpoly;
@@ -1206,9 +1234,7 @@ static void sculpt_update_object(
BLI_assert(pbvh == ss->pbvh);
UNUSED_VARS_NDEBUG(pbvh);
- MEM_SAFE_FREE(ss->pmap);
- MEM_SAFE_FREE(ss->pmap_mem);
- if (need_pmap && ob->type == OB_MESH) {
+ if (need_pmap && ob->type == OB_MESH && !ss->pmap) {
BKE_mesh_vert_poly_map_create(
&ss->pmap, &ss->pmap_mem, me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop);
}
@@ -1227,7 +1253,7 @@ static void sculpt_update_object(
BKE_crazyspace_build_sculpt(depsgraph, scene, ob, &ss->deform_imats, &ss->deform_cos);
BKE_pbvh_vert_coords_apply(ss->pbvh, ss->deform_cos, me->totvert);
- for (a = 0; a < me->totvert; ++a) {
+ for (a = 0; a < me->totvert; a++) {
invert_m3(ss->deform_imats[a]);
}
}
@@ -1268,7 +1294,7 @@ void BKE_sculpt_update_object_before_eval(Object *ob)
SculptSession *ss = ob->sculpt;
if (ss && ss->building_vp_handle == false) {
- if (!ss->cache) {
+ if (!ss->cache && !ss->filter_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 ffeba0148a2..74fbfc318a8 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -88,7 +88,7 @@ float PSYS_FRAND_BASE[PSYS_FRAND_COUNT];
void psys_init_rng(void)
{
RNG *rng = BLI_rng_new_srandom(5831); /* arbitrary */
- for (int i = 0; i < PSYS_FRAND_COUNT; ++i) {
+ for (int i = 0; i < PSYS_FRAND_COUNT; i++) {
PSYS_FRAND_BASE[i] = BLI_rng_get_float(rng);
PSYS_FRAND_SEED_OFFSET[i] = (unsigned int)BLI_rng_get_int(rng);
PSYS_FRAND_SEED_MULTIPLIER[i] = (unsigned int)BLI_rng_get_int(rng);
@@ -2691,7 +2691,7 @@ static void psys_thread_create_path(ParticleTask *task,
pa = &psys->particles[cpa->parent];
par = pcache[cpa->parent];
- /* If particle is unexisting, try to pick a viable parent from particles
+ /* If particle is non-existing, try to pick a viable parent from particles
* used for interpolation. */
for (k = 0; k < 4 && pa && (pa->flag & PARS_UNEXIST); k++) {
if (cpa->pa[k] >= 0) {
@@ -2747,7 +2747,7 @@ static void exec_child_path_cache(TaskPool *__restrict UNUSED(pool),
int i;
cpa = psys->child + task->begin;
- for (i = task->begin; i < task->end; ++i, ++cpa) {
+ for (i = task->begin; i < task->end; i++, cpa++) {
BLI_assert(i < psys->totchildcache);
psys_thread_create_path(task, cpa, cache[i], i);
}
@@ -2794,7 +2794,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim,
/* cache parent paths */
ctx.parent_pass = 1;
psys_tasks_create(&ctx, 0, totparent, &tasks_parent, &numtasks_parent);
- for (i = 0; i < numtasks_parent; ++i) {
+ for (i = 0; i < numtasks_parent; i++) {
ParticleTask *task = &tasks_parent[i];
psys_task_init_path(task, sim);
@@ -2805,7 +2805,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim,
/* cache child paths */
ctx.parent_pass = 0;
psys_tasks_create(&ctx, totparent, totchild, &tasks_child, &numtasks_child);
- for (i = 0; i < numtasks_child; ++i) {
+ for (i = 0; i < numtasks_child; i++) {
ParticleTask *task = &tasks_child[i];
psys_task_init_path(task, sim);
@@ -3011,7 +3011,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
if (part->type == PART_HAIR) {
HairKey *hkey;
- for (k = 0, hkey = pa->hair; k < pa->totkey; ++k, ++hkey) {
+ for (k = 0, hkey = pa->hair; k < pa->totkey; k++, hkey++) {
mul_v3_m4v3(hkey->world_co, hairmat, hkey->co);
}
}
@@ -4068,9 +4068,7 @@ void psys_get_texture(
0,
texvec);
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
+ BKE_mesh_texspace_ensure(me);
sub_v3_v3(texvec, me->loc);
if (me->size[0] != 0.0f) {
texvec[0] /= me->size[0];
diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c
index 3b02e010e7f..dcd2a0b8fae 100644
--- a/source/blender/blenkernel/intern/particle_child.c
+++ b/source/blender/blenkernel/intern/particle_child.c
@@ -381,7 +381,7 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx,
}
/* we have to correct velocity because of kink & clump */
- for (k = 0, key = keys; k < totkeys; ++k, ++key) {
+ for (k = 0, key = keys; k < totkeys; k++, key++) {
if (k >= 2) {
sub_v3_v3v3((key - 1)->vel, key->co, (key - 2)->co);
mul_v3_fl((key - 1)->vel, 0.5);
@@ -657,7 +657,7 @@ float do_clump(ParticleKey *state,
}
static void do_rough(const float loc[3],
- float mat[4][4],
+ const float mat[4][4],
float t,
float fac,
float size,
@@ -701,7 +701,7 @@ static void do_rough_end(
}
static void do_rough_curve(const float loc[3],
- float mat[4][4],
+ const float mat[4][4],
float time,
float fac,
float size,
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 27d85b91ba4..1189785ce0f 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -787,17 +787,17 @@ static void exec_distribute_parent(TaskPool *__restrict UNUSED(pool),
pa = psys->particles + task->begin;
switch (psys->part->from) {
case PART_FROM_FACE:
- for (p = task->begin; p < task->end; ++p, ++pa) {
+ for (p = task->begin; p < task->end; p++, pa++) {
distribute_from_faces_exec(task, pa, p);
}
break;
case PART_FROM_VOLUME:
- for (p = task->begin; p < task->end; ++p, ++pa) {
+ for (p = task->begin; p < task->end; p++, pa++) {
distribute_from_volume_exec(task, pa, p);
}
break;
case PART_FROM_VERT:
- for (p = task->begin; p < task->end; ++p, ++pa) {
+ for (p = task->begin; p < task->end; p++, pa++) {
distribute_from_verts_exec(task, pa, p);
}
break;
@@ -815,11 +815,11 @@ static void exec_distribute_child(TaskPool *__restrict UNUSED(pool),
/* RNG skipping at the beginning */
cpa = psys->child;
- for (p = 0; p < task->begin; ++p, ++cpa) {
+ for (p = 0; p < task->begin; p++, cpa++) {
BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP);
}
- for (; p < task->end; ++p, ++cpa) {
+ for (; p < task->end; p++, cpa++) {
distribute_children_exec(task, cpa, p);
}
}
@@ -1341,7 +1341,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
totpart = (from == PART_FROM_CHILD ? sim->psys->totchild : sim->psys->totpart);
psys_tasks_create(&ctx, 0, totpart, &tasks, &numtasks);
- for (i = 0; i < numtasks; ++i) {
+ for (i = 0; i < numtasks; i++) {
ParticleTask *task = &tasks[i];
psys_task_init_distribute(task, sim);
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index e328ae8952e..43484a57f1c 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -501,7 +501,7 @@ void psys_tasks_free(ParticleTask *tasks, int numtasks)
int i;
/* threads */
- for (i = 0; i < numtasks; ++i) {
+ for (i = 0; i < numtasks; i++) {
if (tasks[i].rng) {
BLI_rng_free(tasks[i].rng);
}
@@ -1695,7 +1695,7 @@ typedef struct SPHRangeData {
static void sph_evaluate_func(BVHTree *tree,
ParticleSystem **psys,
- float co[3],
+ const float co[3],
SPHRangeData *pfr,
float interaction_radius,
BVHTree_RangeQuery callback)
@@ -2497,7 +2497,7 @@ static float collision_point_distance_with_normal(
return 0;
}
static void collision_point_on_surface(
- float p[3], ParticleCollisionElement *pce, float fac, ParticleCollision *col, float *co)
+ const float p[3], ParticleCollisionElement *pce, float fac, ParticleCollision *col, float *co)
{
collision_interpolate_element(pce, 0.f, fac, col);
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index cea68a0c525..7ed986204d5 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -36,7 +36,6 @@
#include "BKE_paint.h"
#include "GPU_buffers.h"
-#include "GPU_immediate.h"
#include "bmesh.h"
@@ -52,8 +51,6 @@
#define STACK_FIXED_DEPTH 100
-#define PBVH_THREADED_LIMIT 4
-
typedef struct PBVHStack {
PBVHNode *node;
bool revisiting;
@@ -80,7 +77,7 @@ void BB_reset(BB *bb)
/* Expand the bounding box to include a new coordinate */
void BB_expand(BB *bb, const float co[3])
{
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
bb->bmin[i] = min_ff(bb->bmin[i], co[i]);
bb->bmax[i] = max_ff(bb->bmax[i], co[i]);
}
@@ -89,7 +86,7 @@ void BB_expand(BB *bb, const float co[3])
/* Expand the bounding box to include another bounding box */
void BB_expand_with_bb(BB *bb, BB *bb2)
{
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
bb->bmin[i] = min_ff(bb->bmin[i], bb2->bmin[i]);
bb->bmax[i] = max_ff(bb->bmax[i], bb2->bmax[i]);
}
@@ -100,7 +97,7 @@ int BB_widest_axis(const BB *bb)
{
float dim[3];
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
dim[i] = bb->bmax[i] - bb->bmin[i];
}
@@ -124,7 +121,7 @@ int BB_widest_axis(const BB *bb)
void BBC_update_centroid(BBC *bbc)
{
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
bbc->bcentroid[i] = (bbc->bmin[i] + bbc->bmax[i]) * 0.5f;
}
}
@@ -294,9 +291,9 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
node->face_vert_indices = (const int(*)[3])face_vert_indices;
- for (int i = 0; i < totface; ++i) {
+ for (int i = 0; i < totface; i++) {
const MLoopTri *lt = &bvh->looptri[node->prim_indices[i]];
- for (int j = 0; j < 3; ++j) {
+ for (int j = 0; j < 3; j++) {
face_vert_indices[i][j] = map_insert_vert(
bvh, map, &node->face_verts, &node->uniq_verts, bvh->mloop[lt->tri[j]].v);
}
@@ -323,10 +320,10 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
vert_indices[ndx] = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter));
}
- for (int i = 0; i < totface; ++i) {
+ for (int i = 0; i < totface; i++) {
const int sides = 3;
- for (int j = 0; j < sides; ++j) {
+ for (int j = 0; j < sides; j++) {
if (face_vert_indices[i][j] < 0) {
face_vert_indices[i][j] = -face_vert_indices[i][j] + node->uniq_verts - 1;
}
@@ -343,7 +340,7 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
static void update_vb(PBVH *bvh, PBVHNode *node, BBC *prim_bbc, int offset, int count)
{
BB_reset(&node->vb);
- for (int i = offset + count - 1; i >= offset; --i) {
+ for (int i = offset + count - 1; i >= offset; i--) {
BB_expand_with_bb(&node->vb, (BB *)(&prim_bbc[bvh->prim_indices[i]]));
}
node->orig_vb = node->vb;
@@ -420,7 +417,7 @@ static bool leaf_needs_material_split(PBVH *bvh, int offset, int count)
const MLoopTri *first = &bvh->looptri[bvh->prim_indices[offset]];
const MPoly *mp = &bvh->mpoly[first->poly];
- for (int i = offset + count - 1; i > offset; --i) {
+ for (int i = offset + count - 1; i > offset; i--) {
int prim = bvh->prim_indices[i];
const MPoly *mp_other = &bvh->mpoly[bvh->looptri[prim].poly];
if (!face_materials_match(mp, mp_other)) {
@@ -431,7 +428,7 @@ static bool leaf_needs_material_split(PBVH *bvh, int offset, int count)
else {
const DMFlagMat *first = &bvh->grid_flag_mats[bvh->prim_indices[offset]];
- for (int i = offset + count - 1; i > offset; --i) {
+ for (int i = offset + count - 1; i > offset; i--) {
int prim = bvh->prim_indices[i];
if (!grid_materials_match(first, &bvh->grid_flag_mats[prim])) {
return true;
@@ -479,7 +476,7 @@ static void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, int offs
if (!cb) {
cb = &cb_backing;
BB_reset(cb);
- for (int i = offset + count - 1; i >= offset; --i) {
+ for (int i = offset + count - 1; i >= offset; i--) {
BB_expand(cb, prim_bbc[bvh->prim_indices[i]].bcentroid);
}
}
@@ -515,7 +512,7 @@ static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim)
MEM_freeN(bvh->prim_indices);
}
bvh->prim_indices = MEM_mallocN(sizeof(int) * totprim, "bvh prim indices");
- for (int i = 0; i < totprim; ++i) {
+ for (int i = 0; i < totprim; i++) {
bvh->prim_indices[i] = i;
}
bvh->totnode = 0;
@@ -564,14 +561,14 @@ void BKE_pbvh_build_mesh(PBVH *bvh,
/* For each face, store the AABB and the AABB centroid */
prim_bbc = MEM_mallocN(sizeof(BBC) * looptri_num, "prim_bbc");
- for (int i = 0; i < looptri_num; ++i) {
+ for (int i = 0; i < looptri_num; i++) {
const MLoopTri *lt = &looptri[i];
const int sides = 3;
BBC *bbc = prim_bbc + i;
BB_reset((BB *)bbc);
- for (int j = 0; j < sides; ++j) {
+ for (int j = 0; j < sides; j++) {
BB_expand((BB *)bbc, verts[bvh->mloop[lt->tri[j]].v].co);
}
@@ -614,13 +611,13 @@ void BKE_pbvh_build_grids(PBVH *bvh,
/* For each grid, store the AABB and the AABB centroid */
BBC *prim_bbc = MEM_mallocN(sizeof(BBC) * totgrid, "prim_bbc");
- for (int i = 0; i < totgrid; ++i) {
+ for (int i = 0; i < totgrid; i++) {
CCGElem *grid = grids[i];
BBC *bbc = prim_bbc + i;
BB_reset((BB *)bbc);
- for (int j = 0; j < gridsize * gridsize; ++j) {
+ for (int j = 0; j < gridsize * gridsize; j++) {
BB_expand((BB *)bbc, CCG_elem_offset_co(key, grid, j));
}
@@ -645,7 +642,7 @@ PBVH *BKE_pbvh_new(void)
void BKE_pbvh_free(PBVH *bvh)
{
- for (int i = 0; i < bvh->totnode; ++i) {
+ for (int i = 0; i < bvh->totnode; i++) {
PBVHNode *node = &bvh->nodes[i];
if (node->flag & PBVH_Leaf) {
@@ -697,7 +694,7 @@ void BKE_pbvh_free(PBVH *bvh)
void BKE_pbvh_free_layer_disp(PBVH *bvh)
{
- for (int i = 0; i < bvh->totnode; ++i) {
+ for (int i = 0; i < bvh->totnode; i++) {
BKE_pbvh_node_layer_disp_free(&bvh->nodes[i]);
}
}
@@ -991,6 +988,7 @@ typedef struct PBVHUpdateData {
float (*vnors)[3];
int flag;
+ bool show_vcol;
} PBVHUpdateData;
static void pbvh_update_normals_accum_task_cb(void *__restrict userdata,
@@ -1010,7 +1008,7 @@ static void pbvh_update_normals_accum_task_cb(void *__restrict userdata,
const int *faces = node->prim_indices;
const int totface = node->totprim;
- for (int i = 0; i < totface; ++i) {
+ for (int i = 0; i < totface; i++) {
const MLoopTri *lt = &bvh->looptri[faces[i]];
const unsigned int vtri[3] = {
bvh->mloop[lt->tri[0]].v,
@@ -1056,15 +1054,16 @@ static void pbvh_update_normals_store_task_cb(void *__restrict userdata,
const int *verts = node->vert_indices;
const int totvert = node->uniq_verts;
- for (int i = 0; i < totvert; ++i) {
+ for (int i = 0; i < totvert; i++) {
const int v = verts[i];
MVert *mvert = &bvh->verts[v];
- /* mvert is shared between nodes, hence between threads. */
- if (atomic_fetch_and_and_char(&mvert->flag, (char)~ME_VERT_PBVH_UPDATE) &
- ME_VERT_PBVH_UPDATE) {
+ /* No atomics necessary because we are iterating over uniq_verts only,
+ * so we know only this thread will handle this vertex. */
+ if (mvert->flag & ME_VERT_PBVH_UPDATE) {
normalize_v3(vnors[v]);
normal_float_to_short_v3(mvert->no, vnors[v]);
+ mvert->flag &= ~ME_VERT_PBVH_UPDATE;
}
}
@@ -1095,8 +1094,7 @@ static void pbvh_faces_update_normals(PBVH *bvh, PBVHNode **nodes, int totnode)
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (totnode > PBVH_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings);
@@ -1105,6 +1103,56 @@ static void pbvh_faces_update_normals(PBVH *bvh, PBVHNode **nodes, int totnode)
MEM_freeN(vnors);
}
+static void pbvh_update_mask_redraw_task_cb(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+
+ PBVHUpdateData *data = userdata;
+ PBVH *bvh = data->bvh;
+ PBVHNode *node = data->nodes[n];
+ if (node->flag & PBVH_UpdateMask) {
+
+ bool has_unmasked = false;
+ bool has_masked = true;
+ if (node->flag & PBVH_Leaf) {
+ PBVHVertexIter vd;
+
+ BKE_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ if (vd.mask && *vd.mask < 1.0f) {
+ has_unmasked = true;
+ }
+ if (vd.mask && *vd.mask > 0.0f) {
+ has_masked = false;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+ else {
+ has_unmasked = true;
+ has_masked = true;
+ }
+ BKE_pbvh_node_fully_masked_set(node, !has_unmasked);
+ BKE_pbvh_node_fully_unmasked_set(node, has_masked);
+
+ node->flag &= ~PBVH_UpdateMask;
+ }
+}
+
+static void pbvh_update_mask_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag)
+{
+ PBVHUpdateData data = {
+ .bvh = bvh,
+ .nodes = nodes,
+ .flag = flag,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_mask_redraw_task_cb, &settings);
+}
+
static void pbvh_update_BB_redraw_task_cb(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict UNUSED(tls))
@@ -1139,8 +1187,7 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag)
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (totnode > PBVH_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings);
}
@@ -1152,71 +1199,105 @@ static int pbvh_get_buffers_update_flags(PBVH *bvh, bool show_vcol)
return update_flags;
}
-static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode, bool show_vcol)
-{
- /* can't be done in parallel with OpenGL */
- for (int n = 0; n < totnode; n++) {
- PBVHNode *node = nodes[n];
-
- if (node->flag & PBVH_RebuildDrawBuffers) {
- GPU_pbvh_buffers_free(node->draw_buffers);
- switch (bvh->type) {
- case PBVH_GRIDS:
- node->draw_buffers = GPU_pbvh_grid_buffers_build(node->totprim, bvh->grid_hidden);
- break;
- case PBVH_FACES:
- node->draw_buffers = GPU_pbvh_mesh_buffers_build(node->face_vert_indices,
- bvh->mpoly,
- bvh->mloop,
- bvh->looptri,
- bvh->verts,
- node->prim_indices,
- node->totprim);
- break;
- case PBVH_BMESH:
- node->draw_buffers = GPU_pbvh_bmesh_buffers_build(bvh->flags &
- PBVH_DYNTOPO_SMOOTH_SHADING);
- break;
- }
-
- node->flag &= ~PBVH_RebuildDrawBuffers;
- }
+static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ /* Create and update draw buffers. The functions called here must not
+ * do any OpenGL calls. Flags are not cleared immediately, that happens
+ * after GPU_pbvh_buffer_flush() which does the final OpenGL calls. */
+ PBVHUpdateData *data = userdata;
+ PBVH *bvh = data->bvh;
+ PBVHNode *node = data->nodes[n];
- if (node->flag & PBVH_UpdateDrawBuffers) {
- const int update_flags = pbvh_get_buffers_update_flags(bvh, show_vcol);
- switch (bvh->type) {
- case PBVH_GRIDS:
- GPU_pbvh_grid_buffers_update(node->draw_buffers,
- bvh->grids,
- bvh->grid_flag_mats,
- node->prim_indices,
- node->totprim,
- &bvh->gridkey,
- update_flags);
- break;
- case PBVH_FACES:
- GPU_pbvh_mesh_buffers_update(node->draw_buffers,
- bvh->verts,
- node->vert_indices,
- node->uniq_verts + node->face_verts,
- CustomData_get_layer(bvh->vdata, CD_PAINT_MASK),
- CustomData_get_layer(bvh->ldata, CD_MLOOPCOL),
- node->face_vert_indices,
- update_flags);
- break;
- case PBVH_BMESH:
- GPU_pbvh_bmesh_buffers_update(node->draw_buffers,
- bvh->bm,
- node->bm_faces,
- node->bm_unique_verts,
- node->bm_other_verts,
- update_flags);
- break;
+ if (node->flag & PBVH_RebuildDrawBuffers) {
+ switch (bvh->type) {
+ case PBVH_GRIDS:
+ node->draw_buffers = GPU_pbvh_grid_buffers_build(node->totprim, bvh->grid_hidden);
+ break;
+ case PBVH_FACES:
+ node->draw_buffers = GPU_pbvh_mesh_buffers_build(node->face_vert_indices,
+ bvh->mpoly,
+ bvh->mloop,
+ bvh->looptri,
+ bvh->verts,
+ node->prim_indices,
+ node->totprim);
+ break;
+ case PBVH_BMESH:
+ node->draw_buffers = GPU_pbvh_bmesh_buffers_build(bvh->flags &
+ PBVH_DYNTOPO_SMOOTH_SHADING);
+ break;
+ }
+ }
+
+ if (node->flag & PBVH_UpdateDrawBuffers) {
+ const int update_flags = pbvh_get_buffers_update_flags(bvh, data->show_vcol);
+ switch (bvh->type) {
+ case PBVH_GRIDS:
+ GPU_pbvh_grid_buffers_update(node->draw_buffers,
+ bvh->grids,
+ bvh->grid_flag_mats,
+ node->prim_indices,
+ node->totprim,
+ &bvh->gridkey,
+ update_flags);
+ break;
+ case PBVH_FACES:
+ GPU_pbvh_mesh_buffers_update(node->draw_buffers,
+ bvh->verts,
+ node->vert_indices,
+ node->uniq_verts + node->face_verts,
+ CustomData_get_layer(bvh->vdata, CD_PAINT_MASK),
+ CustomData_get_layer(bvh->ldata, CD_MLOOPCOL),
+ node->face_vert_indices,
+ update_flags);
+ break;
+ case PBVH_BMESH:
+ GPU_pbvh_bmesh_buffers_update(node->draw_buffers,
+ bvh->bm,
+ node->bm_faces,
+ node->bm_unique_verts,
+ node->bm_other_verts,
+ update_flags);
+ break;
+ }
+ }
+}
+
+static void pbvh_update_draw_buffers(
+ PBVH *bvh, PBVHNode **nodes, int totnode, bool show_vcol, int update_flag)
+{
+ if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(bvh->type, PBVH_GRIDS, PBVH_BMESH)) {
+ /* Free buffers uses OpenGL, so not in parallel. */
+ for (int n = 0; n < totnode; n++) {
+ PBVHNode *node = nodes[n];
+ if (node->flag & PBVH_RebuildDrawBuffers) {
+ GPU_pbvh_buffers_free(node->draw_buffers);
+ node->draw_buffers = NULL;
+ }
+ else if ((node->flag & PBVH_UpdateDrawBuffers) && node->draw_buffers) {
+ if (bvh->type == PBVH_GRIDS) {
+ GPU_pbvh_grid_buffers_update_free(
+ node->draw_buffers, bvh->grid_flag_mats, node->prim_indices);
+ }
+ else if (bvh->type == PBVH_BMESH) {
+ GPU_pbvh_bmesh_buffers_update_free(node->draw_buffers);
+ }
}
-
- node->flag &= ~PBVH_UpdateDrawBuffers;
}
}
+
+ /* Parallel creation and update of draw buffers. */
+ PBVHUpdateData data = {
+ .bvh = bvh,
+ .nodes = nodes,
+ .show_vcol = show_vcol,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_draw_buffer_cb, &settings);
}
static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag)
@@ -1271,6 +1352,24 @@ void BKE_pbvh_update_bounds(PBVH *bvh, int flag)
pbvh_flush_bb(bvh, bvh->nodes, flag);
}
+ MEM_SAFE_FREE(nodes);
+}
+
+void BKE_pbvh_update_vertex_data(PBVH *bvh, int flag)
+{
+ if (!bvh->nodes) {
+ return;
+ }
+
+ PBVHNode **nodes;
+ int totnode;
+
+ BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(flag), &nodes, &totnode);
+
+ if (flag & (PBVH_UpdateMask)) {
+ pbvh_update_mask_redraw(bvh, nodes, totnode, flag);
+ }
+
if (nodes) {
MEM_freeN(nodes);
}
@@ -1308,7 +1407,7 @@ void BKE_pbvh_get_grid_updates(PBVH *bvh, bool clear, void ***r_gridfaces, int *
while ((node = pbvh_iter_next(&iter))) {
if (node->flag & PBVH_UpdateNormals) {
- for (unsigned i = 0; i < node->totprim; ++i) {
+ for (unsigned i = 0; i < node->totprim; i++) {
void *face = bvh->gridfaces[node->prim_indices[i]];
BLI_gset_add(face_set, face);
}
@@ -1379,19 +1478,24 @@ BLI_bitmap **BKE_pbvh_grid_hidden(const PBVH *bvh)
return bvh->grid_hidden;
}
-void BKE_pbvh_get_grid_key(const PBVH *bvh, CCGKey *key)
+const CCGKey *BKE_pbvh_get_grid_key(const PBVH *bvh)
{
BLI_assert(bvh->type == PBVH_GRIDS);
- *key = bvh->gridkey;
+ return &bvh->gridkey;
}
-struct CCGElem **BKE_pbvh_get_grids(const PBVH *bvh, int *num_grids)
+struct CCGElem **BKE_pbvh_get_grids(const PBVH *bvh)
{
BLI_assert(bvh->type == PBVH_GRIDS);
- *num_grids = bvh->totgrid;
return bvh->grids;
}
+int BKE_pbvh_get_grid_num_vertices(const PBVH *bvh)
+{
+ BLI_assert(bvh->type == PBVH_GRIDS);
+ return bvh->totgrid * bvh->gridkey.grid_area;
+}
+
BMesh *BKE_pbvh_get_bmesh(PBVH *bvh)
{
BLI_assert(bvh->type == PBVH_BMESH);
@@ -1406,6 +1510,11 @@ void BKE_pbvh_node_mark_update(PBVHNode *node)
PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
}
+void BKE_pbvh_node_mark_update_mask(PBVHNode *node)
+{
+ node->flag |= PBVH_UpdateMask | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
+}
+
void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node)
{
node->flag |= PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
@@ -1433,6 +1542,40 @@ void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden)
}
}
+void BKE_pbvh_node_fully_masked_set(PBVHNode *node, int fully_masked)
+{
+ BLI_assert(node->flag & PBVH_Leaf);
+
+ if (fully_masked) {
+ node->flag |= PBVH_FullyMasked;
+ }
+ else {
+ node->flag &= ~PBVH_FullyMasked;
+ }
+}
+
+bool BKE_pbvh_node_fully_masked_get(PBVHNode *node)
+{
+ return (node->flag & PBVH_Leaf) && (node->flag & PBVH_FullyMasked);
+}
+
+void BKE_pbvh_node_fully_unmasked_set(PBVHNode *node, int fully_masked)
+{
+ BLI_assert(node->flag & PBVH_Leaf);
+
+ if (fully_masked) {
+ node->flag |= PBVH_FullyUnmasked;
+ }
+ else {
+ node->flag &= ~PBVH_FullyUnmasked;
+ }
+}
+
+bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node)
+{
+ return (node->flag & PBVH_Leaf) && (node->flag & PBVH_FullyUnmasked);
+}
+
void BKE_pbvh_node_get_verts(PBVH *bvh,
PBVHNode *node,
const int **r_vert_indices,
@@ -1572,8 +1715,8 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
/**
* \note doing a full search on all vertices here seems expensive,
- * however this is important to avoid having to recalculate boundbox & sync the buffers to the GPU
- * (which is far more expensive!) See: T47232.
+ * however this is important to avoid having to recalculate boundbox & sync the buffers to the
+ * GPU (which is far more expensive!) See: T47232.
*/
bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node)
{
@@ -1581,7 +1724,7 @@ bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node)
const int *verts = node->vert_indices;
const int totvert = node->uniq_verts + node->face_verts;
- for (int i = 0; i < totvert; ++i) {
+ for (int i = 0; i < totvert; i++) {
const int v = verts[i];
const MVert *mvert = &bvh->verts[v];
@@ -1753,16 +1896,23 @@ static bool pbvh_faces_node_raycast(PBVH *bvh,
const PBVHNode *node,
float (*origco)[3],
const float ray_start[3],
+ const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
- float *depth)
+ float *depth,
+ int *r_active_vertex_index,
+ float *r_face_normal)
{
const MVert *vert = bvh->verts;
const MLoop *mloop = bvh->mloop;
const int *faces = node->prim_indices;
int i, totface = node->totprim;
bool hit = false;
+ float min_depth = FLT_MAX;
+ float location[3] = {0.0f};
+ float nearest_vertex_co[3];
+ copy_v3_fl(nearest_vertex_co, 0.0f);
- for (i = 0; i < totface; ++i) {
+ for (i = 0; i < totface; i++) {
const MLoopTri *lt = &bvh->looptri[faces[i]];
const int *face_verts = node->face_vert_indices[i];
@@ -1787,6 +1937,22 @@ static bool pbvh_faces_node_raycast(PBVH *bvh,
vert[mloop[lt->tri[1]].v].co,
vert[mloop[lt->tri[2]].v].co,
depth);
+
+ if (hit && *depth < min_depth) {
+ min_depth = *depth;
+ normal_tri_v3(r_face_normal,
+ vert[mloop[lt->tri[0]].v].co,
+ vert[mloop[lt->tri[1]].v].co,
+ vert[mloop[lt->tri[2]].v].co);
+ madd_v3_v3v3fl(location, ray_start, ray_normal, *depth);
+ for (int j = 0; j < 3; j++) {
+ if (len_squared_v3v3(location, vert[mloop[lt->tri[j]].v].co) <
+ len_squared_v3v3(location, nearest_vertex_co)) {
+ copy_v3_v3(nearest_vertex_co, vert[mloop[lt->tri[j]].v].co);
+ *r_active_vertex_index = mloop[lt->tri[j]].v;
+ }
+ }
+ }
}
}
@@ -1804,7 +1970,7 @@ static bool pbvh_grids_node_raycast(PBVH *bvh,
const int gridsize = bvh->gridkey.grid_size;
bool hit = false;
- for (int i = 0; i < totgrid; ++i) {
+ for (int i = 0; i < totgrid; i++) {
CCGElem *grid = bvh->grids[node->prim_indices[i]];
BLI_bitmap *gh;
@@ -1814,8 +1980,8 @@ static bool pbvh_grids_node_raycast(PBVH *bvh,
gh = bvh->grid_hidden[node->prim_indices[i]];
- for (int y = 0; y < gridsize - 1; ++y) {
- for (int x = 0; x < gridsize - 1; ++x) {
+ for (int y = 0; y < gridsize - 1; y++) {
+ for (int x = 0; x < gridsize - 1; x++) {
/* check if grid face is hidden */
if (gh) {
if (paint_is_grid_face_hidden(gh, gridsize, x, y)) {
@@ -1857,8 +2023,11 @@ bool BKE_pbvh_node_raycast(PBVH *bvh,
float (*origco)[3],
bool use_origco,
const float ray_start[3],
+ const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
- float *depth)
+ float *depth,
+ int *active_vertex_index,
+ float *face_normal)
{
bool hit = false;
@@ -1868,13 +2037,29 @@ bool BKE_pbvh_node_raycast(PBVH *bvh,
switch (bvh->type) {
case PBVH_FACES:
- hit |= pbvh_faces_node_raycast(bvh, node, origco, ray_start, isect_precalc, depth);
+ hit |= pbvh_faces_node_raycast(bvh,
+ node,
+ origco,
+ ray_start,
+ ray_normal,
+ isect_precalc,
+ depth,
+ active_vertex_index,
+ face_normal);
break;
case PBVH_GRIDS:
hit |= pbvh_grids_node_raycast(bvh, node, origco, ray_start, isect_precalc, depth);
break;
case PBVH_BMESH:
- hit = pbvh_bmesh_node_raycast(node, ray_start, isect_precalc, depth, use_origco);
+ BM_mesh_elem_index_ensure(bvh->bm, BM_VERT);
+ hit = pbvh_bmesh_node_raycast(node,
+ ray_start,
+ ray_normal,
+ isect_precalc,
+ depth,
+ use_origco,
+ active_vertex_index,
+ face_normal);
break;
}
@@ -1987,7 +2172,7 @@ static bool pbvh_faces_node_nearest_to_ray(PBVH *bvh,
int i, totface = node->totprim;
bool hit = false;
- for (i = 0; i < totface; ++i) {
+ for (i = 0; i < totface; i++) {
const MLoopTri *lt = &bvh->looptri[faces[i]];
const int *face_verts = node->face_vert_indices[i];
@@ -2032,7 +2217,7 @@ static bool pbvh_grids_node_nearest_to_ray(PBVH *bvh,
const int gridsize = bvh->gridkey.grid_size;
bool hit = false;
- for (int i = 0; i < totgrid; ++i) {
+ for (int i = 0; i < totgrid; i++) {
CCGElem *grid = bvh->grids[node->prim_indices[i]];
BLI_bitmap *gh;
@@ -2042,8 +2227,8 @@ static bool pbvh_grids_node_nearest_to_ray(PBVH *bvh,
gh = bvh->grid_hidden[node->prim_indices[i]];
- for (int y = 0; y < gridsize - 1; ++y) {
- for (int x = 0; x < gridsize - 1; ++x) {
+ for (int y = 0; y < gridsize - 1; y++) {
+ for (int x = 0; x < gridsize - 1; x++) {
/* check if grid face is hidden */
if (gh) {
if (paint_is_grid_face_hidden(gh, gridsize, x, y)) {
@@ -2126,16 +2311,18 @@ typedef enum {
* Returns true if the AABB is at least partially within the frustum
* (ok, not a real frustum), false otherwise.
*/
-static PlaneAABBIsect test_planes_aabb(const float bb_min[3],
- const float bb_max[3],
- const float (*planes)[4])
+static PlaneAABBIsect test_frustum_aabb(const float bb_min[3],
+ const float bb_max[3],
+ PBVHFrustumPlanes *frustum)
{
- float vmin[3], vmax[3];
PlaneAABBIsect ret = ISECT_INSIDE;
+ float(*planes)[4] = frustum->planes;
- for (int i = 0; i < 4; ++i) {
- for (int axis = 0; axis < 3; ++axis) {
- if (planes[i][axis] > 0) {
+ for (int i = 0; i < frustum->num_planes; i++) {
+ float vmin[3], vmax[3];
+
+ for (int axis = 0; axis < 3; axis++) {
+ if (planes[i][axis] < 0) {
vmin[axis] = bb_min[axis];
vmax[axis] = bb_max[axis];
}
@@ -2145,10 +2332,10 @@ static PlaneAABBIsect test_planes_aabb(const float bb_min[3],
}
}
- if (dot_v3v3(planes[i], vmin) + planes[i][3] > 0) {
+ if (dot_v3v3(planes[i], vmin) + planes[i][3] < 0) {
return ISECT_OUTSIDE;
}
- else if (dot_v3v3(planes[i], vmax) + planes[i][3] >= 0) {
+ else if (dot_v3v3(planes[i], vmax) + planes[i][3] <= 0) {
ret = ISECT_INTERSECT;
}
}
@@ -2156,38 +2343,24 @@ static PlaneAABBIsect test_planes_aabb(const float bb_min[3],
return ret;
}
-bool BKE_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data)
+bool BKE_pbvh_node_frustum_contain_AABB(PBVHNode *node, void *data)
{
const float *bb_min, *bb_max;
/* BKE_pbvh_node_get_BB */
bb_min = node->vb.bmin;
bb_max = node->vb.bmax;
- return test_planes_aabb(bb_min, bb_max, data) != ISECT_OUTSIDE;
+ return test_frustum_aabb(bb_min, bb_max, data) != ISECT_OUTSIDE;
}
-bool BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data)
+bool BKE_pbvh_node_frustum_exclude_AABB(PBVHNode *node, void *data)
{
const float *bb_min, *bb_max;
/* BKE_pbvh_node_get_BB */
bb_min = node->vb.bmin;
bb_max = node->vb.bmax;
- return test_planes_aabb(bb_min, bb_max, data) != ISECT_INSIDE;
-}
-
-typedef struct PBVHNodeDrawCallbackData {
- void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers);
- void *user_data;
-} PBVHNodeDrawCallbackData;
-
-static void pbvh_node_draw_cb(PBVHNode *node, void *data_v)
-{
- PBVHNodeDrawCallbackData *data = data_v;
-
- if (!(node->flag & PBVH_FullyHidden)) {
- data->draw_fn(data->user_data, node->draw_buffers);
- }
+ return test_frustum_aabb(bb_min, bb_max, data) != ISECT_INSIDE;
}
void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg)
@@ -2199,63 +2372,96 @@ void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg)
BKE_pbvh_search_gather(
bvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateNormals), &nodes, &totnode);
- if (bvh->type == PBVH_BMESH) {
- pbvh_bmesh_normals_update(nodes, totnode);
- }
- else if (bvh->type == PBVH_FACES) {
- pbvh_faces_update_normals(bvh, nodes, totnode);
- }
- else if (bvh->type == PBVH_GRIDS) {
- struct CCGFace **faces;
- int num_faces;
- BKE_pbvh_get_grid_updates(bvh, true, (void ***)&faces, &num_faces);
- if (num_faces > 0) {
- BKE_subdiv_ccg_update_normals(subdiv_ccg, faces, num_faces);
- MEM_freeN(faces);
+ if (totnode > 0) {
+ if (bvh->type == PBVH_BMESH) {
+ pbvh_bmesh_normals_update(nodes, totnode);
+ }
+ else if (bvh->type == PBVH_FACES) {
+ pbvh_faces_update_normals(bvh, nodes, totnode);
+ }
+ else if (bvh->type == PBVH_GRIDS) {
+ struct CCGFace **faces;
+ int num_faces;
+ BKE_pbvh_get_grid_updates(bvh, true, (void ***)&faces, &num_faces);
+ if (num_faces > 0) {
+ BKE_subdiv_ccg_update_normals(subdiv_ccg, faces, num_faces);
+ MEM_freeN(faces);
+ }
}
}
- if (nodes) {
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
+}
+
+/**
+ * PBVH drawing, updating draw buffers as needed and culling any nodes outside
+ * the specified frustum.
+ */
+typedef struct PBVHDrawSearchData {
+ PBVHFrustumPlanes *frustum;
+ int accum_update_flag;
+} PBVHDrawSearchData;
+
+static bool pbvh_draw_search_cb(PBVHNode *node, void *data_v)
+{
+ PBVHDrawSearchData *data = data_v;
+ if (data->frustum && !BKE_pbvh_node_frustum_contain_AABB(node, data->frustum)) {
+ return false;
}
+
+ data->accum_update_flag |= node->flag;
+ return true;
}
-void BKE_pbvh_update_draw_buffers(PBVH *bvh, bool show_vcol)
+void BKE_pbvh_draw_cb(PBVH *bvh,
+ bool show_vcol,
+ bool update_only_visible,
+ PBVHFrustumPlanes *frustum,
+ void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers),
+ void *user_data)
{
- /* Update GPU buffers */
PBVHNode **nodes;
int totnode;
- BKE_pbvh_search_gather(
- bvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateDrawBuffers), &nodes, &totnode);
+ const int update_flag = PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers;
- pbvh_update_draw_buffers(bvh, nodes, totnode, show_vcol);
+ if (!update_only_visible) {
+ /* Update all draw buffers, also those outside the view. */
+ BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(update_flag), &nodes, &totnode);
- if (nodes) {
- MEM_freeN(nodes);
+ if (totnode) {
+ pbvh_update_draw_buffers(bvh, nodes, totnode, show_vcol, update_flag);
+ }
+
+ MEM_SAFE_FREE(nodes);
}
-}
-/**
- * Version of #BKE_pbvh_draw that runs a callback.
- */
-void BKE_pbvh_draw_cb(PBVH *bvh,
- float (*planes)[4],
- void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers),
- void *user_data)
-{
- PBVHNodeDrawCallbackData draw_data = {
- .draw_fn = draw_fn,
- .user_data = user_data,
- };
+ /* Gather visible nodes. */
+ PBVHDrawSearchData data = {.frustum = frustum, .accum_update_flag = 0};
+ BKE_pbvh_search_gather(bvh, pbvh_draw_search_cb, &data, &nodes, &totnode);
- if (planes) {
- BKE_pbvh_search_callback(
- bvh, BKE_pbvh_node_planes_contain_AABB, planes, pbvh_node_draw_cb, &draw_data);
+ if (update_only_visible && (data.accum_update_flag & update_flag)) {
+ /* Update draw buffers in visible nodes. */
+ pbvh_update_draw_buffers(bvh, nodes, totnode, show_vcol, data.accum_update_flag);
}
- else {
- BKE_pbvh_search_callback(bvh, NULL, NULL, pbvh_node_draw_cb, &draw_data);
+
+ /* Draw. */
+ for (int a = 0; a < totnode; a++) {
+ PBVHNode *node = nodes[a];
+
+ if (node->flag & PBVH_UpdateDrawBuffers) {
+ /* Flush buffers uses OpenGL, so not in parallel. */
+ GPU_pbvh_buffers_update_flush(node->draw_buffers);
+ }
+
+ node->flag &= ~(PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers);
+
+ if (!(node->flag & PBVH_FullyHidden)) {
+ draw_fn(user_data, node->draw_buffers);
+ }
}
+
+ MEM_SAFE_FREE(nodes);
}
void BKE_pbvh_draw_debug_cb(
@@ -2280,7 +2486,7 @@ void BKE_pbvh_grids_update(
bvh->grid_flag_mats = flagmats;
bvh->grid_hidden = grid_hidden;
- for (int a = 0; a < bvh->totnode; ++a) {
+ for (int a = 0; a < bvh->totnode; a++) {
BKE_pbvh_node_mark_rebuild_draw(&bvh->nodes[a]);
}
}
@@ -2348,7 +2554,7 @@ void BKE_pbvh_vert_coords_apply(PBVH *pbvh, const float (*vertCos)[3], const int
if (pbvh->verts) {
MVert *mvert = pbvh->verts;
/* copy new verts coords */
- for (int a = 0; a < pbvh->totvert; ++a, ++mvert) {
+ for (int a = 0; a < pbvh->totvert; a++, mvert++) {
/* no need for float comparison here (memory is exactly equal or not) */
if (memcmp(mvert->co, vertCos[a], sizeof(float[3])) != 0) {
copy_v3_v3(mvert->co, vertCos[a]);
@@ -2360,7 +2566,7 @@ void BKE_pbvh_vert_coords_apply(PBVH *pbvh, const float (*vertCos)[3], const int
BKE_mesh_calc_normals_looptri(
pbvh->verts, pbvh->totvert, pbvh->mloop, pbvh->looptri, pbvh->totprim, NULL);
- for (int a = 0; a < pbvh->totnode; ++a) {
+ for (int a = 0; a < pbvh->totnode; a++) {
BKE_pbvh_node_mark_update(&pbvh->nodes[a]);
}
@@ -2453,7 +2659,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo
BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids);
BKE_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert);
BKE_pbvh_node_get_verts(bvh, node, &vert_indices, &verts);
- vi->key = &bvh->gridkey;
+ vi->key = bvh->gridkey;
vi->grids = grids;
vi->grid_indices = grid_indices;
@@ -2505,3 +2711,14 @@ void pbvh_show_mask_set(PBVH *bvh, bool show_mask)
{
bvh->show_mask = show_mask;
}
+
+void BKE_pbvh_parallel_range_settings(TaskParallelSettings *settings,
+ bool use_threading,
+ int totnode)
+{
+ const int threaded_limit = 1;
+ BLI_parallel_range_settings_defaults(settings);
+ settings->use_threading = use_threading && (totnode > threaded_limit);
+ settings->min_iter_per_thread = 1;
+ settings->scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+}
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 1d8088c6605..c04e172f116 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -1508,12 +1508,18 @@ static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
bool pbvh_bmesh_node_raycast(PBVHNode *node,
const float ray_start[3],
+ const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
float *depth,
- bool use_original)
+ bool use_original,
+ int *r_active_vertex_index,
+ float *r_face_normal)
{
bool hit = false;
+ float min_depth = FLT_MAX;
+ float nearest_vertex_co[3] = {0.0f};
+ float location[3] = {0.0f};
if (use_original && node->bm_tot_ortri) {
for (int i = 0; i < node->bm_tot_ortri; i++) {
const int *t = node->bm_ortri[i];
@@ -1538,6 +1544,19 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node,
BM_face_as_array_vert_tri(f, v_tri);
hit |= ray_face_intersection_tri(
ray_start, isect_precalc, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth);
+
+ if (hit && *depth < min_depth) {
+ min_depth = *depth;
+ normal_tri_v3(r_face_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co);
+ madd_v3_v3v3fl(location, ray_start, ray_normal, *depth);
+ for (int j = 0; j < 3; j++) {
+ if (len_squared_v3v3(location, v_tri[j]->co) <
+ len_squared_v3v3(location, nearest_vertex_co)) {
+ copy_v3_v3(nearest_vertex_co, v_tri[j]->co);
+ *r_active_vertex_index = BM_elem_index_get(v_tri[j]);
+ }
+ }
+ }
}
}
}
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index e74a8d43c68..bad103743eb 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -206,9 +206,12 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag);
/* pbvh_bmesh.c */
bool pbvh_bmesh_node_raycast(PBVHNode *node,
const float ray_start[3],
+ const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
float *dist,
- bool use_original);
+ bool use_original,
+ int *r_active_vertex_index,
+ float *r_face_normal);
bool pbvh_bmesh_node_nearest_to_ray(PBVHNode *node,
const float ray_start[3],
const float ray_normal[3],
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 13d0f1adb84..7ae5f91c615 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -1831,6 +1831,10 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r
pid->file_type = PTCACHE_FILE_PTCACHE;
}
+/**
+ * \param ob: Optional, may be NULL.
+ * \param scene: Optional may be NULL.
+ */
PTCacheID BKE_ptcache_id_find(Object *ob, Scene *scene, PointCache *cache)
{
PTCacheID result = {0};
@@ -1934,40 +1938,45 @@ static bool foreach_object_ptcache(
Scene *scene, Object *object, int duplis, ForeachPtcacheCb callback, void *callback_user_data)
{
PTCacheID pid;
- /* Soft body. */
- if (object->soft != NULL) {
- BKE_ptcache_id_from_softbody(&pid, object, object->soft);
- if (!callback(&pid, callback_user_data)) {
+
+ if (object != NULL) {
+ /* Soft body. */
+ if (object->soft != NULL) {
+ BKE_ptcache_id_from_softbody(&pid, object, object->soft);
+ if (!callback(&pid, callback_user_data)) {
+ return false;
+ }
+ }
+ /* Particle systems. */
+ if (!foreach_object_particle_ptcache(object, callback, callback_user_data)) {
return false;
}
+ /* Modifiers. */
+ if (!foreach_object_modifier_ptcache(object, callback, callback_user_data)) {
+ return false;
+ }
+ /* Consider all object in dupli groups to be part of the same object,
+ * for baking with linking dupligroups. Once we have better overrides
+ * this can be revisited so users select the local objects directly. */
+ if (scene != NULL && (duplis-- > 0) && (object->instance_collection != NULL)) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (object->instance_collection, current_object) {
+ if (current_object == object) {
+ continue;
+ }
+ foreach_object_ptcache(scene, current_object, duplis, callback, callback_user_data);
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
}
- /* Particle systems. */
- if (!foreach_object_particle_ptcache(object, callback, callback_user_data)) {
- return false;
- }
- /* Modifiers. */
- if (!foreach_object_modifier_ptcache(object, callback, callback_user_data)) {
- return false;
- }
+
/* Rigid body. */
- if (scene != NULL && object->rigidbody_object != NULL && scene->rigidbody_world != NULL) {
+ if (scene != NULL && (object == NULL || object->rigidbody_object != NULL) &&
+ scene->rigidbody_world != NULL) {
BKE_ptcache_id_from_rigidbody(&pid, object, scene->rigidbody_world);
if (!callback(&pid, callback_user_data)) {
return false;
}
}
- /* Consider all object in dupli groups to be part of the same object,
- * for baking with linking dupligroups. Once we have better overrides
- * this can be revisited so users select the local objects directly. */
- if (scene != NULL && (duplis-- > 0) && (object->instance_collection != NULL)) {
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (object->instance_collection, current_object) {
- if (current_object == object) {
- continue;
- }
- foreach_object_ptcache(scene, current_object, duplis, callback, callback_user_data);
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- }
return true;
}
@@ -4537,7 +4546,7 @@ void BKE_ptcache_update_info(PTCacheID *pid)
}
BLI_str_format_int_grouped(formatted_tot, totframes);
- BLI_str_format_byte_unit(formatted_mem, bytes, true);
+ BLI_str_format_byte_unit(formatted_mem, bytes, false);
BLI_snprintf(mem_info,
sizeof(mem_info),
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index ec73406c14c..514f000d73d 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -1452,7 +1452,7 @@ void BKE_rigidbody_remove_object(Main *bmain, Scene *scene, Object *ob)
/* Some users seems to find it funny to use a view-layer instancing collection
* as RBW collection... Despite this being a bad (ab)use of the system, avoid losing objects
* when we remove them from RB simulation. */
- BKE_collection_object_add(bmain, BKE_collection_master(scene), ob);
+ BKE_collection_object_add(bmain, scene->master_collection, ob);
}
BKE_collection_object_remove(bmain, rbw->group, ob, false);
}
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 1ef93427253..4f855bd7d98 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -43,11 +43,13 @@
#include "DNA_windowmanager_types.h"
#include "DNA_workspace_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_world_types.h"
+#include "DNA_defaults.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BLI_callbacks.h"
+#include "BKE_callbacks.h"
#include "BLI_string.h"
#include "BLI_string_utils.h"
#include "BLI_threads.h"
@@ -239,6 +241,8 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
{
/* We never handle usercount here for own data. */
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
+ /* We always need allocation of our private ID data. */
+ const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
sce_dst->ed = NULL;
sce_dst->depsgraph_hash = NULL;
@@ -246,8 +250,10 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
/* Master Collection */
if (sce_src->master_collection) {
- sce_dst->master_collection = BKE_collection_copy_master(
- bmain, sce_src->master_collection, flag);
+ BKE_id_copy_ex(bmain,
+ (ID *)sce_src->master_collection,
+ (ID **)&sce_dst->master_collection,
+ flag_private_id_data);
}
/* View Layers */
@@ -265,10 +271,13 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
BKE_keyingsets_copy(&(sce_dst->keyingsets), &(sce_src->keyingsets));
if (sce_src->nodetree) {
- /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
- * (see BKE_libblock_copy_ex()). */
- BKE_id_copy_ex(bmain, (ID *)sce_src->nodetree, (ID **)&sce_dst->nodetree, flag);
- BKE_libblock_relink_ex(bmain, sce_dst->nodetree, (void *)(&sce_src->id), &sce_dst->id, false);
+ BKE_id_copy_ex(
+ bmain, (ID *)sce_src->nodetree, (ID **)&sce_dst->nodetree, flag_private_id_data);
+ BKE_libblock_relink_ex(bmain,
+ sce_dst->nodetree,
+ (void *)(&sce_src->id),
+ &sce_dst->id,
+ ID_REMAP_SKIP_NEVER_NULL_USAGE);
}
if (sce_src->rigidbody_world) {
@@ -309,6 +318,10 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
flag_subdata);
}
+ if (sce_src->display.shading.prop) {
+ sce_dst->display.shading.prop = IDP_CopyProperty(sce_src->display.shading.prop);
+ }
+
BKE_sound_reset_scene_runtime(sce_dst);
/* Copy sequencer, this is local data! */
@@ -541,6 +554,11 @@ void BKE_scene_free_ex(Scene *sce, const bool do_id_user)
sce->eevee.light_cache = NULL;
}
+ if (sce->display.shading.prop) {
+ IDP_FreeProperty(sce->display.shading.prop);
+ sce->display.shading.prop = NULL;
+ }
+
/* These are freed on doversion. */
BLI_assert(sce->layer_properties == NULL);
}
@@ -550,107 +568,20 @@ void BKE_scene_free(Scene *sce)
BKE_scene_free_ex(sce, true);
}
+/**
+ * \note Use DNA_scene_defaults.h where possible.
+ */
void BKE_scene_init(Scene *sce)
{
- ParticleEditSettings *pset;
- int a;
const char *colorspace_name;
SceneRenderView *srv;
CurveMapping *mblur_shutter_curve;
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(sce, id));
- sce->cursor.rotation_mode = ROT_MODE_XYZ;
- sce->cursor.rotation_quaternion[0] = 1.0f;
- sce->cursor.rotation_axis[1] = 1.0f;
-
- sce->r.mode = 0;
- sce->r.cfra = 1;
- sce->r.sfra = 1;
- sce->r.efra = 250;
- sce->r.frame_step = 1;
- sce->r.xsch = 1920;
- sce->r.ysch = 1080;
- sce->r.xasp = 1;
- sce->r.yasp = 1;
- sce->r.tilex = 256;
- sce->r.tiley = 256;
- sce->r.size = 100;
-
- sce->r.im_format.planes = R_IMF_PLANES_RGBA;
- sce->r.im_format.imtype = R_IMF_IMTYPE_PNG;
- sce->r.im_format.depth = R_IMF_CHAN_DEPTH_8;
- sce->r.im_format.quality = 90;
- sce->r.im_format.compress = 15;
-
- sce->r.displaymode = R_OUTPUT_WINDOW;
- sce->r.framapto = 100;
- sce->r.images = 100;
- sce->r.framelen = 1.0;
- sce->r.blurfac = 0.5;
- sce->r.frs_sec = 24;
- sce->r.frs_sec_base = 1;
-
- /* OCIO_TODO: for forwards compatibility only, so if no tonecurve are used,
- * images would look in the same way as in current blender
- *
- * perhaps at some point should be completely deprecated?
- */
- sce->r.color_mgt_flag |= R_COLOR_MANAGEMENT;
-
- sce->r.gauss = 1.5;
- sce->r.dither_intensity = 1.0f;
-
- sce->r.bake_mode = 0;
- sce->r.bake_filter = 16;
- sce->r.bake_flag = R_BAKE_CLEAR;
- sce->r.bake_samples = 256;
- sce->r.bake_biasdist = 0.001;
-
- sce->r.bake.flag = R_BAKE_CLEAR;
- sce->r.bake.pass_filter = R_BAKE_PASS_FILTER_ALL;
- sce->r.bake.width = 512;
- sce->r.bake.height = 512;
- sce->r.bake.margin = 16;
- sce->r.bake.normal_space = R_BAKE_SPACE_TANGENT;
- sce->r.bake.normal_swizzle[0] = R_BAKE_POSX;
- sce->r.bake.normal_swizzle[1] = R_BAKE_POSY;
- sce->r.bake.normal_swizzle[2] = R_BAKE_POSZ;
- BLI_strncpy(sce->r.bake.filepath, U.renderdir, sizeof(sce->r.bake.filepath));
-
- sce->r.bake.im_format.planes = R_IMF_PLANES_RGBA;
- sce->r.bake.im_format.imtype = R_IMF_IMTYPE_PNG;
- sce->r.bake.im_format.depth = R_IMF_CHAN_DEPTH_8;
- sce->r.bake.im_format.quality = 90;
- sce->r.bake.im_format.compress = 15;
+ MEMCPY_STRUCT_AFTER(sce, DNA_struct_default_get(Scene), id);
- sce->r.scemode = R_DOCOMP | R_DOSEQ | R_EXTENSION;
- sce->r.stamp = R_STAMP_TIME | R_STAMP_FRAME | R_STAMP_DATE | R_STAMP_CAMERA | R_STAMP_SCENE |
- R_STAMP_FILENAME | R_STAMP_RENDERTIME | R_STAMP_MEMORY;
- sce->r.stamp_font_id = 12;
- sce->r.fg_stamp[0] = sce->r.fg_stamp[1] = sce->r.fg_stamp[2] = 0.8f;
- sce->r.fg_stamp[3] = 1.0f;
- sce->r.bg_stamp[0] = sce->r.bg_stamp[1] = sce->r.bg_stamp[2] = 0.0f;
- sce->r.bg_stamp[3] = 0.25f;
-
- sce->r.seq_prev_type = OB_SOLID;
- sce->r.seq_rend_type = OB_SOLID;
- sce->r.seq_flag = 0;
-
- sce->r.threads = 1;
-
- sce->r.simplify_subsurf = 6;
- sce->r.simplify_particles = 1.0f;
-
- sce->r.border.xmin = 0.0f;
- sce->r.border.ymin = 0.0f;
- sce->r.border.xmax = 1.0f;
- sce->r.border.ymax = 1.0f;
-
- sce->r.preview_start_resolution = 64;
-
- sce->r.line_thickness_mode = R_LINE_THICKNESS_ABSOLUTE;
- sce->r.unit_line_thickness = 1.0f;
+ BLI_strncpy(sce->r.bake.filepath, U.renderdir, sizeof(sce->r.bake.filepath));
mblur_shutter_curve = &sce->r.mblur_shutter_curve;
BKE_curvemapping_set_defaults(mblur_shutter_curve, 1, 0.0f, 0.0f, 1.0f, 1.0f);
@@ -660,49 +591,10 @@ void BKE_scene_init(Scene *sce)
CURVE_PRESET_MAX,
CURVEMAP_SLOPE_POS_NEG);
- sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings), "Tool Settings Struct");
+ sce->toolsettings = DNA_struct_default_alloc(ToolSettings);
- sce->toolsettings->object_flag |= SCE_OBJECT_MODE_LOCK;
- sce->toolsettings->doublimit = 0.001;
- sce->toolsettings->vgroup_weight = 1.0f;
- sce->toolsettings->uvcalc_margin = 0.001f;
- sce->toolsettings->uvcalc_flag = UVCALC_TRANSFORM_CORRECT;
- sce->toolsettings->unwrapper = 1;
- sce->toolsettings->select_thresh = 0.01f;
-
- sce->toolsettings->selectmode = SCE_SELECT_VERTEX;
- sce->toolsettings->uv_selectmode = UV_SELECT_VERTEX;
sce->toolsettings->autokey_mode = U.autokey_mode;
- sce->toolsettings->transform_pivot_point = V3D_AROUND_CENTER_MEDIAN;
- sce->toolsettings->snap_mode = SCE_SNAP_MODE_INCREMENT;
- sce->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID;
- sce->toolsettings->snap_uv_mode = SCE_SNAP_MODE_INCREMENT;
- sce->toolsettings->snap_transform_mode_flag = SCE_SNAP_TRANSFORM_MODE_TRANSLATE;
-
- sce->toolsettings->curve_paint_settings.curve_type = CU_BEZIER;
- sce->toolsettings->curve_paint_settings.flag |= CURVE_PAINT_FLAG_CORNERS_DETECT;
- sce->toolsettings->curve_paint_settings.error_threshold = 8;
- sce->toolsettings->curve_paint_settings.radius_max = 1.0f;
- sce->toolsettings->curve_paint_settings.corner_angle = DEG2RADF(70.0f);
-
- sce->toolsettings->statvis.overhang_axis = OB_NEGZ;
- sce->toolsettings->statvis.overhang_min = 0;
- sce->toolsettings->statvis.overhang_max = DEG2RADF(45.0f);
- sce->toolsettings->statvis.thickness_max = 0.1f;
- sce->toolsettings->statvis.thickness_samples = 1;
- sce->toolsettings->statvis.distort_min = DEG2RADF(5.0f);
- sce->toolsettings->statvis.distort_max = DEG2RADF(45.0f);
-
- sce->toolsettings->statvis.sharp_min = DEG2RADF(90.0f);
- sce->toolsettings->statvis.sharp_max = DEG2RADF(180.0f);
-
- sce->toolsettings->proportional_size = 1.0f;
-
- sce->toolsettings->imapaint.paint.flags |= PAINT_SHOW_BRUSH;
- sce->toolsettings->imapaint.normal_angle = 80;
- sce->toolsettings->imapaint.seam_bleed = 2;
-
/* grease pencil multiframe falloff curve */
sce->toolsettings->gp_sculpt.cur_falloff = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
CurveMapping *gp_falloff_curve = sce->toolsettings->gp_sculpt.cur_falloff;
@@ -718,54 +610,25 @@ void BKE_scene_init(Scene *sce)
CURVE_PRESET_BELL,
CURVEMAP_SLOPE_POSITIVE);
- sce->toolsettings->gp_sculpt.guide.spacing = 20.0f;
-
- sce->physics_settings.gravity[0] = 0.0f;
- sce->physics_settings.gravity[1] = 0.0f;
- sce->physics_settings.gravity[2] = -9.81f;
- sce->physics_settings.flag = PHYS_GLOBAL_GRAVITY;
-
sce->unit.system = USER_UNIT_METRIC;
sce->unit.scale_length = 1.0f;
sce->unit.length_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_LENGTH);
sce->unit.mass_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_MASS);
sce->unit.time_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_TIME);
- pset = &sce->toolsettings->particle;
- pset->flag = PE_KEEP_LENGTHS | PE_LOCK_FIRST | PE_DEFLECT_EMITTER | PE_AUTO_VELOCITY;
- pset->emitterdist = 0.25f;
- pset->totrekey = 5;
- pset->totaddkey = 5;
- pset->brushtype = PE_BRUSH_COMB;
- pset->draw_step = 2;
- pset->fade_frames = 2;
- pset->selectmode = SCE_SELECT_PATH;
-
- for (a = 0; a < ARRAY_SIZE(pset->brush); a++) {
- pset->brush[a].strength = 0.5f;
- pset->brush[a].size = 50;
- pset->brush[a].step = 10;
- pset->brush[a].count = 10;
- }
- pset->brush[PE_BRUSH_CUT].strength = 1.0f;
-
- sce->r.ffcodecdata.audio_mixrate = 48000;
- sce->r.ffcodecdata.audio_volume = 1.0f;
- sce->r.ffcodecdata.audio_bitrate = 192;
- sce->r.ffcodecdata.audio_channels = 2;
+ {
+ ParticleEditSettings *pset;
+ pset = &sce->toolsettings->particle;
+ for (int i = 1; i < ARRAY_SIZE(pset->brush); i++) {
+ pset->brush[i] = pset->brush[0];
+ }
+ pset->brush[PE_BRUSH_CUT].strength = 1.0f;
+ }
BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(sce->r.engine));
- sce->audio.distance_model = 2.0f;
- sce->audio.doppler_factor = 1.0f;
- sce->audio.speed_of_sound = 343.3f;
- sce->audio.volume = 1.0f;
- sce->audio.flag = AUDIO_SYNC;
-
BLI_strncpy(sce->r.pic, U.renderdir, sizeof(sce->r.pic));
- BLI_rctf_init(&sce->r.safety, 0.1f, 0.9f, 0.1f, 0.9f);
-
/* Note; in header_info.c the scene copy happens...,
* if you add more to renderdata it has to be checked there. */
@@ -800,14 +663,6 @@ void BKE_scene_init(Scene *sce)
BKE_color_managed_view_settings_init_render(
&sce->r.bake.im_format.view_settings, &sce->r.bake.im_format.display_settings, "Filmic");
- /* Safe Areas */
- copy_v2_fl2(sce->safe_areas.title, 10.0f / 100.0f, 5.0f / 100.0f);
- copy_v2_fl2(sce->safe_areas.action, 3.5f / 100.0f, 3.5f / 100.0f);
- copy_v2_fl2(sce->safe_areas.title_center, 17.5f / 100.0f, 5.0f / 100.0f);
- copy_v2_fl2(sce->safe_areas.action_center, 15.0f / 100.0f, 5.0f / 100.0f);
-
- sce->preview = NULL;
-
/* GP Sculpt brushes */
{
GP_Sculpt_Settings *gset = &sce->toolsettings->gp_sculpt;
@@ -874,16 +729,6 @@ void BKE_scene_init(Scene *sce)
copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
}
- /* GP Stroke Placement */
- sce->toolsettings->gpencil_v3d_align = GP_PROJECT_VIEWSPACE;
- sce->toolsettings->gpencil_v2d_align = GP_PROJECT_VIEWSPACE;
- sce->toolsettings->gpencil_seq_align = GP_PROJECT_VIEWSPACE;
- sce->toolsettings->gpencil_ima_align = GP_PROJECT_VIEWSPACE;
-
- /* Annotations */
- sce->toolsettings->annotate_v3d_align = GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR;
- sce->toolsettings->annotate_thickness = 3;
-
for (int i = 0; i < ARRAY_SIZE(sce->orientation_slots); i++) {
sce->orientation_slots[i].index_custom = -1;
}
@@ -892,80 +737,6 @@ void BKE_scene_init(Scene *sce)
sce->master_collection = BKE_collection_master_add();
BKE_view_layer_add(sce, "View Layer");
-
- /* SceneDisplay */
- copy_v3_v3(sce->display.light_direction, (float[3]){M_SQRT1_3, M_SQRT1_3, M_SQRT1_3});
- sce->display.shadow_shift = 0.1f;
- sce->display.shadow_focus = 0.0f;
-
- sce->display.matcap_ssao_distance = 0.2f;
- sce->display.matcap_ssao_attenuation = 1.0f;
- sce->display.matcap_ssao_samples = 16;
-
- sce->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8;
- sce->display.viewport_aa = SCE_DISPLAY_AA_FXAA;
-
- /* OpenGL Render. */
- BKE_screen_view3d_shading_init(&sce->display.shading);
-
- /* SceneEEVEE */
- sce->eevee.gi_diffuse_bounces = 3;
- sce->eevee.gi_cubemap_resolution = 512;
- sce->eevee.gi_visibility_resolution = 32;
- sce->eevee.gi_cubemap_draw_size = 0.3f;
- sce->eevee.gi_irradiance_draw_size = 0.1f;
- sce->eevee.gi_irradiance_smoothing = 0.1f;
- sce->eevee.gi_filter_quality = 3.0f;
-
- sce->eevee.taa_samples = 16;
- sce->eevee.taa_render_samples = 64;
-
- sce->eevee.sss_samples = 7;
- sce->eevee.sss_jitter_threshold = 0.3f;
-
- sce->eevee.ssr_quality = 0.25f;
- sce->eevee.ssr_max_roughness = 0.5f;
- sce->eevee.ssr_thickness = 0.2f;
- sce->eevee.ssr_border_fade = 0.075f;
- sce->eevee.ssr_firefly_fac = 10.0f;
-
- sce->eevee.volumetric_start = 0.1f;
- sce->eevee.volumetric_end = 100.0f;
- sce->eevee.volumetric_tile_size = 8;
- sce->eevee.volumetric_samples = 64;
- sce->eevee.volumetric_sample_distribution = 0.8f;
- sce->eevee.volumetric_light_clamp = 0.0f;
- sce->eevee.volumetric_shadow_samples = 16;
-
- sce->eevee.gtao_distance = 0.2f;
- sce->eevee.gtao_factor = 1.0f;
- sce->eevee.gtao_quality = 0.25f;
-
- sce->eevee.bokeh_max_size = 100.0f;
- sce->eevee.bokeh_threshold = 1.0f;
-
- copy_v3_fl(sce->eevee.bloom_color, 1.0f);
- sce->eevee.bloom_threshold = 0.8f;
- sce->eevee.bloom_knee = 0.5f;
- sce->eevee.bloom_intensity = 0.05f;
- sce->eevee.bloom_radius = 6.5f;
- sce->eevee.bloom_clamp = 0.0f;
-
- sce->eevee.motion_blur_samples = 8;
- sce->eevee.motion_blur_shutter = 0.5f;
-
- sce->eevee.shadow_method = SHADOW_ESM;
- sce->eevee.shadow_cube_size = 512;
- sce->eevee.shadow_cascade_size = 1024;
-
- sce->eevee.light_cache = NULL;
- sce->eevee.light_threshold = 0.01f;
-
- sce->eevee.overscan = 3.0f;
-
- sce->eevee.flag = SCE_EEVEE_VOLUMETRIC_LIGHTS | SCE_EEVEE_GTAO_BENT_NORMALS |
- SCE_EEVEE_GTAO_BOUNCE | SCE_EEVEE_TAA_REPROJECTION |
- SCE_EEVEE_SSR_HALF_RESOLUTION;
}
Scene *BKE_scene_add(Main *bmain, const char *name)
@@ -1547,34 +1318,41 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on
bool run_callbacks = DEG_id_type_any_updated(depsgraph);
if (run_callbacks) {
- BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_DEPSGRAPH_UPDATE_PRE);
- }
+ BKE_callback_exec_id(bmain, &scene->id, BKE_CB_EVT_DEPSGRAPH_UPDATE_PRE);
+ }
+
+ for (int pass = 0; pass < 2; pass++) {
+ /* (Re-)build dependency graph if needed. */
+ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
+ /* Uncomment this to check if graph was properly tagged for update. */
+ // DEG_debug_graph_relations_validate(depsgraph, bmain, scene);
+ /* Flush editing data if needed. */
+ prepare_mesh_for_viewport_render(bmain, view_layer);
+ /* Update all objects: drivers, matrices, displists, etc. flags set
+ * by depgraph or manual, no layer check here, gets correct flushed.
+ */
+ DEG_evaluate_on_refresh(bmain, depsgraph);
+ /* Update sound system. */
+ BKE_scene_update_sound(depsgraph, bmain);
+ /* Notify python about depsgraph update. */
+ if (run_callbacks) {
+ BKE_callback_exec_id_depsgraph(
+ bmain, &scene->id, depsgraph, BKE_CB_EVT_DEPSGRAPH_UPDATE_POST);
+ }
+ /* Inform editors about possible changes. */
+ DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, false);
+ /* Clear recalc flags. */
+ DEG_ids_clear_recalc(bmain, depsgraph);
+
+ /* If user callback did not tag anything for update we can skip second iteration.
+ * Otherwise we update scene once again, but without running callbacks to bring
+ * scene to a fully evaluated state with user modifications taken into account. */
+ if (DEG_is_fully_evaluated(depsgraph)) {
+ break;
+ }
- /* TODO(sergey): Some functions here are changing global state,
- * for example, clearing update tags from bmain.
- */
- /* (Re-)build dependency graph if needed. */
- DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
- /* Uncomment this to check if graph was properly tagged for update. */
- // DEG_debug_graph_relations_validate(depsgraph, bmain, scene);
- /* Flush editing data if needed. */
- prepare_mesh_for_viewport_render(bmain, view_layer);
- /* Flush recalc flags to dependencies. */
- DEG_graph_flush_update(bmain, depsgraph);
- /* Update all objects: drivers, matrices, displists, etc. flags set
- * by depgraph or manual, no layer check here, gets correct flushed.
- */
- DEG_evaluate_on_refresh(depsgraph);
- /* Update sound system. */
- BKE_scene_update_sound(depsgraph, bmain);
- /* Notify python about depsgraph update. */
- if (run_callbacks) {
- BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_DEPSGRAPH_UPDATE_POST);
+ run_callbacks = false;
}
- /* Inform editors about possible changes. */
- DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, false);
- /* Clear recalc flags. */
- DEG_ids_clear_recalc(bmain, depsgraph);
}
void BKE_scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain)
@@ -1593,33 +1371,52 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph, Main *bmain)
Scene *scene = DEG_get_input_scene(depsgraph);
ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
- /* TODO(sergey): Some functions here are changing global state,
- * for example, clearing update tags from bmain.
- */
- const float ctime = BKE_scene_frame_get(scene);
/* Keep this first. */
- BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_PRE);
- /* Update animated image textures for particles, modifiers, gpu, etc,
- * call this at the start so modifiers with textures don't lag 1 frame.
- */
- BKE_image_editors_update_frame(bmain, scene->r.cfra);
- BKE_sound_set_cfra(scene->r.cfra);
- DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
+ BKE_callback_exec_id(bmain, &scene->id, BKE_CB_EVT_FRAME_CHANGE_PRE);
+
+ for (int pass = 0; pass < 2; pass++) {
+ /* Update animated image textures for particles, modifiers, gpu, etc,
+ * call this at the start so modifiers with textures don't lag 1 frame.
+ */
+ BKE_image_editors_update_frame(bmain, scene->r.cfra);
+ BKE_sound_set_cfra(scene->r.cfra);
+ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
#ifdef POSE_ANIMATION_WORKAROUND
- scene_armature_depsgraph_workaround(bmain, depsgraph);
+ scene_armature_depsgraph_workaround(bmain, depsgraph);
#endif
- /* Update all objects: drivers, matrices, displists, etc. flags set
- * by depgraph or manual, no layer check here, gets correct flushed.
- */
- DEG_evaluate_on_framechange(bmain, depsgraph, ctime);
- /* Update sound system animation. */
- BKE_scene_update_sound(depsgraph, bmain);
- /* Notify editors and python about recalc. */
- BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_POST);
- /* Inform editors about possible changes. */
- DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, true);
- /* clear recalc flags */
- DEG_ids_clear_recalc(bmain, depsgraph);
+ /* Update all objects: drivers, matrices, displists, etc. flags set
+ * by depgraph or manual, no layer check here, gets correct flushed.
+ *
+ * NOTE: Only update for new frame on first iteration. Second iteration is for ensuring user
+ * edits from callback are properly taken into account. Doing a time update on those would
+ * loose any possible unkeyed changes made by the handler. */
+ if (pass == 0) {
+ const float ctime = BKE_scene_frame_get(scene);
+ DEG_evaluate_on_framechange(bmain, depsgraph, ctime);
+ }
+ else {
+ DEG_evaluate_on_refresh(bmain, depsgraph);
+ }
+ /* Update sound system animation. */
+ BKE_scene_update_sound(depsgraph, bmain);
+
+ /* Notify editors and python about recalc. */
+ if (pass == 0) {
+ BKE_callback_exec_id_depsgraph(bmain, &scene->id, depsgraph, BKE_CB_EVT_FRAME_CHANGE_POST);
+ }
+
+ /* Inform editors about possible changes. */
+ DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, true);
+ /* clear recalc flags */
+ DEG_ids_clear_recalc(bmain, depsgraph);
+
+ /* If user callback did not tag anything for update we can skip second iteration.
+ * Otherwise we update scene once again, but without running callbacks to bring
+ * scene to a fully evaluated state with user modifications taken into account. */
+ if (DEG_is_fully_evaluated(depsgraph)) {
+ break;
+ }
+ }
}
/** Ensures given scene/view_layer pair has a valid, up-to-date depsgraph.
@@ -1629,7 +1426,7 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph, Main *bmain)
*/
void BKE_scene_view_layer_graph_evaluated_ensure(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
DEG_make_active(depsgraph);
BKE_scene_graph_update_tagged(depsgraph, bmain);
}
@@ -1877,6 +1674,8 @@ double BKE_scene_unit_scale(const UnitSettings *unit, const int unit_type, doubl
switch (unit_type) {
case B_UNIT_LENGTH:
+ case B_UNIT_VELOCITY:
+ case B_UNIT_ACCELERATION:
return value * (double)unit->scale_length;
case B_UNIT_AREA:
case B_UNIT_POWER:
@@ -2261,7 +2060,7 @@ void BKE_scene_free_depsgraph_hash(Scene *scene)
/* Query depsgraph for a specific contexts. */
-Depsgraph *BKE_scene_get_depsgraph(Scene *scene, ViewLayer *view_layer, bool allocate)
+Depsgraph *BKE_scene_get_depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, bool allocate)
{
BLI_assert(scene != NULL);
BLI_assert(view_layer != NULL);
@@ -2285,7 +2084,7 @@ Depsgraph *BKE_scene_get_depsgraph(Scene *scene, ViewLayer *view_layer, bool all
scene->depsgraph_hash, &key, (void ***)&key_ptr, (void ***)&depsgraph_ptr)) {
*key_ptr = MEM_mallocN(sizeof(DepsgraphKey), __func__);
**key_ptr = key;
- *depsgraph_ptr = DEG_graph_new(scene, view_layer, DAG_EVAL_VIEWPORT);
+ *depsgraph_ptr = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_VIEWPORT);
/* TODO(sergey): Would be cool to avoid string format print,
* but is a bit tricky because we can't know in advance whether
* we will ever enable debug messages for this depsgraph.
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 619845c9ecb..1835fb2a523 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -36,6 +36,7 @@
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_workspace_types.h"
+#include "DNA_defaults.h"
#include "BLI_math_vector.h"
#include "BLI_listbase.h"
@@ -852,22 +853,8 @@ void BKE_screen_view3d_scene_sync(bScreen *sc, Scene *scene)
void BKE_screen_view3d_shading_init(View3DShading *shading)
{
- memset(shading, 0, sizeof(*shading));
-
- shading->type = OB_SOLID;
- shading->prev_type = OB_SOLID;
- shading->flag = V3D_SHADING_SPECULAR_HIGHLIGHT | V3D_SHADING_XRAY_WIREFRAME;
- shading->light = V3D_LIGHTING_STUDIO;
- shading->shadow_intensity = 0.5f;
- shading->xray_alpha = 0.5f;
- shading->xray_alpha_wire = 0.0f;
- shading->cavity_valley_factor = 1.0f;
- shading->cavity_ridge_factor = 1.0f;
- shading->cavity_type = V3D_SHADING_CAVITY_CURVATURE;
- shading->curvature_ridge_factor = 1.0f;
- shading->curvature_valley_factor = 1.0f;
- copy_v3_fl(shading->single_color, 0.8f);
- copy_v3_fl(shading->background_color, 0.05f);
+ const View3DShading *shading_default = DNA_struct_default_get(View3DShading);
+ memcpy(shading, shading_default, sizeof(*shading));
}
/* magic zoom calculation, no idea what
diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c
index ff54327e406..d12710690df 100644
--- a/source/blender/blenkernel/intern/seqcache.c
+++ b/source/blender/blenkernel/intern/seqcache.c
@@ -44,17 +44,6 @@
* Sequencer Cache Design Notes
* ============================
*
- * Cache key members:
- * is_temp_cache - this cache entry will be freed before rendering next frame
- * creator_id - ID of thread that created entry
- * cost - In short: render time divided by playback frame rate
- * link_prev/next - link to another entry created during rendering of the frame
- *
- * Linking: We use links to reduce number of iterations needed to manage cache.
- * Entries are linked in order as they are put into cache.
- * Only permanent (is_temp_cache = 0) cache entries are linked.
- * Putting #SEQ_CACHE_STORE_FINAL_OUT will reset linking
- *
* Function:
* All images created during rendering are added to cache, even if the cache is already full.
* This is because:
@@ -64,6 +53,11 @@
* "holes" in the cache, which can be annoying
* If the cache is full all entries for pending frame will have is_temp_cache set.
*
+ * Linking: We use links to reduce number of iterations over entries needed to manage cache.
+ * Entries are linked in order as they are put into cache.
+ * Only permanent (is_temp_cache = 0) cache entries are linked.
+ * Putting #SEQ_CACHE_STORE_FINAL_OUT will reset linking
+ *
* Only entire frame can be freed to release resources for new entries (recycling).
* Once again, this is to reduce number of iterations, but also more controllable than removing
* entries one by one in reverse order to their creation.
@@ -93,9 +87,10 @@ typedef struct SeqCacheKey {
struct Sequence *seq;
SeqRenderData context;
float nfra;
- float cost;
- bool is_temp_cache;
- short creator_id;
+ float cost; /* In short: render time(s) divided by playback frame duration(s) */
+ bool is_temp_cache; /* this cache entry will be freed before rendering next frame */
+ /* ID of task for asigning temp cache entries to particular task(thread, etc.) */
+ eSeqTaskId task_id;
int type;
} SeqCacheKey;
@@ -172,6 +167,11 @@ static void seq_cache_unlock(Scene *scene)
}
}
+static size_t seq_cache_get_mem_total(void)
+{
+ return ((size_t)U.memcachelimit) * 1024 * 1024;
+}
+
static void seq_cache_keyfree(void *val)
{
SeqCacheKey *key = val;
@@ -228,10 +228,43 @@ static void seq_cache_relink_keys(SeqCacheKey *link_next, SeqCacheKey *link_prev
}
}
+/* Choose a key out of 2 candidates(leftmost and rightmost items)
+ * to recycle based on currently used strategy */
static SeqCacheKey *seq_cache_choose_key(Scene *scene, SeqCacheKey *lkey, SeqCacheKey *rkey)
{
SeqCacheKey *finalkey = NULL;
+ /* Ideally, cache would not need to check the state of prefetching task
+ * that is tricky to do however, because prefetch would need to know,
+ * if a key, that is about to be created would be removed by itself.
+ *
+ * This can happen because only FINAL_OUT item insertion will trigger recycling
+ * but that is also the point, where prefetch can be suspended.
+ *
+ * We could use temp cache as a shield and later make it a non-temporary entry,
+ * but it is not worth of increasing system complexity.
+ */
+ if (scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE) {
+ int pfjob_start, pfjob_end;
+ BKE_sequencer_prefetch_get_time_range(scene, &pfjob_start, &pfjob_end);
+
+ if (lkey) {
+ int lkey_cfra = lkey->seq->start + lkey->nfra;
+ if (lkey_cfra < pfjob_start || lkey_cfra > pfjob_end) {
+ return lkey;
+ }
+ }
+
+ if (rkey) {
+ int rkey_cfra = rkey->seq->start + rkey->nfra;
+ if (rkey_cfra < pfjob_start || rkey_cfra > pfjob_end) {
+ return rkey;
+ }
+ }
+
+ return NULL;
+ }
+
if (rkey && lkey) {
int lkey_cfra = lkey->seq->start + lkey->nfra;
int rkey_cfra = rkey->seq->start + rkey->nfra;
@@ -342,15 +375,16 @@ static SeqCacheKey *seq_cache_get_item_for_removal(Scene *scene)
}
finalkey = seq_cache_choose_key(scene, lkey, rkey);
+
return finalkey;
}
/* Find only "base" keys
* Sources(other types) for a frame must be freed all at once
*/
-static bool seq_cache_recycle_item(Scene *scene)
+bool BKE_sequencer_cache_recycle_item(Scene *scene)
{
- size_t memory_total = ((size_t)U.memcachelimit) * 1024 * 1024;
+ size_t memory_total = seq_cache_get_mem_total();
SeqCache *cache = seq_cache_get_from_scene(scene);
if (!cache) {
return false;
@@ -429,7 +463,7 @@ void BKE_sequencer_cache_free_temp_cache(Scene *scene, short id, int cfra)
SeqCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
BLI_ghashIterator_step(&gh_iter);
- if (key->is_temp_cache && key->creator_id == id && key->seq->start + key->nfra != cfra) {
+ if (key->is_temp_cache && key->task_id == id && key->seq->start + key->nfra != cfra) {
BLI_ghash_remove(cache->hash, key, seq_cache_keyfree, seq_cache_valfree);
}
}
@@ -459,6 +493,8 @@ void BKE_sequencer_cache_cleanup_all(Main *bmain)
}
void BKE_sequencer_cache_cleanup(Scene *scene)
{
+ BKE_sequencer_prefetch_stop(scene);
+
SeqCache *cache = seq_cache_get_from_scene(scene);
if (!cache) {
return;
@@ -542,6 +578,12 @@ struct ImBuf *BKE_sequencer_cache_get(const SeqRenderData *context,
{
Scene *scene = context->scene;
+ if (context->is_prefetch_render) {
+ context = BKE_sequencer_prefetch_get_original_context(context);
+ scene = context->scene;
+ seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene);
+ }
+
if (!scene->ed->cache) {
BKE_sequencer_cache_create(scene);
return NULL;
@@ -571,7 +613,13 @@ bool BKE_sequencer_cache_put_if_possible(
{
Scene *scene = context->scene;
- if (seq_cache_recycle_item(scene)) {
+ if (context->is_prefetch_render) {
+ context = BKE_sequencer_prefetch_get_original_context(context);
+ scene = context->scene;
+ seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene);
+ }
+
+ if (BKE_sequencer_cache_recycle_item(scene)) {
BKE_sequencer_cache_put(context, seq, cfra, type, ibuf, cost);
return true;
}
@@ -586,7 +634,12 @@ void BKE_sequencer_cache_put(
const SeqRenderData *context, Sequence *seq, float cfra, int type, ImBuf *i, float cost)
{
Scene *scene = context->scene;
- short creator_id = 0;
+
+ if (context->is_prefetch_render) {
+ context = BKE_sequencer_prefetch_get_original_context(context);
+ scene = context->scene;
+ seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene);
+ }
if (i == NULL || context->skip_cache || context->is_proxy_render || !seq) {
return;
@@ -632,7 +685,7 @@ void BKE_sequencer_cache_put(
key->link_prev = NULL;
key->link_next = NULL;
key->is_temp_cache = true;
- key->creator_id = creator_id;
+ key->task_id = context->task_id;
/* Item stored for later use */
if (flag & type) {
@@ -688,3 +741,14 @@ void BKE_sequencer_cache_iterate(
cache->last_key = NULL;
seq_cache_unlock(scene);
}
+
+bool BKE_sequencer_cache_is_full(Scene *scene)
+{
+ size_t memory_total = seq_cache_get_mem_total();
+ SeqCache *cache = seq_cache_get_from_scene(scene);
+ if (!cache) {
+ return false;
+ }
+
+ return memory_total < cache->memory_used;
+}
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index 89f3f9ef9fd..dbdaaaa5fc3 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -3434,13 +3434,13 @@ static void do_gaussian_blur_effect_byte_x(Sequence *seq,
float *gausstab_x;
gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x);
- for (i = 0; i < y; ++i) {
- for (j = 0; j < x; ++j) {
+ for (i = 0; i < y; i++) {
+ for (j = 0; j < x; j++) {
int out_index = INDEX(j, i);
float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float accum_weight = 0.0f;
- for (int current_x = j - size_x; current_x <= j + size_x; ++current_x) {
+ for (int current_x = j - size_x; current_x <= j + size_x; current_x++) {
if (current_x < 0 || current_x >= frame_width) {
/* Out of bounds. */
continue;
@@ -3484,12 +3484,12 @@ static void do_gaussian_blur_effect_byte_y(Sequence *seq,
float *gausstab_y;
gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y);
- for (i = 0; i < y; ++i) {
- for (j = 0; j < x; ++j) {
+ for (i = 0; i < y; i++) {
+ for (j = 0; j < x; j++) {
int out_index = INDEX(j, i);
float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float accum_weight = 0.0f;
- for (int current_y = i - size_y; current_y <= i + size_y; ++current_y) {
+ for (int current_y = i - size_y; current_y <= i + size_y; current_y++) {
if (current_y < -start_line || current_y + start_line >= frame_height) {
/* Out of bounds. */
continue;
@@ -3532,12 +3532,12 @@ static void do_gaussian_blur_effect_float_x(Sequence *seq,
float *gausstab_x;
gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x);
- for (i = 0; i < y; ++i) {
- for (j = 0; j < x; ++j) {
+ for (i = 0; i < y; i++) {
+ for (j = 0; j < x; j++) {
int out_index = INDEX(j, i);
float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float accum_weight = 0.0f;
- for (int current_x = j - size_x; current_x <= j + size_x; ++current_x) {
+ for (int current_x = j - size_x; current_x <= j + size_x; current_x++) {
if (current_x < 0 || current_x >= frame_width) {
/* Out of bounds. */
continue;
@@ -3573,12 +3573,12 @@ static void do_gaussian_blur_effect_float_y(Sequence *seq,
float *gausstab_y;
gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y);
- for (i = 0; i < y; ++i) {
- for (j = 0; j < x; ++j) {
+ for (i = 0; i < y; i++) {
+ for (j = 0; j < x; j++) {
int out_index = INDEX(j, i);
float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float accum_weight = 0.0f;
- for (int current_y = i - size_y; current_y <= i + size_y; ++current_y) {
+ for (int current_y = i - size_y; current_y <= i + size_y; current_y++) {
if (current_y < -start_line || current_y + start_line >= frame_height) {
/* Out of bounds. */
continue;
diff --git a/source/blender/blenkernel/intern/seqprefetch.c b/source/blender/blenkernel/intern/seqprefetch.c
new file mode 100644
index 00000000000..c1109347e76
--- /dev/null
+++ b/source/blender/blenkernel/intern/seqprefetch.c
@@ -0,0 +1,453 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_sequence_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_threads.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BKE_animsys.h"
+#include "BKE_library.h"
+#include "BKE_scene.h"
+#include "BKE_main.h"
+#include "BKE_context.h"
+#include "BKE_sequencer.h"
+#include "BKE_layer.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_query.h"
+
+typedef struct PrefetchJob {
+ struct PrefetchJob *next, *prev;
+
+ struct Main *bmain;
+ struct Scene *scene;
+ struct Scene *scene_eval;
+ struct Depsgraph *depsgraph;
+
+ ThreadMutex prefetch_suspend_mutex;
+ ThreadCondition prefetch_suspend_cond;
+
+ ListBase threads;
+
+ /* context */
+ struct SeqRenderData context;
+ struct SeqRenderData context_cpy;
+ struct ListBase *seqbasep;
+ struct ListBase *seqbasep_cpy;
+
+ /* prefetch area */
+ float cfra;
+ int num_frames_prefetched;
+
+ /* control */
+ bool running;
+ bool waiting;
+ bool stop;
+} PrefetchJob;
+
+static bool seq_prefetch_is_playing(Main *bmain)
+{
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ if (screen->animtimer) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool seq_prefetch_is_scrubbing(Main *bmain)
+{
+
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ if (screen->scrubbing) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static PrefetchJob *seq_prefetch_job_get(Scene *scene)
+{
+ if (scene && scene->ed) {
+ return scene->ed->prefetch_job;
+ }
+ return NULL;
+}
+
+static bool seq_prefetch_job_is_running(Scene *scene)
+{
+ PrefetchJob *pfjob = seq_prefetch_job_get(scene);
+
+ if (!pfjob) {
+ return false;
+ }
+
+ return pfjob->running;
+}
+
+static bool seq_prefetch_job_is_waiting(Scene *scene)
+{
+ PrefetchJob *pfjob = seq_prefetch_job_get(scene);
+
+ if (!pfjob) {
+ return false;
+ }
+
+ return pfjob->waiting;
+}
+
+/* for cache context swapping */
+Sequence *BKE_sequencer_prefetch_get_original_sequence(Sequence *seq, Scene *scene)
+{
+ Editing *ed = scene->ed;
+ ListBase *seqbase = &ed->seqbase;
+ Sequence *seq_orig = NULL;
+
+ for (seq_orig = (Sequence *)seqbase->first; seq_orig; seq_orig = seq_orig->next) {
+ if (strcmp(seq->name, seq_orig->name) == 0) {
+ break;
+ }
+ }
+ return seq_orig;
+}
+
+/* for cache context swapping */
+SeqRenderData *BKE_sequencer_prefetch_get_original_context(const SeqRenderData *context)
+{
+ PrefetchJob *pfjob = seq_prefetch_job_get(context->scene);
+
+ return &pfjob->context;
+}
+
+static bool seq_prefetch_is_cache_full(Scene *scene)
+{
+ PrefetchJob *pfjob = seq_prefetch_job_get(scene);
+
+ if (!BKE_sequencer_cache_is_full(pfjob->scene)) {
+ return false;
+ }
+
+ return BKE_sequencer_cache_recycle_item(pfjob->scene) == false;
+}
+
+void BKE_sequencer_prefetch_get_time_range(Scene *scene, int *start, int *end)
+{
+ PrefetchJob *pfjob = seq_prefetch_job_get(scene);
+
+ *start = pfjob->cfra;
+ *end = pfjob->cfra + pfjob->num_frames_prefetched;
+}
+
+static void seq_prefetch_free_depsgraph(PrefetchJob *pfjob)
+{
+ if (pfjob->depsgraph != NULL) {
+ DEG_graph_free(pfjob->depsgraph);
+ }
+ pfjob->depsgraph = NULL;
+ pfjob->scene_eval = NULL;
+}
+
+static void seq_prefetch_update_depsgraph(PrefetchJob *pfjob)
+{
+ DEG_evaluate_on_framechange(
+ pfjob->bmain, pfjob->depsgraph, pfjob->cfra + pfjob->num_frames_prefetched);
+}
+
+static void seq_prefetch_init_depsgraph(PrefetchJob *pfjob)
+{
+ Main *bmain = pfjob->bmain;
+ Scene *scene = pfjob->scene;
+ ViewLayer *view_layer = BKE_view_layer_default_render(scene);
+
+ pfjob->depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
+ DEG_debug_name_set(pfjob->depsgraph, "SEQUENCER PREFETCH");
+
+ /* Make sure there is a correct evaluated scene pointer. */
+ DEG_graph_build_for_render_pipeline(pfjob->depsgraph, pfjob->bmain, scene, view_layer);
+
+ /* Update immediately so we have proper evaluated scene. */
+ seq_prefetch_update_depsgraph(pfjob);
+
+ pfjob->scene_eval = DEG_get_evaluated_scene(pfjob->depsgraph);
+ pfjob->scene_eval->ed->cache_flag = 0;
+}
+
+static void seq_prefetch_update_area(PrefetchJob *pfjob)
+{
+ int cfra = pfjob->scene->r.cfra;
+
+ /* rebase */
+ if (cfra > pfjob->cfra) {
+ int delta = cfra - pfjob->cfra;
+ pfjob->cfra = cfra;
+ pfjob->num_frames_prefetched -= delta;
+
+ if (pfjob->num_frames_prefetched <= 1) {
+ pfjob->num_frames_prefetched = 1;
+ }
+ }
+
+ /* reset */
+ if (cfra < pfjob->cfra) {
+ pfjob->cfra = cfra;
+ pfjob->num_frames_prefetched = 1;
+ }
+}
+
+/* Use also to update scene and context changes */
+void BKE_sequencer_prefetch_stop(Scene *scene)
+{
+ PrefetchJob *pfjob;
+ pfjob = seq_prefetch_job_get(scene);
+
+ if (!pfjob) {
+ return;
+ }
+
+ pfjob->stop = true;
+
+ while (pfjob->running) {
+ BLI_condition_notify_one(&pfjob->prefetch_suspend_cond);
+ }
+}
+
+static void seq_prefetch_update_context(const SeqRenderData *context)
+{
+ PrefetchJob *pfjob;
+ pfjob = seq_prefetch_job_get(context->scene);
+
+ BKE_sequencer_new_render_data(pfjob->bmain,
+ pfjob->depsgraph,
+ pfjob->scene_eval,
+ context->rectx,
+ context->recty,
+ context->preview_render_size,
+ false,
+ &pfjob->context_cpy);
+ pfjob->context_cpy.is_prefetch_render = true;
+ pfjob->context_cpy.task_id = SEQ_TASK_PREFETCH_RENDER;
+
+ BKE_sequencer_new_render_data(pfjob->bmain,
+ pfjob->depsgraph,
+ pfjob->scene,
+ context->rectx,
+ context->recty,
+ context->preview_render_size,
+ false,
+ &pfjob->context);
+ pfjob->context.is_prefetch_render = false;
+
+ /* Same ID as prefetch context, because context will be swapped, but we still
+ * want to assign this ID to cache entries created in this thread.
+ * This is to allow "temp cache" work correctly for both threads.
+ */
+ pfjob->context.task_id = SEQ_TASK_PREFETCH_RENDER;
+}
+
+static void seq_prefetch_update_scene(Scene *scene)
+{
+ PrefetchJob *pfjob = seq_prefetch_job_get(scene);
+
+ if (!pfjob) {
+ return;
+ }
+
+ seq_prefetch_free_depsgraph(pfjob);
+ seq_prefetch_init_depsgraph(pfjob);
+}
+
+static void seq_prefetch_resume(Scene *scene)
+{
+ PrefetchJob *pfjob = seq_prefetch_job_get(scene);
+
+ if (pfjob && pfjob->waiting) {
+ BLI_condition_notify_one(&pfjob->prefetch_suspend_cond);
+ }
+}
+
+void BKE_sequencer_prefetch_free(Scene *scene)
+{
+ PrefetchJob *pfjob = seq_prefetch_job_get(scene);
+ if (!pfjob) {
+ return;
+ }
+
+ BKE_sequencer_prefetch_stop(scene);
+
+ BLI_threadpool_remove(&pfjob->threads, pfjob);
+ BLI_threadpool_end(&pfjob->threads);
+ BLI_mutex_end(&pfjob->prefetch_suspend_mutex);
+ BLI_condition_end(&pfjob->prefetch_suspend_cond);
+ seq_prefetch_free_depsgraph(pfjob);
+ MEM_freeN(pfjob);
+ scene->ed->prefetch_job = NULL;
+}
+
+static void *seq_prefetch_frames(void *job)
+{
+ PrefetchJob *pfjob = (PrefetchJob *)job;
+
+ /* set to NULL before return! */
+ pfjob->scene_eval->ed->prefetch_job = pfjob;
+
+ while (pfjob->cfra + pfjob->num_frames_prefetched < pfjob->scene->r.efra) {
+ BKE_animsys_evaluate_all_animation(pfjob->context_cpy.bmain,
+ pfjob->context_cpy.depsgraph,
+ pfjob->context_cpy.scene,
+ pfjob->cfra + pfjob->num_frames_prefetched);
+ seq_prefetch_update_depsgraph(pfjob);
+
+ ImBuf *ibuf = BKE_sequencer_give_ibuf(
+ &pfjob->context_cpy, pfjob->cfra + pfjob->num_frames_prefetched, 0);
+ BKE_sequencer_cache_free_temp_cache(
+ pfjob->scene, pfjob->context.task_id, pfjob->cfra + pfjob->num_frames_prefetched);
+ IMB_freeImBuf(ibuf);
+
+ /* suspend thread */
+ BLI_mutex_lock(&pfjob->prefetch_suspend_mutex);
+ while ((seq_prefetch_is_cache_full(pfjob->scene) || seq_prefetch_is_scrubbing(pfjob->bmain)) &&
+ pfjob->scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE && !pfjob->stop) {
+ pfjob->waiting = true;
+ BLI_condition_wait(&pfjob->prefetch_suspend_cond, &pfjob->prefetch_suspend_mutex);
+ seq_prefetch_update_area(pfjob);
+ }
+ pfjob->waiting = false;
+ BLI_mutex_unlock(&pfjob->prefetch_suspend_mutex);
+
+ /* Avoid "collision" with main thread, but make sure to fetch at least few frames */
+ if (pfjob->num_frames_prefetched > 5 &&
+ (pfjob->cfra + pfjob->num_frames_prefetched - pfjob->scene->r.cfra) < 2) {
+ break;
+ }
+
+ if (!(pfjob->scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE) || pfjob->stop) {
+ break;
+ }
+
+ seq_prefetch_update_area(pfjob);
+ pfjob->num_frames_prefetched++;
+ }
+
+ BKE_sequencer_cache_free_temp_cache(
+ pfjob->scene, pfjob->context.task_id, pfjob->cfra + pfjob->num_frames_prefetched);
+ pfjob->running = false;
+ pfjob->scene_eval->ed->prefetch_job = NULL;
+
+ return 0;
+}
+
+static PrefetchJob *seq_prefetch_start(const SeqRenderData *context, float cfra)
+{
+ PrefetchJob *pfjob;
+ pfjob = seq_prefetch_job_get(context->scene);
+
+ if (!pfjob) {
+ if (context->scene->ed) {
+ pfjob = (PrefetchJob *)MEM_callocN(sizeof(PrefetchJob), "PrefetchJob");
+ context->scene->ed->prefetch_job = pfjob;
+
+ BLI_threadpool_init(&pfjob->threads, seq_prefetch_frames, 1);
+ BLI_mutex_init(&pfjob->prefetch_suspend_mutex);
+ BLI_condition_init(&pfjob->prefetch_suspend_cond);
+
+ pfjob->bmain = context->bmain;
+
+ pfjob->scene = context->scene;
+ seq_prefetch_init_depsgraph(pfjob);
+ }
+ }
+ seq_prefetch_update_scene(context->scene);
+ seq_prefetch_update_context(context);
+
+ pfjob->cfra = cfra;
+ pfjob->num_frames_prefetched = 1;
+
+ pfjob->waiting = false;
+ pfjob->stop = false;
+ pfjob->running = true;
+
+ if (&pfjob->threads) {
+ BLI_threadpool_remove(&pfjob->threads, pfjob);
+ }
+ BLI_threadpool_insert(&pfjob->threads, pfjob);
+
+ return pfjob;
+}
+
+/* Start or resume prefetching*/
+void BKE_sequencer_prefetch_start(const SeqRenderData *context, float cfra, float cost)
+{
+ Scene *scene = context->scene;
+ Editing *ed = scene->ed;
+ bool has_strips = (bool)ed->seqbasep->first;
+
+ if (!context->is_prefetch_render && !context->is_proxy_render) {
+ bool playing = seq_prefetch_is_playing(context->bmain);
+ bool scrubbing = seq_prefetch_is_scrubbing(context->bmain);
+ bool running = seq_prefetch_job_is_running(scene);
+ seq_prefetch_resume(scene);
+ /* conditions to start:
+ * prefetch enabled, prefetch not running, not scrubbing,
+ * not playing and rendering-expensive footage, cache storage enabled, has strips to render
+ */
+ if ((ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE) && !running && !scrubbing &&
+ !(playing && cost > 0.9) && ed->cache_flag & SEQ_CACHE_ALL_TYPES && has_strips) {
+
+ seq_prefetch_start(context, cfra);
+ }
+ }
+}
+
+bool BKE_sequencer_prefetch_need_redraw(Main *bmain, Scene *scene)
+{
+ bool playing = seq_prefetch_is_playing(bmain);
+ bool scrubbing = seq_prefetch_is_scrubbing(bmain);
+ bool running = seq_prefetch_job_is_running(scene);
+ bool suspended = seq_prefetch_job_is_waiting(scene);
+
+ /* force redraw, when prefetching and using cache view. */
+ if (running && !playing && !suspended && scene->ed->cache_flag & SEQ_CACHE_VIEW_ENABLE) {
+ return true;
+ }
+ /* Sometimes scrubbing flag is set when not scrubbing. In that case I want to catch "event" of
+ * stopping scrubbing */
+ if (scrubbing) {
+ return true;
+ }
+ return false;
+}
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index b29e07bb56d..3e88db787ee 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -112,6 +112,8 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr
static int seq_num_files(Scene *scene, char views_format, const bool is_multiview);
static void seq_anim_add_suffix(Scene *scene, struct anim *anim, const int view_id);
+static ThreadMutex seq_render_mutex = BLI_MUTEX_INITIALIZER;
+
/* **** XXX ******** */
#define SELECT 1
ListBase seqbase_clipboard;
@@ -483,6 +485,7 @@ void BKE_sequencer_editing_free(Scene *scene, const bool do_id_user)
return;
}
+ BKE_sequencer_prefetch_free(scene);
BKE_sequencer_cache_destruct(scene);
SEQ_BEGIN (ed, seq) {
@@ -492,7 +495,6 @@ void BKE_sequencer_editing_free(Scene *scene, const bool do_id_user)
SEQ_END;
BLI_freelistN(&ed->metastack);
-
MEM_freeN(ed);
scene->ed = NULL;
@@ -635,6 +637,8 @@ void BKE_sequencer_new_render_data(Main *bmain,
r_context->is_proxy_render = false;
r_context->view_id = 0;
r_context->gpu_offscreen = NULL;
+ r_context->task_id = SEQ_TASK_MAIN_RENDER;
+ r_context->is_prefetch_render = false;
}
/* ************************* iterator ************************** */
@@ -3534,7 +3538,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
}
/* opengl offscreen render */
- depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ depsgraph = BKE_scene_get_depsgraph(context->bmain, scene, view_layer, true);
BKE_scene_graph_update_for_newframe(depsgraph, context->bmain);
ibuf = sequencer_view3d_cb(
/* set for OpenGL render (NULL when scrubbing) */
@@ -4092,18 +4096,29 @@ ImBuf *BKE_sequencer_give_ibuf(const SeqRenderData *context, float cfra, int cha
out = BKE_sequencer_cache_get(context, seq_arr[count - 1], cfra, SEQ_CACHE_STORE_FINAL_OUT);
}
- BKE_sequencer_cache_free_temp_cache(context->scene, 0, cfra);
+ BKE_sequencer_cache_free_temp_cache(context->scene, context->task_id, cfra);
clock_t begin = seq_estimate_render_cost_begin();
float cost = 0;
if (count && !out) {
+ BLI_mutex_lock(&seq_render_mutex);
out = seq_render_strip_stack(context, &state, seqbasep, cfra, chanshown);
cost = seq_estimate_render_cost_end(context->scene, begin);
- BKE_sequencer_cache_put_if_possible(
- context, seq_arr[count - 1], cfra, SEQ_CACHE_STORE_FINAL_OUT, out, cost);
+
+ if (context->is_prefetch_render) {
+ BKE_sequencer_cache_put(
+ context, seq_arr[count - 1], cfra, SEQ_CACHE_STORE_FINAL_OUT, out, cost);
+ }
+ else {
+ BKE_sequencer_cache_put_if_possible(
+ context, seq_arr[count - 1], cfra, SEQ_CACHE_STORE_FINAL_OUT, out, cost);
+ }
+ BLI_mutex_unlock(&seq_render_mutex);
}
+ BKE_sequencer_prefetch_start(context, cfra, cost);
+
return out;
}
@@ -4334,6 +4349,8 @@ static void sequence_invalidate_cache(Scene *scene,
}
sequence_do_invalidate_dependent(scene, seq, &ed->seqbase);
+ DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
+ BKE_sequencer_prefetch_stop(scene);
}
void BKE_sequence_invalidate_cache_raw(Scene *scene, Sequence *seq)
@@ -4419,6 +4436,7 @@ void BKE_sequencer_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
Sequence *seq;
BKE_sequencer_cache_cleanup(scene);
+ BKE_sequencer_prefetch_stop(scene);
for (seq = seqbase->first; seq; seq = seq->next) {
if (for_render && CFRA >= seq->startdisp && CFRA <= seq->enddisp) {
@@ -4933,7 +4951,7 @@ static bool sequencer_refresh_sound_length_recursive(Main *bmain, Scene *scene,
changed = true;
}
}
- else if (seq->type == SEQ_TYPE_SOUND_RAM) {
+ else if (seq->type == SEQ_TYPE_SOUND_RAM && seq->sound) {
const float length = BKE_sound_get_length(bmain, seq->sound);
int old = seq->len;
float fac;
@@ -5526,7 +5544,7 @@ Sequence *BKE_sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoad
Strip *strip;
seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_IMAGE);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+ seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
/* basic defaults */
seq->len = seq_load->len ? seq_load->len : 1;
@@ -5685,7 +5703,9 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad
seq->views_format = seq_load->views_format;
}
seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+
+ seq->type = SEQ_TYPE_MOVIE;
+ seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
for (i = 0; i < totfiles; i++) {
if (anim_arr[i]) {
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index 9b9fd33f52d..797ae0f0a8a 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -39,6 +39,7 @@
#include "BLI_task.h"
#include "BLI_math_solvers.h"
+#include "BKE_context.h"
#include "BKE_shrinkwrap.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_DerivedMesh.h"
@@ -1408,7 +1409,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd,
Object *ob_target = DEG_get_evaluated_object(ctx->depsgraph, smd->target);
calc.target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false);
- /* TODO there might be several "bugs" on non-uniform scales matrixs
+ /* TODO there might be several "bugs" with non-uniform scales matrices
* because it will no longer be nearest surface, not sphere projection
* because space has been deformed */
BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob, ob_target);
@@ -1480,3 +1481,62 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd,
ss_mesh->release(ss_mesh);
}
}
+
+void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C,
+ Object *ob_source,
+ Object *ob_target)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ struct Scene *sce = CTX_data_scene(C);
+ ShrinkwrapModifierData ssmd = {0};
+ ModifierEvalContext ctx = {depsgraph, ob_source, 0};
+ int totvert;
+
+ ssmd.target = ob_target;
+ ssmd.shrinkType = MOD_SHRINKWRAP_NEAREST_SURFACE;
+ ssmd.shrinkMode = MOD_SHRINKWRAP_ON_SURFACE;
+ ssmd.keepDist = 0.0f;
+
+ Mesh *src_me = ob_source->data;
+ float(*vertexCos)[3] = BKE_mesh_vert_coords_alloc(src_me, &totvert);
+
+ shrinkwrapModifier_deform(&ssmd, &ctx, sce, ob_source, src_me, NULL, -1, vertexCos, totvert);
+
+ BKE_mesh_vert_coords_apply(src_me, vertexCos);
+
+ MEM_freeN(vertexCos);
+}
+
+void BKE_shrinkwrap_remesh_target_project(Mesh *src_me, Mesh *target_me, Object *ob_target)
+{
+ ShrinkwrapModifierData ssmd = {0};
+ int totvert;
+
+ ssmd.target = ob_target;
+ ssmd.shrinkType = MOD_SHRINKWRAP_TARGET_PROJECT;
+ ssmd.shrinkMode = MOD_SHRINKWRAP_ON_SURFACE;
+ ssmd.keepDist = 0.0f;
+
+ float(*vertexCos)[3] = BKE_mesh_vert_coords_alloc(src_me, &totvert);
+
+ ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData;
+
+ calc.smd = &ssmd;
+ calc.numVerts = src_me->totvert;
+ calc.vertexCos = vertexCos;
+ calc.vgroup = -1;
+ calc.target = target_me;
+ calc.keepDist = ssmd.keepDist;
+ BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob_target, ob_target);
+
+ ShrinkwrapTreeData tree;
+ if (BKE_shrinkwrap_init_tree(&tree, calc.target, ssmd.shrinkType, ssmd.shrinkMode, false)) {
+ calc.tree = &tree;
+ TIMEIT_BENCH(shrinkwrap_calc_nearest_surface_point(&calc), deform_surface);
+ BKE_shrinkwrap_free_tree(&tree);
+ }
+
+ BKE_mesh_vert_coords_apply(src_me, vertexCos);
+
+ MEM_freeN(vertexCos);
+}
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 74873db179d..e6c414b92da 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -3352,14 +3352,16 @@ struct Mesh *smokeModifier_do(
if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain &&
smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN && smd->domain->base_res[0]) {
result = createDomainGeometry(smd->domain, ob);
+ BKE_mesh_copy_settings(result, me);
}
else {
result = BKE_mesh_copy_for_eval(me, false);
}
- /* XXX This is really not a nice hack, but until root of the problem is understood,
- * this should be an acceptable workaround I think.
- * See T58492 for details on the issue. */
- result->texflag |= ME_AUTOSPACE;
+
+ /* Smoke simulation needs a texture space relative to the adaptive domain bounds, not the
+ * original mesh. So recompute it at this point in the modifier stack. See T58492. */
+ BKE_mesh_texspace_calc(result);
+
return result;
}
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index d3b72fb295d..b56403dfb6d 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -1049,8 +1049,8 @@ static int sb_detect_aabb_collisionCached(float UNUSED(force[3]),
/* +++ the face external section*/
static int sb_detect_face_pointCached(float face_v1[3],
- float face_v2[3],
- float face_v3[3],
+ const float face_v2[3],
+ const float face_v3[3],
float *damp,
float force[3],
struct Object *vertexowner,
@@ -1147,8 +1147,8 @@ static int sb_detect_face_pointCached(float face_v1[3],
}
static int sb_detect_face_collisionCached(float face_v1[3],
- float face_v2[3],
- float face_v3[3],
+ const float face_v2[3],
+ const float face_v3[3],
float *damp,
float force[3],
struct Object *vertexowner,
@@ -1326,7 +1326,7 @@ static void scan_for_ext_face_forces(Object *ob, float timenow)
/* +++ the spring external section*/
static int sb_detect_edge_collisionCached(float edge_v1[3],
- float edge_v2[3],
+ const float edge_v2[3],
float *damp,
float force[3],
struct Object *vertexowner,
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index c7a0d65a2a9..46a74e25b8b 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -21,6 +21,7 @@
#include "DNA_object_types.h"
#include "DNA_sound_types.h"
#include "DNA_speaker_types.h"
+#include "DNA_defaults.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -34,18 +35,7 @@ void BKE_speaker_init(Speaker *spk)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(spk, id));
- spk->attenuation = 1.0f;
- spk->cone_angle_inner = 360.0f;
- spk->cone_angle_outer = 360.0f;
- spk->cone_volume_outer = 1.0f;
- spk->distance_max = FLT_MAX;
- spk->distance_reference = 1.0f;
- spk->flag = 0;
- spk->pitch = 1.0f;
- spk->sound = NULL;
- spk->volume = 1.0f;
- spk->volume_max = 1.0f;
- spk->volume_min = 0.0f;
+ MEMCPY_STRUCT_AFTER(spk, DNA_struct_default_get(Speaker), id);
}
void *BKE_speaker_add(Main *bmain, const char *name)
diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c
index 6e83f5d75e2..ff92704e2d1 100644
--- a/source/blender/blenkernel/intern/studiolight.c
+++ b/source/blender/blenkernel/intern/studiolight.c
@@ -46,13 +46,16 @@
#include "MEM_guardedalloc.h"
+#include "intern/openexr/openexr_multi.h"
+
/* Statics */
static ListBase studiolights;
static int last_studiolight_id = 0;
#define STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE 96
#define STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT 32
#define STUDIOLIGHT_IRRADIANCE_EQUIRECT_WIDTH (STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT * 2)
-
+#define STUDIOLIGHT_PASSNAME_DIFFUSE "diffuse"
+#define STUDIOLIGHT_PASSNAME_SPECULAR "specular"
/*
* The method to calculate the irradiance buffers
* The irradiance buffer is only shown in the background when in LookDev.
@@ -152,6 +155,10 @@ static void studiolight_free(struct StudioLight *sl)
GPU_TEXTURE_SAFE_FREE(sl->equirect_irradiance_gputexture);
IMB_SAFE_FREE(sl->equirect_radiance_buffer);
IMB_SAFE_FREE(sl->equirect_irradiance_buffer);
+ GPU_TEXTURE_SAFE_FREE(sl->matcap_diffuse.gputexture);
+ GPU_TEXTURE_SAFE_FREE(sl->matcap_specular.gputexture);
+ IMB_SAFE_FREE(sl->matcap_diffuse.ibuf);
+ IMB_SAFE_FREE(sl->matcap_specular.ibuf);
MEM_SAFE_FREE(sl->path_irr_cache);
MEM_SAFE_FREE(sl->path_sh_cache);
MEM_SAFE_FREE(sl);
@@ -342,72 +349,232 @@ static void cube_face_uv_to_direction(float r_dir[3], float x, float y, int face
normalize_v3(r_dir);
}
+typedef struct MultilayerConvertContext {
+ int num_diffuse_channels;
+ float *diffuse_pass;
+ int num_specular_channels;
+ float *specular_pass;
+} MultilayerConvertContext;
+
+static void *studiolight_multilayer_addview(void *UNUSED(base), const char *UNUSED(view_name))
+{
+ return NULL;
+}
+static void *studiolight_multilayer_addlayer(void *base, const char *UNUSED(layer_name))
+{
+ return base;
+}
+
+/* Convert a multilayer pass to ImBuf channel 4 float buffer.
+ * NOTE: Parameter rect will become invalid. Do not use rect after calling this
+ * function */
+static float *studiolight_multilayer_convert_pass(ImBuf *ibuf,
+ float *rect,
+ const unsigned int channels)
+{
+ if (channels == 4) {
+ return rect;
+ }
+ else {
+ float *new_rect = MEM_callocN(sizeof(float[4]) * ibuf->x * ibuf->y, __func__);
+
+ IMB_buffer_float_from_float(new_rect,
+ rect,
+ channels,
+ IB_PROFILE_LINEAR_RGB,
+ IB_PROFILE_LINEAR_RGB,
+ false,
+ ibuf->x,
+ ibuf->y,
+ ibuf->x,
+ ibuf->x);
+
+ MEM_freeN(rect);
+ return new_rect;
+ }
+}
+
+static void studiolight_multilayer_addpass(void *base,
+ void *UNUSED(lay),
+ const char *pass_name,
+ float *rect,
+ int num_channels,
+ const char *UNUSED(chan_id),
+ const char *UNUSED(view_name))
+{
+ MultilayerConvertContext *ctx = base;
+ /* NOTE: This function must free pass pixels data if it is not used, this
+ * is how IMB_exr_multilayer_convert() is working. */
+ /* If we've found a first combined pass, skip all the rest ones. */
+ if (STREQ(pass_name, STUDIOLIGHT_PASSNAME_DIFFUSE)) {
+ ctx->diffuse_pass = rect;
+ ctx->num_diffuse_channels = num_channels;
+ }
+ else if (STREQ(pass_name, STUDIOLIGHT_PASSNAME_SPECULAR)) {
+ ctx->specular_pass = rect;
+ ctx->num_specular_channels = num_channels;
+ }
+ else {
+ MEM_freeN(rect);
+ }
+}
+
static void studiolight_load_equirect_image(StudioLight *sl)
{
if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
- ImBuf *ibuf = NULL;
- ibuf = IMB_loadiffname(sl->path, 0, NULL);
- if (ibuf == NULL) {
- float *colbuf = MEM_mallocN(sizeof(float[4]), __func__);
- copy_v4_fl4(colbuf, 1.0f, 0.0f, 1.0f, 1.0f);
- ibuf = IMB_allocFromBuffer(NULL, colbuf, 1, 1);
+ ImBuf *ibuf = IMB_loadiffname(sl->path, IB_multilayer, NULL);
+ ImBuf *specular_ibuf = NULL;
+ ImBuf *diffuse_ibuf = NULL;
+ const bool failed = (ibuf == NULL);
+
+ if (ibuf) {
+ if (ibuf->ftype == IMB_FTYPE_OPENEXR && ibuf->userdata) {
+ /* the read file is a multilayered openexr file (userdata != NULL)
+ * This file is currently only supported for MATCAPS where
+ * the first found 'diffuse' pass will be used for diffuse lighting
+ * and the first found 'specular' pass will be used for specular lighting */
+ MultilayerConvertContext ctx = {0};
+ IMB_exr_multilayer_convert(ibuf->userdata,
+ &ctx,
+ &studiolight_multilayer_addview,
+ &studiolight_multilayer_addlayer,
+ &studiolight_multilayer_addpass);
+
+ /* `ctx.diffuse_pass` and `ctx.specular_pass` can be freed inside
+ * `studiolight_multilayer_convert_pass` when conversion happens.
+ * When not converted we move the ownership of the buffer to the
+ * `converted_pass`. We only need to free `converted_pass` as it holds
+ * the unmodified allocation from the `ctx.*_pass` or the converted data.
+ */
+ if (ctx.diffuse_pass != NULL) {
+ float *converted_pass = studiolight_multilayer_convert_pass(
+ ibuf, ctx.diffuse_pass, ctx.num_diffuse_channels);
+ diffuse_ibuf = IMB_allocFromBuffer(
+ NULL, converted_pass, ibuf->x, ibuf->y, ctx.num_diffuse_channels);
+ MEM_freeN(converted_pass);
+ }
+
+ if (ctx.specular_pass != NULL) {
+ float *converted_pass = studiolight_multilayer_convert_pass(
+ ibuf, ctx.specular_pass, ctx.num_specular_channels);
+ specular_ibuf = IMB_allocFromBuffer(
+ NULL, converted_pass, ibuf->x, ibuf->y, ctx.num_specular_channels);
+ MEM_freeN(converted_pass);
+ }
+
+ IMB_exr_close(ibuf->userdata);
+ ibuf->userdata = NULL;
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
+ else {
+ /* read file is an single layer openexr file or the read file isn't
+ * an openexr file */
+ IMB_float_from_rect(ibuf);
+ diffuse_ibuf = ibuf;
+ ibuf = NULL;
+ }
+ }
+
+ if (diffuse_ibuf == NULL) {
+ /* Create 1x1 diffuse buffer, in case image failed to load or if there was
+ * only a specular pass in the multilayer file or no passes were found. */
+ const float black[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ const float magenta[4] = {1.0f, 0.0f, 1.0f, 1.0f};
+ diffuse_ibuf = IMB_allocFromBuffer(
+ NULL, (failed || (specular_ibuf == NULL)) ? magenta : black, 1, 1, 4);
+ }
+
+ if ((sl->flag & STUDIOLIGHT_TYPE_MATCAP)) {
+ sl->matcap_diffuse.ibuf = diffuse_ibuf;
+ sl->matcap_specular.ibuf = specular_ibuf;
+ if (specular_ibuf != NULL) {
+ sl->flag |= STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS;
+ }
+ }
+ else {
+ sl->equirect_radiance_buffer = diffuse_ibuf;
+ if (specular_ibuf != NULL) {
+ IMB_freeImBuf(specular_ibuf);
+ }
}
- IMB_float_from_rect(ibuf);
- sl->equirect_radiance_buffer = ibuf;
}
+
sl->flag |= STUDIOLIGHT_EXTERNAL_IMAGE_LOADED;
}
static void studiolight_create_equirect_radiance_gputexture(StudioLight *sl)
{
if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
- char error[256];
BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
ImBuf *ibuf = sl->equirect_radiance_buffer;
- if (sl->flag & STUDIOLIGHT_TYPE_MATCAP) {
- float *gpu_matcap_3components = MEM_callocN(sizeof(float[3]) * ibuf->x * ibuf->y, __func__);
+ sl->equirect_radiance_gputexture = GPU_texture_create_2d(
+ ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, NULL);
+ GPUTexture *tex = sl->equirect_radiance_gputexture;
+ GPU_texture_bind(tex, 0);
+ GPU_texture_filter_mode(tex, true);
+ GPU_texture_wrap_mode(tex, true);
+ GPU_texture_unbind(tex);
+ }
+ sl->flag |= STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE;
+}
- float(*offset4)[4] = (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);
- }
+static void studiolight_create_matcap_gputexture(StudioLightImage *sli)
+{
+ BLI_assert(sli->ibuf);
+ 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;
+ 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);
+ }
+
+ sli->gputexture = GPU_texture_create_nD(ibuf->x,
+ ibuf->y,
+ 0,
+ 2,
+ gpu_matcap_3components,
+ GPU_R11F_G11F_B10F,
+ GPU_DATA_FLOAT,
+ 0,
+ false,
+ NULL);
+ MEM_SAFE_FREE(gpu_matcap_3components);
+}
- sl->equirect_radiance_gputexture = GPU_texture_create_nD(ibuf->x,
- ibuf->y,
- 0,
- 2,
- gpu_matcap_3components,
- GPU_R11F_G11F_B10F,
- GPU_DATA_FLOAT,
- 0,
- false,
- error);
-
- MEM_SAFE_FREE(gpu_matcap_3components);
+static void studiolight_create_matcap_diffuse_gputexture(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ if (sl->flag & STUDIOLIGHT_TYPE_MATCAP) {
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+ studiolight_create_matcap_gputexture(&sl->matcap_diffuse);
}
- else {
- sl->equirect_radiance_gputexture = GPU_texture_create_2d(
- ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error);
- GPUTexture *tex = sl->equirect_radiance_gputexture;
- GPU_texture_bind(tex, 0);
- GPU_texture_filter_mode(tex, true);
- GPU_texture_wrap_mode(tex, true);
- GPU_texture_unbind(tex);
+ }
+ sl->flag |= STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE;
+}
+static void studiolight_create_matcap_specular_gputexture(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ if (sl->flag & STUDIOLIGHT_TYPE_MATCAP) {
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+ if (sl->matcap_specular.ibuf) {
+ studiolight_create_matcap_gputexture(&sl->matcap_specular);
+ }
}
}
- sl->flag |= STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE;
+ sl->flag |= STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE;
}
static void studiolight_create_equirect_irradiance_gputexture(StudioLight *sl)
{
if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
- char error[256];
BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECT_IRRADIANCE_IMAGE_CALCULATED);
ImBuf *ibuf = sl->equirect_irradiance_buffer;
sl->equirect_irradiance_gputexture = GPU_texture_create_2d(
- ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error);
+ ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, NULL);
GPUTexture *tex = sl->equirect_irradiance_gputexture;
GPU_texture_bind(tex, 0);
GPU_texture_filter_mode(tex, true);
@@ -457,32 +624,32 @@ static void studiolight_calculate_radiance_cubemap_buffers(StudioLight *sl)
/* front */
studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 2, 1, 1, -1, 1);
sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS] = IMB_allocFromBuffer(
- NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, 4);
/* back */
studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 2, 1, 1, 1, -1);
sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG] = IMB_allocFromBuffer(
- NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, 4);
/* left */
studiolight_calculate_radiance_buffer(ibuf, colbuf, 2, 1, 0, 1, -1, 1);
sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS] = IMB_allocFromBuffer(
- NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, 4);
/* right */
studiolight_calculate_radiance_buffer(ibuf, colbuf, 2, 1, 0, -1, -1, -1);
sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG] = IMB_allocFromBuffer(
- NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, 4);
/* top */
studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 1, 2, -1, -1, 1);
sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG] = IMB_allocFromBuffer(
- NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, 4);
/* bottom */
studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 1, 2, 1, -1, -1);
sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS] = IMB_allocFromBuffer(
- NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, 4);
#if 0
IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS],
@@ -595,7 +762,7 @@ static void studiolight_spherical_harmonics_calculate_coefficients(StudioLight *
/* The sum of solid angle should be equal to the solid angle of the sphere (4 PI),
* so normalize in order to make our weightAccum exactly match 4 PI. */
- for (int i = 0; i < STUDIOLIGHT_SH_COEFS_LEN; ++i) {
+ for (int i = 0; i < STUDIOLIGHT_SH_COEFS_LEN; i++) {
mul_v3_fl(sh[i], M_PI * 4.0f / weight_accum);
}
}
@@ -603,7 +770,8 @@ static void studiolight_spherical_harmonics_calculate_coefficients(StudioLight *
/* Take monochrome SH as input */
static float studiolight_spherical_harmonics_lambda_get(float *sh, float max_laplacian)
{
- /* From Peter-Pike Sloan's Stupid SH Tricks http://www.ppsloan.org/publications/StupidSH36.pdf */
+ /* From Peter-Pike Sloan's Stupid SH Tricks http://www.ppsloan.org/publications/StupidSH36.pdf
+ */
float table_l[STUDIOLIGHT_SH_BANDS];
float table_b[STUDIOLIGHT_SH_BANDS];
@@ -633,11 +801,11 @@ static float studiolight_spherical_harmonics_lambda_get(float *sh, float max_lap
}
const int no_iterations = 10000000;
- for (int i = 0; i < no_iterations; ++i) {
+ for (int i = 0; i < no_iterations; i++) {
float f = 0.0f;
float fd = 0.0f;
- for (int level = 1; level < STUDIOLIGHT_SH_BANDS; ++level) {
+ for (int level = 1; level < STUDIOLIGHT_SH_BANDS; level++) {
f += table_l[level] * table_b[level] / SQUARE(1.0f + lambda * table_l[level]);
fd += (2.0f * SQUARE(table_l[level]) * table_b[level]) /
CUBE(1.0f + lambda * table_l[level]);
@@ -714,13 +882,12 @@ BLI_INLINE void studiolight_spherical_harmonics_eval(StudioLight *sl,
{
#if STUDIOLIGHT_SH_BANDS == 2
float(*sh)[3] = (float(*)[3])sl->spherical_harmonics_coefs;
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
color[i] = studiolight_spherical_harmonics_geomerics_eval(
normal, sh[0][i], sh[1][i], sh[2][i], sh[3][i]);
}
return;
#else
-
/* L0 */
mul_v3_v3fl(color, sl->spherical_harmonics_coefs[0], 0.282095f);
# if STUDIOLIGHT_SH_BANDS > 1 /* L1 */
@@ -779,7 +946,7 @@ BLI_INLINE void studiolight_spherical_harmonics_eval(StudioLight *sl,
/* This modify the radiance into irradiance. */
static void studiolight_spherical_harmonics_apply_band_factors(StudioLight *sl, float (*sh)[3])
{
- static float sl_sh_band_factors[5] = {
+ static const float sl_sh_band_factors[5] = {
1.0f,
2.0f / 3.0f,
1.0f / 4.0f,
@@ -907,7 +1074,7 @@ static float wrapped_lighting(float NL, float w)
static float blinn_specular(const float L[3],
const float I[3],
const float N[3],
- float R[3],
+ const float R[3],
float NL,
float roughness,
float wrap)
@@ -951,7 +1118,7 @@ static void studiolight_lights_eval(StudioLight *sl, float color[3], const float
copy_v3_v3(spec_light, sl->light_ambient);
reflect_v3_v3v3(R, I, N);
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
SolidLight *light = &sl->light[i];
if (light->flag) {
/* Diffuse lighting */
@@ -1045,7 +1212,8 @@ static void studiolight_calculate_irradiance_equirect_image(StudioLight *sl)
sl->equirect_irradiance_buffer = IMB_allocFromBuffer(NULL,
colbuf,
STUDIOLIGHT_IRRADIANCE_EQUIRECT_WIDTH,
- STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT);
+ STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT,
+ 4);
MEM_freeN(colbuf);
#ifdef STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
@@ -1196,7 +1364,8 @@ static void studiolight_matcap_preview(uint *icon_buffer, StudioLight *sl, bool
{
BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
- ImBuf *ibuf = sl->equirect_radiance_buffer;
+ ImBuf *diffuse_buffer = sl->matcap_diffuse.ibuf;
+ ImBuf *specular_buffer = sl->matcap_specular.ibuf;
ITER_PIXELS (uint, icon_buffer, 1, STUDIOLIGHT_ICON_SIZE, STUDIOLIGHT_ICON_SIZE) {
float dy = RESCALE_COORD(y);
@@ -1206,7 +1375,15 @@ static void studiolight_matcap_preview(uint *icon_buffer, StudioLight *sl, bool
}
float color[4];
- nearest_interpolation_color(ibuf, NULL, color, dx * ibuf->x - 1.0f, dy * ibuf->y - 1.0f);
+ float u = dx * diffuse_buffer->x - 1.0f;
+ float v = dy * diffuse_buffer->y - 1.0f;
+ nearest_interpolation_color(diffuse_buffer, NULL, color, u, v);
+
+ if (specular_buffer) {
+ float specular[4];
+ nearest_interpolation_color(specular_buffer, NULL, specular, u, v);
+ add_v3_v3(color, specular);
+ }
uint alphamask = alpha_circle_mask(dx, dy, 0.5f - texel_size[0], 0.5f);
@@ -1303,9 +1480,9 @@ void BKE_studiolight_default(SolidLight lights[4], float light_ambient[4])
void BKE_studiolight_init(void)
{
/* Add default studio light */
- StudioLight *sl = studiolight_create(STUDIOLIGHT_INTERNAL |
- STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED |
- STUDIOLIGHT_TYPE_STUDIO);
+ StudioLight *sl = studiolight_create(
+ STUDIOLIGHT_INTERNAL | STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED |
+ STUDIOLIGHT_TYPE_STUDIO | STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS);
BLI_strncpy(sl->name, "Default", FILE_MAXFILE);
BLI_addtail(&studiolights, sl);
@@ -1317,7 +1494,8 @@ void BKE_studiolight_init(void)
if (!BKE_appdir_app_is_portable_install()) {
studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES,
STUDIOLIGHT_LIGHTS_FOLDER,
- STUDIOLIGHT_TYPE_STUDIO | STUDIOLIGHT_USER_DEFINED);
+ STUDIOLIGHT_TYPE_STUDIO | STUDIOLIGHT_USER_DEFINED |
+ STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS);
studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES,
STUDIOLIGHT_WORLD_FOLDER,
STUDIOLIGHT_TYPE_WORLD | STUDIOLIGHT_USER_DEFINED);
@@ -1325,8 +1503,10 @@ void BKE_studiolight_init(void)
STUDIOLIGHT_MATCAP_FOLDER,
STUDIOLIGHT_TYPE_MATCAP | STUDIOLIGHT_USER_DEFINED);
}
- studiolight_add_files_from_datafolder(
- BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_LIGHTS_FOLDER, STUDIOLIGHT_TYPE_STUDIO);
+ studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES,
+ STUDIOLIGHT_LIGHTS_FOLDER,
+ STUDIOLIGHT_TYPE_STUDIO |
+ STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS);
studiolight_add_files_from_datafolder(
BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_TYPE_WORLD);
studiolight_add_files_from_datafolder(
@@ -1456,6 +1636,12 @@ void BKE_studiolight_ensure_flag(StudioLight *sl, int flag)
studiolight_calculate_irradiance_equirect_image(sl);
}
}
+ if ((flag & STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE)) {
+ studiolight_create_matcap_diffuse_gputexture(sl);
+ }
+ if ((flag & STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE)) {
+ studiolight_create_matcap_specular_gputexture(sl);
+ }
}
/*
diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c
index d346d4d6f8d..471cca53900 100644
--- a/source/blender/blenkernel/intern/subdiv_ccg.c
+++ b/source/blender/blenkernel/intern/subdiv_ccg.c
@@ -169,11 +169,11 @@ typedef struct CCGEvalGridsData {
SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator;
} CCGEvalGridsData;
-static void subdiv_ccg_eval_grid_element(CCGEvalGridsData *data,
- const int ptex_face_index,
- const float u,
- const float v,
- unsigned char *element)
+static void subdiv_ccg_eval_grid_element_limit(CCGEvalGridsData *data,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ unsigned char *element)
{
Subdiv *subdiv = data->subdiv;
SubdivCCG *subdiv_ccg = data->subdiv_ccg;
@@ -191,18 +191,37 @@ static void subdiv_ccg_eval_grid_element(CCGEvalGridsData *data,
else {
BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, (float *)element);
}
- if (subdiv_ccg->has_mask) {
- float *mask_value_ptr = (float *)(element + subdiv_ccg->mask_offset);
- if (data->mask_evaluator != NULL) {
- *mask_value_ptr = data->mask_evaluator->eval_mask(
- data->mask_evaluator, ptex_face_index, u, v);
- }
- else {
- *mask_value_ptr = 0.0f;
- }
+}
+
+static void subdiv_ccg_eval_grid_element_mask(CCGEvalGridsData *data,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ unsigned char *element)
+{
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ if (!subdiv_ccg->has_mask) {
+ return;
+ }
+ float *mask_value_ptr = (float *)(element + subdiv_ccg->mask_offset);
+ if (data->mask_evaluator != NULL) {
+ *mask_value_ptr = data->mask_evaluator->eval_mask(data->mask_evaluator, ptex_face_index, u, v);
+ }
+ else {
+ *mask_value_ptr = 0.0f;
}
}
+static void subdiv_ccg_eval_grid_element(CCGEvalGridsData *data,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ unsigned char *element)
+{
+ subdiv_ccg_eval_grid_element_limit(data, ptex_face_index, u, v, element);
+ subdiv_ccg_eval_grid_element_mask(data, ptex_face_index, u, v, element);
+}
+
static void subdiv_ccg_eval_regular_grid(CCGEvalGridsData *data, const int face_index)
{
SubdivCCG *subdiv_ccg = data->subdiv_ccg;
@@ -572,7 +591,7 @@ Mesh *BKE_subdiv_to_ccg_mesh(Subdiv *subdiv,
{
/* Make sure evaluator is ready. */
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
- if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh)) {
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh, NULL)) {
if (coarse_mesh->totpoly) {
return false;
}
diff --git a/source/blender/blenkernel/intern/subdiv_converter_mesh.c b/source/blender/blenkernel/intern/subdiv_converter_mesh.c
index 37ca6d0e485..60f80628f5a 100644
--- a/source/blender/blenkernel/intern/subdiv_converter_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_converter_mesh.c
@@ -221,7 +221,7 @@ static void precalc_uv_layer(const OpenSubdiv_Converter *converter, const int la
mpoly, mloop, mloopuv, num_poly, num_vert, limit, false, true);
/* NOTE: First UV vertex is supposed to be always marked as separate. */
storage->num_uv_coordinates = -1;
- for (int vertex_index = 0; vertex_index < num_vert; ++vertex_index) {
+ for (int vertex_index = 0; vertex_index < num_vert; vertex_index++) {
const UvMapVert *uv_vert = BKE_mesh_uv_vert_map_get_vert(uv_vert_map, vertex_index);
while (uv_vert != NULL) {
if (uv_vert->separate) {
diff --git a/source/blender/blenkernel/intern/subdiv_deform.c b/source/blender/blenkernel/intern/subdiv_deform.c
new file mode 100644
index 00000000000..9c7949e7bdb
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_deform.c
@@ -0,0 +1,237 @@
+/*
+ * 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 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv_deform.h"
+
+#include <string.h>
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_customdata.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_eval.h"
+#include "BKE_subdiv_foreach.h"
+#include "BKE_subdiv_mesh.h"
+
+#include "MEM_guardedalloc.h"
+
+/* ================================================================================================
+ * Subdivision context.
+ */
+
+typedef struct SubdivDeformContext {
+ const Mesh *coarse_mesh;
+ Subdiv *subdiv;
+
+ float (*vertex_cos)[3];
+ int num_verts;
+
+ /* Accumulated values.
+ *
+ * Averaging is happening for vertices which correspond to the coarse ones.
+ * This is needed for displacement.
+ *
+ * Displacement is being accumulated to a vertices coordinates, since those
+ * are not needed during traversal of face-vertices vertices. */
+ /* Per-subdivided vertex counter of averaged values. */
+ int *accumulated_counters;
+
+ bool have_displacement;
+} SubdivDeformContext;
+
+static void subdiv_mesh_prepare_accumulator(SubdivDeformContext *ctx, int num_vertices)
+{
+ if (!ctx->have_displacement) {
+ return;
+ }
+ ctx->accumulated_counters = MEM_calloc_arrayN(
+ sizeof(*ctx->accumulated_counters), num_vertices, "subdiv accumulated counters");
+}
+
+static void subdiv_mesh_context_free(SubdivDeformContext *ctx)
+{
+ MEM_SAFE_FREE(ctx->accumulated_counters);
+}
+
+/* ================================================================================================
+ * Accumulation helpers.
+ */
+
+static void subdiv_accumulate_vertex_displacement(SubdivDeformContext *ctx,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ int vertex_index)
+{
+ Subdiv *subdiv = ctx->subdiv;
+ float dummy_P[3], dPdu[3], dPdv[3], D[3];
+ BKE_subdiv_eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
+ /* Accumulate displacement if needed. */
+ if (ctx->have_displacement) {
+ BKE_subdiv_eval_displacement(subdiv, ptex_face_index, u, v, dPdu, dPdv, D);
+ /* NOTE: The storage for vertex coordinates is coming from an external world, not necessarily
+ * initialized to zeroes. */
+ if (ctx->accumulated_counters[vertex_index] == 0) {
+ copy_v3_v3(ctx->vertex_cos[vertex_index], D);
+ }
+ else {
+ add_v3_v3(ctx->vertex_cos[vertex_index], D);
+ }
+ }
+ ++ctx->accumulated_counters[vertex_index];
+}
+
+/* ================================================================================================
+ * Subdivision callbacks.
+ */
+
+static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_context,
+ const int UNUSED(num_vertices),
+ const int UNUSED(num_edges),
+ const int UNUSED(num_loops),
+ const int UNUSED(num_polygons))
+{
+ SubdivDeformContext *subdiv_context = foreach_context->user_data;
+ subdiv_mesh_prepare_accumulator(subdiv_context, subdiv_context->coarse_mesh->totvert);
+ return true;
+}
+
+static void subdiv_mesh_vertex_every_corner(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int coarse_vertex_index,
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int UNUSED(subdiv_vertex_index))
+{
+ SubdivDeformContext *ctx = foreach_context->user_data;
+ subdiv_accumulate_vertex_displacement(ctx, ptex_face_index, u, v, coarse_vertex_index);
+}
+
+static void subdiv_mesh_vertex_corner(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int coarse_vertex_index,
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int UNUSED(subdiv_vertex_index))
+{
+ SubdivDeformContext *ctx = foreach_context->user_data;
+ BLI_assert(coarse_vertex_index != ORIGINDEX_NONE);
+ BLI_assert(coarse_vertex_index < ctx->num_verts);
+ float inv_num_accumulated = 1.0f;
+ if (ctx->accumulated_counters != NULL) {
+ inv_num_accumulated = 1.0f / ctx->accumulated_counters[coarse_vertex_index];
+ }
+ /* Displacement is accumulated in subdiv vertex position.
+ * Needs to be backed up before copying data from original vertex. */
+ float D[3] = {0.0f, 0.0f, 0.0f};
+ float *vertex_co = ctx->vertex_cos[coarse_vertex_index];
+ if (ctx->have_displacement) {
+ copy_v3_v3(D, vertex_co);
+ mul_v3_fl(D, inv_num_accumulated);
+ }
+ /* Copy custom data and evaluate position. */
+ BKE_subdiv_eval_limit_point(ctx->subdiv, ptex_face_index, u, v, vertex_co);
+ /* Apply displacement. */
+ add_v3_v3(vertex_co, D);
+}
+
+/* ================================================================================================
+ * Initialization.
+ */
+
+static void setup_foreach_callbacks(const SubdivDeformContext *subdiv_context,
+ SubdivForeachContext *foreach_context)
+{
+ memset(foreach_context, 0, sizeof(*foreach_context));
+ /* General information. */
+ foreach_context->topology_info = subdiv_mesh_topology_info;
+ /* Every boundary geometry. Used for displacement and normals averaging. */
+ if (subdiv_context->have_displacement) {
+ foreach_context->vertex_every_corner = subdiv_mesh_vertex_every_corner;
+ }
+ foreach_context->vertex_corner = subdiv_mesh_vertex_corner;
+}
+
+/* ================================================================================================
+ * Public entry point.
+ */
+
+void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv,
+ const struct Mesh *coarse_mesh,
+ float (*vertex_cos)[3],
+ int num_verts)
+{
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
+ /* Make sure evaluator is up to date with possible new topology, and that
+ * is is refined for the new positions of coarse vertices.
+ */
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh, vertex_cos)) {
+ /* This could happen in two situations:
+ * - OpenSubdiv is disabled.
+ * - Something totally bad happened, and OpenSubdiv rejected our
+ * topology.
+ * In either way, we can't safely continue. */
+ if (coarse_mesh->totpoly) {
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
+ return;
+ }
+ }
+
+ /* Initialize subdivion mesh creation context. */
+ SubdivDeformContext subdiv_context = {0};
+ subdiv_context.coarse_mesh = coarse_mesh;
+ subdiv_context.subdiv = subdiv;
+ subdiv_context.vertex_cos = vertex_cos;
+ subdiv_context.num_verts = num_verts;
+ subdiv_context.have_displacement = (subdiv->displacement_evaluator != NULL);
+
+ SubdivForeachContext foreach_context;
+ setup_foreach_callbacks(&subdiv_context, &foreach_context);
+ foreach_context.user_data = &subdiv_context;
+
+ /* Dummy mesh rasterization settings. */
+ SubdivToMeshSettings mesh_settings;
+ mesh_settings.resolution = 1;
+ mesh_settings.use_optimal_display = false;
+
+ /* Multi-threaded traversal/evaluation. */
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
+ BKE_subdiv_foreach_subdiv_geometry(subdiv, &foreach_context, &mesh_settings, coarse_mesh);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
+
+ // BKE_mesh_validate(result, true, true);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
+
+ /* Free used memory. */
+ subdiv_mesh_context_free(&subdiv_context);
+}
diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c
index cb042e087d5..bf5e886dd22 100644
--- a/source/blender/blenkernel/intern/subdiv_eval.c
+++ b/source/blender/blenkernel/intern/subdiv_eval.c
@@ -61,7 +61,9 @@ bool BKE_subdiv_eval_begin(Subdiv *subdiv)
return true;
}
-static void set_coarse_positions(Subdiv *subdiv, const Mesh *mesh)
+static void set_coarse_positions(Subdiv *subdiv,
+ const Mesh *mesh,
+ const float (*coarse_vertex_cos)[3])
{
const MVert *mvert = mesh->mvert;
const MLoop *mloop = mesh->mloop;
@@ -83,8 +85,15 @@ static void set_coarse_positions(Subdiv *subdiv, const Mesh *mesh)
if (!BLI_BITMAP_TEST_BOOL(vertex_used_map, vertex_index)) {
continue;
}
- const MVert *vertex = &mvert[vertex_index];
- subdiv->evaluator->setCoarsePositions(subdiv->evaluator, vertex->co, manifold_veretx_index, 1);
+ const float *vertex_co;
+ if (coarse_vertex_cos != NULL) {
+ vertex_co = coarse_vertex_cos[vertex_index];
+ }
+ else {
+ const MVert *vertex = &mvert[vertex_index];
+ vertex_co = vertex->co;
+ }
+ subdiv->evaluator->setCoarsePositions(subdiv->evaluator, vertex_co, manifold_veretx_index, 1);
manifold_veretx_index++;
}
MEM_freeN(vertex_used_map);
@@ -101,7 +110,7 @@ static void set_face_varying_data_from_uv(Subdiv *subdiv,
/* TODO(sergey): OpenSubdiv's C-API converter can change winding of
* loops of a face, need to watch for that, to prevent wrong UVs assigned.
*/
- for (int face_index = 0; face_index < num_faces; ++face_index) {
+ for (int face_index = 0; face_index < num_faces; face_index++) {
const int num_face_vertices = topology_refiner->getNumFaceVertices(topology_refiner,
face_index);
const int *uv_indices = topology_refiner->getFaceFVarValueIndices(
@@ -112,7 +121,9 @@ static void set_face_varying_data_from_uv(Subdiv *subdiv,
}
}
-bool BKE_subdiv_eval_update_from_mesh(Subdiv *subdiv, const Mesh *mesh)
+bool BKE_subdiv_eval_update_from_mesh(Subdiv *subdiv,
+ const Mesh *mesh,
+ const float (*coarse_vertex_cos)[3])
{
if (!BKE_subdiv_eval_begin(subdiv)) {
return false;
@@ -123,7 +134,7 @@ bool BKE_subdiv_eval_update_from_mesh(Subdiv *subdiv, const Mesh *mesh)
return false;
}
/* Set coordinates of base mesh vertices. */
- set_coarse_positions(subdiv, mesh);
+ set_coarse_positions(subdiv, mesh, coarse_vertex_cos);
/* Set face-varyign data to UV maps. */
const int num_uv_layers = CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
for (int layer_index = 0; layer_index < num_uv_layers; layer_index++) {
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
index 1ff9140681f..a30dde6284b 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -82,7 +82,7 @@ static void subdiv_mesh_ctx_cache_uv_layers(SubdivMeshContext *ctx)
{
Mesh *subdiv_mesh = ctx->subdiv_mesh;
ctx->num_uv_layers = CustomData_number_of_layers(&subdiv_mesh->ldata, CD_MLOOPUV);
- for (int layer_index = 0; layer_index < ctx->num_uv_layers; ++layer_index) {
+ for (int layer_index = 0; layer_index < ctx->num_uv_layers; layer_index++) {
ctx->uv_layers[layer_index] = CustomData_get_layer_n(
&subdiv_mesh->ldata, CD_MLOOPUV, layer_index);
}
@@ -220,7 +220,7 @@ static void vertex_interpolation_init(const SubdivMeshContext *ctx,
const float weight = 1.0f / (float)coarse_poly->totloop;
float *weights = BLI_array_alloca(weights, coarse_poly->totloop);
int *indices = BLI_array_alloca(indices, coarse_poly->totloop);
- for (int i = 0; i < coarse_poly->totloop; ++i) {
+ for (int i = 0; i < coarse_poly->totloop; i++) {
weights[i] = weight;
indices[i] = coarse_mloop[coarse_poly->loopstart + i].v;
}
@@ -352,7 +352,7 @@ static void loop_interpolation_init(const SubdivMeshContext *ctx,
const float weight = 1.0f / (float)coarse_poly->totloop;
float *weights = BLI_array_alloca(weights, coarse_poly->totloop);
int *indices = BLI_array_alloca(indices, coarse_poly->totloop);
- for (int i = 0; i < coarse_poly->totloop; ++i) {
+ for (int i = 0; i < coarse_poly->totloop; i++) {
weights[i] = weight;
indices[i] = coarse_poly->loopstart + i;
}
@@ -482,6 +482,8 @@ static void subdiv_accumulate_vertex_normal_and_displacement(SubdivMeshContext *
}
/* Accumulate displacement if needed. */
if (ctx->have_displacement) {
+ /* NOTE: The subdivided mesh is allocated in this module, and its vertices are kept at zero
+ * locations as a default calloc(). */
BKE_subdiv_eval_displacement(subdiv, ptex_face_index, u, v, dPdu, dPdv, D);
add_v3_v3(subdiv_vert->co, D);
}
@@ -498,9 +500,14 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex
const int num_loops,
const int num_polygons)
{
+ /* Multires grid data will be applied or become invalid after subdivision,
+ * so don't try to preserve it and use memory. */
+ CustomData_MeshMasks mask = CD_MASK_EVERYTHING;
+ mask.lmask &= ~CD_MASK_MULTIRES_GRIDS;
+
SubdivMeshContext *subdiv_context = foreach_context->user_data;
- subdiv_context->subdiv_mesh = BKE_mesh_new_nomain_from_template(
- subdiv_context->coarse_mesh, num_vertices, num_edges, 0, num_loops, num_polygons);
+ subdiv_context->subdiv_mesh = BKE_mesh_new_nomain_from_template_ex(
+ subdiv_context->coarse_mesh, num_vertices, num_edges, 0, num_loops, num_polygons, mask);
subdiv_mesh_ctx_cache_custom_data_layers(subdiv_context);
subdiv_mesh_prepare_accumulator(subdiv_context, num_vertices);
return true;
@@ -1159,7 +1166,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
/* Make sure evaluator is up to date with possible new topology, and that
* is is refined for the new positions of coarse vertices.
*/
- if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh)) {
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh, NULL)) {
/* This could happen in two situations:
* - OpenSubdiv is disabled.
* - Something totally bad happened, and OpenSubdiv rejected our
@@ -1170,7 +1177,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
return NULL;
}
}
- /* Initialize subdivion mesh creation context/ */
+ /* Initialize subdivion mesh creation context. */
SubdivMeshContext subdiv_context = {0};
subdiv_context.settings = settings;
subdiv_context.coarse_mesh = coarse_mesh;
@@ -1193,7 +1200,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
if (!subdiv_context.can_evaluate_normals) {
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
- /* Free used memoty. */
+ /* Free used memory. */
subdiv_mesh_context_free(&subdiv_context);
return result;
}
diff --git a/source/blender/blenkernel/intern/subdiv_topology.c b/source/blender/blenkernel/intern/subdiv_topology.c
new file mode 100644
index 00000000000..455fa2cf28f
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_topology.c
@@ -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.
+ *
+ * The Original Code is Copyright (C) 2019 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv_topology.h"
+
+#include "BKE_subdiv.h"
+
+#include "opensubdiv_topology_refiner_capi.h"
+
+int BKE_subdiv_topology_num_fvar_layers_get(const struct Subdiv *subdiv)
+{
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ return topology_refiner->getNumFVarChannels(topology_refiner);
+}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 77dc438cd04..11d2314ace3 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -1784,7 +1784,7 @@ static void *ccgDM_get_tessface_data_layer(DerivedMesh *dm, int type)
/* With ccgdm, we have a simple one to one mapping between loops
* and tessellated face corners. */
- for (i = 0; i < numLoops; ++i, ++tlnors_it, ++lnors) {
+ for (i = 0; i < numLoops; i++, tlnors_it++, lnors++) {
normal_float_to_short_v3(*tlnors_it, *lnors);
}
}
@@ -2263,7 +2263,7 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
}
if (edgeOrigIndex) {
- for (i = 0; i < numFinalEdges; ++i) {
+ for (i = 0; i < numFinalEdges; i++) {
edgeOrigIndex[edgeNum + i] = ORIGINDEX_NONE;
}
}
@@ -2321,7 +2321,7 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
edgeNum += numFinalEdges;
}
- for (index = 0; index < totedge; ++index) {
+ for (index = 0; index < totedge; index++) {
CCGEdge *e = ccgdm->edgeMap[index].edge;
int numFinalEdges = edgeSize - 1;
int mapIndex = ccgDM_getEdgeMapIndex(ss, e);
@@ -2359,13 +2359,13 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
if (has_edge_cd) {
BLI_assert(edgeIdx >= 0 && edgeIdx < dm->getNumEdges(dm));
- for (i = 0; i < numFinalEdges; ++i) {
+ for (i = 0; i < numFinalEdges; i++) {
CustomData_copy_data(&dm->edgeData, &ccgdm->dm.edgeData, edgeIdx, edgeNum + i, 1);
}
}
if (edgeOrigIndex) {
- for (i = 0; i < numFinalEdges; ++i) {
+ for (i = 0; i < numFinalEdges; i++) {
edgeOrigIndex[edgeNum + i] = mapIndex;
}
}
@@ -2384,7 +2384,7 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
}
}
- for (index = 0; index < totvert; ++index) {
+ for (index = 0; index < totvert; index++) {
CCGVert *v = ccgdm->vertMap[index].vert;
int mapIndex = ccgDM_getVertMapIndex(ccgdm->ss, v);
int vertIdx;
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index ad7c5e3f660..f4e89160487 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -41,6 +41,7 @@
#include "DNA_color_types.h"
#include "DNA_particle_types.h"
#include "DNA_linestyle_types.h"
+#include "DNA_defaults.h"
#include "IMB_imbuf.h"
@@ -214,56 +215,11 @@ void BKE_texture_free(Tex *tex)
void BKE_texture_default(Tex *tex)
{
- /* Not here, can be called with some pointers set. :/ */
- /* BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(tex, id)); */
-
- tex->type = TEX_IMAGE;
- tex->ima = NULL;
- tex->stype = 0;
- tex->flag = TEX_CHECKER_ODD;
- tex->imaflag = TEX_INTERPOL | TEX_MIPMAP | TEX_USEALPHA;
- tex->extend = TEX_REPEAT;
- tex->cropxmin = tex->cropymin = 0.0;
- tex->cropxmax = tex->cropymax = 1.0;
- tex->texfilter = TXF_EWA;
- tex->afmax = 8;
- tex->xrepeat = tex->yrepeat = 1;
- tex->sfra = 1;
- tex->frames = 0;
- tex->offset = 0;
- tex->noisesize = 0.25;
- tex->noisedepth = 2;
- tex->turbul = 5.0;
- tex->nabla = 0.025; // also in do_versions
- tex->bright = 1.0;
- tex->contrast = 1.0;
- tex->saturation = 1.0;
- tex->filtersize = 1.0;
- tex->rfac = 1.0;
- tex->gfac = 1.0;
- tex->bfac = 1.0;
- /* newnoise: init. */
- tex->noisebasis = 0;
- tex->noisebasis2 = 0;
- /* musgrave */
- tex->mg_H = 1.0;
- tex->mg_lacunarity = 2.0;
- tex->mg_octaves = 2.0;
- tex->mg_offset = 1.0;
- tex->mg_gain = 1.0;
- tex->ns_outscale = 1.0;
- /* distnoise */
- tex->dist_amount = 1.0;
- /* voronoi */
- tex->vn_w1 = 1.0;
- tex->vn_w2 = tex->vn_w3 = tex->vn_w4 = 0.0;
- tex->vn_mexp = 2.5;
- tex->vn_distm = 0;
- tex->vn_coltype = 0;
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(tex, id));
- BKE_imageuser_default(&tex->iuser);
+ MEMCPY_STRUCT_AFTER(tex, DNA_struct_default_get(Tex), id);
- tex->preview = NULL;
+ BKE_imageuser_default(&tex->iuser);
}
void BKE_texture_type_set(Tex *tex, int type)
@@ -288,69 +244,7 @@ Tex *BKE_texture_add(Main *bmain, const char *name)
void BKE_texture_mtex_default(MTex *mtex)
{
- mtex->texco = TEXCO_UV;
- mtex->mapto = MAP_COL;
- mtex->object = NULL;
- mtex->projx = PROJ_X;
- mtex->projy = PROJ_Y;
- mtex->projz = PROJ_Z;
- mtex->mapping = MTEX_FLAT;
- mtex->ofs[0] = 0.0;
- mtex->ofs[1] = 0.0;
- mtex->ofs[2] = 0.0;
- mtex->size[0] = 1.0;
- mtex->size[1] = 1.0;
- mtex->size[2] = 1.0;
- mtex->tex = NULL;
- mtex->colormodel = 0;
- mtex->r = 1.0;
- mtex->g = 0.0;
- mtex->b = 1.0;
- mtex->k = 1.0;
- mtex->def_var = 1.0;
- mtex->blendtype = MTEX_BLEND;
- mtex->colfac = 1.0;
- mtex->norfac = 1.0;
- mtex->varfac = 1.0;
- mtex->dispfac = 0.2;
- mtex->colspecfac = 1.0f;
- mtex->mirrfac = 1.0f;
- mtex->alphafac = 1.0f;
- mtex->difffac = 1.0f;
- mtex->specfac = 1.0f;
- mtex->emitfac = 1.0f;
- mtex->hardfac = 1.0f;
- mtex->raymirrfac = 1.0f;
- mtex->translfac = 1.0f;
- mtex->ambfac = 1.0f;
- mtex->colemitfac = 1.0f;
- mtex->colreflfac = 1.0f;
- mtex->coltransfac = 1.0f;
- mtex->densfac = 1.0f;
- mtex->scatterfac = 1.0f;
- mtex->reflfac = 1.0f;
- mtex->shadowfac = 1.0f;
- mtex->zenupfac = 1.0f;
- mtex->zendownfac = 1.0f;
- mtex->blendfac = 1.0f;
- mtex->timefac = 1.0f;
- mtex->lengthfac = 1.0f;
- mtex->clumpfac = 1.0f;
- mtex->kinkfac = 1.0f;
- mtex->kinkampfac = 1.0f;
- mtex->roughfac = 1.0f;
- mtex->twistfac = 1.0f;
- mtex->padensfac = 1.0f;
- mtex->lifefac = 1.0f;
- mtex->sizefac = 1.0f;
- mtex->ivelfac = 1.0f;
- mtex->dampfac = 1.0f;
- mtex->gravityfac = 1.0f;
- mtex->fieldfac = 1.0f;
- mtex->normapspace = MTEX_NSPACE_TANGENT;
- mtex->brush_map_mode = MTEX_MAP_MODE_TILED;
- mtex->random_angle = 2.0f * (float)M_PI;
- mtex->brush_angle_mode = 0;
+ memcpy(mtex, DNA_struct_default_get(MTex), sizeof(*mtex));
}
/* ------------------------------------------------------------------------- */
@@ -423,6 +317,9 @@ MTex *BKE_texture_mtex_add_id(ID *id, int slot)
*/
void BKE_texture_copy_data(Main *bmain, Tex *tex_dst, const Tex *tex_src, const int flag)
{
+ /* We always need allocation of our private ID data. */
+ const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
+
if (!BKE_texture_is_image_user(tex_src)) {
tex_dst->ima = NULL;
}
@@ -434,9 +331,8 @@ void BKE_texture_copy_data(Main *bmain, Tex *tex_dst, const Tex *tex_src, const
if (tex_src->nodetree->execdata) {
ntreeTexEndExecTree(tex_src->nodetree->execdata);
}
- /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
- * (see BKE_libblock_copy_ex()). */
- BKE_id_copy_ex(bmain, (ID *)tex_src->nodetree, (ID **)&tex_dst->nodetree, flag);
+ BKE_id_copy_ex(
+ bmain, (ID *)tex_src->nodetree, (ID **)&tex_dst->nodetree, flag_private_id_data);
}
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index a5445be7ce5..1e7b3af53d5 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -1843,18 +1843,18 @@ void BKE_tracking_plane_marker_get_subframe_corners(MovieTrackingPlaneTrack *pla
MovieTrackingPlaneMarker *marker_next = marker + 1;
if (marker_next->framenr == marker->framenr + 1) {
float fac = (framenr - (int)framenr) / (marker_next->framenr - marker->framenr);
- for (i = 0; i < 4; ++i) {
+ for (i = 0; i < 4; i++) {
interp_v2_v2v2(corners[i], marker->corners[i], marker_next->corners[i], fac);
}
}
else {
- for (i = 0; i < 4; ++i) {
+ for (i = 0; i < 4; i++) {
copy_v2_v2(corners[i], marker->corners[i]);
}
}
}
else {
- for (i = 0; i < 4; ++i) {
+ for (i = 0; i < 4; i++) {
copy_v2_v2(corners[i], marker->corners[i]);
}
}
diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c
index 47c12b329dc..fad928c12fe 100644
--- a/source/blender/blenkernel/intern/tracking_auto.c
+++ b/source/blender/blenkernel/intern/tracking_auto.c
@@ -133,7 +133,7 @@ static void dna_marker_to_libmv_marker(/*const*/ MovieTrackingTrack *track,
libmv_marker->track = track_index;
normalized_to_libmv_frame(marker->pos, frame_dimensions, libmv_marker->center);
- for (i = 0; i < 4; ++i) {
+ for (i = 0; i < 4; i++) {
normalized_relative_to_libmv_frame(
marker->pattern_corners[i], marker->pos, frame_dimensions, libmv_marker->patch[i]);
}
@@ -187,7 +187,7 @@ static void libmv_marker_to_dna_marker(libmv_Marker *libmv_marker,
marker->framenr = libmv_marker->frame;
libmv_frame_to_normalized(libmv_marker->center, frame_dimensions, marker->pos);
- for (i = 0; i < 4; ++i) {
+ for (i = 0; i < 4; i++) {
libmv_frame_to_normalized_relative(libmv_marker->patch[i],
libmv_marker->center,
frame_dimensions,
@@ -261,7 +261,7 @@ static void fill_autotrack_tracks(const int frame_width,
/* Count number of markers to be put to a context. */
size_t num_trackable_markers = 0;
for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
- for (int i = 0; i < track->markersnr; ++i) {
+ for (int i = 0; i < track->markersnr; i++) {
const MovieTrackingMarker *marker = track->markers + i;
if ((marker->flag & MARKER_DISABLED) == 0) {
num_trackable_markers++;
@@ -278,7 +278,7 @@ static void fill_autotrack_tracks(const int frame_width,
/* Fill in markers array. */
int track_index = 0, num_filled_libmv_markers = 0;
for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
- for (int i = 0; i < track->markersnr; ++i) {
+ for (int i = 0; i < track->markersnr; i++) {
MovieTrackingMarker *marker = track->markers + i;
if ((marker->flag & MARKER_DISABLED) != 0) {
continue;
@@ -319,7 +319,7 @@ static void create_per_track_tracking_options(const MovieClip *clip,
int i = 0, track_index = 0;
for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
if (!check_track_trackable(clip, track, user)) {
- ++track_index;
+ track_index++;
continue;
}
AutoTrackOptions *options = &context->options[i++];
@@ -330,7 +330,7 @@ static void create_per_track_tracking_options(const MovieClip *clip,
tracking_configure_tracker(track, NULL, &options->track_region_options);
options->use_keyframe_match = track->pattern_match == TRACK_MATCH_KEYFRAME;
context->tracks[track_index] = track;
- ++track_index;
+ track_index++;
}
}
@@ -471,7 +471,7 @@ void BKE_autotrack_context_sync(AutoTrackContext *context)
libmv_Marker libmv_marker;
int clip = 0;
int track;
- for (track = 0; track < context->num_tracks; ++track) {
+ for (track = 0; track < context->num_tracks; track++) {
AutoTrackOptions *options = &context->options[track];
int track_frame = BKE_movieclip_remap_scene_to_clip_frame(
context->clips[options->clip_index], frame);
@@ -506,7 +506,7 @@ void BKE_autotrack_context_sync(AutoTrackContext *context)
}
BLI_spin_unlock(&context->spin_lock);
- for (int clip = 0; clip < context->num_clips; ++clip) {
+ for (int clip = 0; clip < context->num_clips; clip++) {
MovieTracking *tracking = &context->clips[clip]->tracking;
BKE_tracking_dopesheet_tag_update(tracking);
}
@@ -524,7 +524,7 @@ void BKE_autotrack_context_finish(AutoTrackContext *context)
{
int clip_index;
- for (clip_index = 0; clip_index < context->num_clips; ++clip_index) {
+ for (clip_index = 0; clip_index < context->num_clips; clip_index++) {
MovieClip *clip = context->clips[clip_index];
ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
MovieTrackingPlaneTrack *plane_track;
@@ -532,7 +532,7 @@ void BKE_autotrack_context_finish(AutoTrackContext *context)
for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
int track;
- for (track = 0; track < context->num_tracks; ++track) {
+ for (track = 0; track < context->num_tracks; track++) {
if (BKE_tracking_plane_track_has_point_track(plane_track,
context->options[track].track)) {
BKE_tracking_track_plane_from_existing_motion(plane_track, context->first_frame);
diff --git a/source/blender/blenkernel/intern/tracking_solver.c b/source/blender/blenkernel/intern/tracking_solver.c
index 7e7a839b645..ab741eed410 100644
--- a/source/blender/blenkernel/intern/tracking_solver.c
+++ b/source/blender/blenkernel/intern/tracking_solver.c
@@ -221,7 +221,7 @@ static bool reconstruct_retrieve_libmv_tracks(MovieReconstructContext *context,
*
* There's one weak part tho, which is requirement object
* motion starts at the same frame as camera motion does,
- * otherwise that;' be a russian roulette whether object is
+ * otherwise that;' be a Russian roulette whether object is
* aligned correct or not.
*/
if (!origin_set) {
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index 03229c654fb..2c270f10908 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -274,10 +274,10 @@ static int search_closest_marker_index(MovieTrackingTrack *track, int ref_frame)
i = MAX2(0, i);
i = MIN2(i, end - 1);
- for (; i < end - 1 && markers[i].framenr <= ref_frame; ++i) {
+ for (; i < end - 1 && markers[i].framenr <= ref_frame; i++) {
/* pass */
}
- for (; 0 < i && markers[i].framenr > ref_frame; --i) {
+ for (; 0 < i && markers[i].framenr > ref_frame; i--) {
/* pass */
}
@@ -294,7 +294,7 @@ static void retrieve_next_higher_usable_frame(
while (i < end &&
(markers[i].framenr < ref_frame || is_effectively_disabled(ctx, track, &markers[i]))) {
- ++i;
+ i++;
}
if (i < end && markers[i].framenr < *next_higher) {
BLI_assert(markers[i].framenr >= ref_frame);
@@ -309,7 +309,7 @@ static void retrieve_next_lower_usable_frame(
BLI_assert(0 <= i && i < track->markersnr);
while (i >= 0 &&
(markers[i].framenr > ref_frame || is_effectively_disabled(ctx, track, &markers[i]))) {
- --i;
+ i--;
}
if (0 <= i && markers[i].framenr > *next_lower) {
BLI_assert(markers[i].framenr <= ref_frame);
@@ -782,7 +782,7 @@ static int establish_track_initialization_order(StabContext *ctx, TrackInitOrder
if (marker != NULL && (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT))) {
order[tracknr].sort_value = abs(marker->framenr - anchor_frame);
order[tracknr].reference_frame = marker->framenr;
- ++tracknr;
+ tracknr++;
}
}
if (tracknr) {
@@ -907,7 +907,7 @@ static void initialize_all_tracks(StabContext *ctx, float aspect)
local_data->track_weight_curve = retrieve_track_weight_animation(clip, track);
local_data->is_init_for_stabilization = false;
- ++track_len;
+ track_len++;
}
if (!track_len) {
return;
@@ -927,7 +927,7 @@ static void initialize_all_tracks(StabContext *ctx, float aspect)
average_marker_positions(ctx, reference_frame, average_pos);
setup_pivot(average_pos, pivot);
- for (i = 0; i < track_len; ++i) {
+ for (i = 0; i < track_len; i++) {
track = order[i].data;
if (reference_frame != order[i].reference_frame) {
reference_frame = order[i].reference_frame;
@@ -1129,8 +1129,8 @@ static void stabilization_data_to_mat4(float pixel_aspect,
}
/* Calculate scale factor necessary to eliminate black image areas
- * caused by the compensating movements of the stabilizator.
- * This function visits every frame where stabilisation data is
+ * caused by the compensating movements of the stabilizer.
+ * This function visits every frame where stabilization data is
* available and determines the factor for this frame. The overall
* largest factor found is returned as result.
*
diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index 358d8fa0a3e..ed582dc5b94 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -688,7 +688,7 @@ static ImBuf *make_grayscale_ibuf_copy(ImBuf *ibuf)
grayscale->mall |= IB_rectfloat;
grayscale->flags |= IB_rectfloat;
- for (i = 0; i < grayscale->x * grayscale->y; ++i) {
+ for (i = 0; i < grayscale->x * grayscale->y; i++) {
const float *pixel = ibuf->rect_float + ibuf->channels * i;
grayscale->rect_float[i] = 0.2126f * pixel[0] + 0.7152f * pixel[1] + 0.0722f * pixel[2];
@@ -790,9 +790,9 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor,
* here. Probably Libmv is better to work in the linear space,
* but keep sRGB space here for compatibility for now.
*/
- for (y = 0; y < clamped_height; ++y) {
+ for (y = 0; y < clamped_height; y++) {
int x;
- for (x = 0; x < clamped_width; ++x) {
+ for (x = 0; x < clamped_width; x++) {
int src_x = x + clamped_origin_x, src_y = y + clamped_origin_y;
int dst_x = x + dst_offset_x, dst_y = y + dst_offset_y;
int dst_index = (dst_y * width + dst_x) * 4,
diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c
index 36b950fb8f9..ecae1650a51 100644
--- a/source/blender/blenkernel/intern/undo_system.c
+++ b/source/blender/blenkernel/intern/undo_system.c
@@ -503,7 +503,7 @@ bool BKE_undosys_step_push_with_type(UndoStack *ustack,
/* Might not be final place for this to be called - probably only want to call it from some
* undo handlers, not all of them? */
if (BKE_override_library_is_enabled()) {
- BKE_main_override_library_operations_create(CTX_data_main(C), false);
+ BKE_main_override_library_operations_create(G_MAIN, false);
}
/* Remove all undos after (also when 'ustack->step_active == NULL'). */
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 109d615ae83..992e4333049 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -30,6 +30,7 @@
#include "DNA_world_types.h"
#include "DNA_scene_types.h"
#include "DNA_texture_types.h"
+#include "DNA_defaults.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
@@ -71,16 +72,7 @@ void BKE_world_init(World *wrld)
{
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(wrld, id));
- wrld->horr = 0.05f;
- wrld->horg = 0.05f;
- wrld->horb = 0.05f;
-
- wrld->aodist = 10.0f;
- wrld->aoenergy = 1.0f;
-
- wrld->preview = NULL;
- wrld->miststa = 5.0f;
- wrld->mistdist = 25.0f;
+ MEMCPY_STRUCT_AFTER(wrld, DNA_struct_default_get(World), id);
}
World *BKE_world_add(Main *bmain, const char *name)
@@ -106,10 +98,12 @@ World *BKE_world_add(Main *bmain, const char *name)
*/
void BKE_world_copy_data(Main *bmain, World *wrld_dst, const World *wrld_src, const int flag)
{
+ /* We always need allocation of our private ID data. */
+ const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
+
if (wrld_src->nodetree) {
- /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
- * (see BKE_libblock_copy_ex()). */
- BKE_id_copy_ex(bmain, (ID *)wrld_src->nodetree, (ID **)&wrld_dst->nodetree, flag);
+ BKE_id_copy_ex(
+ bmain, (ID *)wrld_src->nodetree, (ID **)&wrld_dst->nodetree, flag_private_id_data);
}
BLI_listbase_clear(&wrld_dst->gpumaterial);
diff --git a/source/blender/blenlib/BLI_allocator.h b/source/blender/blenlib/BLI_allocator.h
new file mode 100644
index 00000000000..52fa8d2b705
--- /dev/null
+++ b/source/blender/blenlib/BLI_allocator.h
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+#ifndef __BLI_ALLOCATOR_H__
+#define __BLI_ALLOCATOR_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * This file offers a couple of memory allocators that can be used with containers such as Vector
+ * and Map. Note that these allocators are not designed to work with standard containers like
+ * std::vector.
+ *
+ * Also see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2271.html for why the standard
+ * allocators are not a good fit applications like Blender. The current implementations in this
+ * file are fairly simple still, more complexity can be added when necessary. For now they do their
+ * job good enough.
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math_base.h"
+#include "BLI_temporary_allocator.h"
+
+namespace BLI {
+
+/**
+ * Use Blenders guarded allocator (aka MEM_malloc). This should always be used except there is a
+ * good reason not to use it.
+ */
+class GuardedAllocator {
+ public:
+ void *allocate(uint size, const char *name)
+ {
+ return MEM_mallocN(size, name);
+ }
+
+ void *allocate_aligned(uint size, uint alignment, const char *name)
+ {
+ alignment = std::max<uint>(alignment, 8);
+ return MEM_mallocN_aligned(size, alignment, name);
+ }
+
+ void deallocate(void *ptr)
+ {
+ MEM_freeN(ptr);
+ }
+};
+
+/**
+ * This is a simple wrapper around malloc/free. Only use this when the GuardedAllocator cannot be
+ * used. This can be the case when the allocated element might live longer than Blenders Allocator.
+ */
+class RawAllocator {
+ private:
+ struct MemHead {
+ int offset;
+ };
+
+ public:
+ void *allocate(uint size, const char *UNUSED(name))
+ {
+ void *ptr = malloc(size + sizeof(MemHead));
+ ((MemHead *)ptr)->offset = sizeof(MemHead);
+ return POINTER_OFFSET(ptr, sizeof(MemHead));
+ }
+
+ void *allocate_aligned(uint size, uint alignment, const char *UNUSED(name))
+ {
+ BLI_assert(is_power_of_2_i((int)alignment));
+ void *ptr = malloc(size + alignment + sizeof(MemHead));
+ void *used_ptr = (void *)((uintptr_t)POINTER_OFFSET(ptr, alignment + sizeof(MemHead)) &
+ ~((uintptr_t)alignment - 1));
+ uint offset = (uint)((uintptr_t)used_ptr - (uintptr_t)ptr);
+ BLI_assert(offset >= sizeof(MemHead));
+ ((MemHead *)used_ptr - 1)->offset = (int)offset;
+ return used_ptr;
+ }
+
+ void deallocate(void *ptr)
+ {
+ MemHead *head = (MemHead *)ptr - 1;
+ int offset = -head->offset;
+ void *actual_pointer = POINTER_OFFSET(ptr, offset);
+ free(actual_pointer);
+ }
+};
+
+/**
+ * Use this only under specific circumstances as described in BLI_temporary_allocator.h.
+ */
+class TemporaryAllocator {
+ public:
+ void *allocate(uint size, const char *UNUSED(name))
+ {
+ return BLI_temporary_allocate(size);
+ }
+
+ void *allocate_aligned(uint size, uint alignment, const char *UNUSED(name))
+ {
+ BLI_assert(alignment <= 64);
+ UNUSED_VARS_NDEBUG(alignment);
+ return BLI_temporary_allocate(size);
+ }
+
+ void deallocate(void *ptr)
+ {
+ BLI_temporary_deallocate(ptr);
+ }
+};
+
+} // namespace BLI
+
+#endif /* __BLI_ALLOCATOR_H__ */
diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h
index a61eff7329e..57e1790fdfd 100644
--- a/source/blender/blenlib/BLI_array.h
+++ b/source/blender/blenlib/BLI_array.h
@@ -83,9 +83,10 @@ void _bli_array_grow_func(void **arr_p,
((void *)(_##arr##_static) != \
NULL) && /* don't add _##arr##_len below because it must be zero */ \
(_bli_array_totalsize_static(arr) >= \
- _##arr##_len + (num))) ? /* we have an empty array and a static var big enough */ \
+ (size_t)(_##arr##_len + \
+ (num)))) ? /* we have an empty array and a static var big enough */ \
(void)(arr = (void *)_##arr##_static) : /* use existing static array or allocate */ \
- (LIKELY(_bli_array_totalsize(arr) >= _##arr##_len + (num)) ? \
+ (LIKELY(_bli_array_totalsize(arr) >= (size_t)(_##arr##_len + (num))) ? \
(void)0 /* do nothing */ : \
_bli_array_grow_func((void **)&(arr), \
_##arr##_static, \
diff --git a/source/blender/blenlib/BLI_array_cxx.h b/source/blender/blenlib/BLI_array_cxx.h
new file mode 100644
index 00000000000..c7704e20fb1
--- /dev/null
+++ b/source/blender/blenlib/BLI_array_cxx.h
@@ -0,0 +1,197 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef __BLI_ARRAY_CXX_H__
+#define __BLI_ARRAY_CXX_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * This is a container that contains a fixed size array. Note however, the size of the array is not
+ * a template argument. Instead it can be specified at the construction time.
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_allocator.h"
+#include "BLI_array_ref.h"
+#include "BLI_memory_utils_cxx.h"
+
+namespace BLI {
+
+template<typename T, typename Allocator = GuardedAllocator> class Array {
+ private:
+ T *m_data;
+ uint m_size;
+ Allocator m_allocator;
+
+ public:
+ Array()
+ {
+ m_data = nullptr;
+ m_size = 0;
+ }
+
+ Array(ArrayRef<T> values)
+ {
+ m_size = values.size();
+ m_data = this->allocate(m_size);
+ uninitialized_copy_n(values.begin(), m_size, m_data);
+ }
+
+ Array(const std::initializer_list<T> &values) : Array(ArrayRef<T>(values))
+ {
+ }
+
+ explicit Array(uint size)
+ {
+ m_data = this->allocate(size);
+ m_size = size;
+
+ for (uint i = 0; i < m_size; i++) {
+ new (m_data + i) T();
+ }
+ }
+
+ Array(uint size, const T &value)
+ {
+ m_data = this->allocate(size);
+ m_size = size;
+ uninitialized_fill_n(m_data, m_size, value);
+ }
+
+ Array(const Array &other)
+ {
+ m_size = other.size();
+ m_allocator = other.m_allocator;
+
+ if (m_size == 0) {
+ m_data = nullptr;
+ return;
+ }
+ else {
+ m_data = this->allocate(m_size);
+ copy_n(other.begin(), m_size, m_data);
+ }
+ }
+
+ Array(Array &&other) noexcept
+ {
+ m_data = other.m_data;
+ m_size = other.m_size;
+ m_allocator = other.m_allocator;
+
+ other.m_data = nullptr;
+ other.m_size = 0;
+ }
+
+ ~Array()
+ {
+ destruct_n(m_data, m_size);
+ if (m_data != nullptr) {
+ m_allocator.deallocate((void *)m_data);
+ }
+ }
+
+ Array &operator=(const Array &other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+
+ this->~Array();
+ new (this) Array(other);
+ return *this;
+ }
+
+ Array &operator=(Array &&other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+
+ this->~Array();
+ new (this) Array(std::move(other));
+ return *this;
+ }
+
+ operator ArrayRef<T>() const
+ {
+ return ArrayRef<T>(m_data, m_size);
+ }
+
+ operator MutableArrayRef<T>()
+ {
+ return MutableArrayRef<T>(m_data, m_size);
+ }
+
+ ArrayRef<T> as_ref() const
+ {
+ return *this;
+ }
+
+ T &operator[](uint index)
+ {
+ BLI_assert(index < m_size);
+ return m_data[index];
+ }
+
+ uint size() const
+ {
+ return m_size;
+ }
+
+ void fill(const T &value)
+ {
+ MutableArrayRef<T>(*this).fill(value);
+ }
+
+ void fill_indices(ArrayRef<uint> indices, const T &value)
+ {
+ MutableArrayRef<T>(*this).fill_indices(indices, value);
+ }
+
+ const T *begin() const
+ {
+ return m_data;
+ }
+
+ const T *end() const
+ {
+ return m_data + m_size;
+ }
+
+ T *begin()
+ {
+ return m_data;
+ }
+
+ T *end()
+ {
+ return m_data + m_size;
+ }
+
+ private:
+ T *allocate(uint size)
+ {
+ return (T *)m_allocator.allocate_aligned(
+ size * sizeof(T), std::alignment_of<T>::value, __func__);
+ }
+};
+
+template<typename T> using TemporaryArray = Array<T, TemporaryAllocator>;
+
+} // namespace BLI
+
+#endif /* __BLI_ARRAY_CXX_H__ */
diff --git a/source/blender/blenlib/BLI_array_ref.h b/source/blender/blenlib/BLI_array_ref.h
new file mode 100644
index 00000000000..e34647676d8
--- /dev/null
+++ b/source/blender/blenlib/BLI_array_ref.h
@@ -0,0 +1,426 @@
+/*
+ * 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.
+ */
+
+#ifndef __BLI_ARRAY_REF_H__
+#define __BLI_ARRAY_REF_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * These classes offer a convenient way to work with continuous chunks of memory of a certain type.
+ * We differentiate #ArrayRef and #MutableArrayRef. The elements in the former are const while the
+ * elements in the other are not.
+ *
+ * Passing array references as parameters has multiple benefits:
+ * - Less templates are used because the function does not have to work with different
+ * container types.
+ * - It encourages an Struct-of-Arrays data layout which is often beneficial when
+ * writing high performance code. Also it makes it easier to reuse code.
+ * - Array references offer convenient ways of slicing and other operations.
+ *
+ * The instances of #ArrayRef and #MutableArrayRef are very small and should be passed by value.
+ * Since array references do not own any memory, it is generally not save to store them.
+ */
+
+#include <vector>
+#include <array>
+#include <algorithm>
+#include <iostream>
+#include <string>
+
+#include "BLI_utildefines.h"
+#include "BLI_memory_utils_cxx.h"
+#include "BLI_index_range.h"
+
+namespace BLI {
+
+/**
+ * References an array of data. The elements in the array should not be changed.
+ */
+template<typename T> class ArrayRef {
+ private:
+ const T *m_start = nullptr;
+ uint m_size = 0;
+
+ public:
+ /**
+ * Create a reference to an empty array.
+ * The pointer is allowed to be nullptr.
+ */
+ ArrayRef() = default;
+
+ ArrayRef(const T *start, uint size) : m_start(start), m_size(size)
+ {
+ }
+
+ ArrayRef(const std::initializer_list<T> &list) : ArrayRef(list.begin(), list.size())
+ {
+ }
+
+ ArrayRef(const std::vector<T> &vector) : ArrayRef(vector.data(), vector.size())
+ {
+ }
+
+ template<std::size_t N> ArrayRef(const std::array<T, N> &array) : ArrayRef(array.data(), N)
+ {
+ }
+
+ /**
+ * Return a continuous part of the array.
+ * Asserts that the slice stays within the array.
+ */
+ ArrayRef slice(uint start, uint size) const
+ {
+ BLI_assert(start + size <= this->size() || size == 0);
+ return ArrayRef(m_start + start, size);
+ }
+
+ ArrayRef slice(IndexRange range) const
+ {
+ return this->slice(range.start(), range.size());
+ }
+
+ /**
+ * Return a new ArrayRef with n elements removed from the beginning.
+ * Asserts that the array contains enough elements.
+ */
+ ArrayRef drop_front(uint n = 1) const
+ {
+ BLI_assert(n <= this->size());
+ return this->slice(n, this->size() - n);
+ }
+
+ /**
+ * Return a new ArrayRef with n elements removed from the beginning.
+ * Asserts that the array contains enough elements.
+ */
+ ArrayRef drop_back(uint n = 1) const
+ {
+ BLI_assert(n <= this->size());
+ return this->slice(0, this->size() - n);
+ }
+
+ /**
+ * Return a new ArrayRef that only contains the first n elements.
+ * Asserts that the array contains enough elements.
+ */
+ ArrayRef take_front(uint n) const
+ {
+ BLI_assert(n <= this->size());
+ return this->slice(0, n);
+ }
+
+ /**
+ * Return a new ArrayRef that only contains the last n elements.
+ * Asserts that the array contains enough elements.
+ */
+ ArrayRef take_back(uint n) const
+ {
+ BLI_assert(n <= this->size());
+ return this->slice(this->size() - n, n);
+ }
+
+ /**
+ * Copy the values in this array to another array.
+ */
+ void copy_to(T *ptr) const
+ {
+ BLI::copy_n(m_start, m_size, ptr);
+ }
+
+ const T *begin() const
+ {
+ return m_start;
+ }
+
+ const T *end() const
+ {
+ return m_start + m_size;
+ }
+
+ /**
+ * Access an element in the array.
+ * Asserts that the index is in the bounds of the array.
+ */
+ const T &operator[](uint index) const
+ {
+ BLI_assert(index < m_size);
+ return m_start[index];
+ }
+
+ /**
+ * Return the number of elements in the referenced array.
+ */
+ uint size() const
+ {
+ return m_size;
+ }
+
+ /**
+ * Return the number of bytes referenced by this ArrayRef.
+ */
+ uint byte_size() const
+ {
+ return sizeof(T) * m_size;
+ }
+
+ /**
+ * Does a linear search to see of the value is in the array.
+ * Return true if it is, otherwise false.
+ */
+ bool contains(const T &value) const
+ {
+ for (const T &element : *this) {
+ if (element == value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Does a constant time check to see if the pointer is within the referenced array.
+ * Return true if it is, otherwise false.
+ */
+ bool contains_ptr(const T *ptr) const
+ {
+ return (this->begin() <= ptr) && (ptr < this->end());
+ }
+
+ /**
+ * Does a linear search to count how often the value is in the array.
+ * Returns the number of occurrences.
+ */
+ uint count(const T &value) const
+ {
+ uint counter = 0;
+ for (const T &element : *this) {
+ if (element == value) {
+ counter++;
+ }
+ }
+ return counter;
+ }
+
+ /**
+ * Return a reference to the first element in the array.
+ * Asserts that the array is not empty.
+ */
+ const T &first() const
+ {
+ BLI_assert(m_size > 0);
+ return m_start[0];
+ }
+
+ /**
+ * Return a reference to the last element in the array.
+ * Asserts that the array is not empty.
+ */
+ const T &last() const
+ {
+ BLI_assert(m_size > 0);
+ return m_start[m_size - 1];
+ }
+
+ /**
+ * Get element at the given index. If the index is out of range, return the fallback value.
+ */
+ T get(uint index, const T &fallback) const
+ {
+ if (index < m_size) {
+ return m_start[index];
+ }
+ return fallback;
+ }
+
+ /**
+ * Get a new array ref to the same underlying memory buffer. No conversions are done.
+ * Asserts when the sizes of the types don't match.
+ */
+ template<typename NewT> ArrayRef<NewT> cast() const
+ {
+ /* Can be adjusted to allow different type sizes when necessary. */
+ BLI_STATIC_ASSERT(sizeof(T) == sizeof(NewT), "");
+ return ArrayRef<NewT>((NewT *)m_start, m_size);
+ }
+
+ /**
+ * A debug utility to print the content of the array ref. Every element will be printed on a
+ * separate line using the given callback.
+ */
+ template<typename PrintLineF> void print_as_lines(std::string name, PrintLineF print_line) const
+ {
+ std::cout << "ArrayRef: " << name << " \tSize:" << m_size << '\n';
+ for (const T &value : *this) {
+ std::cout << " ";
+ print_line(value);
+ std::cout << '\n';
+ }
+ }
+};
+
+/**
+ * Mostly the same as ArrayRef, except that one can change the array elements via this reference.
+ */
+template<typename T> class MutableArrayRef {
+ private:
+ T *m_start;
+ uint m_size;
+
+ public:
+ MutableArrayRef() = default;
+
+ MutableArrayRef(T *start, uint size) : m_start(start), m_size(size)
+ {
+ }
+
+ MutableArrayRef(std::initializer_list<T> &list) : MutableArrayRef(list.begin(), list.size())
+ {
+ }
+
+ MutableArrayRef(std::vector<T> &vector) : MutableArrayRef(vector.data(), vector.size())
+ {
+ }
+
+ template<std::size_t N>
+ MutableArrayRef(std::array<T, N> &array) : MutableArrayRef(array.data(), N)
+ {
+ }
+
+ operator ArrayRef<T>()
+ {
+ return ArrayRef<T>(m_start, m_size);
+ }
+
+ /**
+ * Get the number of elements in the array.
+ */
+ uint size() const
+ {
+ return m_size;
+ }
+
+ /**
+ * Replace all elements in the referenced array with the given value.
+ */
+ void fill(const T &element)
+ {
+ std::fill_n(m_start, m_size, element);
+ }
+
+ /**
+ * Replace a subset of all elements with the given value.
+ */
+ void fill_indices(ArrayRef<uint> indices, const T &element)
+ {
+ for (uint i : indices) {
+ m_start[i] = element;
+ }
+ }
+
+ /**
+ * Copy the values from another array into the references array.
+ */
+ void copy_from(const T *ptr)
+ {
+ BLI::copy_n(ptr, m_size, m_start);
+ }
+
+ void copy_from(ArrayRef<T> other)
+ {
+ BLI_assert(this->size() == other.size());
+ this->copy_from(other.begin());
+ }
+
+ T *begin() const
+ {
+ return m_start;
+ }
+
+ T *end() const
+ {
+ return m_start + m_size;
+ }
+
+ T &operator[](uint index) const
+ {
+ BLI_assert(index < this->size());
+ return m_start[index];
+ }
+
+ /**
+ * Return a continuous part of the array.
+ * Asserts that the slice stays in the array bounds.
+ */
+ MutableArrayRef slice(uint start, uint length) const
+ {
+ BLI_assert(start + length <= this->size());
+ return MutableArrayRef(m_start + start, length);
+ }
+
+ /**
+ * Return a new MutableArrayRef with n elements removed from the beginning.
+ */
+ MutableArrayRef drop_front(uint n = 1) const
+ {
+ BLI_assert(n <= this->size());
+ return this->slice(n, this->size() - n);
+ }
+
+ /**
+ * Return a new MutableArrayRef with n elements removed from the beginning.
+ */
+ MutableArrayRef drop_back(uint n = 1) const
+ {
+ BLI_assert(n <= this->size());
+ return this->slice(0, this->size() - n);
+ }
+
+ /**
+ * Return a new MutableArrayRef that only contains the first n elements.
+ */
+ MutableArrayRef take_front(uint n) const
+ {
+ BLI_assert(n <= this->size());
+ return this->slice(0, n);
+ }
+
+ /**
+ * Return a new MutableArrayRef that only contains the last n elements.
+ */
+ MutableArrayRef take_back(uint n) const
+ {
+ BLI_assert(n <= this->size());
+ return this->slice(this->size() - n, n);
+ }
+
+ ArrayRef<T> as_ref() const
+ {
+ return ArrayRef<T>(m_start, m_size);
+ }
+};
+
+/**
+ * Shorthand to make use of automatic template parameter deduction.
+ */
+template<typename T> ArrayRef<T> ref_c_array(const T *array, uint size)
+{
+ return ArrayRef<T>(array, size);
+}
+
+} /* namespace BLI */
+
+#endif /* __BLI_ARRAY_REF_H__ */
diff --git a/source/blender/blenlib/BLI_callbacks.h b/source/blender/blenlib/BLI_callbacks.h
deleted file mode 100644
index 4d9fc66a806..00000000000
--- a/source/blender/blenlib/BLI_callbacks.h
+++ /dev/null
@@ -1,73 +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.
- */
-
-/** \file
- * \ingroup bli
- */
-
-#ifndef __BLI_CALLBACKS_H__
-#define __BLI_CALLBACKS_H__
-
-struct ID;
-struct Main;
-
-/**
- * Common suffix uses:
- * - ``_PRE/_POST``:
- * For handling discrete non-interactive events.
- * - ``_INIT/_COMPLETE/_CANCEL``:
- * For handling jobs (which may in turn cause other handlers to be called).
- */
-typedef enum {
- BLI_CB_EVT_FRAME_CHANGE_PRE,
- BLI_CB_EVT_FRAME_CHANGE_POST,
- BLI_CB_EVT_RENDER_PRE,
- BLI_CB_EVT_RENDER_POST,
- BLI_CB_EVT_RENDER_WRITE,
- BLI_CB_EVT_RENDER_STATS,
- BLI_CB_EVT_RENDER_INIT,
- BLI_CB_EVT_RENDER_COMPLETE,
- BLI_CB_EVT_RENDER_CANCEL,
- BLI_CB_EVT_LOAD_PRE,
- BLI_CB_EVT_LOAD_POST,
- BLI_CB_EVT_SAVE_PRE,
- BLI_CB_EVT_SAVE_POST,
- BLI_CB_EVT_UNDO_PRE,
- BLI_CB_EVT_UNDO_POST,
- BLI_CB_EVT_REDO_PRE,
- BLI_CB_EVT_REDO_POST,
- BLI_CB_EVT_DEPSGRAPH_UPDATE_PRE,
- BLI_CB_EVT_DEPSGRAPH_UPDATE_POST,
- BLI_CB_EVT_VERSION_UPDATE,
- BLI_CB_EVT_LOAD_FACTORY_USERDEF_POST,
- BLI_CB_EVT_LOAD_FACTORY_STARTUP_POST,
- BLI_CB_EVT_TOT,
-} eCbEvent;
-
-typedef struct bCallbackFuncStore {
- struct bCallbackFuncStore *next, *prev;
- void (*func)(struct Main *, struct ID *, void *arg);
- void *arg;
- short alloc;
-} bCallbackFuncStore;
-
-void BLI_callback_exec(struct Main *bmain, struct ID *self, eCbEvent evt);
-void BLI_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt);
-
-void BLI_callback_global_init(void);
-void BLI_callback_global_finalize(void);
-
-#endif /* __BLI_CALLBACKS_H__ */
diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h
index d8daa81b58d..d78f167a8fd 100644
--- a/source/blender/blenlib/BLI_fileops.h
+++ b/source/blender/blenlib/BLI_fileops.h
@@ -99,8 +99,13 @@ void BLI_filelist_entry_size_to_string(const struct stat *st,
void BLI_filelist_entry_mode_to_string(
const struct stat *st, const bool compact, char r_mode1[], char r_mode2[], char r_mode3[]);
void BLI_filelist_entry_owner_to_string(const struct stat *st, const bool compact, char r_owner[]);
-void BLI_filelist_entry_datetime_to_string(
- const struct stat *st, const int64_t ts, const bool compact, char r_time[], char r_date[]);
+void BLI_filelist_entry_datetime_to_string(const struct stat *st,
+ const int64_t ts,
+ const bool compact,
+ char r_time[],
+ char r_date[],
+ bool *r_is_today,
+ bool *r_is_yesterday);
/* Files */
diff --git a/source/blender/blenlib/BLI_gsqueue.h b/source/blender/blenlib/BLI_gsqueue.h
index 72cd5c7f4ec..4bd53dfddbe 100644
--- a/source/blender/blenlib/BLI_gsqueue.h
+++ b/source/blender/blenlib/BLI_gsqueue.h
@@ -27,12 +27,10 @@
typedef struct _GSQueue GSQueue;
GSQueue *BLI_gsqueue_new(size_t elem_size);
-bool BLI_gsqueue_is_empty(GSQueue *gq);
-int BLI_gsqueue_len(GSQueue *gq);
-void BLI_gsqueue_peek(GSQueue *gq, void *r_item);
+bool BLI_gsqueue_is_empty(const GSQueue *gq);
+size_t BLI_gsqueue_len(const GSQueue *gq);
void BLI_gsqueue_pop(GSQueue *gq, void *r_item);
void BLI_gsqueue_push(GSQueue *gq, const void *item);
-void BLI_gsqueue_push_back(GSQueue *gq, const void *item);
void BLI_gsqueue_free(GSQueue *gq);
#endif /* __BLI_GSQUEUE_H__ */
diff --git a/source/blender/blenlib/BLI_hash_cxx.h b/source/blender/blenlib/BLI_hash_cxx.h
new file mode 100644
index 00000000000..e899f27c9ee
--- /dev/null
+++ b/source/blender/blenlib/BLI_hash_cxx.h
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+#ifndef __BLI_HASH_CXX_H__
+#define __BLI_HASH_CXX_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * This file provides default hash functions for some primitive types. The hash functions can be
+ * used by containers such as Map and Set.
+ */
+
+#include <functional>
+#include <string>
+#include <utility>
+#include <memory>
+
+#include "BLI_utildefines.h"
+#include "BLI_math_base.h"
+
+namespace BLI {
+
+template<typename T> struct DefaultHash {
+};
+
+#define TRIVIAL_DEFAULT_INT_HASH(TYPE) \
+ template<> struct DefaultHash<TYPE> { \
+ uint32_t operator()(TYPE value) const \
+ { \
+ return (uint32_t)value; \
+ } \
+ }
+
+/**
+ * Cannot make any assumptions about the distribution of keys, so use a trivial hash function by
+ * default. The hash table implementations are designed to take all bits of the hash into account
+ * to avoid really bad behavior when the lower bits are all zero. Special hash functions can be
+ * implemented when more knowledge about a specific key distribution is available.
+ */
+TRIVIAL_DEFAULT_INT_HASH(int8_t);
+TRIVIAL_DEFAULT_INT_HASH(uint8_t);
+TRIVIAL_DEFAULT_INT_HASH(int16_t);
+TRIVIAL_DEFAULT_INT_HASH(uint16_t);
+TRIVIAL_DEFAULT_INT_HASH(int32_t);
+TRIVIAL_DEFAULT_INT_HASH(uint32_t);
+TRIVIAL_DEFAULT_INT_HASH(int64_t);
+
+template<> struct DefaultHash<float> {
+ uint32_t operator()(float value) const
+ {
+ return *(uint32_t *)&value;
+ }
+};
+
+template<> struct DefaultHash<std::string> {
+ uint32_t operator()(const std::string &value) const
+ {
+ uint32_t hash = 5381;
+ for (char c : value) {
+ hash = hash * 33 + c;
+ }
+ return hash;
+ }
+};
+
+/**
+ * While we cannot guarantee that the lower 3 bits or a pointer are zero, it is safe to assume
+ * this in the general case. MEM_malloc only returns 8 byte aligned addresses on 64-bit systems.
+ */
+template<typename T> struct DefaultHash<T *> {
+ uint32_t operator()(const T *value) const
+ {
+ uintptr_t ptr = POINTER_AS_UINT(value);
+ uint32_t hash = (uint32_t)(ptr >> 3);
+ return hash;
+ }
+};
+
+template<typename T> struct DefaultHash<std::unique_ptr<T>> {
+ uint32_t operator()(const std::unique_ptr<T> &value) const
+ {
+ return DefaultHash<T *>{}(value.get());
+ }
+};
+
+template<typename T1, typename T2> struct DefaultHash<std::pair<T1, T2>> {
+ uint32_t operator()(const std::pair<T1, T2> &value) const
+ {
+ uint32_t hash1 = DefaultHash<T1>{}(value.first);
+ uint32_t hash2 = DefaultHash<T2>{}(value.second);
+ return hash1 ^ (hash2 * 33);
+ }
+};
+
+} // namespace BLI
+
+#endif /* __BLI_HASH_CXX_H__ */
diff --git a/source/blender/blenlib/BLI_index_range.h b/source/blender/blenlib/BLI_index_range.h
new file mode 100644
index 00000000000..a1fed5bd97c
--- /dev/null
+++ b/source/blender/blenlib/BLI_index_range.h
@@ -0,0 +1,196 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_INDEX_RANGE_H__
+#define __BLI_INDEX_RANGE_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * Allows passing iterators over ranges of integers without actually allocating an array or passing
+ * separate values. A range always has a step of one. If other step sizes are required in some
+ * cases, a separate data structure should be used.
+ */
+
+#include <cmath>
+#include <algorithm>
+#include <iostream>
+
+#include "BLI_utildefines.h"
+
+namespace BLI {
+
+template<typename T> class ArrayRef;
+
+class IndexRange {
+ private:
+ uint m_start = 0;
+ uint m_size = 0;
+
+ public:
+ IndexRange() = default;
+
+ explicit IndexRange(uint size) : m_start(0), m_size(size)
+ {
+ }
+
+ IndexRange(uint start, uint size) : m_start(start), m_size(size)
+ {
+ }
+
+ class Iterator {
+ private:
+ uint m_current;
+
+ public:
+ Iterator(uint current) : m_current(current)
+ {
+ }
+
+ Iterator &operator++()
+ {
+ m_current++;
+ return *this;
+ }
+
+ bool operator!=(const Iterator &iterator) const
+ {
+ return m_current != iterator.m_current;
+ }
+
+ uint operator*() const
+ {
+ return m_current;
+ }
+ };
+
+ Iterator begin() const
+ {
+ return Iterator(m_start);
+ }
+
+ Iterator end() const
+ {
+ return Iterator(m_start + m_size);
+ }
+
+ /**
+ * Access an element in the range.
+ */
+ uint operator[](uint index) const
+ {
+ BLI_assert(index < this->size());
+ return m_start + index;
+ }
+
+ /**
+ * Two ranges compare equal when they contain the same numbers.
+ */
+ friend bool operator==(IndexRange a, IndexRange b)
+ {
+ return (a.m_size == b.m_size) && (a.m_start == b.m_start || a.m_size == 0);
+ }
+
+ /**
+ * Get the amount of numbers in the range.
+ */
+ uint size() const
+ {
+ return m_size;
+ }
+
+ /**
+ * Create a new range starting at the end of the current one.
+ */
+ IndexRange after(uint n) const
+ {
+ return IndexRange(m_start + m_size, n);
+ }
+
+ /**
+ * Create a new range that ends at the start of the current one.
+ */
+ IndexRange before(uint n) const
+ {
+ return IndexRange(m_start - n, n);
+ }
+
+ /**
+ * Get the first element in the range.
+ * Asserts when the range is empty.
+ */
+ uint first() const
+ {
+ BLI_assert(this->size() > 0);
+ return m_start;
+ }
+
+ /**
+ * Get the last element in the range.
+ * Asserts when the range is empty.
+ */
+ uint last() const
+ {
+ BLI_assert(this->size() > 0);
+ return m_start + m_size - 1;
+ }
+
+ /**
+ * Get the element one after the end. The returned value is undefined when the range is empty.
+ */
+ uint one_after_last() const
+ {
+ return m_start + m_size;
+ }
+
+ /**
+ * Get the first element in the range. The returned value is undefined when the range is empty.
+ */
+ uint start() const
+ {
+ return m_start;
+ }
+
+ /**
+ * Returns true when the range contains a certain number, otherwise false.
+ */
+ bool contains(uint value) const
+ {
+ return value >= m_start && value < m_start + m_size;
+ }
+
+ IndexRange slice(uint start, uint size) const
+ {
+ uint new_start = m_start + start;
+ BLI_assert(new_start + size <= m_start + m_size || size == 0);
+ return IndexRange(new_start, size);
+ }
+
+ /**
+ * Get read-only access to a memory buffer that contains the range as actual numbers.
+ */
+ ArrayRef<uint> as_array_ref() const;
+
+ friend std::ostream &operator<<(std::ostream &stream, IndexRange range)
+ {
+ stream << "[" << range.start() << ", " << range.one_after_last() << ")";
+ return stream;
+ }
+};
+
+} // namespace BLI
+
+#endif /* __BLI_INDEX_RANGE_H__ */
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index a348694c4da..b305e919e76 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -24,6 +24,8 @@
* \ingroup bli
*/
+#include "BLI_sys_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -89,6 +91,12 @@ typedef struct BVHTreeRayHit {
enum {
/* Use a priority queue to process nodes in the optimal order (for slow callbacks) */
+ BVH_OVERLAP_USE_THREADING = (1 << 0),
+ BVH_OVERLAP_RETURN_PAIRS = (1 << 1),
+ BVH_OVERLAP_BREAK_ON_FIRST = (1 << 2),
+};
+enum {
+ /* Use a priority queue to process nodes in the optimal order (for slow callbacks) */
BVH_NEAREST_OPTIMAL_ORDER = (1 << 0),
};
enum {
@@ -152,6 +160,14 @@ int BLI_bvhtree_overlap_thread_num(const BVHTree *tree);
/* collision/overlap: check two trees if they overlap,
* alloc's *overlap with length of the int return value */
+BVHTreeOverlap *BLI_bvhtree_overlap_ex(
+ const BVHTree *tree1,
+ const BVHTree *tree2,
+ uint *r_overlap_tot,
+ /* optional callback to test the overlap before adding (must be thread-safe!) */
+ BVHTree_OverlapCallback callback,
+ void *userdata,
+ int flag);
BVHTreeOverlap *BLI_bvhtree_overlap(const BVHTree *tree1,
const BVHTree *tree2,
unsigned int *r_overlap_tot,
@@ -177,6 +193,12 @@ int BLI_bvhtree_find_nearest(BVHTree *tree,
BVHTree_NearestPointCallback callback,
void *userdata);
+int BLI_bvhtree_find_nearest_first(BVHTree *tree,
+ const float co[3],
+ const float dist_sq,
+ BVHTree_NearestPointCallback callback,
+ void *userdata);
+
int BLI_bvhtree_ray_cast_ex(BVHTree *tree,
const float co[3],
const float dir[3],
diff --git a/source/blender/blenlib/BLI_kdtree_impl.h b/source/blender/blenlib/BLI_kdtree_impl.h
index e442bd7a99d..c028266ef64 100644
--- a/source/blender/blenlib/BLI_kdtree_impl.h
+++ b/source/blender/blenlib/BLI_kdtree_impl.h
@@ -21,9 +21,9 @@
#include "BLI_compiler_attrs.h"
-#define _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1##MACRO_ARG2
-#define _CONCAT(MACRO_ARG1, MACRO_ARG2) _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2)
-#define BLI_kdtree_nd_(id) _CONCAT(KDTREE_PREFIX_ID, _##id)
+#define _BLI_CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1##MACRO_ARG2
+#define _BLI_CONCAT(MACRO_ARG1, MACRO_ARG2) _BLI_CONCAT_AUX(MACRO_ARG1, MACRO_ARG2)
+#define BLI_kdtree_nd_(id) _BLI_CONCAT(KDTREE_PREFIX_ID, _##id)
struct KDTree;
typedef struct KDTree KDTree;
@@ -93,6 +93,6 @@ int BLI_kdtree_nd_(range_search_with_len_squared_cb)(
const void *user_data),
const void *user_data) ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
-#undef _CONCAT_AUX
-#undef _CONCAT
+#undef _BLI_CONCAT_AUX
+#undef _BLI_CONCAT
#undef BLI_kdtree_nd_
diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h
index b8b62dd3451..b027acb88da 100644
--- a/source/blender/blenlib/BLI_listbase.h
+++ b/source/blender/blenlib/BLI_listbase.h
@@ -93,6 +93,7 @@ void BLI_listbase_sort_r(ListBase *listbase,
int (*cmp)(void *, const void *, const void *),
void *thunk) ATTR_NONNULL(1, 2);
bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL();
+bool BLI_listbase_move_index(ListBase *listbase, int from, int to) ATTR_NONNULL();
void BLI_freelist(struct ListBase *listbase) ATTR_NONNULL(1);
int BLI_listbase_count_at_most(const struct ListBase *listbase,
const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
diff --git a/source/blender/blenlib/BLI_listbase_wrapper.h b/source/blender/blenlib/BLI_listbase_wrapper.h
new file mode 100644
index 00000000000..34197fe9c45
--- /dev/null
+++ b/source/blender/blenlib/BLI_listbase_wrapper.h
@@ -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.
+ */
+
+#ifndef __BLI_LISTBASE_WRAPPER_H__
+#define __BLI_LISTBASE_WRAPPER_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * The purpose of this wrapper is just to make it more comfortable to iterate of ListBase
+ * instances, that are used in many places in Blender.
+ */
+
+#include "BLI_listbase.h"
+#include "DNA_listBase.h"
+
+namespace BLI {
+
+template<typename T> class IntrusiveListBaseWrapper {
+ private:
+ ListBase *m_listbase;
+
+ public:
+ IntrusiveListBaseWrapper(ListBase *listbase) : m_listbase(listbase)
+ {
+ BLI_assert(listbase);
+ }
+
+ IntrusiveListBaseWrapper(ListBase &listbase) : IntrusiveListBaseWrapper(&listbase)
+ {
+ }
+
+ class Iterator {
+ private:
+ ListBase *m_listbase;
+ T *m_current;
+
+ public:
+ Iterator(ListBase *listbase, T *current) : m_listbase(listbase), m_current(current)
+ {
+ }
+
+ Iterator &operator++()
+ {
+ m_current = m_current->next;
+ return *this;
+ }
+
+ Iterator operator++(int)
+ {
+ Iterator iterator = *this;
+ ++*this;
+ return iterator;
+ }
+
+ bool operator!=(const Iterator &iterator) const
+ {
+ return m_current != iterator.m_current;
+ }
+
+ T *operator*() const
+ {
+ return m_current;
+ }
+ };
+
+ Iterator begin() const
+ {
+ return Iterator(m_listbase, (T *)m_listbase->first);
+ }
+
+ Iterator end() const
+ {
+ return Iterator(m_listbase, nullptr);
+ }
+
+ T get(uint index) const
+ {
+ void *ptr = BLI_findlink(m_listbase, index);
+ BLI_assert(ptr);
+ return (T *)ptr;
+ }
+};
+
+} /* namespace BLI */
+
+#endif /* __BLI_LISTBASE_WRAPPER_H__ */
diff --git a/source/blender/blenlib/BLI_map.h b/source/blender/blenlib/BLI_map.h
new file mode 100644
index 00000000000..1edf7653c71
--- /dev/null
+++ b/source/blender/blenlib/BLI_map.h
@@ -0,0 +1,724 @@
+/*
+ * 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.
+ */
+
+#ifndef __BLI_MAP_H__
+#define __BLI_MAP_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * This file provides a map implementation that uses open addressing with probing.
+ *
+ * The key and value objects are stored directly in the hash table to avoid indirect memory
+ * lookups. Keys and values are stored in groups of four to avoid wasting memory due to padding.
+ */
+
+#include "BLI_hash_cxx.h"
+#include "BLI_array_ref.h"
+#include "BLI_open_addressing.h"
+
+namespace BLI {
+
+// clang-format off
+
+#define ITER_SLOTS_BEGIN(KEY, ARRAY, OPTIONAL_CONST, R_ITEM, R_OFFSET) \
+ uint32_t hash = DefaultHash<KeyT>{}(KEY); \
+ uint32_t perturb = hash; \
+ while (true) { \
+ uint32_t item_index = (hash & ARRAY.slot_mask()) >> OFFSET_SHIFT; \
+ uint8_t R_OFFSET = hash & OFFSET_MASK; \
+ uint8_t initial_offset = R_OFFSET; \
+ OPTIONAL_CONST Item &R_ITEM = ARRAY.item(item_index); \
+ do {
+
+#define ITER_SLOTS_END(R_OFFSET) \
+ R_OFFSET = (R_OFFSET + 1u) & OFFSET_MASK; \
+ } while (R_OFFSET != initial_offset); \
+ perturb >>= 5; \
+ hash = hash * 5 + 1 + perturb; \
+ } ((void)0)
+
+// clang-format on
+
+template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator> class Map {
+ private:
+ static constexpr uint OFFSET_MASK = 3;
+ static constexpr uint OFFSET_SHIFT = 2;
+
+ class Item {
+ private:
+ static constexpr uint8_t IS_EMPTY = 0;
+ static constexpr uint8_t IS_SET = 1;
+ static constexpr uint8_t IS_DUMMY = 2;
+
+ uint8_t m_status[4];
+ char m_keys[4 * sizeof(KeyT)];
+ char m_values[4 * sizeof(ValueT)];
+
+ public:
+ static constexpr uint slots_per_item = 4;
+
+ Item()
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ m_status[offset] = IS_EMPTY;
+ }
+ }
+
+ ~Item()
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ if (m_status[offset] == IS_SET) {
+ this->key(offset)->~KeyT();
+ this->value(offset)->~ValueT();
+ }
+ }
+ }
+
+ Item(const Item &other)
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ uint8_t status = other.m_status[offset];
+ m_status[offset] = status;
+ if (status == IS_SET) {
+ new (this->key(offset)) KeyT(*other.key(offset));
+ new (this->value(offset)) ValueT(*other.value(offset));
+ }
+ }
+ }
+
+ Item(Item &&other) noexcept
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ uint8_t status = other.m_status[offset];
+ m_status[offset] = status;
+ if (status == IS_SET) {
+ new (this->key(offset)) KeyT(std::move(*other.key(offset)));
+ new (this->value(offset)) ValueT(std::move(*other.value(offset)));
+ }
+ }
+ }
+
+ bool has_key(uint offset, const KeyT &key) const
+ {
+ return m_status[offset] == IS_SET && key == *this->key(offset);
+ }
+
+ bool is_set(uint offset) const
+ {
+ return m_status[offset] == IS_SET;
+ }
+
+ bool is_empty(uint offset) const
+ {
+ return m_status[offset] == IS_EMPTY;
+ }
+
+ bool is_dummy(uint offset) const
+ {
+ return m_status[offset] == IS_DUMMY;
+ }
+
+ KeyT *key(uint offset) const
+ {
+ return (KeyT *)(m_keys + offset * sizeof(KeyT));
+ }
+
+ ValueT *value(uint offset) const
+ {
+ return (ValueT *)(m_values + offset * sizeof(ValueT));
+ }
+
+ template<typename ForwardKeyT, typename ForwardValueT>
+ void store(uint offset, ForwardKeyT &&key, ForwardValueT &&value)
+ {
+ BLI_assert(m_status[offset] != IS_SET);
+ m_status[offset] = IS_SET;
+ new (this->key(offset)) KeyT(std::forward<ForwardKeyT>(key));
+ new (this->value(offset)) ValueT(std::forward<ForwardValueT>(value));
+ }
+
+ template<typename ForwardKeyT> void store_without_value(uint offset, ForwardKeyT &&key)
+ {
+ BLI_assert(m_status[offset] != IS_SET);
+ m_status[offset] = IS_SET;
+ new (this->key(offset)) KeyT(std::forward<ForwardKeyT>(key));
+ }
+
+ void set_dummy(uint offset)
+ {
+ BLI_assert(m_status[offset] == IS_SET);
+ m_status[offset] = IS_DUMMY;
+ destruct(this->key(offset));
+ destruct(this->value(offset));
+ }
+ };
+
+ using ArrayType = OpenAddressingArray<Item, 1, Allocator>;
+ ArrayType m_array;
+
+ public:
+ Map() = default;
+
+ /**
+ * Allocate memory such that at least min_usable_slots can be added before the map has to grow
+ * again.
+ */
+ void reserve(uint min_usable_slots)
+ {
+ if (m_array.slots_usable() < min_usable_slots) {
+ this->grow(min_usable_slots);
+ }
+ }
+
+ /**
+ * Remove all elements from the map.
+ */
+ void clear()
+ {
+ this->~Map();
+ new (this) Map();
+ }
+
+ /**
+ * Insert a new key-value-pair in the map.
+ * Asserts when the key existed before.
+ */
+ void add_new(const KeyT &key, const ValueT &value)
+ {
+ this->add_new__impl(key, value);
+ }
+ void add_new(const KeyT &key, ValueT &&value)
+ {
+ this->add_new__impl(key, std::move(value));
+ }
+ void add_new(KeyT &&key, const ValueT &value)
+ {
+ this->add_new__impl(std::move(key), value);
+ }
+ void add_new(KeyT &&key, ValueT &&value)
+ {
+ this->add_new__impl(std::move(key), std::move(value));
+ }
+
+ /**
+ * Insert a new key-value-pair in the map if the key does not exist yet.
+ * Returns true when the pair was newly inserted, otherwise false.
+ */
+ bool add(const KeyT &key, const ValueT &value)
+ {
+ return this->add__impl(key, value);
+ }
+ bool add(const KeyT &key, ValueT &&value)
+ {
+ return this->add__impl(key, std::move(value));
+ }
+ bool add(KeyT &&key, const ValueT &value)
+ {
+ return this->add__impl(std::move(key), value);
+ }
+ bool add(KeyT &&key, ValueT &&value)
+ {
+ return this->add__impl(std::move(key), std::move(value));
+ }
+
+ /**
+ * Remove the key from the map.
+ * Asserts when the key does not exist in the map.
+ */
+ void remove(const KeyT &key)
+ {
+ BLI_assert(this->contains(key));
+ ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
+ if (item.has_key(offset, key)) {
+ item.set_dummy(offset);
+ m_array.update__set_to_dummy();
+ return;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ /**
+ * Get the value for the given key and remove it from the map.
+ * Asserts when the key does not exist in the map.
+ */
+ ValueT pop(const KeyT &key)
+ {
+ BLI_assert(this->contains(key));
+ ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
+ if (item.has_key(offset, key)) {
+ ValueT value = std::move(*item.value(offset));
+ item.set_dummy(offset);
+ m_array.update__set_to_dummy();
+ return value;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ /**
+ * Returns true when the key exists in the map, otherwise false.
+ */
+ bool contains(const KeyT &key) const
+ {
+ ITER_SLOTS_BEGIN (key, m_array, const, item, offset) {
+ if (item.is_empty(offset)) {
+ return false;
+ }
+ else if (item.has_key(offset, key)) {
+ return true;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ /**
+ * First, checks if the key exists in the map.
+ * If it does exist, call the modify function with a pointer to the corresponding value.
+ * If it does not exist, call the create function with a pointer to where the value should be
+ * created.
+ *
+ * Returns whatever is returned from one of the callback functions. Both callbacks have to return
+ * the same type.
+ *
+ * CreateValueF: Takes a pointer to where the value should be created.
+ * ModifyValueF: Takes a pointer to the value that should be modified.
+ */
+ template<typename CreateValueF, typename ModifyValueF>
+ auto add_or_modify(const KeyT &key,
+ const CreateValueF &create_value,
+ const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
+ {
+ return this->add_or_modify__impl(key, create_value, modify_value);
+ }
+ template<typename CreateValueF, typename ModifyValueF>
+ auto add_or_modify(KeyT &&key,
+ const CreateValueF &create_value,
+ const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
+ {
+ return this->add_or_modify__impl(std::move(key), create_value, modify_value);
+ }
+
+ /**
+ * Similar to add, but overrides the value for the key when it exists already.
+ */
+ bool add_override(const KeyT &key, const ValueT &value)
+ {
+ return this->add_override__impl(key, value);
+ }
+ bool add_override(const KeyT &key, ValueT &&value)
+ {
+ return this->add_override__impl(key, std::move(value));
+ }
+ bool add_override(KeyT &&key, const ValueT &value)
+ {
+ return this->add_override__impl(std::move(key), value);
+ }
+ bool add_override(KeyT &&key, ValueT &&value)
+ {
+ return this->add_override__impl(std::move(key), std::move(value));
+ }
+
+ /**
+ * Check if the key exists in the map.
+ * Return a pointer to the value, when it exists.
+ * Otherwise return nullptr.
+ */
+ const ValueT *lookup_ptr(const KeyT &key) const
+ {
+ ITER_SLOTS_BEGIN (key, m_array, const, item, offset) {
+ if (item.is_empty(offset)) {
+ return nullptr;
+ }
+ else if (item.has_key(offset, key)) {
+ return item.value(offset);
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ /**
+ * Lookup the value that corresponds to the key.
+ * Asserts when the key does not exist.
+ */
+ const ValueT &lookup(const KeyT &key) const
+ {
+ const ValueT *ptr = this->lookup_ptr(key);
+ BLI_assert(ptr != nullptr);
+ return *ptr;
+ }
+
+ ValueT *lookup_ptr(const KeyT &key)
+ {
+ const Map *const_this = this;
+ return const_cast<ValueT *>(const_this->lookup_ptr(key));
+ }
+
+ ValueT &lookup(const KeyT &key)
+ {
+ const Map *const_this = this;
+ return const_cast<ValueT &>(const_this->lookup(key));
+ }
+
+ /**
+ * Check if the key exists in the map.
+ * If it does, return a copy of the value.
+ * Otherwise, return the default value.
+ */
+ ValueT lookup_default(const KeyT &key, ValueT default_value) const
+ {
+ const ValueT *ptr = this->lookup_ptr(key);
+ if (ptr != nullptr) {
+ return *ptr;
+ }
+ else {
+ return default_value;
+ }
+ }
+
+ /**
+ * Return the value that corresponds to the given key.
+ * If it does not exist yet, create and insert it first.
+ */
+ template<typename CreateValueF>
+ ValueT &lookup_or_add(const KeyT &key, const CreateValueF &create_value)
+ {
+ return this->lookup_or_add__impl(key, create_value);
+ }
+ template<typename CreateValueF>
+ ValueT &lookup_or_add(KeyT &&key, const CreateValueF &create_value)
+ {
+ return this->lookup_or_add__impl(std::move(key), create_value);
+ }
+
+ /**
+ * Get the number of elements in the map.
+ */
+ uint32_t size() const
+ {
+ return m_array.slots_set();
+ }
+
+ void print_table() const
+ {
+ std::cout << "Hash Table:\n";
+ std::cout << " Size: " << m_array.slots_set() << '\n';
+ std::cout << " Capacity: " << m_array.slots_total() << '\n';
+ uint32_t item_index = 0;
+ for (const Item &item : m_array) {
+ std::cout << " Item: " << item_index++ << '\n';
+ for (uint offset = 0; offset < 4; offset++) {
+ std::cout << " " << offset << " \t";
+ if (item.is_empty(offset)) {
+ std::cout << " <empty>\n";
+ }
+ else if (item.is_set(offset)) {
+ const KeyT &key = *item.key(offset);
+ const ValueT &value = *item.value(offset);
+ uint32_t collisions = this->count_collisions(key);
+ std::cout << " " << key << " -> " << value << " \t Collisions: " << collisions
+ << '\n';
+ }
+ else if (item.is_dummy(offset)) {
+ std::cout << " <dummy>\n";
+ }
+ }
+ }
+ }
+
+ template<typename SubIterator> class BaseIterator {
+ protected:
+ const Map *m_map;
+ uint32_t m_slot;
+
+ public:
+ BaseIterator(const Map *map, uint32_t slot) : m_map(map), m_slot(slot)
+ {
+ }
+
+ BaseIterator &operator++()
+ {
+ m_slot = m_map->next_slot(m_slot + 1);
+ return *this;
+ }
+
+ friend bool operator==(const BaseIterator &a, const BaseIterator &b)
+ {
+ BLI_assert(a.m_map == b.m_map);
+ return a.m_slot == b.m_slot;
+ }
+
+ friend bool operator!=(const BaseIterator &a, const BaseIterator &b)
+ {
+ return !(a == b);
+ }
+
+ SubIterator begin() const
+ {
+ return SubIterator(m_map, m_map->next_slot(0));
+ }
+
+ SubIterator end() const
+ {
+ return SubIterator(m_map, m_map->m_array.slots_total());
+ }
+ };
+
+ class KeyIterator final : public BaseIterator<KeyIterator> {
+ public:
+ KeyIterator(const Map *map, uint32_t slot) : BaseIterator<KeyIterator>(map, slot)
+ {
+ }
+
+ const KeyT &operator*() const
+ {
+ uint32_t item_index = this->m_slot >> OFFSET_SHIFT;
+ uint offset = this->m_slot & OFFSET_MASK;
+ const Item &item = this->m_map->m_array.item(item_index);
+ BLI_assert(item.is_set(offset));
+ return *item.key(offset);
+ }
+ };
+
+ class ValueIterator final : public BaseIterator<ValueIterator> {
+ public:
+ ValueIterator(const Map *map, uint32_t slot) : BaseIterator<ValueIterator>(map, slot)
+ {
+ }
+
+ ValueT &operator*() const
+ {
+ uint32_t item_index = this->m_slot >> OFFSET_SHIFT;
+ uint offset = this->m_slot & OFFSET_MASK;
+ const Item &item = this->m_map->m_array.item(item_index);
+ BLI_assert(item.is_set(offset));
+ return *item.value(offset);
+ }
+ };
+
+ class ItemIterator final : public BaseIterator<ItemIterator> {
+ public:
+ ItemIterator(const Map *map, uint32_t slot) : BaseIterator<ItemIterator>(map, slot)
+ {
+ }
+
+ struct UserItem {
+ const KeyT &key;
+ ValueT &value;
+
+ friend std::ostream &operator<<(std::ostream &stream, const Item &item)
+ {
+ stream << item.key << " -> " << item.value;
+ return stream;
+ }
+ };
+
+ UserItem operator*() const
+ {
+ uint32_t item_index = this->m_slot >> OFFSET_SHIFT;
+ uint offset = this->m_slot & OFFSET_MASK;
+ const Item &item = this->m_map->m_array.item(item_index);
+ BLI_assert(item.is_set(offset));
+ return {*item.key(offset), *item.value(offset)};
+ }
+ };
+
+ template<typename SubIterator> friend class BaseIterator;
+
+ /**
+ * Iterate over all keys in the map.
+ */
+ KeyIterator keys() const
+ {
+ return KeyIterator(this, 0);
+ }
+
+ /**
+ * Iterate over all values in the map.
+ */
+ ValueIterator values() const
+ {
+ return ValueIterator(this, 0);
+ }
+
+ /**
+ * Iterate over all key-value-pairs in the map.
+ * They can be accessed with item.key and item.value.
+ */
+ ItemIterator items() const
+ {
+ return ItemIterator(this, 0);
+ }
+
+ private:
+ uint32_t next_slot(uint32_t slot) const
+ {
+ for (; slot < m_array.slots_total(); slot++) {
+ uint32_t item_index = slot >> OFFSET_SHIFT;
+ uint offset = slot & OFFSET_MASK;
+ const Item &item = m_array.item(item_index);
+ if (item.is_set(offset)) {
+ return slot;
+ }
+ }
+ return slot;
+ }
+
+ uint32_t count_collisions(const KeyT &key) const
+ {
+ uint32_t collisions = 0;
+ ITER_SLOTS_BEGIN (key, m_array, const, item, offset) {
+ if (item.is_empty(offset) || item.has_key(offset, key)) {
+ return collisions;
+ }
+ collisions++;
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ void ensure_can_add()
+ {
+ if (UNLIKELY(m_array.should_grow())) {
+ this->grow(this->size() + 1);
+ }
+ }
+
+ BLI_NOINLINE void grow(uint32_t min_usable_slots)
+ {
+ ArrayType new_array = m_array.init_reserved(min_usable_slots);
+ for (Item &old_item : m_array) {
+ for (uint offset = 0; offset < 4; offset++) {
+ if (old_item.is_set(offset)) {
+ this->add_after_grow(*old_item.key(offset), *old_item.value(offset), new_array);
+ }
+ }
+ }
+ m_array = std::move(new_array);
+ }
+
+ void add_after_grow(KeyT &key, ValueT &value, ArrayType &new_array)
+ {
+ ITER_SLOTS_BEGIN (key, new_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, std::move(key), std::move(value));
+ return;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ template<typename ForwardKeyT, typename ForwardValueT>
+ bool add_override__impl(ForwardKeyT &&key, ForwardValueT &&value)
+ {
+ return this->add_or_modify(
+ std::forward<ForwardKeyT>(key),
+ [&](ValueT *dst) {
+ new (dst) ValueT(std::forward<ForwardValueT>(value));
+ return true;
+ },
+ [&](ValueT *old_value) {
+ *old_value = std::forward<ForwardValueT>(value);
+ return false;
+ });
+ }
+
+ template<typename ForwardKeyT, typename ForwardValueT>
+ bool add__impl(ForwardKeyT &&key, ForwardValueT &&value)
+ {
+ this->ensure_can_add();
+
+ ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, std::forward<ForwardKeyT>(key), std::forward<ForwardValueT>(value));
+ m_array.update__empty_to_set();
+ return true;
+ }
+ else if (item.has_key(offset, key)) {
+ return false;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ template<typename ForwardKeyT, typename ForwardValueT>
+ void add_new__impl(ForwardKeyT &&key, ForwardValueT &&value)
+ {
+ BLI_assert(!this->contains(key));
+ this->ensure_can_add();
+
+ ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, std::forward<ForwardKeyT>(key), std::forward<ForwardValueT>(value));
+ m_array.update__empty_to_set();
+ return;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ template<typename ForwardKeyT, typename CreateValueF, typename ModifyValueF>
+ auto add_or_modify__impl(ForwardKeyT &&key,
+ const CreateValueF &create_value,
+ const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
+ {
+ using CreateReturnT = decltype(create_value(nullptr));
+ using ModifyReturnT = decltype(modify_value(nullptr));
+ BLI_STATIC_ASSERT((std::is_same<CreateReturnT, ModifyReturnT>::value),
+ "Both callbacks should return the same type.");
+
+ this->ensure_can_add();
+
+ ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ m_array.update__empty_to_set();
+ item.store_without_value(offset, std::forward<ForwardKeyT>(key));
+ ValueT *value_ptr = item.value(offset);
+ return create_value(value_ptr);
+ }
+ else if (item.has_key(offset, key)) {
+ ValueT *value_ptr = item.value(offset);
+ return modify_value(value_ptr);
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ template<typename ForwardKeyT, typename CreateValueF>
+ ValueT &lookup_or_add__impl(ForwardKeyT &&key, const CreateValueF &create_value)
+ {
+ this->ensure_can_add();
+
+ ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, std::forward<ForwardKeyT>(key), create_value());
+ m_array.update__empty_to_set();
+ return *item.value(offset);
+ }
+ else if (item.has_key(offset, key)) {
+ return *item.value(offset);
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+};
+
+#undef ITER_SLOTS_BEGIN
+#undef ITER_SLOTS_END
+
+} // namespace BLI
+
+#endif /* __BLI_MAP_H__ */
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index deb29605552..4f841f75d3a 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -121,6 +121,9 @@ MINLINE float max_fff(float a, float b, float c);
MINLINE float min_ffff(float a, float b, float c, float d);
MINLINE float max_ffff(float a, float b, float c, float d);
+MINLINE double min_dd(double a, double b);
+MINLINE double max_dd(double a, double b);
+
MINLINE int min_ii(int a, int b);
MINLINE int max_ii(int a, int b);
MINLINE int min_iii(int a, int b, int c);
@@ -155,6 +158,8 @@ MINLINE int power_of_2_min_i(int n);
MINLINE unsigned int power_of_2_max_u(unsigned int x);
MINLINE unsigned int power_of_2_min_u(unsigned int x);
+MINLINE unsigned int log2_floor_u(unsigned int x);
+MINLINE unsigned int log2_ceil_u(unsigned int x);
MINLINE int divide_round_i(int a, int b);
MINLINE int mod_i(int i, int n);
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 39b1b96d009..87517ebe060 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -188,6 +188,10 @@ float dist_squared_to_projected_aabb_simple(const float projmat[4][4],
const float bbmax[3]);
float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2]);
+double closest_to_line_v2_db(double r_close[2],
+ const double p[2],
+ const double l1[2],
+ const double l2[2]);
float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3]);
void closest_to_line_segment_v2(float r_close[2],
const float p[2],
@@ -267,7 +271,12 @@ bool isect_seg_seg_v2_simple(const float v1[2],
const float v2[2],
const float v3[2],
const float v4[2]);
-
+int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
+ const double v2[2],
+ const double v3[2],
+ const double v4[2],
+ double *r_lambda,
+ double *r_mu);
int isect_line_sphere_v3(const float l1[3],
const float l2[3],
const float sp[3],
@@ -302,7 +311,13 @@ bool isect_line_line_strict_v3(const float v1[3],
const float v4[3],
float vi[3],
float *r_lambda);
-
+bool isect_ray_ray_epsilon_v3(const float ray_origin_a[3],
+ const float ray_direction_a[3],
+ const float ray_origin_b[3],
+ const float ray_direction_b[3],
+ const float epsilon,
+ float *r_lambda_a,
+ float *r_lambda_b);
bool isect_ray_ray_v3(const float ray_origin_a[3],
const float ray_direction_a[3],
const float ray_origin_b[3],
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index f5d87667b73..814b13fa47f 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -252,6 +252,9 @@ void normalize_m4_m4(float R[4][4], const float A[4][4]) ATTR_NONNULL();
void orthogonalize_m3(float R[3][3], int axis);
void orthogonalize_m4(float R[4][4], int axis);
+void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize);
+void orthogonalize_m4_stable(float R[4][4], int axis, bool normalize);
+
bool is_orthogonal_m3(const float mat[3][3]);
bool is_orthogonal_m4(const float mat[4][4]);
bool is_orthonormal_m3(const float mat[3][3]);
@@ -303,8 +306,11 @@ void size_to_mat4(float R[4][4], const float size[3]);
void mat3_to_size(float r[3], const float M[3][3]);
void mat4_to_size(float r[3], const float M[4][4]);
+void mat4_to_size_fix_shear(float r[3], const float M[4][4]);
+
void translate_m4(float mat[4][4], float tx, float ty, float tz);
void rotate_m4(float mat[4][4], const char axis, const float angle);
+void rescale_m4(float mat[4][4], const float scale[3]);
void transform_pivot_set_m4(float mat[4][4], const float pivot[3]);
void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]);
@@ -314,6 +320,10 @@ void mat4_decompose(float loc[3], float quat[4], float size[3], const float wmat
void mat3_polar_decompose(const float mat3[3][3], float r_U[3][3], float r_P[3][3]);
+void loc_rot_size_to_mat4(float R[4][4],
+ const float loc[3],
+ const float rot[3][3],
+ const float size[3]);
void loc_eul_size_to_mat4(float R[4][4],
const float loc[3],
const float eul[3],
diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h
index 7a4ac14970f..1e56b80bcf2 100644
--- a/source/blender/blenlib/BLI_math_rotation.h
+++ b/source/blender/blenlib/BLI_math_rotation.h
@@ -96,6 +96,8 @@ void rotation_between_vecs_to_mat3(float m[3][3], const float v1[3], const float
void rotation_between_vecs_to_quat(float q[4], const float v1[3], const float v2[3]);
void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q2[4]);
+float quat_split_swing_and_twist(const float q[4], int axis, float r_swing[4], float r_twist[4]);
+
float angle_normalized_qt(const float q[4]);
float angle_normalized_qtqt(const float q1[4], const float q2[4]);
float angle_qt(const float q[4]);
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index ccb42683d5a..31d725af5ad 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -103,6 +103,7 @@ MINLINE void add_v2_fl(float r[2], float f);
MINLINE void add_v3_fl(float r[3], float f);
MINLINE void add_v4_fl(float r[4], float f);
MINLINE void add_v2_v2(float r[2], const float a[2]);
+MINLINE void add_v2_v2_db(double r[2], const double a[2]);
MINLINE void add_v2_v2v2(float r[2], const float a[2], const float b[2]);
MINLINE void add_v2_v2v2_int(int r[2], const int a[2], const int b[2]);
MINLINE void add_v3_v3(float r[3], const float a[3]);
@@ -116,6 +117,7 @@ MINLINE void add_v3fl_v3fl_v3s(float r[3], const float a[3], const short b[3]);
MINLINE void sub_v2_v2(float r[2], const float a[2]);
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2]);
+MINLINE void sub_v2_v2v2_db(double r[2], const double a[2], const double b[2]);
MINLINE void sub_v2_v2v2_int(int r[2], const int a[2], const int b[2]);
MINLINE void sub_v3_v3(float r[3], const float a[3]);
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3]);
@@ -184,6 +186,7 @@ MINLINE void abs_v4(float r[4]);
MINLINE void abs_v4_v4(float r[4], const float a[4]);
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
+MINLINE double dot_v2v2_db(const double a[2], const double b[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_v3v3v3(const float p[3],
const float a[3],
@@ -212,8 +215,10 @@ MINLINE int len_manhattan_v2_int(const int v[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE float len_manhattan_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float len_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE float len_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
+MINLINE double len_v2v2_db(const double a[2], const double b[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE float len_v2v2_int(const int v1[2], const int v2[2]);
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
+MINLINE double len_squared_v2v2_db(const double a[2], const double b[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float len_squared_v4v4(const float a[4], const float b[4]) ATTR_WARN_UNUSED_RESULT;
MINLINE float len_manhattan_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/blenlib/BLI_memblock.h b/source/blender/blenlib/BLI_memblock.h
index c5ef26ffb91..8bd8642a4e8 100644
--- a/source/blender/blenlib/BLI_memblock.h
+++ b/source/blender/blenlib/BLI_memblock.h
@@ -30,16 +30,20 @@ extern "C" {
#include "BLI_compiler_attrs.h"
+#define BLI_MEM_BLOCK_CHUNK_SIZE (1 << 15) /* 32KiB */
+
struct BLI_memblock;
typedef struct BLI_memblock BLI_memblock;
typedef void (*MemblockValFreeFP)(void *val);
-BLI_memblock *BLI_memblock_create(uint elem_size) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-void *BLI_memblock_alloc(BLI_memblock *mblk) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+BLI_memblock *BLI_memblock_create_ex(uint elem_size, uint chunk_size) ATTR_WARN_UNUSED_RESULT;
+void *BLI_memblock_alloc(BLI_memblock *mblk) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void BLI_memblock_clear(BLI_memblock *mblk, MemblockValFreeFP valfreefp) ATTR_NONNULL(1);
void BLI_memblock_destroy(BLI_memblock *mblk, MemblockValFreeFP free_callback) ATTR_NONNULL(1);
+#define BLI_memblock_create(elem_size) BLI_memblock_create_ex(elem_size, BLI_MEM_BLOCK_CHUNK_SIZE)
+
typedef struct BLI_memblock_iter {
void **chunk_list;
int cur_index;
@@ -53,6 +57,9 @@ typedef struct BLI_memblock_iter {
void BLI_memblock_iternew(BLI_memblock *pool, BLI_memblock_iter *iter) ATTR_NONNULL();
void *BLI_memblock_iterstep(BLI_memblock_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL();
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_memory_utils_cxx.h b/source/blender/blenlib/BLI_memory_utils_cxx.h
new file mode 100644
index 00000000000..22f333c6303
--- /dev/null
+++ b/source/blender/blenlib/BLI_memory_utils_cxx.h
@@ -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.
+ */
+
+#ifndef __BLI_MEMORY_UTILS_CXX_H__
+#define __BLI_MEMORY_UTILS_CXX_H__
+
+/** \file
+ * \ingroup bli
+ */
+
+#include <memory>
+#include <algorithm>
+
+namespace BLI {
+
+using std::copy;
+using std::copy_n;
+using std::uninitialized_copy;
+using std::uninitialized_copy_n;
+using std::uninitialized_fill;
+using std::uninitialized_fill_n;
+
+template<typename T> void destruct(T *ptr)
+{
+ ptr->~T();
+}
+
+template<typename T> void destruct_n(T *ptr, uint n)
+{
+ for (uint i = 0; i < n; i++) {
+ ptr[i].~T();
+ }
+}
+
+template<typename T> void uninitialized_move_n(T *src, uint n, T *dst)
+{
+ std::uninitialized_copy_n(std::make_move_iterator(src), n, dst);
+}
+
+template<typename T> void move_n(T *src, uint n, T *dst)
+{
+ std::copy_n(std::make_move_iterator(src), n, dst);
+}
+
+template<typename T> void uninitialized_relocate(T *src, T *dst)
+{
+ new (dst) T(std::move(*src));
+ destruct(src);
+}
+
+template<typename T> void uninitialized_relocate_n(T *src, uint n, T *dst)
+{
+ uninitialized_move_n(src, n, dst);
+ destruct_n(src, n);
+}
+
+template<typename T> void relocate(T *src, T *dst)
+{
+ *dst = std::move(*src);
+ destruct(src);
+}
+
+template<typename T> void relocate_n(T *src, uint n, T *dst)
+{
+ move_n(src, n, dst);
+ destruct_n(src, n);
+}
+
+} // namespace BLI
+
+#endif /* __BLI_MEMORY_UTILS_CXX_H__ */
diff --git a/source/blender/blenlib/BLI_open_addressing.h b/source/blender/blenlib/BLI_open_addressing.h
new file mode 100644
index 00000000000..8ca5156a952
--- /dev/null
+++ b/source/blender/blenlib/BLI_open_addressing.h
@@ -0,0 +1,305 @@
+/*
+ * 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.
+ */
+
+#ifndef __BLI_OPEN_ADDRESSING_H__
+#define __BLI_OPEN_ADDRESSING_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * This class offers a useful abstraction for other containers that implement hash tables using
+ * open addressing. It handles the following aspects:
+ * - Allocation and deallocation of the open addressing array.
+ * - Optional small object optimization.
+ * - Keeps track of how many elements and dummies are in the table.
+ *
+ * The nice thing about this abstraction is that it does not get in the way of any performance
+ * optimizations. The data that is actually stored in the table is still fully defined by the
+ * actual hash table implementation.
+ */
+
+#include <cmath>
+
+#include "BLI_utildefines.h"
+#include "BLI_memory_utils_cxx.h"
+#include "BLI_math_base.h"
+#include "BLI_allocator.h"
+
+namespace BLI {
+
+template<typename Item, uint32_t ItemsInSmallStorage = 1, typename Allocator = GuardedAllocator>
+class OpenAddressingArray {
+ private:
+ static constexpr uint32_t slots_per_item = Item::slots_per_item;
+ static constexpr float max_load_factor = 0.5f;
+
+ /* Invariants:
+ * 2^m_item_exponent = m_item_amount
+ * m_item_amount * slots_per_item = m_slots_total
+ * m_slot_mask = m_slots_total - 1
+ * m_slots_set_or_dummy < m_slots_total
+ */
+
+ /* Array containing the actual hash table. Might be a pointer to the inlined storage. */
+ Item *m_items;
+ /* Number of items in the hash table. Must be a power of two. */
+ uint32_t m_item_amount;
+ /* Exponent of the current item amount. */
+ uint8_t m_item_exponent;
+ /* Number of elements that could be stored in the table when the load factor is 1. */
+ uint32_t m_slots_total;
+ /* Number of elements that are not empty. */
+ uint32_t m_slots_set_or_dummy;
+ /* Number of dummy entries. */
+ uint32_t m_slots_dummy;
+ /* Max number of slots that can be non-empty according to the load factor. */
+ uint32_t m_slots_usable;
+ /* Can be used to map a hash value into the range of valid slot indices. */
+ uint32_t m_slot_mask;
+ Allocator m_allocator;
+ char m_local_storage[sizeof(Item) * ItemsInSmallStorage];
+
+ public:
+ explicit OpenAddressingArray(uint8_t item_exponent = 0)
+ {
+ m_slots_total = ((uint32_t)1 << item_exponent) * slots_per_item;
+ m_slots_set_or_dummy = 0;
+ m_slots_dummy = 0;
+ m_slots_usable = (uint32_t)((float)m_slots_total * max_load_factor);
+ m_slot_mask = m_slots_total - 1;
+ m_item_amount = m_slots_total / slots_per_item;
+ m_item_exponent = item_exponent;
+
+ if (m_item_amount <= ItemsInSmallStorage) {
+ m_items = this->small_storage();
+ }
+ else {
+ m_items = (Item *)m_allocator.allocate_aligned(
+ (uint32_t)sizeof(Item) * m_item_amount, std::alignment_of<Item>::value, __func__);
+ }
+
+ for (uint32_t i = 0; i < m_item_amount; i++) {
+ new (m_items + i) Item();
+ }
+ }
+
+ ~OpenAddressingArray()
+ {
+ if (m_items != nullptr) {
+ for (uint32_t i = 0; i < m_item_amount; i++) {
+ m_items[i].~Item();
+ }
+ if (!this->is_in_small_storage()) {
+ m_allocator.deallocate((void *)m_items);
+ }
+ }
+ }
+
+ OpenAddressingArray(const OpenAddressingArray &other)
+ {
+ m_slots_total = other.m_slots_total;
+ m_slots_set_or_dummy = other.m_slots_set_or_dummy;
+ m_slots_dummy = other.m_slots_dummy;
+ m_slots_usable = other.m_slots_usable;
+ m_slot_mask = other.m_slot_mask;
+ m_item_amount = other.m_item_amount;
+ m_item_exponent = other.m_item_exponent;
+
+ if (m_item_amount <= ItemsInSmallStorage) {
+ m_items = this->small_storage();
+ }
+ else {
+ m_items = (Item *)m_allocator.allocate_aligned(
+ sizeof(Item) * m_item_amount, std::alignment_of<Item>::value, __func__);
+ }
+
+ uninitialized_copy_n(other.m_items, m_item_amount, m_items);
+ }
+
+ OpenAddressingArray(OpenAddressingArray &&other) noexcept
+ {
+ m_slots_total = other.m_slots_total;
+ m_slots_set_or_dummy = other.m_slots_set_or_dummy;
+ m_slots_dummy = other.m_slots_dummy;
+ m_slots_usable = other.m_slots_usable;
+ m_slot_mask = other.m_slot_mask;
+ m_item_amount = other.m_item_amount;
+ m_item_exponent = other.m_item_exponent;
+ if (other.is_in_small_storage()) {
+ m_items = this->small_storage();
+ uninitialized_relocate_n(other.m_items, m_item_amount, m_items);
+ }
+ else {
+ m_items = other.m_items;
+ }
+
+ other.m_items = nullptr;
+ other.~OpenAddressingArray();
+ new (&other) OpenAddressingArray();
+ }
+
+ OpenAddressingArray &operator=(const OpenAddressingArray &other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+ this->~OpenAddressingArray();
+ new (this) OpenAddressingArray(other);
+ return *this;
+ }
+
+ OpenAddressingArray &operator=(OpenAddressingArray &&other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+ this->~OpenAddressingArray();
+ new (this) OpenAddressingArray(std::move(other));
+ return *this;
+ }
+
+ /* Prepare a new array that can hold a minimum of min_usable_slots elements. All entries are
+ * empty. */
+ OpenAddressingArray init_reserved(uint32_t min_usable_slots) const
+ {
+ float min_total_slots = (float)min_usable_slots / max_load_factor;
+ uint32_t min_total_items = (uint32_t)std::ceil(min_total_slots / (float)slots_per_item);
+ uint8_t item_exponent = (uint8_t)log2_ceil_u(min_total_items);
+ OpenAddressingArray grown(item_exponent);
+ grown.m_slots_set_or_dummy = this->slots_set();
+ return grown;
+ }
+
+ /**
+ * Amount of items in the array times the number of slots per item.
+ */
+ uint32_t slots_total() const
+ {
+ return m_slots_total;
+ }
+
+ /**
+ * Amount of slots that are initialized with some value that is not empty or dummy.
+ */
+ uint32_t slots_set() const
+ {
+ return m_slots_set_or_dummy - m_slots_dummy;
+ }
+
+ /**
+ * Amount of slots that can be used before the array should grow.
+ */
+ uint32_t slots_usable() const
+ {
+ return m_slots_usable;
+ }
+
+ /**
+ * Update the counters after one empty element is used for a newly added element.
+ */
+ void update__empty_to_set()
+ {
+ m_slots_set_or_dummy++;
+ }
+
+ /**
+ * Update the counters after one previously dummy element becomes set.
+ */
+ void update__dummy_to_set()
+ {
+ m_slots_dummy--;
+ }
+
+ /**
+ * Update the counters after one previously set element becomes a dummy.
+ */
+ void update__set_to_dummy()
+ {
+ m_slots_dummy++;
+ }
+
+ /**
+ * Access the current slot mask for this array.
+ */
+ uint32_t slot_mask() const
+ {
+ return m_slot_mask;
+ }
+
+ /**
+ * Access the item for a specific item index.
+ * Note: The item index is not necessarily the slot index.
+ */
+ const Item &item(uint32_t item_index) const
+ {
+ return m_items[item_index];
+ }
+
+ Item &item(uint32_t item_index)
+ {
+ return m_items[item_index];
+ }
+
+ uint8_t item_exponent() const
+ {
+ return m_item_exponent;
+ }
+
+ uint32_t item_amount() const
+ {
+ return m_item_amount;
+ }
+
+ bool should_grow() const
+ {
+ return m_slots_set_or_dummy >= m_slots_usable;
+ }
+
+ Item *begin()
+ {
+ return m_items;
+ }
+
+ Item *end()
+ {
+ return m_items + m_item_amount;
+ }
+
+ const Item *begin() const
+ {
+ return m_items;
+ }
+
+ const Item *end() const
+ {
+ return m_items + m_item_amount;
+ }
+
+ private:
+ Item *small_storage() const
+ {
+ return reinterpret_cast<Item *>((char *)m_local_storage);
+ }
+
+ bool is_in_small_storage() const
+ {
+ return m_items == this->small_storage();
+ }
+};
+
+} // namespace BLI
+
+#endif /* __BLI_OPEN_ADDRESSING_H__ */
diff --git a/source/blender/blenlib/BLI_polyfill_2d_beautify.h b/source/blender/blenlib/BLI_polyfill_2d_beautify.h
index f815459fdf5..042cb7e0ea9 100644
--- a/source/blender/blenlib/BLI_polyfill_2d_beautify.h
+++ b/source/blender/blenlib/BLI_polyfill_2d_beautify.h
@@ -36,9 +36,10 @@ float BLI_polyfill_beautify_quad_rotate_calc_ex(const float v1[2],
const float v2[2],
const float v3[2],
const float v4[2],
- const bool lock_degenerate);
+ const bool lock_degenerate,
+ float *r_area);
#define BLI_polyfill_beautify_quad_rotate_calc(v1, v2, v3, v4) \
- BLI_polyfill_beautify_quad_rotate_calc_ex(v1, v2, v3, v4, false)
+ BLI_polyfill_beautify_quad_rotate_calc_ex(v1, v2, v3, v4, false, NULL)
/* avoid realloc's when creating new structures for polyfill ngons */
#define BLI_POLYFILL_ALLOC_NGON_RESERVE 64
diff --git a/source/blender/blenlib/BLI_set.h b/source/blender/blenlib/BLI_set.h
new file mode 100644
index 00000000000..dc101add1a7
--- /dev/null
+++ b/source/blender/blenlib/BLI_set.h
@@ -0,0 +1,483 @@
+/*
+ * 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.
+ */
+
+#ifndef __BLI_SET_H__
+#define __BLI_SET_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * This file provides a set implementation that uses open addressing with probing.
+ */
+
+#include "BLI_hash_cxx.h"
+#include "BLI_open_addressing.h"
+#include "BLI_vector.h"
+
+namespace BLI {
+
+// clang-format off
+
+#define ITER_SLOTS_BEGIN(VALUE, ARRAY, OPTIONAL_CONST, R_ITEM, R_OFFSET) \
+ uint32_t hash = DefaultHash<T>{}(VALUE); \
+ uint32_t perturb = hash; \
+ while (true) { \
+ uint32_t item_index = (hash & ARRAY.slot_mask()) >> OFFSET_SHIFT; \
+ uint8_t R_OFFSET = hash & OFFSET_MASK; \
+ uint8_t initial_offset = R_OFFSET; \
+ OPTIONAL_CONST Item &R_ITEM = ARRAY.item(item_index); \
+ do {
+
+#define ITER_SLOTS_END(R_OFFSET) \
+ R_OFFSET = (R_OFFSET + 1) & OFFSET_MASK; \
+ } while (R_OFFSET != initial_offset); \
+ perturb >>= 5; \
+ hash = hash * 5 + 1 + perturb; \
+ } ((void)0)
+
+// clang-format on
+
+template<typename T, typename Allocator = GuardedAllocator> class Set {
+ private:
+ static constexpr uint OFFSET_MASK = 3;
+ static constexpr uint OFFSET_SHIFT = 2;
+
+ class Item {
+ private:
+ static constexpr uint8_t IS_EMPTY = 0;
+ static constexpr uint8_t IS_SET = 1;
+ static constexpr uint8_t IS_DUMMY = 2;
+
+ uint8_t m_status[4];
+ char m_values[4 * sizeof(T)];
+
+ public:
+ static constexpr uint slots_per_item = 4;
+
+ Item()
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ m_status[offset] = IS_EMPTY;
+ }
+ }
+
+ ~Item()
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ if (m_status[offset] == IS_SET) {
+ destruct(this->value(offset));
+ }
+ }
+ }
+
+ Item(const Item &other)
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ uint8_t status = other.m_status[offset];
+ m_status[offset] = status;
+ if (status == IS_SET) {
+ T *src = other.value(offset);
+ T *dst = this->value(offset);
+ new (dst) T(*src);
+ }
+ }
+ }
+
+ Item(Item &&other) noexcept
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ uint8_t status = other.m_status[offset];
+ m_status[offset] = status;
+ if (status == IS_SET) {
+ T *src = other.value(offset);
+ T *dst = this->value(offset);
+ new (dst) T(std::move(*src));
+ }
+ }
+ }
+
+ Item &operator=(const Item &other) = delete;
+ Item &operator=(Item &&other) = delete;
+
+ T *value(uint offset) const
+ {
+ return (T *)(m_values + offset * sizeof(T));
+ }
+
+ template<typename ForwardT> void store(uint offset, ForwardT &&value)
+ {
+ BLI_assert(m_status[offset] != IS_SET);
+ m_status[offset] = IS_SET;
+ T *dst = this->value(offset);
+ new (dst) T(std::forward<ForwardT>(value));
+ }
+
+ void set_dummy(uint offset)
+ {
+ BLI_assert(m_status[offset] == IS_SET);
+ m_status[offset] = IS_DUMMY;
+ destruct(this->value(offset));
+ }
+
+ bool is_empty(uint offset) const
+ {
+ return m_status[offset] == IS_EMPTY;
+ }
+
+ bool is_set(uint offset) const
+ {
+ return m_status[offset] == IS_SET;
+ }
+
+ bool is_dummy(uint offset) const
+ {
+ return m_status[offset] == IS_DUMMY;
+ }
+
+ bool has_value(uint offset, const T &value) const
+ {
+ return m_status[offset] == IS_SET && *this->value(offset) == value;
+ }
+ };
+
+ using ArrayType = OpenAddressingArray<Item, 1, Allocator>;
+ ArrayType m_array = OpenAddressingArray<Item>();
+
+ public:
+ Set() = default;
+
+ /**
+ * Create a new set that contains the given elements.
+ */
+ Set(ArrayRef<T> values)
+ {
+ this->reserve(values.size());
+ for (const T &value : values) {
+ this->add(value);
+ }
+ }
+
+ /**
+ * Create a new set from an initializer list.
+ */
+ Set(std::initializer_list<T> values) : Set(ArrayRef<T>(values))
+ {
+ }
+
+ /**
+ * Make the set large enough to hold the given amount of elements.
+ */
+ void reserve(uint32_t min_usable_slots)
+ {
+ if (m_array.slots_usable() < min_usable_slots) {
+ this->grow(min_usable_slots);
+ }
+ }
+
+ /**
+ * Add a new element to the set.
+ * Asserts that the element did not exist in the set before.
+ */
+ void add_new(const T &value)
+ {
+ this->add_new__impl(value);
+ }
+ void add_new(T &&value)
+ {
+ this->add_new__impl(std::move(value));
+ }
+
+ /**
+ * Add a new value to the set if it does not exist yet.
+ */
+ bool add(const T &value)
+ {
+ return this->add__impl(value);
+ }
+ bool add(T &&value)
+ {
+ return this->add__impl(std::move(value));
+ }
+
+ /**
+ * Add multiple elements to the set.
+ */
+ void add_multiple(ArrayRef<T> values)
+ {
+ for (const T &value : values) {
+ this->add(value);
+ }
+ }
+
+ /**
+ * Add multiple new elements to the set.
+ * Asserts that none of the elements existed in the set before.
+ */
+ void add_multiple_new(ArrayRef<T> values)
+ {
+ for (const T &value : values) {
+ this->add_new(value);
+ }
+ }
+
+ /**
+ * Returns true when the value is in the set, otherwise false.
+ */
+ bool contains(const T &value) const
+ {
+ ITER_SLOTS_BEGIN (value, m_array, const, item, offset) {
+ if (item.is_empty(offset)) {
+ return false;
+ }
+ else if (item.has_value(offset, value)) {
+ return true;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ /**
+ * Remove the value from the set.
+ * Asserts that the value exists in the set currently.
+ */
+ void remove(const T &value)
+ {
+ BLI_assert(this->contains(value));
+ ITER_SLOTS_BEGIN (value, m_array, , item, offset) {
+ if (item.has_value(offset, value)) {
+ item.set_dummy(offset);
+ m_array.update__set_to_dummy();
+ return;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ Vector<T> to_small_vector() const
+ {
+ Vector<T> vector;
+ vector.reserve(this->size());
+ for (const T &value : *this) {
+ vector.append(value);
+ }
+ return vector;
+ }
+
+ uint32_t size() const
+ {
+ return m_array.slots_set();
+ }
+
+ /**
+ * Returns true when there is at least one element that is in both sets.
+ * Otherwise false.
+ */
+ static bool Intersects(const Set &a, const Set &b)
+ {
+ /* Make sure we iterate over the shorter set. */
+ if (a.size() > b.size()) {
+ return Intersects(b, a);
+ }
+
+ for (const T &value : a) {
+ if (b.contains(value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true when there is no value that is in both sets.
+ * Otherwise false.
+ */
+ static bool Disjoint(const Set &a, const Set &b)
+ {
+ return !Intersects(a, b);
+ }
+
+ void print_table() const
+ {
+ std::cout << "Hash Table:\n";
+ std::cout << " Size: " << m_array.slots_set() << '\n';
+ std::cout << " Capacity: " << m_array.slots_total() << '\n';
+ uint32_t item_index = 0;
+ for (const Item &item : m_array) {
+ std::cout << " Item: " << item_index++ << '\n';
+ for (uint offset = 0; offset < 4; offset++) {
+ std::cout << " " << offset << " \t";
+ if (item.is_empty(offset)) {
+ std::cout << " <empty>\n";
+ }
+ else if (item.is_set(offset)) {
+ const T &value = *item.value(offset);
+ uint32_t collisions = this->count_collisions(value);
+ std::cout << " " << value << " \t Collisions: " << collisions << '\n';
+ }
+ else if (item.is_dummy(offset)) {
+ std::cout << " <dummy>\n";
+ }
+ }
+ }
+ }
+
+ class Iterator {
+ private:
+ const Set *m_set;
+ uint32_t m_slot;
+
+ public:
+ Iterator(const Set *set, uint32_t slot) : m_set(set), m_slot(slot)
+ {
+ }
+
+ Iterator &operator++()
+ {
+ m_slot = m_set->next_slot(m_slot + 1);
+ return *this;
+ }
+
+ const T &operator*() const
+ {
+ uint32_t item_index = m_slot >> OFFSET_SHIFT;
+ uint offset = m_slot & OFFSET_MASK;
+ const Item &item = m_set->m_array.item(item_index);
+ BLI_assert(item.is_set(offset));
+ return *item.value(offset);
+ }
+
+ friend bool operator==(const Iterator &a, const Iterator &b)
+ {
+ BLI_assert(a.m_set == b.m_set);
+ return a.m_slot == b.m_slot;
+ }
+
+ friend bool operator!=(const Iterator &a, const Iterator &b)
+ {
+ return !(a == b);
+ }
+ };
+
+ friend Iterator;
+
+ Iterator begin() const
+ {
+ return Iterator(this, this->next_slot(0));
+ }
+
+ Iterator end() const
+ {
+ return Iterator(this, m_array.slots_total());
+ }
+
+ private:
+ uint32_t next_slot(uint32_t slot) const
+ {
+ for (; slot < m_array.slots_total(); slot++) {
+ uint32_t item_index = slot >> OFFSET_SHIFT;
+ uint offset = slot & OFFSET_MASK;
+ const Item &item = m_array.item(item_index);
+ if (item.is_set(offset)) {
+ return slot;
+ }
+ }
+ return slot;
+ }
+
+ void ensure_can_add()
+ {
+ if (UNLIKELY(m_array.should_grow())) {
+ this->grow(this->size() + 1);
+ }
+ }
+
+ BLI_NOINLINE void grow(uint32_t min_usable_slots)
+ {
+ ArrayType new_array = m_array.init_reserved(min_usable_slots);
+
+ for (Item &old_item : m_array) {
+ for (uint8_t offset = 0; offset < 4; offset++) {
+ if (old_item.is_set(offset)) {
+ this->add_after_grow(*old_item.value(offset), new_array);
+ }
+ }
+ }
+
+ m_array = std::move(new_array);
+ }
+
+ void add_after_grow(T &old_value, ArrayType &new_array)
+ {
+ ITER_SLOTS_BEGIN (old_value, new_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, std::move(old_value));
+ return;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ uint32_t count_collisions(const T &value) const
+ {
+ uint32_t collisions = 0;
+ ITER_SLOTS_BEGIN (value, m_array, const, item, offset) {
+ if (item.is_empty(offset) || item.has_value(offset, value)) {
+ return collisions;
+ }
+ collisions++;
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ template<typename ForwardT> void add_new__impl(ForwardT &&value)
+ {
+ BLI_assert(!this->contains(value));
+ this->ensure_can_add();
+
+ ITER_SLOTS_BEGIN (value, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, std::forward<ForwardT>(value));
+ m_array.update__empty_to_set();
+ return;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ template<typename ForwardT> bool add__impl(ForwardT &&value)
+ {
+ this->ensure_can_add();
+
+ ITER_SLOTS_BEGIN (value, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, std::forward<ForwardT>(value));
+ m_array.update__empty_to_set();
+ return true;
+ }
+ else if (item.has_value(offset, value)) {
+ return false;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+};
+
+#undef ITER_SLOTS_BEGIN
+#undef ITER_SLOTS_END
+
+} // namespace BLI
+
+#endif /* __BLI_SET_H__ */
diff --git a/source/blender/blenlib/BLI_sort.h b/source/blender/blenlib/BLI_sort.h
index b6250afdee0..08e61915a83 100644
--- a/source/blender/blenlib/BLI_sort.h
+++ b/source/blender/blenlib/BLI_sort.h
@@ -31,7 +31,7 @@
# define BLI_qsort_r qsort_r
#endif
-/* Quick sort reentrant */
+/* Quick sort re-entrant */
typedef int (*BLI_sort_cmp_t)(const void *a, const void *b, void *ctx);
void BLI_qsort_r(void *a, size_t n, size_t es, BLI_sort_cmp_t cmp, void *thunk)
diff --git a/source/blender/blenlib/BLI_stack_cxx.h b/source/blender/blenlib/BLI_stack_cxx.h
new file mode 100644
index 00000000000..7915acadfac
--- /dev/null
+++ b/source/blender/blenlib/BLI_stack_cxx.h
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ */
+
+#ifndef __BLI_STACK_CXX_H__
+#define __BLI_STACK_CXX_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * Basic stack implementation with support for small object optimization.
+ */
+
+#include "BLI_vector.h"
+
+namespace BLI {
+
+template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Stack {
+ private:
+ Vector<T, N, Allocator> m_elements;
+
+ public:
+ Stack() = default;
+
+ /**
+ * Construct a stack from an array ref. The elements will be pushed in the same order they are in
+ * the array.
+ */
+ Stack(ArrayRef<T> values) : m_elements(values)
+ {
+ }
+
+ operator ArrayRef<T>()
+ {
+ return m_elements;
+ }
+
+ /**
+ * Return the number of elements in the stack.
+ */
+ uint size() const
+ {
+ return m_elements.size();
+ }
+
+ /**
+ * Return true when the stack is empty, otherwise false.
+ */
+ bool empty() const
+ {
+ return this->size() == 0;
+ }
+
+ /**
+ * Add a new element to the top of the stack.
+ */
+ void push(const T &value)
+ {
+ m_elements.append(value);
+ }
+
+ void push(T &&value)
+ {
+ m_elements.append(std::move(value));
+ }
+
+ /**
+ * Remove the element from the top of the stack and return it.
+ * This will assert when the stack is empty.
+ */
+ T pop()
+ {
+ return m_elements.pop_last();
+ }
+
+ /**
+ * Return a reference to the value a the top of the stack.
+ * This will assert when the stack is empty.
+ */
+ T &peek()
+ {
+ BLI_assert(!this->empty());
+ return m_elements[this->size() - 1];
+ }
+
+ T *begin()
+ {
+ return m_elements.begin();
+ }
+
+ T *end()
+ {
+ return m_elements.end();
+ }
+
+ const T *begin() const
+ {
+ return m_elements.begin();
+ }
+
+ const T *end() const
+ {
+ return m_elements.end();
+ }
+
+ /**
+ * Remove all elements from the stack but keep the memory.
+ */
+ void clear()
+ {
+ m_elements.clear();
+ }
+
+ /**
+ * Remove all elements and free any allocated memory.
+ */
+ void clear_and_make_small()
+ {
+ m_elements.clear_and_make_small();
+ }
+
+ /**
+ * Does a linear search to check if the value is in the stack.
+ */
+ bool contains(const T &value)
+ {
+ return m_elements.contains(value);
+ }
+};
+
+} /* namespace BLI */
+
+#endif /* __BLI_STACK_CXX_H__ */
diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h
index 70ffb46e952..cab2e68ca2b 100644
--- a/source/blender/blenlib/BLI_string.h
+++ b/source/blender/blenlib/BLI_string.h
@@ -100,7 +100,7 @@ char *BLI_strncasestr(const char *s, const char *find, size_t len) ATTR_WARN_UNU
int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_strncasecmp(const char *s1, const char *s2, size_t len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-int BLI_natstrcmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_strcmp_ignore_pad(const char *str1,
const char *str2,
const char pad) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
diff --git a/source/blender/blenlib/BLI_string_map.h b/source/blender/blenlib/BLI_string_map.h
new file mode 100644
index 00000000000..ba870eb878a
--- /dev/null
+++ b/source/blender/blenlib/BLI_string_map.h
@@ -0,0 +1,425 @@
+/*
+ * 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.
+ */
+
+#ifndef __BLI_STRING_MAP_H__
+#define __BLI_STRING_MAP_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * This tries to solve the issue that a normal map with std::string as key might do many
+ * allocations when the keys are longer than 16 bytes (the usual small string optimization size).
+ *
+ * For now this still uses std::string, but having this abstraction in place will make it easier to
+ * make it more efficient later on. Also, even if we will never implement this optimization, having
+ * a special map with string keys can be quite handy. */
+
+#include "BLI_map.h"
+#include "BLI_string_ref.h"
+#include "BLI_vector.h"
+
+namespace BLI {
+
+// clang-format off
+
+#define ITER_SLOTS_BEGIN(HASH, ARRAY, OPTIONAL_CONST, R_ITEM, R_OFFSET) \
+ uint32_t hash_copy = HASH; \
+ uint32_t perturb = HASH; \
+ while (true) { \
+ uint32_t item_index = (hash_copy & ARRAY.slot_mask()) >> OFFSET_SHIFT; \
+ uint8_t R_OFFSET = hash_copy & OFFSET_MASK; \
+ uint8_t initial_offset = R_OFFSET; \
+ OPTIONAL_CONST Item &R_ITEM = ARRAY.item(item_index); \
+ do {
+
+#define ITER_SLOTS_END(R_OFFSET) \
+ R_OFFSET = (R_OFFSET + 1) & OFFSET_MASK; \
+ } while (R_OFFSET != initial_offset); \
+ perturb >>= 5; \
+ hash_copy = hash_copy * 5 + 1 + perturb; \
+ } ((void)0)
+
+// clang-format on
+
+template<typename T, typename Allocator = GuardedAllocator> class StringMap {
+ private:
+ static constexpr uint32_t OFFSET_MASK = 3;
+ static constexpr uint32_t OFFSET_SHIFT = 2;
+
+ class Item {
+ private:
+ static constexpr int32_t IS_EMPTY = -1;
+
+ uint32_t m_hashes[4];
+ int32_t m_indices[4];
+ char m_values[sizeof(T) * 4];
+
+ public:
+ static constexpr uint slots_per_item = 4;
+
+ Item()
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ m_indices[offset] = IS_EMPTY;
+ }
+ }
+
+ ~Item()
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ if (this->is_set(offset)) {
+ destruct(this->value(offset));
+ }
+ }
+ }
+
+ Item(const Item &other)
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ m_indices[offset] = other.m_indices[offset];
+ if (other.is_set(offset)) {
+ m_hashes[offset] = other.m_hashes[offset];
+ new (this->value(offset)) T(*other.value(offset));
+ }
+ }
+ }
+
+ Item(Item &&other) noexcept
+ {
+ for (uint offset = 0; offset < 4; offset++) {
+ m_indices[offset] = other.m_indices[offset];
+ if (other.is_set(offset)) {
+ m_hashes[offset] = other.m_hashes[offset];
+ new (this->value(offset)) T(std::move(*other.value(offset)));
+ }
+ }
+ }
+
+ uint32_t index(uint offset) const
+ {
+ return m_indices[offset];
+ }
+
+ uint32_t hash(uint offset) const
+ {
+ return m_hashes[offset];
+ }
+
+ T *value(uint offset) const
+ {
+ return (T *)POINTER_OFFSET(m_values, offset * sizeof(T));
+ }
+
+ bool is_set(uint offset) const
+ {
+ return m_indices[offset] >= 0;
+ }
+
+ bool is_empty(uint offset) const
+ {
+ return m_indices[offset] == IS_EMPTY;
+ }
+
+ bool has_hash(uint offset, uint32_t hash) const
+ {
+ BLI_assert(this->is_set(offset));
+ return m_hashes[offset] == hash;
+ }
+
+ bool has_exact_key(uint offset, StringRef key, const Vector<char> &chars) const
+ {
+ return key == this->get_key(offset, chars);
+ }
+
+ StringRefNull get_key(uint offset, const Vector<char> &chars) const
+ {
+ const char *ptr = chars.begin() + m_indices[offset];
+ uint length = *(uint *)ptr;
+ const char *start = ptr + sizeof(uint);
+ return StringRefNull(start, length);
+ }
+
+ template<typename ForwardT>
+ void store(uint offset, uint32_t hash, uint32_t index, ForwardT &&value)
+ {
+ BLI_assert(!this->is_set(offset));
+ m_hashes[offset] = hash;
+ m_indices[offset] = index;
+ new (this->value(offset)) T(std::forward<ForwardT>(value));
+ }
+ };
+
+ using ArrayType = OpenAddressingArray<Item, 1, Allocator>;
+ ArrayType m_array;
+ Vector<char> m_chars;
+
+ public:
+ StringMap() = default;
+
+ /**
+ * Get the number of key-value pairs in the map.
+ */
+ uint size() const
+ {
+ return m_array.slots_set();
+ }
+
+ /**
+ * Add a new element to the map. It is assumed that the key did not exist before.
+ */
+ void add_new(StringRef key, const T &value)
+ {
+ this->add_new__impl(key, value);
+ }
+ void add_new(StringRef key, T &&value)
+ {
+ this->add_new__impl(key, std::move(value));
+ }
+
+ /**
+ * Return true when the key exists in the map, otherwise false.
+ */
+ bool contains(StringRef key) const
+ {
+ uint32_t hash = this->compute_string_hash(key);
+ ITER_SLOTS_BEGIN (hash, m_array, const, item, offset) {
+ if (item.is_empty(offset)) {
+ return false;
+ }
+ else if (item.has_hash(offset, hash) && item.has_exact_key(offset, key, m_chars)) {
+ return true;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ /**
+ * Get a reference to the value corresponding to a key. It is assumed that the key does exist.
+ */
+ const T &lookup(StringRef key) const
+ {
+ BLI_assert(this->contains(key));
+ T *found_value = nullptr;
+ uint32_t hash = this->compute_string_hash(key);
+ ITER_SLOTS_BEGIN (hash, m_array, const, item, offset) {
+ if (item.is_empty(offset)) {
+ return *found_value;
+ }
+ else if (item.has_hash(offset, hash)) {
+ if (found_value == nullptr) {
+ /* Common case: the first slot with the correct hash contains the key.
+ * However, still need to iterate until the next empty slot to make sure there is no
+ * other key with the exact same hash. */
+ /* TODO: Check if we can guarantee that every hash only exists once in some cases. */
+ found_value = item.value(offset);
+ }
+ else if (item.has_exact_key(offset, key, m_chars)) {
+ /* Found the hash more than once, now check for actual string equality. */
+ return *item.value(offset);
+ }
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ T &lookup(StringRef key)
+ {
+ return const_cast<T &>(const_cast<const StringMap *>(this)->lookup(key));
+ }
+
+ /**
+ * Get a pointer to the value corresponding to the key. Return nullptr, if the key does not
+ * exist.
+ */
+ const T *lookup_ptr(StringRef key) const
+ {
+ uint32_t hash = this->compute_string_hash(key);
+ ITER_SLOTS_BEGIN (hash, m_array, const, item, offset) {
+ if (item.is_empty(offset)) {
+ return nullptr;
+ }
+ else if (item.has_hash(offset, hash) && item.has_exact_key(offset, key, m_chars)) {
+ return item.value(offset);
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ T *lookup_ptr(StringRef key)
+ {
+ return const_cast<T *>(const_cast<const StringMap *>(this)->lookup_ptr(key));
+ }
+
+ /**
+ * Get a copy of the value corresponding to the key. If the key does not exist, return the
+ * default value.
+ */
+ T lookup_default(StringRef key, const T &default_value) const
+ {
+ const T *ptr = this->lookup_ptr(key);
+ if (ptr != nullptr) {
+ return *ptr;
+ }
+ else {
+ return default_value;
+ }
+ }
+
+ /**
+ * Do a linear search over all items to find a key for a value.
+ */
+ StringRefNull find_key_for_value(const T &value) const
+ {
+ for (const Item &item : m_array) {
+ for (uint offset = 0; offset < 4; offset++) {
+ if (item.is_set(offset) && value == *item.value(offset)) {
+ return item.get_key(offset, m_chars);
+ }
+ }
+ }
+ BLI_assert(false);
+ return {};
+ }
+
+ /**
+ * Run a function for every value in the map.
+ */
+ template<typename FuncT> void foreach_value(const FuncT &func)
+ {
+ for (Item &item : m_array) {
+ for (uint offset = 0; offset < 4; offset++) {
+ if (item.is_set(offset)) {
+ func(*item.value(offset));
+ }
+ }
+ }
+ }
+
+ /**
+ * Run a function for every key in the map.
+ */
+ template<typename FuncT> void foreach_key(const FuncT &func)
+ {
+ for (Item &item : m_array) {
+ for (uint offset = 0; offset < 4; offset++) {
+ if (item.is_set(offset)) {
+ StringRefNull key = item.get_key(offset, m_chars);
+ func(key);
+ }
+ }
+ }
+ }
+
+ /**
+ * Run a function for every key-value-pair in the map.
+ */
+ template<typename FuncT> void foreach_key_value_pair(const FuncT &func)
+ {
+ for (Item &item : m_array) {
+ for (uint offset = 0; offset < 4; offset++) {
+ if (item.is_set(offset)) {
+ StringRefNull key = item.get_key(offset, m_chars);
+ T &value = *item.value(offset);
+ func(key, value);
+ }
+ }
+ }
+ }
+
+ private:
+ uint32_t compute_string_hash(StringRef key) const
+ {
+ /* TODO: check if this can be optimized more because we know the key length already. */
+ uint32_t hash = 5381;
+ for (char c : key) {
+ hash = hash * 33 + c;
+ }
+ return hash;
+ }
+
+ uint32_t save_key_in_array(StringRef key)
+ {
+ uint index = m_chars.size();
+ uint string_size = key.size();
+ m_chars.extend(ArrayRef<char>((char *)&string_size, sizeof(uint)));
+ m_chars.extend(key);
+ m_chars.append('\0');
+ return index;
+ }
+
+ StringRefNull key_from_index(uint32_t index) const
+ {
+ const char *ptr = m_chars.begin() + index;
+ uint length = *(uint *)ptr;
+ const char *start = ptr + sizeof(uint);
+ return StringRefNull(start, length);
+ }
+
+ void ensure_can_add()
+ {
+ if (UNLIKELY(m_array.should_grow())) {
+ this->grow(this->size() + 1);
+ }
+ }
+
+ BLI_NOINLINE void grow(uint min_usable_slots)
+ {
+ ArrayType new_array = m_array.init_reserved(min_usable_slots);
+ for (Item &old_item : m_array) {
+ for (uint offset = 0; offset < 4; offset++) {
+ if (old_item.is_set(offset)) {
+ this->add_after_grow(
+ *old_item.value(offset), old_item.hash(offset), old_item.index(offset), new_array);
+ }
+ }
+ }
+ m_array = std::move(new_array);
+ }
+
+ void add_after_grow(T &value, uint32_t hash, uint32_t index, ArrayType &new_array)
+ {
+ ITER_SLOTS_BEGIN (hash, new_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, hash, index, std::move(value));
+ return;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ template<typename ForwardT> void add_new__impl(StringRef key, ForwardT &&value)
+ {
+ BLI_assert(!this->contains(key));
+ this->ensure_can_add();
+ uint32_t hash = this->compute_string_hash(key);
+ ITER_SLOTS_BEGIN (hash, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ uint32_t index = this->save_key_in_array(key);
+ item.store(offset, hash, index, std::forward<ForwardT>(value));
+ m_array.update__empty_to_set();
+ return;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+};
+
+#undef ITER_SLOTS_BEGIN
+#undef ITER_SLOTS_END
+
+} // namespace BLI
+
+#endif /* __BLI_STRING_MAP_H__ */
diff --git a/source/blender/blenlib/BLI_string_ref.h b/source/blender/blenlib/BLI_string_ref.h
new file mode 100644
index 00000000000..76163a2754c
--- /dev/null
+++ b/source/blender/blenlib/BLI_string_ref.h
@@ -0,0 +1,247 @@
+/*
+ * 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.
+ */
+
+#ifndef __BLI_STRING_REF_H__
+#define __BLI_STRING_REF_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * A StringRef is a pointer to a string somewhere in memory. It should not be used to transfer
+ * ownership of that string. When a function gets a StringRef as input, it cannot expect, that
+ * the string will still exist after the function ends.
+ *
+ * There are two types of string references: One that guarantees null termination and one that does
+ * not.
+ */
+
+#include <cstring>
+#include <string>
+#include <sstream>
+
+#include "BLI_utildefines.h"
+#include "BLI_array_ref.h"
+
+namespace BLI {
+
+class StringRef;
+
+class StringRefBase {
+ public:
+ using size_type = size_t;
+
+ protected:
+ const char *m_data;
+ size_type m_size;
+
+ StringRefBase(const char *data, size_type size) : m_data(data), m_size(size)
+ {
+ }
+
+ public:
+ /**
+ * Return the (byte-)length of the referenced string, without any null-terminator.
+ */
+ size_type size() const
+ {
+ return m_size;
+ }
+
+ /**
+ * Return a pointer to the start of the string.
+ */
+ const char *data() const
+ {
+ return m_data;
+ }
+
+ char operator[](size_type index) const
+ {
+ BLI_assert(index <= m_size);
+ return m_data[index];
+ }
+
+ operator ArrayRef<char>() const
+ {
+ return ArrayRef<char>(m_data, m_size);
+ }
+
+ operator std::string() const
+ {
+ return std::string(m_data, m_size);
+ }
+
+ const char *begin() const
+ {
+ return m_data;
+ }
+
+ const char *end() const
+ {
+ return m_data + m_size;
+ }
+
+ void copy_to__with_null(char *dst) const
+ {
+ memcpy(dst, m_data, m_size);
+ dst[m_size] = '\0';
+ }
+
+ /**
+ * Returns true when the string begins with the given prefix. Otherwise false.
+ */
+ bool startswith(StringRef prefix) const;
+
+ /**
+ * Returns true when the string ends with the given suffix. Otherwise false.
+ */
+ bool endswith(StringRef suffix) const;
+};
+
+/**
+ * References a null-terminated char array.
+ */
+class StringRefNull : public StringRefBase {
+
+ public:
+ StringRefNull() : StringRefBase("", 0)
+ {
+ }
+
+ StringRefNull(const char *str) : StringRefBase(str, strlen(str))
+ {
+ BLI_assert(str != NULL);
+ BLI_assert(m_data[m_size] == '\0');
+ }
+
+ StringRefNull(const char *str, size_type size) : StringRefBase(str, size)
+ {
+ BLI_assert(str[size] == '\0');
+ }
+
+ StringRefNull(const std::string &str) : StringRefNull(str.data())
+ {
+ }
+};
+
+/**
+ * References a char array. It might not be null terminated.
+ */
+class StringRef : public StringRefBase {
+ public:
+ StringRef() : StringRefBase(nullptr, 0)
+ {
+ }
+
+ StringRef(StringRefNull other) : StringRefBase(other.data(), other.size())
+ {
+ }
+
+ StringRef(const char *str) : StringRefBase(str, str ? strlen(str) : 0)
+ {
+ }
+
+ StringRef(const char *str, size_type length) : StringRefBase(str, length)
+ {
+ }
+
+ StringRef(const std::string &str) : StringRefBase(str.data(), str.size())
+ {
+ }
+
+ /**
+ * Return a new StringRef that does not contain the first n chars.
+ */
+ StringRef drop_prefix(uint n) const
+ {
+ BLI_assert(n <= m_size);
+ return StringRef(m_data + n, m_size - n);
+ }
+
+ /**
+ * Return a new StringRef that with the given prefix being skipped.
+ * Asserts that the string begins with the given prefix.
+ */
+ StringRef drop_prefix(StringRef prefix) const
+ {
+ BLI_assert(this->startswith(prefix));
+ return this->drop_prefix(prefix.size());
+ }
+};
+
+/* More inline functions
+ ***************************************/
+
+inline std::ostream &operator<<(std::ostream &stream, StringRef ref)
+{
+ stream << std::string(ref);
+ return stream;
+}
+
+inline std::ostream &operator<<(std::ostream &stream, StringRefNull ref)
+{
+ stream << std::string(ref.data(), ref.size());
+ return stream;
+}
+
+inline std::string operator+(StringRef a, StringRef b)
+{
+ return std::string(a) + std::string(b);
+}
+
+inline bool operator==(StringRef a, StringRef b)
+{
+ if (a.size() != b.size()) {
+ return false;
+ }
+ return STREQLEN(a.data(), b.data(), a.size());
+}
+
+inline bool operator!=(StringRef a, StringRef b)
+{
+ return !(a == b);
+}
+
+inline bool StringRefBase::startswith(StringRef prefix) const
+{
+ if (m_size < prefix.m_size) {
+ return false;
+ }
+ for (uint i = 0; i < prefix.m_size; i++) {
+ if (m_data[i] != prefix.m_data[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline bool StringRefBase::endswith(StringRef suffix) const
+{
+ if (m_size < suffix.m_size) {
+ return false;
+ }
+ uint offset = m_size - suffix.m_size;
+ for (uint i = 0; i < suffix.m_size; i++) {
+ if (m_data[offset + i] != suffix.m_data[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace BLI
+
+#endif /* __BLI_STRING_REF_H__ */
diff --git a/source/blender/blenlib/BLI_system.h b/source/blender/blenlib/BLI_system.h
index f4c0399e959..8c0c9ad99bf 100644
--- a/source/blender/blenlib/BLI_system.h
+++ b/source/blender/blenlib/BLI_system.h
@@ -19,11 +19,16 @@
#include <stdio.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/** \file
* \ingroup bli
*/
int BLI_cpu_support_sse2(void);
+int BLI_cpu_support_sse41(void);
void BLI_system_backtrace(FILE *fp);
/* Get CPU brand, result is to be MEM_freeN()-ed. */
@@ -52,4 +57,8 @@ int BLI_system_memory_max_in_megabytes_int(void);
# define BLI_SYSTEM_PID_H <unistd.h>
#endif
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __BLI_SYSTEM_H__ */
diff --git a/source/blender/blenlib/BLI_temporary_allocator.h b/source/blender/blenlib/BLI_temporary_allocator.h
new file mode 100644
index 00000000000..b378e5869c0
--- /dev/null
+++ b/source/blender/blenlib/BLI_temporary_allocator.h
@@ -0,0 +1,64 @@
+/*
+ * 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 bli
+ *
+ * This allocation method assumes
+ * 1. The allocations are short-lived.
+ * 2. The total number of allocations is bound by a constant per thread.
+ *
+ * These two assumptions make it possible to cache and reuse relatively large buffers. They allow
+ * to hand out buffers that are much larger than the requested size, without the fear of running
+ * out of memory.
+ *
+ * The assumptions might feel a bit limiting at first, but hold true in many cases. For example,
+ * many algorithms need to store temporary data. With this allocator, the allocation can become
+ * very cheap for common cases.
+ *
+ * Many cpu-bound algorithms can benefit from being split up into several stages, whereby the
+ * output of one stage is written into an array that is read by the next stage. This makes them
+ * easier to debug, profile and optimize. Often a reason this is not done is that the memory
+ * allocation might be expensive. The goal of this allocator is to make this a non-issue, by
+ * reusing the same long buffers over and over again.
+ *
+ * All allocated buffers are 64 byte aligned, to make them as reusable as possible.
+ * If the requested size is too large, there is a fallback to normal allocation. The allocation
+ * overhead is probably very small in these cases anyway.
+ *
+ * The best way to use this allocator is to use one of the prepared containers like TemporaryVector
+ * and TemporaryArray.
+ */
+
+#ifndef __BLI_TEMPORARY_ALLOCATOR_H__
+#define __BLI_TEMPORARY_ALLOCATOR_H__
+
+#include "BLI_utildefines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BLI_TEMPORARY_BUFFER_ALIGNMENT 64
+
+void *BLI_temporary_allocate(uint size);
+void BLI_temporary_deallocate(void *buffer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BLI_TEMPORARY_ALLOCATOR_H__ */
diff --git a/source/blender/blenlib/BLI_temporary_allocator_cxx.h b/source/blender/blenlib/BLI_temporary_allocator_cxx.h
new file mode 100644
index 00000000000..06159f68059
--- /dev/null
+++ b/source/blender/blenlib/BLI_temporary_allocator_cxx.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#ifndef __BLI_TEMPORARY_ALLOCATOR_CXX_H__
+#define __BLI_TEMPORARY_ALLOCATOR_CXX_H__
+
+/** \file
+ * \ingroup bli
+ */
+
+#include "BLI_temporary_allocator.h"
+
+namespace BLI {
+
+template<typename T> class MutableArrayRef;
+
+template<typename T> MutableArrayRef<T> temporary_allocate_array(uint size)
+{
+ void *ptr = BLI_temporary_allocate(sizeof(T) * size);
+ return MutableArrayRef<T>((T *)ptr, size);
+}
+
+}; // namespace BLI
+
+#endif /* __BLI_TEMPORARY_ALLOCATOR_CXX_H__ */
diff --git a/source/blender/blenlib/BLI_timer.h b/source/blender/blenlib/BLI_timer.h
index dc47aefa090..56cafb1bd36 100644
--- a/source/blender/blenlib/BLI_timer.h
+++ b/source/blender/blenlib/BLI_timer.h
@@ -50,4 +50,8 @@ void BLI_timer_execute(void);
void BLI_timer_free(void);
+/* This function is to be called next to BKE_CB_EVT_LOAD_PRE, to make sure the module
+ * is properly configured for the new file. */
+void BLI_timer_on_file_load(void);
+
#endif /* __BLI_TIMER_H__ */
diff --git a/source/blender/blenlib/BLI_vector.h b/source/blender/blenlib/BLI_vector.h
new file mode 100644
index 00000000000..46c46a1440f
--- /dev/null
+++ b/source/blender/blenlib/BLI_vector.h
@@ -0,0 +1,607 @@
+/*
+ * 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.
+ */
+
+#ifndef __BLI_VECTOR_H__
+#define __BLI_VECTOR_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * This vector wraps a dynamically sized array of a specific type. It supports small object
+ * optimization. That means, when the vector only contains a few elements, no memory allocation is
+ * performed. Instead, those elements are stored directly in the vector.
+ */
+
+#include <algorithm>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <memory>
+
+#include "BLI_utildefines.h"
+#include "BLI_memory_utils_cxx.h"
+#include "BLI_array_ref.h"
+#include "BLI_listbase_wrapper.h"
+#include "BLI_math_base.h"
+#include "BLI_allocator.h"
+
+#include "MEM_guardedalloc.h"
+
+namespace BLI {
+
+template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Vector {
+ private:
+ T *m_begin;
+ T *m_end;
+ T *m_capacity_end;
+ Allocator m_allocator;
+ char m_small_buffer[sizeof(T) * N];
+
+#ifndef NDEBUG
+ /* Storing size in debug builds, because it makes debugging much easier sometimes. */
+ uint m_debug_size;
+# define UPDATE_VECTOR_SIZE(ptr) (ptr)->m_debug_size = (uint)((ptr)->m_end - (ptr)->m_begin)
+#else
+# define UPDATE_VECTOR_SIZE(ptr) ((void)0)
+#endif
+
+ template<typename OtherT, uint OtherN, typename OtherAllocator> friend class Vector;
+
+ public:
+ /**
+ * Create an empty vector.
+ * This does not do any memory allocation.
+ */
+ Vector()
+ {
+ m_begin = this->small_buffer();
+ m_end = m_begin;
+ m_capacity_end = m_begin + N;
+ UPDATE_VECTOR_SIZE(this);
+ }
+
+ /**
+ * Create a vector with a specific size.
+ * The elements will be default initialized.
+ */
+ explicit Vector(uint size) : Vector()
+ {
+ this->reserve(size);
+ this->increase_size_unchecked(size);
+ for (T *current = m_begin; current != m_end; current++) {
+ new (current) T();
+ }
+ }
+
+ /**
+ * Create a vector filled with a specific value.
+ */
+ Vector(uint size, const T &value) : Vector()
+ {
+ this->reserve(size);
+ this->increase_size_unchecked(size);
+ BLI::uninitialized_fill_n(m_begin, size, value);
+ }
+
+ /**
+ * Create a vector from an initializer list.
+ */
+ Vector(std::initializer_list<T> values) : Vector(ArrayRef<T>(values))
+ {
+ }
+
+ /**
+ * Create a vector from an array ref.
+ */
+ Vector(ArrayRef<T> values) : Vector()
+ {
+ this->reserve(values.size());
+ this->increase_size_unchecked(values.size());
+ BLI::uninitialized_copy_n(values.begin(), values.size(), this->begin());
+ }
+
+ /**
+ * Create a vector from any container. It must be possible to use the container in a range-for
+ * loop.
+ */
+ template<typename ContainerT> static Vector FromContainer(const ContainerT &container)
+ {
+ Vector vector;
+ for (const auto &value : container) {
+ vector.append(value);
+ }
+ return vector;
+ }
+
+ /**
+ * Create a vector from a ListBase.
+ */
+ Vector(ListBase &values, bool intrusive_next_and_prev_pointers) : Vector()
+ {
+ BLI_assert(intrusive_next_and_prev_pointers);
+ if (intrusive_next_and_prev_pointers) {
+ for (T value : IntrusiveListBaseWrapper<typename std::remove_pointer<T>::type>(values)) {
+ this->append(value);
+ }
+ }
+ }
+
+ /**
+ * Create a copy of another vector.
+ * The other vector will not be changed.
+ * If the other vector has less than N elements, no allocation will be made.
+ */
+ Vector(const Vector &other) : m_allocator(other.m_allocator)
+ {
+ this->init_copy_from_other_vector(other);
+ }
+
+ template<uint OtherN>
+ Vector(const Vector<T, OtherN, Allocator> &other) : m_allocator(other.m_allocator)
+ {
+ this->init_copy_from_other_vector(other);
+ }
+
+ /**
+ * Steal the elements from another vector.
+ * This does not do an allocation.
+ * The other vector will have zero elements afterwards.
+ */
+ template<uint OtherN>
+ Vector(Vector<T, OtherN, Allocator> &&other) noexcept : m_allocator(other.m_allocator)
+ {
+ uint size = other.size();
+
+ if (other.is_small()) {
+ if (size <= N) {
+ /* Copy between inline buffers. */
+ m_begin = this->small_buffer();
+ m_end = m_begin + size;
+ m_capacity_end = m_begin + N;
+ uninitialized_relocate_n(other.m_begin, size, m_begin);
+ }
+ else {
+ /* Copy from inline buffer to newly allocated buffer. */
+ uint capacity = size;
+ m_begin = (T *)m_allocator.allocate_aligned(
+ sizeof(T) * capacity, std::alignment_of<T>::value, __func__);
+ m_end = m_begin + size;
+ m_capacity_end = m_begin + capacity;
+ uninitialized_relocate_n(other.m_begin, size, m_begin);
+ }
+ }
+ else {
+ /* Steal the pointer. */
+ m_begin = other.m_begin;
+ m_end = other.m_end;
+ m_capacity_end = other.m_capacity_end;
+ }
+
+ other.m_begin = other.small_buffer();
+ other.m_end = other.m_begin;
+ other.m_capacity_end = other.m_begin + OtherN;
+ UPDATE_VECTOR_SIZE(this);
+ UPDATE_VECTOR_SIZE(&other);
+ }
+
+ ~Vector()
+ {
+ destruct_n(m_begin, this->size());
+ if (!this->is_small()) {
+ m_allocator.deallocate(m_begin);
+ }
+ }
+
+ operator ArrayRef<T>() const
+ {
+ return ArrayRef<T>(m_begin, this->size());
+ }
+
+ operator MutableArrayRef<T>()
+ {
+ return MutableArrayRef<T>(m_begin, this->size());
+ }
+
+ Vector &operator=(const Vector &other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+
+ this->~Vector();
+ new (this) Vector(other);
+
+ return *this;
+ }
+
+ Vector &operator=(Vector &&other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+
+ this->~Vector();
+ new (this) Vector(std::move(other));
+
+ return *this;
+ }
+
+ /**
+ * Make sure that enough memory is allocated to hold size elements.
+ * This won't necessarily make an allocation when size is small.
+ * The actual size of the vector does not change.
+ */
+ void reserve(uint size)
+ {
+ this->grow(size);
+ }
+
+ /**
+ * Afterwards the vector has 0 elements, but will still have
+ * memory to be refilled again.
+ */
+ void clear()
+ {
+ destruct_n(m_begin, this->size());
+ m_end = m_begin;
+ UPDATE_VECTOR_SIZE(this);
+ }
+
+ /**
+ * Afterwards the vector has 0 elements and any allocated memory
+ * will be freed.
+ */
+ void clear_and_make_small()
+ {
+ destruct_n(m_begin, this->size());
+ if (!this->is_small()) {
+ m_allocator.deallocate(m_begin);
+ }
+
+ m_begin = this->small_buffer();
+ m_end = m_begin;
+ m_capacity_end = m_begin + N;
+ UPDATE_VECTOR_SIZE(this);
+ }
+
+ /**
+ * Insert a new element at the end of the vector.
+ * This might cause a reallocation with the capacity is exceeded.
+ */
+ void append(const T &value)
+ {
+ this->ensure_space_for_one();
+ this->append_unchecked(value);
+ }
+
+ void append(T &&value)
+ {
+ this->ensure_space_for_one();
+ this->append_unchecked(std::move(value));
+ }
+
+ void append_unchecked(const T &value)
+ {
+ BLI_assert(m_end < m_capacity_end);
+ new (m_end) T(value);
+ m_end++;
+ UPDATE_VECTOR_SIZE(this);
+ }
+
+ void append_unchecked(T &&value)
+ {
+ BLI_assert(m_end < m_capacity_end);
+ new (m_end) T(std::move(value));
+ m_end++;
+ UPDATE_VECTOR_SIZE(this);
+ }
+
+ /**
+ * Insert the same element n times at the end of the vector.
+ * This might result in a reallocation internally.
+ */
+ void append_n_times(const T &value, uint n)
+ {
+ this->reserve(this->size() + n);
+ BLI::uninitialized_fill_n(m_end, n, value);
+ this->increase_size_unchecked(n);
+ }
+
+ void increase_size_unchecked(uint n)
+ {
+ BLI_assert(m_end + n <= m_capacity_end);
+ m_end += n;
+ UPDATE_VECTOR_SIZE(this);
+ }
+
+ /**
+ * Copy the elements of another array to the end of this vector.
+ */
+ void extend(ArrayRef<T> array)
+ {
+ this->extend(array.begin(), array.size());
+ }
+
+ void extend(const T *start, uint amount)
+ {
+ this->reserve(this->size() + amount);
+ this->extend_unchecked(start, amount);
+ }
+
+ void extend_unchecked(ArrayRef<T> array)
+ {
+ this->extend_unchecked(array.begin(), array.size());
+ }
+
+ void extend_unchecked(const T *start, uint amount)
+ {
+ BLI_assert(m_begin + amount <= m_capacity_end);
+ BLI::uninitialized_copy_n(start, amount, m_end);
+ m_end += amount;
+ UPDATE_VECTOR_SIZE(this);
+ }
+
+ /**
+ * Return a reference to the last element in the vector.
+ * This will assert when the vector is empty.
+ */
+ const T &last() const
+ {
+ BLI_assert(this->size() > 0);
+ return *(m_end - 1);
+ }
+
+ T &last()
+ {
+ BLI_assert(this->size() > 0);
+ return *(m_end - 1);
+ }
+
+ /**
+ * Replace every element with a new value.
+ */
+ void fill(const T &value)
+ {
+ std::fill(m_begin, m_end, value);
+ }
+
+ void fill_indices(ArrayRef<uint> indices, const T &value)
+ {
+ MutableArrayRef<T>(*this).fill_indices(indices, value);
+ }
+
+ /**
+ * Return how many values are currently stored in the vector.
+ */
+ uint size() const
+ {
+ BLI_assert(m_debug_size == (uint)(m_end - m_begin));
+ return (uint)(m_end - m_begin);
+ }
+
+ /**
+ * Returns true when the vector contains no elements, otherwise false.
+ */
+ bool empty() const
+ {
+ return m_begin == m_end;
+ }
+
+ /**
+ * Deconstructs the last element and decreases the size by one.
+ * This will assert when the vector is empty.
+ */
+ void remove_last()
+ {
+ BLI_assert(!this->empty());
+ m_end--;
+ destruct(m_end);
+ UPDATE_VECTOR_SIZE(this);
+ }
+
+ /**
+ * Remove the last element from the vector and return it.
+ */
+ T pop_last()
+ {
+ BLI_assert(!this->empty());
+ m_end--;
+ T value = std::move(*m_end);
+ destruct(m_end);
+ UPDATE_VECTOR_SIZE(this);
+ return value;
+ }
+
+ /**
+ * Delete any element in the vector.
+ * The empty space will be filled by the previously last element.
+ */
+ void remove_and_reorder(uint index)
+ {
+ BLI_assert(index < this->size());
+ T *element_to_remove = m_begin + index;
+ m_end--;
+ if (element_to_remove < m_end) {
+ *element_to_remove = std::move(*m_end);
+ }
+ destruct(m_end);
+ UPDATE_VECTOR_SIZE(this);
+ }
+
+ /**
+ * Do a linear search to find the value in the vector.
+ * When found, return the first index, otherwise return -1.
+ */
+ int index(const T &value) const
+ {
+ for (T *current = m_begin; current != m_end; current++) {
+ if (*current == value) {
+ return current - m_begin;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Do a linear search to see of the value is in the vector.
+ * Return true when it exists, otherwise false.
+ */
+ bool contains(const T &value) const
+ {
+ return this->index(value) != -1;
+ }
+
+ /**
+ * Compare vectors element-wise.
+ * Return true when they have the same length and all elements
+ * compare equal, otherwise false.
+ */
+ static bool all_equal(const Vector &a, const Vector &b)
+ {
+ if (a.size() != b.size()) {
+ return false;
+ }
+ for (uint i = 0; i < a.size(); i++) {
+ if (a[i] != b[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ const T &operator[](uint index) const
+ {
+ BLI_assert(index < this->size());
+ return m_begin[index];
+ }
+
+ T &operator[](uint index)
+ {
+ BLI_assert(index < this->size());
+ return m_begin[index];
+ }
+
+ T *begin()
+ {
+ return m_begin;
+ }
+ T *end()
+ {
+ return m_end;
+ }
+
+ const T *begin() const
+ {
+ return m_begin;
+ }
+ const T *end() const
+ {
+ return m_end;
+ }
+
+ /**
+ * Get the current capacity of the vector.
+ */
+ uint capacity() const
+ {
+ return (uint)(m_capacity_end - m_begin);
+ }
+
+ void print_stats() const
+ {
+ std::cout << "Small Vector at " << (void *)this << ":" << std::endl;
+ std::cout << " Elements: " << this->size() << std::endl;
+ std::cout << " Capacity: " << (m_capacity_end - m_begin) << std::endl;
+ std::cout << " Small Elements: " << N << " Size on Stack: " << sizeof(*this) << std::endl;
+ }
+
+ private:
+ T *small_buffer() const
+ {
+ return (T *)m_small_buffer;
+ }
+
+ bool is_small() const
+ {
+ return m_begin == this->small_buffer();
+ }
+
+ void ensure_space_for_one()
+ {
+ if (UNLIKELY(m_end >= m_capacity_end)) {
+ this->grow(std::max(this->size() * 2, (uint)1));
+ }
+ }
+
+ BLI_NOINLINE void grow(uint min_capacity)
+ {
+ if (this->capacity() >= min_capacity) {
+ return;
+ }
+
+ /* Round up to the next power of two. Otherwise consecutive calls to grow can cause a
+ * reallocation every time even though the min_capacity only increments. */
+ min_capacity = power_of_2_max_u(min_capacity);
+ uint size = this->size();
+
+ T *new_array = (T *)m_allocator.allocate_aligned(
+ min_capacity * (uint)sizeof(T), std::alignment_of<T>::value, __func__);
+ uninitialized_relocate_n(m_begin, size, new_array);
+
+ if (!this->is_small()) {
+ m_allocator.deallocate(m_begin);
+ }
+
+ m_begin = new_array;
+ m_end = m_begin + size;
+ m_capacity_end = m_begin + min_capacity;
+ }
+
+ /**
+ * Initialize all properties, except for m_allocator, which has to be initialized beforehand.
+ */
+ template<uint OtherN> void init_copy_from_other_vector(const Vector<T, OtherN, Allocator> &other)
+ {
+ m_allocator = other.m_allocator;
+
+ uint size = other.size();
+ uint capacity = size;
+
+ if (size <= N) {
+ m_begin = this->small_buffer();
+ capacity = N;
+ }
+ else {
+ m_begin = (T *)m_allocator.allocate_aligned(
+ sizeof(T) * size, std::alignment_of<T>::value, __func__);
+ capacity = size;
+ }
+
+ m_end = m_begin + size;
+ m_capacity_end = m_begin + capacity;
+
+ uninitialized_copy(other.begin(), other.end(), m_begin);
+ UPDATE_VECTOR_SIZE(this);
+ }
+};
+
+#undef UPDATE_VECTOR_SIZE
+
+template<typename T, uint N = 4> using TemporaryVector = Vector<T, N, TemporaryAllocator>;
+
+} /* namespace BLI */
+
+#endif /* __BLI_VECTOR_H__ */
diff --git a/source/blender/blenlib/BLI_vector_set.h b/source/blender/blenlib/BLI_vector_set.h
new file mode 100644
index 00000000000..fb21f7ed987
--- /dev/null
+++ b/source/blender/blenlib/BLI_vector_set.h
@@ -0,0 +1,425 @@
+/*
+ * 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.
+ */
+
+#ifndef __BLI_VECTOR_SET_H__
+#define __BLI_VECTOR_SET_H__
+
+/** \file
+ * \ingroup bli
+ *
+ * A VectorSet is a set built on top of a vector. The elements are stored in a continuous array,
+ * but every element exists at most once. The insertion order is maintained, as long as there are
+ * no deletes. The expected time to check if a value is in the VectorSet is O(1).
+ */
+
+#include "BLI_hash_cxx.h"
+#include "BLI_open_addressing.h"
+#include "BLI_vector.h"
+
+namespace BLI {
+
+// clang-format off
+
+#define ITER_SLOTS_BEGIN(VALUE, ARRAY, OPTIONAL_CONST, R_SLOT) \
+ uint32_t hash = DefaultHash<T>{}(VALUE); \
+ uint32_t perturb = hash; \
+ while (true) { \
+ for (uint i = 0; i < 4; i++) {\
+ uint32_t slot_index = (hash + i) & ARRAY.slot_mask(); \
+ OPTIONAL_CONST Slot &R_SLOT = ARRAY.item(slot_index);
+
+#define ITER_SLOTS_END \
+ } \
+ perturb >>= 5; \
+ hash = hash * 5 + 1 + perturb; \
+ } ((void)0)
+
+// clang-format on
+
+template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
+ private:
+ static constexpr int32_t IS_EMPTY = -1;
+ static constexpr int32_t IS_DUMMY = -2;
+
+ class Slot {
+ private:
+ int32_t m_value = IS_EMPTY;
+
+ public:
+ static constexpr uint slots_per_item = 1;
+
+ bool is_set() const
+ {
+ return m_value >= 0;
+ }
+
+ bool is_empty() const
+ {
+ return m_value == IS_EMPTY;
+ }
+
+ bool is_dummy() const
+ {
+ return m_value == IS_DUMMY;
+ }
+
+ bool has_value(const T &value, const Vector<T> &elements) const
+ {
+ return this->is_set() && elements[this->index()] == value;
+ }
+
+ bool has_index(uint index) const
+ {
+ return m_value == (int32_t)index;
+ }
+
+ uint index() const
+ {
+ BLI_assert(this->is_set());
+ return (uint)m_value;
+ }
+
+ int32_t &index_ref()
+ {
+ return m_value;
+ }
+
+ void set_index(uint index)
+ {
+ BLI_assert(!this->is_set());
+ m_value = (int32_t)index;
+ }
+
+ void set_dummy()
+ {
+ BLI_assert(this->is_set());
+ m_value = IS_DUMMY;
+ }
+ };
+
+ using ArrayType = OpenAddressingArray<Slot, 4, Allocator>;
+ ArrayType m_array;
+ Vector<T, 4, Allocator> m_elements;
+
+ public:
+ VectorSet()
+ {
+ BLI_assert(m_array.slots_usable() <= m_elements.capacity());
+ }
+
+ VectorSet(ArrayRef<T> values) : VectorSet()
+ {
+ this->add_multiple(values);
+ }
+
+ VectorSet(const std::initializer_list<T> &values) : VectorSet()
+ {
+ this->add_multiple(values);
+ }
+
+ VectorSet(const Vector<T> &values) : VectorSet()
+ {
+ this->add_multiple(values);
+ }
+
+ /**
+ * Allocate memory such that at least min_usable_slots can be added without having to grow again.
+ */
+ void reserve(uint min_usable_slots)
+ {
+ if (m_array.slots_usable() < min_usable_slots) {
+ this->grow(min_usable_slots);
+ }
+ }
+
+ /**
+ * Add a new element. The method assumes that the value did not exist before.
+ */
+ void add_new(const T &value)
+ {
+ this->add_new__impl(value);
+ }
+ void add_new(T &&value)
+ {
+ this->add_new__impl(std::move(value));
+ }
+
+ /**
+ * Add a new element if it does not exist yet. Does not add the value again if it exists already.
+ */
+ bool add(const T &value)
+ {
+ return this->add__impl(value);
+ }
+ bool add(T &&value)
+ {
+ return this->add__impl(std::move(value));
+ }
+
+ /**
+ * Add multiple values. Duplicates will not be inserted.
+ */
+ void add_multiple(ArrayRef<T> values)
+ {
+ for (const T &value : values) {
+ this->add(value);
+ }
+ }
+
+ /**
+ * Returns true when the value is in the set-vector, otherwise false.
+ */
+ bool contains(const T &value) const
+ {
+ ITER_SLOTS_BEGIN (value, m_array, const, slot) {
+ if (slot.is_empty()) {
+ return false;
+ }
+ else if (slot.has_value(value, m_elements)) {
+ return true;
+ }
+ }
+ ITER_SLOTS_END;
+ }
+
+ /**
+ * Remove a value from the set-vector. The method assumes that the value exists.
+ */
+ void remove(const T &value)
+ {
+ BLI_assert(this->contains(value));
+ ITER_SLOTS_BEGIN (value, m_array, , slot) {
+ if (slot.has_value(value, m_elements)) {
+ uint old_index = m_elements.size() - 1;
+ uint new_index = slot.index();
+
+ m_elements.remove_and_reorder(new_index);
+ slot.set_dummy();
+ m_array.update__set_to_dummy();
+
+ if (old_index != new_index) {
+ T &moved_value = m_elements[new_index];
+ this->update_slot_index(moved_value, old_index, new_index);
+ }
+ return;
+ }
+ }
+ ITER_SLOTS_END;
+ }
+
+ /**
+ * Get and remove the last element of the vector.
+ */
+ T pop()
+ {
+ BLI_assert(this->size() > 0);
+ T value = m_elements.pop_last();
+ uint old_index = m_elements.size();
+
+ ITER_SLOTS_BEGIN (value, m_array, , slot) {
+ if (slot.has_index(old_index)) {
+ slot.set_dummy();
+ m_array.update__set_to_dummy();
+ return value;
+ }
+ }
+ ITER_SLOTS_END;
+ }
+
+ /**
+ * Get the index of the value in the vector. It is assumed that the value is in the vector.
+ */
+ uint index(const T &value) const
+ {
+ BLI_assert(this->contains(value));
+ ITER_SLOTS_BEGIN (value, m_array, const, slot) {
+ if (slot.has_value(value, m_elements)) {
+ return slot.index();
+ }
+ }
+ ITER_SLOTS_END;
+ }
+
+ /**
+ * Get the index of the value in the vector. If it does not exist return -1.
+ */
+ int index_try(const T &value) const
+ {
+ ITER_SLOTS_BEGIN (value, m_array, const, slot) {
+ if (slot.has_value(value, m_elements)) {
+ return slot.index();
+ }
+ else if (slot.is_empty()) {
+ return -1;
+ }
+ }
+ ITER_SLOTS_END;
+ }
+
+ /**
+ * Get the number of elements in the set-vector.
+ */
+ uint size() const
+ {
+ return m_array.slots_set();
+ }
+
+ const T *begin() const
+ {
+ return m_elements.begin();
+ }
+
+ const T *end() const
+ {
+ return m_elements.end();
+ }
+
+ const T &operator[](uint index) const
+ {
+ return m_elements[index];
+ }
+
+ operator ArrayRef<T>() const
+ {
+ return m_elements;
+ }
+
+ operator MutableArrayRef<T>()
+ {
+ return m_elements;
+ }
+
+ void print_stats() const
+ {
+ std::cout << "VectorSet at " << (void *)this << ":\n";
+ std::cout << " Size: " << this->size() << "\n";
+ std::cout << " Usable Slots: " << m_array.slots_usable() << "\n";
+ std::cout << " Total Slots: " << m_array.slots_total() << "\n";
+ std::cout << " Average Collisions: " << this->compute_average_collisions() << "\n";
+ }
+
+ private:
+ void update_slot_index(T &value, uint old_index, uint new_index)
+ {
+ ITER_SLOTS_BEGIN (value, m_array, , slot) {
+ int32_t &stored_index = slot.index_ref();
+ if (stored_index == old_index) {
+ stored_index = new_index;
+ return;
+ }
+ }
+ ITER_SLOTS_END;
+ }
+
+ template<typename ForwardT> void add_new_in_slot(Slot &slot, ForwardT &&value)
+ {
+ uint index = m_elements.size();
+ slot.set_index(index);
+ m_elements.append_unchecked(std::forward<ForwardT>(value));
+ m_array.update__empty_to_set();
+ }
+
+ void ensure_can_add()
+ {
+ if (UNLIKELY(m_array.should_grow())) {
+ this->grow(this->size() + 1);
+ }
+ }
+
+ BLI_NOINLINE void grow(uint min_usable_slots)
+ {
+ ArrayType new_array = m_array.init_reserved(min_usable_slots);
+
+ for (uint i = 0; i < m_elements.size(); i++) {
+ this->add_after_grow(i, new_array);
+ }
+
+ m_array = std::move(new_array);
+ m_elements.reserve(m_array.slots_usable());
+ }
+
+ void add_after_grow(uint index, ArrayType &new_array)
+ {
+ const T &value = m_elements[index];
+ ITER_SLOTS_BEGIN (value, new_array, , slot) {
+ if (slot.is_empty()) {
+ slot.set_index(index);
+ return;
+ }
+ }
+ ITER_SLOTS_END;
+ }
+
+ float compute_average_collisions() const
+ {
+ if (m_elements.size() == 0) {
+ return 0.0f;
+ }
+
+ uint collisions_sum = 0;
+ for (const T &value : m_elements) {
+ collisions_sum += this->count_collisions(value);
+ }
+ return (float)collisions_sum / (float)m_elements.size();
+ }
+
+ uint count_collisions(const T &value) const
+ {
+ uint collisions = 0;
+ ITER_SLOTS_BEGIN (value, m_array, const, slot) {
+ if (slot.is_empty() || slot.has_value(value, m_elements)) {
+ return collisions;
+ }
+ collisions++;
+ }
+ ITER_SLOTS_END;
+ }
+
+ template<typename ForwardT> void add_new__impl(ForwardT &&value)
+ {
+ BLI_assert(!this->contains(value));
+ this->ensure_can_add();
+ ITER_SLOTS_BEGIN (value, m_array, , slot) {
+ if (slot.is_empty()) {
+ this->add_new_in_slot(slot, std::forward<ForwardT>(value));
+ return;
+ }
+ }
+ ITER_SLOTS_END;
+ }
+
+ template<typename ForwardT> bool add__impl(ForwardT &&value)
+ {
+ this->ensure_can_add();
+ ITER_SLOTS_BEGIN (value, m_array, , slot) {
+ if (slot.is_empty()) {
+ this->add_new_in_slot(slot, std::forward<ForwardT>(value));
+ return true;
+ }
+ else if (slot.has_value(value, m_elements)) {
+ return false;
+ }
+ }
+ ITER_SLOTS_END;
+ }
+};
+
+#undef ITER_SLOTS_BEGIN
+#undef ITER_SLOTS_END
+
+} // namespace BLI
+
+#endif /* __BLI_VECTOR_SET_H__ */
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 7f6e9d49b17..f3740b5d39f 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -44,6 +44,7 @@ set(SRC
intern/BLI_ghash_utils.c
intern/BLI_heap.c
intern/BLI_heap_simple.c
+ intern/BLI_index_range.cc
intern/BLI_kdopbvh.c
intern/BLI_linklist.c
intern/BLI_linklist_lockfree.c
@@ -51,6 +52,7 @@ set(SRC
intern/BLI_memblock.c
intern/BLI_memiter.c
intern/BLI_mempool.c
+ intern/BLI_temporary_allocator.cc
intern/BLI_timer.c
intern/DLRB_tree.c
intern/array_store.c
@@ -61,7 +63,6 @@ set(SRC
intern/bitmap_draw_2d.c
intern/boxpack_2d.c
intern/buffer.c
- intern/callbacks.c
intern/convexhull_2d.c
intern/delaunay_2d.c
intern/dynlib.c
@@ -132,9 +133,14 @@ set(SRC
intern/kdtree_impl.h
intern/list_sort_impl.h
+
+
BLI_alloca.h
+ BLI_allocator.h
BLI_args.h
BLI_array.h
+ BLI_array_cxx.h
+ BLI_array_ref.h
BLI_array_store.h
BLI_array_store_utils.h
BLI_array_utils.h
@@ -145,7 +151,6 @@ set(SRC
BLI_blenlib.h
BLI_boxpack_2d.h
BLI_buffer.h
- BLI_callbacks.h
BLI_compiler_attrs.h
BLI_compiler_compat.h
BLI_compiler_typecheck.h
@@ -167,11 +172,13 @@ set(SRC
BLI_ghash.h
BLI_gsqueue.h
BLI_hash.h
+ BLI_hash_cxx.h
BLI_hash_md5.h
BLI_hash_mm2a.h
BLI_hash_mm3.h
BLI_heap.h
BLI_heap_simple.h
+ BLI_index_range.h
BLI_iterator.h
BLI_jitter_2d.h
BLI_kdopbvh.h
@@ -183,6 +190,8 @@ set(SRC
BLI_linklist_lockfree.h
BLI_linklist_stack.h
BLI_listbase.h
+ BLI_listbase_wrapper.h
+ BLI_map.h
BLI_math.h
BLI_math_base.h
BLI_math_bits.h
@@ -200,8 +209,10 @@ set(SRC
BLI_memblock.h
BLI_memiter.h
BLI_memory_utils.h
+ BLI_memory_utils_cxx.h
BLI_mempool.h
BLI_noise.h
+ BLI_open_addressing.h
BLI_path_util.h
BLI_polyfill_2d.h
BLI_polyfill_2d_beautify.h
@@ -209,18 +220,24 @@ set(SRC
BLI_rand.h
BLI_rect.h
BLI_scanfill.h
+ BLI_set.h
BLI_smallhash.h
BLI_sort.h
BLI_sort_utils.h
BLI_stack.h
+ BLI_stack_cxx.h
BLI_strict_flags.h
BLI_string.h
BLI_string_cursor_utf8.h
+ BLI_string_map.h
+ BLI_string_ref.h
BLI_string_utf8.h
BLI_string_utils.h
BLI_sys_types.h
BLI_system.h
BLI_task.h
+ BLI_temporary_allocator.h
+ BLI_temporary_allocator_cxx.h
BLI_threads.h
BLI_timecode.h
BLI_timer.h
@@ -229,6 +246,8 @@ set(SRC
BLI_utildefines_stack.h
BLI_utildefines_variadic.h
BLI_uvproject.h
+ BLI_vector.h
+ BLI_vector_set.h
BLI_vfontdata.h
BLI_voronoi_2d.h
BLI_voxel.h
diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c
index 91f16ca9b7b..a3b745fd63e 100644
--- a/source/blender/blenlib/intern/BLI_filelist.c
+++ b/source/blender/blenlib/intern/BLI_filelist.c
@@ -107,7 +107,7 @@ static int bli_compare(struct direntry *entry1, struct direntry *entry2)
return 1;
}
- return (BLI_natstrcmp(entry1->relname, entry2->relname));
+ return (BLI_strcasecmp_natural(entry1->relname, entry2->relname));
}
struct BuildDirCtx {
@@ -261,36 +261,21 @@ unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_
*/
void BLI_filelist_entry_size_to_string(const struct stat *st,
const uint64_t sz,
- const bool compact,
+ /* Used to change MB -> M, etc. - is that really useful? */
+ const bool UNUSED(compact),
char r_size[FILELIST_DIRENTRY_SIZE_LEN])
{
- double size;
- const char *fmt;
- const char *units[] = {"KiB", "MiB", "GiB", "TiB", NULL};
- const char *units_compact[] = {"K", "M", "G", "T", NULL};
- const char *unit = "B";
-
/*
* Seems st_size is signed 32-bit value in *nix and Windows. This
* will buy us some time until files get bigger than 4GB or until
* everyone starts using __USE_FILE_OFFSET64 or equivalent.
*/
- size = (double)(st ? st->st_size : sz);
-
- if (size > 1024.0) {
- const char **u;
- for (u = compact ? units_compact : units, size /= 1024.0; size > 1024.0 && *(u + 1);
- u++, size /= 1024.0) {
- /* pass */
- }
- fmt = size > 100.0 ? "%.0f %s" : (size > 10.0 ? "%.1f %s" : "%.2f %s");
- unit = *u;
- }
- else {
- fmt = "%.0f %s";
- }
-
- BLI_snprintf(r_size, sizeof(*r_size) * FILELIST_DIRENTRY_SIZE_LEN, fmt, size, unit);
+ double size = (double)(st ? st->st_size : sz);
+#ifdef WIN32
+ BLI_str_format_byte_unit(r_size, size, false);
+#else
+ BLI_str_format_byte_unit(r_size, size, true);
+#endif
}
/**
@@ -366,14 +351,45 @@ void BLI_filelist_entry_owner_to_string(const struct stat *st,
/**
* Convert given entry's time into human-readable strings.
+ *
+ * \param r_is_today: optional, returns true if the date matches today's.
+ * \param r_is_yesterday: optional, returns true if the date matches yesterday's.
*/
void BLI_filelist_entry_datetime_to_string(const struct stat *st,
const int64_t ts,
const bool compact,
char r_time[FILELIST_DIRENTRY_TIME_LEN],
- char r_date[FILELIST_DIRENTRY_DATE_LEN])
+ char r_date[FILELIST_DIRENTRY_DATE_LEN],
+ bool *r_is_today,
+ bool *r_is_yesterday)
{
- time_t ts_mtime = ts;
+ int today_year = 0;
+ int today_yday = 0;
+ int yesterday_year = 0;
+ int yesterday_yday = 0;
+
+ if (r_is_today || r_is_yesterday) {
+ /* Localtime() has only one buffer so need to get data out before called again. */
+ const time_t ts_now = time(NULL);
+ struct tm *today = localtime(&ts_now);
+
+ today_year = today->tm_year;
+ today_yday = today->tm_yday;
+ /* Handle a yesterday that spans a year */
+ today->tm_mday--;
+ mktime(today);
+ yesterday_year = today->tm_year;
+ yesterday_yday = today->tm_yday;
+
+ if (r_is_today) {
+ *r_is_today = false;
+ }
+ if (r_is_yesterday) {
+ *r_is_yesterday = false;
+ }
+ }
+
+ const time_t ts_mtime = ts;
const struct tm *tm = localtime(st ? &st->st_mtime : &ts_mtime);
const time_t zero = 0;
@@ -385,12 +401,20 @@ void BLI_filelist_entry_datetime_to_string(const struct stat *st,
if (r_time) {
strftime(r_time, sizeof(*r_time) * FILELIST_DIRENTRY_TIME_LEN, "%H:%M", tm);
}
+
if (r_date) {
strftime(r_date,
sizeof(*r_date) * FILELIST_DIRENTRY_DATE_LEN,
- compact ? "%d/%m/%y" : "%d-%b-%y",
+ compact ? "%d/%m/%y" : "%d %b %Y",
tm);
}
+
+ if (r_is_today && (tm->tm_year == today_year) && (tm->tm_yday == today_yday)) {
+ *r_is_today = true;
+ }
+ else if (r_is_yesterday && (tm->tm_year == yesterday_year) && (tm->tm_yday == yesterday_yday)) {
+ *r_is_yesterday = true;
+ }
}
/**
@@ -417,7 +441,7 @@ void BLI_filelist_duplicate(struct direntry **dest_filelist,
unsigned int i;
*dest_filelist = MEM_mallocN(sizeof(**dest_filelist) * (size_t)(nrentries), __func__);
- for (i = 0; i < nrentries; ++i) {
+ for (i = 0; i < nrentries; i++) {
struct direntry *const src = &src_filelist[i];
struct direntry *dst = &(*dest_filelist)[i];
BLI_filelist_entry_duplicate(dst, src);
@@ -443,7 +467,7 @@ void BLI_filelist_entry_free(struct direntry *entry)
void BLI_filelist_free(struct direntry *filelist, const unsigned int nrentries)
{
unsigned int i;
- for (i = 0; i < nrentries; ++i) {
+ for (i = 0; i < nrentries; i++) {
BLI_filelist_entry_free(&filelist[i]);
}
diff --git a/source/blender/blenlib/intern/BLI_index_range.cc b/source/blender/blenlib/intern/BLI_index_range.cc
new file mode 100644
index 00000000000..fde4dcf6d41
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_index_range.cc
@@ -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.
+ */
+
+#include <atomic>
+#include <mutex>
+
+#include "BLI_index_range.h"
+#include "BLI_array_ref.h"
+#include "BLI_array_cxx.h"
+#include "BLI_vector.h"
+
+namespace BLI {
+
+static Vector<Array<uint, RawAllocator>, 1, RawAllocator> arrays;
+static uint current_array_size = 0;
+static uint *current_array = nullptr;
+static std::mutex current_array_mutex;
+
+ArrayRef<uint> IndexRange::as_array_ref() const
+{
+ uint min_required_size = m_start + m_size;
+
+ if (min_required_size <= current_array_size) {
+ return ArrayRef<uint>(current_array + m_start, m_size);
+ }
+
+ std::lock_guard<std::mutex> lock(current_array_mutex);
+
+ if (min_required_size <= current_array_size) {
+ return ArrayRef<uint>(current_array + m_start, m_size);
+ }
+
+ uint new_size = std::max<uint>(1000, power_of_2_max_u(min_required_size));
+ Array<uint, RawAllocator> new_array(new_size);
+ for (uint i = 0; i < new_size; i++) {
+ new_array[i] = i;
+ }
+ arrays.append(std::move(new_array));
+
+ current_array = arrays.last().begin();
+ std::atomic_thread_fence(std::memory_order_seq_cst);
+ current_array_size = new_size;
+
+ return ArrayRef<uint>(current_array + m_start, m_size);
+}
+
+} // namespace BLI
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index 0e93fd8e13b..ae862c5ece5 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -1184,6 +1184,56 @@ static void tree_overlap_traverse_cb(BVHOverlapData_Thread *data_thread,
}
/**
+ * a version of #tree_overlap_traverse_cb that that break on first true return.
+ */
+static bool tree_overlap_traverse_first_cb(BVHOverlapData_Thread *data_thread,
+ const BVHNode *node1,
+ const BVHNode *node2)
+{
+ BVHOverlapData_Shared *data = data_thread->shared;
+ int j;
+
+ if (tree_overlap_test(node1, node2, data->start_axis, data->stop_axis)) {
+ /* check if node1 is a leaf */
+ if (!node1->totnode) {
+ /* check if node2 is a leaf */
+ if (!node2->totnode) {
+ BVHTreeOverlap *overlap;
+
+ if (UNLIKELY(node1 == node2)) {
+ return false;
+ }
+
+ /* only difference to tree_overlap_traverse! */
+ if (!data->callback ||
+ data->callback(data->userdata, node1->index, node2->index, data_thread->thread)) {
+ /* both leafs, insert overlap! */
+ if (data_thread->overlap) {
+ overlap = BLI_stack_push_r(data_thread->overlap);
+ overlap->indexA = node1->index;
+ overlap->indexB = node2->index;
+ }
+ return true;
+ }
+ }
+ else {
+ for (j = 0; j < node2->totnode; j++) {
+ if (tree_overlap_traverse_first_cb(data_thread, node1, node2->children[j])) {
+ return true;
+ }
+ }
+ }
+ }
+ else {
+ for (j = 0; j < node1->totnode; j++) {
+ tree_overlap_traverse_first_cb(data_thread, node1->children[j], node2);
+ }
+ }
+ }
+ return false;
+}
+
+/**
* Use to check the total number of threads #BLI_bvhtree_overlap will use.
*
* \warning Must be the first tree passed to #BLI_bvhtree_overlap!
@@ -1212,14 +1262,35 @@ static void bvhtree_overlap_task_cb(void *__restrict userdata,
}
}
-BVHTreeOverlap *BLI_bvhtree_overlap(
+static void bvhtree_overlap_first_task_cb(void *__restrict userdata,
+ const int j,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ BVHOverlapData_Thread *data = &((BVHOverlapData_Thread *)userdata)[j];
+ BVHOverlapData_Shared *data_shared = data->shared;
+
+ tree_overlap_traverse_first_cb(
+ data,
+ data_shared->tree1->nodes[data_shared->tree1->totleaf]->children[j],
+ data_shared->tree2->nodes[data_shared->tree2->totleaf]);
+}
+
+BVHTreeOverlap *BLI_bvhtree_overlap_ex(
const BVHTree *tree1,
const BVHTree *tree2,
uint *r_overlap_tot,
/* optional callback to test the overlap before adding (must be thread-safe!) */
BVHTree_OverlapCallback callback,
- void *userdata)
+ void *userdata,
+ int flag)
{
+ bool use_threading = (flag & BVH_OVERLAP_USE_THREADING) != 0;
+ bool overlap_pairs = (flag & BVH_OVERLAP_RETURN_PAIRS) != 0;
+ bool break_on_first = (flag & BVH_OVERLAP_BREAK_ON_FIRST) != 0;
+
+ /* `RETURN_PAIRS` was not implemented without `BREAK_ON_FIRST`. */
+ BLI_assert(overlap_pairs || break_on_first);
+
const int thread_num = BLI_bvhtree_overlap_thread_num(tree1);
int j;
size_t total = 0;
@@ -1256,7 +1327,7 @@ BVHTreeOverlap *BLI_bvhtree_overlap(
for (j = 0; j < thread_num; j++) {
/* init BVHOverlapData_Thread */
data[j].shared = &data_shared;
- data[j].overlap = BLI_stack_new(sizeof(BVHTreeOverlap), __func__);
+ data[j].overlap = overlap_pairs ? BLI_stack_new(sizeof(BVHTreeOverlap), __func__) : NULL;
/* for callback */
data[j].thread = j;
@@ -1264,26 +1335,48 @@ BVHTreeOverlap *BLI_bvhtree_overlap(
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (tree1->totleaf > KDOPBVH_THREAD_LEAF_THRESHOLD);
- BLI_task_parallel_range(0, thread_num, data, bvhtree_overlap_task_cb, &settings);
+ settings.use_threading = use_threading && (tree1->totleaf > KDOPBVH_THREAD_LEAF_THRESHOLD);
+ BLI_task_parallel_range(0,
+ thread_num,
+ data,
+ break_on_first ? bvhtree_overlap_first_task_cb : bvhtree_overlap_task_cb,
+ &settings);
- for (j = 0; j < thread_num; j++) {
- total += BLI_stack_count(data[j].overlap);
- }
+ if (overlap_pairs) {
+ for (j = 0; j < thread_num; j++) {
+ total += BLI_stack_count(data[j].overlap);
+ }
- to = overlap = MEM_mallocN(sizeof(BVHTreeOverlap) * total, "BVHTreeOverlap");
+ to = overlap = MEM_mallocN(sizeof(BVHTreeOverlap) * total, "BVHTreeOverlap");
- for (j = 0; j < thread_num; j++) {
- uint count = (uint)BLI_stack_count(data[j].overlap);
- BLI_stack_pop_n(data[j].overlap, to, count);
- BLI_stack_free(data[j].overlap);
- to += count;
+ for (j = 0; j < thread_num; j++) {
+ uint count = (uint)BLI_stack_count(data[j].overlap);
+ BLI_stack_pop_n(data[j].overlap, to, count);
+ BLI_stack_free(data[j].overlap);
+ to += count;
+ }
+ *r_overlap_tot = (uint)total;
}
- *r_overlap_tot = (uint)total;
return overlap;
}
+BVHTreeOverlap *BLI_bvhtree_overlap(
+ const BVHTree *tree1,
+ const BVHTree *tree2,
+ uint *r_overlap_tot,
+ /* optional callback to test the overlap before adding (must be thread-safe!) */
+ BVHTree_OverlapCallback callback,
+ void *userdata)
+{
+ return BLI_bvhtree_overlap_ex(tree1,
+ tree2,
+ r_overlap_tot,
+ callback,
+ userdata,
+ BVH_OVERLAP_USE_THREADING | BVH_OVERLAP_RETURN_PAIRS);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1467,6 +1560,95 @@ int BLI_bvhtree_find_nearest(BVHTree *tree,
/** \} */
/* -------------------------------------------------------------------- */
+/** \name BLI_bvhtree_find_nearest_first
+ * \{ */
+
+static bool isect_aabb_v3(BVHNode *node, const float co[3])
+{
+ const BVHTreeAxisRange *bv = (const BVHTreeAxisRange *)node->bv;
+
+ if (co[0] > bv[0].min && co[0] < bv[0].max && co[1] > bv[1].min && co[1] < bv[1].max &&
+ co[2] > bv[2].min && co[2] < bv[2].max) {
+ return true;
+ }
+
+ return false;
+}
+
+static bool dfs_find_duplicate_fast_dfs(BVHNearestData *data, BVHNode *node)
+{
+ if (node->totnode == 0) {
+ if (isect_aabb_v3(node, data->co)) {
+ if (data->callback) {
+ const float dist_sq = data->nearest.dist_sq;
+ data->callback(data->userdata, node->index, data->co, &data->nearest);
+ return (data->nearest.dist_sq < dist_sq);
+ }
+ else {
+ data->nearest.index = node->index;
+ return true;
+ }
+ }
+ }
+ else {
+ /* Better heuristic to pick the closest node to dive on */
+ int i;
+
+ if (data->proj[node->main_axis] <= node->children[0]->bv[node->main_axis * 2 + 1]) {
+ for (i = 0; i != node->totnode; i++) {
+ if (isect_aabb_v3(node->children[i], data->co)) {
+ if (dfs_find_duplicate_fast_dfs(data, node->children[i])) {
+ return true;
+ }
+ }
+ }
+ }
+ else {
+ for (i = node->totnode; i--;) {
+ if (isect_aabb_v3(node->children[i], data->co)) {
+ if (dfs_find_duplicate_fast_dfs(data, node->children[i])) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+/**
+ * Find the first node nearby.
+ * Favors speed over quality since it doesn't find the best target node.
+ */
+int BLI_bvhtree_find_nearest_first(BVHTree *tree,
+ const float co[3],
+ const float dist_sq,
+ BVHTree_NearestPointCallback callback,
+ void *userdata)
+{
+ BVHNearestData data;
+ BVHNode *root = tree->nodes[tree->totleaf];
+
+ /* init data to search */
+ data.tree = tree;
+ data.co = co;
+
+ data.callback = callback;
+ data.userdata = userdata;
+ data.nearest.index = -1;
+ data.nearest.dist_sq = dist_sq;
+
+ /* dfs search */
+ if (root) {
+ dfs_find_duplicate_fast_dfs(&data, root);
+ }
+
+ return data.nearest.index;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name BLI_bvhtree_ray_cast
*
* raycast is done by performing a DFS on the BVHTree and saving the closest hit.
diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c
index ae4f5dcebcf..0fe9fd62198 100644
--- a/source/blender/blenlib/intern/BLI_linklist.c
+++ b/source/blender/blenlib/intern/BLI_linklist.c
@@ -325,7 +325,7 @@ void BLI_linklist_apply(LinkNode *list, LinkNodeApplyFP applyfunc, void *userdat
#include "list_sort_impl.h"
#undef SORT_IMPL_FUNC
-/* reentrant call */
+/* re-entrant call */
#define SORT_IMPL_USE_THUNK
#define SORT_IMPL_FUNC linklist_sort_fn_r
#include "list_sort_impl.h"
diff --git a/source/blender/blenlib/intern/BLI_memblock.c b/source/blender/blenlib/intern/BLI_memblock.c
index f26860afe77..f7239f1b9d1 100644
--- a/source/blender/blenlib/intern/BLI_memblock.c
+++ b/source/blender/blenlib/intern/BLI_memblock.c
@@ -37,7 +37,6 @@
#include "BLI_strict_flags.h" /* keep last */
-#define BLI_MEM_BLOCK_CHUNK_SIZE (1 << 15) /* 32KiB */
#define CHUNK_LIST_SIZE 16
struct BLI_memblock {
@@ -61,18 +60,19 @@ struct BLI_memblock {
int chunk_len;
};
-BLI_memblock *BLI_memblock_create(uint elem_size)
+BLI_memblock *BLI_memblock_create_ex(uint elem_size, uint chunk_size)
{
- BLI_assert(elem_size < BLI_MEM_BLOCK_CHUNK_SIZE);
+ BLI_assert(elem_size < chunk_size);
BLI_memblock *mblk = MEM_mallocN(sizeof(BLI_memblock), "BLI_memblock");
mblk->elem_size = (int)elem_size;
mblk->elem_next = 0;
mblk->elem_last = -1;
- mblk->chunk_size = BLI_MEM_BLOCK_CHUNK_SIZE;
+ mblk->chunk_size = (int)chunk_size;
mblk->chunk_len = CHUNK_LIST_SIZE;
mblk->chunk_list = MEM_callocN(sizeof(void *) * (uint)mblk->chunk_len, "chunk list");
- mblk->chunk_list[0] = MEM_callocN((uint)mblk->chunk_size, "BLI_memblock chunk");
+ mblk->chunk_list[0] = MEM_mallocN_aligned((uint)mblk->chunk_size, 32, "BLI_memblock chunk");
+ memset(mblk->chunk_list[0], 0x0, (uint)mblk->chunk_size);
mblk->chunk_max_ofs = (mblk->chunk_size / mblk->elem_size) * mblk->elem_size;
mblk->elem_next_ofs = 0;
mblk->chunk_next = 0;
@@ -143,8 +143,9 @@ void *BLI_memblock_alloc(BLI_memblock *mblk)
}
if (UNLIKELY(mblk->chunk_list[mblk->chunk_next] == NULL)) {
- mblk->chunk_list[mblk->chunk_next] = MEM_callocN((uint)mblk->chunk_size,
- "BLI_memblock chunk");
+ mblk->chunk_list[mblk->chunk_next] = MEM_mallocN_aligned(
+ (uint)mblk->chunk_size, 32, "BLI_memblock chunk");
+ memset(mblk->chunk_list[mblk->chunk_next], 0x0, (uint)mblk->chunk_size);
}
}
return ptr;
@@ -180,3 +181,11 @@ void *BLI_memblock_iterstep(BLI_memblock_iter *iter)
}
return ptr;
}
+
+/* Direct access. elem is element index inside the chosen chunk. */
+void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem)
+{
+ BLI_assert(chunk < mblk->chunk_len);
+ BLI_assert(elem < (mblk->chunk_size / mblk->elem_size));
+ return (char *)(mblk->chunk_list[chunk]) + mblk->elem_size * elem;
+}
diff --git a/source/blender/blenlib/intern/BLI_temporary_allocator.cc b/source/blender/blenlib/intern/BLI_temporary_allocator.cc
new file mode 100644
index 00000000000..e41cf36f66d
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_temporary_allocator.cc
@@ -0,0 +1,115 @@
+/*
+ * 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 <mutex>
+#include <stack>
+
+#include "BLI_temporary_allocator.h"
+#include "BLI_stack_cxx.h"
+
+using namespace BLI;
+
+constexpr uint ALIGNMENT = BLI_TEMPORARY_BUFFER_ALIGNMENT;
+constexpr uint SMALL_BUFFER_SIZE = 64 * 1024;
+constexpr uintptr_t ALIGNMENT_MASK = ~(uintptr_t)(ALIGNMENT - 1);
+
+enum TemporaryBufferType {
+ Small,
+ Large,
+};
+
+struct MemHead {
+ void *raw_ptr;
+ TemporaryBufferType type;
+};
+
+static MemHead &get_memhead(void *aligned_ptr)
+{
+ return *((MemHead *)aligned_ptr - 1);
+}
+
+static void *raw_allocate(uint size)
+{
+ uint total_allocation_size = size + ALIGNMENT + sizeof(MemHead);
+
+ uintptr_t raw_ptr = (uintptr_t)malloc(total_allocation_size);
+ uintptr_t aligned_ptr = (raw_ptr + ALIGNMENT + sizeof(MemHead)) & ALIGNMENT_MASK;
+
+ MemHead &memhead = get_memhead((void *)aligned_ptr);
+ memhead.raw_ptr = (void *)raw_ptr;
+ return (void *)aligned_ptr;
+}
+
+static void raw_deallocate(void *ptr)
+{
+ BLI_assert(((uintptr_t)ptr & ~ALIGNMENT_MASK) == 0);
+ MemHead &memhead = get_memhead(ptr);
+ void *raw_ptr = memhead.raw_ptr;
+ free(raw_ptr);
+}
+
+struct ThreadLocalBuffers {
+ uint allocated_amount = 0;
+ Stack<void *, 32, RawAllocator> buffers;
+
+ ~ThreadLocalBuffers()
+ {
+ for (void *ptr : buffers) {
+ raw_deallocate(ptr);
+ }
+ }
+};
+
+thread_local ThreadLocalBuffers local_storage;
+
+void *BLI_temporary_allocate(uint size)
+{
+ /* The total amount of allocated buffers using this allocator should be limited by a constant. If
+ * it grows unbounded, there is likely a memory leak somewhere. */
+ BLI_assert(local_storage.allocated_amount < 100);
+
+ if (size <= SMALL_BUFFER_SIZE) {
+ auto &buffers = local_storage.buffers;
+ if (buffers.empty()) {
+ void *ptr = raw_allocate(SMALL_BUFFER_SIZE);
+ MemHead &memhead = get_memhead(ptr);
+ memhead.type = TemporaryBufferType::Small;
+ local_storage.allocated_amount++;
+ return ptr;
+ }
+ else {
+ return buffers.pop();
+ }
+ }
+ else {
+ void *ptr = raw_allocate(size);
+ MemHead &memhead = get_memhead(ptr);
+ memhead.type = TemporaryBufferType::Large;
+ return ptr;
+ }
+}
+
+void BLI_temporary_deallocate(void *buffer)
+{
+ MemHead &memhead = get_memhead(buffer);
+ if (memhead.type == TemporaryBufferType::Small) {
+ auto &buffers = local_storage.buffers;
+ buffers.push(buffer);
+ }
+ else {
+ raw_deallocate(buffer);
+ }
+}
diff --git a/source/blender/blenlib/intern/BLI_timer.c b/source/blender/blenlib/intern/BLI_timer.c
index bf9fd1b57f8..0443dea9a2e 100644
--- a/source/blender/blenlib/intern/BLI_timer.c
+++ b/source/blender/blenlib/intern/BLI_timer.c
@@ -23,7 +23,6 @@
#include "BLI_timer.h"
#include "BLI_listbase.h"
-#include "BLI_callbacks.h"
#include "MEM_guardedalloc.h"
#include "PIL_time.h"
@@ -48,8 +47,6 @@ typedef struct TimerContainer {
static TimerContainer GlobalTimer = {{0}};
-static void ensure_callback_is_registered(void);
-
void BLI_timer_register(uintptr_t uuid,
BLI_timer_func func,
void *user_data,
@@ -57,8 +54,6 @@ void BLI_timer_register(uintptr_t uuid,
double first_interval,
bool persistent)
{
- ensure_callback_is_registered();
-
TimedFunction *timed_func = MEM_callocN(sizeof(TimedFunction), __func__);
timed_func->func = func;
timed_func->user_data_free = user_data_free;
@@ -82,15 +77,10 @@ static void clear_user_data(TimedFunction *timed_func)
bool BLI_timer_unregister(uintptr_t uuid)
{
LISTBASE_FOREACH (TimedFunction *, timed_func, &GlobalTimer.funcs) {
- if (timed_func->uuid == uuid) {
- if (timed_func->tag_removal) {
- return false;
- }
- else {
- timed_func->tag_removal = true;
- clear_user_data(timed_func);
- return true;
- }
+ if (timed_func->uuid == uuid && !timed_func->tag_removal) {
+ timed_func->tag_removal = true;
+ clear_user_data(timed_func);
+ return true;
}
}
return false;
@@ -156,11 +146,7 @@ void BLI_timer_free()
remove_tagged_functions();
}
-struct ID;
-struct Main;
-static void remove_non_persistent_functions(struct Main *UNUSED(_1),
- struct ID *UNUSED(_2),
- void *UNUSED(_3))
+static void remove_non_persistent_functions(void)
{
LISTBASE_FOREACH (TimedFunction *, timed_func, &GlobalTimer.funcs) {
if (!timed_func->persistent) {
@@ -169,18 +155,7 @@ static void remove_non_persistent_functions(struct Main *UNUSED(_1),
}
}
-static bCallbackFuncStore load_pre_callback = {
- NULL,
- NULL, /* next, prev */
- remove_non_persistent_functions, /* func */
- NULL, /* arg */
- 0, /* alloc */
-};
-
-static void ensure_callback_is_registered()
+void BLI_timer_on_file_load(void)
{
- if (!GlobalTimer.file_load_cb_registered) {
- BLI_callback_add(&load_pre_callback, BLI_CB_EVT_LOAD_PRE);
- GlobalTimer.file_load_cb_registered = true;
- }
+ remove_non_persistent_functions();
}
diff --git a/source/blender/blenlib/intern/delaunay_2d.c b/source/blender/blenlib/intern/delaunay_2d.c
index 23f560c5463..d5dcd40346f 100644
--- a/source/blender/blenlib/intern/delaunay_2d.c
+++ b/source/blender/blenlib/intern/delaunay_2d.c
@@ -115,101 +115,9 @@ static void validate_face_centroid(SymEdge *se);
static void validate_cdt(CDT_state *cdt, bool check_all_tris);
#endif
-/* TODO: move these to BLI_vector... and BLI_math... */
-static double max_dd(const double a, const double b)
-{
- return (a > b) ? a : b;
-}
-
-static double len_v2v2_db(const double a[2], const double b[2])
-{
- return sqrt((b[0] - a[0]) * (b[0] - a[0]) + (b[1] - a[1]) * (b[1] - a[1]));
-}
-
-static double len_squared_v2v2_db(const double a[2], const double b[2])
-{
- return (b[0] - a[0]) * (b[0] - a[0]) + (b[1] - a[1]) * (b[1] - a[1]);
-}
-
-static void add_v2_v2_db(double a[2], const double b[2])
-{
- a[0] += b[0];
- a[1] += b[1];
-}
-
-static void sub_v2_v2v2_db(double *a, const double *b, const double *c)
-{
- a[0] = b[0] - c[0];
- a[1] = b[1] - c[1];
-}
-
-static double dot_v2v2_db(const double *a, const double *b)
-{
- return a[0] * b[0] + a[1] * b[1];
-}
-
-static double closest_to_line_v2_db(double r_close[2],
- const double p[2],
- const double l1[2],
- const double l2[2])
-{
- double h[2], u[2], lambda, denom;
- sub_v2_v2v2_db(u, l2, l1);
- sub_v2_v2v2_db(h, p, l1);
- denom = dot_v2v2_db(u, u);
- if (denom < DBL_EPSILON) {
- r_close[0] = l1[0];
- r_close[1] = l1[1];
- return 0.0;
- }
- lambda = dot_v2v2_db(u, h) / dot_v2v2_db(u, u);
- r_close[0] = l1[0] + u[0] * lambda;
- r_close[1] = l1[1] + u[1] * lambda;
- return lambda;
-}
-
-/**
- * If intersection == ISECT_LINE_LINE_CROSS or ISECT_LINE_LINE_NONE:
- * <pre>
- * pt = v1 + lamba * (v2 - v1) = v3 + mu * (v4 - v3)
- * </pre>
- */
-static int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
- const double v2[2],
- const double v3[2],
- const double v4[2],
- double *r_lambda,
- double *r_mu)
-{
- double div, lambda, mu;
-
- div = (v2[0] - v1[0]) * (v4[1] - v3[1]) - (v2[1] - v1[1]) * (v4[0] - v3[0]);
- if (fabs(div) < DBL_EPSILON) {
- return ISECT_LINE_LINE_COLINEAR;
- }
-
- lambda = ((v1[1] - v3[1]) * (v4[0] - v3[0]) - (v1[0] - v3[0]) * (v4[1] - v3[1])) / div;
-
- mu = ((v1[1] - v3[1]) * (v2[0] - v1[0]) - (v1[0] - v3[0]) * (v2[1] - v1[1])) / div;
-
- if (r_lambda) {
- *r_lambda = lambda;
- }
- if (r_mu) {
- *r_mu = mu;
- }
-
- if (lambda >= 0.0 && lambda <= 1.0 && mu >= 0.0 && mu <= 1.0) {
- if (lambda == 0.0 || lambda == 1.0 || mu == 0.0 || mu == 1.0) {
- return ISECT_LINE_LINE_EXACT;
- }
- return ISECT_LINE_LINE_CROSS;
- }
- return ISECT_LINE_LINE_NONE;
-}
-
-/** return 1 if a,b,c forms CCW angle, -1 if a CW angle, 0 if straight */
-static int CCW_test(const double a[2], const double b[2], const double c[2])
+/** return 1 if a,b,c forms CCW angle, -1 if a CW angle, 0 if straight.
+ * For straight test, allow b to be withing eps of line. */
+static int CCW_test(const double a[2], const double b[2], const double c[2], const double eps)
{
double det;
double ab;
@@ -217,14 +125,14 @@ static int CCW_test(const double a[2], const double b[2], const double c[2])
/* This is twice the signed area of triangle abc. */
det = (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]);
ab = len_v2v2_db(a, b);
- if (ab < DBL_EPSILON) {
+ if (ab <= eps) {
return 0;
}
det /= ab;
- if (det > DBL_EPSILON) {
+ if (det > eps) {
return 1;
}
- else if (det < -DBL_EPSILON) {
+ else if (det < -eps) {
return -1;
}
return 0;
@@ -755,7 +663,7 @@ static bool locate_point_final(const double p[2],
}
else {
dist_inside[i] = len_close_p;
- dist_inside[i] = CCW_test(a, b, p) >= 0 ? len_close_p : -len_close_p;
+ dist_inside[i] = CCW_test(a, b, p, epsilon) >= 0 ? len_close_p : -len_close_p;
}
i++;
se = se->next;
@@ -906,7 +814,8 @@ static LocateResult locate_point(CDT_state *cdt, const double p[2])
a = cur_se->vert->co;
b = cur_se->next->vert->co;
c = cur_se->next->next->vert->co;
- if (CCW_test(a, b, p) >= 0 && CCW_test(b, c, p) >= 0 && CCW_test(c, a, p) >= 0) {
+ if (CCW_test(a, b, p, epsilon) >= 0 && CCW_test(b, c, p, epsilon) >= 0 &&
+ CCW_test(c, a, p, epsilon) >= 0) {
#ifdef DEBUG_CDT
if (dbglevel > 1) {
fprintf(stderr, "p in current triangle\n");
@@ -930,7 +839,7 @@ static LocateResult locate_point(CDT_state *cdt, const double p[2])
}
#endif
next_se_sym = sym(next_se);
- if (CCW_test(a, b, p) <= 0 && next_se->face != cdt->outer_face) {
+ if (CCW_test(a, b, p, epsilon) <= 0 && next_se->face != cdt->outer_face) {
#ifdef DEBUG_CDT
if (dbglevel > 1) {
fprintf(stderr, "CCW_test(a, b, p) <= 0\n");
@@ -1524,6 +1433,7 @@ static void add_edge_constraint(
int ccw1, ccw2, isect;
int i, search_count;
double lambda;
+ const double epsilon = cdt->epsilon;
bool done, state_through_vert;
LinkNodePair edge_list = {NULL, NULL};
typedef struct CrossData {
@@ -1634,8 +1544,8 @@ static void add_edge_constraint(
do {
va = t->next->vert;
vb = t->next->next->vert;
- ccw1 = CCW_test(t->vert->co, va->co, v2->co);
- ccw2 = CCW_test(t->vert->co, vb->co, v2->co);
+ ccw1 = CCW_test(t->vert->co, va->co, v2->co, epsilon);
+ ccw2 = CCW_test(t->vert->co, vb->co, v2->co, epsilon);
#ifdef DEBUG_CDT
if (dbg_level > 1) {
fprintf(stderr, "non-final through vert case\n");
@@ -1684,7 +1594,7 @@ static void add_edge_constraint(
}
#endif
} while (t != tstart);
- BLI_assert(tout != NULL); /* TODO: something sensivle for "this can't happen" */
+ BLI_assert(tout != NULL); /* TODO: something sensible for "this can't happen" */
crossings[BLI_array_len(crossings) - 1].out = tout;
}
}
@@ -1727,7 +1637,7 @@ static void add_edge_constraint(
/* 'tout' is 'symedge' from 'vb' to third vertex, 'vc'. */
BLI_assert(tout->vert == va);
vc = tout->next->vert;
- ccw1 = CCW_test(v1->co, v2->co, vc->co);
+ ccw1 = CCW_test(v1->co, v2->co, vc->co, epsilon);
#ifdef DEBUG_CDT
if (dbg_level > 1) {
fprintf(stderr, "now searching with third vertex ");
@@ -2004,7 +1914,7 @@ static void remove_non_constraint_edges(CDT_state *cdt, const bool valid_bmesh)
dissolve = !is_deleted_edge(e) && !is_constrained_edge(e);
if (dissolve) {
se = &e->symedges[0];
- if (valid_bmesh) {
+ if (valid_bmesh && !edge_touches_frame(e)) {
fleft = se->face;
fright = sym(se)->face;
if (fleft != cdt->outer_face && fright != cdt->outer_face &&
@@ -2320,7 +2230,7 @@ CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_ty
CDTEdge *face_edge;
SymEdge *face_symedge;
#ifdef DEBUG_CDT
- int dbg_level = 1;
+ int dbg_level = 0;
#endif
if ((nv > 0 && input->vert_coords == NULL) || (ne > 0 && input->edges == NULL) ||
@@ -2378,6 +2288,13 @@ CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_ty
}
add_edge_constraint(cdt, verts[v1], verts[v2], i, NULL);
}
+#ifdef DEBUG_CDT
+ if (dbg_level > 2) {
+ cdt_draw(cdt, "after edge constraints");
+ dump_cdt(cdt, "after edge constraints");
+ validate_cdt(cdt, true);
+ }
+#endif
cdt->face_edge_offset = ne;
for (f = 0; f < nf; f++) {
int flen = input->faces_len_table[f];
@@ -2410,6 +2327,11 @@ CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_ty
F2(cdt_e->symedges[1].vert->co));
}
}
+ if (dbg_level > 2) {
+ cdt_draw(cdt, "after a face edge");
+ dump_cdt(cdt, "after a face edge");
+ validate_cdt(cdt, true);
+ }
#endif
if (i == 0) {
face_edge = (CDTEdge *)edge_list->link;
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index 0e3987eefc9..99149f5ea42 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -35,7 +35,6 @@
#ifdef WIN32
# include <io.h>
# include "BLI_winstuff.h"
-# include "BLI_callbacks.h"
# include "BLI_fileops_types.h"
# include "utf_winfunc.h"
# include "utfconv.h"
@@ -343,7 +342,7 @@ static bool delete_recursive(const char *dir)
err = true;
}
}
- ++fl;
+ fl++;
}
if (!err && delete_unique(dir, true)) {
@@ -771,7 +770,7 @@ int BLI_delete(const char *file, bool dir, bool recursive)
}
/**
- * Do the two paths denote the same filesystem object?
+ * Do the two paths denote the same file-system object?
*/
static bool check_the_same(const char *path_a, const char *path_b)
{
diff --git a/source/blender/blenlib/intern/gsqueue.c b/source/blender/blenlib/intern/gsqueue.c
index 6d0fdfacb10..5e1fbf6eade 100644
--- a/source/blender/blenlib/intern/gsqueue.c
+++ b/source/blender/blenlib/intern/gsqueue.c
@@ -12,9 +12,6 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
*/
/** \file
@@ -22,9 +19,6 @@
*
* \brief A generic structure queue
* (a queue for fixed length generally small) structures.
- *
- * \note Only use this if you need (first-in-first-out),
- * otherwise #BLI_Stack is more efficient (first-in-last-out).
*/
#include <string.h>
@@ -35,148 +29,168 @@
#include "BLI_gsqueue.h"
#include "BLI_strict_flags.h"
-typedef struct _GSQueueElem GSQueueElem;
-struct _GSQueueElem {
- GSQueueElem *next;
+/* target chunk size: 64kb */
+#define CHUNK_SIZE_DEFAULT (1 << 16)
+/* ensure we get at least this many elems per chunk */
+#define CHUNK_ELEM_MIN 32
+
+struct QueueChunk {
+ struct QueueChunk *next;
char data[0];
};
struct _GSQueue {
- GSQueueElem *head;
- GSQueueElem *tail;
- size_t elem_size;
+ struct QueueChunk *chunk_first; /* first active chunk to pop from */
+ struct QueueChunk *chunk_last; /* flast active chunk to push onto */
+ struct QueueChunk *chunk_free; /* free chunks to reuse */
+ size_t chunk_first_index; /* index into 'chunk_first' */
+ size_t chunk_last_index; /* index into 'chunk_last' */
+ size_t chunk_elem_max; /* number of elements per chunk */
+ size_t elem_size; /* memory size of elements */
+ size_t totelem; /* total number of elements */
};
-/**
- * Create a new GSQueue.
- *
- * \param elem_size: The size of the structures in the queue.
- * \retval The new queue
- */
-GSQueue *BLI_gsqueue_new(size_t elem_size)
+static void *queue_get_first_elem(GSQueue *queue)
{
- GSQueue *gq = MEM_mallocN(sizeof(*gq), "gqueue_new");
- gq->head = gq->tail = NULL;
- gq->elem_size = elem_size;
-
- return gq;
+ return ((char *)(queue)->chunk_first->data) + ((queue)->elem_size * (queue)->chunk_first_index);
}
-/**
- * Query if the queue is empty
- */
-bool BLI_gsqueue_is_empty(GSQueue *gq)
+static void *queue_get_last_elem(GSQueue *queue)
{
- return (gq->head == NULL);
+ return ((char *)(queue)->chunk_last->data) + ((queue)->elem_size * (queue)->chunk_last_index);
}
/**
- * Query number elements in the queue
+ * \return number of elements per chunk, optimized for slop-space.
*/
-int BLI_gsqueue_len(GSQueue *gq)
+static size_t queue_chunk_elem_max_calc(const size_t elem_size, size_t chunk_size)
{
- GSQueueElem *elem;
- int size = 0;
+ /* get at least this number of elems per chunk */
+ const size_t elem_size_min = elem_size * CHUNK_ELEM_MIN;
- for (elem = gq->head; elem; elem = elem->next) {
- size++;
+ BLI_assert((elem_size != 0) && (chunk_size != 0));
+
+ while (UNLIKELY(chunk_size <= elem_size_min)) {
+ chunk_size <<= 1;
}
- return size;
+ /* account for slop-space */
+ chunk_size -= (sizeof(struct QueueChunk) + MEM_SIZE_OVERHEAD);
+
+ return chunk_size / elem_size;
}
-/**
- * Access the item at the head of the queue
- * without removing it.
- *
- * \param r_item: A pointer to an appropriately
- * sized structure (the size passed to #BLI_gsqueue_new)
- */
-void BLI_gsqueue_peek(GSQueue *gq, void *r_item)
+GSQueue *BLI_gsqueue_new(const size_t elem_size)
{
- memcpy(r_item, &gq->head->data, gq->elem_size);
+ GSQueue *queue = MEM_callocN(sizeof(*queue), "BLI_gsqueue_new");
+
+ queue->chunk_elem_max = queue_chunk_elem_max_calc(elem_size, CHUNK_SIZE_DEFAULT);
+ queue->elem_size = elem_size;
+ /* force init */
+ queue->chunk_last_index = queue->chunk_elem_max - 1;
+
+ return queue;
}
-/**
- * Access the item at the head of the queue
- * and remove it.
- *
- * \param r_item: A pointer to an appropriately
- * sized structure (the size passed to #BLI_gsqueue_new).
- * Can be NULL if desired.
- */
-void BLI_gsqueue_pop(GSQueue *gq, void *r_item)
+static void queue_free_chunk(struct QueueChunk *data)
{
- GSQueueElem *elem = gq->head;
- if (elem == gq->tail) {
- gq->head = gq->tail = NULL;
- }
- else {
- gq->head = gq->head->next;
+ while (data) {
+ struct QueueChunk *data_next = data->next;
+ MEM_freeN(data);
+ data = data_next;
}
+}
- if (r_item) {
- memcpy(r_item, elem->data, gq->elem_size);
- }
- MEM_freeN(elem);
+/**
+ * Free the queue's data and the queue itself
+ */
+void BLI_gsqueue_free(GSQueue *queue)
+{
+ queue_free_chunk(queue->chunk_first);
+ queue_free_chunk(queue->chunk_free);
+ MEM_freeN(queue);
}
/**
- * Push an element onto the tail of the queue.
+ * Copies the source value onto the end of the queue
*
- * \param item: A pointer to an appropriately
- * sized structure (the size passed to BLI_gsqueue_new).
+ * \note This copies #GSQueue.elem_size bytes from \a src,
+ * (the pointer itself is not stored).
+ *
+ * \param src: source data to be copied to the queue.
*/
-void BLI_gsqueue_push(GSQueue *gq, const void *item)
+void BLI_gsqueue_push(GSQueue *queue, const void *src)
{
- GSQueueElem *elem;
+ queue->chunk_last_index++;
+ queue->totelem++;
+
+ if (UNLIKELY(queue->chunk_last_index == queue->chunk_elem_max)) {
+ struct QueueChunk *chunk;
+ if (queue->chunk_free) {
+ chunk = queue->chunk_free;
+ queue->chunk_free = chunk->next;
+ }
+ else {
+ chunk = MEM_mallocN(sizeof(*chunk) + (queue->elem_size * queue->chunk_elem_max), __func__);
+ }
- /* compare: prevent events added double in row */
- if (!BLI_gsqueue_is_empty(gq)) {
- if (0 == memcmp(item, gq->head->data, gq->elem_size)) {
- return;
+ chunk->next = NULL;
+
+ if (queue->chunk_last == NULL) {
+ queue->chunk_first = chunk;
+ }
+ else {
+ queue->chunk_last->next = chunk;
}
- }
- elem = MEM_mallocN(sizeof(*elem) + gq->elem_size, "gqueue_push");
- memcpy(elem->data, item, gq->elem_size);
- elem->next = NULL;
- if (BLI_gsqueue_is_empty(gq)) {
- gq->tail = gq->head = elem;
- }
- else {
- gq->tail = gq->tail->next = elem;
+ queue->chunk_last = chunk;
+ queue->chunk_last_index = 0;
}
+
+ BLI_assert(queue->chunk_last_index < queue->chunk_elem_max);
+
+ /* Return last of queue */
+ memcpy(queue_get_last_elem(queue), src, queue->elem_size);
}
/**
- * Push an element back onto the head of the queue (so
- * it would be returned from the next call to BLI_gsqueue_pop).
+ * Retrieves and removes the first element from the queue.
+ * The value is copies to \a dst, which must be at least \a elem_size bytes.
*
- * \param item: A pointer to an appropriately
- * sized structure (the size passed to BLI_gsqueue_new).
+ * Does not reduce amount of allocated memory.
*/
-void BLI_gsqueue_push_back(GSQueue *gq, const void *item)
+void BLI_gsqueue_pop(GSQueue *queue, void *dst)
{
- GSQueueElem *elem = MEM_mallocN(sizeof(*elem) + gq->elem_size, "gqueue_push");
- memcpy(elem->data, item, gq->elem_size);
- elem->next = gq->head;
+ BLI_assert(BLI_gsqueue_is_empty(queue) == false);
- if (BLI_gsqueue_is_empty(gq)) {
- gq->head = gq->tail = elem;
- }
- else {
- gq->head = elem;
+ memcpy(dst, queue_get_first_elem(queue), queue->elem_size);
+ queue->chunk_first_index++;
+ queue->totelem--;
+
+ if (UNLIKELY(queue->chunk_first_index == queue->chunk_elem_max || queue->totelem == 0)) {
+ struct QueueChunk *chunk_free = queue->chunk_first;
+
+ queue->chunk_first = queue->chunk_first->next;
+ queue->chunk_first_index = 0;
+ if (queue->chunk_first == NULL) {
+ queue->chunk_last = NULL;
+ queue->chunk_last_index = queue->chunk_elem_max - 1;
+ }
+
+ chunk_free->next = queue->chunk_free;
+ queue->chunk_free = chunk_free;
}
}
+size_t BLI_gsqueue_len(const GSQueue *queue)
+{
+ return queue->totelem;
+}
+
/**
- * Free the queue
+ * Returns true if the queue is empty, false otherwise
*/
-void BLI_gsqueue_free(GSQueue *gq)
+bool BLI_gsqueue_is_empty(const GSQueue *queue)
{
- while (gq->head) {
- BLI_gsqueue_pop(gq, NULL);
- }
- MEM_freeN(gq);
+ return (queue->chunk_first == NULL);
}
diff --git a/source/blender/blenlib/intern/hash_md5.c b/source/blender/blenlib/intern/hash_md5.c
index 44a9348c5d3..f9e9b3bfbf9 100644
--- a/source/blender/blenlib/intern/hash_md5.c
+++ b/source/blender/blenlib/intern/hash_md5.c
@@ -151,7 +151,7 @@ static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ct
*/
#define OP(a, b, c, d, s, T) \
a += FF(b, c, d) + (*cwp++ = SWAP(*words)) + T; \
- ++words; \
+ words++; \
CYCLIC(a, s); \
a += b; \
(void)0
@@ -408,7 +408,7 @@ char *BLI_hash_md5_to_hexdigest(void *resblock, char r_hex_digest[33])
char *q;
short len;
- for (q = r_hex_digest, p = (const unsigned char *)resblock, len = 0; len < 16; ++p, ++len) {
+ for (q = r_hex_digest, p = (const unsigned char *)resblock, len = 0; len < 16; p++, len++) {
const unsigned char c = *p;
*q++ = hex_map[c >> 4];
*q++ = hex_map[c & 15];
diff --git a/source/blender/blenlib/intern/list_sort_impl.h b/source/blender/blenlib/intern/list_sort_impl.h
index fac1ca8e983..458ace3a712 100644
--- a/source/blender/blenlib/intern/list_sort_impl.h
+++ b/source/blender/blenlib/intern/list_sort_impl.h
@@ -240,7 +240,7 @@ BLI_INLINE void insert_list(struct SortInfo *si, list_node *list, unsigned int r
rank = MAX_RANKS;
}
list = merge_lists(sweep_up(si, NULL, si->n_ranks), list, THUNK_APPEND1(si->func, si->thunk));
- for (i = si->n_ranks; i < rank; ++i) {
+ for (i = si->n_ranks; i < rank; i++) {
si->ranks[i] = NULL;
}
}
@@ -248,7 +248,7 @@ BLI_INLINE void insert_list(struct SortInfo *si, list_node *list, unsigned int r
if (rank) {
list = merge_lists(sweep_up(si, NULL, rank), list, THUNK_APPEND1(si->func, si->thunk));
}
- for (i = rank; i < si->n_ranks && si->ranks[i]; ++i) {
+ for (i = rank; i < si->n_ranks && si->ranks[i]; i++) {
list = merge_lists(si->ranks[i], list, THUNK_APPEND1(si->func, si->thunk));
si->ranks[i] = NULL;
}
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index 31d372945c6..fe5f9f7673f 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -312,7 +312,7 @@ static void listbase_double_from_single(Link *iter, ListBase *listbase)
#include "list_sort_impl.h"
#undef SORT_IMPL_FUNC
-/* reentrant call */
+/* re-entrant call */
#define SORT_IMPL_USE_THUNK
#define SORT_IMPL_FUNC listbase_sort_fn_r
#include "list_sort_impl.h"
@@ -504,6 +504,27 @@ bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step)
}
/**
+ * Move the link at the index \a from to the position at index \a to.
+ *
+ * \return If the move was successful.
+ */
+bool BLI_listbase_move_index(ListBase *listbase, int from, int to)
+{
+ if (from == to) {
+ return false;
+ }
+
+ /* Find the link to move. */
+ void *link = BLI_findlink(listbase, from);
+
+ if (!link) {
+ return false;
+ }
+
+ return BLI_listbase_link_move(listbase, link, to - from);
+}
+
+/**
* Removes and disposes of the entire contents of listbase using direct free(3).
*/
void BLI_freelist(ListBase *listbase)
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index 320f8a0f1ab..0309876d8fb 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -230,6 +230,21 @@ MINLINE unsigned power_of_2_min_u(unsigned x)
return x - (x >> 1);
}
+MINLINE unsigned int log2_floor_u(unsigned int x)
+{
+ return x <= 1 ? 0 : 1 + log2_floor_u(x >> 1);
+}
+
+MINLINE unsigned int log2_ceil_u(unsigned int x)
+{
+ if (is_power_of_2_i((int)x)) {
+ return log2_floor_u(x);
+ }
+ else {
+ return log2_floor_u(x) + 1;
+ }
+}
+
/* rounding and clamping */
#define _round_clamp_fl_impl(arg, ty, min, max) \
@@ -353,6 +368,15 @@ MINLINE float max_ff(float a, float b)
return (a > b) ? a : b;
}
+MINLINE double min_dd(double a, double b)
+{
+ return (a < b) ? a : b;
+}
+MINLINE double max_dd(double a, double b)
+{
+ return (a > b) ? a : b;
+}
+
MINLINE int min_ii(int a, int b)
{
return (a < b) ? a : b;
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index c4bdc73e0e3..6d8193e7675 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -1356,6 +1356,52 @@ bool isect_seg_seg_v2_simple(const float v1[2],
}
/**
+ * If intersection == ISECT_LINE_LINE_CROSS or ISECT_LINE_LINE_NONE:
+ * <pre>
+ * pt = v1 + lambda * (v2 - v1) = v3 + mu * (v4 - v3)
+ * </pre>
+ * \returns intersection type:
+ * - ISECT_LINE_LINE_COLINEAR: collinear.
+ * - ISECT_LINE_LINE_EXACT: intersection at an endpoint of either.
+ * - ISECT_LINE_LINE_CROSS: interaction, not at an endpoint.
+ * - ISECT_LINE_LINE_NONE: no intersection.
+ * Also returns lambda and mu in r_lambda and r_mu.
+ */
+int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
+ const double v2[2],
+ const double v3[2],
+ const double v4[2],
+ double *r_lambda,
+ double *r_mu)
+{
+ double div, lambda, mu;
+
+ div = (v2[0] - v1[0]) * (v4[1] - v3[1]) - (v2[1] - v1[1]) * (v4[0] - v3[0]);
+ if (fabs(div) < DBL_EPSILON) {
+ return ISECT_LINE_LINE_COLINEAR;
+ }
+
+ lambda = ((v1[1] - v3[1]) * (v4[0] - v3[0]) - (v1[0] - v3[0]) * (v4[1] - v3[1])) / div;
+
+ mu = ((v1[1] - v3[1]) * (v2[0] - v1[0]) - (v1[0] - v3[0]) * (v2[1] - v1[1])) / div;
+
+ if (r_lambda) {
+ *r_lambda = lambda;
+ }
+ if (r_mu) {
+ *r_mu = mu;
+ }
+
+ if (lambda >= 0.0 && lambda <= 1.0 && mu >= 0.0 && mu <= 1.0) {
+ if (lambda == 0.0 || lambda == 1.0 || mu == 0.0 || mu == 1.0) {
+ return ISECT_LINE_LINE_EXACT;
+ }
+ return ISECT_LINE_LINE_CROSS;
+ }
+ return ISECT_LINE_LINE_NONE;
+}
+
+/**
* \param l1, l2: Coordinates (point of line).
* \param sp, r: Coordinate and radius (sphere).
* \return r_p1, r_p2: Intersection coordinates.
@@ -3011,19 +3057,21 @@ bool isect_line_line_strict_v3(const float v1[3],
*
* \note Neither directions need to be normalized.
*/
-bool isect_ray_ray_v3(const float ray_origin_a[3],
- const float ray_direction_a[3],
- const float ray_origin_b[3],
- const float ray_direction_b[3],
- float *r_lambda_a,
- float *r_lambda_b)
+bool isect_ray_ray_epsilon_v3(const float ray_origin_a[3],
+ const float ray_direction_a[3],
+ const float ray_origin_b[3],
+ const float ray_direction_b[3],
+ const float epsilon,
+ float *r_lambda_a,
+ float *r_lambda_b)
{
BLI_assert(r_lambda_a || r_lambda_b);
float n[3];
cross_v3_v3v3(n, ray_direction_b, ray_direction_a);
const float nlen = len_squared_v3(n);
- if (UNLIKELY(nlen == 0.0f)) {
+ /* `nlen` is the the square of the area formed by the two vectors. */
+ if (UNLIKELY(nlen < epsilon)) {
/* The lines are parallel. */
return false;
}
@@ -3045,6 +3093,22 @@ bool isect_ray_ray_v3(const float ray_origin_a[3],
return true;
}
+bool isect_ray_ray_v3(const float ray_origin_a[3],
+ const float ray_direction_a[3],
+ const float ray_origin_b[3],
+ const float ray_direction_b[3],
+ float *r_lambda_a,
+ float *r_lambda_b)
+{
+ return isect_ray_ray_epsilon_v3(ray_origin_a,
+ ray_direction_a,
+ ray_origin_b,
+ ray_direction_b,
+ FLT_MIN,
+ r_lambda_a,
+ r_lambda_b);
+}
+
bool isect_aabb_aabb_v3(const float min1[3],
const float max1[3],
const float min2[3],
@@ -3187,6 +3251,26 @@ float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2],
return lambda;
}
+double closest_to_line_v2_db(double r_close[2],
+ const double p[2],
+ const double l1[2],
+ const double l2[2])
+{
+ double h[2], u[2], lambda, denom;
+ sub_v2_v2v2_db(u, l2, l1);
+ sub_v2_v2v2_db(h, p, l1);
+ denom = dot_v2v2_db(u, u);
+ if (denom < DBL_EPSILON) {
+ r_close[0] = l1[0];
+ r_close[1] = l1[1];
+ return 0.0;
+ }
+ lambda = dot_v2v2_db(u, h) / dot_v2v2_db(u, u);
+ r_close[0] = l1[0] + u[0] * lambda;
+ r_close[1] = l1[1] + u[1] * lambda;
+ return lambda;
+}
+
float ray_point_factor_v3_ex(const float p[3],
const float ray_origin[3],
const float ray_direction[3],
@@ -4707,29 +4791,24 @@ void projmat_from_subregion(const float projmat[4][4],
float rect_width = (float)(x_max - x_min);
float rect_height = (float)(y_max - y_min);
+ float x_sca = (float)win_size[0] / rect_width;
+ float y_sca = (float)win_size[1] / rect_height;
+
float x_fac = (float)((x_min + x_max) - win_size[0]) / rect_width;
float y_fac = (float)((y_min + y_max) - win_size[1]) / rect_height;
copy_m4_m4(r_projmat, projmat);
- r_projmat[0][0] *= (float)win_size[0] / rect_width;
- r_projmat[1][1] *= (float)win_size[1] / rect_height;
+ r_projmat[0][0] *= x_sca;
+ r_projmat[1][1] *= y_sca;
-#if 0 /* TODO: check if this is more efficient. */
- r_projmat[2][0] -= x_fac * r_projmat[2][3];
- r_projmat[2][1] -= y_fac * r_projmat[2][3];
-
- r_projmat[3][0] -= x_fac * r_projmat[3][3];
- r_projmat[3][1] -= y_fac * r_projmat[3][3];
-#else
if (projmat[3][3] == 0.0f) {
- r_projmat[2][0] += x_fac;
- r_projmat[2][1] += y_fac;
+ r_projmat[2][0] = r_projmat[2][0] * x_sca + x_fac;
+ r_projmat[2][1] = r_projmat[2][1] * y_sca + y_fac;
}
else {
- r_projmat[3][0] -= x_fac;
- r_projmat[3][1] -= y_fac;
+ r_projmat[3][0] = r_projmat[3][0] * x_sca - x_fac;
+ r_projmat[3][1] = r_projmat[3][1] * y_sca - y_fac;
}
-#endif
}
static void i_multmatrix(float icand[4][4], float Vm[4][4])
diff --git a/source/blender/blenlib/intern/math_interp.c b/source/blender/blenlib/intern/math_interp.c
index 14fde18aa52..6277b1cd9dc 100644
--- a/source/blender/blenlib/intern/math_interp.c
+++ b/source/blender/blenlib/intern/math_interp.c
@@ -687,11 +687,11 @@ void BLI_ewa_filter(const int width,
d = 0.0f;
zero_v4(result);
- for (v = v1; v <= v2; ++v) {
+ for (v = v1; v <= v2; v++) {
const float V = (float)v - V0;
float DQ = ac1 + B * V;
float Q = (C * V + BU) * V + ac2;
- for (u = u1; u <= u2; ++u) {
+ for (u = u1; u <= u2; u++) {
if (Q < (float)(EWA_MAXIDX + 1)) {
float tc[4];
const float wt = EWA_WTS[(Q < 0.0f) ? 0 : (unsigned int)Q];
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index 2568d42566c..33e272ed7eb 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -1146,8 +1146,8 @@ bool invert_m4(float m[4][4])
* \return true on success (i.e. can always find a pivot) and false on failure.
* Mark Segal - 1992.
*
- * \note this is less performant than #EIG_invert_m4_m4 (Eigen), but e.g.
- * for non-invertible scale matrices, findinging a partial solution can
+ * \note this has worse performance than #EIG_invert_m4_m4 (Eigen), but e.g.
+ * for non-invertible scale matrices, finding a partial solution can
* be useful to have a valid local transform center, see T57767.
*/
bool invert_m4_m4_fallback(float inverse[4][4], const float mat[4][4])
@@ -1516,6 +1516,111 @@ void orthogonalize_m4(float mat[4][4], int axis)
mul_v3_fl(mat[2], size[2]);
}
+/** Make an orthonormal basis around v1 in a way that is stable and symmetric. */
+static void orthogonalize_stable(float v1[3], float v2[3], float v3[3], bool normalize)
+{
+ /* Make secondary axis vectors orthogonal to the primary via
+ * plane projection, which preserves the determinant. */
+ float len_sq_v1 = len_squared_v3(v1);
+
+ if (len_sq_v1 > 0.0f) {
+ madd_v3_v3fl(v2, v1, -dot_v3v3(v2, v1) / len_sq_v1);
+ madd_v3_v3fl(v3, v1, -dot_v3v3(v3, v1) / len_sq_v1);
+
+ if (normalize) {
+ mul_v3_fl(v1, 1.0f / sqrtf(len_sq_v1));
+ }
+ }
+
+ /* Make secondary axis vectors orthogonal relative to each other. */
+ float norm_v2[3], norm_v3[3], tmp[3];
+ float length_v2 = normalize_v3_v3(norm_v2, v2);
+ float length_v3 = normalize_v3_v3(norm_v3, v3);
+ float cos_angle = dot_v3v3(norm_v2, norm_v3);
+ float abs_cos_angle = fabsf(cos_angle);
+
+ /* Apply correction if the shear angle is significant, and not degenerate. */
+ if (abs_cos_angle > 1e-4f && abs_cos_angle < 1.0f - FLT_EPSILON) {
+ /* Adjust v2 by half of the necessary angle correction.
+ * Thus the angle change is the same for both axis directions. */
+ float angle = acosf(cos_angle);
+ float target_angle = angle + ((float)M_PI_2 - angle) / 2;
+
+ madd_v3_v3fl(norm_v2, norm_v3, -cos_angle);
+ mul_v3_fl(norm_v2, sinf(target_angle) / len_v3(norm_v2));
+ madd_v3_v3fl(norm_v2, norm_v3, cosf(target_angle));
+
+ /* Make v3 orthogonal. */
+ cross_v3_v3v3(tmp, norm_v2, norm_v3);
+ cross_v3_v3v3(norm_v3, tmp, norm_v2);
+ normalize_v3(norm_v3);
+
+ /* Re-apply scale, preserving area and proportion. */
+ if (!normalize) {
+ float scale_fac = sqrtf(sinf(angle));
+ mul_v3_v3fl(v2, norm_v2, length_v2 * scale_fac);
+ mul_v3_v3fl(v3, norm_v3, length_v3 * scale_fac);
+ }
+ }
+
+ if (normalize) {
+ copy_v3_v3(v2, norm_v2);
+ copy_v3_v3(v3, norm_v3);
+ }
+}
+
+/**
+ * Make an orthonormal matrix around the selected axis of the given matrix,
+ * in a way that is symmetric and stable to variations in the input, and
+ * preserving the value of the determinant, i.e. the overall volume change.
+ *
+ * \param axis: Axis to build the orthonormal basis around.
+ * \param normalize: Normalize the matrix instead of preserving volume.
+ */
+void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize)
+{
+ switch (axis) {
+ case 0:
+ orthogonalize_stable(R[0], R[1], R[2], normalize);
+ break;
+ case 1:
+ orthogonalize_stable(R[1], R[0], R[2], normalize);
+ break;
+ case 2:
+ orthogonalize_stable(R[2], R[0], R[1], normalize);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+}
+
+/**
+ * Make an orthonormal matrix around the selected axis of the given matrix,
+ * in a way that is symmetric and stable to variations in the input, and
+ * preserving the value of the determinant, i.e. the overall volume change.
+ *
+ * \param axis: Axis to build the orthonormal basis around.
+ * \param normalize: Normalize the matrix instead of preserving volume.
+ */
+void orthogonalize_m4_stable(float R[4][4], int axis, bool normalize)
+{
+ switch (axis) {
+ case 0:
+ orthogonalize_stable(R[0], R[1], R[2], normalize);
+ break;
+ case 1:
+ orthogonalize_stable(R[1], R[0], R[2], normalize);
+ break;
+ case 2:
+ orthogonalize_stable(R[2], R[0], R[1], normalize);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+}
+
bool is_orthogonal_m3(const float m[3][3])
{
int i, j;
@@ -1851,6 +1956,19 @@ void mat4_to_size(float size[3], const float mat[4][4])
size[2] = len_v3(mat[2]);
}
+/** Extract scale factors from the matrix, with correction to ensure
+ * exact volume in case of a sheared matrix. */
+void mat4_to_size_fix_shear(float size[3], const float mat[4][4])
+{
+ mat4_to_size(size, mat);
+
+ float volume = size[0] * size[1] * size[2];
+
+ if (volume != 0.0f) {
+ mul_v3_fl(size, cbrtf(fabsf(mat4_to_volume_scale(mat) / volume)));
+ }
+}
+
/**
* This computes the overall volume scale factor of a transformation matrix.
* For an orthogonal matrix, it is the product of all three scale values.
@@ -2045,6 +2163,14 @@ void rotate_m4(float mat[4][4], const char axis, const float angle)
}
}
+/** Scale a matrix in-place. */
+void rescale_m4(float mat[4][4], const float scale[3])
+{
+ mul_v3_fl(mat[0], scale[0]);
+ mul_v3_fl(mat[1], scale[1]);
+ mul_v3_fl(mat[2], scale[2]);
+}
+
/**
* Scale or rotate around a pivot point,
* a convenience function to avoid having to do inline.
@@ -2233,6 +2359,20 @@ bool equals_m4m4(const float mat1[4][4], const float mat2[4][4])
/**
* Make a 4x4 matrix out of 3 transform components.
* Matrices are made in the order: `scale * rot * loc`
+ */
+void loc_rot_size_to_mat4(float mat[4][4],
+ const float loc[3],
+ const float rot[3][3],
+ const float size[3])
+{
+ copy_m4_m3(mat, rot);
+ rescale_m4(mat, size);
+ copy_v3_v3(mat[3], loc);
+}
+
+/**
+ * Make a 4x4 matrix out of 3 transform components.
+ * Matrices are made in the order: `scale * rot * loc`
*
* TODO: need to have a version that allows for rotation order...
*/
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index e4b44240272..37c0c05b061 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -535,6 +535,50 @@ void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q
mul_qt_qtqt(q, tquat, q2);
}
+/**
+ * Decompose a quaternion into a swing rotation (quaternion with the selected
+ * axis component locked at zero), followed by a twist rotation around the axis.
+ *
+ * \param q: input quaternion.
+ * \param axis: twist axis in [0,1,2]
+ * \param r_swing[out]: if not NULL, receives the swing quaternion.
+ * \param r_twist[out]: if not NULL, receives the twist quaternion.
+ * \returns twist angle.
+ */
+float quat_split_swing_and_twist(const float q[4], int axis, float r_swing[4], float r_twist[4])
+{
+ BLI_assert(axis >= 0 && axis <= 2);
+
+ /* Half-twist angle can be computed directly. */
+ float t = atan2f(q[axis + 1], q[0]);
+
+ if (r_swing || r_twist) {
+ float sin_t = sinf(t), cos_t = cosf(t);
+
+ /* Compute swing by multiplying the original quaternion by inverted twist. */
+ if (r_swing) {
+ float twist_inv[4];
+
+ twist_inv[0] = cos_t;
+ zero_v3(twist_inv + 1);
+ twist_inv[axis + 1] = -sin_t;
+
+ mul_qt_qtqt(r_swing, q, twist_inv);
+
+ BLI_assert(fabsf(r_swing[axis + 1]) < BLI_ASSERT_UNIT_EPSILON);
+ }
+
+ /* Output twist last just in case q ovelaps r_twist. */
+ if (r_twist) {
+ r_twist[0] = cos_t;
+ zero_v3(r_twist + 1);
+ r_twist[axis + 1] = sin_t;
+ }
+ }
+
+ return 2.0f * t;
+}
+
/* -------------------------------------------------------------------- */
/** \name Quaternion Angle
*
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index 8cb618ae14e..b4b53a1dd58 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -355,6 +355,12 @@ MINLINE void add_v2_v2(float r[2], const float a[2])
r[1] += a[1];
}
+MINLINE void add_v2_v2_db(double r[2], const double a[2])
+{
+ r[0] += a[0];
+ r[1] += a[1];
+}
+
MINLINE void add_v2_v2v2(float r[2], const float a[2], const float b[2])
{
r[0] = a[0] + b[0];
@@ -430,6 +436,12 @@ MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
r[1] = a[1] - b[1];
}
+MINLINE void sub_v2_v2v2_db(double r[2], const double a[2], const double b[2])
+{
+ r[0] = a[0] - b[0];
+ r[1] = a[1] - b[1];
+}
+
MINLINE void sub_v2_v2v2_int(int r[2], const int a[2], const int b[2])
{
r[0] = a[0] - b[0];
@@ -830,6 +842,11 @@ MINLINE float dot_v2v2(const float a[2], const float b[2])
return a[0] * b[0] + a[1] * b[1];
}
+MINLINE double dot_v2v2_db(const double a[2], const double b[2])
+{
+ return a[0] * b[0] + a[1] * b[1];
+}
+
MINLINE float dot_v3v3(const float a[3], const float b[3])
{
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
@@ -956,6 +973,15 @@ MINLINE float len_v2v2(const float v1[2], const float v2[2])
return sqrtf(x * x + y * y);
}
+MINLINE double len_v2v2_db(const double v1[2], const double v2[2])
+{
+ double x, y;
+
+ x = v1[0] - v2[0];
+ y = v1[1] - v2[1];
+ return sqrt(x * x + y * y);
+}
+
MINLINE float len_v2v2_int(const int v1[2], const int v2[2])
{
float x, y;
@@ -978,6 +1004,14 @@ MINLINE float len_squared_v2v2(const float a[2], const float b[2])
return dot_v2v2(d, d);
}
+MINLINE double len_squared_v2v2_db(const double a[2], const double b[2])
+{
+ double d[2];
+
+ sub_v2_v2v2_db(d, b, a);
+ return dot_v2v2_db(d, d);
+}
+
MINLINE float len_squared_v3v3(const float a[3], const float b[3])
{
float d[3];
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 18acbca00a1..725b6f8937a 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -618,14 +618,14 @@ void BLI_path_rel(char *file, const char *relfile)
*/
if (*q != '/') {
while ((q >= file) && (*q != '/')) {
- --q;
- --p;
+ q--;
+ p--;
}
}
else if (*p != '/') {
while ((p >= temp) && (*p != '/')) {
- --p;
- --q;
+ p--;
+ q--;
}
}
diff --git a/source/blender/blenlib/intern/polyfill_2d_beautify.c b/source/blender/blenlib/intern/polyfill_2d_beautify.c
index 3e94ae8de1f..ab397b86b1a 100644
--- a/source/blender/blenlib/intern/polyfill_2d_beautify.c
+++ b/source/blender/blenlib/intern/polyfill_2d_beautify.c
@@ -75,7 +75,7 @@ static int oedge_cmp(const void *a1, const void *a2)
return -1;
}
- /* only for pradictability */
+ /* Only for predictability. */
if (x1->e_half > x2->e_half) {
return 1;
}
@@ -100,6 +100,10 @@ BLI_INLINE bool is_boundary_edge(uint i_a, uint i_b, const uint coord_last)
* - When true, an existing zero area face on either side of the (2 - 4
* split will return a positive value.
* - When false, the check must be non-biased towards either split direction.
+ * \param r_area: Return the area of the quad,
+ * This can be useful when comparing the return value with near zero epsilons.
+ * In this case the epsilon can be scaled by the area to avoid the return value
+ * of very large faces not having a reliable way to detect near-zero output.
*
* \return (negative number means the edge can be rotated, lager == better).
*/
@@ -107,7 +111,8 @@ float BLI_polyfill_beautify_quad_rotate_calc_ex(const float v1[2],
const float v2[2],
const float v3[2],
const float v4[2],
- const bool lock_degenerate)
+ const bool lock_degenerate,
+ float *r_area)
{
/* not a loop (only to be able to break out) */
do {
@@ -121,6 +126,13 @@ float BLI_polyfill_beautify_quad_rotate_calc_ex(const float v1[2],
BLI_assert((ELEM(v1, v2, v3, v4) == false) && (ELEM(v2, v1, v3, v4) == false) &&
(ELEM(v3, v1, v2, v4) == false) && (ELEM(v4, v1, v2, v3) == false));
+
+ if (r_area) {
+ *r_area = fabsf(area_2x_234) + fabsf(area_2x_241) +
+ /* Include both pairs for predictable results. */
+ fabsf(area_2x_123) + fabsf(area_2x_134) / 8.0f;
+ }
+
/*
* Test for unusable (1-3) state.
* - Area sign flipping to check faces aren't going to point in opposite directions.
@@ -191,7 +203,8 @@ float BLI_polyfill_beautify_quad_rotate_calc_ex(const float v1[2],
static float polyedge_rotate_beauty_calc(const float (*coords)[2],
const struct HalfEdge *edges,
- const struct HalfEdge *e_a)
+ const struct HalfEdge *e_a,
+ float *r_area)
{
const struct HalfEdge *e_b = &edges[e_a->e_radial];
@@ -205,7 +218,7 @@ static float polyedge_rotate_beauty_calc(const float (*coords)[2],
v3 = coords[e_b_other->v];
v4 = coords[e_b->v];
- return BLI_polyfill_beautify_quad_rotate_calc(v1, v2, v3, v4);
+ return BLI_polyfill_beautify_quad_rotate_calc_ex(v1, v2, v3, v4, false, r_area);
}
static void polyedge_beauty_cost_update_single(const float (*coords)[2],
@@ -216,13 +229,18 @@ static void polyedge_beauty_cost_update_single(const float (*coords)[2],
{
const uint i = e->base_index;
/* recalculate edge */
- const float cost = polyedge_rotate_beauty_calc(coords, edges, e);
+ float area;
+ const float cost = polyedge_rotate_beauty_calc(coords, edges, e, &area);
/* We can get cases where both choices generate very small negative costs,
* which leads to infinite loop. Anyway, costs above that are not worth recomputing,
* maybe we could even optimize it to a smaller limit?
* Actually, FLT_EPSILON is too small in some cases, 1e-6f seems to work OK hopefully?
- * See T43578, T49478. */
- if (cost < -1e-6f) {
+ * See T43578, T49478.
+ *
+ * In fact a larger epsilon can still fail when the area of the face is very large,
+ * now the epsilon is scaled by the face area.
+ * See T56532. */
+ if (cost < -1e-6f * max_ff(area, 1.0f)) {
BLI_heap_insert_or_update(eheap, &eheap_table[i], cost, e);
}
else {
@@ -381,7 +399,7 @@ void BLI_polyfill_beautify(const float (*coords)[2],
for (uint i = 0; i < half_edges_len; i++, e++) {
/* Accounts for boundary edged too (UINT_MAX). */
if (e->e_radial < i) {
- const float cost = polyedge_rotate_beauty_calc(coords, half_edges, e);
+ const float cost = polyedge_rotate_beauty_calc(coords, half_edges, e, NULL);
if (cost < 0.0f) {
eheap_table[e->base_index] = BLI_heap_insert(eheap, cost, e);
}
diff --git a/source/blender/blenlib/intern/sort.c b/source/blender/blenlib/intern/sort.c
index 225015db00d..4ae87fff535 100644
--- a/source/blender/blenlib/intern/sort.c
+++ b/source/blender/blenlib/intern/sort.c
@@ -90,7 +90,7 @@ BLI_INLINE char *med3(char *a, char *b, char *c, BLI_sort_cmp_t cmp, void *thunk
}
/**
- * Quick sort reentrant.
+ * Quick sort re-entrant.
*/
void BLI_qsort_r(void *a, size_t n, size_t es, BLI_sort_cmp_t cmp, void *thunk)
{
diff --git a/source/blender/blenlib/intern/stack.c b/source/blender/blenlib/intern/stack.c
index 76aef3761ae..301675c026e 100644
--- a/source/blender/blenlib/intern/stack.c
+++ b/source/blender/blenlib/intern/stack.c
@@ -36,10 +36,6 @@
/* ensure we get at least this many elems per chunk */
#define CHUNK_ELEM_MIN 32
-/* Gets the last element in the stack */
-#define CHUNK_LAST_ELEM(_stack) \
- ((void)0, (((char *)(_stack)->chunk_curr->data) + ((_stack)->elem_size * (_stack)->chunk_index)))
-
struct StackChunk {
struct StackChunk *next;
char data[0];
@@ -56,6 +52,11 @@ struct BLI_Stack {
#endif
};
+static void *stack_get_last_elem(BLI_Stack *stack)
+{
+ return ((char *)(stack)->chunk_curr->data) + ((stack)->elem_size * (stack)->chunk_index);
+}
+
/**
* \return number of elements per chunk, optimized for slop-space.
*/
@@ -148,7 +149,7 @@ void *BLI_stack_push_r(BLI_Stack *stack)
#endif
/* Return end of stack */
- return CHUNK_LAST_ELEM(stack);
+ return stack_get_last_elem(stack);
}
/**
@@ -175,7 +176,7 @@ void BLI_stack_pop(BLI_Stack *stack, void *dst)
{
BLI_assert(BLI_stack_is_empty(stack) == false);
- memcpy(dst, CHUNK_LAST_ELEM(stack), stack->elem_size);
+ memcpy(dst, stack_get_last_elem(stack), stack->elem_size);
BLI_stack_discard(stack);
}
@@ -220,7 +221,7 @@ void *BLI_stack_peek(BLI_Stack *stack)
{
BLI_assert(BLI_stack_is_empty(stack) == false);
- return CHUNK_LAST_ELEM(stack);
+ return stack_get_last_elem(stack);
}
/**
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index 8d921b062dc..05a2d766fe0 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -230,14 +230,8 @@ int BLI_exists(const char *name)
tmp_16[3] = L'\0';
}
- /* change error mode so user does not get a "no disk in drive" popup
- * when looking for a file on an empty CD/DVD drive */
- old_error_mode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
-
res = BLI_wstat(tmp_16, &st);
- SetErrorMode(old_error_mode);
-
free(tmp_16);
if (res == -1) {
return (0);
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c
index 3b69e257f45..0b8ec44cbcd 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -663,8 +663,11 @@ static int left_number_strcmp(const char *s1, const char *s2, int *tiebreaker)
return 0;
}
-/* natural string compare, keeping numbers in order */
-int BLI_natstrcmp(const char *s1, const char *s2)
+/**
+ * Case insensitive, *natural* string comparison,
+ * keeping numbers in order.
+ */
+int BLI_strcasecmp_natural(const char *s1, const char *s2)
{
register int d1 = 0, d2 = 0;
register char c1, c2;
@@ -675,10 +678,7 @@ int BLI_natstrcmp(const char *s1, const char *s2)
* numeric, else do a tolower and char compare */
while (1) {
- c1 = tolower(s1[d1]);
- c2 = tolower(s2[d2]);
-
- if (isdigit(c1) && isdigit(c2)) {
+ if (isdigit(s1[d1]) && isdigit(s2[d2])) {
int numcompare = left_number_strcmp(s1 + d1, s2 + d2, &tiebreaker);
if (numcompare != 0) {
@@ -693,11 +693,11 @@ int BLI_natstrcmp(const char *s1, const char *s2)
while (isdigit(s2[d2])) {
d2++;
}
-
- c1 = tolower(s1[d1]);
- c2 = tolower(s2[d2]);
}
+ c1 = tolower(s1[d1]);
+ c2 = tolower(s2[d2]);
+
/* first check for '.' so "foo.bar" comes before "foo 1.bar" */
if (c1 == '.' && c2 != '.') {
return -1;
@@ -978,7 +978,7 @@ size_t BLI_str_partition_ex(const char *str,
*sep = *suf = NULL;
- for (d = delim; *d != '\0'; ++d) {
+ for (d = delim; *d != '\0'; d++) {
const char *tmp;
if (end) {
diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c
index 22c23727d76..92c4ec73768 100644
--- a/source/blender/blenlib/intern/string_utf8.c
+++ b/source/blender/blenlib/intern/string_utf8.c
@@ -716,7 +716,7 @@ size_t BLI_str_utf8_from_unicode(uint c, char *outbuf)
}
if (outbuf) {
- for (i = len - 1; i > 0; --i) {
+ for (i = len - 1; i > 0; i--) {
outbuf[i] = (c & 0x3f) | 0x80;
c >>= 6;
}
@@ -744,7 +744,7 @@ size_t BLI_str_utf8_from_unicode(uint c, char *outbuf)
*/
char *BLI_str_find_prev_char_utf8(const char *str, const char *p)
{
- for (--p; p >= str; --p) {
+ for (--p; p >= str; p--) {
if ((*p & 0xc0) != 0x80) {
return (char *)p;
}
@@ -771,12 +771,12 @@ char *BLI_str_find_next_char_utf8(const char *p, const char *end)
{
if (*p) {
if (end) {
- for (++p; p < end && (*p & 0xc0) == 0x80; ++p) {
+ for (++p; p < end && (*p & 0xc0) == 0x80; p++) {
/* do nothing */
}
}
else {
- for (++p; (*p & 0xc0) == 0x80; ++p) {
+ for (++p; (*p & 0xc0) == 0x80; p++) {
/* do nothing */
}
}
@@ -852,7 +852,7 @@ size_t BLI_str_partition_ex_utf8(const char *str,
break;
}
- for (d = delim; *d != '\0'; ++d) {
+ for (d = delim; *d != '\0'; d++) {
if (*d == c) {
/* *suf is already correct in case from_right is true. */
if (!from_right) {
diff --git a/source/blender/blenlib/intern/system.c b/source/blender/blenlib/intern/system.c
index 88f2e2625e8..941c2b608e6 100644
--- a/source/blender/blenlib/intern/system.c
+++ b/source/blender/blenlib/intern/system.c
@@ -179,6 +179,19 @@ char *BLI_cpu_brand_string(void)
return NULL;
}
+int BLI_cpu_support_sse41(void)
+{
+ int result[4], num;
+ __cpuid(result, 0);
+ num = result[0];
+
+ if (num >= 1) {
+ __cpuid(result, 0x00000001);
+ return (result[2] & ((int)1 << 19)) != 0;
+ }
+ return 0;
+}
+
void BLI_hostname_get(char *buffer, size_t bufsize)
{
#ifndef WIN32
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index 034a6d4017e..6cdaec97d9a 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -266,7 +266,7 @@ BLI_INLINE TaskThreadLocalStorage *get_task_tls(TaskPool *pool, const int thread
BLI_INLINE void free_task_tls(TaskThreadLocalStorage *tls)
{
TaskMemPool *task_mempool = &tls->task_mempool;
- for (int i = 0; i < task_mempool->num_tasks; ++i) {
+ for (int i = 0; i < task_mempool->num_tasks; i++) {
MEM_freeN(task_mempool->tasks[i]);
}
}
@@ -561,7 +561,7 @@ void BLI_task_scheduler_free(TaskScheduler *scheduler)
/* Delete task thread data */
if (scheduler->task_threads) {
- for (int i = 0; i < scheduler->num_threads + 1; ++i) {
+ for (int i = 0; i < scheduler->num_threads + 1; i++) {
TaskThreadLocalStorage *tls = &scheduler->task_threads[i].tls;
free_task_tls(tls);
}
@@ -732,9 +732,7 @@ static TaskPool *task_pool_create_ex(TaskScheduler *scheduler,
}
/**
- * Create a normal task pool.
- * This means that in single-threaded context, it will not be executed at all until you call
- * \a BLI_task_pool_work_and_wait() on it.
+ * Create a normal task pool. Tasks will be executed as soon as they are added.
*/
TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata)
{
@@ -779,7 +777,7 @@ void BLI_task_pool_free(TaskPool *pool)
#ifdef DEBUG_STATS
printf("Thread ID Allocated Reused Discarded\n");
- for (int i = 0; i < pool->scheduler->num_threads + 1; ++i) {
+ for (int i = 0; i < pool->scheduler->num_threads + 1; i++) {
printf("%02d %05d %05d %05d\n",
i,
pool->mempool_stats[i].num_alloc,
@@ -1066,22 +1064,28 @@ BLI_INLINE void task_parallel_range_calc_chunk_size(const TaskParallelSettings *
chunk_size = settings->min_iter_per_thread;
}
else {
- /* Basic heuristic to avoid threading on low amount of items. We could make that limit
- * configurable in settings too... */
- if (tot_items > 0 && tot_items < 256) {
- chunk_size = tot_items;
- }
- /* NOTE: The idea here is to compensate for rather measurable threading
+ /* Multiplier used in heuristics below to define "optimal" chunk size.
+ * The idea here is to increase the chunk size to compensate for a rather measurable threading
* overhead caused by fetching tasks. With too many CPU threads we are starting
- * to spend too much time in those overheads. */
- else if (num_tasks > 32) {
- chunk_size = 128;
- }
- else if (num_tasks > 16) {
- chunk_size = 64;
- }
- else {
- chunk_size = 32;
+ * to spend too much time in those overheads.
+ * First values are: 1 if num_tasks < 16;
+ * else 2 if num_tasks < 32;
+ * else 3 if num_tasks < 48;
+ * else 4 if num_tasks < 64;
+ * etc.
+ * Note: If we wanted to keep the 'power of two' multiplier, we'd need something like:
+ * 1 << max_ii(0, (int)(sizeof(int) * 8) - 1 - bitscan_reverse_i(num_tasks) - 3)
+ */
+ const int num_tasks_factor = max_ii(1, num_tasks >> 3);
+
+ /* We could make that 'base' 32 number configurable in TaskParallelSettings too, or maybe just
+ * always use that heuristic using TaskParallelSettings.min_iter_per_thread as basis? */
+ chunk_size = 32 * num_tasks_factor;
+
+ /* Basic heuristic to avoid threading on low amount of items.
+ * We could make that limit configurable in settings too. */
+ if (tot_items > 0 && tot_items < max_ii(256, chunk_size * 2)) {
+ chunk_size = tot_items;
}
}
@@ -1118,7 +1122,7 @@ static void parallel_range_func(TaskPool *__restrict pool, void *userdata_chunk,
};
int iter, count;
while (parallel_range_next_iter_get(state, &iter, &count)) {
- for (int i = 0; i < count; ++i) {
+ for (int i = 0; i < count; i++) {
state->func(state->userdata, iter + i, &tls);
}
}
@@ -1142,7 +1146,7 @@ static void parallel_range_single_thread(const int start,
.thread_id = 0,
.userdata_chunk = userdata_chunk_local,
};
- for (int i = start; i < stop; ++i) {
+ for (int i = start; i < stop; i++) {
func(userdata, i, &tls);
}
if (settings->func_finalize != NULL) {
@@ -1275,7 +1279,7 @@ BLI_INLINE Link *parallel_listbase_next_iter_get(ParallelListState *__restrict s
if (LIKELY(result != NULL)) {
*index = state->index;
while (state->link != NULL && task_count < state->chunk_size) {
- ++task_count;
+ task_count++;
state->link = state->link->next;
}
state->index += task_count;
@@ -1294,7 +1298,7 @@ static void parallel_listbase_func(TaskPool *__restrict pool,
int index, count;
while ((link = parallel_listbase_next_iter_get(state, &index, &count)) != NULL) {
- for (int i = 0; i < count; ++i) {
+ for (int i = 0; i < count; i++) {
state->func(state->userdata, link, index + i);
link = link->next;
}
@@ -1306,7 +1310,7 @@ static void task_parallel_listbase_no_threads(struct ListBase *listbase,
TaskParallelListbaseFunc func)
{
int i = 0;
- for (Link *link = listbase->first; link != NULL; link = link->next, ++i) {
+ for (Link *link = listbase->first; link != NULL; link = link->next, i++) {
func(userdata, link, i);
}
}
diff --git a/source/blender/blenlib/intern/voronoi_2d.c b/source/blender/blenlib/intern/voronoi_2d.c
index 29beb93159a..eb718c5e8c6 100644
--- a/source/blender/blenlib/intern/voronoi_2d.c
+++ b/source/blender/blenlib/intern/voronoi_2d.c
@@ -581,7 +581,7 @@ static void voronoi_clampEdges(ListBase *edges, int width, int height, ListBase
}
static int voronoi_getNextSideCoord(
- ListBase *edges, float coord[2], int dim, int dir, float next_coord[2])
+ ListBase *edges, const float coord[2], int dim, int dir, float next_coord[2])
{
VoronoiEdge *edge = edges->first;
float distance = FLT_MAX;
diff --git a/source/blender/blenlib/intern/winstuff.c b/source/blender/blenlib/intern/winstuff.c
index 9e6ea0bb6ee..724f27f4667 100644
--- a/source/blender/blenlib/intern/winstuff.c
+++ b/source/blender/blenlib/intern/winstuff.c
@@ -172,17 +172,7 @@ void RegisterBlendExtension(void)
BLI_getInstallationDir(InstallDir);
GetSystemDirectory(SysDir, FILE_MAXDIR);
-# ifdef _WIN64
- ThumbHandlerDLL = "BlendThumb64.dll";
-# else
- IsWow64Process(GetCurrentProcess(), &IsWOW64);
- if (IsWOW64 == true) {
- ThumbHandlerDLL = "BlendThumb64.dll";
- }
- else {
- ThumbHandlerDLL = "BlendThumb.dll";
- }
-# endif
+ ThumbHandlerDLL = "BlendThumb.dll";
snprintf(
RegCmd, MAX_PATH * 2, "%s\\regsvr32 /s \"%s\\%s\"", SysDir, InstallDir, ThumbHandlerDLL);
system(RegCmd);
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 2a036d7f4ea..545659d06c2 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -24,15 +24,12 @@
#include "zlib.h"
#include <limits.h>
-#include <stdio.h> // for printf fopen fwrite fclose sprintf FILE
-#include <stdlib.h> // for getenv atoi
-#include <stddef.h> // for offsetof
-#include <fcntl.h> // for open
-#include <string.h> // for strrchr strncmp strstr
-#include <math.h> // for fabs
-#include <stdarg.h> /* for va_start/end */
-#include <time.h> /* for gmtime */
-#include <ctype.h> /* for isdigit */
+#include <stdlib.h> /* for atoi. */
+#include <stddef.h> /* for offsetof. */
+#include <fcntl.h> /* for open flags (O_BINARY, O_RDONLY). */
+#include <stdarg.h> /* for va_start/end. */
+#include <time.h> /* for gmtime. */
+#include <ctype.h> /* for isdigit. */
#include "BLI_utildefines.h"
#ifndef WIN32
@@ -95,8 +92,6 @@
#include "DNA_movieclip_types.h"
#include "DNA_mask_types.h"
-#include "RNA_access.h"
-
#include "MEM_guardedalloc.h"
#include "BLI_endian_switch.h"
@@ -111,8 +106,6 @@
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_brush.h"
-#include "BKE_cachefile.h"
-#include "BKE_cloth.h"
#include "BKE_collection.h"
#include "BKE_colortools.h"
#include "BKE_constraint.h"
@@ -120,7 +113,6 @@
#include "BKE_effect.h"
#include "BKE_fcurve.h"
#include "BKE_global.h" // for G
-#include "BKE_gpencil.h"
#include "BKE_gpencil_modifier.h"
#include "BKE_idcode.h"
#include "BKE_idprop.h"
@@ -137,8 +129,6 @@
#include "BKE_multires.h"
#include "BKE_node.h" // for tree type defines
#include "BKE_object.h"
-#include "BKE_ocean.h"
-#include "BKE_outliner_treehash.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
@@ -184,7 +174,7 @@
* - read associated 'direct data'
* - link direct data (internal and to LibBlock)
* - read #FileGlobal
- * - read #USER data, only when indicated (file is ``~/X.XX/startup.blend``)
+ * - read #USER data, only when indicated (file is `~/.config/blender/X.XX/config/userpref.blend`)
* - free file
* - per Library (per #Main)
* - read file
@@ -233,7 +223,7 @@
#define USE_GHASH_RESTORE_POINTER
/* Define this to have verbose debug prints. */
-#define USE_DEBUG_PRINT
+//#define USE_DEBUG_PRINT
#ifdef USE_DEBUG_PRINT
# define DEBUG_PRINTF(...) printf(__VA_ARGS__)
@@ -2597,7 +2587,7 @@ static PreviewImage *direct_link_preview_image(FileData *fd, PreviewImage *old_p
if (prv) {
int i;
- for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ for (i = 0; i < NUM_ICON_SIZES; i++) {
if (prv->rect[i]) {
prv->rect[i] = newdataadr(fd, prv->rect[i]);
}
@@ -2667,6 +2657,7 @@ static void direct_link_id(FileData *fd, ID *id)
* function are still in a clear tag state.
* (glowering at certain nodetree fake data-lock here...). */
id->tag = 0;
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
/* Link direct data of overrides. */
if (id->override_library) {
@@ -2838,6 +2829,12 @@ static PackedFile *direct_link_packedfile(FileData *fd, PackedFile *oldpf)
if (pf) {
pf->data = newpackedadr(fd, pf->data);
+ if (pf->data == NULL) {
+ /* We cannot allow a PackedFile with a NULL data field,
+ * the whole code assumes this is not possible. See T70315. */
+ printf("%s: NULL packedfile data, cleaning up...\n", __func__);
+ MEM_SAFE_FREE(pf);
+ }
}
return pf;
@@ -4382,7 +4379,7 @@ static void direct_link_curve(FileData *fd, Curve *cu)
switch_endian_knots(nu);
}
}
- cu->bb = NULL;
+ cu->texflag &= ~CU_AUTOSPACE_EVALUATED;
}
/** \} */
@@ -4938,7 +4935,7 @@ static void direct_link_mdisps(FileData *fd, int count, MDisps *mdisps, int exte
if (mdisps) {
int i;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
mdisps[i].disps = newdataadr(fd, mdisps[i].disps);
mdisps[i].hidden = newdataadr(fd, mdisps[i].hidden);
@@ -4968,7 +4965,7 @@ static void direct_link_grid_paint_mask(FileData *fd, int count, GridPaintMask *
if (grid_paint_mask) {
int i;
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
GridPaintMask *gpm = &grid_paint_mask[i];
if (gpm->data) {
gpm->data = newdataadr(fd, gpm->data);
@@ -5049,7 +5046,7 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
direct_link_customdata(fd, &mesh->ldata, mesh->totloop);
direct_link_customdata(fd, &mesh->pdata, mesh->totpoly);
- mesh->bb = NULL;
+ mesh->texflag &= ~ME_AUTOSPACE_EVALUATED;
mesh->edit_mesh = NULL;
BKE_mesh_runtime_reset(mesh);
@@ -5339,8 +5336,8 @@ static void lib_link_object(FileData *fd, Main *main)
eModifierType_Smoke);
if (smd && (smd->type == MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
- smd->domain->flags |=
- MOD_SMOKE_FILE_LOAD; /* flag for refreshing the simulation after loading */
+ /* Flag for refreshing the simulation after loading. */
+ smd->domain->flags |= MOD_SMOKE_FILE_LOAD;
}
}
@@ -5753,8 +5750,8 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
}
/* runtime only */
- csmd->delta_cache = NULL;
- csmd->delta_cache_num = 0;
+ csmd->delta_cache.deltas = NULL;
+ csmd->delta_cache.totverts = 0;
}
else if (md->type == eModifierType_MeshSequenceCache) {
MeshSeqCacheModifierData *msmcd = (MeshSeqCacheModifierData *)md;
@@ -6344,7 +6341,7 @@ static void direct_link_lightcache(FileData *fd, LightCache *cache)
if (cache->cube_mips) {
cache->cube_mips = newdataadr(fd, cache->cube_mips);
- for (int i = 0; i < cache->mips_len; ++i) {
+ for (int i = 0; i < cache->mips_len; i++) {
direct_link_lightcache_texture(fd, &cache->cube_mips[i]);
}
}
@@ -6353,6 +6350,14 @@ static void direct_link_lightcache(FileData *fd, LightCache *cache)
cache->grid_data = newdataadr(fd, cache->grid_data);
}
+static void direct_link_view3dshading(FileData *fd, View3DShading *shading)
+{
+ if (shading->prop) {
+ shading->prop = newdataadr(fd, shading->prop);
+ IDP_DirectLinkGroup_OrFree(&shading->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ }
+}
+
/* check for cyclic set-scene,
* libs can cause this case which is normally prevented, see (T#####) */
#define USE_SETSCENE_CHECK
@@ -6755,6 +6760,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
ed->act_seq = newdataadr(fd, ed->act_seq);
ed->cache = NULL;
+ ed->prefetch_job = NULL;
/* recursive link sequences, lb will be correctly initialized */
link_recurs_seq(fd, &ed->seqbase);
@@ -6987,6 +6993,8 @@ static void direct_link_scene(FileData *fd, Scene *sce)
}
}
+ direct_link_view3dshading(fd, &sce->display.shading);
+
sce->layer_properties = newdataadr(fd, sce->layer_properties);
IDP_DirectLinkGroup_OrFree(&sce->layer_properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
@@ -7150,6 +7158,8 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype)
rv3d->render_engine = NULL;
rv3d->sms = NULL;
rv3d->smooth_timer = NULL;
+
+ rv3d->rflag &= ~(RV3D_NAVIGATING | RV3D_PAINTING);
}
}
}
@@ -7255,6 +7265,8 @@ static void direct_link_area(FileData *fd, ScrArea *area)
v3d->fx_settings.ssao = newdataadr(fd, v3d->fx_settings.ssao);
}
+ direct_link_view3dshading(fd, &v3d->shading);
+
blo_do_versions_view3d_split_250(v3d, &sl->regionbase);
}
else if (sl->spacetype == SPACE_GRAPH) {
@@ -7859,6 +7871,45 @@ static void lib_link_clipboard_restore(struct IDNameLib_Map *id_map)
BKE_sequencer_base_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, id_map);
}
+static int lib_link_main_data_restore_cb(void *user_data,
+ ID *UNUSED(id_self),
+ ID **id_pointer,
+ int cb_flag)
+{
+ if (cb_flag & IDWALK_CB_PRIVATE || *id_pointer == NULL) {
+ return IDWALK_RET_NOP;
+ }
+
+ /* Special ugly case here, thanks again for those non-IDs IDs... */
+ /* We probably need to add more cases here (hint: nodetrees),
+ * but will wait for changes from D5559 to get in first. */
+ if (GS((*id_pointer)->name) == ID_GR) {
+ Collection *collection = (Collection *)*id_pointer;
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ return IDWALK_RET_NOP;
+ }
+ }
+
+ struct IDNameLib_Map *id_map = user_data;
+
+ /* Note: Handling of usercount here is really bad, defining its own system...
+ * Will have to be refactored at some point, but that is not top priority task for now.
+ * And all usercounts are properly recomputed at the end of the undo management code anyway. */
+ *id_pointer = restore_pointer_by_name(
+ id_map, *id_pointer, (cb_flag & IDWALK_CB_USER_ONE) ? USER_REAL : USER_IGNORE);
+
+ return IDWALK_RET_NOP;
+}
+
+static void lib_link_main_data_restore(struct IDNameLib_Map *id_map, Main *newmain)
+{
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (newmain, id) {
+ BKE_library_foreach_ID_link(newmain, id, lib_link_main_data_restore_cb, id_map, IDWALK_NOP);
+ }
+ FOREACH_MAIN_ID_END;
+}
+
static void lib_link_window_scene_data_restore(wmWindow *win, Scene *scene, ViewLayer *view_layer)
{
bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
@@ -8178,11 +8229,24 @@ void blo_lib_link_restore(Main *oldmain,
/* keep cursor location through undo */
memcpy(&win->scene->cursor, &oldscene->cursor, sizeof(win->scene->cursor));
+ /* Note: even though that function seems to redo part of what is done by
+ * `lib_link_workspace_layout_restore()` above, it seems to have a slightly different scope:
+ * while the former updates the whole UI pointers from Main db (going over all layouts of
+ * all workspaces), that one only focuses one current active screen, takes care of
+ * potential local view, and needs window's scene pointer to be final... */
lib_link_window_scene_data_restore(win, win->scene, cur_view_layer);
BLI_assert(win->screen == NULL);
}
+ /* Restore all ID pointers in Main database itself
+ * (especially IDProperties might point to some worspace of other 'weirdly unchanged' ID
+ * pointers, see T69146).
+ * Note that this will re;ap again a few pointers in workspaces or so,
+ * but since we are remapping final ones already set above,
+ * that is just some minor harmless double-processing. */
+ lib_link_main_data_restore(id_map, newmain);
+
/* update IDs stored in all possible clipboards */
lib_link_clipboard_restore(id_map);
@@ -9070,7 +9134,12 @@ static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *a
return bhead;
}
-static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const int tag, ID **r_id)
+static BHead *read_libblock(FileData *fd,
+ Main *main,
+ BHead *bhead,
+ const int tag,
+ const bool placeholder_set_indirect_extern,
+ ID **r_id)
{
/* this routine reads a libblock and its direct data. Use link functions to connect it all
*/
@@ -9190,7 +9259,16 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const int ta
/* this case cannot be direct_linked: it's just the ID part */
if (bhead->code == ID_LINK_PLACEHOLDER) {
/* That way, we know which data-lock needs do_versions (required currently for linking). */
- id->tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW;
+ id->tag = tag | LIB_TAG_ID_LINK_PLACEHOLDER | LIB_TAG_NEED_LINK | LIB_TAG_NEW;
+
+ if (placeholder_set_indirect_extern) {
+ if (id->flag & LIB_INDIRECT_WEAK_LINK) {
+ id->tag |= LIB_TAG_INDIRECT;
+ }
+ else {
+ id->tag |= LIB_TAG_EXTERN;
+ }
+ }
return blo_bhead_next(fd, bhead);
}
@@ -9753,8 +9831,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
* to the file format definition. So we can use the entry at the
* end of mainlist, added in direct_link_library. */
Main *libmain = mainlist.last;
- bhead = read_libblock(
- fd, libmain, bhead, LIB_TAG_ID_LINK_PLACEHOLDER | LIB_TAG_EXTERN, NULL);
+ bhead = read_libblock(fd, libmain, bhead, 0, true, NULL);
}
break;
/* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
@@ -9767,7 +9844,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
bhead = blo_bhead_next(fd, bhead);
}
else {
- bhead = read_libblock(fd, bfd->main, bhead, LIB_TAG_LOCAL, NULL);
+ bhead = read_libblock(fd, bfd->main, bhead, LIB_TAG_LOCAL, false, NULL);
}
}
}
@@ -10015,7 +10092,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_ID_LINK_PLACEHOLDER | LIB_TAG_INDIRECT, NULL);
+ read_libblock(fd, libmain, bhead, 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->name);
@@ -10023,6 +10100,12 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
libmain->curlib->parent = mainvar->curlib;
}
else {
+ /* Convert any previously read weak link to regular link
+ * to signal that we want to read this datablock. */
+ if (id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) {
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
+ }
+
/* "id" is either a placeholder or real ID that is already in the
* main of the library (A) it belongs to. However it might have been
* put there by another library (C) which only updated its own
@@ -10064,9 +10147,15 @@ 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, NULL);
+ read_libblock(fd, mainvar, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, false, NULL);
}
else {
+ /* Convert any previously read weak link to regular link
+ * to signal that we want to read this datablock. */
+ if (id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) {
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
+ }
+
/* this is actually only needed on UI call? when ID was already read before,
* and another append happens which invokes same ID...
* in that case the lookup table needs this entry */
@@ -11200,6 +11289,7 @@ static void add_loose_objects_to_scene(Main *mainvar,
BKE_scene_object_base_flag_sync_from_base(base);
ob->id.tag &= ~LIB_TAG_INDIRECT;
+ ob->id.flag &= ~LIB_INDIRECT_WEAK_LINK;
ob->id.tag |= LIB_TAG_EXTERN;
}
}
@@ -11292,6 +11382,7 @@ static void add_collections_to_scene(Main *mainvar,
/* Those are kept for safety and consistency, but should not be needed anymore? */
collection->id.tag &= ~LIB_TAG_INDIRECT;
+ collection->id.flag &= ~LIB_INDIRECT_WEAK_LINK;
collection->id.tag |= LIB_TAG_EXTERN;
}
}
@@ -11316,7 +11407,7 @@ static ID *link_named_part(
if (id == NULL) {
/* not read yet */
const int tag = force_indirect ? LIB_TAG_INDIRECT : LIB_TAG_EXTERN;
- read_libblock(fd, mainl, bhead, tag | LIB_TAG_NEED_EXPAND, &id);
+ read_libblock(fd, mainl, bhead, tag | LIB_TAG_NEED_EXPAND, false, &id);
if (id) {
/* sort by name in list */
@@ -11332,6 +11423,7 @@ static ID *link_named_part(
oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code);
if (!force_indirect && (id->tag & LIB_TAG_INDIRECT)) {
id->tag &= ~LIB_TAG_INDIRECT;
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
id->tag |= LIB_TAG_EXTERN;
}
}
@@ -11370,7 +11462,7 @@ int BLO_library_link_copypaste(Main *mainl, BlendHandle *bh, const unsigned int
if (BKE_idcode_is_valid(bhead->code) && BKE_idcode_is_linkable(bhead->code) &&
(id_types_mask == 0 ||
(BKE_idcode_to_idfilter((short)bhead->code) & id_types_mask) != 0)) {
- read_libblock(fd, mainl, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, &id);
+ read_libblock(fd, mainl, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, false, &id);
num_directly_linked++;
}
@@ -11656,7 +11748,7 @@ static int has_linked_ids_to_read(Main *mainvar)
while (a--) {
for (ID *id = lbarray[a]->first; id; id = id->next) {
- if (id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) {
+ if ((id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) && !(id->flag & LIB_INDIRECT_WEAK_LINK)) {
return true;
}
}
@@ -11687,11 +11779,12 @@ static void read_library_linked_id(
}
id->tag &= ~LIB_TAG_ID_LINK_PLACEHOLDER;
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
if (bhead) {
id->tag |= LIB_TAG_NEED_EXPAND;
// printf("read lib block %s\n", id->name);
- read_libblock(fd, mainvar, bhead, id->tag, r_id);
+ read_libblock(fd, mainvar, bhead, id->tag, false, r_id);
}
else {
blo_reportf_wrap(reports,
@@ -11725,7 +11818,7 @@ static void read_library_linked_ids(FileData *basefd,
while (id) {
ID *id_next = id->next;
- if (id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) {
+ if ((id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) && !(id->flag & LIB_INDIRECT_WEAK_LINK)) {
BLI_remlink(lbarray[a], id);
/* When playing with lib renaming and such, you may end with cases where
@@ -11761,6 +11854,28 @@ static void read_library_linked_ids(FileData *basefd,
BLI_ghash_free(loaded_ids, NULL, NULL);
}
+static void read_library_clear_weak_links(FileData *basefd, ListBase *mainlist, Main *mainvar)
+{
+ /* Any remaining weak links at this point have been lost, silently drop
+ * those by setting them to NULL pointers. */
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a = set_listbasepointers(mainvar, lbarray);
+
+ while (a--) {
+ ID *id = lbarray[a]->first;
+
+ while (id) {
+ ID *id_next = id->next;
+ if ((id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) && (id->flag & LIB_INDIRECT_WEAK_LINK)) {
+ /* printf("Dropping weak link to %s\n", id->name); */
+ change_link_placeholder_to_real_ID_pointer(mainlist, basefd, id, NULL);
+ BLI_freelinkN(lbarray[a], id);
+ }
+ id = id_next;
+ }
+ }
+}
+
static FileData *read_library_file_data(FileData *basefd,
ListBase *mainlist,
Main *mainl,
@@ -11887,6 +12002,9 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
Main *main_newid = BKE_main_new();
for (Main *mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
+ /* Drop weak links for which no datablock was found. */
+ read_library_clear_weak_links(basefd, mainlist, mainptr);
+
/* Do versioning for newly added linked data-locks. If no data-locks
* were read from a library versionfile will still be zero and we can
* skip it. */
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index ba4dc2d33c7..72013bc6eed 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -67,7 +67,6 @@
#include "BKE_global.h" // for G
#include "BKE_library.h"
#include "BKE_main.h"
-#include "BKE_mesh.h" // for ME_ defines (patching)
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_particle.h"
@@ -1697,7 +1696,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
/* will have no effect */
if (brush->alpha == 0) {
- brush->alpha = 0.5f;
+ brush->alpha = 1.0f;
}
/* bad radius */
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 6f5c37d716e..4e0be8ceb9c 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -41,6 +41,8 @@
#include "DNA_sdna_types.h"
#include "DNA_smoke_types.h"
#include "DNA_space_types.h"
+#include "DNA_world_types.h"
+#include "DNA_light_types.h"
#include "MEM_guardedalloc.h"
@@ -63,7 +65,10 @@
#include "BKE_text.h" // for txt_extended_ascii_as_utf8
#include "BKE_texture.h"
#include "BKE_tracking.h"
-#include "BKE_writeffmpeg.h"
+
+#ifdef WITH_FFMPEG
+# include "BKE_writeffmpeg.h"
+#endif
#include "IMB_imbuf.h" // for proxy / timecode versioning stuff
@@ -2606,7 +2611,7 @@ void do_versions_after_linking_260(Main *bmain)
if (input_node) {
link->fromnode = input_node;
link->fromsock = node_group_input_find_socket(input_node, link->fromsock->identifier);
- ++num_inputs;
+ num_inputs++;
if (link->tonode) {
if (input_locx > link->tonode->locx - offsetx) {
@@ -2624,7 +2629,7 @@ void do_versions_after_linking_260(Main *bmain)
if (output_node) {
link->tonode = output_node;
link->tosock = node_group_output_find_socket(output_node, link->tosock->identifier);
- ++num_outputs;
+ num_outputs++;
if (link->fromnode) {
if (output_locx < link->fromnode->locx + offsetx) {
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index b61692799ed..a3dc177262e 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -48,14 +48,13 @@
#include "DNA_view3d_types.h"
#include "DNA_smoke_types.h"
#include "DNA_rigidbody_types.h"
+#include "DNA_light_types.h"
#include "DNA_genfile.h"
#include "BKE_animsys.h"
-#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_fcurve.h"
-#include "BKE_gpencil.h"
#include "BKE_main.h"
#include "BKE_mask.h"
#include "BKE_modifier.h"
@@ -1747,8 +1746,9 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!DNA_struct_elem_find(fd->filesdna, "Brush", "float", "falloff_angle")) {
for (Brush *br = bmain->brushes.first; br; br = br->id.next) {
br->falloff_angle = DEG2RADF(80);
- br->flag &= ~(BRUSH_FLAG_UNUSED_1 | BRUSH_FLAG_UNUSED_6 | BRUSH_FLAG_UNUSED_7 |
- BRUSH_FLAG_UNUSED_17 | BRUSH_FRONTFACE_FALLOFF);
+ /* These flags are used for new feautres. They are not related to falloff_angle */
+ br->flag &= ~(BRUSH_FLAG_UNUSED_1 | BRUSH_ORIGINAL_PLANE | BRUSH_GRAB_ACTIVE_VERTEX |
+ BRUSH_SCENE_SPACING | BRUSH_FRONTFACE_FALLOFF);
}
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index d2017864192..7ea1d25f86d 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -55,8 +55,8 @@
#include "DNA_curve_types.h"
#include "DNA_armature_types.h"
#include "DNA_text_types.h"
+#include "DNA_world_types.h"
-#include "BKE_action.h"
#include "BKE_animsys.h"
#include "BKE_cloth.h"
#include "BKE_collection.h"
@@ -65,22 +65,17 @@
#include "BKE_customdata.h"
#include "BKE_fcurve.h"
#include "BKE_freestyle.h"
-#include "BKE_gpencil.h"
#include "BKE_idprop.h"
-#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_library.h"
#include "BKE_layer.h"
#include "BKE_main.h"
-#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_node.h"
-#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_pointcache.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
-#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_sequencer.h"
#include "BKE_studiolight.h"
@@ -406,7 +401,7 @@ static void do_version_layers_to_collections(Main *bmain, Scene *scene)
}
/* Create collections from layers. */
- Collection *collection_master = BKE_collection_master(scene);
+ Collection *collection_master = scene->master_collection;
Collection *collections[20] = {NULL};
for (int layer = 0; layer < 20; layer++) {
@@ -637,6 +632,18 @@ static void do_version_bones_split_bbone_scale(ListBase *lb)
}
}
+static void do_version_bones_inherit_scale(ListBase *lb)
+{
+ for (Bone *bone = lb->first; bone; bone = bone->next) {
+ if (bone->flag & BONE_NO_SCALE) {
+ bone->inherit_scale_mode = BONE_INHERIT_SCALE_NONE_LEGACY;
+ bone->flag &= ~BONE_NO_SCALE;
+ }
+
+ do_version_bones_inherit_scale(&bone->childbase);
+ }
+}
+
static bool replace_bbone_scale_rnapath(char **p_old_path)
{
char *old_path = *p_old_path;
@@ -715,6 +722,17 @@ static void do_version_constraints_copy_scale_power(ListBase *lb)
}
}
+static void do_version_constraints_copy_rotation_mix_mode(ListBase *lb)
+{
+ for (bConstraint *con = lb->first; con; con = con->next) {
+ if (con->type == CONSTRAINT_TYPE_ROTLIKE) {
+ bRotateLikeConstraint *data = (bRotateLikeConstraint *)con->data;
+ data->mix_mode = (data->flag & ROTLIKE_OFFSET) ? ROTLIKE_MIX_OFFSET : ROTLIKE_MIX_REPLACE;
+ data->flag &= ~ROTLIKE_OFFSET;
+ }
+ }
+}
+
static void do_versions_seq_alloc_transform_and_crop(ListBase *seqbase)
{
for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) {
@@ -825,6 +843,14 @@ static void do_versions_material_convert_legacy_blend_mode(bNodeTree *ntree, cha
}
}
+static void do_versions_local_collection_bits_set(LayerCollection *layer_collection)
+{
+ layer_collection->local_collections_bits = ~(0);
+ LISTBASE_FOREACH (LayerCollection *, child, &layer_collection->layer_collections) {
+ do_versions_local_collection_bits_set(child);
+ }
+}
+
void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
{
bool use_collection_compat_28 = true;
@@ -1430,7 +1456,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
ToolSettings *ts = scene->toolsettings;
/* sculpt brushes */
GP_Sculpt_Settings *gset = &ts->gp_sculpt;
- for (int i = 0; i < GP_SCULPT_TYPE_MAX; ++i) {
+ for (int i = 0; i < GP_SCULPT_TYPE_MAX; i++) {
gp_brush = &gset->brush[i];
gp_brush->flag |= GP_SCULPT_FLAG_ENABLE_CURSOR;
copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
@@ -1842,7 +1868,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
EEVEE_GET_BOOL(props, shadow_high_bitdepth, SCE_EEVEE_SHADOW_HIGH_BITDEPTH);
EEVEE_GET_BOOL(props, taa_reprojection, SCE_EEVEE_TAA_REPROJECTION);
// EEVEE_GET_BOOL(props, sss_enable, SCE_EEVEE_SSS_ENABLED);
- EEVEE_GET_BOOL(props, sss_separate_albedo, SCE_EEVEE_SSS_SEPARATE_ALBEDO);
+ // EEVEE_GET_BOOL(props, sss_separate_albedo, SCE_EEVEE_SSS_SEPARATE_ALBEDO);
EEVEE_GET_BOOL(props, ssr_enable, SCE_EEVEE_SSR_ENABLED);
EEVEE_GET_BOOL(props, ssr_refraction, SCE_EEVEE_SSR_REFRACTION);
EEVEE_GET_BOOL(props, ssr_halfres, SCE_EEVEE_SSR_HALF_RESOLUTION);
@@ -2895,7 +2921,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
case SPACE_VIEW3D: {
View3D *v3d = (View3D *)sl;
- v3d->flag &= ~(V3D_FLAG_UNUSED_0 | V3D_FLAG_UNUSED_1 | V3D_FLAG_UNUSED_10 |
+ v3d->flag &= ~(V3D_LOCAL_COLLECTIONS | V3D_FLAG_UNUSED_1 | V3D_FLAG_UNUSED_10 |
V3D_FLAG_UNUSED_12);
v3d->flag2 &= ~(V3D_FLAG2_UNUSED_3 | V3D_FLAG2_UNUSED_6 | V3D_FLAG2_UNUSED_12 |
V3D_FLAG2_UNUSED_13 | V3D_FLAG2_UNUSED_14 | V3D_FLAG2_UNUSED_15);
@@ -3693,7 +3719,188 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 4)) {
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ bNodeTree *ntree = ntreeFromID(id);
+ if (ntree) {
+ ntree->id.flag |= LIB_PRIVATE_DATA;
+ }
+ }
+ FOREACH_MAIN_ID_END;
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 5)) {
+ for (Brush *br = bmain->brushes.first; br; br = br->id.next) {
+ if (br->ob_mode & OB_MODE_SCULPT && br->normal_radius_factor == 0.0f) {
+ br->normal_radius_factor = 0.5f;
+ }
+ }
+
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ /* Older files do not have a master collection, which is then added through
+ * `BKE_collection_master_add()`, so everything is fine. */
+ if (scene->master_collection != NULL) {
+ scene->master_collection->id.flag |= LIB_PRIVATE_DATA;
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 6)) {
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->shading.flag |= V3D_SHADING_SCENE_LIGHTS_RENDER | V3D_SHADING_SCENE_WORLD_RENDER;
+
+ /* files by default don't have studio lights selected unless interacted
+ * with the shading popover. When no studiolight could be read, we will
+ * select the default world one. */
+ StudioLight *studio_light = BKE_studiolight_find(v3d->shading.lookdev_light,
+ STUDIOLIGHT_TYPE_WORLD);
+ if (studio_light != NULL) {
+ STRNCPY(v3d->shading.lookdev_light, studio_light->name);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 9)) {
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = (SpaceFile *)sl;
+ ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ ARegion *ar_ui = do_versions_find_region(regionbase, RGN_TYPE_UI);
+ ARegion *ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER);
+ ARegion *ar_toolprops = do_versions_find_region_or_null(regionbase,
+ RGN_TYPE_TOOL_PROPS);
+
+ /* Reinsert UI region so that it spawns entire area width */
+ BLI_remlink(regionbase, ar_ui);
+ BLI_insertlinkafter(regionbase, ar_header, ar_ui);
+
+ ar_ui->flag |= RGN_FLAG_DYNAMIC_SIZE;
+
+ if (ar_toolprops && (ar_toolprops->alignment == (RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV))) {
+ SpaceType *stype = BKE_spacetype_from_id(sl->spacetype);
+
+ /* Remove empty region at old location. */
+ BLI_assert(sfile->op == NULL);
+ BKE_area_region_free(stype, ar_toolprops);
+ BLI_freelinkN(regionbase, ar_toolprops);
+ }
+
+ if (sfile->params) {
+ sfile->params->details_flags |= FILE_DETAILS_SIZE | FILE_DETAILS_DATETIME;
+ }
+ }
+ }
+ }
+ }
+
+ /* Convert the BONE_NO_SCALE flag to inherit_scale_mode enum. */
+ if (!DNA_struct_elem_find(fd->filesdna, "Bone", "char", "inherit_scale_mode")) {
+ LISTBASE_FOREACH (bArmature *, arm, &bmain->armatures) {
+ do_version_bones_inherit_scale(&arm->bonebase);
+ }
+ }
+
+ /* Convert the Offset flag to the mix mode enum. */
+ if (!DNA_struct_elem_find(fd->filesdna, "bRotateLikeConstraint", "char", "mix_mode")) {
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ do_version_constraints_copy_rotation_mix_mode(&ob->constraints);
+ if (ob->pose) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+ do_version_constraints_copy_rotation_mix_mode(&pchan->constraints);
+ }
+ }
+ }
+ }
+
+ /* Added studiolight intensity */
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "studiolight_intensity")) {
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->shading.studiolight_intensity = 1.0f;
+ }
+ }
+ }
+ }
+ }
+
+ /* Elatic deform brush */
+ for (Brush *br = bmain->brushes.first; br; br = br->id.next) {
+ if (br->ob_mode & OB_MODE_SCULPT && br->elastic_deform_volume_preservation == 0.0f) {
+ br->elastic_deform_volume_preservation = 0.5f;
+ }
+ }
+ }
+
{
/* Versioning code until next subversion bump goes here. */
+ if (!DNA_struct_elem_find(
+ fd->filesdna, "LayerCollection", "short", "local_collections_bits")) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ LISTBASE_FOREACH (LayerCollection *, layer_collection, &view_layer->layer_collections) {
+ do_versions_local_collection_bits_set(layer_collection);
+ }
+ }
+ }
+ }
+
+ /* Fix wrong 3D viewport copying causing corrupt pointers (T69974). */
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+
+ for (ScrArea *sa_other = screen->areabase.first; sa_other; sa_other = sa_other->next) {
+ for (SpaceLink *sl_other = sa_other->spacedata.first; sl_other;
+ sl_other = sl_other->next) {
+ if (sl != sl_other && sl_other->spacetype == SPACE_VIEW3D) {
+ View3D *v3d_other = (View3D *)sl_other;
+
+ if (v3d->shading.prop == v3d_other->shading.prop) {
+ v3d_other->shading.prop = NULL;
+ }
+ }
+ }
+ }
+ }
+ else if (sl->spacetype == SPACE_FILE) {
+ ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ ARegion *ar_tools = do_versions_find_region_or_null(regionbase, RGN_TYPE_TOOLS);
+ ARegion *ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER);
+
+ if (ar_tools) {
+ ARegion *ar_next = ar_tools->next;
+
+ /* We temporarily had two tools regions, get rid of the second one. */
+ if (ar_next && ar_next->regiontype == RGN_TYPE_TOOLS) {
+ do_versions_remove_region(regionbase, RGN_TYPE_TOOLS);
+ }
+
+ BLI_remlink(regionbase, ar_tools);
+ BLI_insertlinkafter(regionbase, ar_header, ar_tools);
+ }
+ else {
+ ar_tools = do_versions_add_region(RGN_TYPE_TOOLS, "versioning file tools region");
+ BLI_insertlinkafter(regionbase, ar_header, ar_tools);
+ ar_tools->alignment = RGN_ALIGN_LEFT;
+ }
+ }
+ }
+ }
+ }
}
}
diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c
index a3e9b8dc206..2c4ba4a1102 100644
--- a/source/blender/blenloader/intern/versioning_cycles.c
+++ b/source/blender/blenloader/intern/versioning_cycles.c
@@ -34,12 +34,16 @@
#include "DNA_node_types.h"
#include "DNA_particle_types.h"
#include "DNA_camera_types.h"
+#include "DNA_anim_types.h"
#include "BKE_colortools.h"
+#include "BKE_animsys.h"
#include "BKE_idprop.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "MEM_guardedalloc.h"
+
#include "IMB_colormanagement.h"
#include "BLO_readfile.h"
@@ -756,6 +760,424 @@ static void update_vector_math_node_average_operator(bNodeTree *ntree)
}
}
+/* The Noise node now have a dimension property. This property should be
+ * initialized to 3 by default.
+ */
+static void update_noise_node_dimensions(bNodeTree *ntree)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_NOISE) {
+ NodeTexNoise *tex = (NodeTexNoise *)node->storage;
+ tex->dimensions = 3;
+ }
+ }
+}
+
+/* The Mapping node has been rewritten to support dynamic inputs. Previously,
+ * the transformation information was stored in a TexMapping struct in the
+ * node->storage member of bNode. Currently, the transformation information
+ * is stored in input sockets. To correct this, we transfer the information
+ * from the TexMapping struct to the input sockets.
+ *
+ * Additionally, the Minimum and Maximum properties are no longer available
+ * in the node. To correct this, a Vector Minimum and/or a Vector Maximum
+ * nodes are added if needed.
+ *
+ * Finally, the TexMapping struct is freed and node->storage is set to NULL.
+ *
+ * Since the RNA paths of the properties changed, we also have to update the
+ * rna_path of the FCurves if they exist. To do that, we loop over FCurves
+ * and check if they control a property of the node, if they do, we update
+ * the path to be that of the corresponding socket in the node or the added
+ * minimum/maximum node.
+ *
+ */
+static void update_mapping_node_inputs_and_properties(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ /* If node->storage is NULL, then conversion has already taken place.
+ * This can happen if a file with the new mapping node [saved from (2, 81, 8) or newer]
+ * is opened in a blender version prior to (2, 81, 8) and saved from there again. */
+ if (node->type == SH_NODE_MAPPING && node->storage) {
+ TexMapping *mapping = (TexMapping *)node->storage;
+ node->custom1 = mapping->type;
+ node->width = 140.0f;
+
+ bNodeSocket *sockLocation = nodeFindSocket(node, SOCK_IN, "Location");
+ copy_v3_v3(cycles_node_socket_vector_value(sockLocation), mapping->loc);
+ bNodeSocket *sockRotation = nodeFindSocket(node, SOCK_IN, "Rotation");
+ copy_v3_v3(cycles_node_socket_vector_value(sockRotation), mapping->rot);
+ bNodeSocket *sockScale = nodeFindSocket(node, SOCK_IN, "Scale");
+ copy_v3_v3(cycles_node_socket_vector_value(sockScale), mapping->size);
+
+ bNode *maximumNode = NULL;
+ if (mapping->flag & TEXMAP_CLIP_MIN) {
+ maximumNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+ maximumNode->custom1 = NODE_VECTOR_MATH_MAXIMUM;
+ if (mapping->flag & TEXMAP_CLIP_MAX) {
+ maximumNode->locx = node->locx + (node->width + 20.0f) * 2.0f;
+ }
+ else {
+ maximumNode->locx = node->locx + node->width + 20.0f;
+ }
+ maximumNode->locy = node->locy;
+ bNodeSocket *sockMaximumB = BLI_findlink(&maximumNode->inputs, 1);
+ copy_v3_v3(cycles_node_socket_vector_value(sockMaximumB), mapping->min);
+ bNodeSocket *sockMappingResult = nodeFindSocket(node, SOCK_OUT, "Vector");
+
+ LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+ if (link->fromsock == sockMappingResult) {
+ bNodeSocket *sockMaximumResult = nodeFindSocket(maximumNode, SOCK_OUT, "Vector");
+ nodeAddLink(ntree, maximumNode, sockMaximumResult, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ }
+ }
+ if (!(mapping->flag & TEXMAP_CLIP_MAX)) {
+ bNodeSocket *sockMaximumA = BLI_findlink(&maximumNode->inputs, 0);
+ nodeAddLink(ntree, node, sockMappingResult, maximumNode, sockMaximumA);
+ }
+
+ need_update = true;
+ }
+
+ bNode *minimumNode = NULL;
+ if (mapping->flag & TEXMAP_CLIP_MAX) {
+ minimumNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+ minimumNode->custom1 = NODE_VECTOR_MATH_MINIMUM;
+ minimumNode->locx = node->locx + node->width + 20.0f;
+ minimumNode->locy = node->locy;
+ bNodeSocket *sockMinimumB = BLI_findlink(&minimumNode->inputs, 1);
+ copy_v3_v3(cycles_node_socket_vector_value(sockMinimumB), mapping->max);
+
+ bNodeSocket *sockMinimumResult = nodeFindSocket(minimumNode, SOCK_OUT, "Vector");
+ bNodeSocket *sockMappingResult = nodeFindSocket(node, SOCK_OUT, "Vector");
+
+ if (maximumNode) {
+ bNodeSocket *sockMaximumA = BLI_findlink(&maximumNode->inputs, 0);
+ nodeAddLink(ntree, minimumNode, sockMinimumResult, maximumNode, sockMaximumA);
+ }
+ else {
+ LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+ if (link->fromsock == sockMappingResult) {
+ nodeAddLink(ntree, minimumNode, sockMinimumResult, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ }
+ }
+ }
+ bNodeSocket *sockMinimumA = BLI_findlink(&minimumNode->inputs, 0);
+ nodeAddLink(ntree, node, sockMappingResult, minimumNode, sockMinimumA);
+
+ need_update = true;
+ }
+
+ MEM_freeN(node->storage);
+ node->storage = NULL;
+
+ AnimData *animData = BKE_animdata_from_id(&ntree->id);
+ if (animData && animData->action) {
+ char *nodePath = BLI_sprintfN("nodes[\"%s\"]", node->name);
+ for (FCurve *fcu = animData->action->curves.first; fcu; fcu = fcu->next) {
+ if (STRPREFIX(fcu->rna_path, nodePath) &&
+ !BLI_str_endswith(fcu->rna_path, "default_value")) {
+ char *old_fcu_rna_path = fcu->rna_path;
+
+ if (BLI_str_endswith(old_fcu_rna_path, "translation")) {
+ fcu->rna_path = BLI_sprintfN("%s.%s", nodePath, "inputs[1].default_value");
+ }
+ else if (BLI_str_endswith(old_fcu_rna_path, "rotation")) {
+ fcu->rna_path = BLI_sprintfN("%s.%s", nodePath, "inputs[2].default_value");
+ }
+ else if (BLI_str_endswith(old_fcu_rna_path, "scale")) {
+ fcu->rna_path = BLI_sprintfN("%s.%s", nodePath, "inputs[3].default_value");
+ }
+ else if (minimumNode && BLI_str_endswith(old_fcu_rna_path, "max")) {
+ fcu->rna_path = BLI_sprintfN(
+ "nodes[\"%s\"].%s", minimumNode->name, "inputs[1].default_value");
+ }
+ else if (maximumNode && BLI_str_endswith(old_fcu_rna_path, "min")) {
+ fcu->rna_path = BLI_sprintfN(
+ "nodes[\"%s\"].%s", maximumNode->name, "inputs[1].default_value");
+ }
+
+ if (fcu->rna_path != old_fcu_rna_path) {
+ MEM_freeN(old_fcu_rna_path);
+ }
+ }
+ }
+
+ MEM_freeN(nodePath);
+ }
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
+/* The Musgrave node now has a dimension property. This property should
+ * be initialized to 3 by default.
+ */
+static void update_musgrave_node_dimensions(bNodeTree *ntree)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_MUSGRAVE) {
+ NodeTexMusgrave *tex = (NodeTexMusgrave *)node->storage;
+ tex->dimensions = 3;
+ }
+ }
+}
+
+/* The Color output of the Musgrave node has been removed. Previously, this
+ * output was just equal to the Fac output. To correct this, we move links
+ * from the Color output to the Fac output if they exist.
+ */
+static void update_musgrave_node_color_output(bNodeTree *ntree)
+{
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ if (link->fromnode && link->fromnode->type == SH_NODE_TEX_MUSGRAVE) {
+ if (link->fromsock->type == SOCK_RGBA) {
+ link->fromsock = link->fromsock->next;
+ }
+ }
+ }
+}
+
+/* The Voronoi node now have a dimension property. This property should be
+ * initialized to 3 by default.
+ */
+static void update_voronoi_node_dimensions(bNodeTree *ntree)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_VORONOI) {
+ NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
+ tex->dimensions = 3;
+ }
+ }
+}
+
+/* The F3 and F4 features of the Voronoi node have been removed.
+ * To correct this, we set the feature type to be F2 if it is F3
+ * or F4. The SHD_VORONOI_F3 and SHD_VORONOI_F4 enum values were
+ * 2 and 3 respectively.
+ */
+static void update_voronoi_node_f3_and_f4(bNodeTree *ntree)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_VORONOI) {
+ NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
+ if (ELEM(tex->feature, 2, 3)) {
+ tex->feature = SHD_VORONOI_F2;
+ }
+ }
+ }
+}
+
+/* The Fac output of the Voronoi node has been removed. Previously, this
+ * output was the voronoi distance in the Intensity mode and the Cell ID
+ * in the Cell mode. To correct this, we update the identifier and name
+ * of the Fac socket such that it gets mapped to the Distance socket.
+ * This is supposed to work with update_voronoi_node_coloring.
+ */
+static void update_voronoi_node_fac_output(bNodeTree *ntree)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_VORONOI) {
+ bNodeSocket *facOutput = BLI_findlink(&node->outputs, 1);
+ strcpy(facOutput->identifier, "Distance");
+ strcpy(facOutput->name, "Distance");
+ }
+ }
+}
+
+/* The Crackle feature of the Voronoi node has been removed. Previously,
+ * this feature returned the F2 distance minus the F1 distance. The
+ * crackle feature had an enum value of 4. To fix this we do the
+ * following:
+ *
+ * 1. The node feature is set to F1.
+ * 2. A new Voronoi node is added and its feature is set to F2.
+ * 3. The properties, input values, and connections are copied
+ * from the node to the new Voronoi node so that they match
+ * exactly.
+ * 4. A Subtract node is added.
+ * 5. The outputs of the F1 and F2 voronoi are connected to
+ * the inputs of the subtract node.
+ * 6. The output of the subtract node is connected to the
+ * appropriate sockets.
+ *
+ */
+static void update_voronoi_node_crackle(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_VORONOI) {
+ NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
+ bNodeSocket *sockDistance = nodeFindSocket(node, SOCK_OUT, "Distance");
+ bNodeSocket *sockColor = nodeFindSocket(node, SOCK_OUT, "Color");
+ if (tex->feature == 4 && (socket_is_used(sockDistance) || socket_is_used(sockColor))) {
+ tex->feature = SHD_VORONOI_F1;
+
+ bNode *voronoiNode = nodeAddStaticNode(NULL, ntree, SH_NODE_TEX_VORONOI);
+ NodeTexVoronoi *texVoronoi = (NodeTexVoronoi *)voronoiNode->storage;
+ texVoronoi->feature = SHD_VORONOI_F2;
+ texVoronoi->distance = tex->distance;
+ texVoronoi->dimensions = 3;
+ voronoiNode->locx = node->locx + node->width + 20.0f;
+ voronoiNode->locy = node->locy;
+
+ bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector");
+ bNodeSocket *sockScale = nodeFindSocket(node, SOCK_IN, "Scale");
+ bNodeSocket *sockExponent = nodeFindSocket(node, SOCK_IN, "Exponent");
+ bNodeSocket *sockVoronoiVector = nodeFindSocket(voronoiNode, SOCK_IN, "Vector");
+ bNodeSocket *sockVoronoiScale = nodeFindSocket(voronoiNode, SOCK_IN, "Scale");
+ bNodeSocket *sockVoronoiExponent = nodeFindSocket(voronoiNode, SOCK_IN, "Exponent");
+ if (sockVector->link) {
+ nodeAddLink(ntree,
+ sockVector->link->fromnode,
+ sockVector->link->fromsock,
+ voronoiNode,
+ sockVoronoiVector);
+ }
+ *cycles_node_socket_float_value(sockVoronoiScale) = *cycles_node_socket_float_value(
+ sockScale);
+ if (sockScale->link) {
+ nodeAddLink(ntree,
+ sockScale->link->fromnode,
+ sockScale->link->fromsock,
+ voronoiNode,
+ sockVoronoiScale);
+ }
+ *cycles_node_socket_float_value(sockVoronoiExponent) = *cycles_node_socket_float_value(
+ sockExponent);
+ if (sockExponent->link) {
+ nodeAddLink(ntree,
+ sockExponent->link->fromnode,
+ sockExponent->link->fromsock,
+ voronoiNode,
+ sockVoronoiExponent);
+ }
+
+ bNode *subtractNode = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH);
+ subtractNode->custom1 = NODE_MATH_SUBTRACT;
+ subtractNode->locx = voronoiNode->locx + voronoiNode->width + 20.0f;
+ subtractNode->locy = voronoiNode->locy;
+ bNodeSocket *sockSubtractOutValue = nodeFindSocket(subtractNode, SOCK_OUT, "Value");
+
+ LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+ if (link->fromnode == node) {
+ nodeAddLink(ntree, subtractNode, sockSubtractOutValue, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ }
+ }
+
+ bNodeSocket *sockDistanceF1 = nodeFindSocket(node, SOCK_OUT, "Distance");
+ bNodeSocket *sockDistanceF2 = nodeFindSocket(voronoiNode, SOCK_OUT, "Distance");
+ bNodeSocket *sockSubtractA = BLI_findlink(&subtractNode->inputs, 0);
+ bNodeSocket *sockSubtractB = BLI_findlink(&subtractNode->inputs, 1);
+
+ nodeAddLink(ntree, node, sockDistanceF1, subtractNode, sockSubtractB);
+ nodeAddLink(ntree, voronoiNode, sockDistanceF2, subtractNode, sockSubtractA);
+
+ need_update = true;
+ }
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
+/**
+ * The coloring property of the Voronoi node was removed. Previously,
+ * if the coloring enum was set to Intensity (0), the voronoi distance
+ * was returned in all outputs, otherwise, the Cell ID was returned.
+ * Since we remapped the Fac output in update_voronoi_node_fac_output,
+ * then to fix this, we relink the Color output to the Distance
+ * output if coloring was set to 0, and the other way around otherwise.
+ */
+static void update_voronoi_node_coloring(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+ bNode *node = link->fromnode;
+ if (node && node->type == SH_NODE_TEX_VORONOI) {
+ NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
+ if (tex->coloring == 0) {
+ bNodeSocket *sockColor = nodeFindSocket(node, SOCK_OUT, "Color");
+ if (link->fromsock == sockColor) {
+ bNodeSocket *sockDistance = nodeFindSocket(node, SOCK_OUT, "Distance");
+ nodeAddLink(ntree, node, sockDistance, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ need_update = true;
+ }
+ }
+ else {
+ bNodeSocket *sockDistance = nodeFindSocket(node, SOCK_OUT, "Distance");
+ if (link->fromsock == sockDistance) {
+ bNodeSocket *sockColor = nodeFindSocket(node, SOCK_OUT, "Color");
+ nodeAddLink(ntree, node, sockColor, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ need_update = true;
+ }
+ }
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
+/* Previously, the output euclidean distance was actually the squared
+ * euclidean distance. To fix this, we square the the output distance
+ * socket if the distance metric is set to SHD_VORONOI_EUCLIDEAN.
+ */
+static void update_voronoi_node_square_distance(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_VORONOI) {
+ NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
+ bNodeSocket *sockDistance = nodeFindSocket(node, SOCK_OUT, "Distance");
+ if (tex->distance == SHD_VORONOI_EUCLIDEAN &&
+ (tex->feature == SHD_VORONOI_F1 || tex->feature == SHD_VORONOI_F2) &&
+ socket_is_used(sockDistance)) {
+ bNode *multiplyNode = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH);
+ multiplyNode->custom1 = NODE_MATH_MULTIPLY;
+ multiplyNode->locx = node->locx + node->width + 20.0f;
+ multiplyNode->locy = node->locy;
+
+ bNodeSocket *sockValue = nodeFindSocket(multiplyNode, SOCK_OUT, "Value");
+ LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+ if (link->fromsock == sockDistance) {
+ nodeAddLink(ntree, multiplyNode, sockValue, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ }
+ }
+
+ bNodeSocket *sockMultiplyA = BLI_findlink(&multiplyNode->inputs, 0);
+ bNodeSocket *sockMultiplyB = BLI_findlink(&multiplyNode->inputs, 1);
+
+ nodeAddLink(ntree, node, sockDistance, multiplyNode, sockMultiplyA);
+ nodeAddLink(ntree, node, sockDistance, multiplyNode, sockMultiplyB);
+
+ need_update = true;
+ }
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bmain)
{
/* Particle shape shared with Eevee. */
@@ -797,6 +1219,25 @@ void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bm
}
FOREACH_NODETREE_END;
}
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 10)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ update_musgrave_node_color_output(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 11)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ update_voronoi_node_f3_and_f4(ntree);
+ update_voronoi_node_fac_output(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
}
void do_versions_after_linking_cycles(Main *bmain)
@@ -928,4 +1369,43 @@ void do_versions_after_linking_cycles(Main *bmain)
}
FOREACH_NODETREE_END;
}
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 7)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ update_noise_node_dimensions(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 8)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ update_mapping_node_inputs_and_properties(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 10)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ update_musgrave_node_dimensions(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 11)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ update_voronoi_node_dimensions(ntree);
+ update_voronoi_node_crackle(ntree);
+ update_voronoi_node_coloring(ntree);
+ update_voronoi_node_square_distance(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index fa69892584a..c9fb8b6990b 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -38,13 +38,16 @@
#include "DNA_workspace_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_light_types.h"
#include "BKE_appdir.h"
+#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_paint.h"
#include "BKE_screen.h"
#include "BKE_workspace.h"
@@ -195,18 +198,13 @@ static void blo_update_defaults_screen(bScreen *screen,
}
}
- /* Show toopbar for sculpt/paint modes. */
- const bool show_tool_header = STR_ELEM(
- workspace_name, "Sculpting", "Texture Paint", "2D Animation", "2D Full Canvas");
-
- if (show_tool_header) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
- ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
- for (ARegion *ar = regionbase->first; ar; ar = ar->next) {
- if (ar->regiontype == RGN_TYPE_TOOL_HEADER) {
- ar->flag &= ~(RGN_FLAG_HIDDEN | RGN_FLAG_HIDDEN_BY_USER);
- }
+ /* Show top-bar by default. */
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ for (ARegion *ar = regionbase->first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_TOOL_HEADER) {
+ ar->flag &= ~(RGN_FLAG_HIDDEN | RGN_FLAG_HIDDEN_BY_USER);
}
}
}
@@ -265,6 +263,9 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
/* Change default cubemap quality. */
scene->eevee.gi_filter_quality = 3.0f;
+ /* Enable Soft Shadows by default. */
+ scene->eevee.flag |= SCE_EEVEE_SHADOW_SOFT;
+
/* Be sure curfalloff and primitive are initializated */
ToolSettings *ts = scene->toolsettings;
if (ts->gp_sculpt.cur_falloff == NULL) {
@@ -286,6 +287,10 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
CURVEMAP_SLOPE_POSITIVE);
}
+ if (ts->sculpt) {
+ ts->sculpt->paint.symmetry_flags |= PAINT_SYMMETRY_FEATHER;
+ }
+
/* Correct default startup UV's. */
Mesh *me = BLI_findstring(&bmain->meshes, "Cube", offsetof(ID, name) + 2);
if (me && (me->totloop == 24) && (me->mloopuv != NULL)) {
@@ -329,6 +334,14 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
BLI_strncpy(screen->id.name + 2, workspace->id.name + 2, sizeof(screen->id.name) - 2);
BLI_libblock_ensure_unique_name(bmain, screen->id.name);
}
+
+ /* For some reason we have unused screens, needed until re-saving.
+ * Clear unused layouts because they're visible in the outliner & Python API. */
+ LISTBASE_FOREACH_MUTABLE (WorkSpaceLayout *, layout_iter, &workspace->layouts) {
+ if (layout != layout_iter) {
+ BKE_workspace_layout_remove(bmain, workspace, layout_iter);
+ }
+ }
}
/* Scenes */
@@ -345,6 +358,12 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
scene->audio.flag &= ~AUDIO_SYNC;
scene->flag &= ~SCE_FRAME_DROP;
}
+
+ /* Change default selection mode for Grease Pencil. */
+ if (app_template && STREQ(app_template, "2D_Animation")) {
+ ToolSettings *ts = scene->toolsettings;
+ ts->gpencil_selectmode_edit = GP_SELECTMODE_STROKE;
+ }
}
/* Objects */
@@ -400,7 +419,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
{
/* Enable for UV sculpt (other brush types will be created as needed),
* without this the grab brush will be active but not selectable from the list. */
- Brush *brush = BLI_findstring(&bmain->brushes, "Grab", offsetof(ID, name) + 2);
+ const char *brush_name = "Grab";
+ Brush *brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
if (brush) {
brush->ob_mode |= OB_MODE_EDIT;
}
@@ -408,13 +428,103 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) {
brush->blur_kernel_radius = 2;
+
+ /* Use full strength for all non-sculpt brushes,
+ * when painting we want to use full color/weight always.
+ *
+ * Note that sculpt is an exception,
+ * it's values are overwritten by #BKE_brush_sculpt_reset below. */
+ brush->alpha = 1.0;
}
{
/* Change the spacing of the Smear brush to 3.0% */
- Brush *brush = BLI_findstring(&bmain->brushes, "Smear", offsetof(ID, name) + 2);
+ const char *brush_name;
+ Brush *brush;
+
+ brush_name = "Smear";
+ brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
if (brush) {
brush->spacing = 3.0;
}
+
+ brush_name = "Draw Sharp";
+ brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ if (!brush) {
+ brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
+ id_us_min(&brush->id);
+ brush->sculpt_tool = SCULPT_TOOL_DRAW_SHARP;
+ }
+
+ brush_name = "Elastic Deform";
+ brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ if (!brush) {
+ brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
+ id_us_min(&brush->id);
+ brush->sculpt_tool = SCULPT_TOOL_ELASTIC_DEFORM;
+ }
+
+ brush_name = "Pose";
+ brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ if (!brush) {
+ brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
+ id_us_min(&brush->id);
+ brush->sculpt_tool = SCULPT_TOOL_POSE;
+ }
+
+ brush_name = "Simplify";
+ brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ if (!brush) {
+ brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
+ id_us_min(&brush->id);
+ brush->sculpt_tool = SCULPT_TOOL_SIMPLIFY;
+ }
+
+ /* Use the same tool icon color in the brush cursor */
+ for (brush = bmain->brushes.first; brush; brush = brush->id.next) {
+ if (brush->ob_mode & OB_MODE_SCULPT) {
+ BLI_assert(brush->sculpt_tool != 0);
+ BKE_brush_sculpt_reset(brush);
+ }
+ }
+ }
+
+ if (app_template && STREQ(app_template, "2D_Animation")) {
+ /* Update Grease Pencil brushes. */
+ Brush *brush;
+
+ /* Pencil brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Pencil", "Pencil");
+
+ /* Pen brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Pen", "Pen");
+
+ /* Pen Soft brush. */
+ brush = (Brush *)rename_id_for_versioning(bmain, ID_BR, "Draw Soft", "Pencil Soft");
+ if (brush) {
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
+ }
+
+ /* Ink Pen brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Ink", "Ink Pen");
+
+ /* Ink Pen Rough brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Noise", "Ink Pen Rough");
+
+ /* Marker Bold brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Marker", "Marker Bold");
+
+ /* Marker Chisel brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Block", "Marker Chisel");
+
+ /* Remove useless Fill Area.001 brush. */
+ brush = BLI_findstring(&bmain->brushes, "Fill Area.001", offsetof(ID, name) + 2);
+ if (brush) {
+ BKE_id_delete(bmain, brush);
+ }
+
+ /* Reset all grease pencil brushes. */
+ Scene *scene = bmain->scenes.first;
+ BKE_brush_gpencil_presets(bmain, scene->toolsettings);
}
}
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index 9b6f252f62d..62bd605a2c2 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -71,14 +71,12 @@
#include "BKE_constraint.h"
#include "BKE_deform.h"
#include "BKE_fcurve.h"
-#include "BKE_image.h"
#include "BKE_lattice.h"
#include "BKE_main.h" // for Main
#include "BKE_mesh.h" // for ME_ defines (patching)
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
-#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "NOD_socket.h"
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index 8bbfc29131e..bbae1c8e85e 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -29,10 +29,10 @@
#include "DNA_curve_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
#include "BKE_addon.h"
#include "BKE_colorband.h"
-#include "BKE_idprop.h"
#include "BKE_main.h"
#include "BKE_keyconfig.h"
@@ -150,6 +150,10 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
* Include next version bump.
*/
{
+ FROM_DEFAULT_V4_UCHAR(space_file.execution_buts);
+ FROM_DEFAULT_V4_UCHAR(tui.icon_folder);
+ FROM_DEFAULT_V4_UCHAR(space_clip.path_keyframe_before);
+ FROM_DEFAULT_V4_UCHAR(space_clip.path_keyframe_after);
}
#undef FROM_DEFAULT_V4_UCHAR
@@ -609,11 +613,25 @@ void BLO_version_defaults_userpref_blend(Main *bmain, UserDef *userdef)
userdef->drag_threshold_tablet = 10;
}
+ if (!USER_VERSION_ATLEAST(281, 9)) {
+ /* X3D is no longer enabled by default. */
+ BKE_addon_remove_safe(&userdef->addons, "io_scene_x3d");
+ }
+
+ if (!USER_VERSION_ATLEAST(281, 12)) {
+ userdef->render_display_type = USER_RENDER_DISPLAY_WINDOW;
+ userdef->filebrowser_display_type = USER_TEMP_SPACE_DISPLAY_WINDOW;
+ }
+
/**
* Include next version bump.
*/
{
/* pass */
+ if (userdef->file_space_data.display_type == FILE_DEFAULTDISPLAY) {
+ memcpy(
+ &userdef->file_space_data, &U_default.file_space_data, sizeof(userdef->file_space_data));
+ }
}
if (userdef->pixelsize == 0.0f) {
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 0ff7ba0034f..aae5072c8de 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -157,7 +157,6 @@
#include "BKE_layer.h"
#include "BKE_library_override.h"
#include "BKE_main.h"
-#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
#include "BKE_pointcache.h"
@@ -2014,7 +2013,7 @@ static void write_mdisps(WriteData *wd, int count, MDisps *mdlist, int external)
int i;
writestruct(wd, DATA, MDisps, count, mdlist);
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
MDisps *md = &mdlist[i];
if (md->disps) {
if (!external) {
@@ -2035,7 +2034,7 @@ static void write_grid_paint_mask(WriteData *wd, int count, GridPaintMask *grid_
int i;
writestruct(wd, DATA, GridPaintMask, count, grid_paint_mask);
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
GridPaintMask *gpm = &grid_paint_mask[i];
if (gpm->data) {
const int gridsize = BKE_ccg_gridsize(gpm->level);
@@ -2413,6 +2412,13 @@ static void write_view_settings(WriteData *wd, ColorManagedViewSettings *view_se
}
}
+static void write_view3dshading(WriteData *wd, View3DShading *shading)
+{
+ if (shading->prop) {
+ IDP_WriteProperty(shading->prop, wd);
+ }
+}
+
static void write_paint(WriteData *wd, Paint *p)
{
if (p->cavity_curve) {
@@ -2471,7 +2477,7 @@ static void write_lightcache(WriteData *wd, LightCache *cache)
if (cache->cube_mips) {
writestruct(wd, DATA, LightCacheTexture, cache->mips_len, cache->cube_mips);
- for (int i = 0; i < cache->mips_len; ++i) {
+ for (int i = 0; i < cache->mips_len; i++) {
write_lightcache_texture(wd, &cache->cube_mips[i]);
}
}
@@ -2684,6 +2690,8 @@ static void write_scene(WriteData *wd, Scene *sce)
write_lightcache(wd, sce->eevee.light_cache);
}
+ write_view3dshading(wd, &sce->display.shading);
+
/* Freed on doversion. */
BLI_assert(sce->layer_properties == NULL);
}
@@ -2850,6 +2858,7 @@ static void write_area_regions(WriteData *wd, ScrArea *area)
if (v3d->fx_settings.dof) {
writestruct(wd, DATA, GPUDOFSettings, 1, v3d->fx_settings.dof);
}
+ write_view3dshading(wd, &v3d->shading);
}
else if (sl->spacetype == SPACE_GRAPH) {
SpaceGraph *sipo = (SpaceGraph *)sl;
@@ -3627,7 +3636,9 @@ static void write_libraries(WriteData *wd, Main *main)
found_one = false;
while (!found_one && tot--) {
for (id = lbarray[tot]->first; id; id = id->next) {
- if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) {
+ if (id->us > 0 &&
+ ((id->tag & LIB_TAG_EXTERN) ||
+ ((id->tag & LIB_TAG_INDIRECT) && (id->flag & LIB_INDIRECT_WEAK_LINK)))) {
found_one = true;
break;
}
@@ -3657,7 +3668,9 @@ static void write_libraries(WriteData *wd, Main *main)
/* Write link placeholders for all direct linked IDs. */
while (a--) {
for (id = lbarray[a]->first; id; id = id->next) {
- if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) {
+ if (id->us > 0 &&
+ ((id->tag & LIB_TAG_EXTERN) ||
+ ((id->tag & LIB_TAG_INDIRECT) && (id->flag & LIB_INDIRECT_WEAK_LINK)))) {
if (!BKE_idcode_is_linkable(GS(id->name))) {
printf(
"ERROR: write file: data-block '%s' from lib '%s' is not linkable "
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index f5095ca2b5f..599871a505a 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -143,6 +143,8 @@ set(SRC
tools/bmesh_edgesplit.h
tools/bmesh_intersect.c
tools/bmesh_intersect.h
+ tools/bmesh_intersect_edges.c
+ tools/bmesh_intersect_edges.h
tools/bmesh_path.c
tools/bmesh_path.h
tools/bmesh_path_region.c
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
index 48d6bcd7b03..27c03f0a84f 100644
--- a/source/blender/bmesh/intern/bmesh_interp.c
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -330,9 +330,9 @@ static bool quad_co(const float v1[3],
}
static void mdisp_axis_from_quad(float v1[3],
- float v2[3],
+ const float v2[3],
float UNUSED(v3[3]),
- float v4[3],
+ const float v4[3],
float r_axis_x[3],
float r_axis_y[3])
{
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index 788edc348d9..58a7d423d67 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -1026,8 +1026,8 @@ bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
ese->next = ese->prev = NULL;
if (ese_last) {
- if (ese_last->htype ==
- BM_FACE) { /* if there is an active face, use it over the last selected face */
+ /* If there is an active face, use it over the last selected face. */
+ if (ese_last->htype == BM_FACE) {
if (efa) {
ese->ele = (BMElem *)efa;
}
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index b9f0bcc05f0..7086cea1ace 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -369,28 +369,6 @@ static BMOpDefine bmo_remove_doubles_def = {
};
/*
- * Auto Merge.
- *
- * Finds groups of vertices closer then **dist** and merges them together,
- * using the weld verts bmop. The merges must go from a vert not in
- * **verts** to one in **verts**.
- */
-static BMOpDefine bmo_automerge_def = {
- "automerge",
- /* slots_in */
- {{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* input verts */
- {"dist", BMO_OP_SLOT_FLT}, /* maximum distance */
- {{'\0'}},
- },
- {{{'\0'}}}, /* no output */
- bmo_automerge_exec,
- (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
- BMO_OPTYPE_FLAG_NORMALS_CALC |
- BMO_OPTYPE_FLAG_SELECT_FLUSH |
- BMO_OPTYPE_FLAG_SELECT_VALIDATE),
-};
-
-/*
* Collapse Connected.
*
* Collapses connected vertices
@@ -2073,7 +2051,6 @@ static BMOpDefine bmo_symmetrize_def = {
/* clang-format on */
const BMOpDefine *bmo_opdefines[] = {
- &bmo_automerge_def,
&bmo_average_vert_facedata_def,
&bmo_beautify_fill_def,
&bmo_bevel_def,
diff --git a/source/blender/bmesh/intern/bmesh_operators_private.h b/source/blender/bmesh/intern/bmesh_operators_private.h
index 8658f6c233c..137c5aa338e 100644
--- a/source/blender/bmesh/intern/bmesh_operators_private.h
+++ b/source/blender/bmesh/intern/bmesh_operators_private.h
@@ -24,7 +24,6 @@
struct BMOperator;
struct BMesh;
-void bmo_automerge_exec(BMesh *bm, BMOperator *op);
void bmo_average_vert_facedata_exec(BMesh *bm, BMOperator *op);
void bmo_beautify_fill_exec(BMesh *bm, BMOperator *op);
void bmo_bevel_exec(BMesh *bm, BMOperator *op);
diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
index 83ac7df058a..374c912e3f5 100644
--- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
+++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
@@ -94,7 +94,7 @@ static BMLoop *bm_edge_flagged_radial_first(BMEdge *e)
}
static void normalize_v2_m3_v3v3(float out[2],
- float axis_mat[3][3],
+ const float axis_mat[3][3],
const float v1[3],
const float v2[3])
{
@@ -110,7 +110,7 @@ static void normalize_v2_m3_v3v3(float out[2],
*/
static bool bm_face_split_edgenet_find_loop_pair(BMVert *v_init,
const float face_normal[3],
- float face_normal_matrix[3][3],
+ const float face_normal_matrix[3][3],
BMEdge *e_pair[2])
{
/* Always find one boundary edge (to determine winding)
@@ -420,7 +420,7 @@ finally:
static bool bm_face_split_edgenet_find_loop(BMVert *v_init,
const float face_normal[3],
- float face_normal_matrix[3][3],
+ const float face_normal_matrix[3][3],
/* cache to avoid realloc every time */
struct VertOrder *edge_order,
const uint edge_order_len,
diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c
index 51bc86e40eb..219bec15e5b 100644
--- a/source/blender/bmesh/intern/bmesh_query.c
+++ b/source/blender/bmesh/intern/bmesh_query.c
@@ -207,6 +207,34 @@ bool BM_vert_pair_share_face_check_cb(BMVert *v_a,
return false;
}
+BMFace *BM_vert_pair_shared_face_cb(BMVert *v_a,
+ BMVert *v_b,
+ const bool allow_adjacent,
+ bool (*callback)(BMFace *, BMLoop *, BMLoop *, void *userdata),
+ void *user_data,
+ BMLoop **r_l_a,
+ BMLoop **r_l_b)
+{
+ if (v_a->e && v_b->e) {
+ BMIter iter;
+ BMLoop *l_a, *l_b;
+
+ BM_ITER_ELEM (l_a, &iter, v_a, BM_LOOPS_OF_VERT) {
+ BMFace *f = l_a->f;
+ l_b = BM_face_vert_share_loop(f, v_b);
+ if (l_b && (allow_adjacent || !BM_loop_is_adjacent(l_a, l_b)) &&
+ callback(f, l_a, l_b, user_data)) {
+ *r_l_a = l_a;
+ *r_l_b = l_b;
+
+ return f;
+ }
+ }
+ }
+
+ return NULL;
+}
+
/**
* Given 2 verts, find the smallest face they share and give back both loops.
*/
diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h
index e96984490c0..3a864fbb5dd 100644
--- a/source/blender/bmesh/intern/bmesh_query.h
+++ b/source/blender/bmesh/intern/bmesh_query.h
@@ -62,6 +62,13 @@ bool BM_vert_pair_share_face_check_cb(BMVert *v_a,
bool (*test_fn)(BMFace *f, void *user_data),
void *user_data) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2, 3);
+BMFace *BM_vert_pair_shared_face_cb(BMVert *v_a,
+ BMVert *v_b,
+ const bool allow_adjacent,
+ bool (*callback)(BMFace *, BMLoop *, BMLoop *, void *userdata),
+ void *user_data,
+ BMLoop **r_l_a,
+ BMLoop **r_l_b) ATTR_NONNULL(1, 2, 4, 6, 7);
BMFace *BM_vert_pair_share_face_by_len(BMVert *v_a,
BMVert *v_b,
BMLoop **r_l_a,
diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c
index 5403043efb4..bad5036f6cf 100644
--- a/source/blender/bmesh/operators/bmo_bridge.c
+++ b/source/blender/bmesh/operators/bmo_bridge.c
@@ -400,7 +400,7 @@ static void bridge_loop_pair(BMesh *bm,
f_example = l_a ? l_a->f : (l_b ? l_b->f : NULL);
if (v_b != v_b_next) {
- BMVert *v_arr[4] = {v_a, v_b, v_b_next, v_a_next};
+ BMVert *v_arr[4] = {v_b, v_b_next, v_a_next, v_a};
f = BM_face_exists(v_arr, 4);
if (f == NULL) {
/* copy if loop data if its is missing on one ring */
@@ -425,7 +425,7 @@ static void bridge_loop_pair(BMesh *bm,
}
}
else {
- BMVert *v_arr[3] = {v_a, v_b, v_a_next};
+ BMVert *v_arr[3] = {v_b, v_a_next, v_a};
f = BM_face_exists(v_arr, 3);
if (f == NULL) {
/* fan-fill a triangle */
diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c
index f23c420295b..1570c802bee 100644
--- a/source/blender/bmesh/operators/bmo_inset.c
+++ b/source/blender/bmesh/operators/bmo_inset.c
@@ -588,7 +588,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
/* tag if boundary is enabled */
(use_boundary && BM_edge_is_boundary(e) && BM_elem_flag_test(e->l->f, BM_ELEM_TAG)) ||
- /* tag if edge is an interior edge inbetween a tagged and untagged face */
+ /* tag if edge is an interior edge in between a tagged and untagged face */
(bm_edge_is_mixed_face_tag(e->l))) {
/* tag */
BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c
index d783842c017..1d28d8223cd 100644
--- a/source/blender/bmesh/operators/bmo_removedoubles.c
+++ b/source/blender/bmesh/operators/bmo_removedoubles.c
@@ -706,34 +706,3 @@ void bmo_find_doubles_exec(BMesh *bm, BMOperator *op)
slot_targetmap_out = BMO_slot_get(op->slots_out, "targetmap.out");
bmesh_find_doubles_common(bm, op, op, slot_targetmap_out);
}
-
-void bmo_automerge_exec(BMesh *bm, BMOperator *op)
-{
- BMOperator findop, weldop;
- BMIter viter;
- BMVert *v;
-
- /* The "verts" input sent to this op is the set of verts that
- * can be merged away into any other verts. Mark all other verts
- * as VERT_KEEP. */
- BMO_slot_buffer_flag_enable(bm, op->slots_in, "verts", BM_VERT, VERT_IN);
- BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
- if (!BMO_vert_flag_test(bm, v, VERT_IN)) {
- BMO_vert_flag_enable(bm, v, VERT_KEEP);
- }
- }
-
- /* Search for doubles among all vertices, but only merge non-VERT_KEEP
- * vertices into VERT_KEEP vertices. */
- BMO_op_initf(bm, &findop, op->flag, "find_doubles verts=%av keep_verts=%fv", VERT_KEEP);
- BMO_slot_copy(op, slots_in, "dist", &findop, slots_in, "dist");
- BMO_op_exec(bm, &findop);
-
- /* weld the vertices */
- BMO_op_init(bm, &weldop, op->flag, "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);
-}
diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c
index 5d511374989..dabdbc3c97a 100644
--- a/source/blender/bmesh/tools/bmesh_beautify.c
+++ b/source/blender/bmesh/tools/bmesh_beautify.c
@@ -199,7 +199,7 @@ static float bm_edge_calc_rotate_beauty__area(const float v1[3],
* Allowing to rotate out of a degenerate state can flip the faces
* (when performed iteratively).
*/
- return BLI_polyfill_beautify_quad_rotate_calc_ex(v1_xy, v2_xy, v3_xy, v4_xy, true);
+ return BLI_polyfill_beautify_quad_rotate_calc_ex(v1_xy, v2_xy, v3_xy, v4_xy, true, NULL);
} while (false);
return FLT_MAX;
diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.c b/source/blender/bmesh/tools/bmesh_intersect_edges.c
new file mode 100644
index 00000000000..ffdcf179491
--- /dev/null
+++ b/source/blender/bmesh/tools/bmesh_intersect_edges.c
@@ -0,0 +1,911 @@
+/*
+ * 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 bmesh
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_sort.h"
+#include "BLI_stack.h"
+
+#include "BKE_bvhutils.h"
+
+#include "bmesh.h"
+
+#include "bmesh_intersect_edges.h" /* own include */
+
+#define KDOP_AXIS_LEN 14
+
+/* -------------------------------------------------------------------- */
+/** \name Weld Linked Wire Edges into Linked Faces
+ *
+ * Used with the merge vertices option.
+ * \{ */
+
+/* Callbacks for `BM_vert_pair_shared_face_cb` */
+
+struct EDBMSplitBestFaceData {
+ BMEdge **edgenet;
+ int edgenet_len;
+
+ /**
+ * Track the range of vertices in edgenet along the faces normal,
+ * find the lowest since it's most likely to be most co-planar with the face.
+ */
+ float best_face_range_on_normal_axis;
+ BMFace *r_best_face;
+};
+
+static bool bm_vert_pair_share_best_splittable_face_cb(BMFace *f,
+ BMLoop *l_a,
+ BMLoop *l_b,
+ void *userdata)
+{
+ struct EDBMSplitBestFaceData *data = userdata;
+ float no[3];
+ copy_v3_v3(no, f->no);
+
+ float min = dot_v3v3(l_a->v->co, no);
+ float max = dot_v3v3(l_b->v->co, no);
+ if (min > max) {
+ SWAP(float, min, max);
+ }
+
+ BMVert *v_test = l_b->v;
+ BMEdge **e_iter = &data->edgenet[0];
+ int verts_len = data->edgenet_len - 1;
+ for (int i = verts_len; i--; e_iter++) {
+ v_test = BM_edge_other_vert(*e_iter, v_test);
+ if (!BM_face_point_inside_test(f, v_test->co)) {
+ return false;
+ }
+ float dot = dot_v3v3(v_test->co, no);
+ if (dot < min) {
+ min = dot;
+ }
+ if (dot > max) {
+ max = dot;
+ }
+ }
+
+ const float test_face_range_on_normal_axis = max - min;
+ if (test_face_range_on_normal_axis < data->best_face_range_on_normal_axis) {
+ data->best_face_range_on_normal_axis = test_face_range_on_normal_axis;
+ data->r_best_face = f;
+ }
+
+ return false;
+}
+
+/* find the best splittable face between the two vertices. */
+static bool bm_vert_pair_share_splittable_face_cb(BMFace *UNUSED(f),
+ BMLoop *l_a,
+ BMLoop *l_b,
+ void *userdata)
+{
+ float(*data)[3] = userdata;
+ float *v_a_co = data[0];
+ float *v_a_b_dir = data[1];
+
+ float lambda;
+ if (isect_ray_seg_v3(v_a_co, v_a_b_dir, l_a->prev->v->co, l_a->next->v->co, &lambda)) {
+ if (IN_RANGE(lambda, 0.0f, 1.0f)) {
+ return true;
+ }
+ else if (isect_ray_seg_v3(v_a_co, v_a_b_dir, l_b->prev->v->co, l_b->next->v->co, &lambda)) {
+ return IN_RANGE(lambda, 0.0f, 1.0f);
+ }
+ }
+ return false;
+}
+
+void BM_vert_weld_linked_wire_edges_into_linked_faces(
+ BMesh *bm, BMVert *v, const float epsilon, BMEdge **r_edgenet[], int *r_edgenet_alloc_len)
+{
+ BMEdge **edgenet = *r_edgenet;
+ int edgenet_alloc_len = *r_edgenet_alloc_len;
+
+ BMIter iter;
+ BMEdge *e;
+ BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
+ int edgenet_len = 0;
+ BMVert *v_other = v;
+ while (BM_edge_is_wire(e)) {
+ if (edgenet_alloc_len == edgenet_len) {
+ edgenet_alloc_len = (edgenet_alloc_len + 1) * 2;
+ edgenet = MEM_reallocN(edgenet, (edgenet_alloc_len) * sizeof(*edgenet));
+ }
+ edgenet[edgenet_len++] = e;
+ v_other = BM_edge_other_vert(e, v_other);
+ if (v_other == v) {
+ /* Endless loop. */
+ break;
+ }
+
+ BMEdge *e_next = BM_DISK_EDGE_NEXT(e, v_other);
+ if (e_next == e) {
+ /* Vert is wire_endpoint. */
+ edgenet_len = 0;
+ break;
+ }
+
+ BMEdge *e_test = e_next;
+ while ((e_test = BM_DISK_EDGE_NEXT(e_test, v_other)) != e) {
+ if (e_test->l) {
+ /* Vert is linked to a face. */
+ goto l_break;
+ }
+ }
+
+ e = e_next;
+ }
+
+ BMLoop *dummy;
+ BMFace *best_face;
+
+ l_break:
+ if (edgenet_len == 0) {
+ /* Nothing to do. */
+ continue;
+ }
+ if (edgenet_len == 1) {
+ float data[2][3];
+ copy_v3_v3(data[0], v_other->co);
+ sub_v3_v3v3(data[1], v->co, data[0]);
+ best_face = BM_vert_pair_shared_face_cb(
+ v_other, v, true, bm_vert_pair_share_splittable_face_cb, &data, &dummy, &dummy);
+ }
+ else {
+ struct EDBMSplitBestFaceData data = {
+ .edgenet = edgenet,
+ .edgenet_len = edgenet_len,
+ .best_face_range_on_normal_axis = FLT_MAX,
+ .r_best_face = NULL,
+ };
+ BM_vert_pair_shared_face_cb(
+ v_other, v, true, bm_vert_pair_share_best_splittable_face_cb, &data, &dummy, &dummy);
+
+ if (data.r_best_face) {
+ float no[3], min = FLT_MAX, max = -FLT_MAX;
+ copy_v3_v3(no, data.r_best_face->no);
+ BMVert *v_test;
+ BMIter f_iter;
+ BM_ITER_ELEM (v_test, &f_iter, data.r_best_face, BM_VERTS_OF_FACE) {
+ float dot = dot_v3v3(v_test->co, no);
+ if (dot < min) {
+ min = dot;
+ }
+ if (dot > max) {
+ max = dot;
+ }
+ }
+ float range = max - min + 2 * epsilon;
+ if (range < data.best_face_range_on_normal_axis) {
+ data.r_best_face = NULL;
+ }
+ }
+ best_face = data.r_best_face;
+ }
+
+ if (best_face) {
+ BM_face_split_edgenet(bm, best_face, edgenet, edgenet_len, NULL, NULL);
+ }
+ }
+
+ *r_edgenet = edgenet;
+ *r_edgenet_alloc_len = edgenet_alloc_len;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Auto-Merge & Split Selection
+ *
+ * Used after transform operations.
+ * \{ */
+
+struct EDBMSplitElem {
+ union {
+ BMElem *elem;
+ BMVert *vert;
+ struct {
+ BMEdge *edge;
+ float lambda;
+ };
+ };
+};
+
+/* -------------------------------------------------------------------- */
+/* Overlap Callbacks */
+
+struct EDBMSplitData {
+ BMesh *bm;
+ BLI_Stack *pair_stack;
+ int cut_edges_a_len;
+ int cut_edges_b_len;
+ float dist_sq;
+ float dist_sq_sq;
+};
+
+/* Utils */
+
+static void bm_vert_pair_elem_setup_ex(BMVert *v,
+ float edge_index,
+ struct EDBMSplitElem *r_pair_elem)
+{
+ BLI_assert(v->head.index == -1);
+ v->head.index = edge_index;
+ r_pair_elem->vert = v;
+}
+
+static void bm_edge_pair_elem_setup(BMEdge *e,
+ float lambda,
+ int *r_data_cut_edges_len,
+ struct EDBMSplitElem *r_pair_elem)
+{
+ r_pair_elem->edge = e;
+ r_pair_elem->lambda = lambda;
+
+ e->head.index++;
+ /* Obs: Check Multithread. */
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
+ (*r_data_cut_edges_len)++;
+ }
+}
+
+/* Util for Vert x Edge and Edge x Edge callbacks */
+static bool bm_vertxedge_isect_impl_ex(BMVert *v,
+ BMEdge *e,
+ int edge_index,
+ const float co[3],
+ const float dir[3],
+ float lambda,
+ float data_dist_sq,
+ int *data_cut_edges_len,
+ struct EDBMSplitElem r_pair[2])
+{
+ BLI_assert(v->head.index == -1);
+
+ BMVert *e_v;
+ float dist_sq_vert_factor;
+
+ if (lambda < 0.5f) {
+ e_v = e->v1;
+ dist_sq_vert_factor = lambda;
+ }
+ else {
+ e_v = e->v2;
+ dist_sq_vert_factor = 1.0f - lambda;
+ }
+
+ if (v != e_v) {
+ CLAMP(lambda, 0.0f, 1.0f);
+
+ float near[3];
+ madd_v3_v3v3fl(near, co, dir, lambda);
+
+ float dist_sq = len_squared_v3v3(v->co, near);
+ if (dist_sq < data_dist_sq) {
+ float dist_sq_vert = SQUARE(dist_sq_vert_factor) * len_squared_v3(dir);
+ if (dist_sq_vert < data_dist_sq) {
+ if (e_v->head.index != -1) {
+ /* Vertex already has an intersection. */
+ return false;
+ }
+
+ bm_vert_pair_elem_setup_ex(e_v, -2, &r_pair[1]);
+ }
+ else {
+ bm_edge_pair_elem_setup(e, lambda, data_cut_edges_len, &r_pair[1]);
+ }
+
+ bm_vert_pair_elem_setup_ex(v, edge_index, &r_pair[0]);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Vertex x Vertex Callback */
+
+static bool bm_vertxvert_isect_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
+{
+ struct EDBMSplitData *data = userdata;
+ BMVert *v_a = BM_vert_at_index(data->bm, index_a);
+ BMVert *v_b = BM_vert_at_index(data->bm, index_b);
+
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
+
+ BLI_assert(v_a->head.index == -1);
+
+ /* Set index -2 for sure that it will not repeat keys in `targetmap`. */
+ bm_vert_pair_elem_setup_ex(v_a, -2, &pair[0]);
+ bm_vert_pair_elem_setup_ex(v_b, -1, &pair[1]);
+
+ return true;
+}
+
+/* Vertex x Edge and Edge x Vertex Callbacks */
+
+static int bm_vertxedge_isect_impl(BMesh *bm,
+ int vert_index,
+ int edge_index,
+ float data_dist_sq,
+ int *data_cut_edges_len,
+ struct EDBMSplitElem r_pair[2])
+{
+ BMVert *v = BM_vert_at_index(bm, vert_index);
+ BMEdge *e = BM_edge_at_index(bm, edge_index);
+
+ if (v->head.index != -1) {
+ /* Only one vertex per edge. */
+ return false;
+ }
+
+ float co[3], dir[3], lambda;
+ copy_v3_v3(co, e->v1->co);
+ sub_v3_v3v3(dir, e->v2->co, co);
+ lambda = ray_point_factor_v3_ex(v->co, co, dir, 0.0f, -1.0f);
+
+ return bm_vertxedge_isect_impl_ex(
+ v, e, edge_index, co, dir, lambda, data_dist_sq, data_cut_edges_len, r_pair);
+}
+
+static bool bm_vertxedge_isect_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
+{
+ struct EDBMSplitData *data = userdata;
+ struct EDBMSplitElem pair_tmp[2];
+ if (bm_vertxedge_isect_impl(
+ data->bm, index_a, index_b, data->dist_sq, &data->cut_edges_b_len, pair_tmp)) {
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
+ pair[0] = pair_tmp[0];
+ pair[1] = pair_tmp[1];
+
+ return true;
+ }
+
+ return false;
+}
+
+static bool bm_edgexvert_isect_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
+{
+ struct EDBMSplitData *data = userdata;
+ struct EDBMSplitElem pair_tmp[2];
+ if (bm_vertxedge_isect_impl(
+ data->bm, index_b, index_a, data->dist_sq, &data->cut_edges_a_len, pair_tmp)) {
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
+ pair[0] = pair_tmp[1];
+ pair[1] = pair_tmp[0];
+
+ return true;
+ }
+
+ return false;
+}
+
+/* Edge x Edge Callbacks */
+
+static void bm_edgexedge_isect_impl(struct EDBMSplitData *data,
+ int index_a,
+ int index_b,
+ BMEdge *e_a,
+ BMEdge *e_b,
+ const float co_a[3],
+ const float dir_a[3],
+ const float co_b[3],
+ const float dir_b[3],
+ float lambda_a,
+ float lambda_b)
+{
+ float dist_sq_va_factor, dist_sq_vb_factor;
+ BMVert *e_a_v, *e_b_v;
+ if (lambda_a < 0.5f) {
+ e_a_v = e_a->v1;
+ dist_sq_va_factor = lambda_a;
+ }
+ else {
+ e_a_v = e_a->v2;
+ dist_sq_va_factor = 1.0f - lambda_a;
+ }
+
+ if (lambda_b < 0.5f) {
+ e_b_v = e_b->v1;
+ dist_sq_vb_factor = lambda_b;
+ }
+ else {
+ e_b_v = e_b->v2;
+ dist_sq_vb_factor = 1.0f - lambda_b;
+ }
+
+ if (e_a_v != e_b_v) {
+ CLAMP(lambda_a, 0.0f, 1.0f);
+ CLAMP(lambda_b, 0.0f, 1.0f);
+
+ float near_a[3], near_b[3];
+ madd_v3_v3v3fl(near_a, co_a, dir_a, lambda_a);
+ madd_v3_v3v3fl(near_b, co_b, dir_b, lambda_b);
+
+ float dist_sq = len_squared_v3v3(near_a, near_b);
+ if (dist_sq < data->dist_sq) {
+ struct EDBMSplitElem pair_tmp[2];
+
+ float dist_sq_va = SQUARE(dist_sq_va_factor) * len_squared_v3(dir_a);
+ float dist_sq_vb = SQUARE(dist_sq_vb_factor) * len_squared_v3(dir_b);
+
+ if (dist_sq_va < data->dist_sq) {
+ if (e_a_v->head.index != -1) {
+ /* Only one vertex per edge. */
+ return;
+ }
+ bm_vert_pair_elem_setup_ex(e_a_v, index_b, &pair_tmp[0]);
+ }
+
+ if (dist_sq_vb < data->dist_sq) {
+ if (e_b_v->head.index != -1) {
+ /* Only one vertex per edge. */
+ return;
+ }
+ bm_vert_pair_elem_setup_ex(e_b_v, index_a, &pair_tmp[1]);
+ }
+ else {
+ bm_edge_pair_elem_setup(e_b, lambda_b, &data->cut_edges_b_len, &pair_tmp[1]);
+ }
+
+ /* Don't setup edges before a return. */
+ if (dist_sq_va >= data->dist_sq) {
+ bm_edge_pair_elem_setup(e_a, lambda_a, &data->cut_edges_a_len, &pair_tmp[0]);
+ }
+
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
+ pair[0] = pair_tmp[0];
+ pair[1] = pair_tmp[1];
+ }
+ }
+}
+
+static bool bm_edgexedge_isect_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
+{
+ bool ret = false;
+ struct EDBMSplitData *data = userdata;
+ BMEdge *e_a = BM_edge_at_index(data->bm, index_a);
+ BMEdge *e_b = BM_edge_at_index(data->bm, index_b);
+
+ float co_a[3], dir_a[3], co_b[3], dir_b[3];
+ copy_v3_v3(co_a, e_a->v1->co);
+ sub_v3_v3v3(dir_a, e_a->v2->co, co_a);
+
+ copy_v3_v3(co_b, e_b->v1->co);
+ sub_v3_v3v3(dir_b, e_b->v2->co, co_b);
+
+ float lambda_a, lambda_b;
+ /* Using with dist^4 as `epsilon` is not the best solution, but it fits in most cases. */
+ if (isect_ray_ray_epsilon_v3(co_a, dir_a, co_b, dir_b, data->dist_sq_sq, &lambda_a, &lambda_b)) {
+ if (ELEM(index_b, e_a->v1->head.index, e_a->v2->head.index) ||
+ ELEM(index_a, e_b->v1->head.index, e_b->v2->head.index)) {
+ return ret;
+ }
+
+ /* Edge x Edge returns always false. */
+ bm_edgexedge_isect_impl(
+ data, index_a, index_b, e_a, e_b, co_a, dir_a, co_b, dir_b, lambda_a, lambda_b);
+ }
+ else {
+ /* Parallel */
+ struct EDBMSplitElem pair_tmp[2];
+ float vec[3], len_sq_a, len_sq_b, lambda;
+ sub_v3_v3v3(vec, co_b, co_a);
+ len_sq_a = len_squared_v3(dir_a);
+ len_sq_b = len_squared_v3(dir_b);
+
+ if (!ELEM(e_b->v1, e_a->v1, e_a->v2) && e_b->v1->head.index == -1) {
+ lambda = dot_v3v3(vec, dir_a) / len_sq_a;
+ if (bm_vertxedge_isect_impl_ex(e_b->v1,
+ e_a,
+ index_a,
+ co_a,
+ dir_a,
+ lambda,
+ data->dist_sq,
+ &data->cut_edges_a_len,
+ pair_tmp)) {
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
+ pair[0] = pair_tmp[1];
+ pair[1] = pair_tmp[0];
+ ret |= true;
+ }
+ }
+
+ if (!ELEM(e_a->v1, e_b->v1, e_b->v2) && e_a->v1->head.index == -1) {
+ lambda = -dot_v3v3(vec, dir_b) / len_sq_b;
+ if (bm_vertxedge_isect_impl_ex(e_a->v1,
+ e_b,
+ index_b,
+ co_b,
+ dir_b,
+ lambda,
+ data->dist_sq,
+ &data->cut_edges_b_len,
+ pair_tmp)) {
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
+ pair[0] = pair_tmp[0];
+ pair[1] = pair_tmp[1];
+ ret |= true;
+ }
+ }
+
+ add_v3_v3(vec, dir_b);
+ if (!ELEM(e_b->v2, e_a->v1, e_a->v2) && e_b->v2->head.index == -1) {
+ lambda = dot_v3v3(vec, dir_a) / len_sq_a;
+ if (bm_vertxedge_isect_impl_ex(e_b->v2,
+ e_a,
+ index_a,
+ co_a,
+ dir_a,
+ lambda,
+ data->dist_sq,
+ &data->cut_edges_a_len,
+ pair_tmp)) {
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
+ pair[0] = pair_tmp[1];
+ pair[1] = pair_tmp[0];
+ ret |= true;
+ }
+ }
+
+ sub_v3_v3(vec, dir_a);
+ if (!ELEM(e_a->v2, e_b->v1, e_b->v2) && e_a->v2->head.index == -1) {
+ lambda = 1.0f - dot_v3v3(vec, dir_b) / len_sq_b;
+ if (bm_vertxedge_isect_impl_ex(e_a->v2,
+ e_b,
+ index_b,
+ co_b,
+ dir_b,
+ lambda,
+ data->dist_sq,
+ &data->cut_edges_b_len,
+ pair_tmp)) {
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
+ pair[0] = pair_tmp[0];
+ pair[1] = pair_tmp[1];
+ ret |= true;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/* -------------------------------------------------------------------- */
+/* BVHTree Overlap Function */
+
+static void bvhtree_overlap_thread_safe(const BVHTree *tree1,
+ const BVHTree *tree2,
+ BVHTree_OverlapCallback callback,
+ void *userdata)
+{
+ BLI_bvhtree_overlap_ex(tree1, tree2, NULL, callback, userdata, BVH_OVERLAP_BREAK_ON_FIRST);
+}
+
+/* -------------------------------------------------------------------- */
+/* Callbacks for `BLI_qsort_r` */
+
+static int sort_cmp_by_lambda_a_cb(const void *index1_v, const void *index2_v, void *keys_v)
+{
+ const struct EDBMSplitElem(*pair_array)[2] = keys_v;
+ const int index1 = *(int *)index1_v;
+ const int index2 = *(int *)index2_v;
+
+ if (pair_array[index1][0].lambda > pair_array[index2][0].lambda) {
+ return 1;
+ }
+ else {
+ return -1;
+ }
+}
+
+static int sort_cmp_by_lambda_b_cb(const void *index1_v, const void *index2_v, void *keys_v)
+{
+ const struct EDBMSplitElem(*pair_array)[2] = keys_v;
+ const int index1 = *(int *)index1_v;
+ const int index2 = *(int *)index2_v;
+
+ if (pair_array[index1][1].lambda > pair_array[index2][1].lambda) {
+ return 1;
+ }
+ else {
+ return -1;
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/* Main API */
+
+bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHash *r_targetmap)
+{
+ bool ok = false;
+
+ BMIter iter;
+ BMVert *v;
+ BMEdge *e;
+ int i;
+
+ BM_mesh_elem_table_ensure(bm, BM_VERT | BM_EDGE);
+
+ /* Store all intersections in this array. */
+ struct EDBMSplitElem(*pair_iter)[2], (*pair_array)[2] = NULL;
+ BLI_Stack *pair_stack = BLI_stack_new(sizeof(*pair_array), __func__);
+ int pair_len = 0;
+
+ float dist_sq = SQUARE(dist);
+ struct EDBMSplitData data = {
+ .bm = bm,
+ .pair_stack = pair_stack,
+ .cut_edges_a_len = 0,
+ .cut_edges_b_len = 0,
+ .dist_sq = dist_sq,
+ .dist_sq_sq = SQUARE(dist_sq),
+ };
+
+ /* tag and count the verts to be tested. */
+ int verts_act_len = 0, verts_remain_len = 0;
+ int loose_verts_act_len = 0, loose_verts_remain_len = 0;
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, hflag)) {
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ v->head.index = -1;
+ verts_act_len++;
+ if (!v->e) {
+ loose_verts_act_len++;
+ }
+ }
+ else {
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
+ v->head.index = -1;
+ verts_remain_len++;
+ if (!v->e) {
+ loose_verts_remain_len++;
+ }
+ }
+ }
+ }
+ bm->elem_index_dirty |= BM_VERT;
+
+ /* Start the creation of BVHTrees. */
+ BVHTree *tree_loose_verts_act = NULL, *tree_loose_verts_remain = NULL;
+ if (loose_verts_act_len) {
+ tree_loose_verts_act = BLI_bvhtree_new(loose_verts_act_len, dist, 2, KDOP_AXIS_LEN);
+ }
+ if (loose_verts_remain_len) {
+ tree_loose_verts_remain = BLI_bvhtree_new(loose_verts_remain_len, 0.0f, 2, KDOP_AXIS_LEN);
+ }
+
+ if (tree_loose_verts_act || tree_loose_verts_remain) {
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ if (tree_loose_verts_act && !v->e) {
+ BLI_bvhtree_insert(tree_loose_verts_act, i, v->co, 1);
+ }
+ }
+ else if (tree_loose_verts_remain && !v->e && !BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
+ BLI_bvhtree_insert(tree_loose_verts_remain, i, v->co, 1);
+ }
+ }
+ if (tree_loose_verts_act) {
+ BLI_bvhtree_balance(tree_loose_verts_act);
+ }
+
+ if (tree_loose_verts_remain) {
+ BLI_bvhtree_balance(tree_loose_verts_remain);
+ }
+
+ if (tree_loose_verts_act && tree_loose_verts_remain) {
+ /* First pair search. */
+ bvhtree_overlap_thread_safe(
+ tree_loose_verts_act, tree_loose_verts_remain, bm_vertxvert_isect_cb, &data);
+ }
+ }
+
+ /* Tag and count the edges. */
+ int edges_act_len = 0, edges_remain_len = 0;
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e->v1, BM_ELEM_TAG) || BM_elem_flag_test(e->v2, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ edges_act_len++;
+ }
+ else {
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ edges_remain_len++;
+ }
+ }
+ }
+
+ if (edges_remain_len) {
+ BVHTree *tree_edges_act = NULL, *tree_edges_remain = NULL;
+ tree_edges_remain = BLI_bvhtree_new(edges_remain_len, 0.0f, 2, KDOP_AXIS_LEN);
+ if (edges_act_len) {
+ tree_edges_act = BLI_bvhtree_new(edges_act_len, dist, 2, KDOP_AXIS_LEN);
+ }
+
+ BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
+ float co[2][3];
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ if (tree_edges_act) {
+ e->head.index = 0;
+ copy_v3_v3(co[0], e->v1->co);
+ copy_v3_v3(co[1], e->v2->co);
+ BLI_bvhtree_insert(tree_edges_act, i, co[0], 2);
+ }
+ }
+ else if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ /* Tag used in the overlap callbacks. */
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ e->head.index = 0;
+ copy_v3_v3(co[0], e->v1->co);
+ copy_v3_v3(co[1], e->v2->co);
+ BLI_bvhtree_insert(tree_edges_remain, i, co[0], 2);
+ }
+ }
+ /* Use `e->head.index` to count intersections. */
+ bm->elem_index_dirty |= BM_EDGE;
+
+ BLI_bvhtree_balance(tree_edges_remain);
+ if (tree_edges_act) {
+ BLI_bvhtree_balance(tree_edges_act);
+ }
+
+ if (tree_edges_act) {
+ /* Edge x Edge */
+ bvhtree_overlap_thread_safe(tree_edges_act, tree_edges_remain, bm_edgexedge_isect_cb, &data);
+
+ if (tree_loose_verts_remain) {
+ /* Edge x Vert */
+ bvhtree_overlap_thread_safe(
+ tree_edges_act, tree_loose_verts_remain, bm_edgexvert_isect_cb, &data);
+ }
+
+ BLI_bvhtree_free(tree_edges_act);
+ }
+
+ if (tree_loose_verts_act) {
+ /* Vert x Edge */
+ bvhtree_overlap_thread_safe(
+ tree_loose_verts_act, tree_edges_remain, bm_vertxedge_isect_cb, &data);
+ }
+
+ BLI_bvhtree_free(tree_edges_remain);
+
+ pair_len = BLI_stack_count(pair_stack);
+ if (pair_len) {
+ pair_array = MEM_mallocN(sizeof(*pair_array) * pair_len, __func__);
+ BLI_stack_pop_n_reverse(pair_stack, pair_array, pair_len);
+
+ /* Map intersections per edge. */
+ union {
+ struct {
+ int cuts_len;
+ int cuts_index[];
+ };
+ int as_int[0];
+ } * e_map_iter, *e_map;
+
+ size_t e_map_size = (max_ii(data.cut_edges_a_len, data.cut_edges_b_len) * sizeof(*e_map)) +
+ (pair_len * sizeof(*(e_map->cuts_index)));
+
+ e_map = MEM_mallocN(e_map_size, __func__);
+
+ /* Convert every pair to Vert x Vert. */
+ for (int pair = 0; pair < 2; pair++) {
+ int map_len = 0;
+ pair_iter = &pair_array[0];
+ for (i = 0; i < pair_len; i++, pair_iter++) {
+ if ((*pair_iter)[pair].elem->head.htype != BM_EDGE) {
+ /* Take the opportunity to set all vert indices to -1 again. */
+ (*pair_iter)[pair].elem->head.index = -1;
+ continue;
+ }
+ e = (*pair_iter)[pair].edge;
+ if (!BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ int e_cuts_len = e->head.index;
+
+ e_map_iter = (void *)&e_map->as_int[map_len];
+ e_map_iter->cuts_len = e_cuts_len;
+ e_map_iter->cuts_index[0] = i;
+
+ /* Use `e->head.index` to indicate which slot to fill with the `cut` index. */
+ e->head.index = map_len + 1;
+ map_len += 1 + e_cuts_len;
+ }
+ else {
+ e_map->as_int[++e->head.index] = i;
+ }
+ }
+
+ /* Split Edges A to set all Vert x Edge. */
+ for (i = 0; i < map_len;
+ e_map_iter = (void *)&e_map->as_int[i], i += 1 + e_map_iter->cuts_len) {
+
+ /* sort by lambda. */
+ BLI_qsort_r(e_map_iter->cuts_index,
+ e_map_iter->cuts_len,
+ sizeof(*(e_map->cuts_index)),
+ pair == 0 ? sort_cmp_by_lambda_a_cb : sort_cmp_by_lambda_b_cb,
+ pair_array);
+
+ float lambda, lambda_prev = 0.0f;
+ for (int j = 0; j < e_map_iter->cuts_len; j++) {
+ struct EDBMSplitElem *pair_elem = &pair_array[e_map_iter->cuts_index[j]][pair];
+ lambda = (pair_elem->lambda - lambda_prev) / (1.0f - lambda_prev);
+ lambda_prev = pair_elem->lambda;
+ e = pair_elem->edge;
+
+ BMVert *v_new = BM_edge_split(bm, e, e->v1, NULL, lambda);
+ v_new->head.index = -1;
+ pair_elem->vert = v_new;
+ }
+ }
+ }
+
+ MEM_freeN(e_map);
+ }
+ }
+
+ BLI_bvhtree_free(tree_loose_verts_act);
+ BLI_bvhtree_free(tree_loose_verts_remain);
+
+ if (r_targetmap) {
+ if (pair_array == NULL) {
+ pair_len = BLI_stack_count(pair_stack);
+ if (pair_len) {
+ pair_array = MEM_mallocN(sizeof(*pair_array) * pair_len, __func__);
+ BLI_stack_pop_n_reverse(pair_stack, pair_array, pair_len);
+ }
+ }
+
+ if (pair_array) {
+ /* Organize the vertices in the order they will be merged. */
+ pair_iter = &pair_array[0];
+ for (i = 0; i < pair_len; i++, pair_iter++) {
+ BLI_assert((*pair_iter)[0].elem->head.htype == BM_VERT);
+ BLI_assert((*pair_iter)[1].elem->head.htype == BM_VERT);
+ BLI_assert((*pair_iter)[0].elem != (*pair_iter)[1].elem);
+
+ BLI_ghash_insert(r_targetmap, (*pair_iter)[0].vert, (*pair_iter)[1].vert);
+ }
+
+ ok = true;
+ }
+ }
+
+ BLI_stack_free(pair_stack);
+ if (pair_array) {
+ MEM_freeN(pair_array);
+ }
+
+ return ok;
+}
+
+/** \} */
diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.h b/source/blender/bmesh/tools/bmesh_intersect_edges.h
new file mode 100644
index 00000000000..a22a1ca1e1d
--- /dev/null
+++ b/source/blender/bmesh/tools/bmesh_intersect_edges.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 bmesh
+ */
+
+#ifndef __BMESH_INTERSECT_EDGES_H__
+#define __BMESH_INTERSECT_EDGES_H__
+
+void BM_vert_weld_linked_wire_edges_into_linked_faces(
+ BMesh *bm, BMVert *v, const float epsilon, BMEdge **r_edgenet[], int *r_edgenet_alloc_len);
+
+bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHash *r_targetmap);
+
+#endif /* __BMESH_INTERSECT_EDGES_H__ */
diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp
index a15c215d2e2..9d0d075cade 100644
--- a/source/blender/collada/AnimationExporter.cpp
+++ b/source/blender/collada/AnimationExporter.cpp
@@ -594,7 +594,7 @@ std::string AnimationExporter::collada_tangent_from_curve(
const FCurve *fcu = curve.get_fcurve();
int tangent = (semantic == COLLADASW::InputSemantic::IN_TANGENT) ? 0 : 2;
- for (int i = 0; i < fcu->totvert; ++i) {
+ for (int i = 0; i < fcu->totvert; i++) {
BezTriple &bezt = fcu->bezt[i];
float sampled_time = bezt.vec[tangent][0];
diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp
index 54177560eb5..79593f07383 100644
--- a/source/blender/collada/AnimationImporter.cpp
+++ b/source/blender/collada/AnimationImporter.cpp
@@ -733,7 +733,7 @@ void AnimationImporter::Assign_float_animations(const COLLADAFW::UniqueId &listi
* Reason: old blender versions stored spot_size in radians (was a bug)
*/
if (this->import_from_version == "" ||
- BLI_natstrcmp(this->import_from_version.c_str(), "2.69.10") != -1) {
+ BLI_strcasecmp_natural(this->import_from_version.c_str(), "2.69.10") != -1) {
fcurve_deg_to_rad(fcu);
}
}
diff --git a/source/blender/collada/BCAnimationCurve.cpp b/source/blender/collada/BCAnimationCurve.cpp
index b494c749fe3..bf32ec9148c 100644
--- a/source/blender/collada/BCAnimationCurve.cpp
+++ b/source/blender/collada/BCAnimationCurve.cpp
@@ -249,7 +249,7 @@ const int BCAnimationCurve::closest_index_below(const float sample_frame) const
int lower_index = 0;
int upper_index = 0;
- for (int fcu_index = 0; fcu_index < fcurve->totvert; ++fcu_index) {
+ for (int fcu_index = 0; fcu_index < fcurve->totvert; fcu_index++) {
upper_index = fcu_index;
const int cframe = fcurve->bezt[fcu_index].vec[1][0]; // inacurate!
@@ -537,7 +537,7 @@ bool BCAnimationCurve::is_keyframe(int frame)
return false;
}
- for (int i = 0; i < fcurve->totvert; ++i) {
+ for (int i = 0; i < fcurve->totvert; i++) {
const int cframe = nearbyint(fcurve->bezt[i].vec[1][0]);
if (cframe == frame) {
return true;
diff --git a/source/blender/collada/BCAnimationSampler.cpp b/source/blender/collada/BCAnimationSampler.cpp
index 49d87f92fda..5262d0b3672 100644
--- a/source/blender/collada/BCAnimationSampler.cpp
+++ b/source/blender/collada/BCAnimationSampler.cpp
@@ -129,7 +129,7 @@ static void add_keyframes_from(bAction *action, BCFrameSet &frameset)
void BCAnimationSampler::check_property_is_animated(
BCAnimation &animation, float *ref, float *val, std::string data_path, int length)
{
- for (int array_index = 0; array_index < length; ++array_index) {
+ for (int array_index = 0; array_index < length; array_index++) {
if (!bc_in_range(ref[length], val[length], 0.00001)) {
BCCurveKey key(BC_ANIMATION_TYPE_OBJECT, data_path, array_index);
BCAnimationCurveMap::iterator it = animation.curve_map.find(key);
@@ -195,7 +195,7 @@ void BCAnimationSampler::sample_scene(BCExportSettings &export_settings, bool ke
int startframe = scene->r.sfra;
int endframe = scene->r.efra;
- for (int frame_index = startframe; frame_index <= endframe; ++frame_index) {
+ for (int frame_index = startframe; frame_index <= endframe; frame_index++) {
/* Loop over all frames and decide for each frame if sampling is necessary */
bool is_scene_sample_frame = false;
bool needs_update = true;
diff --git a/source/blender/collada/BlenderContext.cpp b/source/blender/collada/BlenderContext.cpp
index 709f84c3f77..8735d71ec40 100644
--- a/source/blender/collada/BlenderContext.cpp
+++ b/source/blender/collada/BlenderContext.cpp
@@ -121,7 +121,7 @@ bContext *BlenderContext::get_context()
Depsgraph *BlenderContext::get_depsgraph()
{
if (!depsgraph) {
- depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ depsgraph = BKE_scene_get_depsgraph(main, scene, view_layer, true);
}
return depsgraph;
}
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index 98b166716c3..9d838406101 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -333,7 +333,7 @@ std::string DocumentImporter::get_import_version(const COLLADAFW::FileInfo *asse
const char AUTORING_TOOL[] = "authoring_tool";
const std::string BLENDER("Blender ");
const COLLADAFW::FileInfo::ValuePairPointerArray &valuePairs = asset->getValuePairArray();
- for (size_t i = 0, count = valuePairs.getCount(); i < count; ++i) {
+ for (size_t i = 0, count = valuePairs.getCount(); i < count; i++) {
const COLLADAFW::FileInfo::ValuePair *valuePair = valuePairs[i];
const COLLADAFW::String &key = valuePair->first;
const COLLADAFW::String &value = valuePair->second;
@@ -567,7 +567,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node,
root_objects->push_back(ob);
}
}
- ++geom_done;
+ geom_done++;
}
while (camera_done < camera.getCount()) {
ob = create_camera_object(camera[camera_done], sce);
@@ -580,7 +580,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node,
root_objects->push_back(ob);
}
}
- ++camera_done;
+ camera_done++;
}
while (lamp_done < lamp.getCount()) {
ob = create_light_object(lamp[lamp_done], sce);
@@ -593,7 +593,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node,
root_objects->push_back(ob);
}
}
- ++lamp_done;
+ lamp_done++;
}
while (controller_done < controller.getCount()) {
COLLADAFW::InstanceGeometry *geometry = (COLLADAFW::InstanceGeometry *)
@@ -608,7 +608,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node,
root_objects->push_back(ob);
}
}
- ++controller_done;
+ controller_done++;
}
/* XXX instance_node is not supported yet */
while (inst_done < inst_node.getCount()) {
@@ -635,7 +635,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node,
}
}
}
- ++inst_done;
+ inst_done++;
read_transform = false;
}
diff --git a/source/blender/collada/SceneExporter.cpp b/source/blender/collada/SceneExporter.cpp
index 01854bef328..24449de0ddd 100644
--- a/source/blender/collada/SceneExporter.cpp
+++ b/source/blender/collada/SceneExporter.cpp
@@ -88,7 +88,7 @@ void SceneExporter::writeNodeList(std::vector<Object *> &child_objects, Object *
* I really prefer to enforce the export of hidden
* elements in an object hierarchy. When the children of
* the hidden elements are exported as well. */
- for (int i = 0; i < child_objects.size(); ++i) {
+ for (int i = 0; i < child_objects.size(); i++) {
Object *child = child_objects[i];
writeNode(child);
if (bc_is_marked(child)) {
diff --git a/source/blender/compositor/intern/COM_Debug.cpp b/source/blender/compositor/intern/COM_Debug.cpp
index 72c1e0cf316..c2ef7d37a59 100644
--- a/source/blender/compositor/intern/COM_Debug.cpp
+++ b/source/blender/compositor/intern/COM_Debug.cpp
@@ -335,7 +335,7 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
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) {
+ 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);
@@ -377,7 +377,7 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
}
/* operations not included in any group */
- for (int j = 0; j < totops; ++j) {
+ for (int j = 0; j < totops; j++) {
NodeOperation *operation = system->m_operations[j];
if (op_groups.find(operation) != op_groups.end()) {
continue;
@@ -397,8 +397,8 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
std::vector<std::string> &read_groups = op_groups[read];
std::vector<std::string> &write_groups = op_groups[write];
- for (int k = 0; k < write_groups.size(); ++k) {
- for (int l = 0; l < read_groups.size(); ++l) {
+ for (int k = 0; k < write_groups.size(); k++) {
+ for (int l = 0; l < read_groups.size(); l++) {
len += snprintf(str + len,
maxlen > len ? maxlen - len : 0,
"\"O_%p%s\" -> \"O_%p%s\" [style=dotted]\r\n",
@@ -448,8 +448,8 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
from,
to_op,
to);
- for (int k = 0; k < from_groups.size(); ++k) {
- for (int l = 0; l < to_groups.size(); ++l) {
+ for (int k = 0; k < from_groups.size(); k++) {
+ 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",
@@ -483,7 +483,7 @@ void DebugInfo::graphviz(const ExecutionSystem *system)
BLI_snprintf(basename, sizeof(basename), "compositor_%d.dot", m_file_index);
BLI_join_dirfile(filename, sizeof(filename), BKE_tempdir_session(), basename);
- ++m_file_index;
+ m_file_index++;
FILE *fp = BLI_fopen(filename, "wb");
fputs(str, fp);
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
index 198385649da..a00c613d1e2 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
@@ -608,7 +608,7 @@ static void find_reachable_operations_recursive(Tags &reachable, NodeOperation *
}
reachable.insert(op);
- for (int i = 0; i < op->getNumberOfInputSockets(); ++i) {
+ for (int i = 0; i < op->getNumberOfInputSockets(); i++) {
NodeOperationInput *input = op->getInputSocket(i);
if (input->isConnected()) {
find_reachable_operations_recursive(reachable, &input->getLink()->getOperation());
@@ -661,7 +661,7 @@ static void sort_operations_recursive(NodeOperationBuilder::Operations &sorted,
}
visited.insert(op);
- for (int i = 0; i < op->getNumberOfInputSockets(); ++i) {
+ for (int i = 0; i < op->getNumberOfInputSockets(); i++) {
NodeOperationInput *input = op->getInputSocket(i);
if (input->isConnected()) {
sort_operations_recursive(sorted, visited, &input->getLink()->getOperation());
@@ -696,7 +696,7 @@ static void add_group_operations_recursive(Tags &visited, NodeOperation *op, Exe
}
/* add all eligible input ops to the group */
- for (int i = 0; i < op->getNumberOfInputSockets(); ++i) {
+ for (int i = 0; i < op->getNumberOfInputSockets(); i++) {
NodeOperationInput *input = op->getInputSocket(i);
if (input->isConnected()) {
add_group_operations_recursive(visited, &input->getLink()->getOperation(), group);
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cpp
index 48af823f8f5..5ed2af0c11d 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.cpp
+++ b/source/blender/compositor/intern/COM_WorkScheduler.cpp
@@ -239,8 +239,8 @@ void WorkScheduler::initialize(bool use_opencl, int num_cpu_threads)
g_context = NULL;
g_program = NULL;
- if (clewInit() !=
- CLEW_SUCCESS) { /* this will check for errors and skip if already initialized */
+ /* This will check for errors and skip if already initialized. */
+ if (clewInit() != CLEW_SUCCESS) {
return;
}
diff --git a/source/blender/compositor/nodes/COM_CornerPinNode.cpp b/source/blender/compositor/nodes/COM_CornerPinNode.cpp
index 9a9ecb755af..efe847bbfbf 100644
--- a/source/blender/compositor/nodes/COM_CornerPinNode.cpp
+++ b/source/blender/compositor/nodes/COM_CornerPinNode.cpp
@@ -45,7 +45,7 @@ void CornerPinNode::convertToOperations(NodeConverter &converter,
converter.addOperation(plane_mask_operation);
converter.mapInputSocket(input_image, warp_image_operation->getInputSocket(0));
- for (int i = 0; i < 4; ++i) {
+ for (int i = 0; i < 4; i++) {
NodeInput *corner_input = getInputSocket(node_corner_index[i]);
converter.mapInputSocket(corner_input, warp_image_operation->getInputSocket(i + 1));
converter.mapInputSocket(corner_input, plane_mask_operation->getInputSocket(i));
diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp b/source/blender/compositor/nodes/COM_CryptomatteNode.cpp
index 4219fd49d44..da80ef697c1 100644
--- a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cpp
@@ -90,7 +90,7 @@ void CryptomatteNode::convertToOperations(NodeConverter &converter,
converter.addOperation(operation);
- for (int i = 0; i < getNumberOfInputSockets() - 1; ++i) {
+ for (int i = 0; i < getNumberOfInputSockets() - 1; i++) {
converter.mapInputSocket(this->getInputSocket(i + 1), operation->getInputSocket(i));
}
diff --git a/source/blender/compositor/nodes/COM_ImageNode.cpp b/source/blender/compositor/nodes/COM_ImageNode.cpp
index 6bce56ffd52..8e2590a9d92 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.cpp
+++ b/source/blender/compositor/nodes/COM_ImageNode.cpp
@@ -206,7 +206,7 @@ void ImageNode::convertToOperations(NodeConverter &converter,
/* without this, multilayer that fail to load will crash blender [#32490] */
if (is_multilayer_ok == false) {
- for (int i = 0; i < getNumberOfOutputSockets(); ++i) {
+ for (int i = 0; i < getNumberOfOutputSockets(); i++) {
converter.setInvalidOutput(getOutputSocket(i));
}
}
diff --git a/source/blender/compositor/nodes/COM_ImageNode.h b/source/blender/compositor/nodes/COM_ImageNode.h
index 781fef37355..cde9f997f85 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.h
+++ b/source/blender/compositor/nodes/COM_ImageNode.h
@@ -16,6 +16,9 @@
* Copyright 2011, Blender Foundation.
*/
+#ifndef __COM_IMAGENODE_H__
+#define __COM_IMAGENODE_H__
+
#include "COM_defines.h"
#include "COM_Node.h"
#include "DNA_node_types.h"
@@ -44,3 +47,5 @@ class ImageNode : public Node {
ImageNode(bNode *editorNode);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
};
+
+#endif /* __COM_IMAGENODE_H__ */
diff --git a/source/blender/compositor/nodes/COM_KeyingNode.h b/source/blender/compositor/nodes/COM_KeyingNode.h
index 9ae1d04b03f..fc5f55e33ae 100644
--- a/source/blender/compositor/nodes/COM_KeyingNode.h
+++ b/source/blender/compositor/nodes/COM_KeyingNode.h
@@ -16,6 +16,9 @@
* Copyright 2012, Blender Foundation.
*/
+#ifndef __COM_KEYINGNODE_H__
+#define __COM_KEYINGNODE_H__
+
#include "COM_Node.h"
/**
@@ -55,3 +58,5 @@ class KeyingNode : public Node {
KeyingNode(bNode *editorNode);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
};
+
+#endif /* __COM_KEYINGNODE_H__ */
diff --git a/source/blender/compositor/nodes/COM_KeyingScreenNode.h b/source/blender/compositor/nodes/COM_KeyingScreenNode.h
index edaf0238667..12db2ed8889 100644
--- a/source/blender/compositor/nodes/COM_KeyingScreenNode.h
+++ b/source/blender/compositor/nodes/COM_KeyingScreenNode.h
@@ -16,6 +16,9 @@
* Copyright 2012, Blender Foundation.
*/
+#ifndef __COM_KEYINGSCREENNODE_H__
+#define __COM_KEYINGSCREENNODE_H__
+
#include "COM_Node.h"
#include "DNA_node_types.h"
@@ -28,3 +31,5 @@ class KeyingScreenNode : public Node {
KeyingScreenNode(bNode *editorNode);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
};
+
+#endif /* __COM_KEYINGSCREENNODE_H__ */
diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.cpp b/source/blender/compositor/nodes/COM_OutputFileNode.cpp
index 822359771f3..d40f822eb55 100644
--- a/source/blender/compositor/nodes/COM_OutputFileNode.cpp
+++ b/source/blender/compositor/nodes/COM_OutputFileNode.cpp
@@ -69,7 +69,7 @@ void OutputFileNode::convertToOperations(NodeConverter &converter,
int num_inputs = getNumberOfInputSockets();
bool previewAdded = false;
- for (int i = 0; i < num_inputs; ++i) {
+ for (int i = 0; i < num_inputs; i++) {
NodeInput *input = getInputSocket(i);
NodeImageMultiFileSocket *sockdata =
(NodeImageMultiFileSocket *)input->getbNodeSocket()->storage;
@@ -88,7 +88,7 @@ void OutputFileNode::convertToOperations(NodeConverter &converter,
else { /* single layer format */
int num_inputs = getNumberOfInputSockets();
bool previewAdded = false;
- for (int i = 0; i < num_inputs; ++i) {
+ for (int i = 0; i < num_inputs; i++) {
NodeInput *input = getInputSocket(i);
if (input->isLinked()) {
NodeImageMultiFileSocket *sockdata =
diff --git a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h
index 0d57163dc97..6ee73e22af0 100644
--- a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h
+++ b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h
@@ -16,6 +16,9 @@
* Copyright 2013, Blender Foundation.
*/
+#ifndef __COM_PLANETRACKDEFORMNODE_H__
+#define __COM_PLANETRACKDEFORMNODE_H__
+
#include "COM_Node.h"
extern "C" {
@@ -32,3 +35,5 @@ class PlaneTrackDeformNode : public Node {
PlaneTrackDeformNode(bNode *editorNode);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
};
+
+#endif /* __COM_PLANETRACKDEFORMNODE_H__ */
diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.h b/source/blender/compositor/nodes/COM_RenderLayersNode.h
index 7e574678f2b..f6822f98fd9 100644
--- a/source/blender/compositor/nodes/COM_RenderLayersNode.h
+++ b/source/blender/compositor/nodes/COM_RenderLayersNode.h
@@ -16,6 +16,9 @@
* Copyright 2011, Blender Foundation.
*/
+#ifndef __COM_RENDERLAYERSNODE_H__
+#define __COM_RENDERLAYERSNODE_H__
+
#include "COM_Node.h"
#include "DNA_node_types.h"
#include "COM_RenderLayersProg.h"
@@ -46,3 +49,5 @@ class RenderLayersNode : public Node {
void missingSocketLink(NodeConverter &converter, NodeOutput *output) const;
void missingRenderLink(NodeConverter &converter) const;
};
+
+#endif /* __COM_RENDERLAYERSNODE_H__ */
diff --git a/source/blender/compositor/nodes/COM_TextureNode.h b/source/blender/compositor/nodes/COM_TextureNode.h
index 026d42ce2c3..8fe620a89b3 100644
--- a/source/blender/compositor/nodes/COM_TextureNode.h
+++ b/source/blender/compositor/nodes/COM_TextureNode.h
@@ -16,6 +16,9 @@
* Copyright 2011, Blender Foundation.
*/
+#ifndef __COM_TEXTURENODE_H__
+#define __COM_TEXTURENODE_H__
+
#include "COM_Node.h"
#include "DNA_node_types.h"
@@ -28,3 +31,5 @@ class TextureNode : public Node {
TextureNode(bNode *editorNode);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
};
+
+#endif /* __COM_TEXTURENODE_H__ */
diff --git a/source/blender/compositor/nodes/COM_TrackPositionNode.h b/source/blender/compositor/nodes/COM_TrackPositionNode.h
index c9420764598..7136077a123 100644
--- a/source/blender/compositor/nodes/COM_TrackPositionNode.h
+++ b/source/blender/compositor/nodes/COM_TrackPositionNode.h
@@ -16,6 +16,9 @@
* Copyright 2012, Blender Foundation.
*/
+#ifndef __COM_TRACKPOSITIONNODE_H__
+#define __COM_TRACKPOSITIONNODE_H__
+
#include "COM_Node.h"
#include "DNA_node_types.h"
@@ -28,3 +31,5 @@ class TrackPositionNode : public Node {
TrackPositionNode(bNode *editorNode);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
};
+
+#endif /* __COM_TRACKPOSITIONNODE_H__ */
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp b/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
index 84c41134b89..1b2e3b2821e 100644
--- a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
@@ -93,7 +93,7 @@ __m128 *BlurBaseOperation::convert_gausstab_sse(const float *gausstab, int size)
{
int n = 2 * size + 1;
__m128 *gausstab_sse = (__m128 *)MEM_mallocN_aligned(sizeof(__m128) * n, 16, "gausstab sse");
- for (int i = 0; i < n; ++i) {
+ for (int i = 0; i < n; i++) {
gausstab_sse[i] = _mm_set1_ps(gausstab[i]);
}
return gausstab_sse;
diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.cpp b/source/blender/compositor/operations/COM_DenoiseOperation.cpp
index ad53ab13def..8235c296c5a 100644
--- a/source/blender/compositor/operations/COM_DenoiseOperation.cpp
+++ b/source/blender/compositor/operations/COM_DenoiseOperation.cpp
@@ -21,16 +21,19 @@
#include "COM_DenoiseOperation.h"
#include "BLI_math.h"
+#include "BLI_system.h"
#ifdef WITH_OPENIMAGEDENOISE
+# include "BLI_threads.h"
# include <OpenImageDenoise/oidn.hpp>
+static pthread_mutex_t oidn_lock = BLI_MUTEX_INITIALIZER;
#endif
#include <iostream>
DenoiseOperation::DenoiseOperation() : SingleThreadedOperation()
{
this->addInputSocket(COM_DT_COLOR);
- this->addInputSocket(COM_DT_COLOR);
this->addInputSocket(COM_DT_VECTOR);
+ this->addInputSocket(COM_DT_COLOR);
this->addOutputSocket(COM_DT_COLOR);
this->m_settings = NULL;
}
@@ -38,23 +41,23 @@ void DenoiseOperation::initExecution()
{
SingleThreadedOperation::initExecution();
this->m_inputProgramColor = getInputSocketReader(0);
- this->m_inputProgramAlbedo = getInputSocketReader(1);
- this->m_inputProgramNormal = getInputSocketReader(2);
+ this->m_inputProgramNormal = getInputSocketReader(1);
+ this->m_inputProgramAlbedo = getInputSocketReader(2);
}
void DenoiseOperation::deinitExecution()
{
this->m_inputProgramColor = NULL;
- this->m_inputProgramAlbedo = NULL;
this->m_inputProgramNormal = NULL;
+ this->m_inputProgramAlbedo = NULL;
SingleThreadedOperation::deinitExecution();
}
MemoryBuffer *DenoiseOperation::createMemoryBuffer(rcti *rect2)
{
MemoryBuffer *tileColor = (MemoryBuffer *)this->m_inputProgramColor->initializeTileData(rect2);
- MemoryBuffer *tileAlbedo = (MemoryBuffer *)this->m_inputProgramAlbedo->initializeTileData(rect2);
MemoryBuffer *tileNormal = (MemoryBuffer *)this->m_inputProgramNormal->initializeTileData(rect2);
+ MemoryBuffer *tileAlbedo = (MemoryBuffer *)this->m_inputProgramAlbedo->initializeTileData(rect2);
rcti rect;
rect.xmin = 0;
rect.ymin = 0;
@@ -62,7 +65,7 @@ MemoryBuffer *DenoiseOperation::createMemoryBuffer(rcti *rect2)
rect.ymax = getHeight();
MemoryBuffer *result = new MemoryBuffer(COM_DT_COLOR, &rect);
float *data = result->getBuffer();
- this->generateDenoise(data, tileColor, tileAlbedo, tileNormal, this->m_settings);
+ this->generateDenoise(data, tileColor, tileNormal, tileAlbedo, this->m_settings);
return result;
}
@@ -85,8 +88,8 @@ bool DenoiseOperation::determineDependingAreaOfInterest(rcti * /*input*/,
void DenoiseOperation::generateDenoise(float *data,
MemoryBuffer *inputTileColor,
- MemoryBuffer *inputTileAlbedo,
MemoryBuffer *inputTileNormal,
+ MemoryBuffer *inputTileAlbedo,
NodeDenoise *settings)
{
float *inputBufferColor = inputTileColor->getBuffer();
@@ -95,61 +98,69 @@ void DenoiseOperation::generateDenoise(float *data,
return;
}
#ifdef WITH_OPENIMAGEDENOISE
- oidn::DeviceRef device = oidn::newDevice();
- device.commit();
+ if (BLI_cpu_support_sse41()) {
+ oidn::DeviceRef device = oidn::newDevice();
+ device.commit();
- oidn::FilterRef filter = device.newFilter("RT");
- filter.setImage("color",
- inputBufferColor,
- oidn::Format::Float3,
- inputTileColor->getWidth(),
- inputTileColor->getHeight(),
- 0,
- 4 * sizeof(float));
- if (inputTileAlbedo && inputTileAlbedo->getBuffer()) {
- filter.setImage("albedo",
- inputTileAlbedo->getBuffer(),
+ oidn::FilterRef filter = device.newFilter("RT");
+ filter.setImage("color",
+ inputBufferColor,
oidn::Format::Float3,
- inputTileAlbedo->getWidth(),
- inputTileAlbedo->getHeight(),
+ inputTileColor->getWidth(),
+ inputTileColor->getHeight(),
0,
4 * sizeof(float));
- }
- if (inputTileNormal && inputTileNormal->getBuffer()) {
- filter.setImage("normal",
- inputTileNormal->getBuffer(),
+ if (inputTileNormal && inputTileNormal->getBuffer()) {
+ filter.setImage("normal",
+ inputTileNormal->getBuffer(),
+ oidn::Format::Float3,
+ inputTileNormal->getWidth(),
+ inputTileNormal->getHeight(),
+ 0,
+ 3 * sizeof(float));
+ }
+ if (inputTileAlbedo && inputTileAlbedo->getBuffer()) {
+ filter.setImage("albedo",
+ inputTileAlbedo->getBuffer(),
+ oidn::Format::Float3,
+ inputTileAlbedo->getWidth(),
+ inputTileAlbedo->getHeight(),
+ 0,
+ 4 * sizeof(float));
+ }
+ filter.setImage("output",
+ data,
oidn::Format::Float3,
- inputTileNormal->getWidth(),
- inputTileNormal->getHeight(),
+ inputTileColor->getWidth(),
+ inputTileColor->getHeight(),
0,
- 3 * sizeof(float));
- }
- filter.setImage("output",
- data,
- oidn::Format::Float3,
- inputTileColor->getWidth(),
- inputTileColor->getHeight(),
- 0,
- 4 * sizeof(float));
+ 4 * sizeof(float));
- BLI_assert(settings);
- if (settings) {
- filter.set("hdr", settings->hdr);
- filter.set("srgb", false);
- }
+ BLI_assert(settings);
+ if (settings) {
+ filter.set("hdr", settings->hdr);
+ filter.set("srgb", false);
+ }
- filter.commit();
- filter.execute();
+ filter.commit();
+ /* Since it's memory intensive, it's better to run only one instance of OIDN at a time.
+ * OpenImageDenoise is multithreaded internally and should use all available cores nonetheless.
+ */
+ BLI_mutex_lock(&oidn_lock);
+ filter.execute();
+ BLI_mutex_unlock(&oidn_lock);
- /* copy the alpha channel, OpenImageDenoise currently only supports RGB */
- size_t numPixels = inputTileColor->getWidth() * inputTileColor->getHeight();
- for (size_t i = 0; i < numPixels; ++i) {
- data[i * 4 + 3] = inputBufferColor[i * 4 + 3];
+ /* copy the alpha channel, OpenImageDenoise currently only supports RGB */
+ size_t numPixels = inputTileColor->getWidth() * inputTileColor->getHeight();
+ for (size_t i = 0; i < numPixels; i++) {
+ data[i * 4 + 3] = inputBufferColor[i * 4 + 3];
+ }
+ return;
}
-#else
+#endif
+ /* If built without OIDN or running on an unsupported CPU, just pass through. */
UNUSED_VARS(inputTileAlbedo, inputTileNormal, settings);
::memcpy(data,
inputBufferColor,
inputTileColor->getWidth() * inputTileColor->getHeight() * sizeof(float) * 4);
-#endif
}
diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.h b/source/blender/compositor/operations/COM_DenoiseOperation.h
index 6e19bd6034a..fc06bb81a97 100644
--- a/source/blender/compositor/operations/COM_DenoiseOperation.h
+++ b/source/blender/compositor/operations/COM_DenoiseOperation.h
@@ -19,8 +19,8 @@
* Stefan Werner
*/
-#ifndef __COM_DENOISEBASEOPERATION_H__
-#define __COM_DENOISEBASEOPERATION_H__
+#ifndef __COM_DENOISEOPERATION_H__
+#define __COM_DENOISEOPERATION_H__
#include "COM_SingleThreadedOperation.h"
#include "DNA_node_types.h"
@@ -62,10 +62,11 @@ class DenoiseOperation : public SingleThreadedOperation {
protected:
void generateDenoise(float *data,
MemoryBuffer *inputTileColor,
- MemoryBuffer *inputTileAlbedo,
MemoryBuffer *inputTileNormal,
+ MemoryBuffer *inputTileAlbedo,
NodeDenoise *settings);
MemoryBuffer *createMemoryBuffer(rcti *rect);
};
-#endif
+
+#endif /* __COM_DENOISEOPERATION_H__ */
diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp
index 7cf1086dca1..52bc00e9b84 100644
--- a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp
+++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp
@@ -387,7 +387,7 @@ void *DilateStepOperation::initializeTileData(rcti *rect)
for (x = 0; x < bwidth + 5 * half_window; x++) {
buf[x] = -FLT_MAX;
}
- for (x = xmin; x < xmax; ++x) {
+ for (x = xmin; x < xmax; x++) {
buf[x - rect->xmin + window - 1] = buffer[(y * width + x)];
}
@@ -516,7 +516,7 @@ void *ErodeStepOperation::initializeTileData(rcti *rect)
for (x = 0; x < bwidth + 5 * half_window; x++) {
buf[x] = FLT_MAX;
}
- for (x = xmin; x < xmax; ++x) {
+ for (x = xmin; x < xmax; x++) {
buf[x - rect->xmin + window - 1] = buffer[(y * width + x)];
}
diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp
index 59a397ab32d..1b590c0c392 100644
--- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp
@@ -72,7 +72,7 @@ void DirectionalBlurOperation::executePixel(float output[4], int x, int y, void
float lsc = this->m_sc;
float lrot = this->m_rot;
/* blur the image */
- for (int i = 0; i < iterations; ++i) {
+ for (int i = 0; i < iterations; i++) {
const float cs = cosf(lrot), ss = sinf(lrot);
const float isc = 1.0f / (1.0f + lsc);
diff --git a/source/blender/compositor/operations/COM_DisplaceOperation.cpp b/source/blender/compositor/operations/COM_DisplaceOperation.cpp
index 3efc566cb4e..b775bfdee4c 100644
--- a/source/blender/compositor/operations/COM_DisplaceOperation.cpp
+++ b/source/blender/compositor/operations/COM_DisplaceOperation.cpp
@@ -111,12 +111,12 @@ void DisplaceOperation::pixelTransform(const float xy[2], float r_uv[2], float r
if (read_displacement(xy[0] + epsilon[0], xy[1], xs, ys, xy, uv[0], uv[1])) {
r_deriv[0][0] += uv[0] - r_uv[0];
r_deriv[1][0] += uv[1] - r_uv[1];
- ++num;
+ num++;
}
if (read_displacement(xy[0] - epsilon[0], xy[1], xs, ys, xy, uv[0], uv[1])) {
r_deriv[0][0] += r_uv[0] - uv[0];
r_deriv[1][0] += r_uv[1] - uv[1];
- ++num;
+ num++;
}
if (num > 0) {
float numinv = 1.0f / (float)num;
@@ -128,12 +128,12 @@ void DisplaceOperation::pixelTransform(const float xy[2], float r_uv[2], float r
if (read_displacement(xy[0], xy[1] + epsilon[1], xs, ys, xy, uv[0], uv[1])) {
r_deriv[0][1] += uv[0] - r_uv[0];
r_deriv[1][1] += uv[1] - r_uv[1];
- ++num;
+ num++;
}
if (read_displacement(xy[0], xy[1] - epsilon[1], xs, ys, xy, uv[0], uv[1])) {
r_deriv[0][1] += r_uv[0] - uv[0];
r_deriv[1][1] += r_uv[1] - uv[1];
- ++num;
+ num++;
}
if (num > 0) {
float numinv = 1.0f / (float)num;
diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
index 2c12091c458..3058a5990c6 100644
--- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
@@ -89,18 +89,18 @@ void *FastGaussianBlurOperation::initializeTileData(rcti *rect)
this->m_sy = this->m_data.sizey * this->m_size / 2.0f;
if ((this->m_sx == this->m_sy) && (this->m_sx > 0.0f)) {
- for (c = 0; c < COM_NUM_CHANNELS_COLOR; ++c) {
+ for (c = 0; c < COM_NUM_CHANNELS_COLOR; c++) {
IIR_gauss(copy, this->m_sx, c, 3);
}
}
else {
if (this->m_sx > 0.0f) {
- for (c = 0; c < COM_NUM_CHANNELS_COLOR; ++c) {
+ for (c = 0; c < COM_NUM_CHANNELS_COLOR; c++) {
IIR_gauss(copy, this->m_sx, c, 1);
}
}
if (this->m_sy > 0.0f) {
- for (c = 0; c < COM_NUM_CHANNELS_COLOR; ++c) {
+ for (c = 0; c < COM_NUM_CHANNELS_COLOR; c++) {
IIR_gauss(copy, this->m_sy, c, 2);
}
}
@@ -216,16 +216,16 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src,
W = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss W buf");
if (xy & 1) { // H
int offset;
- for (y = 0; y < src_height; ++y) {
+ for (y = 0; y < src_height; y++) {
const int yx = y * src_width;
offset = yx * num_channels + chan;
- for (x = 0; x < src_width; ++x) {
+ for (x = 0; x < src_width; x++) {
X[x] = buffer[offset];
offset += num_channels;
}
YVV(src_width);
offset = yx * num_channels + chan;
- for (x = 0; x < src_width; ++x) {
+ for (x = 0; x < src_width; x++) {
buffer[offset] = Y[x];
offset += num_channels;
}
@@ -235,15 +235,15 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src,
int offset;
const int add = src_width * num_channels;
- for (x = 0; x < src_width; ++x) {
+ for (x = 0; x < src_width; x++) {
offset = x * num_channels + chan;
- for (y = 0; y < src_height; ++y) {
+ for (y = 0; y < src_height; y++) {
X[y] = buffer[offset];
offset += add;
}
YVV(src_height);
offset = x * num_channels + chan;
- for (y = 0; y < src_height; ++y) {
+ for (y = 0; y < src_height; y++) {
buffer[offset] = Y[y];
offset += add;
}
diff --git a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp
index 30a6a05ed2c..b43b94af06a 100644
--- a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp
@@ -61,7 +61,7 @@ static void FHT(fREAL *data, unsigned int M, unsigned int inverse)
int i, j = 0;
unsigned int Nh = len >> 1;
- for (i = 1; i < (len - 1); ++i) {
+ for (i = 1; i < (len - 1); i++) {
j = revbin_upd(j, Nh);
if (j > i) {
t1 = data[i];
@@ -117,7 +117,7 @@ static void FHT(fREAL *data, unsigned int M, unsigned int inverse)
if (inverse) {
fREAL sc = (fREAL)1 / (fREAL)len;
- for (k = 0; k < len; ++k) {
+ for (k = 0; k < len; k++) {
data[k] *= sc;
}
}
@@ -136,14 +136,14 @@ static void FHT2D(
// rows (forward transform skips 0 pad data)
maxy = inverse ? Ny : nzp;
- for (j = 0; j < maxy; ++j) {
+ for (j = 0; j < maxy; j++) {
FHT(&data[Nx * j], Mx, inverse);
}
// transpose data
if (Nx == Ny) { // square
- for (j = 0; j < Ny; ++j) {
- for (i = j + 1; i < Nx; ++i) {
+ for (j = 0; j < Ny; j++) {
+ for (i = j + 1; i < Nx; i++) {
unsigned int op = i + (j << Mx), np = j + (i << My);
SWAP(fREAL, data[op], data[np]);
}
@@ -171,7 +171,7 @@ static void FHT2D(
SWAP(unsigned int, Mx, My);
// now columns == transposed rows
- for (j = 0; j < Ny; ++j) {
+ for (j = 0; j < Ny; j++) {
FHT(&data[Nx * j], Mx, inverse);
}
@@ -421,9 +421,9 @@ void GlareFogGlowOperation::generateGlare(float *data,
scale = 0.25f * sqrtf((float)(sz * sz));
- for (y = 0; y < sz; ++y) {
+ for (y = 0; y < sz; y++) {
v = 2.0f * (y / (float)sz) - 1.0f;
- for (x = 0; x < sz; ++x) {
+ for (x = 0; x < sz; x++) {
u = 2.0f * (x / (float)sz) - 1.0f;
r = (u * u + v * v) * scale;
d = -sqrtf(sqrtf(sqrtf(r))) * 9.0f;
diff --git a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp b/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
index 951dec9281e..4fccb62e3df 100644
--- a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
@@ -41,7 +41,7 @@ void GlareStreaksOperation::generateGlare(float *data,
for (a = 0.0f; a < DEG2RADF(360.0f) && (!breaked); a += ang) {
const float an = a + settings->angle_ofs;
const float vx = cos((double)an), vy = sin((double)an);
- for (n = 0; n < settings->iter && (!breaked); ++n) {
+ for (n = 0; n < settings->iter && (!breaked); n++) {
const float p4 = pow(4.0, (double)n);
const float vxp = vx * p4, vyp = vy * p4;
const float wt = pow((double)settings->fade, (double)p4);
@@ -50,8 +50,8 @@ void GlareStreaksOperation::generateGlare(float *data,
(double)n +
1); // colormodulation amount relative to current pass
float *tdstcol = tdst->getBuffer();
- for (y = 0; y < tsrc->getHeight() && (!breaked); ++y) {
- for (x = 0; x < tsrc->getWidth(); ++x, tdstcol += 4) {
+ for (y = 0; y < tsrc->getHeight() && (!breaked); y++) {
+ for (x = 0; x < tsrc->getWidth(); x++, tdstcol += 4) {
// first pass no offset, always same for every pass, exact copy,
// otherwise results in uneven brightness, only need once
if (n == 0) {
diff --git a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp b/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp
index 300d122589f..83dd90ef08b 100644
--- a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp
@@ -51,7 +51,7 @@ void KeyingBlurOperation::executePixel(float output[4], int x, int y, void *data
if (this->m_axis == 0) {
const int start = max(0, x - this->m_size + 1), end = min(bufferWidth, x + this->m_size);
- for (int cx = start; cx < end; ++cx) {
+ for (int cx = start; cx < end; cx++) {
int bufferIndex = (y * bufferWidth + cx);
average += buffer[bufferIndex];
count++;
@@ -60,7 +60,7 @@ 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);
- for (int cy = start; cy < end; ++cy) {
+ for (int cy = start; cy < end; cy++) {
int bufferIndex = (cy * bufferWidth + x);
average += buffer[bufferIndex];
count++;
diff --git a/source/blender/compositor/operations/COM_KeyingClipOperation.cpp b/source/blender/compositor/operations/COM_KeyingClipOperation.cpp
index b11bd54a190..eafd1e671f8 100644
--- a/source/blender/compositor/operations/COM_KeyingClipOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingClipOperation.cpp
@@ -71,8 +71,8 @@ void KeyingClipOperation::executePixel(float output[4], int x, int y, void *data
ok = true;
}
- for (int cx = start_x; ok == false && cx <= end_x; ++cx) {
- for (int cy = start_y; ok == false && cy <= end_y; ++cy) {
+ for (int cx = start_x; ok == false && cx <= end_x; cx++) {
+ for (int cy = start_y; ok == false && cy <= end_y; cy++) {
if (UNLIKELY(cx == x && cy == y)) {
continue;
}
diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cpp b/source/blender/compositor/operations/COM_MapUVOperation.cpp
index 21d432b9222..de55c9fb4b8 100644
--- a/source/blender/compositor/operations/COM_MapUVOperation.cpp
+++ b/source/blender/compositor/operations/COM_MapUVOperation.cpp
@@ -117,12 +117,12 @@ void MapUVOperation::pixelTransform(const float xy[2],
if (read_uv(xy[0] + epsilon[0], xy[1], uv[0], uv[1], alpha)) {
r_deriv[0][0] += uv[0] - r_uv[0];
r_deriv[1][0] += uv[1] - r_uv[1];
- ++num;
+ num++;
}
if (read_uv(xy[0] - epsilon[0], xy[1], uv[0], uv[1], alpha)) {
r_deriv[0][0] += r_uv[0] - uv[0];
r_deriv[1][0] += r_uv[1] - uv[1];
- ++num;
+ num++;
}
if (num > 0) {
float numinv = 1.0f / (float)num;
@@ -134,12 +134,12 @@ void MapUVOperation::pixelTransform(const float xy[2],
if (read_uv(xy[0], xy[1] + epsilon[1], uv[0], uv[1], alpha)) {
r_deriv[0][1] += uv[0] - r_uv[0];
r_deriv[1][1] += uv[1] - r_uv[1];
- ++num;
+ num++;
}
if (read_uv(xy[0], xy[1] - epsilon[1], uv[0], uv[1], alpha)) {
r_deriv[0][1] += r_uv[0] - uv[0];
r_deriv[1][1] += r_uv[1] - uv[1];
- ++num;
+ num++;
}
if (num > 0) {
float numinv = 1.0f / (float)num;
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
index 9d1be09de0e..444af5c4cf7 100644
--- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
@@ -183,7 +183,7 @@ void *OutputOpenExrMultiLayerMultiViewOperation::get_handle(const char *filename
IMB_exr_add_view(exrhandle, srv->name);
- for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
+ for (unsigned int i = 0; i < this->m_layers.size(); i++) {
add_exr_channels(exrhandle,
this->m_layers[i].name,
this->m_layers[i].datatype,
@@ -229,7 +229,7 @@ void OutputOpenExrMultiLayerMultiViewOperation::deinitExecution()
exrhandle = this->get_handle(filename);
- for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
+ for (unsigned int i = 0; i < this->m_layers.size(); i++) {
add_exr_channels(exrhandle,
this->m_layers[i].name,
this->m_layers[i].datatype,
@@ -239,7 +239,7 @@ void OutputOpenExrMultiLayerMultiViewOperation::deinitExecution()
this->m_layers[i].outputBuffer);
}
- for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
+ for (unsigned int i = 0; i < this->m_layers.size(); i++) {
/* memory can only be freed after we write all views to the file */
this->m_layers[i].outputBuffer = NULL;
this->m_layers[i].imageInput = NULL;
@@ -250,7 +250,7 @@ void OutputOpenExrMultiLayerMultiViewOperation::deinitExecution()
IMB_exr_write_channels(exrhandle);
/* free buffer memory for all the views */
- for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
+ for (unsigned int i = 0; i < this->m_layers.size(); i++) {
free_exr_channels(
exrhandle, this->m_rd, this->m_layers[i].name, this->m_layers[i].datatype);
}
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cpp
index 79e3b2f1108..c06994d7cdb 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.cpp
@@ -162,7 +162,7 @@ static void write_buffer_rect(rcti *rect,
for (x = x1; x < x2 && (!breaked); x++) {
reader->readSampled(color, x, y, COM_PS_NEAREST);
- for (i = 0; i < size; ++i) {
+ for (i = 0; i < size; i++) {
buffer[offset + i] = color[i];
}
offset += size;
@@ -298,7 +298,7 @@ void OutputOpenExrMultiLayerOperation::add_layer(const char *name,
void OutputOpenExrMultiLayerOperation::initExecution()
{
- for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
+ for (unsigned int i = 0; i < this->m_layers.size(); i++) {
if (this->m_layers[i].use_layer) {
SocketReader *reader = getInputSocketReader(i);
this->m_layers[i].imageInput = reader;
@@ -310,7 +310,7 @@ void OutputOpenExrMultiLayerOperation::initExecution()
void OutputOpenExrMultiLayerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
{
- for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
+ for (unsigned int i = 0; i < this->m_layers.size(); i++) {
OutputOpenExrLayer &layer = this->m_layers[i];
if (layer.imageInput) {
write_buffer_rect(rect,
@@ -343,7 +343,7 @@ void OutputOpenExrMultiLayerOperation::deinitExecution()
suffix);
BLI_make_existing_file(filename);
- for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
+ for (unsigned int i = 0; i < this->m_layers.size(); i++) {
OutputOpenExrLayer &layer = this->m_layers[i];
if (!layer.imageInput) {
continue; /* skip unconnected sockets */
@@ -369,7 +369,7 @@ void OutputOpenExrMultiLayerOperation::deinitExecution()
}
IMB_exr_close(exrhandle);
- for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
+ for (unsigned int i = 0; i < this->m_layers.size(); i++) {
if (this->m_layers[i].outputBuffer) {
MEM_freeN(this->m_layers[i].outputBuffer);
this->m_layers[i].outputBuffer = NULL;
diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
index 313be2f5ecf..676601d82da 100644
--- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
@@ -60,7 +60,7 @@ static bool check_corners(float corners[4][2])
static void readCornersFromSockets(rcti *rect, SocketReader *readers[4], float corners[4][2])
{
- for (int i = 0; i < 4; ++i) {
+ for (int i = 0; i < 4; i++) {
float result[4] = {0.0f, 0.0f, 0.0f, 0.0f};
readers[i]->readSampled(result, rect->xmin, rect->ymin, COM_PS_NEAREST);
corners[i][0] = result[0];
@@ -208,7 +208,7 @@ void *PlaneCornerPinWarpImageOperation::initializeTileData(rcti *rect)
bool PlaneCornerPinWarpImageOperation::determineDependingAreaOfInterest(
rcti *input, ReadBufferOperation *readOperation, rcti *output)
{
- for (int i = 0; i < 4; ++i) {
+ for (int i = 0; i < 4; i++) {
if (getInputOperation(i + 1)->determineDependingAreaOfInterest(input, readOperation, output)) {
return true;
}
diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
index ef7dfbd4116..78a83391ed1 100644
--- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
@@ -105,7 +105,7 @@ void PlaneDistortWarpImageOperation::executePixelSampled(float output[4],
}
else {
zero_v4(output);
- for (int sample = 0; sample < this->m_motion_blur_samples; ++sample) {
+ for (int sample = 0; sample < this->m_motion_blur_samples; sample++) {
float color[4];
warpCoord(x, y, this->m_samples[sample].perspectiveMatrix, uv, deriv);
m_pixelReader->readFiltered(color, uv[0], uv[1], deriv[0], deriv[1]);
@@ -121,7 +121,7 @@ bool PlaneDistortWarpImageOperation::determineDependingAreaOfInterest(
float min[2], max[2];
INIT_MINMAX2(min, max);
- for (int sample = 0; sample < this->m_motion_blur_samples; ++sample) {
+ for (int sample = 0; sample < this->m_motion_blur_samples; sample++) {
float UVs[4][2];
float deriv[2][2];
MotionSample *sample_data = &this->m_samples[sample];
@@ -208,9 +208,9 @@ void PlaneDistortMaskOperation::executePixelSampled(float output[4],
output[0] = (float)inside_counter / this->m_osa;
}
else {
- for (int motion_sample = 0; motion_sample < this->m_motion_blur_samples; ++motion_sample) {
+ for (int motion_sample = 0; motion_sample < this->m_motion_blur_samples; motion_sample++) {
MotionSample *sample_data = &this->m_samples[motion_sample];
- for (int osa_sample = 0; osa_sample < this->m_osa; ++osa_sample) {
+ for (int osa_sample = 0; osa_sample < this->m_osa; osa_sample++) {
point[0] = x + this->m_jitter[osa_sample][0];
point[1] = y + this->m_jitter[osa_sample][1];
if (isect_point_tri_v2(point,
diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
index c2fe41eea1d..cbf5a25fa31 100644
--- a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
@@ -93,7 +93,7 @@ void PlaneTrackMaskOperation::initExecution()
const float frame = (float)this->m_framenumber - this->m_motion_blur_shutter;
const float frame_step = (this->m_motion_blur_shutter * 2.0f) / this->m_motion_blur_samples;
float frame_iter = frame;
- for (int sample = 0; sample < this->m_motion_blur_samples; ++sample) {
+ for (int sample = 0; sample < this->m_motion_blur_samples; sample++) {
readCornersFromTrack(corners, frame_iter);
calculateCorners(corners, true, sample);
frame_iter += frame_step;
@@ -116,7 +116,7 @@ void PlaneTrackWarpImageOperation::initExecution()
const float frame = (float)this->m_framenumber - this->m_motion_blur_shutter;
const float frame_step = (this->m_motion_blur_shutter * 2.0f) / this->m_motion_blur_samples;
float frame_iter = frame;
- for (int sample = 0; sample < this->m_motion_blur_samples; ++sample) {
+ for (int sample = 0; sample < this->m_motion_blur_samples; sample++) {
readCornersFromTrack(corners, frame_iter);
calculateCorners(corners, true, sample);
frame_iter += frame_step;
diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
index 738f7ed31ba..94224ac77a6 100644
--- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
@@ -148,7 +148,7 @@ void ScreenLensDistortionOperation::accumulate(MemoryBuffer *buffer,
float k4 = m_k4[a];
float dk4 = m_dk4[a];
- for (float z = 0; z < ds; ++z) {
+ for (float z = 0; z < ds; z++) {
float tz = (z + (m_jitter ? BLI_rng_get_float(m_rng) : 0.5f)) * sd;
float t = 1.0f - (k4 + tz * dk4) * r_sq;
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index 49c510d9d3e..21ab148496c 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -73,6 +73,7 @@ set(SRC
intern/depsgraph_query.cc
intern/depsgraph_query_foreach.cc
intern/depsgraph_query_iter.cc
+ intern/depsgraph_registry.cc
intern/depsgraph_tag.cc
intern/depsgraph_type.cc
intern/depsgraph_update.cc
@@ -107,6 +108,7 @@ set(SRC
intern/node/deg_node_time.h
intern/depsgraph.h
intern/depsgraph_physics.h
+ intern/depsgraph_registry.h
intern/depsgraph_tag.h
intern/depsgraph_type.h
intern/depsgraph_update.h
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index fd12f90016b..e44dddbcf54 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -87,7 +87,10 @@ extern "C" {
/* Create new Depsgraph instance */
// TODO: what args are needed here? What's the building-graph entry point?
-Depsgraph *DEG_graph_new(struct Scene *scene, struct ViewLayer *view_layer, eEvaluationMode mode);
+Depsgraph *DEG_graph_new(struct Main *bmain,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ eEvaluationMode mode);
/* Free Depsgraph itself and all its data */
void DEG_graph_free(Depsgraph *graph);
@@ -108,6 +111,8 @@ void DEG_graph_on_visible_update(struct Main *bmain, Depsgraph *depsgraph, const
/* Update all dependency graphs when visible scenes/layers changes. */
void DEG_on_visible_update(struct Main *bmain, const bool do_time);
+/* NOTE: Will return NULL if the flag is not known, allowing to gracefully handle situations
+ * when recalc flag has been removed. */
const char *DEG_update_tag_as_string(IDRecalcFlag flag);
void DEG_id_tag_update(struct ID *id, int flag);
@@ -126,11 +131,6 @@ void DEG_id_type_tag(struct Main *bmain, short id_type);
void DEG_ids_clear_recalc(struct Main *bmain, Depsgraph *depsgraph);
-/* Update Flushing ------------------------------- */
-
-/* Flush updates for IDs in a single scene. */
-void DEG_graph_flush_update(struct Main *bmain, Depsgraph *depsgraph);
-
/* Check if something was changed in the database and inform
* editors about this.
*/
@@ -154,7 +154,7 @@ void DEG_evaluate_on_framechange(struct Main *bmain, Depsgraph *graph, float cti
/* Data changed recalculation entry point.
* < context_type: context to perform evaluation for
*/
-void DEG_evaluate_on_refresh(Depsgraph *graph);
+void DEG_evaluate_on_refresh(struct Main *bmain, Depsgraph *graph);
bool DEG_needs_eval(Depsgraph *graph);
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index 37dfaf2c3e2..e24fa9e8996 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -74,6 +74,13 @@ void DEG_graph_build_for_compositor_preview(struct Depsgraph *graph,
struct ViewLayer *view_layer,
struct bNodeTree *nodetree);
+void DEG_graph_build_from_ids(struct Depsgraph *graph,
+ struct Main *bmain,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ struct ID **ids,
+ const int num_ids);
+
/* Tag relations from the given graph for update. */
void DEG_graph_tag_relations_update(struct Depsgraph *graph);
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index 82f7f33411a..fb456611b15 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -236,9 +236,21 @@ void DEG_foreach_dependent_ID(const Depsgraph *depsgraph,
/* Starts traversal from given component of the given ID, invokes callback for every other
* component which is directly on indirectly dependent on the source one. */
+enum {
+ /* Ignore transform solvers which depends on multiple inputs and affects final transform.
+ * Is used for cases like snapping objects which are part of a rigid body simulation:
+ * without this there will be "false-positive" dependencies between transform components of
+ * objects:
+ *
+ * object 1 transform before solver ---> solver ------> object 1 final transform
+ * object 2 transform before solver -----^ \------> object 2 final transform
+ */
+ DEG_FOREACH_COMPONENT_IGNORE_TRANSFORM_SOLVERS,
+};
void DEG_foreach_dependent_ID_component(const Depsgraph *depsgraph,
const ID *id,
eDepsObjectComponentType source_component_type,
+ int flags,
DEGForeachIDComponentCallback callback,
void *user_data);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index 4cbdd169980..4ca7240abd1 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -74,6 +74,10 @@ DepsgraphBuilder::DepsgraphBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuild
{
}
+DepsgraphBuilder::~DepsgraphBuilder()
+{
+}
+
bool DepsgraphBuilder::need_pull_base_into_graph(Base *base)
{
/* Simple check: enabled bases are always part of dependency graph. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h
index 040bb6cfeea..97e12e9ceb2 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder.h
@@ -35,11 +35,13 @@ class DepsgraphBuilderCache;
class DepsgraphBuilder {
public:
- bool need_pull_base_into_graph(Base *base);
+ virtual ~DepsgraphBuilder();
- bool check_pchan_has_bbone(Object *object, const bPoseChannel *pchan);
- bool check_pchan_has_bbone_segments(Object *object, const bPoseChannel *pchan);
- bool check_pchan_has_bbone_segments(Object *object, const char *bone_name);
+ virtual bool need_pull_base_into_graph(Base *base);
+
+ virtual bool check_pchan_has_bbone(Object *object, const bPoseChannel *pchan);
+ virtual bool check_pchan_has_bbone_segments(Object *object, const bPoseChannel *pchan);
+ virtual bool check_pchan_has_bbone_segments(Object *object, const char *bone_name);
protected:
/* NOTE: The builder does NOT take ownership over any of those resources. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
index d11a60b77dd..bea59eceea2 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
@@ -149,7 +149,7 @@ bool check_relation_can_murder(Relation *relation)
Relation *select_relation_to_murder(Relation *relation, StackEntry *cycle_start_entry)
{
- /* More or less russian roulette solver, which will make sure only
+ /* More or less Russian roulette solver, which will make sure only
* specially marked relations are kept alive.
*
* TODO(sergey): There might be better strategies here. */
@@ -176,7 +176,7 @@ void solve_cycles(CyclesSolverState *state)
OperationNode *node = entry->node;
bool all_child_traversed = true;
const int num_visited = get_node_num_visited_children(node);
- for (int i = num_visited; i < node->outlinks.size(); ++i) {
+ for (int i = num_visited; i < node->outlinks.size(); i++) {
Relation *rel = node->outlinks[i];
if (rel->to->type == NodeType::OPERATION) {
OperationNode *to = (OperationNode *)rel->to;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index fd4c1e251e4..7dfc863b847 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -609,12 +609,8 @@ void DepsgraphNodeBuilder::build_object(int base_index,
build_particle_systems(object, is_visible);
}
/* Proxy object to copy from. */
- if (object->proxy_from != NULL) {
- build_object(-1, object->proxy_from, DEG_ID_LINKED_INDIRECTLY, is_visible);
- }
- if (object->proxy_group != NULL) {
- build_object(-1, object->proxy_group, DEG_ID_LINKED_INDIRECTLY, is_visible);
- }
+ build_object_proxy_from(object, is_visible);
+ build_object_proxy_group(object, is_visible);
/* Object dupligroup. */
if (object->instance_collection != NULL) {
const bool is_current_parent_collection_visible = is_parent_collection_visible_;
@@ -653,6 +649,22 @@ void DepsgraphNodeBuilder::build_object_flags(int base_index,
is_from_set));
}
+void DepsgraphNodeBuilder::build_object_proxy_from(Object *object, bool is_visible)
+{
+ if (object->proxy_from == NULL) {
+ return;
+ }
+ build_object(-1, object->proxy_from, DEG_ID_LINKED_INDIRECTLY, is_visible);
+}
+
+void DepsgraphNodeBuilder::build_object_proxy_group(Object *object, bool is_visible)
+{
+ if (object->proxy_group == NULL) {
+ return;
+ }
+ build_object(-1, object->proxy_group, DEG_ID_LINKED_INDIRECTLY, is_visible);
+}
+
void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visible)
{
if (object->data == NULL) {
@@ -900,19 +912,17 @@ void DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcurve, int driver_index
{
/* Create data node for this driver */
ID *id_cow = get_cow_id(id);
- ChannelDriver *driver_orig = fcurve->driver;
/* TODO(sergey): ideally we could pass the COW of fcu, but since it
* has not yet been allocated at this point we can't. As a workaround
* the animation systems allocates an array so we can do a fast lookup
* with the driver index. */
- ensure_operation_node(
- id,
- NodeType::PARAMETERS,
- OperationCode::DRIVER,
- function_bind(BKE_animsys_eval_driver, _1, id_cow, driver_index, driver_orig),
- fcurve->rna_path ? fcurve->rna_path : "",
- fcurve->array_index);
+ ensure_operation_node(id,
+ NodeType::PARAMETERS,
+ OperationCode::DRIVER,
+ function_bind(BKE_animsys_eval_driver, _1, id_cow, driver_index, fcurve),
+ fcurve->rna_path ? fcurve->rna_path : "",
+ fcurve->array_index);
build_driver_variables(id, fcurve);
}
@@ -1155,7 +1165,7 @@ void DepsgraphNodeBuilder::build_particle_settings(ParticleSettings *particle_se
&particle_settings->id, NodeType::PARTICLE_SETTINGS, OperationCode::PARTICLE_SETTINGS_EVAL);
op_node->set_as_exit();
/* Texture slots. */
- for (int mtex_index = 0; mtex_index < MAX_MTEX; ++mtex_index) {
+ for (int mtex_index = 0; mtex_index < MAX_MTEX; mtex_index++) {
MTex *mtex = particle_settings->mtex[mtex_index];
if (mtex == NULL || mtex->tex == NULL) {
continue;
@@ -1436,7 +1446,7 @@ void DepsgraphNodeBuilder::build_material(Material *material)
void DepsgraphNodeBuilder::build_materials(Material **materials, int num_materials)
{
- for (int i = 0; i < num_materials; ++i) {
+ for (int i = 0; i < num_materials; i++) {
if (materials[i] == NULL) {
continue;
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index 65f3521b556..865f60432c1 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -93,8 +93,8 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
return (T *)cow->id.orig_id;
}
- void begin_build();
- void end_build();
+ virtual void begin_build();
+ virtual void end_build();
IDNode *add_id_node(ID *id);
IDNode *find_id_node(ID *id);
@@ -145,71 +145,75 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
OperationNode *find_operation_node(
ID *id, NodeType comp_type, OperationCode opcode, const char *name = "", int name_tag = -1);
- void build_id(ID *id);
+ virtual void build_id(ID *id);
- void build_scene_render(Scene *scene, ViewLayer *view_layer);
- void build_scene_parameters(Scene *scene);
- void build_scene_compositor(Scene *scene);
+ virtual void build_scene_render(Scene *scene, ViewLayer *view_layer);
+ virtual void build_scene_parameters(Scene *scene);
+ virtual void build_scene_compositor(Scene *scene);
- void build_layer_collections(ListBase *lb);
- void build_view_layer(Scene *scene,
- ViewLayer *view_layer,
- eDepsNode_LinkedState_Type linked_state);
- void build_collection(LayerCollection *from_layer_collection, Collection *collection);
- void build_object(int base_index,
- Object *object,
- eDepsNode_LinkedState_Type linked_state,
- bool is_visible);
- void build_object_flags(int base_index, Object *object, eDepsNode_LinkedState_Type linked_state);
- void build_object_data(Object *object, bool is_object_visible);
- void build_object_data_camera(Object *object);
- void build_object_data_geometry(Object *object, bool is_object_visible);
- void build_object_data_geometry_datablock(ID *obdata, bool is_object_visible);
- void build_object_data_light(Object *object);
- void build_object_data_lightprobe(Object *object);
- void build_object_data_speaker(Object *object);
- void build_object_transform(Object *object);
- void build_object_constraints(Object *object);
- void build_object_pointcache(Object *object);
- void build_pose_constraints(Object *object,
- bPoseChannel *pchan,
- int pchan_index,
- bool is_object_visible);
- void build_rigidbody(Scene *scene);
- void build_particle_systems(Object *object, bool is_object_visible);
- void build_particle_settings(ParticleSettings *part);
- void build_animdata(ID *id);
- void build_animdata_nlastrip_targets(ListBase *strips);
- void build_animation_images(ID *id);
- void build_action(bAction *action);
- void build_driver(ID *id, FCurve *fcurve, int driver_index);
- void build_driver_variables(ID *id, FCurve *fcurve);
- void build_driver_id_property(ID *id, const char *rna_path);
- void build_parameters(ID *id);
- void build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
- void build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
- void build_rig(Object *object, bool is_object_visible);
- void build_proxy_rig(Object *object);
- void build_armature(bArmature *armature);
- void build_shapekeys(Key *key);
- void build_camera(Camera *camera);
- void build_light(Light *lamp);
- void build_nodetree(bNodeTree *ntree);
- void build_material(Material *ma);
- void build_materials(Material **materials, int num_materials);
- void build_texture(Tex *tex);
- void build_image(Image *image);
- void build_world(World *world);
- void build_gpencil(bGPdata *gpd);
- void build_cachefile(CacheFile *cache_file);
- void build_mask(Mask *mask);
- void build_movieclip(MovieClip *clip);
- void build_lightprobe(LightProbe *probe);
- void build_speaker(Speaker *speaker);
- void build_sound(bSound *sound);
- void build_scene_sequencer(Scene *scene);
- void build_scene_audio(Scene *scene);
- void build_scene_speakers(Scene *scene, ViewLayer *view_layer);
+ virtual void build_layer_collections(ListBase *lb);
+ virtual void build_view_layer(Scene *scene,
+ ViewLayer *view_layer,
+ eDepsNode_LinkedState_Type linked_state);
+ virtual void build_collection(LayerCollection *from_layer_collection, Collection *collection);
+ virtual void build_object(int base_index,
+ Object *object,
+ eDepsNode_LinkedState_Type linked_state,
+ bool is_visible);
+ virtual void build_object_proxy_from(Object *object, bool is_object_visible);
+ virtual void build_object_proxy_group(Object *object, bool is_object_visible);
+ virtual void build_object_flags(int base_index,
+ Object *object,
+ eDepsNode_LinkedState_Type linked_state);
+ virtual void build_object_data(Object *object, bool is_object_visible);
+ virtual void build_object_data_camera(Object *object);
+ virtual void build_object_data_geometry(Object *object, bool is_object_visible);
+ virtual void build_object_data_geometry_datablock(ID *obdata, bool is_object_visible);
+ virtual void build_object_data_light(Object *object);
+ virtual void build_object_data_lightprobe(Object *object);
+ virtual void build_object_data_speaker(Object *object);
+ virtual void build_object_transform(Object *object);
+ virtual void build_object_constraints(Object *object);
+ virtual void build_object_pointcache(Object *object);
+ virtual void build_pose_constraints(Object *object,
+ bPoseChannel *pchan,
+ int pchan_index,
+ bool is_object_visible);
+ virtual void build_rigidbody(Scene *scene);
+ virtual void build_particle_systems(Object *object, bool is_object_visible);
+ virtual void build_particle_settings(ParticleSettings *part);
+ virtual void build_animdata(ID *id);
+ virtual void build_animdata_nlastrip_targets(ListBase *strips);
+ virtual void build_animation_images(ID *id);
+ virtual void build_action(bAction *action);
+ virtual void build_driver(ID *id, FCurve *fcurve, int driver_index);
+ virtual void build_driver_variables(ID *id, FCurve *fcurve);
+ virtual void build_driver_id_property(ID *id, const char *rna_path);
+ virtual void build_parameters(ID *id);
+ virtual void build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
+ virtual void build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
+ virtual void build_rig(Object *object, bool is_object_visible);
+ virtual void build_proxy_rig(Object *object);
+ virtual void build_armature(bArmature *armature);
+ virtual void build_shapekeys(Key *key);
+ virtual void build_camera(Camera *camera);
+ virtual void build_light(Light *lamp);
+ virtual void build_nodetree(bNodeTree *ntree);
+ virtual void build_material(Material *ma);
+ virtual void build_materials(Material **materials, int num_materials);
+ virtual void build_texture(Tex *tex);
+ virtual void build_image(Image *image);
+ virtual void build_world(World *world);
+ virtual void build_gpencil(bGPdata *gpd);
+ virtual void build_cachefile(CacheFile *cache_file);
+ virtual void build_mask(Mask *mask);
+ virtual void build_movieclip(MovieClip *clip);
+ virtual void build_lightprobe(LightProbe *probe);
+ virtual void build_speaker(Speaker *speaker);
+ virtual void build_sound(bSound *sound);
+ virtual void build_scene_sequencer(Scene *scene);
+ virtual void build_scene_audio(Scene *scene);
+ virtual void build_scene_speakers(Scene *scene, ViewLayer *view_layer);
/* Per-ID information about what was already in the dependency graph.
* Allows to re-use certain values, to speed up following evaluation. */
@@ -259,7 +263,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
/* NOTE: Collection are possibly built recursively, so be careful when
* setting the current state. */
Collection *collection_;
- /* Accumulated flag over the hierarchy opf currently building collections.
+ /* Accumulated flag over the hierarchy of currently building collections.
* Denotes whether all the hierarchy from parent of collection_ to the
* very root is visible (aka not restricted.). */
bool is_parent_collection_visible_;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
index 2f6b8c0ba6b..88ebf1c9b50 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
@@ -105,7 +105,7 @@ void DepsgraphNodeBuilder::build_view_layer(Scene *scene,
*
* TODO(sergey): Need to go more granular on visibility checks. */
build_object(base_index, base->object, linked_state, true);
- ++base_index;
+ base_index++;
}
}
build_layer_collections(&view_layer->layer_collections);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index ba6a4756313..f1e7278ffdb 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -657,20 +657,8 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
build_particle_systems(object);
}
/* Proxy object to copy from. */
- if (object->proxy_from != NULL) {
- /* Object is linked here (comes from the library). */
- build_object(NULL, object->proxy_from);
- ComponentKey ob_transform_key(&object->proxy_from->id, NodeType::TRANSFORM);
- ComponentKey proxy_transform_key(&object->id, NodeType::TRANSFORM);
- add_relation(ob_transform_key, proxy_transform_key, "Proxy Transform");
- }
- if (object->proxy_group != NULL && object->proxy_group != object->proxy) {
- /* Object is local here (local in .blend file, users interacts with it). */
- build_object(NULL, object->proxy_group);
- OperationKey proxy_group_eval_key(
- &object->proxy_group->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL);
- add_relation(proxy_group_eval_key, transform_eval_key, "Proxy Group Transform");
- }
+ build_object_proxy_from(object);
+ build_object_proxy_group(object);
/* Object dupligroup. */
if (object->instance_collection != NULL) {
build_collection(NULL, object, object->instance_collection);
@@ -685,6 +673,31 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
build_parameters(&object->id);
}
+void DepsgraphRelationBuilder::build_object_proxy_from(Object *object)
+{
+ if (object->proxy_from == NULL) {
+ return;
+ }
+ /* Object is linked here (comes from the library). */
+ build_object(NULL, object->proxy_from);
+ ComponentKey ob_transform_key(&object->proxy_from->id, NodeType::TRANSFORM);
+ ComponentKey proxy_transform_key(&object->id, NodeType::TRANSFORM);
+ add_relation(ob_transform_key, proxy_transform_key, "Proxy Transform");
+}
+
+void DepsgraphRelationBuilder::build_object_proxy_group(Object *object)
+{
+ if (object->proxy_group == NULL || object->proxy_group == object->proxy) {
+ return;
+ }
+ /* Object is local here (local in .blend file, users interacts with it). */
+ build_object(NULL, object->proxy_group);
+ OperationKey proxy_group_eval_key(
+ &object->proxy_group->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL);
+ OperationKey transform_eval_key(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL);
+ add_relation(proxy_group_eval_key, transform_eval_key, "Proxy Group Transform");
+}
+
void DepsgraphRelationBuilder::build_object_flags(Base *base, Object *object)
{
if (base == NULL) {
@@ -807,13 +820,25 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object)
{
Object *parent = object->parent;
ID *parent_id = &object->parent->id;
- ComponentKey ob_key(&object->id, NodeType::TRANSFORM);
- /* Type-specific links/ */
+ ComponentKey object_transform_key(&object->id, NodeType::TRANSFORM);
+ /* Type-specific links. */
switch (object->partype) {
/* Armature Deform (Virtual Modifier) */
case PARSKEL: {
- ComponentKey parent_key(parent_id, NodeType::TRANSFORM);
- add_relation(parent_key, ob_key, "Armature Deform Parent");
+ ComponentKey parent_transform_key(parent_id, NodeType::TRANSFORM);
+ add_relation(parent_transform_key, object_transform_key, "Parent Armature Transform");
+
+ if (parent->type == OB_ARMATURE) {
+ ComponentKey object_geometry_key(&object->id, NodeType::GEOMETRY);
+ ComponentKey parent_pose_key(parent_id, NodeType::EVAL_POSE);
+ add_relation(
+ parent_transform_key, object_geometry_key, "Parent Armature Transform -> Geometry");
+ add_relation(parent_pose_key, object_geometry_key, "Parent Armature Pose -> Geometry");
+
+ add_depends_on_transform_relation(
+ &object->id, object_geometry_key, "Virtual Armature Modifier");
+ }
+
break;
}
@@ -821,7 +846,7 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object)
case PARVERT1:
case PARVERT3: {
ComponentKey parent_key(parent_id, NodeType::GEOMETRY);
- add_relation(parent_key, ob_key, "Vertex Parent");
+ add_relation(parent_key, object_transform_key, "Vertex Parent");
/* Original index is used for optimizations of lookups for subdiv
* only meshes.
* TODO(sergey): This optimization got lost at 2.8, so either verify
@@ -833,7 +858,7 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object)
DEGCustomDataMeshMasks::MaskFace(CD_MASK_ORIGINDEX) |
DEGCustomDataMeshMasks::MaskPoly(CD_MASK_ORIGINDEX));
ComponentKey transform_key(parent_id, NodeType::TRANSFORM);
- add_relation(transform_key, ob_key, "Vertex Parent TFM");
+ add_relation(transform_key, object_transform_key, "Vertex Parent TFM");
break;
}
@@ -842,8 +867,8 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object)
ComponentKey parent_bone_key(parent_id, NodeType::BONE, object->parsubstr);
OperationKey parent_transform_key(
parent_id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL);
- add_relation(parent_bone_key, ob_key, "Bone Parent");
- add_relation(parent_transform_key, ob_key, "Armature Parent");
+ add_relation(parent_bone_key, object_transform_key, "Bone Parent");
+ add_relation(parent_transform_key, object_transform_key, "Armature Parent");
break;
}
@@ -852,8 +877,8 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object)
/* Lattice Deform Parent - Virtual Modifier. */
ComponentKey parent_key(parent_id, NodeType::TRANSFORM);
ComponentKey geom_key(parent_id, NodeType::GEOMETRY);
- add_relation(parent_key, ob_key, "Lattice Deform Parent");
- add_relation(geom_key, ob_key, "Lattice Deform Parent Geom");
+ add_relation(parent_key, object_transform_key, "Lattice Deform Parent");
+ add_relation(geom_key, object_transform_key, "Lattice Deform Parent Geom");
}
else if (object->parent->type == OB_CURVE) {
Curve *cu = (Curve *)object->parent->data;
@@ -861,20 +886,20 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object)
if (cu->flag & CU_PATH) {
/* Follow Path. */
ComponentKey parent_key(parent_id, NodeType::GEOMETRY);
- add_relation(parent_key, ob_key, "Curve Follow Parent");
+ add_relation(parent_key, object_transform_key, "Curve Follow Parent");
ComponentKey transform_key(parent_id, NodeType::TRANSFORM);
- add_relation(transform_key, ob_key, "Curve Follow TFM");
+ add_relation(transform_key, object_transform_key, "Curve Follow TFM");
}
else {
/* Standard Parent. */
ComponentKey parent_key(parent_id, NodeType::TRANSFORM);
- add_relation(parent_key, ob_key, "Curve Parent");
+ add_relation(parent_key, object_transform_key, "Curve Parent");
}
}
else {
/* Standard Parent. */
ComponentKey parent_key(parent_id, NodeType::TRANSFORM);
- add_relation(parent_key, ob_key, "Parent");
+ add_relation(parent_key, object_transform_key, "Parent");
}
break;
}
@@ -887,7 +912,7 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object)
ComponentKey parent_geometry_key(parent_id, NodeType::GEOMETRY);
/* NOTE: Metaballs are evaluating geometry only after their transform,
* so we only hook up to transform channel here. */
- add_relation(parent_geometry_key, ob_key, "Parent");
+ add_relation(parent_geometry_key, object_transform_key, "Parent");
}
/* Dupliverts uses original vertex index. */
@@ -1797,7 +1822,7 @@ void DepsgraphRelationBuilder::build_particle_settings(ParticleSettings *part)
particle_settings_init_key, particle_settings_eval_key, "Particle Settings Init Order");
add_relation(particle_settings_reset_key, particle_settings_eval_key, "Particle Settings Reset");
/* Texture slots. */
- for (int mtex_index = 0; mtex_index < MAX_MTEX; ++mtex_index) {
+ for (int mtex_index = 0; mtex_index < MAX_MTEX; mtex_index++) {
MTex *mtex = part->mtex[mtex_index];
if (mtex == NULL || mtex->tex == NULL) {
continue;
@@ -2246,7 +2271,7 @@ void DepsgraphRelationBuilder::build_material(Material *material)
void DepsgraphRelationBuilder::build_materials(Material **materials, int num_materials)
{
- for (int i = 0; i < num_materials; ++i) {
+ for (int i = 0; i < num_materials; i++) {
if (materials[i] == NULL) {
continue;
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index e58ef989ac9..c6a0014577f 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -191,93 +191,95 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
void add_customdata_mask(Object *object, const DEGCustomDataMeshMasks &customdata_masks);
void add_special_eval_flag(ID *object, uint32_t flag);
- void build_id(ID *id);
-
- void build_scene_render(Scene *scene, ViewLayer *view_layer);
- void build_scene_parameters(Scene *scene);
- void build_scene_compositor(Scene *scene);
-
- void build_layer_collections(ListBase *lb);
- void build_view_layer(Scene *scene,
- ViewLayer *view_layer,
- eDepsNode_LinkedState_Type linked_state);
- void build_collection(LayerCollection *from_layer_collection,
- Object *object,
- Collection *collection);
- void build_object(Base *base, Object *object);
- void build_object_flags(Base *base, Object *object);
- void build_object_data(Object *object);
- void build_object_data_camera(Object *object);
- void build_object_data_geometry(Object *object);
- void build_object_data_geometry_datablock(ID *obdata);
- void build_object_data_light(Object *object);
- void build_object_data_lightprobe(Object *object);
- void build_object_data_speaker(Object *object);
- void build_object_parent(Object *object);
- void build_object_pointcache(Object *object);
- void build_constraints(ID *id,
- NodeType component_type,
- const char *component_subdata,
- ListBase *constraints,
- RootPChanMap *root_map);
- void build_animdata(ID *id);
- void build_animdata_curves(ID *id);
- void build_animdata_curves_targets(ID *id,
- ComponentKey &adt_key,
- OperationNode *operation_from,
- ListBase *curves);
- void build_animdata_nlastrip_targets(ID *id,
- ComponentKey &adt_key,
- OperationNode *operation_from,
- ListBase *strips);
- void build_animdata_drivers(ID *id);
- void build_animation_images(ID *id);
- void build_action(bAction *action);
- void build_driver(ID *id, FCurve *fcurve);
- void build_driver_data(ID *id, FCurve *fcurve);
- void build_driver_variables(ID *id, FCurve *fcurve);
- void build_driver_id_property(ID *id, const char *rna_path);
- void build_parameters(ID *id);
- void build_world(World *world);
- void build_rigidbody(Scene *scene);
- void build_particle_systems(Object *object);
- void build_particle_settings(ParticleSettings *part);
- void build_particle_system_visualization_object(Object *object,
- ParticleSystem *psys,
- Object *draw_object);
- void build_ik_pose(Object *object,
- bPoseChannel *pchan,
- bConstraint *con,
- RootPChanMap *root_map);
- void build_splineik_pose(Object *object,
- bPoseChannel *pchan,
- bConstraint *con,
- RootPChanMap *root_map);
- void build_rig(Object *object);
- void build_proxy_rig(Object *object);
- void build_shapekeys(Key *key);
- void build_armature(bArmature *armature);
- void build_camera(Camera *camera);
- void build_light(Light *lamp);
- void build_nodetree(bNodeTree *ntree);
- void build_material(Material *ma);
- void build_materials(Material **materials, int num_materials);
- void build_texture(Tex *tex);
- void build_image(Image *image);
- void build_gpencil(bGPdata *gpd);
- void build_cachefile(CacheFile *cache_file);
- void build_mask(Mask *mask);
- void build_movieclip(MovieClip *clip);
- void build_lightprobe(LightProbe *probe);
- void build_speaker(Speaker *speaker);
- void build_sound(bSound *sound);
- void build_scene_sequencer(Scene *scene);
- void build_scene_audio(Scene *scene);
- void build_scene_speakers(Scene *scene, ViewLayer *view_layer);
-
- void build_nested_datablock(ID *owner, ID *id);
- void build_nested_nodetree(ID *owner, bNodeTree *ntree);
- void build_nested_shapekey(ID *owner, Key *key);
+ virtual void build_id(ID *id);
+
+ virtual void build_scene_render(Scene *scene, ViewLayer *view_layer);
+ virtual void build_scene_parameters(Scene *scene);
+ virtual void build_scene_compositor(Scene *scene);
+
+ virtual void build_layer_collections(ListBase *lb);
+ virtual void build_view_layer(Scene *scene,
+ ViewLayer *view_layer,
+ eDepsNode_LinkedState_Type linked_state);
+ virtual void build_collection(LayerCollection *from_layer_collection,
+ Object *object,
+ Collection *collection);
+ virtual void build_object(Base *base, Object *object);
+ virtual void build_object_proxy_from(Object *object);
+ virtual void build_object_proxy_group(Object *object);
+ virtual void build_object_flags(Base *base, Object *object);
+ virtual void build_object_data(Object *object);
+ virtual void build_object_data_camera(Object *object);
+ virtual void build_object_data_geometry(Object *object);
+ virtual void build_object_data_geometry_datablock(ID *obdata);
+ virtual void build_object_data_light(Object *object);
+ virtual void build_object_data_lightprobe(Object *object);
+ virtual void build_object_data_speaker(Object *object);
+ virtual void build_object_parent(Object *object);
+ virtual void build_object_pointcache(Object *object);
+ virtual void build_constraints(ID *id,
+ NodeType component_type,
+ const char *component_subdata,
+ ListBase *constraints,
+ RootPChanMap *root_map);
+ virtual void build_animdata(ID *id);
+ virtual void build_animdata_curves(ID *id);
+ virtual void build_animdata_curves_targets(ID *id,
+ ComponentKey &adt_key,
+ OperationNode *operation_from,
+ ListBase *curves);
+ virtual void build_animdata_nlastrip_targets(ID *id,
+ ComponentKey &adt_key,
+ OperationNode *operation_from,
+ ListBase *strips);
+ virtual void build_animdata_drivers(ID *id);
+ virtual void build_animation_images(ID *id);
+ virtual void build_action(bAction *action);
+ virtual void build_driver(ID *id, FCurve *fcurve);
+ virtual void build_driver_data(ID *id, FCurve *fcurve);
+ virtual void build_driver_variables(ID *id, FCurve *fcurve);
+ virtual void build_driver_id_property(ID *id, const char *rna_path);
+ virtual void build_parameters(ID *id);
+ virtual void build_world(World *world);
+ virtual void build_rigidbody(Scene *scene);
+ virtual void build_particle_systems(Object *object);
+ virtual void build_particle_settings(ParticleSettings *part);
+ virtual void build_particle_system_visualization_object(Object *object,
+ ParticleSystem *psys,
+ Object *draw_object);
+ virtual void build_ik_pose(Object *object,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ RootPChanMap *root_map);
+ virtual void build_splineik_pose(Object *object,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ RootPChanMap *root_map);
+ virtual void build_rig(Object *object);
+ virtual void build_proxy_rig(Object *object);
+ virtual void build_shapekeys(Key *key);
+ virtual void build_armature(bArmature *armature);
+ virtual void build_camera(Camera *camera);
+ virtual void build_light(Light *lamp);
+ virtual void build_nodetree(bNodeTree *ntree);
+ virtual void build_material(Material *ma);
+ virtual void build_materials(Material **materials, int num_materials);
+ virtual void build_texture(Tex *tex);
+ virtual void build_image(Image *image);
+ virtual void build_gpencil(bGPdata *gpd);
+ virtual void build_cachefile(CacheFile *cache_file);
+ virtual void build_mask(Mask *mask);
+ virtual void build_movieclip(MovieClip *clip);
+ virtual void build_lightprobe(LightProbe *probe);
+ virtual void build_speaker(Speaker *speaker);
+ virtual void build_sound(bSound *sound);
+ virtual void build_scene_sequencer(Scene *scene);
+ virtual void build_scene_audio(Scene *scene);
+ virtual void build_scene_speakers(Scene *scene, ViewLayer *view_layer);
+
+ virtual void build_nested_datablock(ID *owner, ID *id);
+ virtual void build_nested_nodetree(ID *owner, bNodeTree *ntree);
+ virtual void build_nested_shapekey(ID *owner, Key *key);
void add_particle_collision_relations(const OperationKey &key,
Object *object,
@@ -290,8 +292,8 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
bool add_absorption,
const char *name);
- void build_copy_on_write_relations();
- void build_copy_on_write_relations(IDNode *id_node);
+ virtual void build_copy_on_write_relations();
+ virtual void build_copy_on_write_relations(IDNode *id_node);
template<typename KeyType> OperationNode *find_operation_node(const KeyType &key);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
index d3ae3da9b56..180499519f6 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
@@ -211,7 +211,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
}
/* Final transform properties go to the Done node for the exit. */
else if (STREQ(prop_name, "head") || STREQ(prop_name, "tail") ||
- STRPREFIX(prop_name, "matrix")) {
+ STREQ(prop_name, "length") || STRPREFIX(prop_name, "matrix")) {
if (source == RNAPointerSource::EXIT) {
node_identifier.operation_code = OperationCode::BONE_DONE;
}
@@ -280,7 +280,11 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
else if (RNA_struct_is_a(ptr->type, &RNA_Mesh) || RNA_struct_is_a(ptr->type, &RNA_Modifier) ||
RNA_struct_is_a(ptr->type, &RNA_GpencilModifier) ||
RNA_struct_is_a(ptr->type, &RNA_Spline) || RNA_struct_is_a(ptr->type, &RNA_TextBox) ||
- RNA_struct_is_a(ptr->type, &RNA_GPencilLayer)) {
+ RNA_struct_is_a(ptr->type, &RNA_GPencilLayer) ||
+ RNA_struct_is_a(ptr->type, &RNA_LatticePoint) ||
+ RNA_struct_is_a(ptr->type, &RNA_MeshUVLoop) ||
+ RNA_struct_is_a(ptr->type, &RNA_MeshLoopColor) ||
+ RNA_struct_is_a(ptr->type, &RNA_VertexGroupElement)) {
/* When modifier is used as FROM operation this is likely referencing to
* the property (for example, modifier's influence).
* But when it's used as TO operation, this is geometry component. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
index 3e5e96d30ff..13cf8e63832 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
@@ -97,7 +97,7 @@ void deg_graph_transitive_reduction(Depsgraph *graph)
else if (rel->from->custom_flags & OP_REACHABLE) {
rel->unlink();
OBJECT_GUARDED_DELETE(rel, Relation);
- ++num_removed_relations;
+ num_removed_relations++;
}
else {
++it_rel;
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
index 9c4a672b805..ee3959a0861 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
@@ -144,7 +144,7 @@ static int deg_debug_node_color_index(const Node *node)
#ifdef COLOR_SCHEME_NODE_TYPE
const int(*pair)[2];
- for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
+ for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; pair++) {
if ((*pair)[0] == node->type) {
return (*pair)[1];
}
@@ -197,7 +197,7 @@ static void deg_debug_graphviz_legend(const DebugContext &ctx)
#ifdef COLOR_SCHEME_NODE_TYPE
const int(*pair)[2];
- for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
+ for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; pair++) {
DepsNodeFactory *nti = type_get_factory((NodeType)(*pair)[0]);
deg_debug_graphviz_legend_color(
ctx, nti->tname().c_str(), deg_debug_colors_light[(*pair)[1] % deg_debug_max_colors]);
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc
index b4cf30685a2..4a668e817fe 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc
@@ -85,7 +85,7 @@ string gnuplotify_name(const string &name)
{
string result = "";
const int length = name.length();
- for (int i = 0; i < length; ++i) {
+ for (int i = 0; i < length; i++) {
const char ch = name[i];
if (ch == '_') {
result += "\\\\\\";
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 6d3aed65a14..dcdea87fe1a 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -45,6 +45,8 @@ extern "C" {
#include "DEG_depsgraph_debug.h"
#include "intern/depsgraph_update.h"
+#include "intern/depsgraph_physics.h"
+#include "intern/depsgraph_registry.h"
#include "intern/eval/deg_eval_copy_on_write.h"
@@ -55,8 +57,6 @@ extern "C" {
#include "intern/node/deg_node_operation.h"
#include "intern/node/deg_node_time.h"
-#include "intern/depsgraph_physics.h"
-
namespace DEG {
/* TODO(sergey): Find a better place for this. */
@@ -65,10 +65,11 @@ template<typename T> static void remove_from_vector(vector<T> *vector, const T &
vector->erase(std::remove(vector->begin(), vector->end(), value), vector->end());
}
-Depsgraph::Depsgraph(Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
+Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
: time_source(NULL),
need_update(true),
need_update_time(false),
+ bmain(bmain),
scene(scene),
view_layer(view_layer),
mode(mode),
@@ -313,17 +314,23 @@ ID *Depsgraph::get_cow_id(const ID *id_orig) const
/* Public Graph API */
/* Initialize a new Depsgraph */
-Depsgraph *DEG_graph_new(Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
+Depsgraph *DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
{
- DEG::Depsgraph *deg_depsgraph = OBJECT_GUARDED_NEW(DEG::Depsgraph, scene, view_layer, mode);
+ DEG::Depsgraph *deg_depsgraph = OBJECT_GUARDED_NEW(
+ DEG::Depsgraph, bmain, scene, view_layer, mode);
+ DEG::register_graph(deg_depsgraph);
return reinterpret_cast<Depsgraph *>(deg_depsgraph);
}
/* Free graph's contents and graph itself */
void DEG_graph_free(Depsgraph *graph)
{
+ if (graph == NULL) {
+ return;
+ }
using DEG::Depsgraph;
DEG::Depsgraph *deg_depsgraph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ DEG::unregister_graph(deg_depsgraph);
OBJECT_GUARDED_DELETE(deg_depsgraph, Depsgraph);
}
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index 96b1a2a1f8a..30ae4edde34 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -100,7 +100,7 @@ struct Depsgraph {
typedef vector<OperationNode *> OperationNodes;
typedef vector<IDNode *> IDDepsNodes;
- Depsgraph(Scene *scene, ViewLayer *view_layer, eEvaluationMode mode);
+ Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode);
~Depsgraph();
TimeSourceNode *add_time_source();
@@ -172,7 +172,8 @@ struct Depsgraph {
* Mainly used by graph evaluation. */
SpinLock lock;
- /* Scene, layer, mode this dependency graph is built for. */
+ /* Main, scene, layer, mode this dependency graph is built for. */
+ Main *bmain;
Scene *scene;
ViewLayer *view_layer;
eEvaluationMode mode;
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index dd2d7f70ed5..f67ab381c79 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -59,6 +59,7 @@ extern "C" {
#include "intern/node/deg_node_id.h"
#include "intern/node/deg_node_operation.h"
+#include "intern/depsgraph_registry.h"
#include "intern/depsgraph_type.h"
/* ****************** */
@@ -323,6 +324,147 @@ void DEG_graph_build_for_compositor_preview(
}
}
+/* Optimized builders for dependency graph built from a given set of IDs.
+ *
+ * General notes:
+ *
+ * - We pull in all bases if their objects are in the set of IDs. This allows to have proper
+ * visibility and other flags assigned to the objects.
+ * All other bases (the ones which points to object which is outside of the set of IDs) are
+ * completely ignored.
+ *
+ * - Proxy groups pointing to objects which are outside of the IDs set are also ignored.
+ * This way we avoid high-poly character body pulled into the dependency graph when it's coming
+ * from a library into an animation file and the dependency graph constructed for a proxy rig. */
+
+namespace DEG {
+namespace {
+
+class DepsgraphFromIDsFilter {
+ public:
+ DepsgraphFromIDsFilter(ID **ids, const int num_ids)
+ {
+ for (int i = 0; i < num_ids; ++i) {
+ ids_.insert(ids[0]);
+ }
+ }
+
+ bool contains(ID *id)
+ {
+ return ids_.find(id) != ids_.end();
+ }
+
+ protected:
+ set<ID *> ids_;
+};
+
+class DepsgraphFromIDsNodeBuilder : public DepsgraphNodeBuilder {
+ public:
+ DepsgraphFromIDsNodeBuilder(
+ Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache, ID **ids, const int num_ids)
+ : DepsgraphNodeBuilder(bmain, graph, cache), filter_(ids, num_ids)
+ {
+ }
+
+ virtual bool need_pull_base_into_graph(Base *base) override
+ {
+ if (!filter_.contains(&base->object->id)) {
+ return false;
+ }
+ return DepsgraphNodeBuilder::need_pull_base_into_graph(base);
+ }
+
+ virtual void build_object_proxy_group(Object *object, bool is_visible) override
+ {
+ if (object->proxy_group == NULL) {
+ return;
+ }
+ if (!filter_.contains(&object->proxy_group->id)) {
+ return;
+ }
+ DepsgraphNodeBuilder::build_object_proxy_group(object, is_visible);
+ }
+
+ protected:
+ DepsgraphFromIDsFilter filter_;
+};
+
+class DepsgraphFromIDsRelationBuilder : public DepsgraphRelationBuilder {
+ public:
+ DepsgraphFromIDsRelationBuilder(
+ Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache, ID **ids, const int num_ids)
+ : DepsgraphRelationBuilder(bmain, graph, cache), filter_(ids, num_ids)
+ {
+ }
+
+ virtual bool need_pull_base_into_graph(Base *base) override
+ {
+ if (!filter_.contains(&base->object->id)) {
+ return false;
+ }
+ return DepsgraphRelationBuilder::need_pull_base_into_graph(base);
+ }
+
+ virtual void build_object_proxy_group(Object *object) override
+ {
+ if (object->proxy_group == NULL) {
+ return;
+ }
+ if (!filter_.contains(&object->proxy_group->id)) {
+ return;
+ }
+ DepsgraphRelationBuilder::build_object_proxy_group(object);
+ }
+
+ protected:
+ DepsgraphFromIDsFilter filter_;
+};
+
+} // namespace
+} // namespace DEG
+
+void DEG_graph_build_from_ids(Depsgraph *graph,
+ Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ ID **ids,
+ const int num_ids)
+{
+ double start_time = 0.0;
+ if (G.debug & (G_DEBUG_DEPSGRAPH_BUILD | G_DEBUG_DEPSGRAPH_TIME)) {
+ start_time = PIL_check_seconds_timer();
+ }
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ /* Perform sanity checks. */
+ BLI_assert(BLI_findindex(&scene->view_layers, view_layer) != -1);
+ BLI_assert(deg_graph->scene == scene);
+ BLI_assert(deg_graph->view_layer == view_layer);
+ DEG::DepsgraphBuilderCache builder_cache;
+ /* Generate all the nodes in the graph first */
+ DEG::DepsgraphFromIDsNodeBuilder node_builder(bmain, deg_graph, &builder_cache, ids, num_ids);
+ node_builder.begin_build();
+ node_builder.build_view_layer(scene, view_layer, DEG::DEG_ID_LINKED_DIRECTLY);
+ for (int i = 0; i < num_ids; ++i) {
+ node_builder.build_id(ids[i]);
+ }
+ node_builder.end_build();
+ /* Hook up relationships between operations - to determine evaluation order. */
+ DEG::DepsgraphFromIDsRelationBuilder relation_builder(
+ bmain, deg_graph, &builder_cache, ids, num_ids);
+ relation_builder.begin_build();
+ relation_builder.build_view_layer(scene, view_layer, DEG::DEG_ID_LINKED_DIRECTLY);
+ for (int i = 0; i < num_ids; ++i) {
+ relation_builder.build_id(ids[i]);
+ }
+ relation_builder.build_copy_on_write_relations();
+ /* Finalize building. */
+ graph_build_finalize_common(deg_graph, bmain);
+ /* Finish statistics. */
+ if (G.debug & (G_DEBUG_DEPSGRAPH_BUILD | G_DEBUG_DEPSGRAPH_TIME)) {
+ printf("Depsgraph built in %f seconds.\n", PIL_check_seconds_timer() - start_time);
+ }
+}
+
/* Tag graph relations for update. */
void DEG_graph_tag_relations_update(Depsgraph *graph)
{
@@ -356,12 +498,7 @@ void DEG_graph_relations_update(Depsgraph *graph, Main *bmain, Scene *scene, Vie
void DEG_relations_tag_update(Main *bmain)
{
DEG_GLOBAL_DEBUG_PRINTF(TAG, "%s: Tagging relations for update.\n", __func__);
- LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
- LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
- Depsgraph *depsgraph = (Depsgraph *)BKE_scene_get_depsgraph(scene, view_layer, false);
- if (depsgraph != NULL) {
- DEG_graph_tag_relations_update(depsgraph);
- }
- }
+ for (DEG::Depsgraph *depsgraph : DEG::get_all_registered_graphs(bmain)) {
+ DEG_graph_tag_relations_update(reinterpret_cast<Depsgraph *>(depsgraph));
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc
index 6253d31b8aa..d079c958e04 100644
--- a/source/blender/depsgraph/intern/depsgraph_debug.cc
+++ b/source/blender/depsgraph/intern/depsgraph_debug.cc
@@ -91,7 +91,7 @@ bool DEG_debug_graph_relations_validate(Depsgraph *graph,
Scene *scene,
ViewLayer *view_layer)
{
- Depsgraph *temp_depsgraph = DEG_graph_new(scene, view_layer, DEG_get_mode(graph));
+ Depsgraph *temp_depsgraph = DEG_graph_new(bmain, scene, view_layer, DEG_get_mode(graph));
bool valid = true;
DEG_graph_build_from_view_layer(temp_depsgraph, bmain, scene, view_layer);
if (!DEG_debug_compare(temp_depsgraph, graph)) {
@@ -112,13 +112,13 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
int counter1 = 0;
for (DEG::Relation *tmp_rel : node->outlinks) {
if (tmp_rel == rel) {
- ++counter1;
+ counter1++;
}
}
int counter2 = 0;
for (DEG::Relation *tmp_rel : rel->to->inlinks) {
if (tmp_rel == rel) {
- ++counter2;
+ counter2++;
}
}
if (counter1 != counter2) {
@@ -137,13 +137,13 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
int counter1 = 0;
for (DEG::Relation *tmp_rel : node->inlinks) {
if (tmp_rel == rel) {
- ++counter1;
+ counter1++;
}
}
int counter2 = 0;
for (DEG::Relation *tmp_rel : rel->from->outlinks) {
if (tmp_rel == rel) {
- ++counter2;
+ counter2++;
}
}
if (counter1 != counter2) {
@@ -179,7 +179,7 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
int num_links_pending = 0;
for (DEG::Relation *rel : node->inlinks) {
if (rel->from->type == DEG::NodeType::OPERATION) {
- ++num_links_pending;
+ num_links_pending++;
}
}
if (node->num_links_pending != num_links_pending) {
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
index 55241d03e94..b2b7d2a9d00 100644
--- a/source/blender/depsgraph/intern/depsgraph_eval.cc
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -49,7 +49,7 @@ extern "C" {
#include "intern/depsgraph.h"
/* Evaluate all nodes tagged for updating. */
-void DEG_evaluate_on_refresh(Depsgraph *graph)
+void DEG_evaluate_on_refresh(Main *bmain, Depsgraph *graph)
{
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
deg_graph->ctime = BKE_scene_frame_get(deg_graph->scene);
@@ -60,6 +60,7 @@ void DEG_evaluate_on_refresh(Depsgraph *graph)
if (deg_graph->scene_cow) {
BKE_scene_frame_set(deg_graph->scene_cow, deg_graph->ctime);
}
+ DEG::deg_graph_flush_updates(bmain, deg_graph);
DEG::deg_evaluate_on_refresh(deg_graph);
deg_graph->need_update_time = false;
}
diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
index 33cb1ba7416..b7a40fb69bd 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
@@ -68,9 +68,20 @@ void deg_foreach_clear_flags(const Depsgraph *graph)
}
}
+bool deg_foreach_needs_visit(const OperationNode *op_node, const int flags)
+{
+ if (flags & DEG_FOREACH_COMPONENT_IGNORE_TRANSFORM_SOLVERS) {
+ if (op_node->opcode == OperationCode::RIGIDBODY_SIM) {
+ return false;
+ }
+ }
+ return true;
+}
+
void deg_foreach_dependent_operation(const Depsgraph *graph,
const ID *id,
eDepsObjectComponentType source_component_type,
+ int flags,
DEGForeachOperation callback,
void *user_data)
{
@@ -91,6 +102,9 @@ void deg_foreach_dependent_operation(const Depsgraph *graph,
continue;
}
for (OperationNode *op_node : comp_node->operations) {
+ if (!deg_foreach_needs_visit(op_node, flags)) {
+ continue;
+ }
queue.push_back(op_node);
op_node->scheduled = true;
op_node->owner->custom_flags |= DEG_NODE_VISITED;
@@ -108,7 +122,7 @@ void deg_foreach_dependent_operation(const Depsgraph *graph,
/* Schedule outgoing operation nodes. */
if (op_node->outlinks.size() == 1) {
OperationNode *to_node = (OperationNode *)op_node->outlinks[0]->to;
- if (to_node->scheduled == false) {
+ if (to_node->scheduled == false && deg_foreach_needs_visit(to_node, flags)) {
to_node->scheduled = true;
op_node = to_node;
}
@@ -119,7 +133,7 @@ void deg_foreach_dependent_operation(const Depsgraph *graph,
else {
for (Relation *rel : op_node->outlinks) {
OperationNode *to_node = (OperationNode *)rel->to;
- if (to_node->scheduled == false) {
+ if (to_node->scheduled == false && deg_foreach_needs_visit(to_node, flags)) {
queue.push_front(to_node);
to_node->scheduled = true;
}
@@ -150,6 +164,7 @@ void deg_foreach_dependent_component_callback(OperationNode *op_node, void *user
void deg_foreach_dependent_ID_component(const Depsgraph *graph,
const ID *id,
eDepsObjectComponentType source_component_type,
+ int flags,
DEGForeachIDComponentCallback callback,
void *user_data)
{
@@ -157,7 +172,7 @@ void deg_foreach_dependent_ID_component(const Depsgraph *graph,
data.callback = callback;
data.user_data = user_data;
deg_foreach_dependent_operation(
- graph, id, source_component_type, deg_foreach_dependent_component_callback, &data);
+ graph, id, source_component_type, flags, deg_foreach_dependent_component_callback, &data);
}
struct ForeachIDData {
@@ -185,7 +200,7 @@ void deg_foreach_dependent_ID(const Depsgraph *graph,
data.callback = callback;
data.user_data = user_data;
deg_foreach_dependent_operation(
- graph, id, DEG_OB_COMP_ANY, deg_foreach_dependent_ID_callback, &data);
+ graph, id, DEG_OB_COMP_ANY, 0, deg_foreach_dependent_ID_callback, &data);
}
void deg_foreach_ancestor_ID(const Depsgraph *graph,
@@ -278,11 +293,12 @@ void DEG_foreach_dependent_ID(const Depsgraph *depsgraph,
void DEG_foreach_dependent_ID_component(const Depsgraph *depsgraph,
const ID *id,
eDepsObjectComponentType source_component_type,
+ int flags,
DEGForeachIDComponentCallback callback,
void *user_data)
{
DEG::deg_foreach_dependent_ID_component(
- (const DEG::Depsgraph *)depsgraph, id, source_component_type, callback, user_data);
+ (const DEG::Depsgraph *)depsgraph, id, source_component_type, flags, callback, user_data);
}
void DEG_foreach_ancestor_ID(const Depsgraph *depsgraph,
diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
index 251857b58c9..28789968286 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
@@ -146,6 +146,8 @@ bool deg_objects_dupli_iterator_next(BLI_Iterator *iter)
*temp_dupli_object = *dob->ob;
temp_dupli_object->base_flag = dupli_parent->base_flag | BASE_FROM_DUPLI;
temp_dupli_object->base_local_view_bits = dupli_parent->base_local_view_bits;
+ temp_dupli_object->runtime.local_collections_bits =
+ dupli_parent->runtime.local_collections_bits;
temp_dupli_object->dt = MIN2(temp_dupli_object->dt, dupli_parent->dt);
copy_v4_v4(temp_dupli_object->color, dupli_parent->color);
diff --git a/source/blender/depsgraph/intern/depsgraph_registry.cc b/source/blender/depsgraph/intern/depsgraph_registry.cc
new file mode 100644
index 00000000000..ad60b1bc4cf
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_registry.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.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/depsgraph_registry.h"
+
+#include "BLI_utildefines.h"
+
+#include "intern/depsgraph.h"
+
+namespace DEG {
+
+typedef set<Depsgraph *> DepsgraphStorage;
+typedef map<Main *, DepsgraphStorage> MainDepsgraphMap;
+
+static MainDepsgraphMap g_graph_registry;
+
+void register_graph(Depsgraph *depsgraph)
+{
+ Main *bmain = depsgraph->bmain;
+ MainDepsgraphMap::iterator it = g_graph_registry.find(bmain);
+ if (it == g_graph_registry.end()) {
+ it = g_graph_registry.insert(make_pair(bmain, DepsgraphStorage())).first;
+ }
+ DepsgraphStorage &storage = it->second;
+ storage.insert(depsgraph);
+}
+
+void unregister_graph(Depsgraph *depsgraph)
+{
+ Main *bmain = depsgraph->bmain;
+ MainDepsgraphMap::iterator it = g_graph_registry.find(bmain);
+ BLI_assert(it != g_graph_registry.end());
+
+ // Remove dependency graph from storage.
+ DepsgraphStorage &storage = it->second;
+ storage.erase(depsgraph);
+
+ // If this was the last depsgraph associated with the main, remove the main entry as well.
+ if (storage.empty()) {
+ g_graph_registry.erase(bmain);
+ }
+}
+
+const set<Depsgraph *> &get_all_registered_graphs(Main *bmain)
+{
+ MainDepsgraphMap::iterator it = g_graph_registry.find(bmain);
+ if (it == g_graph_registry.end()) {
+ static DepsgraphStorage empty_storage;
+ return empty_storage;
+ }
+ return it->second;
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_registry.h b/source/blender/depsgraph/intern/depsgraph_registry.h
new file mode 100644
index 00000000000..7517b6a0b2a
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_registry.h
@@ -0,0 +1,38 @@
+/*
+ * 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 depsgraph
+ */
+
+#pragma once
+
+#include "intern/depsgraph_type.h"
+
+struct Main;
+
+namespace DEG {
+
+struct Depsgraph;
+
+void register_graph(Depsgraph *depsgraph);
+void unregister_graph(Depsgraph *depsgraph);
+const set<Depsgraph *> &get_all_registered_graphs(Main *bmain);
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index b73a3c08e10..2fdce0e30a5 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -30,7 +30,6 @@
#include <queue>
#include "BLI_utildefines.h"
-#include "BLI_listbase.h"
#include "BLI_math_bits.h"
#include "BLI_task.h"
@@ -64,6 +63,7 @@ extern "C" {
#include "intern/builder/deg_builder.h"
#include "intern/depsgraph.h"
#include "intern/depsgraph_update.h"
+#include "intern/depsgraph_registry.h"
#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/eval/deg_eval_flush.h"
#include "intern/node/deg_node.h"
@@ -412,11 +412,15 @@ static void graph_id_tag_update_single_flag(Main *bmain,
string stringify_append_bit(const string &str, IDRecalcFlag tag)
{
+ const char *tag_name = DEG_update_tag_as_string(tag);
+ if (tag_name == NULL) {
+ return str;
+ }
string result = str;
if (!result.empty()) {
result += ", ";
}
- result += DEG_update_tag_as_string(tag);
+ result += tag_name;
return result;
}
@@ -601,13 +605,8 @@ NodeType geometry_tag_to_component(const ID *id)
void id_tag_update(Main *bmain, ID *id, int flag, eUpdateSource update_source)
{
graph_id_tag_update(bmain, NULL, id, flag, update_source);
- LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
- LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
- Depsgraph *depsgraph = (Depsgraph *)BKE_scene_get_depsgraph(scene, view_layer, false);
- if (depsgraph != NULL) {
- graph_id_tag_update(bmain, depsgraph, id, flag, update_source);
- }
- }
+ for (DEG::Depsgraph *depsgraph : DEG::get_all_registered_graphs(bmain)) {
+ graph_id_tag_update(bmain, depsgraph, id, flag, update_source);
}
}
@@ -717,8 +716,7 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag)
case ID_RECALC_ALL:
return "ALL";
}
- BLI_assert(!"Unhandled update flag, should never happen!");
- return "UNKNOWN";
+ return NULL;
}
/* Data-Based Tagging */
@@ -766,24 +764,11 @@ void DEG_graph_id_type_tag(Depsgraph *depsgraph, short id_type)
void DEG_id_type_tag(Main *bmain, short id_type)
{
- LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
- LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
- Depsgraph *depsgraph = (Depsgraph *)BKE_scene_get_depsgraph(scene, view_layer, false);
- if (depsgraph != NULL) {
- DEG_graph_id_type_tag(depsgraph, id_type);
- }
- }
+ for (DEG::Depsgraph *depsgraph : DEG::get_all_registered_graphs(bmain)) {
+ DEG_graph_id_type_tag(reinterpret_cast<::Depsgraph *>(depsgraph), id_type);
}
}
-void DEG_graph_flush_update(Main *bmain, Depsgraph *depsgraph)
-{
- if (depsgraph == NULL) {
- return;
- }
- DEG::deg_graph_flush_updates(bmain, (DEG::Depsgraph *)depsgraph);
-}
-
/* Update dependency graph when visible scenes/layers changes. */
void DEG_graph_on_visible_update(Main *bmain, Depsgraph *depsgraph, const bool do_time)
{
@@ -793,13 +778,8 @@ void DEG_graph_on_visible_update(Main *bmain, Depsgraph *depsgraph, const bool d
void DEG_on_visible_update(Main *bmain, const bool do_time)
{
- LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
- LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
- Depsgraph *depsgraph = (Depsgraph *)BKE_scene_get_depsgraph(scene, view_layer, false);
- if (depsgraph != NULL) {
- DEG_graph_on_visible_update(bmain, depsgraph, do_time);
- }
- }
+ for (DEG::Depsgraph *depsgraph : DEG::get_all_registered_graphs(bmain)) {
+ DEG_graph_on_visible_update(bmain, reinterpret_cast<::Depsgraph *>(depsgraph), do_time);
}
}
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 138523c7208..27adcfca808 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -102,8 +102,12 @@ set(SRC
engines/eevee/eevee_motion_blur.c
engines/eevee/eevee_occlusion.c
engines/eevee/eevee_render.c
+ engines/eevee/eevee_sampling.c
engines/eevee/eevee_screen_raytrace.c
engines/eevee/eevee_shaders.c
+ engines/eevee/eevee_shadows.c
+ engines/eevee/eevee_shadows_cascade.c
+ engines/eevee/eevee_shadows_cube.c
engines/eevee/eevee_subsurface.c
engines/eevee/eevee_temporal_sampling.c
engines/eevee/eevee_volumes.c
@@ -201,6 +205,7 @@ 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)
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl SRC)
@@ -209,10 +214,6 @@ data_to_c_simple(engines/eevee/shaders/prepass_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/prepass_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/shadow_process_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/shadow_process_geom.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/shadow_store_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/shadow_copy_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/bsdf_lut_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/btdf_lut_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/bsdf_common_lib.glsl SRC)
@@ -307,6 +308,7 @@ data_to_c_simple(modes/shaders/overlay_face_wireframe_geom.glsl SRC)
data_to_c_simple(modes/shaders/overlay_face_wireframe_frag.glsl SRC)
data_to_c_simple(modes/shaders/object_camera_image_frag.glsl SRC)
data_to_c_simple(modes/shaders/object_camera_image_vert.glsl SRC)
+data_to_c_simple(modes/shaders/object_color_axes_vert.glsl SRC)
data_to_c_simple(modes/shaders/object_empty_axes_vert.glsl SRC)
data_to_c_simple(modes/shaders/object_empty_image_frag.glsl SRC)
data_to_c_simple(modes/shaders/object_empty_image_vert.glsl SRC)
diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c
index f548bd15bf4..188e252a285 100644
--- a/source/blender/draw/engines/basic/basic_engine.c
+++ b/source/blender/draw/engines/basic/basic_engine.c
@@ -162,7 +162,8 @@ static void basic_cache_populate(void *vedata, Object *ob)
}
}
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+ const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
const bool do_cull = (draw_ctx->v3d &&
(draw_ctx->v3d->shading.flag & V3D_SHADING_BACKFACE_CULLING));
DRWShadingGroup *shgrp = (do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp;
diff --git a/source/blender/draw/engines/eevee/eevee_bloom.c b/source/blender/draw/engines/eevee/eevee_bloom.c
index 14faa827be5..c6cc336db56 100644
--- a/source/blender/draw/engines/eevee/eevee_bloom.c
+++ b/source/blender/draw/engines/eevee/eevee_bloom.c
@@ -128,7 +128,7 @@ int EEVEE_bloom_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
/* Downsample buffers */
copy_v2_v2_int(texsize, blitsize);
- for (int i = 0; i < effects->bloom_iteration_len; ++i) {
+ for (int i = 0; i < effects->bloom_iteration_len; i++) {
texsize[0] /= 2;
texsize[1] /= 2;
@@ -147,7 +147,7 @@ int EEVEE_bloom_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
/* Upsample buffers */
copy_v2_v2_int(texsize, blitsize);
- for (int i = 0; i < effects->bloom_iteration_len - 1; ++i) {
+ for (int i = 0; i < effects->bloom_iteration_len - 1; i++) {
texsize[0] /= 2;
texsize[1] /= 2;
@@ -167,7 +167,7 @@ int EEVEE_bloom_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
/* Cleanup to release memory */
GPU_FRAMEBUFFER_FREE_SAFE(fbl->bloom_blit_fb);
- for (int i = 0; i < MAX_BLOOM_STEP - 1; ++i) {
+ for (int i = 0; i < MAX_BLOOM_STEP - 1; i++) {
GPU_FRAMEBUFFER_FREE_SAFE(fbl->bloom_down_fb[i]);
GPU_FRAMEBUFFER_FREE_SAFE(fbl->bloom_accum_fb[i]);
}
@@ -288,7 +288,7 @@ void EEVEE_bloom_draw(EEVEE_Data *vedata)
last = effects->bloom_downsample[0];
- for (int i = 1; i < effects->bloom_iteration_len; ++i) {
+ for (int i = 1; i < effects->bloom_iteration_len; i++) {
copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[i - 1]);
effects->unf_source_buffer = last;
@@ -300,7 +300,7 @@ void EEVEE_bloom_draw(EEVEE_Data *vedata)
}
/* Upsample and accumulate */
- for (int i = effects->bloom_iteration_len - 2; i >= 0; --i) {
+ for (int i = effects->bloom_iteration_len - 2; i >= 0; i--) {
copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[i]);
effects->unf_source_buffer = effects->bloom_downsample[i];
effects->unf_base_buffer = last;
@@ -324,7 +324,7 @@ void EEVEE_bloom_draw(EEVEE_Data *vedata)
void EEVEE_bloom_free(void)
{
- for (int i = 0; i < 2; ++i) {
+ for (int i = 0; i < 2; i++) {
DRW_SHADER_FREE_SAFE(e_data.bloom_blit_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.bloom_downsample_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.bloom_upsample_sh[i]);
diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c
index b792f93ced2..dd70ee1bd4b 100644
--- a/source/blender/draw/engines/eevee/eevee_data.c
+++ b/source/blender/draw/engines/eevee/eevee_data.c
@@ -35,23 +35,13 @@ void EEVEE_view_layer_data_free(void *storage)
MEM_SAFE_FREE(sldata->lights);
DRW_UBO_FREE_SAFE(sldata->light_ubo);
DRW_UBO_FREE_SAFE(sldata->shadow_ubo);
- DRW_UBO_FREE_SAFE(sldata->shadow_render_ubo);
- GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cube_target_fb);
- GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cube_store_fb);
- GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cube_copy_fb);
- GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cascade_target_fb);
- GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cascade_store_fb);
- GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cascade_copy_fb);
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_target);
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_blur);
+ GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_fb);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool);
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_target);
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_blur);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool);
- MEM_SAFE_FREE(sldata->shcasters_buffers[0].shadow_casters);
- MEM_SAFE_FREE(sldata->shcasters_buffers[0].flags);
- MEM_SAFE_FREE(sldata->shcasters_buffers[1].shadow_casters);
- MEM_SAFE_FREE(sldata->shcasters_buffers[1].flags);
+ for (int i = 0; i < 2; i++) {
+ MEM_SAFE_FREE(sldata->shcasters_buffers[i].bbox);
+ MEM_SAFE_FREE(sldata->shcasters_buffers[i].update);
+ }
if (sldata->fallback_lightcache) {
EEVEE_lightcache_free(sldata->fallback_lightcache);
@@ -153,7 +143,6 @@ static void eevee_light_data_init(DrawData *dd)
{
EEVEE_LightEngineData *led = (EEVEE_LightEngineData *)dd;
led->need_update = true;
- led->prev_cube_shadow_id = -1;
}
EEVEE_LightEngineData *EEVEE_light_data_get(Object *ob)
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 12d70131031..572e38a9395 100644
--- a/source/blender/draw/engines/eevee/eevee_depth_of_field.c
+++ b/source/blender/draw/engines/eevee/eevee_depth_of_field.c
@@ -269,7 +269,7 @@ void EEVEE_depth_of_field_draw(EEVEE_Data *vedata)
void EEVEE_depth_of_field_free(void)
{
- for (int i = 0; i < 2; ++i) {
+ for (int i = 0; i < 2; i++) {
DRW_SHADER_FREE_SAFE(e_data.dof_downsample_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.dof_scatter_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.dof_resolve_sh[i]);
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c
index 0ca1e0b2858..7df1c299454 100644
--- a/source/blender/draw/engines/eevee/eevee_effects.c
+++ b/source/blender/draw/engines/eevee/eevee_effects.c
@@ -206,7 +206,7 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata,
/**
* Compute Mipmap texel alignment.
*/
- for (int i = 0; i < 10; ++i) {
+ for (int i = 0; i < 10; i++) {
int mip_size[2];
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));
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index ab4eb7b8532..a1096390bce 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -84,7 +84,7 @@ static void eevee_engine_init(void *ved)
/* EEVEE_effects_init needs to go first for TAA */
EEVEE_effects_init(sldata, vedata, camera, false);
EEVEE_materials_init(sldata, stl, fbl);
- EEVEE_lights_init(sldata);
+ EEVEE_shadows_init(sldata);
EEVEE_lightprobes_init(sldata, vedata);
}
@@ -139,7 +139,7 @@ void EEVEE_cache_populate(void *vedata, Object *ob)
}
if (cast_shadow) {
- EEVEE_lights_cache_shcaster_object_add(sldata, ob);
+ EEVEE_shadows_caster_register(sldata, ob);
}
}
@@ -223,7 +223,7 @@ static void eevee_draw_background(void *vedata)
/* Refresh shadows */
DRW_stats_group_start("Shadows");
- EEVEE_draw_shadows(sldata, vedata, stl->effects->taa_view);
+ EEVEE_shadows_draw(sldata, vedata, stl->effects->taa_view);
DRW_stats_group_end();
if (((stl->effects->enabled_effects & EFFECT_TAA) != 0) &&
@@ -269,9 +269,7 @@ static void eevee_draw_background(void *vedata)
if (DRW_state_draw_background()) {
DRW_draw_pass(psl->background_pass);
}
- EEVEE_draw_default_passes(psl);
- DRW_draw_pass(psl->material_pass);
- DRW_draw_pass(psl->material_pass_cull);
+ EEVEE_materials_draw_opaque(sldata, psl);
EEVEE_subsurface_data_render(sldata, vedata);
DRW_stats_group_end();
@@ -368,11 +366,21 @@ static void eevee_draw_background(void *vedata)
}
break;
case 8:
- if (effects->sss_data) {
- DRW_transform_to_display(effects->sss_data, false, false);
+ if (effects->sss_irradiance) {
+ DRW_transform_to_display(effects->sss_irradiance, false, false);
}
break;
case 9:
+ if (effects->sss_radius) {
+ DRW_transform_to_display(effects->sss_radius, false, false);
+ }
+ break;
+ case 10:
+ if (effects->sss_albedo) {
+ DRW_transform_to_display(effects->sss_albedo, false, false);
+ }
+ break;
+ case 11:
if (effects->velocity_tx) {
DRW_transform_to_display(effects->velocity_tx, false, false);
}
@@ -467,7 +475,7 @@ static void eevee_engine_free(void)
EEVEE_depth_of_field_free();
EEVEE_effects_free();
EEVEE_lightprobes_free();
- EEVEE_lights_free();
+ EEVEE_shadows_free();
EEVEE_materials_free();
EEVEE_mist_free();
EEVEE_motion_blur_free();
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c
index 05aea652591..261b7f00e42 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.c
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.c
@@ -188,7 +188,7 @@ static uint eevee_lightcache_memsize_get(LightCache *lcache)
}
if (lcache->cube_tx.data) {
size += MEM_allocN_len(lcache->cube_tx.data);
- for (int mip = 0; mip < lcache->mips_len; ++mip) {
+ for (int mip = 0; mip < lcache->mips_len; mip++) {
size += MEM_allocN_len(lcache->cube_mips[mip].data);
}
}
@@ -199,7 +199,7 @@ static int eevee_lightcache_irradiance_sample_count(LightCache *lcache)
{
int total_irr_samples = 0;
- for (int i = 1; i < lcache->grid_len; ++i) {
+ for (int i = 1; i < lcache->grid_len; i++) {
EEVEE_LightGrid *egrid = lcache->grid_data + i;
total_irr_samples += egrid->resolution[0] * egrid->resolution[1] * egrid->resolution[2];
}
@@ -218,7 +218,7 @@ void EEVEE_lightcache_info_update(SceneEEVEE *eevee)
}
char formatted_mem[15];
- BLI_str_format_byte_unit(formatted_mem, eevee_lightcache_memsize_get(lcache), true);
+ BLI_str_format_byte_unit(formatted_mem, eevee_lightcache_memsize_get(lcache), false);
int irr_samples = eevee_lightcache_irradiance_sample_count(lcache);
@@ -305,7 +305,7 @@ LightCache *EEVEE_lightcache_create(const int grid_len,
light_cache->cube_mips = MEM_callocN(sizeof(LightCacheTexture) * light_cache->mips_len,
"LightCacheTexture");
- for (int mip = 0; mip < light_cache->mips_len; ++mip) {
+ for (int mip = 0; mip < light_cache->mips_len; mip++) {
GPU_texture_get_mipmap_size(
light_cache->cube_tx.tex, mip + 1, light_cache->cube_mips[mip].tex_size);
}
@@ -346,7 +346,7 @@ void EEVEE_lightcache_load(LightCache *lcache)
NULL);
GPU_texture_bind(lcache->cube_tx.tex, 0);
GPU_texture_mipmap_mode(lcache->cube_tx.tex, true, true);
- for (int mip = 0; mip < lcache->mips_len; ++mip) {
+ for (int mip = 0; mip < lcache->mips_len; mip++) {
GPU_texture_add_mipmap(
lcache->cube_tx.tex, GPU_DATA_10_11_11_REV, mip + 1, lcache->cube_mips[mip].data);
}
@@ -369,7 +369,7 @@ static void eevee_lightbake_readback_reflections(LightCache *lcache)
lcache->cube_tx.data_type = LIGHTCACHETEX_UINT;
lcache->cube_tx.components = 1;
- for (int mip = 0; mip < lcache->mips_len; ++mip) {
+ for (int mip = 0; mip < lcache->mips_len; mip++) {
LightCacheTexture *cube_mip = lcache->cube_mips + mip;
MEM_SAFE_FREE(cube_mip->data);
GPU_texture_get_mipmap_size(lcache->cube_tx.tex, mip + 1, cube_mip->tex_size);
@@ -388,7 +388,7 @@ void EEVEE_lightcache_free(LightCache *lcache)
MEM_SAFE_FREE(lcache->grid_tx.data);
if (lcache->cube_mips) {
- for (int i = 0; i < lcache->mips_len; ++i) {
+ for (int i = 0; i < lcache->mips_len; i++) {
MEM_SAFE_FREE(lcache->cube_mips[i].data);
}
MEM_SAFE_FREE(lcache->cube_mips);
@@ -471,7 +471,7 @@ static void eevee_lightbake_create_render_target(EEVEE_LightBake *lbake, int rt_
lbake->rt_color = DRW_texture_create_cube(
rt_res, GPU_RGBA16F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
- for (int i = 0; i < 6; ++i) {
+ for (int i = 0; i < 6; i++) {
GPU_framebuffer_ensure_config(&lbake->rt_fb[i],
{GPU_ATTACHMENT_TEXTURE_CUBEFACE(lbake->rt_depth, i),
GPU_ATTACHMENT_TEXTURE_CUBEFACE(lbake->rt_color, i)});
@@ -561,7 +561,7 @@ wmJob *EEVEE_lightbake_job_create(struct wmWindowManager *wm,
/* Cannot reuse depsgraph for now because we cannot get the update from the
* main database directly. TODO reuse depsgraph and only update positions. */
/* lbake->depsgraph = old_lbake->depsgraph; */
- lbake->depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
+ lbake->depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
lbake->mutex = BLI_mutex_alloc();
@@ -612,7 +612,7 @@ void *EEVEE_lightbake_job_data_alloc(struct Main *bmain,
EEVEE_LightBake *lbake = MEM_callocN(sizeof(EEVEE_LightBake), "EEVEE_LightBake");
- lbake->depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
+ lbake->depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
lbake->scene = scene;
lbake->bmain = bmain;
lbake->view_layer_input = view_layer;
@@ -670,7 +670,7 @@ static void eevee_lightbake_delete_resources(EEVEE_LightBake *lbake)
DRW_TEXTURE_FREE_SAFE(lbake->rt_color);
DRW_TEXTURE_FREE_SAFE(lbake->grid_prev);
GPU_FRAMEBUFFER_FREE_SAFE(lbake->store_fb);
- for (int i = 0; i < 6; ++i) {
+ for (int i = 0; i < 6; i++) {
GPU_FRAMEBUFFER_FREE_SAFE(lbake->rt_fb[i]);
}
@@ -743,7 +743,7 @@ static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lb
EEVEE_effects_init(sldata, vedata, NULL, true);
EEVEE_materials_init(sldata, stl, fbl);
- EEVEE_lights_init(sldata);
+ EEVEE_shadows_init(sldata);
EEVEE_lightprobes_init(sldata, vedata);
EEVEE_effects_cache_init(sldata, vedata);
@@ -875,10 +875,10 @@ static void compute_cell_id(EEVEE_LightGrid *egrid,
*r_stride = 0;
*r_final_idx = 0;
r_local_cell[0] = r_local_cell[1] = r_local_cell[2] = 0;
- for (int lvl = max_lvl; lvl >= 0; --lvl) {
+ for (int lvl = max_lvl; lvl >= 0; lvl--) {
*r_stride = 1 << lvl;
int prev_stride = *r_stride << 1;
- for (int i = 0; i < cell_count; ++i) {
+ for (int i = 0; i < cell_count; i++) {
*r_final_idx = i;
cell_id_to_grid_loc(egrid, *r_final_idx, r_local_cell);
if (((r_local_cell[0] % *r_stride) == 0) && ((r_local_cell[1] % *r_stride) == 0) &&
@@ -1210,12 +1210,12 @@ void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float
/* Render irradiance grids */
if (lcache->flag & LIGHTCACHE_UPDATE_GRID) {
- for (lbake->bounce_curr = 0; lbake->bounce_curr < lbake->bounce_len; ++lbake->bounce_curr) {
+ for (lbake->bounce_curr = 0; lbake->bounce_curr < lbake->bounce_len; lbake->bounce_curr++) {
/* Bypass world, start at 1. */
lbake->probe = lbake->grid_prb + 1;
lbake->grid = lcache->grid_data + 1;
for (lbake->grid_curr = 1; lbake->grid_curr < lbake->grid_len;
- ++lbake->grid_curr, ++lbake->probe, ++lbake->grid) {
+ lbake->grid_curr++, lbake->probe++, lbake->grid++) {
LightProbe *prb = *lbake->probe;
lbake->grid_sample_len = prb->grid_resolution_x * prb->grid_resolution_y *
prb->grid_resolution_z;
@@ -1233,7 +1233,7 @@ void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float
lbake->probe = lbake->cube_prb + 1;
lbake->cube = lcache->cube_data + 1;
for (lbake->cube_offset = 1; lbake->cube_offset < lbake->cube_len;
- ++lbake->cube_offset, ++lbake->probe, ++lbake->cube) {
+ lbake->cube_offset++, lbake->probe++, lbake->cube++) {
lightbake_do_sample(lbake, eevee_lightbake_render_probe_sample);
}
}
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
index 8b1309e8537..19f3983998e 100644
--- a/source/blender/draw/engines/eevee/eevee_lightprobes.c
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -410,7 +410,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
/* Grid Display */
if (scene_eval->eevee.flag & SCE_EEVEE_SHOW_IRRADIANCE) {
EEVEE_LightGrid *egrid = lcache->grid_data + 1;
- for (int p = 1; p < lcache->grid_len; ++p, egrid++) {
+ for (int p = 1; p < lcache->grid_len; p++, egrid++) {
DRWShadingGroup *shgrp = DRW_shgroup_create(EEVEE_shaders_probe_grid_display_sh_get(),
psl->probe_display);
@@ -471,7 +471,7 @@ static bool eevee_lightprobes_culling_test(Object *ob)
normalize_v3(tmp[2]);
mul_v3_fl(tmp[2], probe->distinf);
- for (int v = 0; v < 8; ++v) {
+ for (int v = 0; v < 8; v++) {
mul_m4_v3(tmp, bbox.vec[v]);
}
const DRWView *default_view = DRW_view_default_get();
@@ -845,7 +845,7 @@ static void render_cubemap(void (*callback)(int face, EEVEE_BakeRenderData *user
}
}
- for (int i = 0; i < 6; ++i) {
+ for (int i = 0; i < 6; i++) {
DRW_view_set_active(views[i]);
callback(i, user_data);
}
@@ -860,11 +860,11 @@ static void render_reflections(void (*callback)(int face, EEVEE_BakeRenderData *
DRWView *main_view = stl->effects->taa_view;
DRWView **views = stl->g_data->planar_views;
/* Prepare views at the same time for faster culling. */
- for (int i = 0; i < ref_count; ++i) {
+ for (int i = 0; i < ref_count; i++) {
lightbake_planar_ensure_view(&planar_data[i], main_view, &views[i]);
}
- for (int i = 0; i < ref_count; ++i) {
+ for (int i = 0; i < ref_count; i++) {
DRW_view_set_active(views[i]);
callback(i, user_data);
}
@@ -904,7 +904,7 @@ static void lightbake_render_scene_face(int face, EEVEE_BakeRenderData *user_dat
struct GPUFrameBuffer **face_fb = user_data->face_fb;
/* Be sure that cascaded shadow maps are updated. */
- EEVEE_draw_shadows(sldata, user_data->vedata, views[face]);
+ EEVEE_shadows_draw(sldata, user_data->vedata, views[face]);
GPU_framebuffer_bind(face_fb[face]);
GPU_framebuffer_clear_depth(face_fb[face], 1.0f);
@@ -912,11 +912,9 @@ static void lightbake_render_scene_face(int face, EEVEE_BakeRenderData *user_dat
DRW_draw_pass(psl->depth_pass);
DRW_draw_pass(psl->depth_pass_cull);
DRW_draw_pass(psl->probe_background);
- DRW_draw_pass(psl->material_pass);
- DRW_draw_pass(psl->material_pass_cull);
+ EEVEE_materials_draw_opaque(sldata, psl);
DRW_draw_pass(psl->sss_pass); /* Only output standard pass */
DRW_draw_pass(psl->sss_pass_cull);
- EEVEE_draw_default_passes(psl);
DRW_draw_pass(psl->transparent_pass);
}
@@ -964,7 +962,7 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us
DRW_stats_group_start("Planar Reflection");
/* Be sure that cascaded shadow maps are updated. */
- EEVEE_draw_shadows(sldata, vedata, stl->g_data->planar_views[layer]);
+ EEVEE_shadows_draw(sldata, vedata, stl->g_data->planar_views[layer]);
GPU_framebuffer_bind(fbl->planarref_fb);
GPU_framebuffer_clear_depth(fbl->planarref_fb, 1.0);
@@ -987,9 +985,7 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us
GPU_framebuffer_bind(fbl->planarref_fb);
/* Shading pass */
- EEVEE_draw_default_passes(psl);
- DRW_draw_pass(psl->material_pass);
- DRW_draw_pass(psl->material_pass_cull);
+ EEVEE_materials_draw_opaque(sldata, psl);
DRW_draw_pass(psl->sss_pass); /* Only output standard pass */
DRW_draw_pass(psl->sss_pass_cull);
DRW_draw_pass(psl->refract_pass);
@@ -1221,7 +1217,7 @@ static void downsample_planar(void *vedata, int level)
const float *size = DRW_viewport_size_get();
copy_v2_v2(stl->g_data->planar_texel_size, size);
- for (int i = 0; i < level - 1; ++i) {
+ for (int i = 0; i < level - 1; i++) {
stl->g_data->planar_texel_size[0] /= 2.0f;
stl->g_data->planar_texel_size[1] /= 2.0f;
min_ff(floorf(stl->g_data->planar_texel_size[0]), 1.0f);
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c
index 0bfc23b8354..126ec8d81c4 100644
--- a/source/blender/draw/engines/eevee/eevee_lights.c
+++ b/source/blender/draw/engines/eevee/eevee_lights.c
@@ -20,11 +20,7 @@
* \ingroup DNA
*/
-#include "DRW_render.h"
-
-#include "BLI_dynstr.h"
-#include "BLI_rand.h"
-#include "BLI_rect.h"
+#include "BLI_sys_types.h" /* bool */
#include "BKE_object.h"
@@ -32,623 +28,20 @@
#include "eevee_private.h"
-#define SHADOW_CASTER_ALLOC_CHUNK 16
-
-// #define DEBUG_CSM
-// #define DEBUG_SHADOW_DISTRIBUTION
-
-static struct {
- struct GPUShader *shadow_sh;
- struct GPUShader *shadow_store_cube_sh[SHADOW_METHOD_MAX];
- struct GPUShader *shadow_store_cube_high_sh[SHADOW_METHOD_MAX];
- struct GPUShader *shadow_store_cascade_sh[SHADOW_METHOD_MAX];
- struct GPUShader *shadow_store_cascade_high_sh[SHADOW_METHOD_MAX];
- struct GPUShader *shadow_copy_cube_sh[SHADOW_METHOD_MAX];
- struct GPUShader *shadow_copy_cascade_sh[SHADOW_METHOD_MAX];
-} e_data = {NULL}; /* Engine data */
-
-extern char datatoc_shadow_vert_glsl[];
-extern char datatoc_shadow_frag_glsl[];
-extern char datatoc_shadow_process_vert_glsl[];
-extern char datatoc_shadow_process_geom_glsl[];
-extern char datatoc_shadow_store_frag_glsl[];
-extern char datatoc_shadow_copy_frag_glsl[];
-extern char datatoc_concentric_samples_lib_glsl[];
-
-extern char datatoc_common_view_lib_glsl[];
-
-/* Prototypes */
-static void eevee_light_setup(Object *ob, EEVEE_Light *evli);
-static float light_attenuation_radius_get(Light *la, float light_threshold);
-
-/* *********** LIGHT BITS *********** */
-static void lightbits_set_single(EEVEE_LightBits *bitf, uint idx, bool val)
-{
- if (val) {
- bitf->fields[idx / 8] |= (1 << (idx % 8));
- }
- else {
- bitf->fields[idx / 8] &= ~(1 << (idx % 8));
- }
-}
-
-static void lightbits_set_all(EEVEE_LightBits *bitf, bool val)
-{
- memset(bitf, (val) ? 0xFF : 0x00, sizeof(EEVEE_LightBits));
-}
-
-static void lightbits_or(EEVEE_LightBits *r, const EEVEE_LightBits *v)
-{
- for (int i = 0; i < MAX_LIGHTBITS_FIELDS; ++i) {
- r->fields[i] |= v->fields[i];
- }
-}
-
-static bool lightbits_get(const EEVEE_LightBits *r, uint idx)
-{
- return r->fields[idx / 8] & (1 << (idx % 8));
-}
-
-static void lightbits_convert(EEVEE_LightBits *r,
- const EEVEE_LightBits *bitf,
- const int *light_bit_conv_table,
- uint table_length)
-{
- for (int i = 0; i < table_length; ++i) {
- if (lightbits_get(bitf, i) != 0) {
- if (light_bit_conv_table[i] >= 0) {
- r->fields[i / 8] |= (1 << (i % 8));
- }
- }
- }
-}
-
-/* *********** FUNCTIONS *********** */
-
-void EEVEE_lights_init(EEVEE_ViewLayerData *sldata)
-{
- const uint shadow_ubo_size = sizeof(EEVEE_Shadow) * MAX_SHADOW +
- sizeof(EEVEE_ShadowCube) * MAX_SHADOW_CUBE +
- sizeof(EEVEE_ShadowCascade) * MAX_SHADOW_CASCADE;
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
-
- if (!e_data.shadow_sh) {
- e_data.shadow_sh = DRW_shader_create_with_lib(datatoc_shadow_vert_glsl,
- NULL,
- datatoc_shadow_frag_glsl,
- datatoc_common_view_lib_glsl,
- NULL);
- }
-
- if (!sldata->lights) {
- sldata->lights = MEM_callocN(sizeof(EEVEE_LightsInfo), "EEVEE_LightsInfo");
- sldata->light_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_Light) * MAX_LIGHT, NULL);
- sldata->shadow_ubo = DRW_uniformbuffer_create(shadow_ubo_size, NULL);
- sldata->shadow_render_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_ShadowRender), NULL);
-
- for (int i = 0; i < 2; ++i) {
- sldata->shcasters_buffers[i].shadow_casters = MEM_callocN(
- sizeof(EEVEE_ShadowCaster) * SHADOW_CASTER_ALLOC_CHUNK, "EEVEE_ShadowCaster buf");
- sldata->shcasters_buffers[i].flags = MEM_callocN(sizeof(sldata->shcasters_buffers[0].flags) *
- SHADOW_CASTER_ALLOC_CHUNK,
- "EEVEE_shcast_buffer flags buf");
- sldata->shcasters_buffers[i].alloc_count = SHADOW_CASTER_ALLOC_CHUNK;
- sldata->shcasters_buffers[i].count = 0;
- }
-
- sldata->lights->shcaster_frontbuffer = &sldata->shcasters_buffers[0];
- sldata->lights->shcaster_backbuffer = &sldata->shcasters_buffers[1];
- }
-
- /* Flip buffers */
- SWAP(EEVEE_ShadowCasterBuffer *,
- sldata->lights->shcaster_frontbuffer,
- sldata->lights->shcaster_backbuffer);
-
- const int sh_method = scene_eval->eevee.shadow_method;
- int sh_cube_size = scene_eval->eevee.shadow_cube_size;
- int sh_cascade_size = scene_eval->eevee.shadow_cascade_size;
- const bool sh_high_bitdepth = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_HIGH_BITDEPTH) != 0;
- sldata->lights->soft_shadows = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_SOFT) != 0;
-
- EEVEE_LightsInfo *linfo = sldata->lights;
- if ((linfo->shadow_cube_size != sh_cube_size) || (linfo->shadow_method != sh_method) ||
- (linfo->shadow_high_bitdepth != sh_high_bitdepth)) {
- BLI_assert((sh_cube_size > 0) && (sh_cube_size <= 4096));
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool);
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_target);
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_blur);
-
- /* Compute adequate size for the octahedral map. */
- linfo->shadow_cube_store_size = OCTAHEDRAL_SIZE_FROM_CUBESIZE(sh_cube_size);
-
- CLAMP(linfo->shadow_cube_store_size, 1, 4096);
- CLAMP(sh_cube_size, 1, 4096);
-
- linfo->shadow_render_data.cube_texel_size = 1.0f / sh_cube_size;
- }
-
- if ((linfo->shadow_cascade_size != sh_cascade_size) || (linfo->shadow_method != sh_method) ||
- (linfo->shadow_high_bitdepth != sh_high_bitdepth)) {
- BLI_assert((sh_cascade_size > 0) && (sh_cascade_size <= 4096));
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool);
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_target);
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_blur);
-
- CLAMP(sh_cascade_size, 1, 4096);
- }
-
- linfo->shadow_high_bitdepth = sh_high_bitdepth;
- linfo->shadow_method = sh_method;
- linfo->shadow_cube_size = sh_cube_size;
- linfo->shadow_cascade_size = sh_cascade_size;
-
- /* only compile the ones needed. reduce startup time. */
- if ((sh_method == SHADOW_ESM) && !e_data.shadow_copy_cube_sh[SHADOW_ESM]) {
- e_data.shadow_copy_cube_sh[SHADOW_ESM] = DRW_shader_create(datatoc_shadow_process_vert_glsl,
- datatoc_shadow_process_geom_glsl,
- datatoc_shadow_copy_frag_glsl,
- "#define ESM\n"
- "#define COPY\n");
- e_data.shadow_copy_cascade_sh[SHADOW_ESM] = DRW_shader_create(datatoc_shadow_process_vert_glsl,
- datatoc_shadow_process_geom_glsl,
- datatoc_shadow_copy_frag_glsl,
- "#define ESM\n"
- "#define COPY\n"
- "#define CSM\n");
- }
- else if ((sh_method == SHADOW_VSM) && !e_data.shadow_copy_cube_sh[SHADOW_VSM]) {
- e_data.shadow_copy_cube_sh[SHADOW_VSM] = DRW_shader_create(datatoc_shadow_process_vert_glsl,
- datatoc_shadow_process_geom_glsl,
- datatoc_shadow_copy_frag_glsl,
- "#define VSM\n"
- "#define COPY\n");
- e_data.shadow_copy_cascade_sh[SHADOW_VSM] = DRW_shader_create(datatoc_shadow_process_vert_glsl,
- datatoc_shadow_process_geom_glsl,
- datatoc_shadow_copy_frag_glsl,
- "#define VSM\n"
- "#define COPY\n"
- "#define CSM\n");
- }
-}
-
-static GPUShader *eevee_lights_get_store_sh(int shadow_method, bool high_blur, bool cascade)
-{
- GPUShader **shader;
-
- if (cascade) {
- shader = (high_blur) ? &e_data.shadow_store_cascade_high_sh[shadow_method] :
- &e_data.shadow_store_cascade_sh[shadow_method];
- }
- else {
- shader = (high_blur) ? &e_data.shadow_store_cube_high_sh[shadow_method] :
- &e_data.shadow_store_cube_sh[shadow_method];
- }
-
- if (*shader == NULL) {
- DynStr *ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, datatoc_concentric_samples_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_shadow_store_frag_glsl);
- char *store_shadow_shader_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
-
- ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, (shadow_method == SHADOW_VSM) ? "#define VSM\n" : "#define ESM\n");
- if (high_blur) {
- BLI_dynstr_append(ds_frag, "#define HIGH_BLUR\n");
- }
- if (cascade) {
- BLI_dynstr_append(ds_frag, "#define CSM\n");
- }
- char *define_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
-
- *shader = DRW_shader_create(datatoc_shadow_process_vert_glsl,
- datatoc_shadow_process_geom_glsl,
- store_shadow_shader_str,
- define_str);
-
- MEM_freeN(store_shadow_shader_str);
- MEM_freeN(define_str);
- }
-
- return *shader;
-}
-
-static DRWPass *eevee_lights_cube_store_pass_get(EEVEE_PassList *psl,
- EEVEE_ViewLayerData *sldata,
- int shadow_method,
- int shadow_samples_len)
-{
- bool high_blur = shadow_samples_len > 16;
- DRWPass **pass = (high_blur) ? &psl->shadow_cube_store_pass : &psl->shadow_cube_store_high_pass;
- if (*pass == NULL) {
- *pass = DRW_pass_create("Shadow Cube Storage Pass", DRW_STATE_WRITE_COLOR);
- GPUShader *shader = eevee_lights_get_store_sh(shadow_method, high_blur, false);
- DRWShadingGroup *grp = DRW_shgroup_create(shader, *pass);
- DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cube_blur);
- DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
-
- DRW_shgroup_call_procedural_triangles(grp, NULL, 6);
- }
- return *pass;
-}
-
-static DRWPass *eevee_lights_cascade_store_pass_get(EEVEE_PassList *psl,
- EEVEE_ViewLayerData *sldata,
- int shadow_method,
- int shadow_samples_len)
-{
- bool high_blur = shadow_samples_len > 16;
- DRWPass **pass = (high_blur) ? &psl->shadow_cascade_store_pass :
- &psl->shadow_cascade_store_high_pass;
- if (*pass == NULL) {
- *pass = DRW_pass_create("Shadow Cascade Storage Pass", DRW_STATE_WRITE_COLOR);
- GPUShader *shader = eevee_lights_get_store_sh(shadow_method, high_blur, true);
- DRWShadingGroup *grp = DRW_shgroup_create(shader, *pass);
- DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cascade_blur);
- DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
-
- DRW_shgroup_call_procedural_triangles(grp, NULL, MAX_CASCADE_NUM);
- }
- return *pass;
-}
-
-void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
-{
- EEVEE_LightsInfo *linfo = sldata->lights;
- EEVEE_StorageList *stl = vedata->stl;
- EEVEE_PassList *psl = vedata->psl;
-
- linfo->shcaster_frontbuffer->count = 0;
- linfo->num_light = 0;
- linfo->num_cube_layer = 0;
- linfo->num_cascade_layer = 0;
- linfo->gpu_cube_len = linfo->gpu_cascade_len = linfo->gpu_shadow_len = 0;
- linfo->cpu_cube_len = linfo->cpu_cascade_len = 0;
- memset(linfo->light_ref, 0, sizeof(linfo->light_ref));
- memset(linfo->shadow_cube_ref, 0, sizeof(linfo->shadow_cube_ref));
- memset(linfo->shadow_cascade_ref, 0, sizeof(linfo->shadow_cascade_ref));
- memset(linfo->new_shadow_id, -1, sizeof(linfo->new_shadow_id));
-
- /* Shadow Casters: Reset flags. */
- memset(linfo->shcaster_backbuffer->flags,
- (char)SHADOW_CASTER_PRUNED,
- linfo->shcaster_backbuffer->alloc_count);
- memset(linfo->shcaster_frontbuffer->flags, 0x00, linfo->shcaster_frontbuffer->alloc_count);
-
- psl->shadow_cube_store_pass = NULL;
- psl->shadow_cube_store_high_pass = NULL;
- psl->shadow_cascade_store_pass = NULL;
- psl->shadow_cascade_store_high_pass = NULL;
-
- {
- DRW_PASS_CREATE(psl->shadow_cube_copy_pass, DRW_STATE_WRITE_COLOR);
-
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_copy_cube_sh[linfo->shadow_method],
- psl->shadow_cube_copy_pass);
- DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cube_target);
- DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
-
- DRW_shgroup_call_procedural_triangles(grp, NULL, 6);
- }
-
- {
- DRW_PASS_CREATE(psl->shadow_cascade_copy_pass, DRW_STATE_WRITE_COLOR);
-
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_copy_cascade_sh[linfo->shadow_method],
- psl->shadow_cascade_copy_pass);
- DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cascade_target);
- DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
-
- DRW_shgroup_call_procedural_triangles(grp, NULL, MAX_CASCADE_NUM);
- }
-
- {
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- DRW_PASS_CREATE(psl->shadow_pass, state);
-
- stl->g_data->shadow_shgrp = DRW_shgroup_create(e_data.shadow_sh, psl->shadow_pass);
- }
-}
-
-void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
+/* Reconstruct local obmat from EEVEE_light. (normalized) */
+void eevee_light_matrix_get(const EEVEE_Light *evli, float r_mat[4][4])
{
- EEVEE_LightsInfo *linfo = sldata->lights;
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const float threshold = draw_ctx->scene->eevee.light_threshold;
- /* Step 1 find all lights in the scene and setup them */
- if (linfo->num_light >= MAX_LIGHT) {
- printf("Too many lights in the scene !!!\n");
- }
- else {
- Light *la = (Light *)ob->data;
-
- /* Early out if light has no power. */
- if (la->energy == 0.0f || is_zero_v3(&la->r)) {
- return;
- }
-
- EEVEE_Light *evli = linfo->light_data + linfo->num_light;
- eevee_light_setup(ob, evli);
-
- /* We do not support shadowmaps for dupli lights. */
- if ((ob->base_flag & BASE_FROM_DUPLI) != 0) {
- linfo->num_light++;
- return;
- }
-
- EEVEE_LightEngineData *led = EEVEE_light_data_ensure(ob);
-
- /* Save previous shadow id. */
- int prev_cube_sh_id = led->prev_cube_shadow_id;
-
- /* Default light without shadows */
- led->data.ld.shadow_id = -1;
- led->prev_cube_shadow_id = -1;
-
- if (la->mode & LA_SHADOW) {
- if (la->type == LA_SUN) {
- int cascade_nbr = la->cascade_count;
-
- if ((linfo->gpu_cascade_len + 1) <= MAX_SHADOW_CASCADE) {
- /* Save Light object. */
- linfo->shadow_cascade_ref[linfo->cpu_cascade_len] = ob;
-
- /* Store indices. */
- EEVEE_ShadowCascadeData *data = &led->data.scad;
- data->shadow_id = linfo->gpu_shadow_len;
- data->cascade_id = linfo->gpu_cascade_len;
- data->layer_id = linfo->num_cascade_layer;
-
- /* Increment indices. */
- linfo->gpu_shadow_len += 1;
- linfo->gpu_cascade_len += 1;
- linfo->num_cascade_layer += cascade_nbr;
-
- linfo->cpu_cascade_len += 1;
- }
- }
- else if (la->type == LA_SPOT || la->type == LA_LOCAL || la->type == LA_AREA) {
- if ((linfo->gpu_cube_len + 1) <= MAX_SHADOW_CUBE) {
- /* Save Light object. */
- linfo->shadow_cube_ref[linfo->cpu_cube_len] = ob;
-
- /* For light update tracking. */
- if ((prev_cube_sh_id >= 0) && (prev_cube_sh_id < linfo->shcaster_backbuffer->count)) {
- linfo->new_shadow_id[prev_cube_sh_id] = linfo->cpu_cube_len;
- }
- led->prev_cube_shadow_id = linfo->cpu_cube_len;
-
- /* Saving light bounds for later. */
- BLI_assert(linfo->cpu_cube_len >= 0 && linfo->cpu_cube_len < MAX_LIGHT);
- copy_v3_v3(linfo->shadow_bounds[linfo->cpu_cube_len].center, ob->obmat[3]);
- linfo->shadow_bounds[linfo->cpu_cube_len].radius = light_attenuation_radius_get(
- la, threshold);
-
- EEVEE_ShadowCubeData *data = &led->data.scd;
- /* Store indices. */
- data->shadow_id = linfo->gpu_shadow_len;
- data->cube_id = linfo->gpu_cube_len;
- data->layer_id = linfo->num_cube_layer;
-
- /* Increment indices. */
- linfo->gpu_shadow_len += 1;
- linfo->gpu_cube_len += 1;
- linfo->num_cube_layer += 1;
-
- linfo->cpu_cube_len += 1;
- }
- }
- }
-
- led->data.ld.light_id = linfo->num_light;
- linfo->light_ref[linfo->num_light] = ob;
- linfo->num_light++;
- }
-}
-
-/* Add a shadow caster to the shadowpasses */
-void EEVEE_lights_cache_shcaster_add(EEVEE_ViewLayerData *UNUSED(sldata),
- EEVEE_StorageList *stl,
- struct GPUBatch *geom,
- Object *ob)
-{
- DRW_shgroup_call(stl->g_data->shadow_shgrp, geom, ob);
-}
-
-void EEVEE_lights_cache_shcaster_material_add(EEVEE_ViewLayerData *sldata,
- EEVEE_PassList *psl,
- struct GPUMaterial *gpumat,
- struct GPUBatch *geom,
- struct Object *ob,
- const float *alpha_threshold)
-{
- /* TODO / PERF : reuse the same shading group for objects with the same material */
- DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, psl->shadow_pass);
-
- if (grp == NULL) {
- return;
- }
-
- /* Grrr needed for correctness but not 99% of the time not needed.
- * TODO detect when needed? */
- DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
- DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
- DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
- DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
- DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
- DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
-
- if (alpha_threshold != NULL) {
- DRW_shgroup_uniform_float(grp, "alphaThreshold", alpha_threshold, 1);
- }
-
- DRW_shgroup_call(grp, geom, ob);
+ copy_v3_v3(r_mat[0], evli->rightvec);
+ copy_v3_v3(r_mat[1], evli->upvec);
+ negate_v3_v3(r_mat[2], evli->forwardvec);
+ copy_v3_v3(r_mat[3], evli->position);
+ r_mat[0][3] = 0.0f;
+ r_mat[1][3] = 0.0f;
+ r_mat[2][3] = 0.0f;
+ r_mat[3][3] = 1.0f;
}
-/* Make that object update shadow casting lights inside its influence bounding box. */
-void EEVEE_lights_cache_shcaster_object_add(EEVEE_ViewLayerData *sldata, Object *ob)
-{
- if ((ob->base_flag & BASE_FROM_DUPLI) != 0) {
- /* TODO: Special case for dupli objects because we cannot save the object pointer. */
- return;
- }
-
- EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob);
- EEVEE_LightsInfo *linfo = sldata->lights;
- EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
- EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
- int past_id = oedata->shadow_caster_id;
-
- /* Update flags in backbuffer. */
- if (past_id > -1 && past_id < backbuffer->count) {
- backbuffer->flags[past_id] &= ~SHADOW_CASTER_PRUNED;
-
- if (oedata->need_update) {
- backbuffer->flags[past_id] |= SHADOW_CASTER_UPDATED;
- }
- }
-
- /* Update id. */
- oedata->shadow_caster_id = frontbuffer->count++;
-
- /* Make sure shadow_casters is big enough. */
- if (oedata->shadow_caster_id >= frontbuffer->alloc_count) {
- frontbuffer->alloc_count += SHADOW_CASTER_ALLOC_CHUNK;
- frontbuffer->shadow_casters = MEM_reallocN(
- frontbuffer->shadow_casters, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count);
- frontbuffer->flags = MEM_reallocN(frontbuffer->flags,
- sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count);
- }
-
- EEVEE_ShadowCaster *shcaster = frontbuffer->shadow_casters + oedata->shadow_caster_id;
-
- if (oedata->need_update) {
- frontbuffer->flags[oedata->shadow_caster_id] = SHADOW_CASTER_UPDATED;
- }
-
- /* Update World AABB in frontbuffer. */
- BoundBox *bb = BKE_object_boundbox_get(ob);
- float min[3], max[3];
- INIT_MINMAX(min, max);
- for (int i = 0; i < 8; ++i) {
- float vec[3];
- copy_v3_v3(vec, bb->vec[i]);
- mul_m4_v3(ob->obmat, vec);
- minmax_v3v3_v3(min, max, vec);
- }
-
- EEVEE_BoundBox *aabb = &shcaster->bbox;
- add_v3_v3v3(aabb->center, min, max);
- mul_v3_fl(aabb->center, 0.5f);
- sub_v3_v3v3(aabb->halfdim, aabb->center, max);
-
- aabb->halfdim[0] = fabsf(aabb->halfdim[0]);
- aabb->halfdim[1] = fabsf(aabb->halfdim[1]);
- aabb->halfdim[2] = fabsf(aabb->halfdim[2]);
-
- oedata->need_update = false;
-}
-
-void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
-{
- EEVEE_LightsInfo *linfo = sldata->lights;
- eGPUTextureFormat shadow_pool_format = GPU_R32F;
-
- sldata->common_data.la_num_light = linfo->num_light;
-
- /* Setup enough layers. */
- /* Free textures if number mismatch. */
- if (linfo->num_cube_layer != linfo->cache_num_cube_layer) {
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool);
- linfo->cache_num_cube_layer = linfo->num_cube_layer;
- linfo->update_flag |= LIGHT_UPDATE_SHADOW_CUBE;
- }
-
- if (linfo->num_cascade_layer != linfo->cache_num_cascade_layer) {
- DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool);
- linfo->cache_num_cascade_layer = linfo->num_cascade_layer;
- }
-
- switch (linfo->shadow_method) {
- case SHADOW_ESM:
- shadow_pool_format = ((linfo->shadow_high_bitdepth) ? GPU_R32F : GPU_R16F);
- break;
- case SHADOW_VSM:
- shadow_pool_format = ((linfo->shadow_high_bitdepth) ? GPU_RG32F : GPU_RG16F);
- break;
- default:
- BLI_assert(!"Incorrect Shadow Method");
- break;
- }
-
- /* Cubemaps */
- if (!sldata->shadow_cube_target) {
- sldata->shadow_cube_target = DRW_texture_create_cube(
- linfo->shadow_cube_size, GPU_DEPTH_COMPONENT24, 0, NULL);
- sldata->shadow_cube_blur = DRW_texture_create_cube(
- linfo->shadow_cube_size, shadow_pool_format, DRW_TEX_FILTER, NULL);
- }
- GPU_framebuffer_ensure_config(
- &sldata->shadow_cube_copy_fb,
- {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(sldata->shadow_cube_blur)});
-
- if (!sldata->shadow_cube_pool) {
- sldata->shadow_cube_pool = DRW_texture_create_2d_array(linfo->shadow_cube_store_size,
- linfo->shadow_cube_store_size,
- max_ii(1, linfo->num_cube_layer),
- shadow_pool_format,
- DRW_TEX_FILTER,
- NULL);
- }
- GPU_framebuffer_ensure_config(&sldata->shadow_cube_target_fb,
- {GPU_ATTACHMENT_TEXTURE(sldata->shadow_cube_target)});
- GPU_framebuffer_ensure_config(
- &sldata->shadow_cube_store_fb,
- {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(sldata->shadow_cube_pool)});
-
- /* CSM */
- if (!sldata->shadow_cascade_target) {
- sldata->shadow_cascade_target = DRW_texture_create_2d_array(linfo->shadow_cascade_size,
- linfo->shadow_cascade_size,
- MAX_CASCADE_NUM,
- GPU_DEPTH_COMPONENT24,
- 0,
- NULL);
- sldata->shadow_cascade_blur = DRW_texture_create_2d_array(linfo->shadow_cascade_size,
- linfo->shadow_cascade_size,
- MAX_CASCADE_NUM,
- shadow_pool_format,
- DRW_TEX_FILTER,
- NULL);
- }
- GPU_framebuffer_ensure_config(
- &sldata->shadow_cascade_copy_fb,
- {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(sldata->shadow_cascade_blur)});
-
- if (!sldata->shadow_cascade_pool) {
- sldata->shadow_cascade_pool = DRW_texture_create_2d_array(linfo->shadow_cascade_size,
- linfo->shadow_cascade_size,
- max_ii(1, linfo->num_cascade_layer),
- shadow_pool_format,
- DRW_TEX_FILTER,
- NULL);
- }
- GPU_framebuffer_ensure_config(&sldata->shadow_cascade_target_fb,
- {GPU_ATTACHMENT_TEXTURE(sldata->shadow_cascade_target)});
- GPU_framebuffer_ensure_config(
- &sldata->shadow_cascade_store_fb,
- {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(sldata->shadow_cascade_pool)});
-
- /* Update Lights UBOs. */
- EEVEE_lights_update(sldata, vedata);
-}
-
-float light_attenuation_radius_get(Light *la, float light_threshold)
+static float light_attenuation_radius_get(const Light *la, float light_threshold)
{
if (la->mode & LA_CUSTOM_ATTENUATION) {
return la->att_dist;
@@ -664,7 +57,7 @@ float light_attenuation_radius_get(Light *la, float light_threshold)
return distance;
}
-static void light_shape_parameters_set(EEVEE_Light *evli, const Light *la, float scale[3])
+static void light_shape_parameters_set(EEVEE_Light *evli, const Light *la, const float scale[3])
{
if (la->type == LA_SPOT) {
/* Spot size & blend */
@@ -684,7 +77,7 @@ static void light_shape_parameters_set(EEVEE_Light *evli, const Light *la, float
}
}
else if (la->type == LA_SUN) {
- evli->radius = max_ff(0.001f, tanf(la->sun_angle / 2.0f));
+ evli->radius = max_ff(0.001f, tanf(min_ff(la->sun_angle, DEG2RADF(179.9f)) / 2.0f));
}
else {
evli->radius = max_ff(0.001f, la->area_size);
@@ -774,809 +167,54 @@ static void eevee_light_setup(Object *ob, EEVEE_Light *evli)
mul_v3_fl(evli->color, power * la->energy);
/* No shadow by default */
- evli->shadowid = -1.0f;
-}
-
-/**
- * Special ball distribution:
- * Point are distributed in a way that when they are orthogonally
- * projected into any plane, the resulting distribution is (close to)
- * a uniform disc distribution.
- */
-static void sample_ball(int sample_ofs, float radius, float rsample[3])
-{
- double ht_point[3];
- double ht_offset[3] = {0.0, 0.0, 0.0};
- uint ht_primes[3] = {2, 3, 7};
-
- BLI_halton_3d(ht_primes, ht_offset, sample_ofs, ht_point);
-
- float omega = ht_point[1] * 2.0f * M_PI;
-
- rsample[2] = ht_point[0] * 2.0f - 1.0f; /* cos theta */
-
- float r = sqrtf(fmaxf(0.0f, 1.0f - rsample[2] * rsample[2])); /* sin theta */
-
- rsample[0] = r * cosf(omega);
- rsample[1] = r * sinf(omega);
-
- radius *= sqrt(sqrt(ht_point[2]));
- mul_v3_fl(rsample, radius);
-}
-
-static void sample_rectangle(
- int sample_ofs, float x_axis[3], float y_axis[3], float size_x, float size_y, float rsample[3])
-{
- double ht_point[2];
- double ht_offset[2] = {0.0, 0.0};
- uint ht_primes[2] = {2, 3};
-
- BLI_halton_2d(ht_primes, ht_offset, sample_ofs, ht_point);
-
- /* Change ditribution center to be 0,0 */
- ht_point[0] = (ht_point[0] > 0.5f) ? ht_point[0] - 1.0f : ht_point[0];
- ht_point[1] = (ht_point[1] > 0.5f) ? ht_point[1] - 1.0f : ht_point[1];
-
- zero_v3(rsample);
- madd_v3_v3fl(rsample, x_axis, (ht_point[0] * 2.0f) * size_x);
- madd_v3_v3fl(rsample, y_axis, (ht_point[1] * 2.0f) * size_y);
-}
-
-static void sample_ellipse(
- int sample_ofs, float x_axis[3], float y_axis[3], float size_x, float size_y, float rsample[3])
-{
- double ht_point[2];
- double ht_offset[2] = {0.0, 0.0};
- uint ht_primes[2] = {2, 3};
-
- BLI_halton_2d(ht_primes, ht_offset, sample_ofs, ht_point);
-
- /* Uniform disc sampling. */
- float omega = ht_point[1] * 2.0f * M_PI;
- float r = sqrtf(ht_point[0]);
- ht_point[0] = r * cosf(omega) * size_x;
- ht_point[1] = r * sinf(omega) * size_y;
-
- zero_v3(rsample);
- madd_v3_v3fl(rsample, x_axis, ht_point[0]);
- madd_v3_v3fl(rsample, y_axis, ht_point[1]);
-}
-
-static void shadow_cube_random_position_set(EEVEE_Light *evli,
- Light *la,
- int sample_ofs,
- float ws_sample_pos[3])
-{
- float jitter[3];
-
-#ifndef DEBUG_SHADOW_DISTRIBUTION
- int i = sample_ofs;
-#else
- for (int i = 0; i <= sample_ofs; ++i) {
-#endif
- switch (la->type) {
- case LA_AREA:
- if (ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_SQUARE)) {
- sample_rectangle(i, evli->rightvec, evli->upvec, evli->sizex, evli->sizey, jitter);
- }
- else {
- sample_ellipse(i, evli->rightvec, evli->upvec, evli->sizex, evli->sizey, jitter);
- }
- break;
- default:
- sample_ball(i, evli->radius, jitter);
- }
-#ifdef DEBUG_SHADOW_DISTRIBUTION
- float p[3];
- add_v3_v3v3(p, jitter, ws_sample_pos);
- DRW_debug_sphere(p, 0.01f, (float[4]){1.0f, (sample_ofs == i) ? 1.0f : 0.0f, 0.0f, 1.0f});
-}
-#endif
-add_v3_v3(ws_sample_pos, jitter);
-}
-
-static void eevee_shadow_cube_setup(Object *ob,
- EEVEE_LightsInfo *linfo,
- EEVEE_LightEngineData *led,
- int sample_ofs)
-{
- EEVEE_ShadowCubeData *sh_data = &led->data.scd;
- EEVEE_Light *evli = linfo->light_data + sh_data->light_id;
- EEVEE_Shadow *ubo_data = linfo->shadow_data + sh_data->shadow_id;
- EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + sh_data->cube_id;
- Light *la = (Light *)ob->data;
-
- copy_v3_v3(cube_data->position, ob->obmat[3]);
-
- if (linfo->soft_shadows) {
- shadow_cube_random_position_set(evli, la, sample_ofs, cube_data->position);
- }
-
- ubo_data->bias = 0.05f * la->bias;
- ubo_data->near = la->clipsta;
- ubo_data->far = 1.0f / (evli->invsqrdist * evli->invsqrdist);
- ubo_data->exp = (linfo->shadow_method == SHADOW_VSM) ? la->bleedbias : la->bleedexp;
-
- evli->shadowid = (float)(sh_data->shadow_id);
- ubo_data->shadow_start = (float)(sh_data->layer_id);
- ubo_data->data_start = (float)(sh_data->cube_id);
- ubo_data->shadow_blur = la->soft * 0.02f; /* Used by translucence shadowmap blur */
-
- ubo_data->contact_dist = (la->mode & LA_SHAD_CONTACT) ? la->contact_dist : 0.0f;
- ubo_data->contact_bias = 0.05f * la->contact_bias;
- ubo_data->contact_spread = la->contact_spread;
- ubo_data->contact_thickness = la->contact_thickness;
-}
-
-static void shadow_cascade_random_matrix_set(float mat[4][4], float radius, int sample_ofs)
-{
- float jitter[3];
-
-#ifndef DEBUG_SHADOW_DISTRIBUTION
- int i = sample_ofs;
-#else
- for (int i = 0; i <= sample_ofs; ++i) {
-#endif
- sample_ellipse(i, mat[0], mat[1], radius, radius, jitter);
-#ifdef DEBUG_SHADOW_DISTRIBUTION
- float p[3];
- add_v3_v3v3(p, jitter, mat[2]);
- DRW_debug_sphere(p, 0.01f, (float[4]){1.0f, (sample_ofs == i) ? 1.0f : 0.0f, 0.0f, 1.0f});
-}
-#endif
-
-add_v3_v3(mat[2], jitter);
-orthogonalize_m4(mat, 2);
-}
-
-#define LERP(t, a, b) ((a) + (t) * ((b) - (a)))
-
-static double round_to_digits(double value, int digits)
-{
- double factor = pow(10.0, digits - ceil(log10(fabs(value))));
- return round(value * factor) / factor;
-}
-
-static void frustum_min_bounding_sphere(const float corners[8][3],
- float r_center[3],
- float *r_radius)
-{
-#if 0 /* Simple solution but waste too much space. */
- float minvec[3], maxvec[3];
-
- /* compute the bounding box */
- INIT_MINMAX(minvec, maxvec);
- for (int i = 0; i < 8; ++i) {
- minmax_v3v3_v3(minvec, maxvec, corners[i]);
- }
-
- /* compute the bounding sphere of this box */
- r_radius = len_v3v3(minvec, maxvec) * 0.5f;
- add_v3_v3v3(r_center, minvec, maxvec);
- mul_v3_fl(r_center, 0.5f);
-#else
- /* Find averaged center. */
- zero_v3(r_center);
- for (int i = 0; i < 8; ++i) {
- add_v3_v3(r_center, corners[i]);
- }
- mul_v3_fl(r_center, 1.0f / 8.0f);
-
- /* Search the largest distance from the sphere center. */
- *r_radius = 0.0f;
- for (int i = 0; i < 8; ++i) {
- float rad = len_squared_v3v3(corners[i], r_center);
- if (rad > *r_radius) {
- *r_radius = rad;
- }
- }
-
- /* TODO try to reduce the radius further by moving the center.
- * Remember we need a __stable__ solution! */
-
- /* Try to reduce float imprecision leading to shimmering. */
- *r_radius = (float)round_to_digits(sqrtf(*r_radius), 3);
-#endif
-}
-
-static void eevee_shadow_cascade_setup(Object *ob,
- EEVEE_LightsInfo *linfo,
- EEVEE_LightEngineData *led,
- DRWView *view,
- float view_near,
- float view_far,
- int sample_ofs)
-{
- Light *la = (Light *)ob->data;
-
- /* Camera Matrices */
- float persinv[4][4], vp_projmat[4][4];
- DRW_view_persmat_get(view, persinv, true);
- DRW_view_winmat_get(view, vp_projmat, false);
- bool is_persp = DRW_view_is_persp_get(view);
-
- /* Lights Matrices */
- int cascade_nbr = la->cascade_count;
-
- EEVEE_ShadowCascadeData *sh_data = &led->data.scad;
- EEVEE_Light *evli = linfo->light_data + sh_data->light_id;
- EEVEE_Shadow *ubo_data = linfo->shadow_data + sh_data->shadow_id;
- EEVEE_ShadowCascade *cascade_data = linfo->shadow_cascade_data + sh_data->cascade_id;
-
- /* obmat = Object Space > World Space */
- /* viewmat = World Space > View Space */
- float(*viewmat)[4] = sh_data->viewmat;
-#if 0 /* done at culling time */
- normalize_m4_m4(viewmat, ob->obmat);
-#endif
-
- if (linfo->soft_shadows) {
- shadow_cascade_random_matrix_set(viewmat, evli->radius, sample_ofs);
- }
-
- copy_m4_m4(sh_data->viewinv, viewmat);
- invert_m4(viewmat);
-
- /* The technique consists into splitting
- * the view frustum into several sub-frustum
- * that are individually receiving one shadow map */
-
- float csm_start, csm_end;
-
- if (is_persp) {
- csm_start = view_near;
- csm_end = max_ff(view_far, -la->cascade_max_dist);
- /* Avoid artifacts */
- csm_end = min_ff(view_near, csm_end);
- }
- else {
- csm_start = -view_far;
- csm_end = view_far;
- }
-
- /* init near/far */
- for (int c = 0; c < MAX_CASCADE_NUM; ++c) {
- cascade_data->split_start[c] = csm_end;
- cascade_data->split_end[c] = csm_end;
- }
-
- /* Compute split planes */
- float splits_start_ndc[MAX_CASCADE_NUM];
- float splits_end_ndc[MAX_CASCADE_NUM];
-
- {
- /* Nearest plane */
- float p[4] = {1.0f, 1.0f, csm_start, 1.0f};
- /* TODO: we don't need full m4 multiply here */
- mul_m4_v4(vp_projmat, p);
- splits_start_ndc[0] = p[2];
- if (is_persp) {
- splits_start_ndc[0] /= p[3];
- }
- }
-
- {
- /* Farthest plane */
- float p[4] = {1.0f, 1.0f, csm_end, 1.0f};
- /* TODO: we don't need full m4 multiply here */
- mul_m4_v4(vp_projmat, p);
- splits_end_ndc[cascade_nbr - 1] = p[2];
- if (is_persp) {
- splits_end_ndc[cascade_nbr - 1] /= p[3];
- }
- }
-
- cascade_data->split_start[0] = csm_start;
- cascade_data->split_end[cascade_nbr - 1] = csm_end;
-
- for (int c = 1; c < cascade_nbr; ++c) {
- /* View Space */
- float linear_split = LERP(((float)(c) / (float)cascade_nbr), csm_start, csm_end);
- float exp_split = csm_start * powf(csm_end / csm_start, (float)(c) / (float)cascade_nbr);
-
- if (is_persp) {
- cascade_data->split_start[c] = LERP(la->cascade_exponent, linear_split, exp_split);
- }
- else {
- cascade_data->split_start[c] = linear_split;
- }
- cascade_data->split_end[c - 1] = cascade_data->split_start[c];
-
- /* Add some overlap for smooth transition */
- cascade_data->split_start[c] = LERP(la->cascade_fade,
- cascade_data->split_end[c - 1],
- (c > 1) ? cascade_data->split_end[c - 2] :
- cascade_data->split_start[0]);
-
- /* NDC Space */
- {
- float p[4] = {1.0f, 1.0f, cascade_data->split_start[c], 1.0f};
- /* TODO: we don't need full m4 multiply here */
- mul_m4_v4(vp_projmat, p);
- splits_start_ndc[c] = p[2];
-
- if (is_persp) {
- splits_start_ndc[c] /= p[3];
- }
- }
-
- {
- float p[4] = {1.0f, 1.0f, cascade_data->split_end[c - 1], 1.0f};
- /* TODO: we don't need full m4 multiply here */
- mul_m4_v4(vp_projmat, p);
- splits_end_ndc[c - 1] = p[2];
-
- if (is_persp) {
- splits_end_ndc[c - 1] /= p[3];
- }
- }
- }
-
- /* Set last cascade split fade distance into the first split_start. */
- float prev_split = (cascade_nbr > 1) ? cascade_data->split_end[cascade_nbr - 2] :
- cascade_data->split_start[0];
- cascade_data->split_start[0] = LERP(
- la->cascade_fade, cascade_data->split_end[cascade_nbr - 1], prev_split);
-
- /* For each cascade */
- for (int c = 0; c < cascade_nbr; ++c) {
- float(*projmat)[4] = sh_data->projmat[c];
- /* Given 8 frustum corners */
- float corners[8][3] = {
- /* Near Cap */
- {1.0f, -1.0f, splits_start_ndc[c]},
- {-1.0f, -1.0f, splits_start_ndc[c]},
- {-1.0f, 1.0f, splits_start_ndc[c]},
- {1.0f, 1.0f, splits_start_ndc[c]},
- /* Far Cap */
- {1.0f, -1.0f, splits_end_ndc[c]},
- {-1.0f, -1.0f, splits_end_ndc[c]},
- {-1.0f, 1.0f, splits_end_ndc[c]},
- {1.0f, 1.0f, splits_end_ndc[c]},
- };
-
- /* Transform them into world space */
- for (int i = 0; i < 8; ++i) {
- mul_project_m4_v3(persinv, corners[i]);
- }
-
- float center[3];
- frustum_min_bounding_sphere(corners, center, &(sh_data->radius[c]));
-
-#ifdef DEBUG_CSM
- float dbg_col[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- if (c < 3) {
- dbg_col[c] = 1.0f;
- }
- DRW_debug_bbox((BoundBox *)&corners, dbg_col);
- DRW_debug_sphere(center, sh_data->radius[c], dbg_col);
-#endif
-
- /* Project into lightspace */
- mul_m4_v3(viewmat, center);
-
- /* Snap projection center to nearest texel to cancel shimmering. */
- float shadow_origin[2], shadow_texco[2];
- /* Light to texture space. */
- mul_v2_v2fl(shadow_origin, center, linfo->shadow_cascade_size / (2.0f * sh_data->radius[c]));
-
- /* Find the nearest texel. */
- shadow_texco[0] = roundf(shadow_origin[0]);
- shadow_texco[1] = roundf(shadow_origin[1]);
-
- /* Compute offset. */
- sub_v2_v2(shadow_texco, shadow_origin);
- /* Texture to light space. */
- mul_v2_fl(shadow_texco, (2.0f * sh_data->radius[c]) / linfo->shadow_cascade_size);
-
- /* Apply offset. */
- add_v2_v2(center, shadow_texco);
-
- /* Expand the projection to cover frustum range */
- rctf rect_cascade;
- BLI_rctf_init_pt_radius(&rect_cascade, center, sh_data->radius[c]);
- orthographic_m4(projmat,
- rect_cascade.xmin,
- rect_cascade.xmax,
- rect_cascade.ymin,
- rect_cascade.ymax,
- la->clipsta,
- la->clipend);
-
- mul_m4_m4m4(sh_data->viewprojmat[c], projmat, viewmat);
- mul_m4_m4m4(cascade_data->shadowmat[c], texcomat, sh_data->viewprojmat[c]);
-
-#ifdef DEBUG_CSM
- DRW_debug_m4_as_bbox(sh_data->viewprojmat[c], dbg_col, true);
-#endif
- }
-
- ubo_data->bias = 0.05f * la->bias;
- ubo_data->near = la->clipsta;
- ubo_data->far = la->clipend;
- ubo_data->exp = (linfo->shadow_method == SHADOW_VSM) ? la->bleedbias : la->bleedexp;
-
- evli->shadowid = (float)(sh_data->shadow_id);
- ubo_data->shadow_start = (float)(sh_data->layer_id);
- ubo_data->data_start = (float)(sh_data->cascade_id);
- ubo_data->shadow_blur = la->soft * 0.02f; /* Used by translucence shadowmap blur */
-
- ubo_data->contact_dist = (la->mode & LA_SHAD_CONTACT) ? la->contact_dist : 0.0f;
- ubo_data->contact_bias = 0.05f * la->contact_bias;
- ubo_data->contact_spread = la->contact_spread;
- ubo_data->contact_thickness = la->contact_thickness;
+ evli->shadow_id = -1.0f;
}
-/* Used for checking if object is inside the shadow volume. */
-static bool sphere_bbox_intersect(const EEVEE_BoundSphere *bs, const EEVEE_BoundBox *bb)
+void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
- /* We are testing using a rougher AABB vs AABB test instead of full AABB vs Sphere. */
- /* TODO test speed with AABB vs Sphere. */
- bool x = fabsf(bb->center[0] - bs->center[0]) <= (bb->halfdim[0] + bs->radius);
- bool y = fabsf(bb->center[1] - bs->center[1]) <= (bb->halfdim[1] + bs->radius);
- bool z = fabsf(bb->center[2] - bs->center[2]) <= (bb->halfdim[2] + bs->radius);
+ EEVEE_LightsInfo *linfo = sldata->lights;
+ linfo->num_light = 0;
- return x && y && z;
+ EEVEE_shadows_cache_init(sldata, vedata);
}
-void EEVEE_lights_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
{
- EEVEE_StorageList *stl = vedata->stl;
- EEVEE_EffectsInfo *effects = stl->effects;
EEVEE_LightsInfo *linfo = sldata->lights;
- Object *ob;
- int i;
- char *flag;
- EEVEE_ShadowCaster *shcaster;
- EEVEE_BoundSphere *bsphere;
- EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
- EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
-
- EEVEE_LightBits update_bits = {{0}};
- if ((linfo->update_flag & LIGHT_UPDATE_SHADOW_CUBE) != 0) {
- /* Update all lights. */
- lightbits_set_all(&update_bits, true);
- }
- else {
- /* Search for deleted shadow casters and if shcaster WAS in shadow radius. */
- /* No need to run this if we already update all lights. */
- EEVEE_LightBits past_bits = {{0}};
- EEVEE_LightBits curr_bits = {{0}};
- shcaster = backbuffer->shadow_casters;
- flag = backbuffer->flags;
- for (i = 0; i < backbuffer->count; ++i, ++flag, ++shcaster) {
- /* If the shadowcaster has been deleted or updated. */
- if (*flag != 0) {
- /* Add the lights that were intersecting with its BBox. */
- lightbits_or(&past_bits, &shcaster->bits);
- }
- }
- /* Convert old bits to new bits and add result to final update bits. */
- /* NOTE: This might be overkill since all lights are tagged to refresh if
- * the light count changes. */
- lightbits_convert(&curr_bits, &past_bits, linfo->new_shadow_id, MAX_LIGHT);
- lightbits_or(&update_bits, &curr_bits);
- }
-
- /* Search for updates in current shadow casters. */
- shcaster = frontbuffer->shadow_casters;
- flag = frontbuffer->flags;
- for (i = 0; i < frontbuffer->count; i++, flag++, shcaster++) {
- /* Run intersection checks to fill the bitfields. */
- bsphere = linfo->shadow_bounds;
- for (int j = 0; j < linfo->cpu_cube_len; j++, bsphere++) {
- bool iter = sphere_bbox_intersect(bsphere, &shcaster->bbox);
- lightbits_set_single(&shcaster->bits, j, iter);
- }
- /* Only add to final bits if objects has been updated. */
- if (*flag != 0) {
- lightbits_or(&update_bits, &shcaster->bits);
- }
- }
+ const Light *la = (Light *)ob->data;
- /* Setup shadow cube in UBO and tag for update if necessary. */
- for (i = 0; (i < MAX_SHADOW_CUBE) && (ob = linfo->shadow_cube_ref[i]); i++) {
- EEVEE_LightEngineData *led = EEVEE_light_data_ensure(ob);
-
- eevee_shadow_cube_setup(ob, linfo, led, effects->taa_current_sample - 1);
- if (lightbits_get(&update_bits, i) != 0 || linfo->soft_shadows) {
- led->need_update = true;
- }
+ if (linfo->num_light >= MAX_LIGHT) {
+ printf("Too many lights in the scene !!!\n");
+ return;
}
- /* Resize shcasters buffers if too big. */
- if (frontbuffer->alloc_count - frontbuffer->count > SHADOW_CASTER_ALLOC_CHUNK) {
- frontbuffer->alloc_count = (frontbuffer->count / SHADOW_CASTER_ALLOC_CHUNK) *
- SHADOW_CASTER_ALLOC_CHUNK;
- frontbuffer->alloc_count += (frontbuffer->count % SHADOW_CASTER_ALLOC_CHUNK != 0) ?
- SHADOW_CASTER_ALLOC_CHUNK :
- 0;
- frontbuffer->shadow_casters = MEM_reallocN(
- frontbuffer->shadow_casters, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count);
- frontbuffer->flags = MEM_reallocN(frontbuffer->flags,
- sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count);
+ /* Early out if light has no power. */
+ if (la->energy == 0.0f || is_zero_v3(&la->r)) {
+ return;
}
-}
-
-static void eevee_ensure_cube_views(float near, float far, const float pos[3], DRWView *view[6])
-{
- float winmat[4][4], viewmat[4][4];
- perspective_m4(winmat, -near, near, -near, near, near, far);
- for (int i = 0; i < 6; i++) {
- unit_m4(viewmat);
- negate_v3_v3(viewmat[3], pos);
- mul_m4_m4m4(viewmat, cubefacemat[i], viewmat);
+ EEVEE_Light *evli = linfo->light_data + linfo->num_light;
+ eevee_light_setup(ob, evli);
- if (view[i] == NULL) {
- view[i] = DRW_view_create(viewmat, winmat, NULL, NULL, NULL);
+ if (la->mode & LA_SHADOW) {
+ if (la->type == LA_SUN) {
+ EEVEE_shadows_cascade_add(linfo, evli, ob);
}
- else {
- DRW_view_update(view[i], viewmat, winmat, NULL, NULL);
+ else if (ELEM(la->type, LA_SPOT, LA_LOCAL, LA_AREA)) {
+ EEVEE_shadows_cube_add(linfo, evli, ob);
}
}
-}
-static void eevee_ensure_cascade_views(EEVEE_ShadowCascadeData *cascade_data,
- int cascade_count,
- DRWView *view[4])
-{
- for (int i = 0; i < cascade_count; i++) {
- if (view[i] == NULL) {
- view[i] = DRW_view_create(cascade_data->viewmat, cascade_data->projmat[i], NULL, NULL, NULL);
- }
- else {
- DRW_view_update(view[i], cascade_data->viewmat, cascade_data->projmat[i], NULL, NULL);
- }
- }
+ linfo->num_light++;
}
-/* this refresh lights shadow buffers */
-void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWView *view)
+void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
- EEVEE_PassList *psl = vedata->psl;
- EEVEE_StorageList *stl = vedata->stl;
- EEVEE_EffectsInfo *effects = stl->effects;
- EEVEE_PrivateData *g_data = stl->g_data;
EEVEE_LightsInfo *linfo = sldata->lights;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const float light_threshold = draw_ctx->scene->eevee.light_threshold;
- Object *ob;
- int i;
-
- int saved_ray_type = sldata->common_data.ray_type;
-
- /* TODO: make it optional if we don't draw shadows. */
- sldata->common_data.ray_type = EEVEE_RAY_SHADOW;
- DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
-
- /* Precompute all shadow/view test before rendering and trashing the culling cache. */
- bool cube_visible[MAX_SHADOW_CUBE];
- for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
- Light *la = (Light *)ob->data;
- BoundSphere bsphere = {
- .center = {ob->obmat[3][0], ob->obmat[3][1], ob->obmat[3][2]},
- .radius = light_attenuation_radius_get(la, light_threshold),
- };
- cube_visible[i] = DRW_culling_sphere_test(view, &bsphere);
- }
-
- bool cascade_visible[MAX_SHADOW_CASCADE];
- for (i = 0; (ob = linfo->shadow_cascade_ref[i]) && (i < MAX_SHADOW_CASCADE); i++) {
- EEVEE_LightEngineData *led = EEVEE_light_data_get(ob);
- EEVEE_ShadowCascadeData *sh_data = &led->data.scad;
- float plane[4];
- normalize_m4_m4(sh_data->viewmat, ob->obmat);
- plane_from_point_normal_v3(plane, sh_data->viewmat[3], sh_data->viewmat[2]);
- /* TODO: check against near/far instead of "local Z = 0" plane.
- * Or even the cascades AABB. */
- cascade_visible[i] = DRW_culling_plane_test(view, plane);
- }
-
- /* Cube Shadow Maps */
- DRW_stats_group_start("Cube Shadow Maps");
- /* Render each shadow to one layer of the array */
- for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
- EEVEE_LightEngineData *led = EEVEE_light_data_ensure(ob);
- Light *la = (Light *)ob->data;
-
- if (!led->need_update || !cube_visible[i]) {
- continue;
- }
-
- EEVEE_ShadowRender *srd = &linfo->shadow_render_data;
- EEVEE_ShadowCubeData *evscd = &led->data.scd;
- EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + evscd->cube_id;
-
- srd->clip_near = la->clipsta;
- srd->clip_far = light_attenuation_radius_get(la, light_threshold);
- srd->stored_texel_size = 1.0 / (float)linfo->shadow_cube_store_size;
- srd->exponent = la->bleedexp;
-
- eevee_ensure_cube_views(
- srd->clip_near, srd->clip_far, cube_data->position, g_data->cube_views);
-
- /* Render shadow cube */
- /* Render 6 faces separately: seems to be faster for the general case.
- * The only time it's more beneficial is when the CPU culling overhead
- * outweigh the instancing overhead. which is rarely the case. */
- for (int j = 0; j < 6; j++) {
- DRW_view_set_active(g_data->cube_views[j]);
-
- GPU_framebuffer_texture_cubeface_attach(
- sldata->shadow_cube_target_fb, sldata->shadow_cube_target, 0, j, 0);
- GPU_framebuffer_bind(sldata->shadow_cube_target_fb);
- GPU_framebuffer_clear_depth(sldata->shadow_cube_target_fb, 1.0f);
- DRW_draw_pass(psl->shadow_pass);
- }
-
- /* 0.001f is arbitrary, but it should be relatively small so that filter size is not too big.
- */
- float filter_texture_size = la->soft * 0.001f;
- float filter_pixel_size = ceil(filter_texture_size / srd->cube_texel_size);
-
- /* TODO: OPTI: Don't do this intermediate step if no filter is needed. */
- {
- srd->filter_size[0] = srd->cube_texel_size * ((filter_pixel_size > 1.0f) ? 1.5f : 0.0f);
- srd->view_count = 6;
- srd->base_id = 0;
- DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd);
-
- /* Copy using a small 3x3 box filter */
- GPU_framebuffer_bind(sldata->shadow_cube_copy_fb);
- DRW_draw_pass(psl->shadow_cube_copy_pass);
- }
- /* Push it to shadowmap array */
- {
- /* Adjust constants if concentric samples change. */
- const float max_filter_size = 7.5f;
- const float magic = 4.5f; /* Dunno why but that works. */
- const int max_sample = 256;
-
- if (filter_pixel_size > 2.0f) {
- srd->filter_size[0] = srd->cube_texel_size * max_filter_size * magic;
- filter_pixel_size = max_ff(0.0f, filter_pixel_size - 3.0f);
- /* Compute number of concentric samples. Depends directly on filter size. */
- float pix_size_sqr = filter_pixel_size * filter_pixel_size;
- srd->shadow_samples_len[0] = min_ii(
- max_sample, 4 + 8 * (int)filter_pixel_size + 4 * (int)(pix_size_sqr));
- }
- else {
- srd->filter_size[0] = 0.0f;
- srd->shadow_samples_len[0] = 4;
- }
- srd->view_count = 1;
- srd->base_id = evscd->layer_id;
- srd->shadow_samples_len_inv[0] = 1.0f / (float)srd->shadow_samples_len[0];
- DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd);
-
- DRWPass *store_pass = eevee_lights_cube_store_pass_get(
- psl, sldata, linfo->shadow_method, srd->shadow_samples_len[0]);
-
- GPU_framebuffer_bind(sldata->shadow_cube_store_fb);
- DRW_draw_pass(store_pass);
- }
-
- if (linfo->soft_shadows == false) {
- led->need_update = false;
- }
- }
- linfo->update_flag &= ~LIGHT_UPDATE_SHADOW_CUBE;
- DRW_stats_group_end();
-
- float near = DRW_view_near_distance_get(view);
- float far = DRW_view_far_distance_get(view);
-
- /* Cascaded Shadow Maps */
- DRW_stats_group_start("Cascaded Shadow Maps");
- for (i = 0; (ob = linfo->shadow_cascade_ref[i]) && (i < MAX_SHADOW_CASCADE); i++) {
- if (!cascade_visible[i]) {
- continue;
- }
-
- EEVEE_LightEngineData *led = EEVEE_light_data_ensure(ob);
- Light *la = (Light *)ob->data;
-
- EEVEE_ShadowCascadeData *evscd = &led->data.scad;
- EEVEE_ShadowRender *srd = &linfo->shadow_render_data;
-
- srd->clip_near = la->clipsta;
- srd->clip_far = la->clipend;
- srd->view_count = la->cascade_count;
- srd->stored_texel_size = 1.0 / (float)linfo->shadow_cascade_size;
-
- DRW_uniformbuffer_update(sldata->shadow_render_ubo, &linfo->shadow_render_data);
-
- eevee_shadow_cascade_setup(ob, linfo, led, view, near, far, effects->taa_current_sample - 1);
-
- /* Meh, Reusing the cube views. */
- BLI_assert(MAX_CASCADE_NUM <= 6);
- eevee_ensure_cascade_views(evscd, la->cascade_count, g_data->cube_views);
-
- /* Render shadow cascades */
- /* Render cascade separately: seems to be faster for the general case.
- * The only time it's more beneficial is when the CPU culling overhead
- * outweigh the instancing overhead. which is rarely the case. */
- for (int j = 0; j < la->cascade_count; j++) {
- DRW_view_set_active(g_data->cube_views[j]);
-
- GPU_framebuffer_texture_layer_attach(
- sldata->shadow_cascade_target_fb, sldata->shadow_cascade_target, 0, j, 0);
- GPU_framebuffer_bind(sldata->shadow_cascade_target_fb);
- GPU_framebuffer_clear_depth(sldata->shadow_cascade_target_fb, 1.0f);
- DRW_draw_pass(psl->shadow_pass);
- }
- /* Copy using a small 3x3 box filter */
- {
- /* NOTE: We always do it in the case of CSM because of artifacts in the farthest cascade. */
- copy_v4_fl(srd->filter_size, srd->stored_texel_size);
- srd->base_id = 0;
- DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd);
-
- GPU_framebuffer_bind(sldata->shadow_cascade_copy_fb);
- DRW_draw_pass(psl->shadow_cascade_copy_pass);
- }
- /* Push it to shadowmap array and blur more */
- {
- int max_pass_sample = 0;
-
- for (int j = 0; j < la->cascade_count; j++) {
- /* 0.01f factor to convert to percentage */
- float filter_texture_size = la->soft * 0.01f / evscd->radius[j];
- float filter_pixel_size = ceil(linfo->shadow_cascade_size * filter_texture_size);
- /* Adjust constants if concentric samples change. */
- const float max_filter_size = 7.5f;
- const float magic = 3.2f; /* Arbitrary: less banding */
- const int max_sample = 256;
-
- if (filter_pixel_size > 2.0f) {
- srd->filter_size[j] = srd->stored_texel_size * max_filter_size * magic;
- filter_pixel_size = max_ff(0.0f, filter_pixel_size - 3.0f);
- /* Compute number of concentric samples. Depends directly on filter size. */
- float pix_size_sqr = filter_pixel_size * filter_pixel_size;
- srd->shadow_samples_len[j] = min_ii(
- max_sample, 4 + 8 * (int)filter_pixel_size + 4 * (int)(pix_size_sqr));
- }
- else {
- srd->filter_size[j] = 0.0f;
- srd->shadow_samples_len[j] = 4;
- }
- srd->shadow_samples_len_inv[j] = 1.0f / (float)srd->shadow_samples_len[j];
- max_pass_sample = max_ii(max_pass_sample, srd->shadow_samples_len[j]);
- }
- srd->base_id = evscd->layer_id;
- DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd);
-
- /* XXX(fclem) this create drawcalls outside of cache generation. */
- DRWPass *store_pass = eevee_lights_cascade_store_pass_get(
- psl, sldata, linfo->shadow_method, max_pass_sample);
-
- GPU_framebuffer_bind(sldata->shadow_cascade_store_fb);
- DRW_draw_pass(store_pass);
- }
- }
-
- DRW_stats_group_end();
-
- DRW_view_set_active(view);
+ sldata->common_data.la_num_light = linfo->num_light;
DRW_uniformbuffer_update(sldata->light_ubo, &linfo->light_data);
- DRW_uniformbuffer_update(sldata->shadow_ubo, &linfo->shadow_data); /* Update all data at once */
-
- sldata->common_data.ray_type = saved_ray_type;
- DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
-}
-void EEVEE_lights_free(void)
-{
- DRW_SHADER_FREE_SAFE(e_data.shadow_sh);
- for (int i = 0; i < SHADOW_METHOD_MAX; ++i) {
- DRW_SHADER_FREE_SAFE(e_data.shadow_store_cube_sh[i]);
- DRW_SHADER_FREE_SAFE(e_data.shadow_store_cube_high_sh[i]);
- DRW_SHADER_FREE_SAFE(e_data.shadow_store_cascade_sh[i]);
- DRW_SHADER_FREE_SAFE(e_data.shadow_store_cascade_high_sh[i]);
- DRW_SHADER_FREE_SAFE(e_data.shadow_copy_cube_sh[i]);
- DRW_SHADER_FREE_SAFE(e_data.shadow_copy_cascade_sh[i]);
- }
+ EEVEE_shadows_update(sldata, vedata);
}
diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c
index f52fcf31267..94d61a81fcc 100644
--- a/source/blender/draw/engines/eevee/eevee_lookdev.c
+++ b/source/blender/draw/engines/eevee/eevee_lookdev.c
@@ -151,6 +151,9 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata,
stl->g_data->studiolight_matrix, 'Z', v3d->shading.studiolight_rot_z);
DRW_shgroup_uniform_mat3(*grp, "StudioLightMatrix", stl->g_data->studiolight_matrix);
DRW_shgroup_uniform_float_copy(*grp, "backgroundAlpha", background_alpha);
+ DRW_shgroup_uniform_float(
+ *grp, "studioLightIntensity", &v3d->shading.studiolight_intensity, 1);
+
DRW_shgroup_uniform_vec3(*grp, "color", background_color, 1);
DRW_shgroup_call(*grp, geom, NULL);
if (!pinfo) {
@@ -170,12 +173,14 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata,
/* Do we need to recalc the lightprobes? */
if (g_data->studiolight_index != sl->index ||
g_data->studiolight_rot_z != v3d->shading.studiolight_rot_z ||
+ g_data->studiolight_intensity != v3d->shading.studiolight_intensity ||
g_data->studiolight_cubemap_res != scene->eevee.gi_cubemap_resolution ||
g_data->studiolight_glossy_clamp != scene->eevee.gi_glossy_clamp ||
g_data->studiolight_filter_quality != scene->eevee.gi_filter_quality) {
stl->lookdev_lightcache->flag |= LIGHTCACHE_UPDATE_WORLD;
g_data->studiolight_index = sl->index;
g_data->studiolight_rot_z = v3d->shading.studiolight_rot_z;
+ g_data->studiolight_intensity = v3d->shading.studiolight_intensity;
g_data->studiolight_cubemap_res = scene->eevee.gi_cubemap_resolution;
g_data->studiolight_glossy_clamp = scene->eevee.gi_glossy_clamp;
g_data->studiolight_filter_quality = scene->eevee.gi_filter_quality;
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 738745f3072..f01c6363ccb 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -48,6 +48,9 @@ static struct {
char *frag_shader_lib;
char *vert_shader_str;
char *vert_shadow_shader_str;
+ char *vert_background_shader_str;
+ char *vert_volume_shader_str;
+ char *geom_volume_shader_str;
char *volume_shader_lib;
struct GPUShader *default_prepass_sh;
@@ -63,8 +66,6 @@ static struct {
struct GPUTexture *util_tex;
struct GPUTexture *noise_tex;
- struct GPUUniformBuffer *dummy_sss_profile;
-
uint sss_count;
float alpha_hash_offset;
@@ -273,21 +274,6 @@ struct GPUTexture *EEVEE_materials_get_util_tex(void)
return e_data.util_tex;
}
-static int eevee_material_shadow_option(int shadow_method)
-{
- switch (shadow_method) {
- case SHADOW_ESM:
- return VAR_MAT_ESM;
- case SHADOW_VSM:
- return VAR_MAT_VSM;
- default:
- BLI_assert(!"Incorrect Shadow Method");
- break;
- }
-
- return 0;
-}
-
static char *eevee_get_defines(int options)
{
char *str = NULL;
@@ -322,23 +308,8 @@ static char *eevee_get_defines(int options)
if ((options & VAR_MAT_REFRACT) != 0) {
BLI_dynstr_append(ds, "#define USE_REFRACTION\n");
}
- if ((options & VAR_MAT_SSSALBED) != 0) {
- BLI_dynstr_append(ds, "#define USE_SSS_ALBEDO\n");
- }
- if ((options & VAR_MAT_TRANSLUC) != 0) {
- BLI_dynstr_append(ds, "#define USE_TRANSLUCENCY\n");
- }
- if ((options & VAR_MAT_VSM) != 0) {
- BLI_dynstr_append(ds, "#define SHADOW_VSM\n");
- }
- if ((options & VAR_MAT_ESM) != 0) {
- BLI_dynstr_append(ds, "#define SHADOW_ESM\n");
- }
if ((options & VAR_MAT_LOOKDEV) != 0) {
- /* Auto config shadow method. Avoid more permutation. */
- BLI_assert((options & (VAR_MAT_VSM | VAR_MAT_ESM)) == 0);
BLI_dynstr_append(ds, "#define LOOKDEV\n");
- BLI_dynstr_append(ds, "#define SHADOW_ESM\n");
}
str = BLI_dynstr_get_cstring(ds);
@@ -435,11 +406,6 @@ static void create_default_shader(int options)
MEM_freeN(frag_str);
}
-static void eevee_init_dummys(void)
-{
- e_data.dummy_sss_profile = GPU_material_create_sss_profile_ubo();
-}
-
static void eevee_init_noise_texture(void)
{
e_data.noise_tex = DRW_texture_create_2d(64, 64, GPU_RGBA16F, 0, (float *)blue_noise);
@@ -484,7 +450,7 @@ static void eevee_init_util_texture(void)
texels_layer += 64 * 64;
/* Copy Refraction GGX LUT in layer 5 - 21 */
- for (int j = 0; j < 16; ++j) {
+ for (int j = 0; j < 16; j++) {
for (int i = 0; i < 64 * 64; i++) {
texels_layer[i][0] = btdf_split_sum_ggx[j * 2][i];
texels_layer[i][1] = 0.0; /* UNUSED */
@@ -602,6 +568,15 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
e_data.vert_shadow_shader_str = BLI_string_joinN(
datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_shadow_vert_glsl);
+ e_data.vert_background_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_background_vert_glsl);
+
+ e_data.vert_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_volumetric_vert_glsl);
+
+ e_data.geom_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_volumetric_geom_glsl);
+
e_data.default_background = DRW_shader_create_with_lib(datatoc_background_vert_glsl,
NULL,
datatoc_default_world_frag_glsl,
@@ -631,7 +606,6 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
eevee_init_util_texture();
eevee_init_noise_texture();
- eevee_init_dummys();
}
if (!DRW_state_is_image_render() && ((stl->effects->enabled_effects & EFFECT_TAA) == 0)) {
@@ -675,7 +649,7 @@ struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, Wor
wo,
engine,
options,
- datatoc_background_vert_glsl,
+ e_data.vert_background_shader_str,
NULL,
e_data.frag_shader_lib,
SHADER_DEFINES "#define PROBE_CAPTURE\n",
@@ -695,7 +669,7 @@ struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, Wor
wo,
engine,
options,
- datatoc_background_vert_glsl,
+ e_data.vert_background_shader_str,
NULL,
e_data.frag_shader_lib,
SHADER_DEFINES "#define WORLD_BACKGROUND\n",
@@ -718,8 +692,8 @@ struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World *
wo,
engine,
options,
- datatoc_volumetric_vert_glsl,
- datatoc_volumetric_geom_glsl,
+ e_data.vert_volume_shader_str,
+ e_data.geom_volume_shader_str,
e_data.volume_shader_lib,
defines,
true);
@@ -731,22 +705,15 @@ struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World *
struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene,
Material *ma,
- EEVEE_Data *vedata,
+ EEVEE_Data *UNUSED(vedata),
bool use_blend,
- bool use_refract,
- bool use_translucency,
- int shadow_method)
+ bool use_refract)
{
- EEVEE_EffectsInfo *effects = vedata->stl->effects;
const void *engine = &DRW_engine_viewport_eevee_type;
int options = VAR_MAT_MESH;
SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND);
SET_FLAG_FROM_TEST(options, use_refract, VAR_MAT_REFRACT);
- SET_FLAG_FROM_TEST(options, effects->sss_separate_albedo, VAR_MAT_SSSALBED);
- SET_FLAG_FROM_TEST(options, use_translucency, VAR_MAT_TRANSLUC);
-
- options |= eevee_material_shadow_option(shadow_method);
GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true);
if (mat) {
@@ -786,8 +753,8 @@ struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material
ma,
engine,
options,
- datatoc_volumetric_vert_glsl,
- datatoc_volumetric_geom_glsl,
+ e_data.vert_volume_shader_str,
+ e_data.geom_volume_shader_str,
e_data.volume_shader_lib,
defines,
true);
@@ -835,13 +802,11 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene,
return mat;
}
-struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma, int shadow_method)
+struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma)
{
const void *engine = &DRW_engine_viewport_eevee_type;
int options = VAR_MAT_MESH | VAR_MAT_HAIR;
- options |= eevee_material_shadow_option(shadow_method);
-
GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true);
if (mat) {
return mat;
@@ -872,8 +837,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create(EEVEE_ViewLaye
DRWPass *pass,
bool is_hair,
bool use_blend,
- bool use_ssr,
- int shadow_method)
+ bool use_ssr)
{
static int ssr_id;
ssr_id = (use_ssr) ? 1 : -1;
@@ -882,8 +846,6 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create(EEVEE_ViewLaye
SET_FLAG_FROM_TEST(options, is_hair, VAR_MAT_HAIR);
SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND);
- options |= eevee_material_shadow_option(shadow_method);
-
if (e_data.default_lit[options] == NULL) {
create_default_shader(options);
}
@@ -903,8 +865,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get(EEVEE_ViewLayerDa
ParticleSystem *psys,
ModifierData *md,
bool is_hair,
- bool use_ssr,
- int shadow_method)
+ bool use_ssr)
{
static int ssr_id;
ssr_id = (use_ssr) ? 1 : -1;
@@ -916,8 +877,6 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get(EEVEE_ViewLayerDa
SET_FLAG_FROM_TEST(options, is_hair, VAR_MAT_HAIR);
- options |= eevee_material_shadow_option(shadow_method);
-
if (e_data.default_lit[options] == NULL) {
create_default_shader(options);
}
@@ -1164,7 +1123,6 @@ static void material_opaque(Material *ma,
Scene *scene = draw_ctx->scene;
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
- EEVEE_LightsInfo *linfo = sldata->lights;
bool use_diffuse, use_glossy, use_refract;
float *color_p = &ma->r;
@@ -1186,11 +1144,8 @@ static void material_opaque(Material *ma,
*shgrp_depth_clip = emsg->depth_clip_grp;
/* This will have been created already, just perform a lookup. */
- *gpumat =
- (use_gpumat) ?
- EEVEE_material_mesh_get(
- scene, ma, vedata, false, use_ssrefract, use_translucency, linfo->shadow_method) :
- NULL;
+ *gpumat = (use_gpumat) ? EEVEE_material_mesh_get(scene, ma, vedata, false, use_ssrefract) :
+ NULL;
*gpumat_depth = (use_gpumat) ? EEVEE_material_mesh_depth_get(
scene, ma, (ma->blend_method == MA_BM_HASHED), false) :
NULL;
@@ -1203,8 +1158,7 @@ static void material_opaque(Material *ma,
static float half = 0.5f;
/* Shading */
- *gpumat = EEVEE_material_mesh_get(
- scene, ma, vedata, false, use_ssrefract, use_translucency, linfo->shadow_method);
+ *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, false, use_ssrefract);
eGPUMaterialStatus status_mat_surface = GPU_material_status(*gpumat);
@@ -1311,15 +1265,15 @@ static void material_opaque(Material *ma,
*gpumat, stl->effects->sss_sample_count, &sss_tex_profile);
if (sss_profile) {
- if (use_translucency) {
- DRW_shgroup_uniform_block(*shgrp, "sssProfile", sss_profile);
- DRW_shgroup_uniform_texture(*shgrp, "sssTexProfile", sss_tex_profile);
- }
-
/* Limit of 8 bit stencil buffer. ID 255 is refraction. */
if (e_data.sss_count < 254) {
- DRW_shgroup_stencil_mask(*shgrp, e_data.sss_count + 1);
- EEVEE_subsurface_add_pass(sldata, vedata, e_data.sss_count + 1, sss_profile);
+ int sss_id = e_data.sss_count + 1;
+ DRW_shgroup_stencil_mask(*shgrp, sss_id);
+ EEVEE_subsurface_add_pass(sldata, vedata, sss_id, sss_profile);
+ if (use_translucency) {
+ EEVEE_subsurface_translucency_add_pass(
+ sldata, vedata, sss_id, sss_profile, sss_tex_profile);
+ }
e_data.sss_count++;
}
else {
@@ -1327,19 +1281,6 @@ static void material_opaque(Material *ma,
printf("Error: Too many different Subsurface shader in the scene.\n");
}
}
- else {
- if (use_translucency) {
- /* NOTE: This is a nasty workaround, because the sss profile might not have been
- * generated but the UBO is still declared in this case even if not used.
- * But rendering without a bound UBO might result in crashes on certain platform. */
- DRW_shgroup_uniform_block(*shgrp, "sssProfile", e_data.dummy_sss_profile);
- }
- }
- }
- else {
- if (use_translucency) {
- DRW_shgroup_uniform_block(*shgrp, "sssProfile", e_data.dummy_sss_profile);
- }
}
break;
}
@@ -1360,8 +1301,7 @@ static void material_opaque(Material *ma,
/* Fallback to default shader */
if (*shgrp == NULL) {
bool use_ssr = ((effects->enabled_effects & EFFECT_SSR) != 0);
- *shgrp = EEVEE_default_shading_group_get(
- sldata, vedata, NULL, NULL, NULL, false, use_ssr, linfo->shadow_method);
+ *shgrp = EEVEE_default_shading_group_get(sldata, vedata, NULL, NULL, NULL, false, use_ssr);
DRW_shgroup_uniform_vec3(*shgrp, "basecol", color_p, 1);
DRW_shgroup_uniform_float(*shgrp, "metallic", metal_p, 1);
DRW_shgroup_uniform_float(*shgrp, "specular", spec_p, 1);
@@ -1401,7 +1341,6 @@ static void material_transparent(Material *ma,
Scene *scene = draw_ctx->scene;
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
- EEVEE_LightsInfo *linfo = sldata->lights;
const bool do_cull = (ma->blend_flag & MA_BL_CULL_BACKFACE) != 0;
const bool use_ssrefract = (((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) &&
@@ -1411,14 +1350,31 @@ static void material_transparent(Material *ma,
const float *spec_p = &ma->spec;
const float *rough_p = &ma->roughness;
+ const bool use_prepass = ((ma->blend_flag & MA_BL_HIDE_BACKFACE) != 0);
+
+ DRWState cur_state;
+ DRWState all_state = (DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_CULL_BACK |
+ DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_DEPTH_EQUAL |
+ DRW_STATE_BLEND_CUSTOM);
+
+ /* Depth prepass */
+ if (use_prepass) {
+ *shgrp_depth = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->transparent_pass);
+
+ cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0;
+
+ DRW_shgroup_state_disable(*shgrp_depth, all_state);
+ DRW_shgroup_state_enable(*shgrp_depth, cur_state);
+ }
+
if (ma->use_nodes && ma->nodetree) {
static float error_col[3] = {1.0f, 0.0f, 1.0f};
static float compile_col[3] = {0.5f, 0.5f, 0.5f};
static float half = 0.5f;
/* Shading */
- *gpumat = EEVEE_material_mesh_get(
- scene, ma, vedata, true, use_ssrefract, false, linfo->shadow_method);
+ *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, true, use_ssrefract);
switch (GPU_material_status(*gpumat)) {
case GPU_MAT_SUCCESS: {
@@ -1461,37 +1417,20 @@ static void material_transparent(Material *ma,
/* Fallback to default shader */
if (*shgrp == NULL) {
*shgrp = EEVEE_default_shading_group_create(
- sldata, vedata, psl->transparent_pass, false, true, false, linfo->shadow_method);
+ sldata, vedata, psl->transparent_pass, false, true, false);
DRW_shgroup_uniform_vec3(*shgrp, "basecol", color_p, 1);
DRW_shgroup_uniform_float(*shgrp, "metallic", metal_p, 1);
DRW_shgroup_uniform_float(*shgrp, "specular", spec_p, 1);
DRW_shgroup_uniform_float(*shgrp, "roughness", rough_p, 1);
}
- const bool use_prepass = ((ma->blend_flag & MA_BL_HIDE_BACKFACE) != 0);
-
- DRWState all_state = (DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_CULL_BACK |
- DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_DEPTH_EQUAL |
- DRW_STATE_BLEND_CUSTOM);
-
- DRWState cur_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM;
+ cur_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM;
cur_state |= (use_prepass) ? DRW_STATE_DEPTH_EQUAL : DRW_STATE_DEPTH_LESS_EQUAL;
cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0;
/* Disable other blend modes and use the one we want. */
DRW_shgroup_state_disable(*shgrp, all_state);
DRW_shgroup_state_enable(*shgrp, cur_state);
-
- /* Depth prepass */
- if (use_prepass) {
- *shgrp_depth = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->transparent_pass);
-
- cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0;
-
- DRW_shgroup_state_disable(*shgrp_depth, all_state);
- DRW_shgroup_state_enable(*shgrp_depth, cur_state);
- }
}
/* Return correct material or &defmaterial if slot is empty. */
@@ -1515,7 +1454,8 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
Scene *scene = draw_ctx->scene;
GHash *material_hash = stl->g_data->material_hash;
- bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+ bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
/* First get materials for this mesh. */
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
@@ -1531,7 +1471,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
struct GPUMaterial **gpumat_depth_array = BLI_array_alloca(gpumat_array, materials_len);
struct Material **ma_array = BLI_array_alloca(ma_array, materials_len);
- for (int i = 0; i < materials_len; ++i) {
+ for (int i = 0; i < materials_len; i++) {
ma_array[i] = eevee_object_material_get(ob, i);
gpumat_array[i] = NULL;
gpumat_depth_array[i] = NULL;
@@ -1599,7 +1539,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
/* TODO(fclem): Support shadows in sculpt mode. */
}
else if (mat_geom) {
- for (int i = 0; i < materials_len; ++i) {
+ for (int i = 0; i < materials_len; i++) {
if (mat_geom[i] == NULL) {
continue;
}
@@ -1625,7 +1565,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
ADD_SHGROUP_CALL_SAFE(shgrp_depth_clip_array[i], ob, mat_geom[i], oedata);
char *name = auto_layer_names;
- for (int j = 0; j < auto_layer_count; ++j) {
+ for (int j = 0; j < auto_layer_count; j++) {
/* TODO don't add these uniform when not needed (default pass shaders). */
/* FIXME: This is broken, as it overrides any autolayers srgb bool of the previous mesh
* that shares the same material. */
@@ -1650,18 +1590,18 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
struct GPUMaterial *gpumat;
switch (ma_array[i]->blend_shadow) {
case MA_BS_SOLID:
- EEVEE_lights_cache_shcaster_add(sldata, stl, mat_geom[i], ob);
+ EEVEE_shadows_caster_add(sldata, stl, mat_geom[i], ob);
*cast_shadow = true;
break;
case MA_BS_CLIP:
gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], false, true);
- EEVEE_lights_cache_shcaster_material_add(
+ EEVEE_shadows_caster_material_add(
sldata, psl, gpumat, mat_geom[i], ob, &ma_array[i]->alpha_threshold);
*cast_shadow = true;
break;
case MA_BS_HASHED:
gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], true, true);
- EEVEE_lights_cache_shcaster_material_add(sldata, psl, gpumat, mat_geom[i], ob, NULL);
+ EEVEE_shadows_caster_material_add(sldata, psl, gpumat, mat_geom[i], ob, NULL);
*cast_shadow = true;
break;
case MA_BS_NONE:
@@ -1728,8 +1668,7 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata,
static float half = 0.5f;
static float error_col[3] = {1.0f, 0.0f, 1.0f};
static float compile_col[3] = {0.5f, 0.5f, 0.5f};
- struct GPUMaterial *gpumat = EEVEE_material_hair_get(
- scene, ma, sldata->lights->shadow_method);
+ struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma);
switch (GPU_material_status(gpumat)) {
case GPU_MAT_SUCCESS: {
@@ -1774,8 +1713,7 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata,
/* Fallback to default shader */
if (shgrp == NULL) {
- shgrp = EEVEE_default_shading_group_get(
- sldata, vedata, ob, psys, md, true, use_ssr, sldata->lights->shadow_method);
+ shgrp = EEVEE_default_shading_group_get(sldata, vedata, ob, psys, md, true, use_ssr);
DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1);
DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1);
DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1);
@@ -1804,12 +1742,15 @@ void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
void EEVEE_materials_free(void)
{
- for (int i = 0; i < VAR_MAT_MAX; ++i) {
+ for (int i = 0; i < VAR_MAT_MAX; i++) {
DRW_SHADER_FREE_SAFE(e_data.default_lit[i]);
}
MEM_SAFE_FREE(e_data.frag_shader_lib);
MEM_SAFE_FREE(e_data.vert_shader_str);
MEM_SAFE_FREE(e_data.vert_shadow_shader_str);
+ MEM_SAFE_FREE(e_data.vert_background_shader_str);
+ MEM_SAFE_FREE(e_data.vert_volume_shader_str);
+ MEM_SAFE_FREE(e_data.geom_volume_shader_str);
MEM_SAFE_FREE(e_data.volume_shader_lib);
DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_sh);
DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_clip_sh);
@@ -1819,14 +1760,16 @@ void EEVEE_materials_free(void)
DRW_SHADER_FREE_SAFE(e_data.update_noise_sh);
DRW_TEXTURE_FREE_SAFE(e_data.util_tex);
DRW_TEXTURE_FREE_SAFE(e_data.noise_tex);
- DRW_UBO_FREE_SAFE(e_data.dummy_sss_profile);
}
-void EEVEE_draw_default_passes(EEVEE_PassList *psl)
+void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_PassList *psl)
{
- for (int i = 0; i < VAR_MAT_MAX; ++i) {
+ for (int i = 0; i < VAR_MAT_MAX; i++) {
if (psl->default_pass[i]) {
DRW_draw_pass(psl->default_pass[i]);
}
}
+
+ DRW_draw_pass(psl->material_pass);
+ DRW_draw_pass(psl->material_pass_cull);
}
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 3cdafee95a2..f4f40d40de6 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -23,9 +23,12 @@
#ifndef __EEVEE_PRIVATE_H__
#define __EEVEE_PRIVATE_H__
+#include "DRW_render.h"
+
+#include "BLI_bitmap.h"
+
#include "DNA_lightprobe_types.h"
-struct EEVEE_BoundSphere;
struct EEVEE_ShadowCasterBuffer;
struct GPUFrameBuffer;
struct Object;
@@ -39,11 +42,13 @@ extern struct DrawEngineType draw_engine_eevee_type;
#define MAX_PLANAR 16 /* TODO : find size by dividing UBO max size by grid data size */
#define MAX_LIGHT 128 /* TODO : find size by dividing UBO max size by light data size */
#define MAX_CASCADE_NUM 4
-#define MAX_SHADOW 256 /* TODO : Make this depends on GL_MAX_ARRAY_TEXTURE_LAYERS */
+#define MAX_SHADOW 128 /* TODO : Make this depends on GL_MAX_ARRAY_TEXTURE_LAYERS */
#define MAX_SHADOW_CASCADE 8
#define MAX_SHADOW_CUBE (MAX_SHADOW - MAX_CASCADE_NUM * MAX_SHADOW_CASCADE)
#define MAX_BLOOM_STEP 16
+// #define DEBUG_SHADOW_DISTRIBUTION
+
/* Only define one of these. */
// #define IRRADIANCE_SH_L2
// #define IRRADIANCE_CUBEMAP
@@ -118,16 +123,19 @@ extern struct DrawEngineType draw_engine_eevee_type;
} \
((void)0)
-#define OVERLAY_ENABLED(v3d) ((v3d) && (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0)
-#define LOOK_DEV_MODE_ENABLED(v3d) ((v3d) && (v3d->shading.type == OB_MATERIAL))
+#define MATERIAL_PREVIEW_MODE_ENABLED(v3d) ((v3d) && (v3d->shading.type == OB_MATERIAL))
#define LOOK_DEV_OVERLAY_ENABLED(v3d) \
- (LOOK_DEV_MODE_ENABLED(v3d) && OVERLAY_ENABLED(v3d) && \
+ ((v3d) && (v3d->shading.type == OB_MATERIAL) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && \
(v3d->overlay.flag & V3D_OVERLAY_LOOK_DEV))
#define USE_SCENE_LIGHT(v3d) \
- ((!v3d) || (!LOOK_DEV_MODE_ENABLED(v3d)) || \
- ((LOOK_DEV_MODE_ENABLED(v3d) && (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS))))
+ ((!v3d) || \
+ ((v3d->shading.type == OB_MATERIAL) && (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS)) || \
+ ((v3d->shading.type == OB_RENDER) && (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS_RENDER)))
#define LOOK_DEV_STUDIO_LIGHT_ENABLED(v3d) \
- (LOOK_DEV_MODE_ENABLED(v3d) && !(v3d->shading.flag & V3D_SHADING_SCENE_WORLD))
+ ((v3d) && (((v3d->shading.type == OB_MATERIAL) && \
+ ((v3d->shading.flag & V3D_SHADING_SCENE_WORLD) == 0)) || \
+ ((v3d->shading.type == OB_RENDER) && \
+ ((v3d->shading.flag & V3D_SHADING_SCENE_WORLD_RENDER) == 0))))
#define OCTAHEDRAL_SIZE_FROM_CUBESIZE(cube_size) \
((int)ceilf(sqrtf((cube_size * cube_size) * 6.0f)))
@@ -147,14 +155,12 @@ enum {
VAR_MAT_PROBE = (1 << 1),
VAR_MAT_HAIR = (1 << 2),
VAR_MAT_BLEND = (1 << 3),
- VAR_MAT_VSM = (1 << 4),
- VAR_MAT_ESM = (1 << 5),
- VAR_MAT_VOLUME = (1 << 6),
- VAR_MAT_LOOKDEV = (1 << 7),
+ VAR_MAT_VOLUME = (1 << 4),
+ VAR_MAT_LOOKDEV = (1 << 5),
/* Max number of variation */
/* IMPORTANT : Leave it last and set
* it's value accordingly. */
- VAR_MAT_MAX = (1 << 8),
+ VAR_MAT_MAX = (1 << 6),
/* These are options that are not counted in VAR_MAT_MAX
* because they are not cumulative with the others above. */
VAR_MAT_CLIP = (1 << 9),
@@ -162,8 +168,6 @@ enum {
VAR_MAT_MULT = (1 << 11),
VAR_MAT_SHADOW = (1 << 12),
VAR_MAT_REFRACT = (1 << 13),
- VAR_MAT_TRANSLUC = (1 << 15),
- VAR_MAT_SSSALBED = (1 << 16),
};
/* ************ PROBE UBO ************* */
@@ -187,10 +191,6 @@ typedef struct EEVEE_PlanarReflection {
/* --------------------------------------- */
-typedef struct EEVEE_BoundSphere {
- float center[3], radius;
-} EEVEE_BoundSphere;
-
typedef struct EEVEE_BoundBox {
float center[3], halfdim[3];
} EEVEE_BoundBox;
@@ -198,12 +198,6 @@ typedef struct EEVEE_BoundBox {
typedef struct EEVEE_PassList {
/* Shadows */
struct DRWPass *shadow_pass;
- struct DRWPass *shadow_cube_copy_pass;
- struct DRWPass *shadow_cube_store_pass;
- struct DRWPass *shadow_cube_store_high_pass;
- struct DRWPass *shadow_cascade_copy_pass;
- struct DRWPass *shadow_cascade_store_pass;
- struct DRWPass *shadow_cascade_store_high_pass;
/* Probes */
struct DRWPass *probe_background;
@@ -239,6 +233,7 @@ typedef struct EEVEE_PassList {
struct DRWPass *sss_blur_ps;
struct DRWPass *sss_resolve_ps;
struct DRWPass *sss_accum_ps;
+ struct DRWPass *sss_translucency_ps;
struct DRWPass *color_downsample_ps;
struct DRWPass *color_downsample_cube_ps;
struct DRWPass *velocity_resolve;
@@ -289,6 +284,7 @@ typedef struct EEVEE_FramebufferList {
struct GPUFrameBuffer *sss_blit_fb;
struct GPUFrameBuffer *sss_resolve_fb;
struct GPUFrameBuffer *sss_clear_fb;
+ struct GPUFrameBuffer *sss_translucency_fb;
struct GPUFrameBuffer *sss_accum_fb;
struct GPUFrameBuffer *dof_down_fb;
struct GPUFrameBuffer *dof_scatter_fb;
@@ -365,7 +361,7 @@ typedef struct EEVEE_StorageList {
typedef struct EEVEE_Light {
float position[3], invsqrdist;
float color[3], spec;
- float spotsize, spotblend, radius, shadowid;
+ float spotsize, spotblend, radius, shadow_id;
float rightvec[3], sizex;
float upvec[3], sizey;
float forwardvec[3], light_type;
@@ -375,13 +371,13 @@ typedef struct EEVEE_Light {
#define LAMPTYPE_AREA_ELLIPSE 100.0f
typedef struct EEVEE_Shadow {
- float near, far, bias, exp;
- float shadow_start, data_start, multi_shadow_count, shadow_blur;
+ float near, far, bias, type_data_id;
float contact_dist, contact_bias, contact_spread, contact_thickness;
} EEVEE_Shadow;
typedef struct EEVEE_ShadowCube {
- float position[3], pad;
+ float shadowmat[4][4];
+ float position[3], _pad0[1];
} EEVEE_ShadowCube;
typedef struct EEVEE_ShadowCascade {
@@ -389,42 +385,34 @@ typedef struct EEVEE_ShadowCascade {
float shadowmat[MAX_CASCADE_NUM][4][4];
float split_start[4];
float split_end[4];
+ float shadow_vec[3], tex_id;
} EEVEE_ShadowCascade;
-typedef struct EEVEE_ShadowRender {
- int shadow_samples_len[MAX_CASCADE_NUM];
- float shadow_samples_len_inv[MAX_CASCADE_NUM];
- float filter_size[MAX_CASCADE_NUM];
- int view_count;
- int base_id;
- float cube_texel_size;
- float stored_texel_size;
- float clip_near;
- float clip_far;
- float exponent;
- float pad;
-} EEVEE_ShadowRender;
+typedef struct EEVEE_ShadowCascadeRender {
+ /* World->Light->NDC : used for rendering the shadow map. */
+ float projmat[MAX_CASCADE_NUM][4][4];
+ float viewmat[4][4], viewinv[4][4];
+ float radius[MAX_CASCADE_NUM];
+ float cascade_max_dist;
+ float cascade_exponent;
+ float cascade_fade;
+ int cascade_count;
+} EEVEE_ShadowCascadeRender;
BLI_STATIC_ASSERT_ALIGN(EEVEE_Light, 16)
BLI_STATIC_ASSERT_ALIGN(EEVEE_Shadow, 16)
BLI_STATIC_ASSERT_ALIGN(EEVEE_ShadowCube, 16)
BLI_STATIC_ASSERT_ALIGN(EEVEE_ShadowCascade, 16)
-BLI_STATIC_ASSERT_ALIGN(EEVEE_ShadowRender, 16)
-
-/* This is just a really long bitflag with special function to access it. */
-#define MAX_LIGHTBITS_FIELDS (MAX_LIGHT / 8)
-typedef struct EEVEE_LightBits {
- uchar fields[MAX_LIGHTBITS_FIELDS];
-} EEVEE_LightBits;
-typedef struct EEVEE_ShadowCaster {
- struct EEVEE_LightBits bits;
- struct EEVEE_BoundBox bbox;
-} EEVEE_ShadowCaster;
+BLI_STATIC_ASSERT(sizeof(EEVEE_Shadow) * MAX_SHADOW +
+ sizeof(EEVEE_ShadowCascade) * MAX_SHADOW_CASCADE +
+ sizeof(EEVEE_ShadowCube) * MAX_SHADOW_CUBE <
+ 16384,
+ "Shadow UBO is too big!!!")
typedef struct EEVEE_ShadowCasterBuffer {
- struct EEVEE_ShadowCaster *shadow_casters;
- char *flags;
+ struct EEVEE_BoundBox *bbox;
+ BLI_bitmap *update;
uint alloc_count;
uint count;
} EEVEE_ShadowCasterBuffer;
@@ -434,42 +422,31 @@ typedef struct EEVEE_LightsInfo {
int num_light, cache_num_light;
int num_cube_layer, cache_num_cube_layer;
int num_cascade_layer, cache_num_cascade_layer;
- int gpu_cube_len, gpu_cascade_len, gpu_shadow_len;
- int cpu_cube_len, cpu_cascade_len;
- int update_flag;
- int shadow_cube_size, shadow_cascade_size, shadow_method;
+ int cube_len, cascade_len, shadow_len;
+ int shadow_cube_size, shadow_cascade_size;
bool shadow_high_bitdepth, soft_shadows;
- int shadow_cube_store_size;
- /* List of lights in the scene. */
- /* XXX This is fragile, can get out of sync quickly. */
- struct Object *light_ref[MAX_LIGHT];
- struct Object *shadow_cube_ref[MAX_SHADOW_CUBE];
- struct Object *shadow_cascade_ref[MAX_SHADOW_CASCADE];
/* UBO Storage : data used by UBO */
struct EEVEE_Light light_data[MAX_LIGHT];
- struct EEVEE_ShadowRender shadow_render_data;
struct EEVEE_Shadow shadow_data[MAX_SHADOW];
struct EEVEE_ShadowCube shadow_cube_data[MAX_SHADOW_CUBE];
struct EEVEE_ShadowCascade shadow_cascade_data[MAX_SHADOW_CASCADE];
+ /* Additionnal rendering info for cascade. */
+ struct EEVEE_ShadowCascadeRender shadow_cascade_render[MAX_SHADOW_CASCADE];
+ /* Back index in light_data. */
+ uchar shadow_cube_light_indices[MAX_SHADOW_CUBE];
+ uchar shadow_cascade_light_indices[MAX_SHADOW_CASCADE];
+ /* Update bitmap. */
+ BLI_bitmap sh_cube_update[BLI_BITMAP_SIZE(MAX_SHADOW_CUBE)];
/* Lights tracking */
- int new_shadow_id[MAX_LIGHT]; /* To be able to convert old bitfield to new bitfield */
- struct EEVEE_BoundSphere shadow_bounds[MAX_LIGHT]; /* Tightly packed light bounds */
- /* Pointers only. */
- struct EEVEE_ShadowCasterBuffer *shcaster_frontbuffer;
- struct EEVEE_ShadowCasterBuffer *shcaster_backbuffer;
+ struct BoundSphere shadow_bounds[MAX_LIGHT]; /* Tightly packed light bounds */
+ /* List of bbox and update bitmap. Double buffered. */
+ struct EEVEE_ShadowCasterBuffer *shcaster_frontbuffer, *shcaster_backbuffer;
+ /* AABB of all shadow casters combined. */
+ struct {
+ float min[3], max[3];
+ } shcaster_aabb;
} EEVEE_LightsInfo;
-/* EEVEE_LightsInfo->shadow_casters_flag */
-enum {
- SHADOW_CASTER_PRUNED = (1 << 0),
- SHADOW_CASTER_UPDATED = (1 << 1),
-};
-
-/* EEVEE_LightsInfo->update_flag */
-enum {
- LIGHT_UPDATE_SHADOW_CUBE = (1 << 0),
-};
-
/* ************ PROBE DATA ************* */
typedef struct EEVEE_LightProbeVisTest {
struct Collection *collection; /* Skip test if NULL */
@@ -549,8 +526,8 @@ typedef struct EEVEE_EffectsInfo {
bool swap_double_buffer;
/* SSSS */
int sss_sample_count;
- bool sss_separate_albedo;
- struct GPUTexture *sss_data; /* Textures from pool */
+ struct GPUTexture *sss_irradiance; /* Textures from pool */
+ struct GPUTexture *sss_radius;
struct GPUTexture *sss_albedo;
struct GPUTexture *sss_blur;
struct GPUTexture *sss_stencil;
@@ -708,20 +685,10 @@ typedef struct EEVEE_ViewLayerData {
struct GPUUniformBuffer *light_ubo;
struct GPUUniformBuffer *shadow_ubo;
- struct GPUUniformBuffer *shadow_render_ubo;
struct GPUUniformBuffer *shadow_samples_ubo;
- struct GPUFrameBuffer *shadow_cube_target_fb;
- struct GPUFrameBuffer *shadow_cube_store_fb;
- struct GPUFrameBuffer *shadow_cube_copy_fb;
- struct GPUFrameBuffer *shadow_cascade_target_fb;
- struct GPUFrameBuffer *shadow_cascade_store_fb;
- struct GPUFrameBuffer *shadow_cascade_copy_fb;
-
- struct GPUTexture *shadow_cube_target;
- struct GPUTexture *shadow_cube_blur;
- struct GPUTexture *shadow_cascade_target;
- struct GPUTexture *shadow_cascade_blur;
+ struct GPUFrameBuffer *shadow_fb;
+
struct GPUTexture *shadow_cube_pool;
struct GPUTexture *shadow_cascade_pool;
@@ -743,23 +710,6 @@ typedef struct EEVEE_ViewLayerData {
/* ************ OBJECT DATA ************ */
-typedef struct EEVEE_LightData {
- short light_id, shadow_id;
-} EEVEE_LightData;
-
-typedef struct EEVEE_ShadowCubeData {
- short light_id, shadow_id, cube_id, layer_id;
-} EEVEE_ShadowCubeData;
-
-typedef struct EEVEE_ShadowCascadeData {
- short light_id, shadow_id, cascade_id, layer_id;
- /* World->Light->NDC : used for rendering the shadow map. */
- float viewprojmat[MAX_CASCADE_NUM][4][4]; /* Could be removed. */
- float projmat[MAX_CASCADE_NUM][4][4];
- float viewmat[4][4], viewinv[4][4];
- float radius[MAX_CASCADE_NUM];
-} EEVEE_ShadowCascadeData;
-
/* These are the structs stored inside Objects.
* It works even if the object is in multiple layers
* because we don't get the same "Object *" for each layer. */
@@ -767,13 +717,6 @@ typedef struct EEVEE_LightEngineData {
DrawData dd;
bool need_update;
- /* This needs to be out of the union to avoid undefined behavior. */
- short prev_cube_shadow_id;
- union {
- struct EEVEE_LightData ld;
- struct EEVEE_ShadowCubeData scd;
- struct EEVEE_ShadowCascadeData scad;
- } data;
} EEVEE_LightEngineData;
typedef struct EEVEE_LightProbeEngineData {
@@ -846,6 +789,7 @@ typedef struct EEVEE_PrivateData {
/* LookDev Settings */
int studiolight_index;
float studiolight_rot_z;
+ float studiolight_intensity;
int studiolight_cubemap_res;
float studiolight_glossy_clamp;
float studiolight_filter_quality;
@@ -892,43 +836,67 @@ void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, struct World *wo);
struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, struct World *wo);
struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, struct World *wo);
-struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene,
- Material *ma,
- EEVEE_Data *vedata,
- bool use_blend,
- bool use_refract,
- bool use_translucency,
- int shadow_method);
+struct GPUMaterial *EEVEE_material_mesh_get(
+ struct Scene *scene, Material *ma, EEVEE_Data *vedata, bool use_blend, bool use_refract);
struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material *ma);
struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene,
Material *ma,
bool use_hashed_alpha,
bool is_shadow);
-struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma, int shadow_method);
+struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma);
void EEVEE_materials_free(void);
-void EEVEE_draw_default_passes(EEVEE_PassList *psl);
+void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl);
void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const double offsets[3]);
void EEVEE_update_viewvecs(float invproj[4][4], float winmat[4][4], float (*r_viewvecs)[4]);
/* eevee_lights.c */
-void EEVEE_lights_init(EEVEE_ViewLayerData *sldata);
+void eevee_light_matrix_get(const EEVEE_Light *evli, float r_mat[4][4]);
void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, struct Object *ob);
-void EEVEE_lights_cache_shcaster_add(EEVEE_ViewLayerData *sldata,
- EEVEE_StorageList *stl,
- struct GPUBatch *geom,
- Object *ob);
-void EEVEE_lights_cache_shcaster_material_add(EEVEE_ViewLayerData *sldata,
- EEVEE_PassList *psl,
- struct GPUMaterial *gpumat,
- struct GPUBatch *geom,
- struct Object *ob,
- const float *alpha_threshold);
-void EEVEE_lights_cache_shcaster_object_add(EEVEE_ViewLayerData *sldata, struct Object *ob);
void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
-void EEVEE_lights_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
-void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct DRWView *view);
-void EEVEE_lights_free(void);
+
+/* eevee_shadows.c */
+void eevee_contact_shadow_setup(const Light *la, EEVEE_Shadow *evsh);
+void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata);
+void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_shadows_caster_add(EEVEE_ViewLayerData *sldata,
+ EEVEE_StorageList *stl,
+ struct GPUBatch *geom,
+ Object *ob);
+void EEVEE_shadows_caster_material_add(EEVEE_ViewLayerData *sldata,
+ EEVEE_PassList *psl,
+ struct GPUMaterial *gpumat,
+ struct GPUBatch *geom,
+ struct Object *ob,
+ const float *alpha_threshold);
+void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, struct Object *ob);
+void EEVEE_shadows_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_shadows_cube_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, struct Object *ob);
+bool EEVEE_shadows_cube_setup(EEVEE_LightsInfo *linfo, const EEVEE_Light *evli, int sample_ofs);
+void EEVEE_shadows_cascade_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, struct Object *ob);
+void EEVEE_shadows_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct DRWView *view);
+void EEVEE_shadows_draw_cubemap(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, int cube_index);
+void EEVEE_shadows_draw_cascades(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ DRWView *view,
+ int cascade_index);
+void EEVEE_shadows_free(void);
+
+/* eevee_sampling.c */
+void EEVEE_sample_ball(int sample_ofs, float radius, float rsample[3]);
+void EEVEE_sample_rectangle(int sample_ofs,
+ const float x_axis[3],
+ const float y_axis[3],
+ float size_x,
+ float size_y,
+ float rsample[3]);
+void EEVEE_sample_ellipse(int sample_ofs,
+ const float x_axis[3],
+ const float y_axis[3],
+ float size_x,
+ float size_y,
+ float rsample[3]);
+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);
@@ -1041,6 +1009,11 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
uint sss_id,
struct GPUUniformBuffer *sss_profile);
+void EEVEE_subsurface_translucency_add_pass(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ uint sss_id,
+ struct GPUUniformBuffer *sss_profile,
+ struct GPUTexture *sss_tex_profile);
void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_subsurface_output_accumulate(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 f840fa23bd2..75e837f140b 100644
--- a/source/blender/draw/engines/eevee/eevee_render.c
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -133,7 +133,7 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *
/* EEVEE_effects_init needs to go first for TAA */
EEVEE_effects_init(sldata, vedata, ob_camera_eval, false);
EEVEE_materials_init(sldata, stl, fbl);
- EEVEE_lights_init(sldata);
+ EEVEE_shadows_init(sldata);
EEVEE_lightprobes_init(sldata, vedata);
/* INIT CACHE */
@@ -198,7 +198,7 @@ void EEVEE_render_cache(void *vedata,
}
if (cast_shadow) {
- EEVEE_lights_cache_shcaster_object_add(sldata, ob);
+ EEVEE_shadows_caster_register(sldata, ob);
}
}
@@ -369,7 +369,7 @@ static void eevee_render_result_z(RenderLayer *rl,
DRW_view_winmat_get(NULL, winmat, false);
/* Convert ogl depth [0..1] to view Z [near..far] */
- for (int i = 0; i < rp->rectx * rp->recty; ++i) {
+ for (int i = 0; i < rp->rectx * rp->recty; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
}
@@ -478,7 +478,8 @@ static void eevee_render_draw_background(EEVEE_Data *vedata)
GPU_ATTACHMENT_LEAVE,
GPU_ATTACHMENT_TEXTURE(stl->effects->ssr_normal_input),
GPU_ATTACHMENT_TEXTURE(stl->effects->ssr_specrough_input),
- GPU_ATTACHMENT_TEXTURE(stl->effects->sss_data),
+ GPU_ATTACHMENT_TEXTURE(stl->effects->sss_irradiance),
+ GPU_ATTACHMENT_TEXTURE(stl->effects->sss_radius),
GPU_ATTACHMENT_TEXTURE(stl->effects->sss_albedo)});
GPU_framebuffer_bind(fbl->main_fb);
}
@@ -582,8 +583,8 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
EEVEE_lightprobes_refresh_planar(sldata, vedata);
/* Refresh Shadows */
- EEVEE_lights_update(sldata, vedata);
- EEVEE_draw_shadows(sldata, vedata, stl->effects->taa_view);
+ EEVEE_shadows_update(sldata, vedata);
+ EEVEE_shadows_draw(sldata, vedata, stl->effects->taa_view);
/* Set matrices. */
DRW_view_set_active(stl->effects->taa_view);
@@ -605,9 +606,7 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
/* Shading pass */
eevee_render_draw_background(vedata);
GPU_framebuffer_bind(fbl->main_fb);
- EEVEE_draw_default_passes(psl);
- DRW_draw_pass(psl->material_pass);
- DRW_draw_pass(psl->material_pass_cull);
+ EEVEE_materials_draw_opaque(sldata, psl);
EEVEE_subsurface_data_render(sldata, vedata);
/* Effects pre-transparency */
EEVEE_subsurface_compute(sldata, vedata);
diff --git a/source/blender/draw/engines/eevee/eevee_sampling.c b/source/blender/draw/engines/eevee/eevee_sampling.c
new file mode 100644
index 00000000000..5e951928c5a
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_sampling.c
@@ -0,0 +1,129 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup EEVEE
+ */
+
+#include "eevee_private.h"
+
+#include "BLI_rand.h"
+
+/**
+ * Special ball distribution:
+ * Point are distributed in a way that when they are orthogonally
+ * projected into any plane, the resulting distribution is (close to)
+ * a uniform disc distribution.
+ */
+void EEVEE_sample_ball(int sample_ofs, float radius, float rsample[3])
+{
+ double ht_point[3];
+ double ht_offset[3] = {0.0, 0.0, 0.0};
+ uint ht_primes[3] = {2, 3, 7};
+
+ BLI_halton_3d(ht_primes, ht_offset, sample_ofs, ht_point);
+
+ /* Decorelate AA and shadow samples. (see T68594) */
+ ht_point[0] = fmod(ht_point[0] * 1151.0, 1.0);
+ ht_point[1] = fmod(ht_point[1] * 1069.0, 1.0);
+ ht_point[2] = fmod(ht_point[2] * 1151.0, 1.0);
+
+ float omega = ht_point[1] * 2.0f * M_PI;
+
+ rsample[2] = ht_point[0] * 2.0f - 1.0f; /* cos theta */
+
+ float r = sqrtf(fmaxf(0.0f, 1.0f - rsample[2] * rsample[2])); /* sin theta */
+
+ rsample[0] = r * cosf(omega);
+ rsample[1] = r * sinf(omega);
+
+ radius *= sqrt(sqrt(ht_point[2]));
+ mul_v3_fl(rsample, radius);
+}
+
+void EEVEE_sample_rectangle(int sample_ofs,
+ const float x_axis[3],
+ const float y_axis[3],
+ float size_x,
+ float size_y,
+ float rsample[3])
+{
+ double ht_point[2];
+ double ht_offset[2] = {0.0, 0.0};
+ uint ht_primes[2] = {2, 3};
+
+ BLI_halton_2d(ht_primes, ht_offset, sample_ofs, ht_point);
+
+ /* Decorelate AA and shadow samples. (see T68594) */
+ ht_point[0] = fmod(ht_point[0] * 1151.0, 1.0);
+ ht_point[1] = fmod(ht_point[1] * 1069.0, 1.0);
+
+ /* Change ditribution center to be 0,0 */
+ ht_point[0] = (ht_point[0] > 0.5f) ? ht_point[0] - 1.0f : ht_point[0];
+ ht_point[1] = (ht_point[1] > 0.5f) ? ht_point[1] - 1.0f : ht_point[1];
+
+ zero_v3(rsample);
+ madd_v3_v3fl(rsample, x_axis, (ht_point[0] * 2.0f) * size_x);
+ madd_v3_v3fl(rsample, y_axis, (ht_point[1] * 2.0f) * size_y);
+}
+
+void EEVEE_sample_ellipse(int sample_ofs,
+ const float x_axis[3],
+ const float y_axis[3],
+ float size_x,
+ float size_y,
+ float rsample[3])
+{
+ double ht_point[2];
+ double ht_offset[2] = {0.0, 0.0};
+ uint ht_primes[2] = {2, 3};
+
+ BLI_halton_2d(ht_primes, ht_offset, sample_ofs, ht_point);
+
+ /* Decorelate AA and shadow samples. (see T68594) */
+ ht_point[0] = fmod(ht_point[0] * 1151.0, 1.0);
+ ht_point[1] = fmod(ht_point[1] * 1069.0, 1.0);
+
+ /* Uniform disc sampling. */
+ float omega = ht_point[1] * 2.0f * M_PI;
+ float r = sqrtf(ht_point[0]);
+ ht_point[0] = r * cosf(omega) * size_x;
+ ht_point[1] = r * sinf(omega) * size_y;
+
+ zero_v3(rsample);
+ madd_v3_v3fl(rsample, x_axis, ht_point[0]);
+ madd_v3_v3fl(rsample, y_axis, ht_point[1]);
+}
+
+void EEVEE_random_rotation_m4(int sample_ofs, float scale, float r_mat[4][4])
+{
+ double ht_point[3];
+ double ht_offset[3] = {0.0, 0.0, 0.0};
+ uint ht_primes[3] = {2, 3, 5};
+
+ BLI_halton_3d(ht_primes, ht_offset, sample_ofs, ht_point);
+
+ /* Decorelate AA and shadow samples. (see T68594) */
+ ht_point[0] = fmod(ht_point[0] * 1151.0, 1.0);
+ ht_point[1] = fmod(ht_point[1] * 1069.0, 1.0);
+ ht_point[2] = fmod(ht_point[2] * 1151.0, 1.0);
+
+ rotate_m4(r_mat, 'X', ht_point[0] * scale);
+ rotate_m4(r_mat, 'Y', ht_point[1] * scale);
+ rotate_m4(r_mat, 'Z', ht_point[2] * scale);
+}
diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
index 3d1b64422a4..2daf2388d63 100644
--- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
+++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
@@ -338,7 +338,7 @@ void EEVEE_reflection_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
void EEVEE_screen_raytrace_free(void)
{
- for (int i = 0; i < SSR_MAX_SHADER; ++i) {
+ for (int i = 0; i < SSR_MAX_SHADER; i++) {
DRW_SHADER_FREE_SAFE(e_data.ssr_sh[i]);
}
}
diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c
new file mode 100644
index 00000000000..46fc6e07c1c
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_shadows.c
@@ -0,0 +1,412 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup EEVEE
+ */
+
+#include "BLI_sys_types.h" /* bool */
+
+// #include "BLI_dynstr.h"
+// #include "BLI_rand.h"
+
+#include "BKE_object.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "eevee_private.h"
+
+#define SH_CASTER_ALLOC_CHUNK 32
+
+static struct {
+ struct GPUShader *shadow_sh;
+} e_data = {NULL}; /* Engine data */
+
+extern char datatoc_shadow_vert_glsl[];
+extern char datatoc_shadow_frag_glsl[];
+extern char datatoc_common_view_lib_glsl[];
+
+void eevee_contact_shadow_setup(const Light *la, EEVEE_Shadow *evsh)
+{
+ evsh->contact_dist = (la->mode & LA_SHAD_CONTACT) ? la->contact_dist : 0.0f;
+ evsh->contact_bias = 0.05f * la->contact_bias;
+ evsh->contact_thickness = la->contact_thickness;
+}
+
+void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata)
+{
+ const uint shadow_ubo_size = sizeof(EEVEE_Shadow) * MAX_SHADOW +
+ sizeof(EEVEE_ShadowCube) * MAX_SHADOW_CUBE +
+ sizeof(EEVEE_ShadowCascade) * MAX_SHADOW_CASCADE;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+
+ if (!e_data.shadow_sh) {
+ e_data.shadow_sh = DRW_shader_create_with_lib(datatoc_shadow_vert_glsl,
+ NULL,
+ datatoc_shadow_frag_glsl,
+ datatoc_common_view_lib_glsl,
+ NULL);
+ }
+
+ if (!sldata->lights) {
+ sldata->lights = MEM_callocN(sizeof(EEVEE_LightsInfo), "EEVEE_LightsInfo");
+ sldata->light_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_Light) * MAX_LIGHT, NULL);
+ sldata->shadow_ubo = DRW_uniformbuffer_create(shadow_ubo_size, NULL);
+
+ for (int i = 0; i < 2; i++) {
+ sldata->shcasters_buffers[i].bbox = MEM_callocN(
+ 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;
+ sldata->shcasters_buffers[i].count = 0;
+ }
+ sldata->lights->shcaster_frontbuffer = &sldata->shcasters_buffers[0];
+ sldata->lights->shcaster_backbuffer = &sldata->shcasters_buffers[1];
+ }
+
+ /* Flip buffers */
+ SWAP(EEVEE_ShadowCasterBuffer *,
+ sldata->lights->shcaster_frontbuffer,
+ sldata->lights->shcaster_backbuffer);
+
+ int sh_cube_size = scene_eval->eevee.shadow_cube_size;
+ int sh_cascade_size = scene_eval->eevee.shadow_cascade_size;
+ const bool sh_high_bitdepth = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_HIGH_BITDEPTH) != 0;
+ sldata->lights->soft_shadows = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_SOFT) != 0;
+
+ EEVEE_LightsInfo *linfo = sldata->lights;
+ if ((linfo->shadow_cube_size != sh_cube_size) ||
+ (linfo->shadow_high_bitdepth != sh_high_bitdepth)) {
+ BLI_assert((sh_cube_size > 0) && (sh_cube_size <= 4096));
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool);
+ CLAMP(sh_cube_size, 1, 4096);
+ }
+
+ if ((linfo->shadow_cascade_size != sh_cascade_size) ||
+ (linfo->shadow_high_bitdepth != sh_high_bitdepth)) {
+ BLI_assert((sh_cascade_size > 0) && (sh_cascade_size <= 4096));
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool);
+ CLAMP(sh_cascade_size, 1, 4096);
+ }
+
+ linfo->shadow_high_bitdepth = sh_high_bitdepth;
+ linfo->shadow_cube_size = sh_cube_size;
+ linfo->shadow_cascade_size = sh_cascade_size;
+}
+
+void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_LightsInfo *linfo = sldata->lights;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PassList *psl = vedata->psl;
+
+ EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
+ EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
+
+ frontbuffer->count = 0;
+ linfo->num_cube_layer = 0;
+ linfo->num_cascade_layer = 0;
+ linfo->cube_len = linfo->cascade_len = linfo->shadow_len = 0;
+
+ /* Shadow Casters: Reset flags. */
+ BLI_bitmap_set_all(backbuffer->update, true, backbuffer->alloc_count);
+ /* Is this one needed? */
+ BLI_bitmap_set_all(frontbuffer->update, false, frontbuffer->alloc_count);
+
+ INIT_MINMAX(linfo->shcaster_aabb.min, linfo->shcaster_aabb.max);
+
+ {
+ DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_SHADOW_OFFSET;
+ DRW_PASS_CREATE(psl->shadow_pass, state);
+
+ stl->g_data->shadow_shgrp = DRW_shgroup_create(e_data.shadow_sh, psl->shadow_pass);
+ }
+}
+
+/* Add a shadow caster to the shadowpasses */
+void EEVEE_shadows_caster_add(EEVEE_ViewLayerData *UNUSED(sldata),
+ EEVEE_StorageList *stl,
+ struct GPUBatch *geom,
+ Object *ob)
+{
+ DRW_shgroup_call(stl->g_data->shadow_shgrp, geom, ob);
+}
+
+void EEVEE_shadows_caster_material_add(EEVEE_ViewLayerData *sldata,
+ EEVEE_PassList *psl,
+ struct GPUMaterial *gpumat,
+ struct GPUBatch *geom,
+ struct Object *ob,
+ const float *alpha_threshold)
+{
+ /* TODO / PERF : reuse the same shading group for objects with the same material */
+ DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, psl->shadow_pass);
+
+ if (grp == NULL) {
+ return;
+ }
+
+ /* Unfortunately needed for correctness but not 99% of the time not needed.
+ * TODO detect when needed? */
+ DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
+ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
+ DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+
+ if (alpha_threshold != NULL) {
+ DRW_shgroup_uniform_float(grp, "alphaThreshold", alpha_threshold, 1);
+ }
+
+ DRW_shgroup_call(grp, geom, ob);
+}
+
+/* Make that object update shadow casting lights inside its influence bounding box. */
+void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob)
+{
+ EEVEE_LightsInfo *linfo = sldata->lights;
+ EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
+ EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
+ bool update = true;
+ int id = frontbuffer->count;
+
+ /* Make sure shadow_casters is big enough. */
+ if (id + 1 >= frontbuffer->alloc_count) {
+ frontbuffer->alloc_count += SH_CASTER_ALLOC_CHUNK;
+ frontbuffer->bbox = MEM_reallocN(frontbuffer->bbox,
+ sizeof(EEVEE_BoundBox) * frontbuffer->alloc_count);
+ BLI_BITMAP_RESIZE(frontbuffer->update, frontbuffer->alloc_count);
+ }
+
+ if (ob->base_flag & BASE_FROM_DUPLI) {
+ /* Duplis will always refresh the shadowmaps as if they were deleted each frame. */
+ /* TODO(fclem) fix this. */
+ update = true;
+ }
+ else {
+ EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob);
+ int past_id = oedata->shadow_caster_id;
+ oedata->shadow_caster_id = id;
+ /* Update flags in backbuffer. */
+ if (past_id > -1 && past_id < backbuffer->count) {
+ BLI_BITMAP_SET(backbuffer->update, past_id, oedata->need_update);
+ }
+ update = oedata->need_update;
+ oedata->need_update = false;
+ }
+
+ if (update) {
+ BLI_BITMAP_ENABLE(frontbuffer->update, id);
+ }
+
+ /* Update World AABB in frontbuffer. */
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ float min[3], max[3];
+ INIT_MINMAX(min, max);
+ for (int i = 0; i < 8; i++) {
+ float vec[3];
+ copy_v3_v3(vec, bb->vec[i]);
+ mul_m4_v3(ob->obmat, vec);
+ minmax_v3v3_v3(min, max, vec);
+ }
+
+ EEVEE_BoundBox *aabb = &frontbuffer->bbox[id];
+ add_v3_v3v3(aabb->center, min, max);
+ mul_v3_fl(aabb->center, 0.5f);
+ sub_v3_v3v3(aabb->halfdim, aabb->center, max);
+
+ aabb->halfdim[0] = fabsf(aabb->halfdim[0]);
+ aabb->halfdim[1] = fabsf(aabb->halfdim[1]);
+ aabb->halfdim[2] = fabsf(aabb->halfdim[2]);
+
+ minmax_v3v3_v3(linfo->shcaster_aabb.min, linfo->shcaster_aabb.max, min);
+ minmax_v3v3_v3(linfo->shcaster_aabb.min, linfo->shcaster_aabb.max, max);
+
+ frontbuffer->count++;
+}
+
+/* Used for checking if object is inside the shadow volume. */
+static bool sphere_bbox_intersect(const BoundSphere *bs, const EEVEE_BoundBox *bb)
+{
+ /* We are testing using a rougher AABB vs AABB test instead of full AABB vs Sphere. */
+ /* TODO test speed with AABB vs Sphere. */
+ bool x = fabsf(bb->center[0] - bs->center[0]) <= (bb->halfdim[0] + bs->radius);
+ bool y = fabsf(bb->center[1] - bs->center[1]) <= (bb->halfdim[1] + bs->radius);
+ bool z = fabsf(bb->center[2] - bs->center[2]) <= (bb->halfdim[2] + bs->radius);
+
+ return x && y && z;
+}
+
+void EEVEE_shadows_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ EEVEE_LightsInfo *linfo = sldata->lights;
+ EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
+ EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
+
+ eGPUTextureFormat shadow_pool_format = (linfo->shadow_high_bitdepth) ? GPU_DEPTH_COMPONENT24 :
+ GPU_DEPTH_COMPONENT16;
+ /* Setup enough layers. */
+ /* Free textures if number mismatch. */
+ if (linfo->num_cube_layer != linfo->cache_num_cube_layer) {
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool);
+ linfo->cache_num_cube_layer = linfo->num_cube_layer;
+ /* Update all lights. */
+ BLI_bitmap_set_all(&linfo->sh_cube_update[0], true, MAX_LIGHT);
+ }
+
+ if (linfo->num_cascade_layer != linfo->cache_num_cascade_layer) {
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool);
+ linfo->cache_num_cascade_layer = linfo->num_cascade_layer;
+ }
+
+ if (!sldata->shadow_cube_pool) {
+ /* TODO shadowcube array. */
+ int cube_size = linfo->shadow_cube_size + ((true) ? 2 : 0);
+ sldata->shadow_cube_pool = DRW_texture_create_2d_array(cube_size,
+ cube_size,
+ max_ii(1, linfo->num_cube_layer * 6),
+ shadow_pool_format,
+ DRW_TEX_FILTER | DRW_TEX_COMPARE,
+ NULL);
+ }
+
+ if (!sldata->shadow_cascade_pool) {
+ sldata->shadow_cascade_pool = DRW_texture_create_2d_array(linfo->shadow_cascade_size,
+ linfo->shadow_cascade_size,
+ max_ii(1, linfo->num_cascade_layer),
+ shadow_pool_format,
+ DRW_TEX_FILTER | DRW_TEX_COMPARE,
+ NULL);
+ }
+
+ if (sldata->shadow_fb == NULL) {
+ sldata->shadow_fb = GPU_framebuffer_create();
+ }
+
+ /* Gather all light own update bits. to avoid costly intersection check. */
+ for (int j = 0; j < linfo->cube_len; j++) {
+ const EEVEE_Light *evli = linfo->light_data + linfo->shadow_cube_light_indices[j];
+ /* Setup shadow cube in UBO and tag for update if necessary. */
+ if (EEVEE_shadows_cube_setup(linfo, evli, effects->taa_current_sample - 1)) {
+ BLI_BITMAP_ENABLE(&linfo->sh_cube_update[0], j);
+ }
+ }
+
+ /* TODO(fclem) This part can be slow, optimize it. */
+ EEVEE_BoundBox *bbox = backbuffer->bbox;
+ BoundSphere *bsphere = linfo->shadow_bounds;
+ /* Search for deleted shadow casters or if shcaster WAS in shadow radius. */
+ for (int i = 0; i < backbuffer->count; i++) {
+ /* If the shadowcaster has been deleted or updated. */
+ if (BLI_BITMAP_TEST(backbuffer->update, i)) {
+ for (int j = 0; j < linfo->cube_len; j++) {
+ if (!BLI_BITMAP_TEST(&linfo->sh_cube_update[0], j)) {
+ if (sphere_bbox_intersect(&bsphere[j], &bbox[i])) {
+ BLI_BITMAP_ENABLE(&linfo->sh_cube_update[0], j);
+ }
+ }
+ }
+ }
+ }
+ /* Search for updates in current shadow casters. */
+ bbox = frontbuffer->bbox;
+ for (int i = 0; i < frontbuffer->count; i++) {
+ /* If the shadowcaster has been updated. */
+ if (BLI_BITMAP_TEST(frontbuffer->update, i)) {
+ for (int j = 0; j < linfo->cube_len; j++) {
+ if (!BLI_BITMAP_TEST(&linfo->sh_cube_update[0], j)) {
+ if (sphere_bbox_intersect(&bsphere[j], &bbox[i])) {
+ BLI_BITMAP_ENABLE(&linfo->sh_cube_update[0], j);
+ }
+ }
+ }
+ }
+ }
+
+ /* Resize shcasters buffers if too big. */
+ if (frontbuffer->alloc_count - frontbuffer->count > SH_CASTER_ALLOC_CHUNK) {
+ frontbuffer->alloc_count = (frontbuffer->count / SH_CASTER_ALLOC_CHUNK) *
+ SH_CASTER_ALLOC_CHUNK;
+ frontbuffer->alloc_count += (frontbuffer->count % SH_CASTER_ALLOC_CHUNK != 0) ?
+ SH_CASTER_ALLOC_CHUNK :
+ 0;
+ frontbuffer->bbox = MEM_reallocN(frontbuffer->bbox,
+ sizeof(EEVEE_BoundBox) * frontbuffer->alloc_count);
+ BLI_BITMAP_RESIZE(frontbuffer->update, frontbuffer->alloc_count);
+ }
+}
+
+/* this refresh lights shadow buffers */
+void EEVEE_shadows_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWView *view)
+{
+ EEVEE_LightsInfo *linfo = sldata->lights;
+
+ int saved_ray_type = sldata->common_data.ray_type;
+
+ /* Precompute all shadow/view test before rendering and trashing the culling cache. */
+ BLI_bitmap *cube_visible = BLI_BITMAP_NEW_ALLOCA(MAX_SHADOW_CUBE);
+ bool any_visible = false;
+ for (int cube = 0; cube < linfo->cube_len; cube++) {
+ if (DRW_culling_sphere_test(view, linfo->shadow_bounds + cube)) {
+ BLI_BITMAP_ENABLE(cube_visible, cube);
+ any_visible = true;
+ }
+ }
+
+ if (!any_visible && linfo->cascade_len == 0) {
+ sldata->common_data.ray_type = EEVEE_RAY_SHADOW;
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+ }
+
+ DRW_stats_group_start("Cube Shadow Maps");
+ {
+ for (int cube = 0; cube < linfo->cube_len; cube++) {
+ if (BLI_BITMAP_TEST(cube_visible, cube) && BLI_BITMAP_TEST(linfo->sh_cube_update, cube)) {
+ EEVEE_shadows_draw_cubemap(sldata, vedata, cube);
+ }
+ }
+ }
+ DRW_stats_group_end();
+
+ DRW_stats_group_start("Cascaded Shadow Maps");
+ {
+ for (int cascade = 0; cascade < linfo->cascade_len; cascade++) {
+ EEVEE_shadows_draw_cascades(sldata, vedata, view, cascade);
+ }
+ }
+ DRW_stats_group_end();
+
+ DRW_view_set_active(view);
+
+ DRW_uniformbuffer_update(sldata->shadow_ubo, &linfo->shadow_data); /* Update all data at once */
+
+ if (!any_visible && linfo->cascade_len == 0) {
+ sldata->common_data.ray_type = saved_ray_type;
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+ }
+}
+
+void EEVEE_shadows_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.shadow_sh);
+}
diff --git a/source/blender/draw/engines/eevee/eevee_shadows_cascade.c b/source/blender/draw/engines/eevee/eevee_shadows_cascade.c
new file mode 100644
index 00000000000..b2dc8103df2
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_shadows_cascade.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.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup EEVEE
+ */
+
+#include "BLI_rect.h"
+#include "BLI_sys_types.h" /* bool */
+
+#include "BKE_object.h"
+
+#include "eevee_private.h"
+
+#include "BLI_rand.h" /* needs to be after for some reason. */
+
+void EEVEE_shadows_cascade_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, Object *ob)
+{
+ if (linfo->cascade_len >= MAX_SHADOW_CASCADE) {
+ return;
+ }
+
+ const Light *la = (Light *)ob->data;
+ EEVEE_Shadow *sh_data = linfo->shadow_data + linfo->shadow_len;
+ EEVEE_ShadowCascade *csm_data = linfo->shadow_cascade_data + linfo->cascade_len;
+ EEVEE_ShadowCascadeRender *csm_render = linfo->shadow_cascade_render + linfo->cascade_len;
+
+ sh_data->bias = max_ff(la->bias * 0.00002f, 0.0f);
+ eevee_contact_shadow_setup(la, sh_data);
+
+ linfo->shadow_cascade_light_indices[linfo->cascade_len] = linfo->num_light;
+ evli->shadow_id = linfo->shadow_len++;
+ sh_data->type_data_id = linfo->cascade_len++;
+ csm_data->tex_id = linfo->num_cascade_layer;
+ csm_render->cascade_fade = la->cascade_fade;
+ csm_render->cascade_count = la->cascade_count;
+ csm_render->cascade_exponent = la->cascade_exponent;
+ csm_render->cascade_max_dist = la->cascade_max_dist;
+
+ linfo->num_cascade_layer += la->cascade_count;
+}
+
+static void shadow_cascade_random_matrix_set(float mat[4][4], float radius, int sample_ofs)
+{
+ float jitter[3];
+#ifndef DEBUG_SHADOW_DISTRIBUTION
+ EEVEE_sample_ellipse(sample_ofs, mat[0], mat[1], radius, radius, jitter);
+#else
+ for (int i = 0; i <= sample_ofs; i++) {
+ EEVEE_sample_ellipse(i, mat[0], mat[1], radius, radius, jitter);
+ float p[3];
+ add_v3_v3v3(p, jitter, mat[2]);
+ DRW_debug_sphere(p, 0.01f, (float[4]){1.0f, (sample_ofs == i) ? 1.0f : 0.0f, 0.0f, 1.0f});
+ }
+#endif
+ add_v3_v3(mat[2], jitter);
+ orthogonalize_m4(mat, 2);
+}
+
+static double round_to_digits(double value, int digits)
+{
+ double factor = pow(10.0, digits - ceil(log10(fabs(value))));
+ return round(value * factor) / factor;
+}
+
+static void frustum_min_bounding_sphere(const float corners[8][3],
+ float r_center[3],
+ float *r_radius)
+{
+#if 0 /* Simple solution but waste too much space. */
+ float minvec[3], maxvec[3];
+
+ /* compute the bounding box */
+ INIT_MINMAX(minvec, maxvec);
+ for (int i = 0; i < 8; i++) {
+ minmax_v3v3_v3(minvec, maxvec, corners[i]);
+ }
+
+ /* compute the bounding sphere of this box */
+ r_radius = len_v3v3(minvec, maxvec) * 0.5f;
+ add_v3_v3v3(r_center, minvec, maxvec);
+ mul_v3_fl(r_center, 0.5f);
+#else
+ /* Find averaged center. */
+ zero_v3(r_center);
+ for (int i = 0; i < 8; i++) {
+ add_v3_v3(r_center, corners[i]);
+ }
+ mul_v3_fl(r_center, 1.0f / 8.0f);
+
+ /* Search the largest distance from the sphere center. */
+ *r_radius = 0.0f;
+ for (int i = 0; i < 8; i++) {
+ float rad = len_squared_v3v3(corners[i], r_center);
+ if (rad > *r_radius) {
+ *r_radius = rad;
+ }
+ }
+
+ /* TODO try to reduce the radius further by moving the center.
+ * Remember we need a __stable__ solution! */
+
+ /* Try to reduce float imprecision leading to shimmering. */
+ *r_radius = (float)round_to_digits(sqrtf(*r_radius), 3);
+#endif
+}
+
+BLI_INLINE float lerp(float t, float a, float b)
+{
+ return ((a) + (t) * ((b) - (a)));
+}
+
+static void eevee_shadow_cascade_setup(EEVEE_LightsInfo *linfo,
+ EEVEE_Light *evli,
+ DRWView *view,
+ float view_near,
+ float view_far,
+ int sample_ofs)
+{
+ EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id;
+ EEVEE_ShadowCascade *csm_data = linfo->shadow_cascade_data + (int)shdw_data->type_data_id;
+ EEVEE_ShadowCascadeRender *csm_render = linfo->shadow_cascade_render +
+ (int)shdw_data->type_data_id;
+ int cascade_nbr = csm_render->cascade_count;
+ float cascade_fade = csm_render->cascade_fade;
+ float cascade_max_dist = csm_render->cascade_max_dist;
+ float cascade_exponent = csm_render->cascade_exponent;
+
+ float jitter_ofs[2];
+ double ht_point[2];
+ double ht_offset[2] = {0.0, 0.0};
+ uint ht_primes[2] = {2, 3};
+
+ BLI_halton_2d(ht_primes, ht_offset, sample_ofs, ht_point);
+
+ /* Not really sure why we need 4.0 factor here. */
+ jitter_ofs[0] = (ht_point[0] * 2.0 - 1.0) * 4.0 / linfo->shadow_cascade_size;
+ jitter_ofs[1] = (ht_point[1] * 2.0 - 1.0) * 4.0 / linfo->shadow_cascade_size;
+
+ /* Camera Matrices */
+ float persinv[4][4], vp_projmat[4][4];
+ DRW_view_persmat_get(view, persinv, true);
+ DRW_view_winmat_get(view, vp_projmat, false);
+ bool is_persp = DRW_view_is_persp_get(view);
+
+ /* obmat = Object Space > World Space */
+ /* viewmat = World Space > View Space */
+ float(*viewmat)[4] = csm_render->viewmat;
+ eevee_light_matrix_get(evli, viewmat);
+ /* At this point, viewmat == normalize_m4(obmat) */
+
+ if (linfo->soft_shadows) {
+ shadow_cascade_random_matrix_set(viewmat, evli->radius, sample_ofs);
+ }
+
+ copy_m4_m4(csm_render->viewinv, viewmat);
+ invert_m4(viewmat);
+
+ copy_v3_v3(csm_data->shadow_vec, csm_render->viewinv[2]);
+
+ /* Compute near and far value based on all shadow casters cumulated AABBs. */
+ float sh_near = -1.0e30f, sh_far = 1.0e30f;
+ BoundBox shcaster_bounds;
+ BKE_boundbox_init_from_minmax(
+ &shcaster_bounds, linfo->shcaster_aabb.min, linfo->shcaster_aabb.max);
+#ifdef DEBUG_CSM
+ float dbg_col1[4] = {1.0f, 0.5f, 0.6f, 1.0f};
+ DRW_debug_bbox(&shcaster_bounds, dbg_col1);
+#endif
+ for (int i = 0; i < 8; i++) {
+ mul_m4_v3(viewmat, shcaster_bounds.vec[i]);
+ sh_near = max_ff(sh_near, shcaster_bounds.vec[i][2]);
+ sh_far = min_ff(sh_far, shcaster_bounds.vec[i][2]);
+ }
+#ifdef DEBUG_CSM
+ float dbg_col2[4] = {0.5f, 1.0f, 0.6f, 1.0f};
+ float pts[2][3] = {{0.0, 0.0, sh_near}, {0.0, 0.0, sh_far}};
+ mul_m4_v3(csm_render->viewinv, pts[0]);
+ mul_m4_v3(csm_render->viewinv, pts[1]);
+ DRW_debug_sphere(pts[0], 1.0f, dbg_col1);
+ DRW_debug_sphere(pts[1], 1.0f, dbg_col2);
+#endif
+ /* The rest of the function is assuming inverted Z. */
+ /* Add a little bias to avoid invalid matrices. */
+ sh_far = -(sh_far - 1e-3);
+ sh_near = -sh_near;
+
+ /* The technique consists into splitting
+ * the view frustum into several sub-frustum
+ * that are individually receiving one shadow map */
+
+ float csm_start, csm_end;
+
+ if (is_persp) {
+ csm_start = view_near;
+ csm_end = max_ff(view_far, -cascade_max_dist);
+ /* Avoid artifacts */
+ csm_end = min_ff(view_near, csm_end);
+ }
+ else {
+ csm_start = -view_far;
+ csm_end = view_far;
+ }
+
+ /* init near/far */
+ for (int c = 0; c < MAX_CASCADE_NUM; c++) {
+ csm_data->split_start[c] = csm_end;
+ csm_data->split_end[c] = csm_end;
+ }
+
+ /* Compute split planes */
+ float splits_start_ndc[MAX_CASCADE_NUM];
+ float splits_end_ndc[MAX_CASCADE_NUM];
+
+ {
+ /* Nearest plane */
+ float p[4] = {1.0f, 1.0f, csm_start, 1.0f};
+ /* TODO: we don't need full m4 multiply here */
+ mul_m4_v4(vp_projmat, p);
+ splits_start_ndc[0] = p[2];
+ if (is_persp) {
+ splits_start_ndc[0] /= p[3];
+ }
+ }
+
+ {
+ /* Farthest plane */
+ float p[4] = {1.0f, 1.0f, csm_end, 1.0f};
+ /* TODO: we don't need full m4 multiply here */
+ mul_m4_v4(vp_projmat, p);
+ splits_end_ndc[cascade_nbr - 1] = p[2];
+ if (is_persp) {
+ splits_end_ndc[cascade_nbr - 1] /= p[3];
+ }
+ }
+
+ csm_data->split_start[0] = csm_start;
+ csm_data->split_end[cascade_nbr - 1] = csm_end;
+
+ for (int c = 1; c < cascade_nbr; c++) {
+ /* View Space */
+ float linear_split = lerp(((float)(c) / (float)cascade_nbr), csm_start, csm_end);
+ float exp_split = csm_start * powf(csm_end / csm_start, (float)(c) / (float)cascade_nbr);
+
+ if (is_persp) {
+ csm_data->split_start[c] = lerp(cascade_exponent, linear_split, exp_split);
+ }
+ else {
+ csm_data->split_start[c] = linear_split;
+ }
+ csm_data->split_end[c - 1] = csm_data->split_start[c];
+
+ /* Add some overlap for smooth transition */
+ csm_data->split_start[c] = lerp(cascade_fade,
+ csm_data->split_end[c - 1],
+ (c > 1) ? csm_data->split_end[c - 2] :
+ csm_data->split_start[0]);
+
+ /* NDC Space */
+ {
+ float p[4] = {1.0f, 1.0f, csm_data->split_start[c], 1.0f};
+ /* TODO: we don't need full m4 multiply here */
+ mul_m4_v4(vp_projmat, p);
+ splits_start_ndc[c] = p[2];
+
+ if (is_persp) {
+ splits_start_ndc[c] /= p[3];
+ }
+ }
+
+ {
+ float p[4] = {1.0f, 1.0f, csm_data->split_end[c - 1], 1.0f};
+ /* TODO: we don't need full m4 multiply here */
+ mul_m4_v4(vp_projmat, p);
+ splits_end_ndc[c - 1] = p[2];
+
+ if (is_persp) {
+ splits_end_ndc[c - 1] /= p[3];
+ }
+ }
+ }
+
+ /* Set last cascade split fade distance into the first split_start. */
+ float prev_split = (cascade_nbr > 1) ? csm_data->split_end[cascade_nbr - 2] :
+ csm_data->split_start[0];
+ csm_data->split_start[0] = lerp(cascade_fade, csm_data->split_end[cascade_nbr - 1], prev_split);
+
+ /* For each cascade */
+ for (int c = 0; c < cascade_nbr; c++) {
+ float(*projmat)[4] = csm_render->projmat[c];
+ /* Given 8 frustum corners */
+ float corners[8][3] = {
+ /* Near Cap */
+ {1.0f, -1.0f, splits_start_ndc[c]},
+ {-1.0f, -1.0f, splits_start_ndc[c]},
+ {-1.0f, 1.0f, splits_start_ndc[c]},
+ {1.0f, 1.0f, splits_start_ndc[c]},
+ /* Far Cap */
+ {1.0f, -1.0f, splits_end_ndc[c]},
+ {-1.0f, -1.0f, splits_end_ndc[c]},
+ {-1.0f, 1.0f, splits_end_ndc[c]},
+ {1.0f, 1.0f, splits_end_ndc[c]},
+ };
+
+ /* Transform them into world space */
+ for (int i = 0; i < 8; i++) {
+ mul_project_m4_v3(persinv, corners[i]);
+ }
+
+ float center[3];
+ frustum_min_bounding_sphere(corners, center, &(csm_render->radius[c]));
+
+#ifdef DEBUG_CSM
+ float dbg_col[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ if (c < 3) {
+ dbg_col[c] = 1.0f;
+ }
+ DRW_debug_bbox((BoundBox *)&corners, dbg_col);
+ DRW_debug_sphere(center, csm_render->radius[c], dbg_col);
+#endif
+
+ /* Project into lightspace */
+ mul_m4_v3(viewmat, center);
+
+ /* Snap projection center to nearest texel to cancel shimmering. */
+ float shadow_origin[2], shadow_texco[2];
+ /* Light to texture space. */
+ mul_v2_v2fl(
+ shadow_origin, center, linfo->shadow_cascade_size / (2.0f * csm_render->radius[c]));
+
+ /* Find the nearest texel. */
+ shadow_texco[0] = roundf(shadow_origin[0]);
+ shadow_texco[1] = roundf(shadow_origin[1]);
+
+ /* Compute offset. */
+ sub_v2_v2(shadow_texco, shadow_origin);
+ /* Texture to light space. */
+ mul_v2_fl(shadow_texco, (2.0f * csm_render->radius[c]) / linfo->shadow_cascade_size);
+
+ /* Apply offset. */
+ add_v2_v2(center, shadow_texco);
+
+ /* Expand the projection to cover frustum range */
+ rctf rect_cascade;
+ BLI_rctf_init_pt_radius(&rect_cascade, center, csm_render->radius[c]);
+ orthographic_m4(projmat,
+ rect_cascade.xmin,
+ rect_cascade.xmax,
+ rect_cascade.ymin,
+ rect_cascade.ymax,
+ sh_near,
+ sh_far);
+
+ /* Anti-Aliasing */
+ if (linfo->soft_shadows) {
+ add_v2_v2(projmat[3], jitter_ofs);
+ }
+
+ float viewprojmat[4][4];
+ mul_m4_m4m4(viewprojmat, projmat, viewmat);
+ mul_m4_m4m4(csm_data->shadowmat[c], texcomat, viewprojmat);
+
+#ifdef DEBUG_CSM
+ DRW_debug_m4_as_bbox(viewprojmat, dbg_col, true);
+#endif
+ }
+
+ shdw_data->near = sh_near;
+ shdw_data->far = sh_far;
+}
+
+static void eevee_ensure_cascade_views(EEVEE_ShadowCascadeRender *csm_render,
+ DRWView *view[MAX_CASCADE_NUM])
+{
+ for (int i = 0; i < csm_render->cascade_count; i++) {
+ if (view[i] == NULL) {
+ view[i] = DRW_view_create(csm_render->viewmat, csm_render->projmat[i], NULL, NULL, NULL);
+ }
+ else {
+ DRW_view_update(view[i], csm_render->viewmat, csm_render->projmat[i], NULL, NULL);
+ }
+ }
+}
+
+void EEVEE_shadows_draw_cascades(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ DRWView *view,
+ int cascade_index)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ EEVEE_PrivateData *g_data = stl->g_data;
+ EEVEE_LightsInfo *linfo = sldata->lights;
+
+ EEVEE_Light *evli = linfo->light_data + linfo->shadow_cascade_light_indices[cascade_index];
+ EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id;
+ EEVEE_ShadowCascade *csm_data = linfo->shadow_cascade_data + (int)shdw_data->type_data_id;
+ EEVEE_ShadowCascadeRender *csm_render = linfo->shadow_cascade_render +
+ (int)shdw_data->type_data_id;
+
+ float near = DRW_view_near_distance_get(view);
+ float far = DRW_view_far_distance_get(view);
+
+ eevee_shadow_cascade_setup(linfo, evli, view, near, far, effects->taa_current_sample - 1);
+
+ /* Meh, Reusing the cube views. */
+ BLI_assert(MAX_CASCADE_NUM <= 6);
+ eevee_ensure_cascade_views(csm_render, g_data->cube_views);
+
+ /* Render shadow cascades */
+ /* Render cascade separately: seems to be faster for the general case.
+ * The only time it's more beneficial is when the CPU culling overhead
+ * outweigh the instancing overhead. which is rarely the case. */
+ for (int j = 0; j < csm_render->cascade_count; j++) {
+ DRW_view_set_active(g_data->cube_views[j]);
+ int layer = csm_data->tex_id + j;
+ GPU_framebuffer_texture_layer_attach(
+ sldata->shadow_fb, sldata->shadow_cascade_pool, 0, layer, 0);
+ GPU_framebuffer_bind(sldata->shadow_fb);
+ GPU_framebuffer_clear_depth(sldata->shadow_fb, 1.0f);
+ DRW_draw_pass(psl->shadow_pass);
+ }
+}
diff --git a/source/blender/draw/engines/eevee/eevee_shadows_cube.c b/source/blender/draw/engines/eevee/eevee_shadows_cube.c
new file mode 100644
index 00000000000..a355e7e0792
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_shadows_cube.c
@@ -0,0 +1,225 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup EEVEE
+ */
+
+#include "eevee_private.h"
+
+void EEVEE_shadows_cube_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, Object *ob)
+{
+ if (linfo->cube_len >= MAX_SHADOW_CUBE) {
+ return;
+ }
+
+ const Light *la = (Light *)ob->data;
+ EEVEE_Shadow *sh_data = linfo->shadow_data + linfo->shadow_len;
+
+ /* Always update dupli lights as EEVEE_LightEngineData is not saved.
+ * Same issue with dupli shadow casters. */
+ bool update = (ob->base_flag & BASE_FROM_DUPLI) != 0;
+ if (!update) {
+ EEVEE_LightEngineData *led = EEVEE_light_data_ensure(ob);
+ if (led->need_update) {
+ update = true;
+ led->need_update = false;
+ }
+ }
+
+ if (update) {
+ BLI_BITMAP_ENABLE(&linfo->sh_cube_update[0], linfo->cube_len);
+ }
+
+ sh_data->near = max_ff(la->clipsta, 1e-8f);
+ sh_data->bias = max_ff(la->bias * 0.05f, 0.0f);
+ eevee_contact_shadow_setup(la, sh_data);
+
+ /* Saving light bounds for later. */
+ BoundSphere *cube_bound = linfo->shadow_bounds + linfo->cube_len;
+ copy_v3_v3(cube_bound->center, evli->position);
+ cube_bound->radius = sqrt(1.0f / evli->invsqrdist);
+
+ linfo->shadow_cube_light_indices[linfo->cube_len] = linfo->num_light;
+ evli->shadow_id = linfo->shadow_len++;
+ sh_data->type_data_id = linfo->cube_len++;
+
+ /* Same as linfo->cube_len, no need to save. */
+ linfo->num_cube_layer++;
+}
+
+static void shadow_cube_random_position_set(const EEVEE_Light *evli,
+ int sample_ofs,
+ float ws_sample_pos[3])
+{
+ float jitter[3];
+#ifdef DEBUG_SHADOW_DISTRIBUTION
+ int i = 0;
+start:
+#else
+ int i = sample_ofs;
+#endif
+ switch ((int)evli->light_type) {
+ case LA_AREA:
+ EEVEE_sample_rectangle(i, evli->rightvec, evli->upvec, evli->sizex, evli->sizey, jitter);
+ break;
+ case (int)LAMPTYPE_AREA_ELLIPSE:
+ EEVEE_sample_ellipse(i, evli->rightvec, evli->upvec, evli->sizex, evli->sizey, jitter);
+ break;
+ default:
+ EEVEE_sample_ball(i, evli->radius, jitter);
+ }
+#ifdef DEBUG_SHADOW_DISTRIBUTION
+ float p[3];
+ add_v3_v3v3(p, jitter, ws_sample_pos);
+ DRW_debug_sphere(p, 0.01f, (float[4]){1.0f, (sample_ofs == i) ? 1.0f : 0.0f, 0.0f, 1.0f});
+ if (i++ < sample_ofs) {
+ goto start;
+ }
+#endif
+ add_v3_v3(ws_sample_pos, jitter);
+}
+
+/* Return true if sample has changed and light needs to be updated. */
+bool EEVEE_shadows_cube_setup(EEVEE_LightsInfo *linfo, const EEVEE_Light *evli, int sample_ofs)
+{
+ EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id;
+ EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + (int)shdw_data->type_data_id;
+
+ eevee_light_matrix_get(evli, cube_data->shadowmat);
+
+ shdw_data->far = max_ff(sqrt(1.0f / evli->invsqrdist), 3e-4);
+ shdw_data->near = min_ff(shdw_data->near, shdw_data->far - 1e-4);
+
+ bool update = false;
+
+ if (linfo->soft_shadows) {
+ shadow_cube_random_position_set(evli, sample_ofs, cube_data->shadowmat[3]);
+ /* Update if position changes (avoid infinite update if soft shadows does not move).
+ * Other changes are caught by depsgraph tagging. This one is for update between samples. */
+ update = !compare_v3v3(cube_data->shadowmat[3], cube_data->position, 1e-10f);
+ /**
+ * Anti-Aliasing jitter: Add random rotation.
+ *
+ * The 2.0 factor is because texel angular size is not even across the cube-map,
+ * so we make the rotation range a bit bigger.
+ * This will not blur the shadow even if the spread is too big since we are just
+ * rotating the shadow cube-map.
+ * Note that this may be a rough approximation an may not converge to a perfectly
+ * smooth shadow (because sample distribution is quite non-uniform) but is enough
+ * in practice.
+ **/
+ /* NOTE: this has implication for spotlight rendering optimization
+ * (see EEVEE_shadows_draw_cubemap). */
+ float angular_texel_size = 2.0f * DEG2RADF(90) / (float)linfo->shadow_cube_size;
+ EEVEE_random_rotation_m4(sample_ofs, angular_texel_size, cube_data->shadowmat);
+ }
+
+ copy_v3_v3(cube_data->position, cube_data->shadowmat[3]);
+ invert_m4(cube_data->shadowmat);
+
+ return update;
+}
+
+static void eevee_ensure_cube_views(
+ float near, float far, int cube_res, const float viewmat[4][4], DRWView *view[6])
+{
+ float winmat[4][4];
+ float side = near;
+
+ /* TODO shadowcube array. */
+ if (true) {
+ /* This half texel offset is used to ensure correct filtering between faces. */
+ /* FIXME: This exhibit float precision issue with lower cube_res.
+ * But it seems to be caused by the perspective_m4. */
+ side *= ((float)cube_res + 1.0f) / (float)(cube_res);
+ }
+
+ perspective_m4(winmat, -side, side, -side, side, near, far);
+
+ for (int i = 0; i < 6; i++) {
+ float tmp[4][4];
+ mul_m4_m4m4(tmp, cubefacemat[i], viewmat);
+
+ if (view[i] == NULL) {
+ view[i] = DRW_view_create(tmp, winmat, NULL, NULL, NULL);
+ }
+ else {
+ DRW_view_update(view[i], tmp, winmat, NULL, NULL);
+ }
+ }
+}
+
+/* Does a spot angle fits a single cubeface. */
+static bool spot_angle_fit_single_face(const EEVEE_Light *evli)
+{
+ /* alpha = spot/cone half angle. */
+ /* beta = scaled spot/cone half angle. */
+ float cos_alpha = evli->spotsize;
+ float sin_alpha = sqrtf(max_ff(0.0f, 1.0f - cos_alpha * cos_alpha));
+ float cos_beta = min_ff(cos_alpha / hypotf(cos_alpha, sin_alpha * evli->sizex),
+ cos_alpha / hypotf(cos_alpha, sin_alpha * evli->sizey));
+ /* Don't use 45 degrees because AA jitter can offset the face. */
+ return cos_beta > cosf(DEG2RADF(42.0f));
+}
+
+void EEVEE_shadows_draw_cubemap(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, int cube_index)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PrivateData *g_data = stl->g_data;
+ EEVEE_LightsInfo *linfo = sldata->lights;
+
+ EEVEE_Light *evli = linfo->light_data + linfo->shadow_cube_light_indices[cube_index];
+ EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id;
+ EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + (int)shdw_data->type_data_id;
+
+ eevee_ensure_cube_views(shdw_data->near,
+ shdw_data->far,
+ linfo->shadow_cube_size,
+ cube_data->shadowmat,
+ g_data->cube_views);
+
+ /* Render shadow cube */
+ /* Render 6 faces separately: seems to be faster for the general case.
+ * The only time it's more beneficial is when the CPU culling overhead
+ * outweigh the instancing overhead. which is rarely the case. */
+ for (int j = 0; j < 6; j++) {
+ /* Optimization: Only render the needed faces. */
+ /* Skip all but -Z face. */
+ if (evli->light_type == LA_SPOT && j != 5 && spot_angle_fit_single_face(evli)) {
+ continue;
+ }
+ /* Skip +Z face. */
+ if (evli->light_type != LA_LOCAL && j == 4) {
+ continue;
+ }
+ /* TODO(fclem) some cube sides can be invisible in the main views. Cull them. */
+ // if (frustum_intersect(g_data->cube_views[j], main_view))
+ // continue;
+
+ DRW_view_set_active(g_data->cube_views[j]);
+ int layer = cube_index * 6 + j;
+ GPU_framebuffer_texture_layer_attach(sldata->shadow_fb, sldata->shadow_cube_pool, 0, layer, 0);
+ GPU_framebuffer_bind(sldata->shadow_fb);
+ GPU_framebuffer_clear_depth(sldata->shadow_fb, 1.0f);
+ DRW_draw_pass(psl->shadow_pass);
+ }
+
+ BLI_BITMAP_SET(&linfo->sh_cube_update[0], cube_index, false);
+}
diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c
index 24956239508..8376b8c67b8 100644
--- a/source/blender/draw/engines/eevee/eevee_subsurface.c
+++ b/source/blender/draw/engines/eevee/eevee_subsurface.c
@@ -38,7 +38,13 @@ static struct {
extern char datatoc_common_view_lib_glsl[];
extern char datatoc_common_uniforms_lib_glsl[];
+extern char datatoc_lights_lib_glsl[];
+extern char datatoc_raytrace_lib_glsl[];
+extern char datatoc_octahedron_lib_glsl[];
+extern char datatoc_bsdf_sampling_lib_glsl[];
+extern char datatoc_bsdf_common_lib_glsl[];
extern char datatoc_effect_subsurface_frag_glsl[];
+extern char datatoc_effect_translucency_frag_glsl[];
static void eevee_create_shader_subsurface(void)
{
@@ -46,16 +52,23 @@ static void eevee_create_shader_subsurface(void)
datatoc_common_uniforms_lib_glsl,
datatoc_effect_subsurface_frag_glsl);
+ /* TODO(fclem) remove some of these dependencies. */
+ char *frag_translucent_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_bsdf_sampling_lib_glsl,
+ datatoc_raytrace_lib_glsl,
+ datatoc_octahedron_lib_glsl,
+ datatoc_lights_lib_glsl,
+ datatoc_effect_translucency_frag_glsl);
+
e_data.sss_sh[0] = DRW_shader_create_fullscreen(frag_str, "#define FIRST_PASS\n");
e_data.sss_sh[1] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n");
- e_data.sss_sh[2] = DRW_shader_create_fullscreen(frag_str,
- "#define SECOND_PASS\n"
- "#define USE_SEP_ALBEDO\n");
- e_data.sss_sh[3] = DRW_shader_create_fullscreen(frag_str,
- "#define SECOND_PASS\n"
- "#define USE_SEP_ALBEDO\n"
- "#define RESULT_ACCUM\n");
+ e_data.sss_sh[2] = DRW_shader_create_fullscreen(frag_str, "#define RESULT_ACCUM\n");
+ e_data.sss_sh[3] = DRW_shader_create_fullscreen(frag_translucent_str,
+ "#define EEVEE_TRANSLUCENCY\n" SHADER_DEFINES);
+ MEM_freeN(frag_translucent_str);
MEM_freeN(frag_str);
}
@@ -69,7 +82,6 @@ void EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
effects->sss_sample_count = 1 + scene_eval->eevee.sss_samples * 2;
- effects->sss_separate_albedo = (scene_eval->eevee.flag & SCE_EEVEE_SSS_SEPARATE_ALBEDO) != 0;
common_data->sss_jitter_threshold = scene_eval->eevee.sss_jitter_threshold;
}
@@ -90,9 +102,13 @@ void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
effects->sss_stencil = DRW_texture_pool_query_2d(
fs_size[0], fs_size[1], GPU_DEPTH24_STENCIL8, &draw_engine_eevee_type);
effects->sss_blur = DRW_texture_pool_query_2d(
- fs_size[0], fs_size[1], GPU_RGBA16F, &draw_engine_eevee_type);
- effects->sss_data = DRW_texture_pool_query_2d(
- fs_size[0], fs_size[1], GPU_RGBA16F, &draw_engine_eevee_type);
+ fs_size[0], fs_size[1], GPU_R11F_G11F_B10F, &draw_engine_eevee_type);
+ effects->sss_irradiance = DRW_texture_pool_query_2d(
+ fs_size[0], fs_size[1], GPU_R11F_G11F_B10F, &draw_engine_eevee_type);
+ effects->sss_radius = DRW_texture_pool_query_2d(
+ fs_size[0], fs_size[1], GPU_R16F, &draw_engine_eevee_type);
+ effects->sss_albedo = DRW_texture_pool_query_2d(
+ fs_size[0], fs_size[1], GPU_R11F_G11F_B10F, &draw_engine_eevee_type);
GPUTexture *stencil_tex = effects->sss_stencil;
@@ -115,15 +131,13 @@ void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
{GPU_ATTACHMENT_TEXTURE(stencil_tex), GPU_ATTACHMENT_TEXTURE(txl->color)});
GPU_framebuffer_ensure_config(
- &fbl->sss_clear_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(effects->sss_data)});
+ &fbl->sss_translucency_fb,
+ {GPU_ATTACHMENT_TEXTURE(stencil_tex), GPU_ATTACHMENT_TEXTURE(effects->sss_irradiance)});
- if (effects->sss_separate_albedo) {
- effects->sss_albedo = DRW_texture_pool_query_2d(
- fs_size[0], fs_size[1], GPU_R11F_G11F_B10F, &draw_engine_eevee_type);
- }
- else {
- effects->sss_albedo = NULL;
- }
+ GPU_framebuffer_ensure_config(&fbl->sss_clear_fb,
+ {GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(effects->sss_irradiance),
+ GPU_ATTACHMENT_TEXTURE(effects->sss_radius)});
}
else {
/* Cleanup to release memory */
@@ -132,7 +146,8 @@ void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_clear_fb);
effects->sss_stencil = NULL;
effects->sss_blur = NULL;
- effects->sss_data = NULL;
+ effects->sss_irradiance = NULL;
+ effects->sss_radius = NULL;
}
}
@@ -202,6 +217,7 @@ void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
DRW_PASS_CREATE(psl->sss_blur_ps, state);
DRW_PASS_CREATE(psl->sss_resolve_ps, state | DRW_STATE_BLEND_ADD);
DRW_PASS_CREATE(psl->sss_accum_ps, state | DRW_STATE_BLEND_ADD);
+ DRW_PASS_CREATE(psl->sss_translucency_ps, state | DRW_STATE_BLEND_ADD);
}
void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata,
@@ -219,42 +235,66 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata,
DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[0], 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, "sssData", &effects->sss_data);
+ DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_irradiance);
+ DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius);
DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_stencil_mask(grp, sss_id);
DRW_shgroup_call(grp, quad, NULL);
- struct GPUShader *sh = (effects->sss_separate_albedo) ? e_data.sss_sh[2] : e_data.sss_sh[1];
- grp = DRW_shgroup_create(sh, psl->sss_resolve_ps);
+ grp = DRW_shgroup_create(e_data.sss_sh[1], 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, "sssData", &effects->sss_blur);
+ 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_block(grp, "sssProfile", sss_profile);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_stencil_mask(grp, sss_id);
DRW_shgroup_call(grp, quad, NULL);
- if (effects->sss_separate_albedo) {
- DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo);
- }
-
if (DRW_state_is_image_render()) {
- grp = DRW_shgroup_create(e_data.sss_sh[3], psl->sss_accum_ps);
+ grp = DRW_shgroup_create(e_data.sss_sh[2], psl->sss_accum_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, "sssData", &effects->sss_blur);
+ 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_block(grp, "sssProfile", sss_profile);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_stencil_mask(grp, sss_id);
DRW_shgroup_call(grp, quad, NULL);
-
- if (effects->sss_separate_albedo) {
- DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo);
- }
}
}
+void EEVEE_subsurface_translucency_add_pass(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ uint sss_id,
+ struct GPUUniformBuffer *sss_profile,
+ GPUTexture *sss_tex_profile)
+{
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
+ GPUTexture **depth_src = GPU_depth_blitting_workaround() ? &effects->sss_stencil : &dtxl->depth;
+
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[3], psl->sss_translucency_ps);
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_texture(grp, "sssTexProfile", sss_tex_profile);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
+ DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius);
+ DRW_shgroup_uniform_texture_ref(grp, "sssShadowCubes", &sldata->shadow_cube_pool);
+ DRW_shgroup_uniform_texture_ref(grp, "sssShadowCascades", &sldata->shadow_cascade_pool);
+ DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
+ DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_stencil_mask(grp, sss_id);
+ DRW_shgroup_call(grp, quad, NULL);
+}
+
void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
{
EEVEE_PassList *psl = vedata->psl;
@@ -273,7 +313,8 @@ void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat
GPU_ATTACHMENT_LEAVE,
GPU_ATTACHMENT_LEAVE,
GPU_ATTACHMENT_LEAVE,
- GPU_ATTACHMENT_TEXTURE(effects->sss_data),
+ GPU_ATTACHMENT_TEXTURE(effects->sss_irradiance),
+ GPU_ATTACHMENT_TEXTURE(effects->sss_radius),
GPU_ATTACHMENT_TEXTURE(effects->sss_albedo)});
GPU_framebuffer_bind(fbl->main_fb);
@@ -287,11 +328,12 @@ void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat
GPU_ATTACHMENT_LEAVE,
GPU_ATTACHMENT_LEAVE,
GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_NONE,
GPU_ATTACHMENT_NONE});
}
}
-void EEVEE_subsurface_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_StorageList *stl = vedata->stl;
@@ -313,6 +355,28 @@ void EEVEE_subsurface_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
GPU_framebuffer_blit(fbl->main_fb, 0, fbl->sss_blur_fb, 0, GPU_STENCIL_BIT);
}
+ if (!DRW_pass_is_empty(psl->sss_translucency_ps)) {
+ /* We sample the shadow-maps using normal sampler. We need to disable Comparison mode.
+ * TODO(fclem) avoid this by using sampler objects.*/
+ GPU_texture_bind(sldata->shadow_cube_pool, 0);
+ GPU_texture_compare_mode(sldata->shadow_cube_pool, false);
+ GPU_texture_unbind(sldata->shadow_cube_pool);
+ GPU_texture_bind(sldata->shadow_cascade_pool, 0);
+ GPU_texture_compare_mode(sldata->shadow_cascade_pool, false);
+ GPU_texture_unbind(sldata->shadow_cascade_pool);
+
+ GPU_framebuffer_bind(fbl->sss_translucency_fb);
+ DRW_draw_pass(psl->sss_translucency_ps);
+
+ /* Reset original state. */
+ GPU_texture_bind(sldata->shadow_cube_pool, 0);
+ GPU_texture_compare_mode(sldata->shadow_cube_pool, true);
+ GPU_texture_unbind(sldata->shadow_cube_pool);
+ GPU_texture_bind(sldata->shadow_cascade_pool, 0);
+ GPU_texture_compare_mode(sldata->shadow_cascade_pool, true);
+ GPU_texture_unbind(sldata->shadow_cascade_pool);
+ }
+
/* 1. horizontal pass */
GPU_framebuffer_bind(fbl->sss_blur_fb);
GPU_framebuffer_clear_color(fbl->sss_blur_fb, clear);
diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
index 96924efa8bc..e5f89aab4d1 100644
--- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
+++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
@@ -63,7 +63,7 @@ static void compute_cdf(float (*func)(float x), float cdf[FILTER_CDF_TABLE_SIZE]
{
cdf[0] = 0.0f;
/* Actual CDF evaluation. */
- for (int u = 0; u < FILTER_CDF_TABLE_SIZE - 1; ++u) {
+ for (int u = 0; u < FILTER_CDF_TABLE_SIZE - 1; u++) {
float x = (float)(u + 1) / (float)(FILTER_CDF_TABLE_SIZE - 1);
cdf[u + 1] = cdf[u] + func(x - 0.5f); /* [-0.5..0.5]. We resize later. */
}
@@ -80,7 +80,7 @@ static void invert_cdf(const float cdf[FILTER_CDF_TABLE_SIZE],
{
for (int u = 0; u < FILTER_CDF_TABLE_SIZE; u++) {
float x = (float)u / (float)(FILTER_CDF_TABLE_SIZE - 1);
- for (int i = 0; i < FILTER_CDF_TABLE_SIZE; ++i) {
+ for (int i = 0; i < FILTER_CDF_TABLE_SIZE; i++) {
if (cdf[i] >= x) {
if (i == FILTER_CDF_TABLE_SIZE - 1) {
invert_cdf[u] = 1.0f;
@@ -123,7 +123,7 @@ static void eevee_create_cdf_table_temporal_sampling(void)
invert_cdf(cdf_table, e_data.inverted_cdf);
/* Scale and offset table. */
- for (int i = 0; i < FILTER_CDF_TABLE_SIZE; ++i) {
+ for (int i = 0; i < FILTER_CDF_TABLE_SIZE; i++) {
e_data.inverted_cdf[i] = (e_data.inverted_cdf[i] - 0.5f) * filter_width;
}
diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c
index 7fb5c25ffc6..fac87bad41a 100644
--- a/source/blender/draw/engines/eevee/eevee_volumes.c
+++ b/source/blender/draw/engines/eevee/eevee_volumes.c
@@ -82,6 +82,8 @@ extern char datatoc_volumetric_integration_frag_glsl[];
extern char datatoc_volumetric_lib_glsl[];
extern char datatoc_common_fullscreen_vert_glsl[];
+#define USE_VOLUME_OPTI (GLEW_ARB_shader_image_load_store && GLEW_ARB_shading_language_420pack)
+
static void eevee_create_shader_volumes(void)
{
e_data.volumetric_common_lib = BLI_string_joinN(datatoc_common_view_lib_glsl,
@@ -123,7 +125,10 @@ static void eevee_create_shader_volumes(void)
datatoc_volumetric_geom_glsl,
datatoc_volumetric_integration_frag_glsl,
e_data.volumetric_common_lib,
- NULL);
+ USE_VOLUME_OPTI ? "#extension GL_ARB_shader_image_load_store: enable\n"
+ "#extension GL_ARB_shading_language_420pack: enable\n"
+ "#define USE_VOLUME_OPTI\n" :
+ NULL);
e_data.volumetric_resolve_sh = DRW_shader_create_with_lib(datatoc_common_fullscreen_vert_glsl,
NULL,
datatoc_volumetric_resolve_frag_glsl,
@@ -250,7 +255,7 @@ void EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
if (DRW_view_is_persp_get(NULL)) {
float sample_distribution = scene_eval->eevee.volumetric_sample_distribution;
- sample_distribution = 4.0f * (1.00001f - sample_distribution);
+ sample_distribution = 4.0f * (max_ff(1.0f - sample_distribution, 1e-2f));
const float clip_start = common_data->view_vecs[0][2];
/* Negate */
@@ -408,7 +413,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
DRWShadingGroup *grp = DRW_shgroup_material_create(mat, vedata->psl->volumetric_objects_ps);
- BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texcoloc, NULL, &texcosize);
+ BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texcoloc, &texcosize);
/* TODO(fclem) remove those "unnecessary" UBOs */
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
@@ -509,7 +514,8 @@ void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_shgroup_uniform_texture_ref(grp, "volumeExtinction", &txl->volume_transmit);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]);
+ DRW_shgroup_call_procedural_triangles(
+ grp, NULL, USE_VOLUME_OPTI ? 1 : common_data->vol_tex_size[2]);
DRW_PASS_CREATE(psl->volumetric_resolve_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM);
grp = DRW_shgroup_create(e_data.volumetric_resolve_sh, psl->volumetric_resolve_ps);
@@ -595,7 +601,7 @@ void EEVEE_volumes_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
effects->volume_transmit = e_data.dummy_transmit;
}
-void EEVEE_volumes_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+void EEVEE_volumes_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_TextureList *txl = vedata->txl;
@@ -605,6 +611,15 @@ void EEVEE_volumes_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda
if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) {
DRW_stats_group_start("Volumetrics");
+ /* We sample the shadow-maps using shadow sampler. We need to enable Comparison mode.
+ * TODO(fclem) avoid this by using sampler objects.*/
+ GPU_texture_bind(sldata->shadow_cube_pool, 0);
+ GPU_texture_compare_mode(sldata->shadow_cube_pool, true);
+ GPU_texture_unbind(sldata->shadow_cube_pool);
+ GPU_texture_bind(sldata->shadow_cascade_pool, 0);
+ GPU_texture_compare_mode(sldata->shadow_cascade_pool, true);
+ GPU_texture_unbind(sldata->shadow_cascade_pool);
+
GPU_framebuffer_bind(fbl->volumetric_fb);
DRW_draw_pass(psl->volumetric_world_ps);
DRW_draw_pass(psl->volumetric_objects_ps);
@@ -612,9 +627,31 @@ void EEVEE_volumes_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda
GPU_framebuffer_bind(fbl->volumetric_scat_fb);
DRW_draw_pass(psl->volumetric_scatter_ps);
- GPU_framebuffer_bind(fbl->volumetric_integ_fb);
+ if (USE_VOLUME_OPTI) {
+ int tex_scatter = GPU_texture_opengl_bindcode(txl->volume_scatter_history);
+ int tex_transmit = GPU_texture_opengl_bindcode(txl->volume_transmit_history);
+ /* TODO(fclem) Encapsulate these GL calls into DRWManager. */
+ glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
+ /* Subtlety here! we need to tell the GL that the texture is layered (GL_TRUE)
+ * in order to bind the full 3D texture and not just a 2D slice. */
+ glBindImageTexture(0, tex_scatter, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R11F_G11F_B10F);
+ glBindImageTexture(1, tex_transmit, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R11F_G11F_B10F);
+
+ GPU_framebuffer_bind(fbl->volumetric_fb);
+ }
+ else {
+ GPU_framebuffer_bind(fbl->volumetric_integ_fb);
+ }
+
DRW_draw_pass(psl->volumetric_integration_ps);
+ if (USE_VOLUME_OPTI) {
+ glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
+
+ glBindImageTexture(0, 0, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R11F_G11F_B10F);
+ glBindImageTexture(1, 0, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R11F_G11F_B10F);
+ }
+
SWAP(struct GPUFrameBuffer *, fbl->volumetric_scat_fb, fbl->volumetric_integ_fb);
SWAP(GPUTexture *, txl->volume_scatter, txl->volume_scatter_history);
SWAP(GPUTexture *, txl->volume_transmit, txl->volume_transmit_history);
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 7f795eaac2b..98012aea303 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -56,12 +56,12 @@ struct LightData {
#endif
struct ShadowData {
- vec4 near_far_bias_exp;
- vec4 shadow_data_start_end;
+ vec4 near_far_bias_id;
vec4 contact_shadow_data;
};
struct ShadowCubeData {
+ mat4 shadowmat;
vec4 position;
};
@@ -69,22 +69,20 @@ struct ShadowCascadeData {
mat4 shadowmat[MAX_CASCADE_NUM];
vec4 split_start_distances;
vec4 split_end_distances;
+ vec4 shadow_vec_id;
};
/* convenience aliases */
-#define sh_near near_far_bias_exp.x
-#define sh_far near_far_bias_exp.y
-#define sh_bias near_far_bias_exp.z
-#define sh_exp near_far_bias_exp.w
-#define sh_bleed near_far_bias_exp.w
-#define sh_tex_start shadow_data_start_end.x
-#define sh_data_start shadow_data_start_end.y
-#define sh_multi_nbr shadow_data_start_end.z
-#define sh_blur shadow_data_start_end.w
+#define sh_near near_far_bias_id.x
+#define sh_far near_far_bias_id.y
+#define sh_bias near_far_bias_id.z
+#define sh_data_index near_far_bias_id.w
#define sh_contact_dist contact_shadow_data.x
#define sh_contact_offset contact_shadow_data.y
#define sh_contact_spread contact_shadow_data.z
#define sh_contact_thickness contact_shadow_data.w
+#define sh_shadow_vec shadow_vec_id.xyz
+#define sh_tex_index shadow_vec_id.w
/* ------- Convenience functions --------- */
@@ -777,10 +775,9 @@ struct Closure {
vec3 transmittance;
float holdout;
# ifdef USE_SSS
- vec4 sss_data;
-# ifdef USE_SSS_ALBEDO
+ vec3 sss_irradiance;
vec3 sss_albedo;
-# endif
+ float sss_radius;
# endif
vec4 ssr_data;
vec2 ssr_normal;
@@ -796,13 +793,8 @@ Closure nodetree_exec(void); /* Prototype */
# define CLOSURE_HOLDOUT_FLAG 4
# ifdef USE_SSS
-# ifdef USE_SSS_ALBEDO
-# define CLOSURE_DEFAULT \
- Closure(vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec3(0.0), vec4(0.0), vec2(0.0), 0)
-# else
-# define CLOSURE_DEFAULT \
- Closure(vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec4(0.0), vec2(0.0), 0)
-# endif
+# define CLOSURE_DEFAULT \
+ Closure(vec3(0.0), vec3(0.0), 0.0, vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec2(0.0), 0)
# else
# define CLOSURE_DEFAULT Closure(vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec2(0.0), 0)
# endif
@@ -823,30 +815,22 @@ void closure_load_ssr_data(
}
}
-# ifdef USE_SSS
-void closure_load_sss_data(float radius,
- vec3 sss_radiance,
-# ifdef USE_SSS_ALBEDO
- vec3 sss_albedo,
-# endif
- int sss_id,
- inout Closure cl)
+void closure_load_sss_data(
+ float radius, vec3 sss_irradiance, vec3 sss_albedo, int sss_id, inout Closure cl)
{
+# ifdef USE_SSS
if (sss_id == outputSssId) {
- cl.sss_data = vec4(sss_radiance, radius);
-# ifdef USE_SSS_ALBEDO
+ cl.sss_irradiance = sss_irradiance;
+ cl.sss_radius = radius;
cl.sss_albedo = sss_albedo;
-# endif
cl.flag |= CLOSURE_SSS_FLAG;
}
- else {
- cl.radiance += sss_radiance;
-# ifdef USE_SSS_ALBEDO
- cl.radiance += sss_radiance * sss_albedo;
-# endif
+ else
+# endif
+ {
+ cl.radiance += sss_irradiance * sss_albedo;
}
}
-# endif
Closure closure_mix(Closure cl1, Closure cl2, float fac)
{
@@ -862,13 +846,11 @@ Closure closure_mix(Closure cl1, Closure cl2, float fac)
cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal;
# ifdef USE_SSS
- cl.sss_data = mix(cl1.sss_data, cl2.sss_data, fac);
+ cl.sss_albedo = mix(cl1.sss_albedo, cl2.sss_albedo, fac);
bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG);
- /* It also does not make sense to mix SSS radius or albedo. */
- cl.sss_data.w = (use_cl1_sss) ? cl1.sss_data.w : cl2.sss_data.w;
-# ifdef USE_SSS_ALBEDO
- cl.sss_albedo = (use_cl1_sss) ? cl1.sss_albedo : cl2.sss_albedo;
-# endif
+ /* It also does not make sense to mix SSS radius or irradiance. */
+ cl.sss_radius = (use_cl1_sss) ? cl1.sss_radius : cl2.sss_radius;
+ cl.sss_irradiance = (use_cl1_sss) ? cl1.sss_irradiance : cl2.sss_irradiance;
# endif
return cl;
}
@@ -887,13 +869,11 @@ Closure closure_add(Closure cl1, Closure cl2)
cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal;
# ifdef USE_SSS
- cl.sss_data = cl1.sss_data + cl2.sss_data;
+ cl.sss_albedo = cl1.sss_albedo + cl2.sss_albedo;
bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG);
- /* It also does not make sense to mix SSS radius or albedo. */
- cl.sss_data.w = (use_cl1_sss) ? cl1.sss_data.w : cl2.sss_data.w;
-# ifdef USE_SSS_ALBEDO
- cl.sss_albedo = (use_cl1_sss) ? cl1.sss_albedo : cl2.sss_albedo;
-# endif
+ /* It also does not make sense to mix SSS radius or irradiance. */
+ cl.sss_radius = (use_cl1_sss) ? cl1.sss_radius : cl2.sss_radius;
+ cl.sss_irradiance = (use_cl1_sss) ? cl1.sss_irradiance : cl2.sss_irradiance;
# endif
return cl;
}
@@ -914,10 +894,9 @@ layout(location = 0) out vec4 outRadiance;
layout(location = 1) out vec2 ssrNormals;
layout(location = 2) out vec4 ssrData;
# ifdef USE_SSS
-layout(location = 3) out vec4 sssData;
-# ifdef USE_SSS_ALBEDO
-layout(location = 4) out vec4 sssAlbedo;
-# endif
+layout(location = 3) out vec3 sssIrradiance;
+layout(location = 4) out float sssRadius;
+layout(location = 5) out vec3 sssAlbedo;
# endif
# else /* USE_ALPHA_BLEND */
/* Use dual source blending to be able to make a whole range of effects. */
@@ -953,10 +932,9 @@ void main()
ssrNormals = cl.ssr_normal;
ssrData = cl.ssr_data;
# ifdef USE_SSS
- sssData = cl.sss_data;
-# ifdef USE_SSS_ALBEDO
- sssAlbedo = cl.sss_albedo.rgbb;
-# endif
+ sssIrradiance = cl.sss_irradiance;
+ sssRadius = cl.sss_radius;
+ sssAlbedo = cl.sss_albedo;
# endif
# endif
@@ -964,6 +942,8 @@ void main()
# ifdef USE_SSS
float fac = float(!sssToggle);
+ /* TODO(fclem) we shouldn't need this.
+ * Just disable USE_SSS when USE_REFRACTION is enabled. */
# ifdef USE_REFRACTION
/* SSRefraction pass is done after the SSS pass.
* In order to not loose the diffuse light totally we
@@ -971,11 +951,7 @@ void main()
fac = 1.0;
# endif
-# ifdef USE_SSS_ALBEDO
- outRadiance.rgb += cl.sss_data.rgb * cl.sss_albedo.rgb * fac;
-# else
- outRadiance.rgb += cl.sss_data.rgb * fac;
-# endif
+ outRadiance.rgb += cl.sss_irradiance.rgb * cl.sss_albedo.rgb * fac;
# endif
}
diff --git a/source/blender/draw/engines/eevee/shaders/default_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_frag.glsl
index 1f60661d234..ca06d458f6e 100644
--- a/source/blender/draw/engines/eevee/shaders/default_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/default_frag.glsl
@@ -31,7 +31,7 @@ Closure nodetree_exec(void)
vec3 f0 = mix(dielectric, basecol, metallic);
vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic);
vec3 out_diff, out_spec, ssr_spec;
- eevee_closure_default(N, albedo, f0, f90, 1, roughness, 1.0, out_diff, out_spec, ssr_spec);
+ eevee_closure_default(N, albedo, f0, f90, 1, roughness, 1.0, true, out_diff, out_spec, ssr_spec);
Closure cl = CLOSURE_DEFAULT;
cl.radiance = out_spec + out_diff * albedo;
diff --git a/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl
index 70466479a29..41e103609f3 100644
--- a/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl
@@ -8,6 +8,7 @@ out vec4 FragColor;
uniform mat3 StudioLightMatrix;
uniform sampler2D image;
uniform float studioLightBackground = 1.0;
+uniform float studioLightIntensity = 1.0;
in vec3 viewPosition;
# define M_PI 3.14159265358979323846
@@ -51,6 +52,7 @@ void main()
#ifdef LOOKDEV
vec3 worldvec = background_transform_to_world(viewPosition);
background_color = node_tex_environment_equirectangular(StudioLightMatrix * worldvec, image).rgb;
+ background_color *= studioLightIntensity;
background_color = mix(color, background_color, studioLightBackground);
#else
background_color = color;
diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
index 44f22848c2f..598cc3e5183 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
@@ -147,7 +147,7 @@ void main()
make_orthonormal_basis(N, T, B); /* Generate tangent space */
/* Planar Reflections */
- for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; ++i) {
+ for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) {
PlanarData pd = planars_data[i];
float fade = probe_attenuation_planar(pd, worldPosition, wN, 0.0);
@@ -504,7 +504,7 @@ void main()
/* Find Planar Reflections affecting this pixel */
PlanarData pd;
float planar_index;
- for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; ++i) {
+ for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) {
pd = planars_data[i];
float fade = probe_attenuation_planar(pd, worldPosition, N, 0.0);
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 4260c601543..1241cf0e387 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
@@ -10,7 +10,8 @@ layout(std140) uniform sssProfile
};
uniform sampler2D depthBuffer;
-uniform sampler2D sssData;
+uniform sampler2D sssIrradiance;
+uniform sampler2D sssRadius;
uniform sampler2D sssAlbedo;
#ifndef UTIL_TEX
@@ -19,9 +20,12 @@ uniform sampler2DArray utilTex;
# define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
#endif /* UTIL_TEX */
-layout(location = 0) out vec4 FragColor;
#ifdef RESULT_ACCUM
+/* Render Passes Accumulation */
+layout(location = 0) out vec4 sssDirect;
layout(location = 1) out vec4 sssColor;
+#else
+layout(location = 0) out vec4 sssRadiance;
#endif
float get_view_z_from_depth(float depth)
@@ -43,7 +47,8 @@ void main(void)
{
vec2 pixel_size = 1.0 / vec2(textureSize(depthBuffer, 0).xy); /* TODO precompute */
vec2 uvs = gl_FragCoord.xy * pixel_size;
- vec4 sss_data = texture(sssData, uvs).rgba;
+ vec3 sss_irradiance = texture(sssIrradiance, uvs).rgb;
+ float sss_radius = texture(sssRadius, uvs).r;
float depth_view = get_view_z_from_depth(texture(depthBuffer, uvs).r);
float rand = texelfetch_noise_tex(gl_FragCoord.xy).r;
@@ -58,44 +63,36 @@ 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_data.aa / homcoord;
+ 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 */
/* Center sample */
- vec3 accum = sss_data.rgb * kernel[0].rgb;
+ vec3 accum = sss_irradiance * kernel[0].rgb;
for (int i = 1; i < sss_samples && i < MAX_SSS_SAMPLES; i++) {
vec2 sample_uv = uvs + kernel[i].a * finalStep *
((abs(kernel[i].a) > sssJitterThreshold) ? dir : dir_rand);
- vec3 color = texture(sssData, sample_uv).rgb;
+ 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_data.a)), 0.0, 1.0);
-
+ float s = clamp(1.0 - exp(-(depth_delta * depth_delta) / (2.0 * sss_radius)), 0.0, 1.0);
/* Out of view samples. */
if (any(lessThan(sample_uv, vec2(0.0))) || any(greaterThan(sample_uv, vec2(1.0)))) {
s = 1.0;
}
-
- accum += kernel[i].rgb * mix(color, sss_data.rgb, s);
+ /* Mix with first sample in failure case and apply kernel color. */
+ accum += kernel[i].rgb * mix(color, sss_irradiance, s);
}
-#ifdef FIRST_PASS
- FragColor = vec4(accum, sss_data.a);
+#ifdef RESULT_ACCUM
+ sssDirect = vec4(accum, 1.0);
+ sssColor = vec4(texture(sssAlbedo, uvs).rgb, 1.0);
+#elif defined(FIRST_PASS)
+ sssRadiance = vec4(accum, 1.0);
#else /* SECOND_PASS */
-# ifdef USE_SEP_ALBEDO
-# ifdef RESULT_ACCUM
- FragColor = vec4(accum, 1.0);
- sssColor = texture(sssAlbedo, uvs);
-# else
- FragColor = vec4(accum * texture(sssAlbedo, uvs).rgb, 1.0);
-# endif
-# else
- FragColor = vec4(accum, 1.0);
-# endif
+ sssRadiance = vec4(accum * texture(sssAlbedo, uvs).rgb, 1.0);
#endif
}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl
new file mode 100644
index 00000000000..86f53522bc6
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl
@@ -0,0 +1,165 @@
+
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+uniform sampler1D sssTexProfile;
+uniform sampler2D sssRadius;
+
+uniform sampler2DArray sssShadowCubes;
+uniform sampler2DArray sssShadowCascades;
+
+#define MAX_SSS_SAMPLES 65
+#define SSS_LUT_SIZE 64.0
+#define SSS_LUT_SCALE ((SSS_LUT_SIZE - 1.0) / float(SSS_LUT_SIZE))
+#define SSS_LUT_BIAS (0.5 / float(SSS_LUT_SIZE))
+
+layout(std140) uniform sssProfile
+{
+ vec4 kernel[MAX_SSS_SAMPLES];
+ vec4 radii_max_radius;
+ int sss_samples;
+};
+
+vec3 sss_profile(float s)
+{
+ s /= radii_max_radius.w;
+ return texture(sssTexProfile, saturate(s) * SSS_LUT_SCALE + SSS_LUT_BIAS).rgb;
+}
+
+#ifndef UTIL_TEX
+# define UTIL_TEX
+uniform sampler2DArray utilTex;
+# define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
+#endif /* UTIL_TEX */
+
+float light_translucent_power_with_falloff(LightData ld, vec3 N, vec4 l_vector)
+{
+ float power, falloff;
+ /* XXX : Removing Area Power. */
+ /* TODO : put this out of the shader. */
+ if (ld.l_type >= AREA_RECT) {
+ power = (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0);
+ if (ld.l_type == AREA_ELLIPSE) {
+ power *= M_PI * 0.25;
+ }
+ power *= 0.3 * 20.0 *
+ max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */
+ power /= (l_vector.w * l_vector.w);
+ falloff = dot(N, l_vector.xyz / l_vector.w);
+ }
+ else if (ld.l_type == SUN) {
+ power = 1.0 / (1.0 + (ld.l_radius * ld.l_radius * 0.5));
+ power *= ld.l_radius * ld.l_radius * M_PI; /* Removing area light power*/
+ power *= M_2PI * 0.78; /* Matching cycles with point light. */
+ power *= 0.082; /* XXX ad hoc, empirical */
+ falloff = dot(N, -ld.l_forward);
+ }
+ else {
+ power = (4.0 * ld.l_radius * ld.l_radius) * (1.0 / 10.0);
+ power *= 1.5; /* XXX ad hoc, empirical */
+ power /= (l_vector.w * l_vector.w);
+ falloff = dot(N, l_vector.xyz / l_vector.w);
+ }
+ /* No transmittance at grazing angle (hide artifacts) */
+ return power * saturate(falloff * 2.0);
+}
+
+/* Some driver poorly optimize this code. Use direct reference to matrices. */
+#define sd(x) shadows_data[x]
+#define scube(x) shadows_cube_data[x]
+#define scascade(x) shadows_cascade_data[x]
+
+vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, vec2 rand, float sss_scale)
+{
+ int shadow_id = int(ld.l_shadowid);
+
+ vec4 L = (ld.l_type != SUN) ? l_vector : vec4(-ld.l_forward, 1.0);
+
+ /* We use the full l_vector.xyz so that the spread is minimize
+ * if the shading point is further away from the light source */
+ /* TODO(fclem) do something better than this. */
+ // vec3 T, B;
+ // make_orthonormal_basis(L.xyz / L.w, T, B);
+ // rand.xy *= data.sh_blur;
+ // W = W + T * rand.x + B * rand.y;
+
+ float s, dist;
+ int data_id = int(sd(shadow_id).sh_data_index);
+ if (ld.l_type == SUN) {
+ vec4 view_z = vec4(dot(W - cameraPos, cameraForward));
+
+ vec4 weights = step(scascade(data_id).split_end_distances, view_z);
+ float id = abs(4.0 - dot(weights, weights));
+ if (id > 3.0) {
+ return vec3(0.0);
+ }
+
+ /* Same factor as in get_cascade_world_distance(). */
+ float range = abs(sd(shadow_id).sh_far - sd(shadow_id).sh_near);
+
+ vec4 shpos = scascade(data_id).shadowmat[int(id)] * vec4(W, 1.0);
+ dist = shpos.z * range;
+
+ if (shpos.z > 1.0 || shpos.z < 0.0) {
+ return vec3(0.0);
+ }
+
+ float tex_id = scascade(data_id).sh_tex_index;
+ s = sample_cascade(sssShadowCascades, shpos.xy, tex_id + id).r;
+ s *= range;
+ }
+ else {
+ vec3 cubevec = transform_point(scube(data_id).shadowmat, W);
+ dist = length(cubevec);
+ cubevec /= dist;
+ /* tex_id == data_id for cube shadowmap */
+ float tex_id = float(data_id);
+ s = sample_cube(sssShadowCubes, cubevec, tex_id).r;
+ s = length(cubevec / max_v3(abs(cubevec))) *
+ linear_depth(true, s, sd(shadow_id).sh_far, sd(shadow_id).sh_near);
+ }
+ float delta = dist - s;
+
+ float power = light_translucent_power_with_falloff(ld, N, l_vector);
+
+ return power * sss_profile(abs(delta) / sss_scale);
+}
+
+#undef sd
+#undef scube
+#undef scsmd
+
+void main(void)
+{
+ vec2 uvs = uvcoordsvar.xy;
+ float sss_scale = texture(sssRadius, uvs).r;
+ vec3 W = get_world_space_from_depth(uvs, texture(depthBuffer, uvs).r);
+ vec3 N = normalize(cross(dFdx(W), dFdy(W)));
+
+ vec3 rand = texelfetch_noise_tex(gl_FragCoord.xy).zwy;
+ rand.xy *= fast_sqrt(rand.z);
+
+ vec3 accum = vec3(0.0);
+ for (int i = 0; i < MAX_LIGHT && i < laNumLight; i++) {
+ LightData ld = lights_data[i];
+
+ /* Only shadowed light can produce translucency */
+ if (ld.l_shadowid < 0.0) {
+ continue;
+ }
+
+ vec4 l_vector; /* Non-Normalized Light Vector with length in last component. */
+ l_vector.xyz = ld.l_position - W;
+ l_vector.w = length(l_vector.xyz);
+
+ float att = light_attenuation(ld, l_vector);
+ if (att < 1e-8) {
+ continue;
+ }
+
+ accum += att * ld.l_color * light_translucent(ld, W, -N, l_vector, rand.xy, sss_scale);
+ }
+
+ FragColor = vec4(accum, 1.0);
+}
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 37b02a2130f..296c1581545 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
@@ -64,7 +64,7 @@ void main()
float weight_accum = 0.0;
vec3 sh = vec3(0.0);
- for (int face = 0; face < 6; ++face) {
+ for (int face = 0; face < 6; face++) {
for (float x = halfpix; x < 1.0; x += pixstep) {
for (float y = halfpix; y < 1.0; y += pixstep) {
float weight, coef;
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl
index e10cb5f4999..f8bc1703c66 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl
@@ -37,7 +37,7 @@ void main()
fFace = face[0];
gl_Layer = Layer + fFace;
- for (int v = 0; v < 3; ++v) {
+ for (int v = 0; v < 3; v++) {
gl_Position = vPos[v];
worldPosition = x_axis[fFace] * vPos[v].x + y_axis[fFace] * vPos[v].y + maj_axes[fFace];
#ifdef USE_ATTR
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
index 56c05e3c036..ab205b78274 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
@@ -233,7 +233,7 @@ void fallback_cubemap(vec3 N,
#endif
/* Starts at 1 because 0 is world probe */
- for (int i = 1; i < MAX_PROBE && i < prbNumRenderCube && spec_accum.a < 0.999; ++i) {
+ for (int i = 1; i < MAX_PROBE && i < prbNumRenderCube && spec_accum.a < 0.999; i++) {
float fade = probe_attenuation_cube(i, W);
if (fade > 0.0) {
@@ -262,7 +262,7 @@ vec3 probe_evaluate_grid(GridData gd, vec3 W, vec3 N, vec3 localpos)
vec3 irradiance_accum = vec3(0.0);
/* For each neighbor cells */
- for (int i = 0; i < 8; ++i) {
+ for (int i = 0; i < 8; i++) {
ivec3 offset = ivec3(i, i >> 1, i >> 2) & ivec3(1);
vec3 cell_cos = clamp(localpos_floored + vec3(offset), vec3(0.0), vec3(gd.g_resolution) - 1.0);
diff --git a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
index c3643cccbfc..b1c78cae54f 100644
--- a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
@@ -1,6 +1,6 @@
-uniform sampler2DArray shadowCubeTexture;
-uniform sampler2DArray shadowCascadeTexture;
+uniform sampler2DArrayShadow shadowCubeTexture;
+uniform sampler2DArrayShadow shadowCascadeTexture;
#define LAMPS_LIB
@@ -24,129 +24,115 @@ layout(std140) uniform light_block
/* Used to define the area light shape, doesn't directly correspond to a Blender light type. */
#define AREA_ELLIPSE 100.0
-#if defined(SHADOW_VSM)
-# define ShadowSample vec2
-# define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).rg
-# define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).rg
-#elif defined(SHADOW_ESM)
-# define ShadowSample float
-# define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).r
-# define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).r
-#else
-# define ShadowSample float
-# define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).r
-# define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).r
-#endif
-
-#if defined(SHADOW_VSM)
-# define get_depth_delta(dist, s) (dist - s.x)
-#else
-# define get_depth_delta(dist, s) (dist - s)
-#endif
-
- /* ----------------------------------------------------------- */
- /* ----------------------- Shadow tests ---------------------- */
- /* ----------------------------------------------------------- */
-
-#if defined(SHADOW_VSM)
-
-float shadow_test(ShadowSample moments, float dist, ShadowData sd)
+float cubeFaceIndexEEVEE(vec3 P)
{
- float p = 0.0;
-
- if (dist <= moments.x) {
- p = 1.0;
+ vec3 aP = abs(P);
+ if (all(greaterThan(aP.xx, aP.yz))) {
+ return (P.x > 0.0) ? 0.0 : 1.0;
+ }
+ else if (all(greaterThan(aP.yy, aP.xz))) {
+ return (P.y > 0.0) ? 2.0 : 3.0;
+ }
+ else {
+ return (P.z > 0.0) ? 4.0 : 5.0;
}
-
- float variance = moments.y - (moments.x * moments.x);
- variance = max(variance, sd.sh_bias / 10.0);
-
- float d = moments.x - dist;
- float p_max = variance / (variance + d * d);
-
- /* Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1] */
- p_max = clamp((p_max - sd.sh_bleed) / (1.0 - sd.sh_bleed), 0.0, 1.0);
-
- return max(p, p_max);
}
-#elif defined(SHADOW_ESM)
-
-float shadow_test(ShadowSample z, float dist, ShadowData sd)
+vec2 cubeFaceCoordEEVEE(vec3 P, float face, float scale)
{
- return saturate(exp(sd.sh_exp * (z - dist + sd.sh_bias)));
+ if (face < 2.0) {
+ return (P.zy / P.x) * scale * vec2(-0.5, -sign(P.x) * 0.5) + 0.5;
+ }
+ else if (face < 4.0) {
+ return (P.xz / P.y) * scale * vec2(sign(P.y) * 0.5, 0.5) + 0.5;
+ }
+ else {
+ return (P.xy / P.z) * scale * vec2(0.5, -sign(P.z) * 0.5) + 0.5;
+ }
}
-#else
-
-float shadow_test(ShadowSample z, float dist, ShadowData sd)
+vec2 cubeFaceCoordEEVEE(vec3 P, float face, sampler2DArray tex)
{
- return step(0, z - dist + sd.sh_bias);
+ /* Scaling to compensate the 1px border around the face. */
+ float cube_res = float(textureSize(tex, 0).x);
+ float scale = (cube_res) / (cube_res + 1.0);
+ return cubeFaceCoordEEVEE(P, face, scale);
}
-#endif
-
-/* ----------------------------------------------------------- */
-/* ----------------------- Shadow types ---------------------- */
-/* ----------------------------------------------------------- */
-
-float shadow_cubemap(ShadowData sd, ShadowCubeData scd, float texid, vec3 W)
+vec2 cubeFaceCoordEEVEE(vec3 P, float face, sampler2DArrayShadow tex)
{
- vec3 cubevec = W - scd.position.xyz;
- float dist = length(cubevec);
+ /* Scaling to compensate the 1px border around the face. */
+ float cube_res = float(textureSize(tex, 0).x);
+ float scale = (cube_res) / (cube_res + 1.0);
+ return cubeFaceCoordEEVEE(P, face, scale);
+}
- cubevec /= dist;
+vec4 sample_cube(sampler2DArray tex, vec3 cubevec, float cube)
+{
+ /* Manual Shadow Cube Layer indexing. */
+ /* TODO Shadow Cube Array. */
+ float face = cubeFaceIndexEEVEE(cubevec);
+ vec2 uv = cubeFaceCoordEEVEE(cubevec, face, tex);
- ShadowSample s = sample_cube(cubevec, texid);
- return shadow_test(s, dist, sd);
+ vec3 coord = vec3(uv, cube * 6.0 + face);
+ return texture(tex, coord);
}
-float evaluate_cascade(ShadowData sd, mat4 shadowmat, vec3 W, float range, float texid)
+vec4 sample_cascade(sampler2DArray tex, vec2 co, float cascade_id)
{
- vec4 shpos = shadowmat * vec4(W, 1.0);
- float dist = shpos.z * range;
+ return texture(tex, vec3(co, cascade_id));
+}
- ShadowSample s = sample_cascade(shpos.xy, texid);
- float vis = shadow_test(s, dist, sd);
+/* Some driver poorly optimize this code. Use direct reference to matrices. */
+#define sd(x) shadows_data[x]
+#define scube(x) shadows_cube_data[x]
+#define scascade(x) shadows_cascade_data[x]
- /* If fragment is out of shadowmap range, do not occlude */
- if (shpos.z < 1.0 && shpos.z > 0.0) {
- return vis;
- }
- else {
- return 1.0;
- }
+float sample_cube_shadow(int shadow_id, vec3 W)
+{
+ int data_id = int(sd(shadow_id).sh_data_index);
+ vec3 cubevec = transform_point(scube(data_id).shadowmat, W);
+ float dist = max(sd(shadow_id).sh_near, max_v3(abs(cubevec)) - sd(shadow_id).sh_bias);
+ dist = buffer_depth(true, dist, sd(shadow_id).sh_far, sd(shadow_id).sh_near);
+ /* Manual Shadow Cube Layer indexing. */
+ /* TODO Shadow Cube Array. */
+ float face = cubeFaceIndexEEVEE(cubevec);
+ vec2 coord = cubeFaceCoordEEVEE(cubevec, face, shadowCubeTexture);
+ /* tex_id == data_id for cube shadowmap */
+ float tex_id = float(data_id);
+ return texture(shadowCubeTexture, vec4(coord, tex_id * 6.0 + face, dist));
}
-float shadow_cascade(ShadowData sd, int scd_id, float texid, vec3 W)
+float sample_cascade_shadow(int shadow_id, vec3 W)
{
+ int data_id = int(sd(shadow_id).sh_data_index);
+ float tex_id = scascade(data_id).sh_tex_index;
vec4 view_z = vec4(dot(W - cameraPos, cameraForward));
- vec4 weights = smoothstep(shadows_cascade_data[scd_id].split_end_distances,
- shadows_cascade_data[scd_id].split_start_distances.yzwx,
- view_z);
-
- weights.yzw -= weights.xyz;
-
- vec4 vis = vec4(1.0);
- float range = abs(sd.sh_far - sd.sh_near); /* Same factor as in get_cascade_world_distance(). */
-
- /* Branching using (weights > 0.0) is reaally slooow on intel so avoid it for now. */
- /* TODO OPTI: Only do 2 samples and blend. */
- vis.x = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[0], W, range, texid + 0);
- vis.y = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[1], W, range, texid + 1);
- vis.z = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[2], W, range, texid + 2);
- vis.w = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[3], W, range, texid + 3);
-
- float weight_sum = dot(vec4(1.0), weights);
- if (weight_sum > 0.9999) {
- float vis_sum = dot(vec4(1.0), vis * weights);
- return vis_sum / weight_sum;
- }
- else {
- float vis_sum = dot(vec4(1.0), vis * step(0.001, weights));
- return mix(1.0, vis_sum, weight_sum);
- }
+ vec4 weights = 1.0 - smoothstep(scascade(data_id).split_end_distances,
+ scascade(data_id).split_start_distances.yzwx,
+ view_z);
+ float tot_weight = dot(weights.xyz, vec3(1.0));
+
+ int cascade = int(clamp(tot_weight, 0.0, 3.0));
+ float blend = fract(tot_weight);
+ float vis = weights.w;
+ vec4 coord, shpos;
+ /* Main cascade. */
+ shpos = scascade(data_id).shadowmat[cascade] * vec4(W, 1.0);
+ coord = vec4(shpos.xy, tex_id + float(cascade), shpos.z - sd(shadow_id).sh_bias);
+ vis += texture(shadowCascadeTexture, coord) * (1.0 - blend);
+
+ cascade = min(3, cascade + 1);
+ /* Second cascade. */
+ shpos = scascade(data_id).shadowmat[cascade] * vec4(W, 1.0);
+ coord = vec4(shpos.xy, tex_id + float(cascade), shpos.z - sd(shadow_id).sh_bias);
+ vis += texture(shadowCascadeTexture, coord) * blend;
+
+ return saturate(vis);
}
+#undef sd
+#undef scube
+#undef scsmd
/* ----------------------------------------------------------- */
/* --------------------- Light Functions --------------------- */
@@ -173,16 +159,9 @@ float spot_attenuation(LightData ld, vec3 l_vector)
return spotmask;
}
-float light_visibility(LightData ld,
- vec3 W,
-#ifndef VOLUMETRICS
- vec3 viewPosition,
- vec3 vN,
-#endif
- vec4 l_vector)
+float light_attenuation(LightData ld, vec4 l_vector)
{
float vis = 1.0;
-
if (ld.l_type == SPOT) {
vis *= spot_attenuation(ld, l_vector.xyz);
}
@@ -192,69 +171,66 @@ float light_visibility(LightData ld,
if (ld.l_type != SUN) {
vis *= distance_attenuation(l_vector.w * l_vector.w, ld.l_influence);
}
+ return vis;
+}
+
+float light_visibility(LightData ld,
+ vec3 W,
+#ifndef VOLUMETRICS
+ vec3 viewPosition,
+ float tracing_depth,
+ vec3 true_normal,
+ float rand_x,
+ const bool use_contact_shadows,
+#endif
+ vec4 l_vector)
+{
+ float vis = light_attenuation(ld, l_vector);
#if !defined(VOLUMETRICS) || defined(VOLUME_SHADOW)
/* shadowing */
if (ld.l_shadowid >= 0.0 && vis > 0.001) {
- ShadowData data = shadows_data[int(ld.l_shadowid)];
if (ld.l_type == SUN) {
- vis *= shadow_cascade(data, int(data.sh_data_start), data.sh_tex_start, W);
+ vis *= sample_cascade_shadow(int(ld.l_shadowid), W);
}
else {
- vis *= shadow_cubemap(
- data, shadows_cube_data[int(data.sh_data_start)], data.sh_tex_start, W);
+ vis *= sample_cube_shadow(int(ld.l_shadowid), W);
}
# ifndef VOLUMETRICS
+ ShadowData sd = shadows_data[int(ld.l_shadowid)];
/* Only compute if not already in shadow. */
- if (data.sh_contact_dist > 0.0) {
- vec4 L = (ld.l_type != SUN) ? l_vector : vec4(-ld.l_forward, 1.0);
- float trace_distance = (ld.l_type != SUN) ? min(data.sh_contact_dist, l_vector.w) :
- data.sh_contact_dist;
-
- vec3 T, B;
- make_orthonormal_basis(L.xyz / L.w, T, B);
-
- vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
- rand.zw *= fast_sqrt(rand.y) * data.sh_contact_spread;
-
- /* We use the full l_vector.xyz so that the spread is minimize
- * if the shading point is further away from the light source */
- vec3 ray_dir = L.xyz + T * rand.z + B * rand.w;
- ray_dir = transform_direction(ViewMatrix, ray_dir);
- ray_dir = normalize(ray_dir);
-
- vec3 ray_ori = viewPosition;
-
- /* Fix translucency shadowed by contact shadows. */
- vN = (gl_FrontFacing) ? vN : -vN;
-
- if (dot(vN, ray_dir) <= 0.0) {
- return vis;
+ if (use_contact_shadows && sd.sh_contact_dist > 0.0 && vis > 1e-8) {
+ /* Contact Shadows. */
+ vec3 ray_ori, ray_dir;
+ float trace_distance;
+
+ 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;
+ }
+ else {
+ ray_dir = shadows_cube_data[int(sd.sh_data_index)].position.xyz - W;
+ float len = length(ray_dir);
+ trace_distance = min(sd.sh_contact_dist, len);
+ ray_dir *= trace_distance / len;
}
- float bias = 0.5; /* Constant Bias */
- bias += 1.0 - abs(dot(vN, ray_dir)); /* Angle dependent bias */
- bias *= gl_FrontFacing ? data.sh_contact_offset : -data.sh_contact_offset;
-
- vec3 nor_bias = vN * bias;
- ray_ori += nor_bias;
-
- ray_dir *= trace_distance;
- ray_dir -= nor_bias;
+ ray_dir = transform_direction(ViewMatrix, ray_dir);
+ ray_ori = vec3(viewPosition.xy, tracing_depth) + true_normal * sd.sh_contact_offset;
vec3 hit_pos = raycast(
- -1, ray_ori, ray_dir, data.sh_contact_thickness, rand.x, 0.1, 0.001, false);
+ -1, ray_ori, ray_dir, sd.sh_contact_thickness, rand_x, 0.1, 0.001, false);
if (hit_pos.z > 0.0) {
hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z);
float hit_dist = distance(viewPosition, hit_pos);
float dist_ratio = hit_dist / trace_distance;
- return vis * saturate(dist_ratio * dist_ratio * dist_ratio);
+ return vis * saturate(dist_ratio * 3.0 - 2.0);
}
}
-# endif
+# endif /* VOLUMETRICS */
}
#endif
@@ -325,134 +301,3 @@ float light_specular(LightData ld, vec4 ltc_mat, vec3 N, vec3 V, vec4 l_vector)
}
}
#endif
-
-#define MAX_SSS_SAMPLES 65
-#define SSS_LUT_SIZE 64.0
-#define SSS_LUT_SCALE ((SSS_LUT_SIZE - 1.0) / float(SSS_LUT_SIZE))
-#define SSS_LUT_BIAS (0.5 / float(SSS_LUT_SIZE))
-
-#ifdef USE_TRANSLUCENCY
-layout(std140) uniform sssProfile
-{
- vec4 kernel[MAX_SSS_SAMPLES];
- vec4 radii_max_radius;
- int sss_samples;
-};
-
-uniform sampler1D sssTexProfile;
-
-vec3 sss_profile(float s)
-{
- s /= radii_max_radius.w;
- return texture(sssTexProfile, saturate(s) * SSS_LUT_SCALE + SSS_LUT_BIAS).rgb;
-}
-#endif
-
-vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale)
-{
-#if !defined(USE_TRANSLUCENCY) || defined(VOLUMETRICS)
- return vec3(0.0);
-#else
- vec3 vis = vec3(1.0);
-
- if (ld.l_type == SPOT) {
- vis *= spot_attenuation(ld, l_vector.xyz);
- }
- if (ld.l_type >= SPOT) {
- vis *= step(0.0, -dot(l_vector.xyz, ld.l_forward));
- }
- if (ld.l_type != SUN) {
- vis *= distance_attenuation(l_vector.w * l_vector.w, ld.l_influence);
- }
-
- /* Only shadowed light can produce translucency */
- if (ld.l_shadowid >= 0.0 && vis.x > 0.001) {
- ShadowData data = shadows_data[int(ld.l_shadowid)];
- float delta;
-
- vec4 L = (ld.l_type != SUN) ? l_vector : vec4(-ld.l_forward, 1.0);
-
- vec3 T, B;
- make_orthonormal_basis(L.xyz / L.w, T, B);
-
- vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
- rand.zw *= fast_sqrt(rand.y) * data.sh_blur;
-
- /* We use the full l_vector.xyz so that the spread is minimize
- * if the shading point is further away from the light source */
- W = W + T * rand.z + B * rand.w;
-
- if (ld.l_type == SUN) {
- int scd_id = int(data.sh_data_start);
- vec4 view_z = vec4(dot(W - cameraPos, cameraForward));
-
- vec4 weights = step(shadows_cascade_data[scd_id].split_end_distances, view_z);
- float id = abs(4.0 - dot(weights, weights));
-
- if (id > 3.0) {
- return vec3(0.0);
- }
-
- /* Same factor as in get_cascade_world_distance(). */
- float range = abs(data.sh_far - data.sh_near);
-
- vec4 shpos = shadows_cascade_data[scd_id].shadowmat[int(id)] * vec4(W, 1.0);
- float dist = shpos.z * range;
-
- if (shpos.z > 1.0 || shpos.z < 0.0) {
- return vec3(0.0);
- }
-
- ShadowSample s = sample_cascade(shpos.xy, data.sh_tex_start + id);
- delta = get_depth_delta(dist, s);
- }
- else {
- vec3 cubevec = W - shadows_cube_data[int(data.sh_data_start)].position.xyz;
- float dist = length(cubevec);
- cubevec /= dist;
-
- ShadowSample s = sample_cube(cubevec, data.sh_tex_start);
- delta = get_depth_delta(dist, s);
- }
-
- /* XXX : Removing Area Power. */
- /* TODO : put this out of the shader. */
- float falloff;
- if (ld.l_type == AREA_RECT || ld.l_type == AREA_ELLIPSE) {
- vis *= (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0);
- if (ld.l_type == AREA_ELLIPSE) {
- vis *= M_PI * 0.25;
- }
- vis *= 0.3 * 20.0 *
- max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */
- vis /= (l_vector.w * l_vector.w);
- falloff = dot(N, l_vector.xyz / l_vector.w);
- }
- else if (ld.l_type == SUN) {
- vis /= 1.0f + (ld.l_radius * ld.l_radius * 0.5f);
- vis *= ld.l_radius * ld.l_radius * M_PI; /* Removing area light power*/
- vis *= M_2PI * 0.78; /* Matching cycles with point light. */
- vis *= 0.082; /* XXX ad hoc, empirical */
- falloff = dot(N, -ld.l_forward);
- }
- else {
- vis *= (4.0 * ld.l_radius * ld.l_radius) * (1.0 / 10.0);
- vis *= 1.5; /* XXX ad hoc, empirical */
- vis /= (l_vector.w * l_vector.w);
- falloff = dot(N, l_vector.xyz / l_vector.w);
- }
- // vis *= M_1_PI; /* Normalize */
-
- /* Applying profile */
- vis *= sss_profile(abs(delta) / scale);
-
- /* No transmittance at grazing angle (hide artifacts) */
- vis *= saturate(falloff * 2.0);
- }
- else {
- vis = vec3(0.0);
- }
-
- return vis;
-#endif
-}
diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
index 53f1517505c..3774054659d 100644
--- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
@@ -144,14 +144,12 @@ void CLOSURE_NAME(vec3 N
,
float ior
#endif
+ ,
+ const bool use_contact_shadows
#ifdef CLOSURE_DIFFUSE
,
out vec3 out_diff
#endif
-#ifdef CLOSURE_SUBSURFACE
- ,
- out vec3 out_trans
-#endif
#ifdef CLOSURE_GLOSSY
,
out vec3 out_spec
@@ -170,10 +168,6 @@ void CLOSURE_NAME(vec3 N
out_diff = vec3(0.0);
#endif
-#ifdef CLOSURE_SUBSURFACE
- out_trans = vec3(0.0);
-#endif
-
#ifdef CLOSURE_GLOSSY
out_spec = vec3(0.0);
#endif
@@ -230,14 +224,31 @@ void CLOSURE_NAME(vec3 N
vec3 out_spec_clear = vec3(0.0);
# endif
- for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) {
+ float tracing_depth = gl_FragCoord.z;
+ /* 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, gl_FragCoord.z);
+ /* Convert to view Z. */
+ tracing_depth = get_view_z_from_depth(tracing_depth);
+
+ vec3 true_normal = normalize(cross(dFdx(viewPosition), dFdy(viewPosition)));
+
+ for (int i = 0; i < MAX_LIGHT && i < laNumLight; i++) {
LightData ld = lights_data[i];
vec4 l_vector; /* Non-Normalized Light Vector with length in last component. */
l_vector.xyz = ld.l_position - worldPosition;
l_vector.w = length(l_vector.xyz);
- float l_vis = light_visibility(ld, worldPosition, viewPosition, viewNormal, l_vector);
+ float l_vis = light_visibility(ld,
+ worldPosition,
+ viewPosition,
+ tracing_depth,
+ true_normal,
+ rand.x,
+ use_contact_shadows,
+ l_vector);
if (l_vis < 1e-8) {
continue;
@@ -249,10 +260,6 @@ void CLOSURE_NAME(vec3 N
out_diff += l_color_vis * light_diffuse(ld, N, V, l_vector);
# endif
-# ifdef CLOSURE_SUBSURFACE
- out_trans += ld.l_color * light_translucent(ld, worldPosition, -N, l_vector, sss_scale);
-# endif
-
# ifdef CLOSURE_GLOSSY
out_spec += l_color_vis * light_specular(ld, ltc_mat, N, V, l_vector) * ld.l_spec;
# endif
@@ -297,7 +304,7 @@ void CLOSURE_NAME(vec3 N
/* Planar Reflections */
/* ---------------------------- */
- for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar && spec_accum.a < 0.999; ++i) {
+ for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar && spec_accum.a < 0.999; i++) {
PlanarData pd = planars_data[i];
/* Fade on geometric normal. */
@@ -373,7 +380,7 @@ void CLOSURE_NAME(vec3 N
# endif
/* Starts at 1 because 0 is world probe */
- for (int i = 1; ACCUM < 0.999 && i < prbNumRenderCube && i < MAX_PROBE; ++i) {
+ for (int i = 1; ACCUM < 0.999 && i < prbNumRenderCube && i < MAX_PROBE; i++) {
float fade = probe_attenuation_cube(i, worldPosition);
if (fade > 0.0) {
@@ -441,10 +448,17 @@ void CLOSURE_NAME(vec3 N
/* Ambient Occlusion */
/* ---------------------------- */
# if defined(CLOSURE_GLOSSY) || defined(CLOSURE_DIFFUSE)
- /* HACK: Fix for translucent BSDF. (see T65631) */
- bool same_side = dot((gl_FrontFacing) ? worldNormal : -worldNormal, N) > 0.0;
+ if (!use_contact_shadows) {
+ /* HACK: Fix for translucent BSDF. (see T65631) */
+ N = -N;
+ }
vec3 bent_normal;
- float final_ao = occlusion_compute(same_side ? N : -N, viewPosition, ao, rand, bent_normal);
+ float final_ao = occlusion_compute(N, viewPosition, ao, rand, bent_normal);
+ if (!use_contact_shadows) {
+ N = -N;
+ /* Bypass bent normal. */
+ bent_normal = N;
+ }
# endif
/* ---------------------------- */
@@ -501,7 +515,7 @@ void CLOSURE_NAME(vec3 N
/* Irradiance Grids */
/* ---------------------------- */
/* Start at 1 because 0 is world irradiance */
- for (int i = 1; i < MAX_GRID && i < prbNumRenderGrid && diff_accum.a < 0.999; ++i) {
+ for (int i = 1; i < MAX_GRID && i < prbNumRenderGrid && diff_accum.a < 0.999; i++) {
GridData gd = grids_data[i];
vec3 localpos;
diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
index 14e0c947b47..f88cfdf3787 100644
--- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
@@ -120,7 +120,8 @@ void prepare_raycast(vec3 ray_origin,
ss_ray = ss_start * m.xyyy + 0.5;
ss_step *= m.xyyy;
- ss_ray.xy += m * ssrPixelSize * 2.0; /* take the center of the texel. * 2 because halfres. */
+ /* take the center of the texel. */
+ // ss_ray.xy += sign(ss_ray.xy) * m * ssrPixelSize * (1.0 + hizMipOffset);
}
/* See times_and_deltas. */
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl
deleted file mode 100644
index 5646c257562..00000000000
--- a/source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl
+++ /dev/null
@@ -1,199 +0,0 @@
-/* Copy the depth only shadowmap into another texture while converting
- * to linear depth (or other storage method) and doing a 3x3 box filter. */
-
-layout(std140) uniform shadow_render_block
-{
- /* Use vectors to avoid alignment padding. */
- ivec4 shadowSampleCount;
- vec4 shadowInvSampleCount;
- vec4 filterSize;
- int viewCount;
- int baseId;
- float cubeTexelSize;
- float storedTexelSize;
- float nearClip;
- float farClip;
- float exponent;
-};
-
-#ifdef CSM
-uniform sampler2DArray shadowTexture;
-#else
-uniform samplerCube shadowTexture;
-#endif
-
-flat in int layerID;
-
-#ifdef CSM
-# define cascadeID layerID
-#else
-# define cascadeID 0
-#endif
-
-out vec4 FragColor;
-
-#define linear_depth(z) \
- ((nearClip * farClip) / (clamp(z, 0.0, 0.999999) * (nearClip - farClip) + farClip))
-
-/* add bias so background filtering does not bleed into shadow map */
-#define BACKGROUND_BIAS 0.05
-
-#ifdef CSM
-vec4 get_world_distance(vec4 depths, vec3 cos[4])
-{
- depths += step(vec4(0.9999), depths) * BACKGROUND_BIAS;
- return clamp(
- depths * abs(farClip - nearClip), 0.0, 1e10); /* Same factor as in shadow_cascade(). */
-}
-
-float get_world_distance(float depth, vec3 cos)
-{
- depth += step(0.9999, depth) * BACKGROUND_BIAS;
- return clamp(
- depth * abs(farClip - nearClip), 0.0, 1e10); /* Same factor as in shadow_cascade(). */
-}
-
-#else /* CUBEMAP */
-vec4 get_world_distance(vec4 depths, vec3 cos[4])
-{
- depths = linear_depth(depths);
- cos[0] = normalize(abs(cos[0]));
- cos[1] = normalize(abs(cos[1]));
- cos[2] = normalize(abs(cos[2]));
- cos[3] = normalize(abs(cos[3]));
- vec4 cos_vec;
- cos_vec.x = max(cos[0].x, max(cos[0].y, cos[0].z));
- cos_vec.y = max(cos[1].x, max(cos[1].y, cos[1].z));
- cos_vec.z = max(cos[2].x, max(cos[2].y, cos[2].z));
- cos_vec.w = max(cos[3].x, max(cos[3].y, cos[3].z));
- return depths / cos_vec;
-}
-
-float get_world_distance(float depth, vec3 cos)
-{
- depth = linear_depth(depth);
- cos = normalize(abs(cos));
- float cos_vec = max(cos.x, max(cos.y, cos.z));
- return depth / cos_vec;
-}
-#endif
-
-/* Marco Salvi's GDC 2008 presentation about shadow maps pre-filtering techniques slide 24 */
-#define ln_space_prefilter_step(ref, sample) exp(sample - ref)
-#define ln_space_prefilter_finalize(ref, sum) (ref + log(SAMPLE_WEIGHT * sum))
-
-#define SAMPLE_WEIGHT 0.11111
-
-#ifdef ESM
-void prefilter(vec4 depths, float ref, inout float accum)
-{
- accum += dot(ln_space_prefilter_step(ref, depths), vec4(1.0));
-}
-#else /* VSM */
-void prefilter(vec4 depths, float ref, inout vec2 accum)
-{
- vec4 depths_sqr = depths * depths;
- accum += vec2(dot(vec4(1.0), depths), dot(vec4(1.0), depths_sqr)) * SAMPLE_WEIGHT;
-}
-#endif
-
-#ifdef CSM
-vec3 get_texco(vec2 uvs, vec2 ofs)
-{
- return vec3(uvs + ofs, float(cascadeID));
-}
-#else /* CUBEMAP */
-const vec3 minorAxisX[6] = vec3[6](vec3(0.0f, 0.0f, -1.0f),
- vec3(0.0f, 0.0f, 1.0f),
- vec3(1.0f, 0.0f, 0.0f),
- vec3(1.0f, 0.0f, 0.0f),
- vec3(1.0f, 0.0f, 0.0f),
- vec3(-1.0f, 0.0f, 0.0f));
-
-const vec3 minorAxisY[6] = vec3[6](vec3(0.0f, -1.0f, 0.0f),
- vec3(0.0f, -1.0f, 0.0f),
- vec3(0.0f, 0.0f, 1.0f),
- vec3(0.0f, 0.0f, -1.0f),
- vec3(0.0f, -1.0f, 0.0f),
- vec3(0.0f, -1.0f, 0.0f));
-
-const vec3 majorAxis[6] = vec3[6](vec3(1.0f, 0.0f, 0.0f),
- vec3(-1.0f, 0.0f, 0.0f),
- vec3(0.0f, 1.0f, 0.0f),
- vec3(0.0f, -1.0f, 0.0f),
- vec3(0.0f, 0.0f, 1.0f),
- vec3(0.0f, 0.0f, -1.0f));
-
-vec3 get_texco(vec2 uvs, vec2 ofs)
-{
- uvs += ofs;
- return majorAxis[layerID] + uvs.x * minorAxisX[layerID] + uvs.y * minorAxisY[layerID];
-}
-#endif
-
-void main()
-{
- /* Copy the depth only shadowmap into another texture while converting
- * to linear depth and do a 3x3 box blur. */
-
-#ifdef CSM
- vec2 uvs = gl_FragCoord.xy * storedTexelSize;
-#else /* CUBEMAP */
- vec2 uvs = gl_FragCoord.xy * cubeTexelSize * 2.0 - 1.0;
-#endif
-
- /* Center texel */
- vec3 co = get_texco(uvs, vec2(0.0));
- float depth = texture(shadowTexture, co).r;
- depth = get_world_distance(depth, co);
-
- if (filterSize[cascadeID] == 0.0) {
-#ifdef ESM
- FragColor = vec4(depth);
-#else /* VSM */
- FragColor = vec2(depth, depth * depth).xyxy;
-#endif
- return;
- }
-
-#ifdef ESM
- float ref = depth;
- float accum = 1.0;
-#else /* VSM */
- float ref = 0.0; /* UNUSED */
- vec2 accum = vec2(depth, depth * depth) * SAMPLE_WEIGHT;
-#endif
-
- vec3 ofs = vec3(1.0, 0.0, -1.0) * filterSize[cascadeID];
-
- vec3 cos[4];
- cos[0] = get_texco(uvs, ofs.zz);
- cos[1] = get_texco(uvs, ofs.yz);
- cos[2] = get_texco(uvs, ofs.xz);
- cos[3] = get_texco(uvs, ofs.zy);
-
- vec4 depths;
- depths.x = texture(shadowTexture, cos[0]).r;
- depths.y = texture(shadowTexture, cos[1]).r;
- depths.z = texture(shadowTexture, cos[2]).r;
- depths.w = texture(shadowTexture, cos[3]).r;
- depths = get_world_distance(depths, cos);
- prefilter(depths, ref, accum);
-
- cos[0] = get_texco(uvs, ofs.xy);
- cos[1] = get_texco(uvs, ofs.zx);
- cos[2] = get_texco(uvs, ofs.yx);
- cos[3] = get_texco(uvs, ofs.xx);
- depths.x = texture(shadowTexture, cos[0]).r;
- depths.y = texture(shadowTexture, cos[1]).r;
- depths.z = texture(shadowTexture, cos[2]).r;
- depths.w = texture(shadowTexture, cos[3]).r;
- depths = get_world_distance(depths, cos);
- prefilter(depths, ref, accum);
-
-#ifdef ESM
- accum = ln_space_prefilter_finalize(ref, accum);
-#endif
- /* Clamp infinite sum. */
- FragColor = vec2(clamp(accum, 0.0, 1e16)).xyxy;
-}
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_process_geom.glsl b/source/blender/draw/engines/eevee/shaders/shadow_process_geom.glsl
deleted file mode 100644
index 591666560c4..00000000000
--- a/source/blender/draw/engines/eevee/shaders/shadow_process_geom.glsl
+++ /dev/null
@@ -1,36 +0,0 @@
-
-layout(triangles) in;
-layout(triangle_strip, max_vertices = 3) out;
-
-layout(std140) uniform shadow_render_block
-{
- /* Use vectors to avoid alignment padding. */
- ivec4 shadowSampleCount;
- vec4 shadowInvSampleCount;
- vec4 filterSize;
- int viewCount;
- int baseId;
- float cubeTexelSize;
- float storedTexelSize;
- float nearClip;
- float farClip;
- float exponent;
-};
-
-in int layerID_g[];
-
-flat out int layerID;
-
-void main()
-{
- gl_Layer = layerID_g[0];
- layerID = gl_Layer - baseId;
-
- gl_Position = gl_in[0].gl_Position;
- EmitVertex();
- gl_Position = gl_in[1].gl_Position;
- EmitVertex();
- gl_Position = gl_in[2].gl_Position;
- EmitVertex();
- EndPrimitive();
-}
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_process_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_process_vert.glsl
deleted file mode 100644
index 95e6a48b81f..00000000000
--- a/source/blender/draw/engines/eevee/shaders/shadow_process_vert.glsl
+++ /dev/null
@@ -1,32 +0,0 @@
-
-layout(std140) uniform shadow_render_block
-{
- /* Use vectors to avoid alignment padding. */
- ivec4 shadowSampleCount;
- vec4 shadowInvSampleCount;
- vec4 filterSize;
- int viewCount;
- int baseId;
- float cubeTexelSize;
- float storedTexelSize;
- float nearClip;
- float farClip;
- float exponent;
-};
-
-out int layerID_g;
-
-void main()
-{
- int v = gl_VertexID % 3;
- layerID_g = gl_VertexID / 3;
- float x = -1.0 + float((v & 1) << 2);
- float y = -1.0 + float((v & 2) << 1);
- gl_Position = vec4(x, y, 1.0, 1.0);
-
- /* HACK avoid changing drawcall parameters. */
- if (layerID_g >= viewCount) {
- gl_Position = vec4(0.0);
- }
- layerID_g += baseId;
-}
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl
deleted file mode 100644
index 5c19ccd5ce1..00000000000
--- a/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl
+++ /dev/null
@@ -1,322 +0,0 @@
-
-layout(std140) uniform shadow_render_block
-{
- /* Use vectors to avoid alignment padding. */
- ivec4 shadowSampleCount;
- vec4 shadowInvSampleCount;
- vec4 filterSize;
- int viewCount;
- int baseId;
- float cubeTexelSize;
- float storedTexelSize;
- float nearClip;
- float farClip;
- float exponent;
-};
-
-#ifdef CSM
-uniform sampler2DArray shadowTexture;
-#else
-uniform samplerCube shadowTexture;
-#endif
-
-flat in int layerID;
-
-#ifdef CSM
-# define cascadeID layerID
-#else
-# define cascadeID 0
-#endif
-
-out vec4 FragColor;
-
-vec3 octahedral_to_cubemap_proj(vec2 co)
-{
- co = co * 2.0 - 1.0;
-
- vec2 abs_co = abs(co);
- vec3 v = vec3(co, 1.0 - (abs_co.x + abs_co.y));
-
- if (abs_co.x + abs_co.y > 1.0) {
- v.xy = (abs(co.yx) - 1.0) * -sign(co.xy);
- }
-
- return v;
-}
-
-/* Marco Salvi's GDC 2008 presentation about shadow maps pre-filtering techniques slide 24 */
-/* http://advances.realtimerendering.com/s2009/SIGGRAPH%202009%20-%20Lighting%20Research%20at%20Bungie.pdf
- * Slide 55. */
-#define ln_space_prefilter_step(ref, sample) exp(sample - ref)
-#define ln_space_prefilter_finalize(ref, sum) (ref + log(shadowInvSampleCount[cascadeID] * sum))
-
-#ifdef CSM
-vec3 get_texco(vec3 cos, const vec2 ofs)
-{
- cos.xy += ofs * filterSize[cascadeID];
- return cos;
-}
-#else /* CUBEMAP */
-/* global vars */
-vec3 T = vec3(0.0);
-vec3 B = vec3(0.0);
-
-void make_orthonormal_basis(vec3 N)
-{
- vec3 UpVector = (abs(N.z) < 0.999) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
- T = normalize(cross(UpVector, N));
- B = cross(N, T);
-}
-
-vec3 get_texco(vec3 cos, const vec2 ofs)
-{
- return cos + ofs.x * T + ofs.y * B;
-}
-
-#endif
-
-#ifdef ESM
-void grouped_samples_accum(vec3 cos,
- const vec2 co1,
- const vec2 co2,
- const vec2 co3,
- const vec2 co4,
- float ref,
- inout vec4 accum)
-{
- vec4 depths;
- depths.x = texture(shadowTexture, get_texco(cos, co1)).r;
- depths.y = texture(shadowTexture, get_texco(cos, co2)).r;
- depths.z = texture(shadowTexture, get_texco(cos, co3)).r;
- depths.w = texture(shadowTexture, get_texco(cos, co4)).r;
-
- accum += ln_space_prefilter_step(ref, depths);
-}
-#else /* VSM */
-void grouped_samples_accum(vec3 cos,
- const vec2 co1,
- const vec2 co2,
- const vec2 co3,
- const vec2 co4,
- float ref,
- inout vec2 accum)
-{
- vec4 depths1, depths2;
- depths1.xy = texture(shadowTexture, get_texco(cos, co1)).rg;
- depths1.zw = texture(shadowTexture, get_texco(cos, co2)).rg;
- depths2.xy = texture(shadowTexture, get_texco(cos, co3)).rg;
- depths2.zw = texture(shadowTexture, get_texco(cos, co4)).rg;
-
- accum += depths1.xy + depths1.zw + depths2.xy + depths2.zw;
-}
-#endif
-
-void main()
-{
- vec3 cos;
-
- cos.xy = gl_FragCoord.xy * storedTexelSize;
-
-#ifdef CSM
- cos.z = float(cascadeID);
-#else /* CUBEMAP */
- /* add a 2 pixel border to ensure filtering is correct */
- cos.xy *= 1.0 + storedTexelSize * 2.0;
- cos.xy -= storedTexelSize;
-
- float pattern = 1.0;
-
- /* edge mirroring : only mirror if directly adjacent
- * (not diagonally adjacent) */
- vec2 m = abs(cos.xy - 0.5) + 0.5;
- vec2 f = floor(m);
- if (f.x - f.y != 0.0) {
- cos.xy = 1.0 - cos.xy;
- }
-
- /* clamp to [0-1] */
- cos.xy = fract(cos.xy);
-
- /* get cubemap vector */
- cos = normalize(octahedral_to_cubemap_proj(cos.xy));
- make_orthonormal_basis(cos);
-
- T *= filterSize[cascadeID];
- B *= filterSize[cascadeID];
-#endif
-
-#ifdef ESM
- /* disc blur in log space. */
- vec4 depths;
- depths.x = texture(shadowTexture, get_texco(cos, concentric[0])).r;
- depths.y = texture(shadowTexture, get_texco(cos, concentric[1])).r;
- depths.z = texture(shadowTexture, get_texco(cos, concentric[2])).r;
- depths.w = texture(shadowTexture, get_texco(cos, concentric[3])).r;
- float ref = depths.x;
- vec4 accum = ln_space_prefilter_step(ref, depths);
-
-#else /* VSM */
- float ref = 0.0; /* UNUSED */
- vec2 accum = vec2(0.0);
- grouped_samples_accum(
- cos, concentric[0], concentric[1], concentric[2], concentric[3], ref, accum);
-#endif
-
- /**
- * Making the `grouped_samples_accum` be called within a loop would be
- * the most conventional solution, however in some older gpus, transverse the huge
- * `const vec2 concentric[]` array with variable indices is extremely slow.
- * The solution is to use constant indices to access the array.
- */
- if (shadowSampleCount[cascadeID] > 4) {
- grouped_samples_accum(
- cos, concentric[4], concentric[5], concentric[6], concentric[7], ref, accum);
- grouped_samples_accum(
- cos, concentric[8], concentric[9], concentric[10], concentric[11], ref, accum);
- grouped_samples_accum(
- cos, concentric[12], concentric[13], concentric[14], concentric[15], ref, accum);
- }
- if (shadowSampleCount[cascadeID] > 16) {
- grouped_samples_accum(
- cos, concentric[16], concentric[17], concentric[18], concentric[19], ref, accum);
- grouped_samples_accum(
- cos, concentric[20], concentric[21], concentric[22], concentric[23], ref, accum);
- grouped_samples_accum(
- cos, concentric[24], concentric[25], concentric[26], concentric[27], ref, accum);
- grouped_samples_accum(
- cos, concentric[28], concentric[29], concentric[30], concentric[31], ref, accum);
- grouped_samples_accum(
- cos, concentric[32], concentric[33], concentric[34], concentric[35], ref, accum);
- }
-#ifdef HIGH_BLUR
- if (shadowSampleCount[cascadeID] > 36) {
- grouped_samples_accum(
- cos, concentric[36], concentric[37], concentric[38], concentric[39], ref, accum);
- grouped_samples_accum(
- cos, concentric[40], concentric[41], concentric[42], concentric[43], ref, accum);
- grouped_samples_accum(
- cos, concentric[44], concentric[45], concentric[46], concentric[47], ref, accum);
- grouped_samples_accum(
- cos, concentric[48], concentric[49], concentric[50], concentric[51], ref, accum);
- grouped_samples_accum(
- cos, concentric[52], concentric[53], concentric[54], concentric[55], ref, accum);
- grouped_samples_accum(
- cos, concentric[56], concentric[57], concentric[58], concentric[59], ref, accum);
- grouped_samples_accum(
- cos, concentric[60], concentric[61], concentric[62], concentric[63], ref, accum);
- }
- if (shadowSampleCount[cascadeID] > 64) {
- grouped_samples_accum(
- cos, concentric[64], concentric[65], concentric[66], concentric[67], ref, accum);
- grouped_samples_accum(
- cos, concentric[68], concentric[69], concentric[70], concentric[71], ref, accum);
- grouped_samples_accum(
- cos, concentric[72], concentric[73], concentric[74], concentric[75], ref, accum);
- grouped_samples_accum(
- cos, concentric[76], concentric[77], concentric[78], concentric[79], ref, accum);
- grouped_samples_accum(
- cos, concentric[80], concentric[81], concentric[82], concentric[83], ref, accum);
- grouped_samples_accum(
- cos, concentric[84], concentric[85], concentric[86], concentric[87], ref, accum);
- grouped_samples_accum(
- cos, concentric[88], concentric[89], concentric[90], concentric[91], ref, accum);
- grouped_samples_accum(
- cos, concentric[92], concentric[93], concentric[94], concentric[95], ref, accum);
- grouped_samples_accum(
- cos, concentric[96], concentric[97], concentric[98], concentric[99], ref, accum);
- }
- if (shadowSampleCount[cascadeID] > 100) {
- grouped_samples_accum(
- cos, concentric[100], concentric[101], concentric[102], concentric[103], ref, accum);
- grouped_samples_accum(
- cos, concentric[104], concentric[105], concentric[106], concentric[107], ref, accum);
- grouped_samples_accum(
- cos, concentric[108], concentric[109], concentric[110], concentric[111], ref, accum);
- grouped_samples_accum(
- cos, concentric[112], concentric[113], concentric[114], concentric[115], ref, accum);
- grouped_samples_accum(
- cos, concentric[116], concentric[117], concentric[118], concentric[119], ref, accum);
- grouped_samples_accum(
- cos, concentric[120], concentric[121], concentric[122], concentric[123], ref, accum);
- grouped_samples_accum(
- cos, concentric[124], concentric[125], concentric[126], concentric[127], ref, accum);
- grouped_samples_accum(
- cos, concentric[128], concentric[129], concentric[130], concentric[131], ref, accum);
- grouped_samples_accum(
- cos, concentric[132], concentric[133], concentric[134], concentric[135], ref, accum);
- grouped_samples_accum(
- cos, concentric[136], concentric[137], concentric[138], concentric[139], ref, accum);
- grouped_samples_accum(
- cos, concentric[140], concentric[141], concentric[142], concentric[143], ref, accum);
- }
- if (shadowSampleCount[cascadeID] > 144) {
- grouped_samples_accum(
- cos, concentric[144], concentric[145], concentric[146], concentric[147], ref, accum);
- grouped_samples_accum(
- cos, concentric[148], concentric[149], concentric[150], concentric[151], ref, accum);
- grouped_samples_accum(
- cos, concentric[152], concentric[153], concentric[154], concentric[155], ref, accum);
- grouped_samples_accum(
- cos, concentric[156], concentric[157], concentric[158], concentric[159], ref, accum);
- grouped_samples_accum(
- cos, concentric[160], concentric[161], concentric[162], concentric[163], ref, accum);
- grouped_samples_accum(
- cos, concentric[164], concentric[165], concentric[166], concentric[167], ref, accum);
- grouped_samples_accum(
- cos, concentric[168], concentric[169], concentric[170], concentric[171], ref, accum);
- grouped_samples_accum(
- cos, concentric[172], concentric[173], concentric[174], concentric[175], ref, accum);
- grouped_samples_accum(
- cos, concentric[176], concentric[177], concentric[178], concentric[179], ref, accum);
- grouped_samples_accum(
- cos, concentric[180], concentric[181], concentric[182], concentric[183], ref, accum);
- grouped_samples_accum(
- cos, concentric[184], concentric[185], concentric[186], concentric[187], ref, accum);
- grouped_samples_accum(
- cos, concentric[188], concentric[189], concentric[190], concentric[191], ref, accum);
- grouped_samples_accum(
- cos, concentric[192], concentric[193], concentric[194], concentric[195], ref, accum);
- }
- if (shadowSampleCount[cascadeID] > 196) {
- grouped_samples_accum(
- cos, concentric[196], concentric[197], concentric[198], concentric[199], ref, accum);
- grouped_samples_accum(
- cos, concentric[200], concentric[201], concentric[202], concentric[203], ref, accum);
- grouped_samples_accum(
- cos, concentric[204], concentric[205], concentric[206], concentric[207], ref, accum);
- grouped_samples_accum(
- cos, concentric[208], concentric[209], concentric[210], concentric[211], ref, accum);
- grouped_samples_accum(
- cos, concentric[212], concentric[213], concentric[114], concentric[215], ref, accum);
- grouped_samples_accum(
- cos, concentric[216], concentric[217], concentric[218], concentric[219], ref, accum);
- grouped_samples_accum(
- cos, concentric[220], concentric[221], concentric[222], concentric[223], ref, accum);
- grouped_samples_accum(
- cos, concentric[224], concentric[225], concentric[226], concentric[227], ref, accum);
- grouped_samples_accum(
- cos, concentric[228], concentric[229], concentric[230], concentric[231], ref, accum);
- grouped_samples_accum(
- cos, concentric[232], concentric[233], concentric[234], concentric[235], ref, accum);
- grouped_samples_accum(
- cos, concentric[236], concentric[237], concentric[238], concentric[239], ref, accum);
- grouped_samples_accum(
- cos, concentric[240], concentric[241], concentric[242], concentric[243], ref, accum);
- grouped_samples_accum(
- cos, concentric[244], concentric[245], concentric[246], concentric[247], ref, accum);
- grouped_samples_accum(
- cos, concentric[248], concentric[249], concentric[250], concentric[251], ref, accum);
- grouped_samples_accum(
- cos, concentric[252], concentric[253], concentric[254], concentric[255], ref, accum);
- }
-#endif
-
-#ifdef ESM
- accum.x = dot(vec4(1.0), accum);
- accum.x = ln_space_prefilter_finalize(ref, accum.x);
- FragColor = accum.xxxx;
-
-#else /* VSM */
- FragColor = accum.xyxy * shadowInvSampleCount[cascadeID];
-#endif
-}
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
index acd1e58ff97..c3c442e7b69 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
@@ -8,10 +8,17 @@
uniform sampler3D volumeScattering; /* Result of the scatter step */
uniform sampler3D volumeExtinction;
+#ifdef USE_VOLUME_OPTI
+uniform layout(binding = 0, r11f_g11f_b10f) writeonly restrict image3D finalScattering_img;
+uniform layout(binding = 1, r11f_g11f_b10f) writeonly restrict image3D finalTransmittance_img;
+vec3 finalScattering;
+vec3 finalTransmittance;
+#else
flat in int slice;
layout(location = 0) out vec3 finalScattering;
layout(location = 1) out vec3 finalTransmittance;
+#endif
void main()
{
@@ -36,10 +43,11 @@ void main()
orig_ray_len = prev_ray_len / view_cell.z;
}
- /* Without compute shader and arbitrary write we need to
- * accumulate from the beginning of the ray for each cell. */
- float integration_end = float(slice);
- for (int i = 0; i < slice; ++i) {
+#ifdef USE_VOLUME_OPTI
+ int slice = textureSize(volumeScattering, 0).z;
+ ivec2 texco = ivec2(gl_FragCoord.xy);
+#endif
+ for (int i = 0; i <= slice; i++) {
ivec3 volume_cell = ivec3(gl_FragCoord.xy, i);
vec3 Lscat = texelFetch(volumeScattering, volume_cell, 0).rgb;
@@ -63,5 +71,11 @@ void main()
finalScattering += finalTransmittance * Lscat;
finalTransmittance *= Tr;
+
+#ifdef USE_VOLUME_OPTI
+ ivec3 coord = ivec3(texco, i);
+ imageStore(finalScattering_img, coord, vec4(finalScattering, 0.0));
+ imageStore(finalTransmittance_img, coord, vec4(finalTransmittance, 0.0));
+#endif
}
}
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl
index d345cd5c808..9621fa1cc0d 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl
@@ -38,7 +38,7 @@ void main()
phase_function_isotropic();
#ifdef VOLUME_LIGHTING /* Lights */
- for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) {
+ for (int i = 0; i < MAX_LIGHT && i < laNumLight; i++) {
LightData ld = lights_data[i];
diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c
index f6646ca575e..704e16b2907 100644
--- a/source/blender/draw/engines/external/external_engine.c
+++ b/source/blender/draw/engines/external/external_engine.c
@@ -28,6 +28,8 @@
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
+#include "BKE_object.h"
+
#include "ED_screen.h"
#include "GPU_matrix.h"
@@ -156,7 +158,8 @@ static void external_cache_populate(void *vedata, Object *ob)
{
EXTERNAL_StorageList *stl = ((EXTERNAL_Data *)vedata)->stl;
- if (!DRW_object_is_renderable(ob)) {
+ if (!(DRW_object_is_renderable(ob) &&
+ DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) {
return;
}
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
index 541a9e31586..8006c784190 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
@@ -80,7 +80,7 @@ static void gpencil_set_buffer_stroke_point(GPUVertBuf *vbo,
uint thickness_id,
uint uvdata_id,
uint prev_pos_id,
- float ref_pt[3],
+ const float ref_pt[3],
short thickness,
const float ink[4])
{
@@ -110,7 +110,7 @@ static void gpencil_set_fill_point(GPUVertBuf *vbo,
int idx,
bGPDspoint *pt,
const float fcolor[4],
- float uv[2],
+ const float uv[2],
uint pos_id,
uint color_id,
uint text_id)
@@ -886,7 +886,7 @@ void gpencil_get_edlin_geom(struct GpencilBatchCacheElem *be,
static void set_grid_point(GPUVertBuf *vbo,
int idx,
- float col_grid[4],
+ const float col_grid[4],
uint pos_id,
uint color_id,
float v1,
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
index 93040afe2c7..ce5d8cbf732 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
@@ -61,13 +61,81 @@
#define TEXTURE 4
#define PATTERN 5
+/* Verify if must fade object or not. */
+static bool gpencil_fade_object_check(GPENCIL_StorageList *stl, Object *ob)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ const bool is_overlay = (bool)((v3d) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) &&
+ (v3d->gp_flag & V3D_GP_SHOW_PAPER));
+
+ if ((!is_overlay) || (ob == draw_ctx->obact) ||
+ ((v3d->gp_flag & V3D_GP_FADE_NOACTIVE_GPENCIL) == 0) ||
+ (v3d->overlay.gpencil_paper_opacity == 1.0f)) {
+ return false;
+ }
+
+ const bool playing = stl->storage->is_playing;
+ const bool is_render = (bool)stl->storage->is_render;
+ const bool is_mat_preview = (bool)stl->storage->is_mat_preview;
+ const bool is_select = (bool)(DRW_state_is_select() || DRW_state_is_depth());
+
+ return (bool)((!is_render) && (!playing) && (!is_mat_preview) && (!is_select));
+}
+
+/* Define Fade layer uniforms. */
+static void gpencil_set_fade_layer_uniforms(
+ GPENCIL_StorageList *stl, DRWShadingGroup *grp, Object *ob, bGPDlayer *gpl, const bool skip)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) : true;
+ const bool is_fade = (v3d) && (v3d->gp_flag & V3D_GP_FADE_NOACTIVE_LAYERS) &&
+ (draw_ctx->obact) && (draw_ctx->obact == ob) &&
+ ((gpl->flag & GP_LAYER_ACTIVE) == 0);
+
+ const bool playing = stl->storage->is_playing;
+ const bool is_render = (bool)stl->storage->is_render;
+ const bool is_mat_preview = (bool)stl->storage->is_mat_preview;
+ const bool is_select = (bool)(DRW_state_is_select() || DRW_state_is_depth());
+
+ /* If drawing or not fading layer, skip. */
+ if ((!overlay) || (skip) || (!is_fade) || (is_render) || (playing) || (is_mat_preview) ||
+ (is_select)) {
+ DRW_shgroup_uniform_int_copy(grp, "fade_layer", 0);
+ return;
+ }
+
+ /* If layer is above active, use alpha (2) if below use mix with background (1). */
+ if (stl->storage->is_ontop) {
+ DRW_shgroup_uniform_int_copy(grp, "fade_layer", 2);
+ }
+ else {
+ DRW_shgroup_uniform_int_copy(grp, "fade_layer", 1);
+ }
+ if (v3d) {
+ DRW_shgroup_uniform_vec3(grp, "fade_color", v3d->shading.background_color, 1);
+ DRW_shgroup_uniform_float(grp, "fade_layer_factor", &v3d->overlay.gpencil_fade_layer, 1);
+ }
+}
+
+/* Define Fade object uniforms. */
+static void gpencil_set_fade_ob_uniforms(View3D *v3d, DRWShadingGroup *grp, bool status)
+{
+ DRW_shgroup_uniform_bool_copy(grp, "fade_ob", status);
+ if (v3d) {
+ DRW_shgroup_uniform_vec3(grp, "fade_color", v3d->shading.background_color, 1);
+ DRW_shgroup_uniform_float(grp, "fade_ob_factor", &v3d->overlay.gpencil_paper_opacity, 1);
+ }
+}
+
/* Get number of vertex for using in GPU VBOs */
static void gpencil_calc_vertex(GPENCIL_StorageList *stl,
tGPencilObjectCache *cache_ob,
GpencilBatchCache *cache,
bGPdata *gpd)
{
- if (!cache->is_dirty) {
+ if ((!cache->is_dirty) || (gpd == NULL)) {
return;
}
@@ -81,10 +149,15 @@ static void gpencil_calc_vertex(GPENCIL_StorageList *stl,
(bool)((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) :
true;
const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay &&
- main_onion && gpencil_onion_active(gpd) && !playing;
+ main_onion && !playing && gpencil_onion_active(gpd);
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ /* Onion skining. */
+ const int step = gpd->gstep;
+ const int mode = gpd->onion_mode;
+ const short onion_keytype = gpd->onion_keytype;
+
cache_ob->tot_vertex = 0;
cache_ob->tot_triangles = 0;
int idx_eval = 0;
@@ -97,7 +170,7 @@ static void gpencil_calc_vertex(GPENCIL_StorageList *stl,
continue;
}
- /* if multiedit or onion skin need to count all frames of the layer */
+ /* If multiedit or onion skin need to count all frames of the layer. */
if ((is_multiedit) || (is_onion)) {
init_gpf = gpl->frames.first;
}
@@ -111,9 +184,35 @@ static void gpencil_calc_vertex(GPENCIL_StorageList *stl,
for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- cache_ob->tot_vertex += gps->totpoints + 3;
- cache_ob->tot_triangles += gps->totpoints - 1;
+ if (!is_onion) {
+ if ((!is_multiedit) ||
+ ((is_multiedit) && ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)))) {
+ cache_ob->tot_vertex += gps->totpoints + 3;
+ cache_ob->tot_triangles += gps->totpoints - 1;
+ }
+ }
+ else {
+ /* Only selected frames. */
+ if ((mode == GP_ONION_MODE_SELECTED) && ((gpf->flag & GP_FRAME_SELECT) == 0)) {
+ continue;
+ }
+ /* Verify keyframe type. */
+ if ((onion_keytype > -1) && (gpf->key_type != onion_keytype)) {
+ continue;
+ }
+ /* Absolute range. */
+ if (mode == GP_ONION_MODE_ABSOLUTE) {
+ if ((gpl->actframe) && (abs(gpl->actframe->framenum - gpf->framenum) > step)) {
+ continue;
+ }
+ }
+ /* For relative range it takes too much time compute, so use all frames. */
+ cache_ob->tot_vertex += gps->totpoints + 3;
+ cache_ob->tot_triangles += gps->totpoints - 1;
+ }
}
+
+ /* If not multiframe nor Onion skin, don't need follow counting. */
if ((!is_multiedit) && (!is_onion)) {
break;
}
@@ -208,8 +307,11 @@ static void gpencil_calc_2d_bounding_box(const float (*points2d)[2],
}
/* calc texture coordinates using flat projected points */
-static void gpencil_calc_stroke_fill_uv(
- const float (*points2d)[2], int totpoints, float minv[2], float maxv[2], float (*r_uv)[2])
+static void gpencil_calc_stroke_fill_uv(const float (*points2d)[2],
+ int totpoints,
+ const float minv[2],
+ float maxv[2],
+ float (*r_uv)[2])
{
float d[2];
d[0] = maxv[0] - minv[0];
@@ -264,7 +366,6 @@ static void set_wireframe_color(Object *ob,
else {
copy_v4_v4(color, gp_style->stroke_rgba);
}
- float alpha = color[3];
/* wire color */
if ((v3d) && (id > -1)) {
@@ -301,13 +402,13 @@ static void set_wireframe_color(Object *ob,
else {
copy_v3_v3(color, v3d->shading.single_color);
}
- color[3] = alpha;
+ color[3] = 1.0f;
linearrgb_to_srgb_v4(stl->shgroups[id].wire_color, color);
break;
}
case V3D_SHADING_OBJECT_COLOR: {
copy_v4_v4(color, ob->color);
- color[3] = alpha;
+ color[3] = 1.0f;
linearrgb_to_srgb_v4(stl->shgroups[id].wire_color, color);
break;
}
@@ -324,7 +425,7 @@ static void set_wireframe_color(Object *ob,
hsv_to_rgb_v(hsv, &wire_col[0]);
copy_v3_v3(stl->shgroups[id].wire_color, wire_col);
- stl->shgroups[id].wire_color[3] = alpha;
+ stl->shgroups[id].wire_color[3] = 1.0f;
break;
}
default: {
@@ -337,22 +438,24 @@ static void set_wireframe_color(Object *ob,
copy_v4_v4(stl->shgroups[id].wire_color, color);
}
- /* if solid, the alpha must be set to 1.0 */
+ /* if solid, the alpha must be set to alpha */
if (stl->shgroups[id].shading_type[0] == OB_SOLID) {
stl->shgroups[id].wire_color[3] = 1.0f;
}
}
/* create shading group for filling */
-static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_Data *vedata,
+static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_e_data *e_data,
+ GPENCIL_Data *vedata,
DRWPass *pass,
GPUShader *shader,
Object *ob,
+ float (*obmat)[4],
bGPdata *gpd,
bGPDlayer *gpl,
MaterialGPencilStyle *gp_style,
int id,
- int shading_type[2])
+ const int shading_type[2])
{
GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
const DRWContextState *draw_ctx = DRW_context_state_get();
@@ -361,6 +464,8 @@ static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_Data *vedata,
/* e_data.gpencil_fill_sh */
DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
+ DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat);
+
DRW_shgroup_uniform_vec4(grp, "color2", gp_style->mix_rgba, 1);
/* set style type */
@@ -431,6 +536,12 @@ static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_Data *vedata,
DRW_shgroup_uniform_int(grp, "shading_type", &stl->shgroups[id].shading_type[0], 2);
+ /* Fade layer uniforms. */
+ gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, false);
+
+ /* Fade object uniforms. */
+ gpencil_set_fade_ob_uniforms(v3d, grp, gpencil_fade_object_check(stl, ob));
+
/* wire color */
set_wireframe_color(ob, gpl, v3d, stl, gp_style, id, true);
DRW_shgroup_uniform_vec4(grp, "wire_color", stl->shgroups[id].wire_color, 1);
@@ -464,7 +575,7 @@ static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_Data *vedata,
}
else {
/* if no texture defined, need a blank texture to avoid errors in draw manager */
- DRW_shgroup_uniform_texture(grp, "myTexture", stl->g_data->gpencil_blank_texture);
+ DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
stl->shgroups[id].texture_clamp = 0;
DRW_shgroup_uniform_int(grp, "texture_clamp", &stl->shgroups[id].texture_clamp, 1);
}
@@ -484,10 +595,12 @@ bool gpencil_onion_active(bGPdata *gpd)
}
/* create shading group for strokes */
-DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_Data *vedata,
+DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_e_data *e_data,
+ GPENCIL_Data *vedata,
DRWPass *pass,
GPUShader *shader,
Object *ob,
+ float (*obmat)[4],
bGPdata *gpd,
bGPDlayer *gpl,
bGPDstroke *gps,
@@ -509,6 +622,8 @@ DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_Data *vedata,
DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat);
+
/* avoid wrong values */
if ((gpd) && (gpd->pixfactor == 0.0f)) {
gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
@@ -553,6 +668,12 @@ DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_Data *vedata,
}
DRW_shgroup_uniform_int(grp, "shading_type", &stl->shgroups[id].shading_type[0], 2);
+ /* Fade layer uniforms. */
+ gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, false);
+
+ /* Fade object uniforms. */
+ gpencil_set_fade_ob_uniforms(v3d, grp, gpencil_fade_object_check(stl, ob));
+
/* wire color */
set_wireframe_color(ob, gpl, v3d, stl, gp_style, id, false);
DRW_shgroup_uniform_vec4(grp, "wire_color", stl->shgroups[id].wire_color, 1);
@@ -603,6 +724,12 @@ DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_Data *vedata,
DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1);
}
+ /* Fade layer uniforms. */
+ gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, true);
+
+ /* Fade object uniforms. */
+ gpencil_set_fade_ob_uniforms(v3d, grp, false);
+
/* image texture for pattern */
if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
ImBuf *ibuf;
@@ -628,17 +755,19 @@ DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_Data *vedata,
}
else {
/* if no texture defined, need a blank texture to avoid errors in draw manager */
- DRW_shgroup_uniform_texture(grp, "myTexture", stl->g_data->gpencil_blank_texture);
+ DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
}
return grp;
}
/* create shading group for points */
-static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_Data *vedata,
+static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_e_data *e_data,
+ GPENCIL_Data *vedata,
DRWPass *pass,
GPUShader *shader,
Object *ob,
+ float (*obmat)[4],
bGPdata *gpd,
bGPDlayer *gpl,
bGPDstroke *gps,
@@ -659,6 +788,8 @@ static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_Data *vedata,
DRW_shgroup_uniform_vec2(grp, "Viewport", viewport_size, 1);
DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat);
+
/* avoid wrong values */
if ((gpd) && (gpd->pixfactor == 0.0f)) {
gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
@@ -702,6 +833,12 @@ static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_Data *vedata,
}
DRW_shgroup_uniform_int(grp, "shading_type", &stl->shgroups[id].shading_type[0], 2);
+ /* Fade layer uniforms. */
+ gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, false);
+
+ /* Fade object uniforms. */
+ gpencil_set_fade_ob_uniforms(v3d, grp, gpencil_fade_object_check(stl, ob));
+
/* wire color */
set_wireframe_color(ob, gpl, v3d, stl, gp_style, id, false);
DRW_shgroup_uniform_vec4(grp, "wire_color", stl->shgroups[id].wire_color, 1);
@@ -760,6 +897,12 @@ static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_Data *vedata,
DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1);
}
+ /* Fade layer uniforms. */
+ gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, true);
+
+ /* Fade object uniforms. */
+ gpencil_set_fade_ob_uniforms(v3d, grp, false);
+
/* image texture */
if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
ImBuf *ibuf;
@@ -785,7 +928,7 @@ static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_Data *vedata,
}
else {
/* if no texture defined, need a blank texture to avoid errors in draw manager */
- DRW_shgroup_uniform_texture(grp, "myTexture", stl->g_data->gpencil_blank_texture);
+ DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
}
return grp;
@@ -944,6 +1087,11 @@ static void gpencil_add_editpoints_vertexdata(GpencilBatchCache *cache,
GP_SCULPT_MASK_SELECTMODE_STROKE |
GP_SCULPT_MASK_SELECTMODE_SEGMENT)));
+ const bool show_sculpt_points = (GPENCIL_SCULPT_MODE(gpd) &&
+ (ts->gpencil_selectmode_sculpt &
+ (GP_SCULPT_MASK_SELECTMODE_POINT |
+ GP_SCULPT_MASK_SELECTMODE_SEGMENT)));
+
MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
/* alpha factor for edit points/line to make them more subtle */
@@ -955,8 +1103,19 @@ static void gpencil_add_editpoints_vertexdata(GpencilBatchCache *cache,
return;
}
const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
+
+ /* If Sculpt mode and the mask is disabled, the select must be hidden. */
const bool hide_select = GPENCIL_SCULPT_MODE(gpd) && !use_sculpt_mask;
+ /* Show Edit points if:
+ * Edit mode: Not in Stroke selection mode
+ * Sculpt mode: Not in Stroke mask mode and any other mask mode enabled
+ * Weight mode: Always
+ */
+ const bool show_points = (show_sculpt_points) || (is_weight_paint) ||
+ (GPENCIL_EDIT_MODE(gpd) &&
+ (ts->gpencil_selectmode_edit != GP_SELECTMODE_STROKE));
+
if (cache->is_dirty) {
if ((obact == ob) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) &&
(v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES)) {
@@ -976,8 +1135,8 @@ static void gpencil_add_editpoints_vertexdata(GpencilBatchCache *cache,
&cache->grp_used);
}
- /* In sculpt mode, the point are only visible if masking is enabled. */
- if (hide_select) {
+ /* If the points are hidden return. */
+ if ((!show_points) || (hide_select)) {
return;
}
@@ -1028,7 +1187,8 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache,
const bool playing = stl->storage->is_playing;
const bool is_render = (bool)stl->storage->is_render;
const bool is_mat_preview = (bool)stl->storage->is_mat_preview;
- const bool overlay_multiedit = v3d != NULL ? (v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) : true;
+ const bool overlay_multiedit = v3d != NULL ? !(v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) :
+ true;
/* Get evaluation context */
/* NOTE: We must check if C is valid, otherwise we get crashes when trying to save files
@@ -1052,6 +1212,12 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache,
continue;
}
+ /* Copy color to temp fields. */
+ if ((is_multiedit) && (gp_style)) {
+ copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
+ copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
+ }
+
/* be sure recalc all cache in source stroke to avoid recalculation when frame change
* and improve fps */
gpencil_recalc_geometry_caches(
@@ -1069,7 +1235,8 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache,
}
}
- if ((gpl->actframe->framenum == gpf->framenum) || (!is_multiedit) || (overlay_multiedit)) {
+ if ((gpl->actframe && (gpl->actframe->framenum == gpf->framenum)) || (!is_multiedit) ||
+ (overlay_multiedit)) {
/* hide any blend layer */
if ((!stl->storage->simplify_blend) || (gpl->blend_mode == eGplBlendMode_Regular)) {
/* fill */
@@ -1188,19 +1355,19 @@ static void gpencil_draw_onionskins(GpencilBatchCache *cache,
int idx;
float fac = 1.0f;
int step = 0;
- int mode = 0;
bool colflag = false;
- bGPDframe *gpf_loop = NULL;
+ const int mode = gpd->onion_mode;
+ bGPDframe *gpf_loop = ((gpd->onion_flag & GP_ONION_LOOP) && (mode != GP_ONION_MODE_SELECTED)) ?
+ gpl->frames.first :
+ NULL;
int last = gpf->framenum;
colflag = (bool)gpd->onion_flag & GP_ONION_GHOST_PREVCOL;
const short onion_keytype = gpd->onion_keytype;
-
/* -------------------------------
* 1) Draw Previous Frames First
* ------------------------------- */
step = gpd->gstep;
- mode = gpd->onion_mode;
if (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) {
copy_v3_v3(color, gpd->gcolor_prev);
@@ -1249,7 +1416,7 @@ static void gpencil_draw_onionskins(GpencilBatchCache *cache,
}
/* if loop option, save the frame to use later */
- if ((mode != GP_ONION_MODE_ABSOLUTE) && (gpd->onion_flag & GP_ONION_LOOP)) {
+ if ((mode == GP_ONION_MODE_SELECTED) && (gpd->onion_flag & GP_ONION_LOOP)) {
gpf_loop = gf;
}
@@ -1260,7 +1427,6 @@ static void gpencil_draw_onionskins(GpencilBatchCache *cache,
* 2) Now draw next frames
* ------------------------------- */
step = gpd->gstep_next;
- mode = gpd->onion_mode;
if (gpd->onion_flag & GP_ONION_GHOST_NEXTCOL) {
copy_v3_v3(color, gpd->gcolor_next);
@@ -1439,6 +1605,9 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data,
gp_style = BKE_material_gpencil_settings_get(ob, ob->actcol);
}
+ static float unit_mat[4][4] = {
+ {1.0, 0.0, 0.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, 0.0, 0.0, 1.0}};
+
/* drawing strokes */
/* Check if may need to draw the active stroke cache, only if this layer is the active layer
* that is being edited. (Stroke buffer is currently stored in gp-data)
@@ -1459,10 +1628,12 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data,
if (gpd->runtime.sbuffer_used > 1) {
if ((gp_style) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
stl->g_data->shgrps_drawing_stroke = gpencil_shgroup_stroke_create(
+ e_data,
vedata,
psl->drawing_pass,
e_data->gpencil_stroke_sh,
NULL,
+ unit_mat,
gpd,
NULL,
NULL,
@@ -1483,10 +1654,12 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data,
}
else {
stl->g_data->shgrps_drawing_stroke = gpencil_shgroup_point_create(
+ e_data,
vedata,
psl->drawing_pass,
e_data->gpencil_point_sh,
NULL,
+ unit_mat,
gpd,
NULL,
NULL,
@@ -1546,6 +1719,8 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data,
DRWShadingGroup *shgrp = DRW_shgroup_create(e_data->gpencil_edit_point_sh, psl->drawing_pass);
const float *viewport_size = DRW_viewport_size_get();
DRW_shgroup_uniform_vec2(shgrp, "Viewport", viewport_size, 1);
+ DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", unit_mat);
+
/* Disable stencil for this type */
DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
stl->g_data->batch_buffer_ctrlpoint = gpencil_get_buffer_ctrlpoint_geom(gpd);
@@ -1555,7 +1730,7 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data,
}
/* create all missing batches */
-static void gpencil_create_batches(GpencilBatchCache *cache)
+static void gpencil_batches_ensure(GpencilBatchCache *cache)
{
if ((cache->b_point.vbo) && (cache->b_point.batch == NULL)) {
cache->b_point.batch = GPU_batch_create_ex(
@@ -1608,7 +1783,7 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
true;
const bool main_onion = v3d != NULL ? (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) : true;
const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && main_onion &&
- gpencil_onion_active(gpd) && overlay;
+ overlay && gpencil_onion_active(gpd);
int start_stroke = 0;
int start_point = 0;
@@ -1617,6 +1792,8 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
int start_edlin = 0;
uint stencil_id = 1;
+ /* Flag to determine if the layer is above active layer. */
+ stl->storage->is_ontop = false;
for (int i = 0; i < cache->grp_used; i++) {
elm = &cache->grp_cache[i];
array_elm = &cache_ob->shgrp_array[idx];
@@ -1644,6 +1821,10 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
}
gpl = elm->gpl;
+ if ((!stl->storage->is_ontop) && (gpl->flag & GP_LAYER_ACTIVE)) {
+ stl->storage->is_ontop = true;
+ }
+
bGPDframe *gpf = elm->gpf;
bGPDstroke *gps = elm->gps;
MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
@@ -1663,10 +1844,12 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
case eGpencilBatchGroupType_Stroke: {
const int len = elm->vertex_idx - start_stroke;
- shgrp = gpencil_shgroup_stroke_create(vedata,
+ shgrp = gpencil_shgroup_stroke_create(e_data,
+ vedata,
stroke_pass,
e_data->gpencil_stroke_sh,
ob,
+ obmat,
gpd,
gpl,
gps,
@@ -1675,32 +1858,37 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
elm->onion,
scale,
cache_ob->shading_type);
- if ((do_onion) || (elm->onion == false)) {
- DRW_shgroup_call_range_obmat(shgrp, cache->b_stroke.batch, obmat, start_stroke, len);
- }
- stl->storage->shgroup_id++;
- start_stroke = elm->vertex_idx;
/* set stencil mask id */
if (gpencil_is_stencil_required(gp_style)) {
+ if (stencil_id == 1) {
+ /* Clear previous stencils. */
+ DRW_shgroup_clear_framebuffer(shgrp, GPU_STENCIL_BIT, 0, 0, 0, 0, 0.0f, 0x0);
+ }
DRW_shgroup_stencil_mask(shgrp, stencil_id);
stencil_id++;
}
else {
/* Disable stencil for this type */
DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- /* set stencil mask id as not used */
- DRW_shgroup_stencil_mask(shgrp, 0x0);
}
+
+ if ((do_onion) || (elm->onion == false)) {
+ DRW_shgroup_call_range(shgrp, cache->b_stroke.batch, start_stroke, len);
+ }
+ stl->storage->shgroup_id++;
+ start_stroke = elm->vertex_idx;
break;
}
case eGpencilBatchGroupType_Point: {
const int len = elm->vertex_idx - start_point;
- shgrp = gpencil_shgroup_point_create(vedata,
+ shgrp = gpencil_shgroup_point_create(e_data,
+ vedata,
stroke_pass,
e_data->gpencil_point_sh,
ob,
+ obmat,
gpd,
gpl,
gps,
@@ -1710,49 +1898,50 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
scale,
cache_ob->shading_type);
+ /* Disable stencil for this type */
+ DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
+
if ((do_onion) || (elm->onion == false)) {
- DRW_shgroup_call_range_obmat(shgrp, cache->b_point.batch, obmat, start_point, len);
+ DRW_shgroup_call_range(shgrp, cache->b_point.batch, start_point, len);
}
stl->storage->shgroup_id++;
start_point = elm->vertex_idx;
-
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- /* set stencil mask id as not used */
- DRW_shgroup_stencil_mask(shgrp, 0x0);
break;
}
case eGpencilBatchGroupType_Fill: {
const int len = elm->vertex_idx - start_fill;
- shgrp = gpencil_shgroup_fill_create(vedata,
+ shgrp = gpencil_shgroup_fill_create(e_data,
+ vedata,
stroke_pass,
e_data->gpencil_fill_sh,
ob,
+ obmat,
gpd,
gpl,
gp_style,
stl->storage->shgroup_id,
cache_ob->shading_type);
+ /* Disable stencil for this type */
+ DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
+
if ((do_onion) || (elm->onion == false)) {
- DRW_shgroup_call_range_obmat(shgrp, cache->b_fill.batch, obmat, start_fill, len);
+ DRW_shgroup_call_range(shgrp, cache->b_fill.batch, start_fill, len);
}
stl->storage->shgroup_id++;
start_fill = elm->vertex_idx;
-
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- /* set stencil mask id as not used */
- DRW_shgroup_stencil_mask(shgrp, 0x0);
break;
}
case eGpencilBatchGroupType_Edit: {
if (stl->g_data->shgrps_edit_point) {
const int len = elm->vertex_idx - start_edit;
+
+ shgrp = DRW_shgroup_create_sub(stl->g_data->shgrps_edit_point);
+ DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", obmat);
/* use always the same group */
- DRW_shgroup_call_range_obmat(
- stl->g_data->shgrps_edit_point, cache->b_edit.batch, obmat, start_edit, len);
+ DRW_shgroup_call_range(
+ stl->g_data->shgrps_edit_point, cache->b_edit.batch, start_edit, len);
start_edit = elm->vertex_idx;
}
@@ -1761,9 +1950,12 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
case eGpencilBatchGroupType_Edlin: {
if (stl->g_data->shgrps_edit_line) {
const int len = elm->vertex_idx - start_edlin;
+
+ shgrp = DRW_shgroup_create_sub(stl->g_data->shgrps_edit_line);
+ DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", obmat);
/* use always the same group */
- DRW_shgroup_call_range_obmat(
- stl->g_data->shgrps_edit_line, cache->b_edlin.batch, obmat, start_edlin, len);
+ DRW_shgroup_call_range(
+ stl->g_data->shgrps_edit_line, cache->b_edlin.batch, start_edlin, len);
start_edlin = elm->vertex_idx;
}
@@ -1803,6 +1995,7 @@ void gpencil_populate_multiedit(GPENCIL_e_data *e_data,
GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph);
GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval);
@@ -1818,45 +2011,29 @@ void gpencil_populate_multiedit(GPENCIL_e_data *e_data,
if (gpl->flag & GP_LAYER_HIDE) {
continue;
}
+ const float alpha = GPENCIL_SIMPLIFY_TINT(scene, playing) ? 0.0f : gpl->tintcolor[3];
+ const float tintcolor[4] = {gpl->tintcolor[0], gpl->tintcolor[1], gpl->tintcolor[2], alpha};
/* list of frames to draw */
if (!playing) {
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
- gpencil_draw_strokes(cache,
- e_data,
- vedata,
- ob,
- gpd,
- gpl,
- gpf,
- gpl->opacity,
- gpl->tintcolor,
- false,
- cache_ob);
+ gpencil_draw_strokes(
+ cache, e_data, vedata, ob, gpd, gpl, gpf, gpl->opacity, tintcolor, false, cache_ob);
}
}
}
else {
gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
if (gpf) {
- gpencil_draw_strokes(cache,
- e_data,
- vedata,
- ob,
- gpd,
- gpl,
- gpf,
- gpl->opacity,
- gpl->tintcolor,
- false,
- cache_ob);
+ gpencil_draw_strokes(
+ cache, e_data, vedata, ob, gpd, gpl, gpf, gpl->opacity, tintcolor, false, cache_ob);
}
}
}
/* create batchs and shading groups */
- gpencil_create_batches(cache);
+ gpencil_batches_ensure(cache);
gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
cache->is_dirty = false;
@@ -1873,23 +2050,36 @@ void gpencil_populate_datablock(GPENCIL_e_data *e_data,
const ViewLayer *view_layer = DEG_get_evaluated_view_layer(draw_ctx->depsgraph);
Scene *scene = draw_ctx->scene;
+ /* TODO: Review why is needed this recalc when render cycles + GP object in background.
+ * We need these lines to keep running the background render, but asap we get an alternative
+ * solution, we must remove it and keep all logic inside gpencil_modifier module. (antoniov)
+ */
+ if (ob->runtime.gpencil_tot_layers == 0) {
+ BKE_gpencil_modifiers_calc(draw_ctx->depsgraph, draw_ctx->scene, ob);
+ }
+
/* Use original data to shared in edit/transform operators */
bGPdata *gpd_eval = (bGPdata *)ob->data;
bGPdata *gpd = (bGPdata *)DEG_get_original_id(&gpd_eval->id);
+ const bool main_onion = draw_ctx->v3d != NULL ?
+ (draw_ctx->v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) :
+ true;
+ const bool playing = stl->storage->is_playing;
+ const bool overlay = draw_ctx->v3d != NULL ?
+ (bool)((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) :
+ true;
+ const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay &&
+ main_onion && !playing && gpencil_onion_active(gpd);
+
View3D *v3d = draw_ctx->v3d;
int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph);
bGPDframe *gpf_eval = NULL;
- const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) : true;
const bool time_remap = BKE_gpencil_has_time_modifiers(ob);
float opacity;
bGPDframe *gpf = NULL;
- bGPDlayer *gpl_active = BKE_gpencil_layer_getactive(gpd);
-
- /* check if playing animation */
- const bool playing = stl->storage->is_playing;
GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval);
@@ -1942,12 +2132,6 @@ void gpencil_populate_datablock(GPENCIL_e_data *e_data,
(v3d->overlay.flag & V3D_OVERLAY_BONE_SELECT)) {
opacity = opacity * v3d->overlay.xray_alpha_bone;
}
- /* fade no active layers */
- if ((overlay) && (draw_ctx->object_mode == OB_MODE_PAINT_GPENCIL) &&
- (v3d->gp_flag & V3D_GP_FADE_NOACTIVE_LAYERS) && (draw_ctx->obact) &&
- (draw_ctx->obact == ob) && (gpl != gpl_active)) {
- opacity = opacity * v3d->overlay.gpencil_fade_layer;
- }
/* Get evaluated frames array data */
int idx_eval = BLI_findindex(&gpd->layers, gpl);
@@ -1955,7 +2139,7 @@ void gpencil_populate_datablock(GPENCIL_e_data *e_data,
/* draw onion skins */
if (!ID_IS_LINKED(&gpd->id)) {
- if ((gpl->onion_flag & GP_LAYER_ONIONSKIN) &&
+ if ((do_onion) && (gpl->onion_flag & GP_LAYER_ONIONSKIN) &&
((!playing) || (gpd->onion_flag & GP_ONION_GHOST_ALWAYS)) && (!cache_ob->is_dup_ob) &&
(gpd->id.us <= 1)) {
if ((!stl->storage->is_render) ||
@@ -1965,12 +2149,14 @@ void gpencil_populate_datablock(GPENCIL_e_data *e_data,
}
}
/* draw normal strokes */
+ const float alpha = GPENCIL_SIMPLIFY_TINT(scene, playing) ? 0.0f : gpl->tintcolor[3];
+ const float tintcolor[4] = {gpl->tintcolor[0], gpl->tintcolor[1], gpl->tintcolor[2], alpha};
gpencil_draw_strokes(
- cache, e_data, vedata, ob, gpd, gpl, gpf_eval, opacity, gpl->tintcolor, false, cache_ob);
+ cache, e_data, vedata, ob, gpd, gpl, gpf_eval, opacity, tintcolor, false, cache_ob);
}
/* create batchs and shading groups */
- gpencil_create_batches(cache);
+ gpencil_batches_ensure(cache);
gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
cache->is_dirty = false;
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index aa5918feaa8..7d9f2d1fdf3 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -62,6 +62,8 @@ extern char datatoc_gpencil_edit_point_frag_glsl[];
extern char datatoc_gpencil_blend_frag_glsl[];
extern char datatoc_gpencil_merge_depth_frag_glsl[];
+extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
+
extern char datatoc_common_colormanagement_lib_glsl[];
extern char datatoc_common_view_lib_glsl[];
@@ -112,7 +114,7 @@ static void GPENCIL_create_framebuffers(void *vedata)
const float *viewport_size = DRW_viewport_size_get();
const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
- /* create multiframe framebuffer for AA */
+ /* create multisample framebuffer for AA */
if ((stl->storage->framebuffer_flag & GP_FRAMEBUFFER_MULTISAMPLE) &&
(stl->storage->multisamples > 0)) {
gpencil_multisample_ensure(vedata, size[0], size[1]);
@@ -177,6 +179,12 @@ static void GPENCIL_create_framebuffers(void *vedata)
static void GPENCIL_create_shaders(void)
{
+ /* blank texture used if no texture defined for fill shader */
+ if (!e_data.gpencil_blank_texture) {
+ float rect[1][1][4] = {{{0.0f}}};
+ e_data.gpencil_blank_texture = DRW_texture_create_2d(
+ 1, 1, GPU_RGBA8, DRW_TEX_FILTER, (float *)rect);
+ }
/* normal fill shader */
if (!e_data.gpencil_fill_sh) {
e_data.gpencil_fill_sh = GPU_shader_create_from_arrays({
@@ -222,7 +230,12 @@ static void GPENCIL_create_shaders(void)
/* used for edit lines for edit modes */
if (!e_data.gpencil_line_sh) {
- e_data.gpencil_line_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_FLAT_COLOR);
+ e_data.gpencil_line_sh = DRW_shader_create_with_lib(
+ datatoc_gpencil_edit_point_vert_glsl,
+ NULL,
+ datatoc_gpu_shader_3D_smooth_color_frag_glsl,
+ datatoc_common_view_lib_glsl,
+ NULL);
}
/* used to filling during drawing */
@@ -283,6 +296,7 @@ static void GPENCIL_engine_free(void)
DRW_SHADER_FREE_SAFE(e_data.gpencil_stroke_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_point_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_edit_point_sh);
+ DRW_SHADER_FREE_SAFE(e_data.gpencil_line_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_fullscreen_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_simple_fullscreen_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_blend_fullscreen_sh);
@@ -290,6 +304,8 @@ static void GPENCIL_engine_free(void)
DRW_SHADER_FREE_SAFE(e_data.gpencil_background_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_paper_sh);
+ DRW_TEXTURE_FREE_SAFE(e_data.gpencil_blank_texture);
+
/* effects */
GPENCIL_delete_fx_shaders(&e_data);
}
@@ -335,17 +351,11 @@ void GPENCIL_cache_init(void *vedata)
stl->g_data->shgrps_edit_point = NULL;
/* reset textures */
- stl->g_data->gpencil_blank_texture = NULL;
stl->g_data->batch_buffer_stroke = NULL;
stl->g_data->batch_buffer_fill = NULL;
stl->g_data->batch_buffer_ctrlpoint = NULL;
stl->g_data->batch_grid = NULL;
- /* blank texture used if no texture defined for fill shader */
- float rect[1][1][4] = {{{0.0f}}};
- stl->g_data->gpencil_blank_texture = DRW_texture_create_2d(
- 1, 1, GPU_RGBA8, DRW_TEX_FILTER, (float *)rect);
-
if (!stl->shgroups) {
/* Alloc maximum size because count strokes is very slow and can be very complex due onion
* skinning.
@@ -799,8 +809,6 @@ void DRW_gpencil_free_runtime_data(void *ved)
GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
/* free gpu data */
- DRW_TEXTURE_FREE_SAFE(stl->g_data->gpencil_blank_texture);
-
GPU_BATCH_DISCARD_SAFE(stl->g_data->batch_buffer_stroke);
MEM_SAFE_FREE(stl->g_data->batch_buffer_stroke);
@@ -847,66 +855,18 @@ static void gpencil_draw_pass_range(GPENCIL_StorageList *stl,
return;
}
- DRWShadingGroup *shgrp = init_shgrp;
- DRWShadingGroup *from_shgrp = init_shgrp;
- DRWShadingGroup *to_shgrp = init_shgrp;
- int stencil_tot = 0;
- bool do_last = true;
-
- /* Loop all shading groups to separate by stencil groups. */
- while ((shgrp) && (shgrp != end_shgrp)) {
- do_last = true;
- /* Count number of groups using stencil. */
- if (DRW_shgroup_stencil_mask_get(shgrp) != 0) {
- stencil_tot++;
- }
+ const bool do_antialiasing = ((!stl->storage->is_mat_preview) && (multi));
- /* Draw stencil group and clear stencil bit. This is required because the number of
- * shading groups can be greater than the limit of 255 stencil values.
- * Only count as stencil if the shading group has an stencil value assigned. This reduces
- * the number of clears because Dots, Fills and some Line strokes don't need stencil.
- */
- if (stencil_tot == 255) {
- DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d :
- psl->stroke_pass_2d,
- from_shgrp,
- to_shgrp);
- /* Clear Stencil and prepare for next group. */
- GPU_framebuffer_clear_stencil(fb, 0x0);
-
- /* Set new init group and reset. */
- do_last = false;
-
- shgrp = DRW_shgroup_get_next(shgrp);
- if (shgrp) {
- from_shgrp = to_shgrp = shgrp;
- stencil_tot = 0;
- if (shgrp != end_shgrp) {
- continue;
- }
- else {
- do_last = true;
- break;
- }
- }
- else {
- /* No more groups. */
- break;
- }
- }
-
- /* Still below stencil group limit. */
- shgrp = DRW_shgroup_get_next(shgrp);
- if (shgrp) {
- to_shgrp = shgrp;
- }
+ if (do_antialiasing) {
+ MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl);
}
- /* Draw last pending groups. */
- if (do_last) {
- DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d : psl->stroke_pass_2d,
- from_shgrp,
- to_shgrp);
+ DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d : psl->stroke_pass_2d,
+ init_shgrp,
+ end_shgrp);
+
+ if (do_antialiasing) {
+ MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fb, txl);
}
}
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index f723bd16634..c475c343d22 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -147,6 +147,7 @@ typedef struct GPENCIL_Storage {
bool is_mat_preview;
bool background_ready;
int is_xray;
+ bool is_ontop;
bool reset_cache;
const float *pixsize;
float render_pixsize;
@@ -267,9 +268,6 @@ typedef struct g_data {
/* grid geometry */
GPUBatch *batch_grid;
- /* textures */
- struct GPUTexture *gpencil_blank_texture;
-
/* runtime pointers texture */
struct GPUTexture *input_depth_tx;
struct GPUTexture *input_color_tx;
@@ -299,6 +297,9 @@ typedef enum eGPsession_Flag {
} eGPsession_Flag;
typedef struct GPENCIL_e_data {
+ /* textures */
+ struct GPUTexture *gpencil_blank_texture;
+
/* general drawing shaders */
struct GPUShader *gpencil_fill_sh;
struct GPUShader *gpencil_stroke_sh;
@@ -389,10 +390,12 @@ typedef struct GpencilBatchCache {
} GpencilBatchCache;
/* general drawing functions */
-struct DRWShadingGroup *gpencil_shgroup_stroke_create(struct GPENCIL_Data *vedata,
+struct DRWShadingGroup *gpencil_shgroup_stroke_create(struct GPENCIL_e_data *e_data,
+ struct GPENCIL_Data *vedata,
struct DRWPass *pass,
struct GPUShader *shader,
struct Object *ob,
+ float (*obmat)[4],
struct bGPdata *gpd,
struct bGPDlayer *gpl,
struct bGPDstroke *gps,
diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c
index 56ba90067cf..f1d704a72a3 100644
--- a/source/blender/draw/engines/gpencil/gpencil_render.c
+++ b/source/blender/draw/engines/gpencil/gpencil_render.c
@@ -73,7 +73,7 @@ void GPENCIL_render_init(GPENCIL_Data *ved, RenderEngine *engine, struct Depsgra
* because there is no viewport. So we need to manually create one
* NOTE : use 32 bit format for precision in render mode.
*/
- /* create multiframe framebuffer for AA */
+ /* create multisample framebuffer for AA */
if (U.gpencil_multisamples > 0) {
int rect_w = (int)viewport_size[0];
int rect_h = (int)viewport_size[1];
@@ -131,7 +131,7 @@ static void GPENCIL_render_cache(void *vedata,
/* TODO: Reuse Eevee code in shared module instead to duplicate here */
static void GPENCIL_render_update_viewvecs(float invproj[4][4],
- float winmat[4][4],
+ const float winmat[4][4],
float (*r_viewvecs)[4])
{
/* view vectors for the corners of the view frustum.
@@ -308,6 +308,9 @@ void GPENCIL_render_to_image(void *vedata,
DRW_render_object_iter(vedata, engine, draw_ctx->depsgraph, GPENCIL_render_cache);
GPENCIL_cache_finish(vedata);
+
+ DRW_render_instance_buffer_finish();
+
GPENCIL_draw_scene(vedata);
/* combined data */
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl
index a1cfb2ae4ae..f75322f90e2 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl
@@ -1,4 +1,6 @@
+uniform mat4 gpModelMatrix;
+
in vec3 pos;
in vec4 color;
in float size;
@@ -8,7 +10,7 @@ out float finalThickness;
void main()
{
- gl_Position = point_object_to_ndc(pos);
+ gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
finalColor = color;
finalThickness = size;
}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
index 64bb70f2a3f..0c290260b20 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
@@ -26,6 +26,12 @@ uniform int viewport_xray;
uniform int shading_type[2];
uniform vec4 wire_color;
+uniform int fade_layer;
+uniform float fade_layer_factor;
+uniform bool fade_ob;
+uniform vec3 fade_color;
+uniform float fade_ob_factor;
+
/* keep this list synchronized with list in gpencil_draw_utils.c */
#define SOLID 0
#define GRADIENT 1
@@ -211,4 +217,16 @@ void main()
fragColor.a *= 0.5;
}
}
+ /* Apply paper opacity */
+ if (fade_layer == 1) {
+ /* Layer is below, mix with background. */
+ fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_layer_factor);
+ }
+ else if (fade_layer == 2) {
+ /* Layer is above, change opacity. */
+ fragColor.a *= fade_layer_factor;
+ }
+ else if (fade_ob == true) {
+ fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_ob_factor);
+ }
}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl
index eb452f4c660..263dc570423 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl
@@ -1,4 +1,6 @@
+uniform mat4 gpModelMatrix;
+
in vec3 pos;
in vec4 color;
in vec2 texCoord;
@@ -8,7 +10,7 @@ out vec2 texCoord_interp;
void main(void)
{
- gl_Position = point_object_to_ndc(pos);
+ gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
finalColor = color;
texCoord_interp = texCoord;
}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl
index 34777018a73..d79b8fb4d8a 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl
@@ -14,6 +14,12 @@ in vec4 mColor;
in vec2 mTexCoord;
out vec4 fragColor;
+uniform int fade_layer;
+uniform float fade_layer_factor;
+uniform bool fade_ob;
+uniform vec3 fade_color;
+uniform float fade_ob_factor;
+
#define texture2D texture
#define GPENCIL_MODE_LINE 0
@@ -104,4 +110,17 @@ void main()
if (fragColor.a < 0.0035) {
discard;
}
+
+ /* Apply paper opacity */
+ if (fade_layer == 1) {
+ /* Layer is below, mix with background. */
+ fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_layer_factor);
+ }
+ else if (fade_layer == 2) {
+ /* Layer is above, change opacity. */
+ fragColor.a *= fade_layer_factor;
+ }
+ else if (fade_ob == true) {
+ fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_ob_factor);
+ }
}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
index ef8b361373f..87963c66858 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
@@ -6,6 +6,7 @@ uniform float pixfactor;
uniform int viewport_xray;
uniform int shading_type[2];
uniform vec4 wire_color;
+uniform mat4 gpModelMatrix;
in vec3 pos;
in vec4 color;
@@ -30,8 +31,8 @@ float defaultpixsize = pixsize * (1000.0 / pixfactor);
void main()
{
- gl_Position = point_object_to_ndc(pos);
- finalprev_pos = point_object_to_ndc(prev_pos);
+ gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
+ finalprev_pos = point_world_to_ndc((gpModelMatrix * vec4(prev_pos, 1.0)).xyz);
finalColor = color;
if (keep_size == TRUE) {
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl
index 73baacb35d4..0f1665b73c2 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl
@@ -8,6 +8,12 @@ uniform vec4 colormix;
uniform float mix_stroke_factor;
uniform int shading_type[2];
+uniform int fade_layer;
+uniform float fade_layer_factor;
+uniform bool fade_ob;
+uniform vec3 fade_color;
+uniform float fade_ob_factor;
+
in vec4 mColor;
in vec2 mTexCoord;
in vec2 uvfac;
@@ -88,4 +94,17 @@ void main()
if (fragColor.a < 0.0035) {
discard;
}
+
+ /* Apply paper opacity */
+ if (fade_layer == 1) {
+ /* Layer is below, mix with background. */
+ fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_layer_factor);
+ }
+ else if (fade_layer == 2) {
+ /* Layer is above, change opacity. */
+ fragColor.a *= fade_layer_factor;
+ }
+ else if (fade_ob == true) {
+ fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_ob_factor);
+ }
}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
index c7089f357f9..582b9a7f249 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
@@ -6,6 +6,7 @@ uniform float pixfactor;
uniform int viewport_xray;
uniform int shading_type[2];
uniform vec4 wire_color;
+uniform mat4 gpModelMatrix;
in vec3 pos;
in vec4 color;
@@ -28,7 +29,7 @@ float defaultpixsize = pixsize * (1000.0 / pixfactor);
void main(void)
{
- gl_Position = point_object_to_ndc(pos);
+ gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
finalColor = color;
if (keep_size == TRUE) {
diff --git a/source/blender/draw/engines/select/select_draw_utils.c b/source/blender/draw/engines/select/select_draw_utils.c
index ec47d6ea8eb..f1d008c29c7 100644
--- a/source/blender/draw/engines/select/select_draw_utils.c
+++ b/source/blender/draw/engines/select/select_draw_utils.c
@@ -49,8 +49,7 @@ void select_id_object_min_max(Object *obj, float r_min[3], float r_max[3])
BoundBox *bb;
BMEditMesh *em = BKE_editmesh_from_object(obj);
if (em) {
- /* Use Object Texture Space. */
- bb = BKE_mesh_texspace_get(em->mesh_eval_cage, NULL, NULL, NULL);
+ bb = BKE_editmesh_cage_boundbox_get(em);
}
else {
bb = BKE_object_boundbox_get(obj);
@@ -63,12 +62,18 @@ short select_id_get_object_select_mode(Scene *scene, Object *ob)
{
short r_select_mode = 0;
if (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT)) {
+ /* In order to sample flat colors for vertex weights / texture-paint / vertex-paint
+ * we need to be in SCE_SELECT_FACE mode so select_cache_init() correctly sets up
+ * a shgroup with select_id_flat.
+ * Note this is not working correctly for vertex-paint (yet), but has been discussed
+ * in T66645 and there is a solution by @mano-wii in P1032.
+ * So OB_MODE_VERTEX_PAINT is already included here [required for P1032 I guess]. */
Mesh *me_orig = DEG_get_original_object(ob)->data;
- if (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL) {
- r_select_mode = SCE_SELECT_FACE;
- }
if (me_orig->editflag & ME_EDIT_PAINT_VERT_SEL) {
- r_select_mode |= SCE_SELECT_VERTEX;
+ r_select_mode = SCE_SELECT_VERTEX;
+ }
+ else {
+ r_select_mode = SCE_SELECT_FACE;
}
}
else {
@@ -123,7 +128,11 @@ static void draw_select_id_edit_mesh(SELECTID_StorageList *stl,
}
else {
if (ob->dt >= OB_SOLID) {
+#ifdef USE_CAGE_OCCLUSION
+ struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me);
+#else
struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_surface(me);
+#endif
DRWShadingGroup *face_shgrp = stl->g_data->shgrp_face_unif;
DRW_shgroup_call_no_cull(face_shgrp, geom_faces, ob);
}
diff --git a/source/blender/draw/engines/select/select_engine.c b/source/blender/draw/engines/select/select_engine.c
index 5dc20a589f0..abfa57dd218 100644
--- a/source/blender/draw/engines/select/select_engine.c
+++ b/source/blender/draw/engines/select/select_engine.c
@@ -252,7 +252,11 @@ static void select_cache_populate(void *vedata, Object *ob)
DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_faces, ob->obmat);
}
else if (ob->dt >= OB_SOLID) {
+#ifdef USE_CAGE_OCCLUSION
+ struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me);
+#else
struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_surface(me);
+#endif
DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_faces, ob->obmat);
}
diff --git a/source/blender/draw/engines/select/select_private.h b/source/blender/draw/engines/select/select_private.h
index 642cd6ffc56..1e99a49252e 100644
--- a/source/blender/draw/engines/select/select_private.h
+++ b/source/blender/draw/engines/select/select_private.h
@@ -23,6 +23,8 @@
#ifndef __SELECT_PRIVATE_H__
#define __SELECT_PRIVATE_H__
+#define USE_CAGE_OCCLUSION
+
#include "DRW_render.h"
/* GPUViewport.storage
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl
index a1f80440404..fd4cea4279a 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl
@@ -5,7 +5,8 @@ uniform sampler2D materialBuffer;
uniform sampler2D normalBuffer;
/* normalBuffer contains viewport normals */
uniform sampler2D cavityBuffer;
-uniform sampler2D matcapImage;
+uniform sampler2D matcapDiffuseImage;
+uniform sampler2D matcapSpecularImage;
uniform vec2 invertedViewportSize;
uniform vec4 viewvecs[3];
@@ -55,8 +56,15 @@ void main()
normal_viewport = (metallic > 0.0) ? normal_viewport : -normal_viewport;
bool flipped = world_data.matcap_orientation != 0;
vec2 matcap_uv = matcap_uv_compute(I_vs, normal_viewport, flipped);
- vec3 matcap = textureLod(matcapImage, matcap_uv, 0.0).rgb;
- vec3 shaded_color = matcap * base_color;
+ vec3 matcap_diffuse = textureLod(matcapDiffuseImage, matcap_uv, 0.0).rgb;
+
+# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
+ vec3 matcap_specular = textureLod(matcapSpecularImage, matcap_uv, 0.0).rgb;
+# else
+ vec3 matcap_specular = vec3(0.0);
+# endif
+
+ vec3 shaded_color = matcap_diffuse * base_color + matcap_specular;
#elif defined(V3D_LIGHTING_STUDIO)
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
index 0428b0d408c..bd16189db32 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
@@ -256,7 +256,7 @@ void main()
float coc = decode_coc(texelFetch(inputCocTex, texel, 0).rg);
float max_radius = coc;
vec2 noise = get_random_vector(noiseOffset) * 0.2 * clamp(max_radius * 0.2 - 4.0, 0.0, 1.0);
- for (int i = 0; i < NUM_SAMPLES; ++i) {
+ for (int i = 0; i < NUM_SAMPLES; i++) {
vec2 tc = uv + (noise + samples[i].xy) * invertedViewportSize * max_radius;
/* decode_signed_coc return biggest coc. */
@@ -359,8 +359,8 @@ void main()
vec v[9];
/* Add the pixels which make up our window to the pixel array. */
- for (int dX = -1; dX <= 1; ++dX) {
- for (int dY = -1; dY <= 1; ++dY) {
+ for (int dX = -1; dX <= 1; dX++) {
+ for (int dY = -1; dY <= 1; dY++) {
vec2 offset = vec2(float(dX), float(dY));
/* If a pixel in the window is located at (x+dX, y+dY), put it at index (dX + R)(2R + 1) +
* (dY + R) of the pixel array. This will fill the pixel array, with the top left pixel of
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl
index 505b4822ad6..abd8c1f6579 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl
@@ -1,5 +1,6 @@
-uniform int object_id = 0;
+
layout(location = 0) out uint objectId;
+
uniform float ImageTransparencyCutoff = 0.1;
#ifdef V3D_SHADING_TEXTURE_COLOR
uniform sampler2D image;
@@ -10,11 +11,10 @@ in vec2 uv_interp;
void main()
{
#ifdef V3D_SHADING_TEXTURE_COLOR
- vec4 diffuse_color = texture(image, uv_interp);
- if (diffuse_color.a < ImageTransparencyCutoff) {
+ if (texture(image, uv_interp).a < ImageTransparencyCutoff) {
discard;
}
#endif
- objectId = uint(object_id);
+ objectId = uint(resource_id + 1) & 0xFFu;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
index c78b2182d04..f799ce41cb2 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
@@ -8,8 +8,7 @@ uniform float alpha = 0.5;
uniform vec2 invertedViewportSize;
uniform vec4 viewvecs[3];
-uniform vec3 materialDiffuseColor;
-uniform vec3 materialSpecularColor;
+uniform vec4 materialColorAndMetal;
uniform float materialRoughness;
uniform float shadowMultiplier = 0.5;
@@ -27,7 +26,8 @@ in vec2 uv_interp;
in vec3 vertexColor;
#endif
#ifdef V3D_LIGHTING_MATCAP
-uniform sampler2D matcapImage;
+uniform sampler2D matcapDiffuseImage;
+uniform sampler2D matcapSpecularImage;
#endif
layout(std140) uniform world_block
@@ -41,17 +41,17 @@ layout(location = 1) out
void main()
{
- vec4 diffuse_color;
+ vec4 base_color;
#if defined(V3D_SHADING_TEXTURE_COLOR)
- diffuse_color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied);
- if (diffuse_color.a < ImageTransparencyCutoff) {
+ base_color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied);
+ if (base_color.a < ImageTransparencyCutoff) {
discard;
}
#elif defined(V3D_SHADING_VERTEX_COLOR)
- diffuse_color = vec4(vertexColor, 1.0);
+ base_color.rgb = vertexColor;
#else
- diffuse_color = vec4(materialDiffuseColor, 1.0);
+ base_color.rgb = materialColorAndMetal.rgb;
#endif /* V3D_SHADING_TEXTURE_COLOR */
vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize;
@@ -63,17 +63,31 @@ void main()
/* -------- SHADING --------- */
#ifdef V3D_LIGHTING_FLAT
- vec3 shaded_color = diffuse_color.rgb;
+ vec3 shaded_color = base_color.rgb;
#elif defined(V3D_LIGHTING_MATCAP)
bool flipped = world_data.matcap_orientation != 0;
vec2 matcap_uv = matcap_uv_compute(I_vs, nor, flipped);
- vec3 matcap = textureLod(matcapImage, matcap_uv, 0.0).rgb;
- vec3 shaded_color = matcap * diffuse_color.rgb;
+ vec3 matcap_diffuse = textureLod(matcapDiffuseImage, matcap_uv, 0.0).rgb;
+# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
+ vec3 matcap_specular = textureLod(matcapSpecularImage, matcap_uv, 0.0).rgb;
+# else
+ vec3 matcap_specular = vec3(0.0);
+# endif
+ vec3 shaded_color = matcap_diffuse * base_color.rgb + matcap_specular;
#elif defined(V3D_LIGHTING_STUDIO)
+# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
+ float metallic = materialColorAndMetal.a;
+ vec3 specular_color = mix(vec3(0.05), base_color.rgb, metallic);
+ vec3 diffuse_color = mix(base_color.rgb, vec3(0.0), metallic);
+# else
+ vec3 specular_color = vec3(0.0);
+ vec3 diffuse_color = base_color.rgb;
+# endif
+
vec3 shaded_color = get_world_lighting(
- world_data, diffuse_color.rgb, materialSpecularColor, materialRoughness, nor, I_vs);
+ world_data, diffuse_color, specular_color, materialRoughness, nor, I_vs);
#endif
#ifdef V3D_SHADING_SHADOW
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
index c673b2484de..b5f95f2dcf8 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
@@ -1,7 +1,5 @@
-uniform int object_id = 0;
-uniform vec3 materialDiffuseColor;
-uniform float materialMetallic;
+uniform vec4 materialColorAndMetal;
uniform float materialRoughness;
uniform sampler2D image;
@@ -48,7 +46,7 @@ void main()
# elif defined(V3D_SHADING_VERTEX_COLOR)
color.rgb = vertexColor;
# else
- color.rgb = materialDiffuseColor;
+ color.rgb = materialColorAndMetal.rgb;
# endif
# ifdef V3D_LIGHTING_MATCAP
@@ -56,7 +54,7 @@ void main()
metallic = float(gl_FrontFacing);
roughness = 0.0;
# else
- metallic = materialMetallic;
+ metallic = materialColorAndMetal.a;
roughness = materialRoughness;
# endif
@@ -64,7 +62,7 @@ void main()
/* Add some variation to the hairs to avoid uniform look. */
float hair_variation = hair_rand * 0.1;
color = clamp(color - hair_variation, 0.0, 1.0);
- metallic = clamp(materialMetallic - hair_variation, 0.0, 1.0);
+ metallic = clamp(materialColorAndMetal.a - hair_variation, 0.0, 1.0);
roughness = clamp(materialRoughness - hair_variation, 0.0, 1.0);
# endif
@@ -73,7 +71,7 @@ void main()
#endif /* MATDATA_PASS_ENABLED */
#ifdef OBJECT_ID_PASS_ENABLED
- objectId = uint(object_id);
+ objectId = uint(resource_id + 1) & 0xFFu;
#endif
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
index 7eb12dbdeb9..04dd9ab85bb 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
@@ -25,6 +25,10 @@ out vec2 uv_interp;
out vec3 vertexColor;
#endif
+#ifdef OBJECT_ID_PASS_ENABLED
+RESOURCE_ID_VARYING
+#endif
+
/* From http://libnoise.sourceforge.net/noisegen/index.html */
float integer_noise(int n)
{
@@ -91,12 +95,18 @@ void main()
#endif
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
- normal_viewport = normal_object_to_view(nor);
# ifndef HAIR_SHADER
+ normal_viewport = normal_object_to_view(nor);
normal_viewport = normalize(normal_viewport);
+# else
+ normal_viewport = normal_world_to_view(nor);
# endif
#endif
+#ifdef OBJECT_ID_PASS_ENABLED
+ PASS_RESOURCE_ID
+#endif
+
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
#endif
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
index fd06c85747f..c24c335189e 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
@@ -1,6 +1,4 @@
-uniform vec3 OrcoTexCoFactors[2];
-
uniform sampler2D depthBuffer;
uniform sampler3D densityTexture;
@@ -172,7 +170,7 @@ vec4 volume_integration(vec3 ray_ori, vec3 ray_dir, float ray_inc, float ray_max
float noise = fract(dither_mat[tx.x][tx.y] + noiseOfs);
float ray_len = noise * ray_inc;
- for (int i = 0; i < samplesLen && ray_len < ray_max; ++i, ray_len += ray_inc) {
+ for (int i = 0; i < samplesLen && ray_len < ray_max; i++, ray_len += ray_inc) {
vec3 ls_pos = ray_ori + ray_dir * ray_len;
vec3 Lscat;
@@ -216,13 +214,13 @@ void main()
vs_ray_dir /= abs(vs_ray_dir.z);
/* TODO(fclem) Precompute the matrix/ */
- vec3 ls_ray_dir = mat3(ViewMatrixInverse) * vs_ray_dir * OrcoTexCoFactors[1] * 2.0;
+ vec3 ls_ray_dir = mat3(ViewMatrixInverse) * vs_ray_dir * OrcoTexCoFactors[1].xyz * 2.0;
ls_ray_dir = mat3(ModelMatrixInverse) * ls_ray_dir;
vec3 ls_ray_ori = point_view_to_object(vs_ray_ori);
vec3 ls_ray_end = point_view_to_object(vs_ray_end);
- ls_ray_ori = (OrcoTexCoFactors[0] + ls_ray_ori * OrcoTexCoFactors[1]) * 2.0 - 1.0;
- ls_ray_end = (OrcoTexCoFactors[0] + ls_ray_end * OrcoTexCoFactors[1]) * 2.0 - 1.0;
+ ls_ray_ori = (OrcoTexCoFactors[0].xyz + ls_ray_ori * OrcoTexCoFactors[1].xyz) * 2.0 - 1.0;
+ ls_ray_end = (OrcoTexCoFactors[0].xyz + ls_ray_end * OrcoTexCoFactors[1].xyz) * 2.0 - 1.0;
/* TODO: Align rays to volume center so that it mimics old behaviour of slicing the volume. */
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
index 6f0bb56fafd..3542a1a91fc 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
@@ -1,10 +1,11 @@
-uniform vec3 OrcoTexCoFactors[2];
uniform float slicePosition;
uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */
in vec3 pos;
+RESOURCE_ID_VARYING
+
#ifdef VOLUME_SLICE
in vec3 uvs;
@@ -27,6 +28,8 @@ void main()
#else
vec3 final_pos = pos;
#endif
- final_pos = ((final_pos * 0.5 + 0.5) - OrcoTexCoFactors[0]) / OrcoTexCoFactors[1];
+ final_pos = ((final_pos * 0.5 + 0.5) - OrcoTexCoFactors[0].xyz) / OrcoTexCoFactors[1].xyz;
gl_Position = point_object_to_ndc(final_pos);
+
+ PASS_RESOURCE_ID
}
diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c
index add49462de1..15522ba0dfb 100644
--- a/source/blender/draw/engines/workbench/workbench_deferred.c
+++ b/source/blender/draw/engines/workbench/workbench_deferred.c
@@ -83,7 +83,6 @@ static struct {
struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */
SceneDisplay display; /* world light direction for shadows */
- int next_object_id;
struct GPUUniformBuffer *sampling_ubo;
struct GPUTexture *jitter_tx;
@@ -147,6 +146,7 @@ static char *workbench_build_prepass_frag(void)
{
DynStr *ds = BLI_dynstr_new();
+ BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl);
BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
BLI_dynstr_append(ds, datatoc_workbench_prepass_frag_glsl);
@@ -330,7 +330,6 @@ static struct GPUTexture *create_jitter_texture(int num_samples)
static void workbench_init_object_data(DrawData *dd)
{
WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd;
- data->object_id = ((e_data.next_object_id++) & 0xff) + 1;
data->shadow_bbox_dirty = true;
}
@@ -379,11 +378,10 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
workbench_effect_info_init(stl->effects);
}
- if (!e_data.next_object_id) {
+ if (!e_data.shadow_pass_sh) {
WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
memset(sh_data->prepass_sh_cache, 0, sizeof(sh_data->prepass_sh_cache));
memset(e_data.composite_sh_cache, 0, sizeof(e_data.composite_sh_cache));
- e_data.next_object_id = 1;
#ifdef DEBUG_SHADOW_VOLUME
const char *shadow_frag = datatoc_workbench_shadow_debug_frag_glsl;
#else
@@ -652,7 +650,7 @@ void workbench_deferred_engine_free(void)
for (int index = 0; index < MAX_COMPOSITE_SHADERS; index++) {
DRW_SHADER_FREE_SAFE(e_data.composite_sh_cache[index]);
}
- for (int index = 0; index < MAX_CAVITY_SHADERS; ++index) {
+ for (int index = 0; index < MAX_CAVITY_SHADERS; index++) {
DRW_SHADER_FREE_SAFE(e_data.cavity_sh[index]);
}
DRW_SHADER_FREE_SAFE(e_data.ghost_resolve_sh);
@@ -694,16 +692,22 @@ static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingG
if (CAVITY_ENABLED(wpd)) {
DRW_shgroup_uniform_texture_ref(grp, "cavityBuffer", &e_data.cavity_buffer_tx);
}
- if (SPECULAR_HIGHLIGHT_ENABLED(wpd) || STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
+ if (workbench_is_specular_highlight_enabled(wpd) || STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
}
- if (SPECULAR_HIGHLIGHT_ENABLED(wpd) || STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
+ if (workbench_is_specular_highlight_enabled(wpd) || STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
}
if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
- BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE);
+ BKE_studiolight_ensure_flag(wpd->studio_light,
+ STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE |
+ STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE);
DRW_shgroup_uniform_texture(
- grp, "matcapImage", wpd->studio_light->equirect_radiance_gputexture);
+ grp, "matcapDiffuseImage", wpd->studio_light->matcap_diffuse.gputexture);
+ if (workbench_is_specular_highlight_enabled(wpd)) {
+ DRW_shgroup_uniform_texture(
+ grp, "matcapSpecularImage", wpd->studio_light->matcap_specular.gputexture);
+ }
}
}
@@ -862,18 +866,11 @@ static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedat
WORKBENCH_PassList *psl = vedata->psl;
WORKBENCH_PrivateData *wpd = stl->g_data;
WORKBENCH_MaterialData *material;
- WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure(
- &ob->id,
- &draw_engine_workbench_solid,
- sizeof(WORKBENCH_ObjectData),
- &workbench_init_object_data,
- NULL);
WORKBENCH_MaterialData material_template;
const bool is_ghost = (ob->dtx & OB_DRAWXRAY);
/* Solid */
workbench_material_update_data(wpd, ob, mat, &material_template, color_type);
- material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1;
material_template.color_type = color_type;
material_template.ima = ima;
material_template.iuser = iuser;
@@ -893,8 +890,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedat
shader, (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_pass : psl->prepass_pass);
workbench_material_copy(material, &material_template);
DRW_shgroup_stencil_mask(material->shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF);
- DRW_shgroup_uniform_int(material->shgrp, "object_id", &material->object_id, 1);
- workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob, true, true, interp);
+ workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob, true, interp);
BLI_ghash_insert(wpd->material_hash, POINTER_FROM_UINT(hash), material);
}
return material;
@@ -937,8 +933,7 @@ static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *o
(ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_hair_pass : psl->prepass_hair_pass,
shader);
DRW_shgroup_stencil_mask(shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF);
- DRW_shgroup_uniform_int(shgrp, "object_id", &material->object_id, 1);
- workbench_material_shgroup_uniform(wpd, shgrp, material, ob, true, true, interp);
+ workbench_material_shgroup_uniform(wpd, shgrp, material, ob, true, interp);
}
}
}
@@ -950,7 +945,8 @@ static void workbench_cache_populate_texture_paint_mode(WORKBENCH_Data *vedata,
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+ const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
WORKBENCH_MaterialData *material;
/* Force workbench to render active object textured when in texture paint mode */
@@ -1099,7 +1095,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
if (use_sculpt_pbvh) {
struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len);
- for (int i = 0; i < materials_len; ++i) {
+ for (int i = 0; i < materials_len; i++) {
struct Material *mat = give_current_material(ob, i + 1);
if (mat != NULL && mat->a < 1.0f) {
material = workbench_forward_get_or_create_material_data(
@@ -1121,7 +1117,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
geoms = DRW_cache_object_surface_material_get(
ob, gpumat_array, materials_len, NULL, NULL, NULL);
- for (int i = 0; i < materials_len; ++i) {
+ for (int i = 0; i < materials_len; i++) {
if (geoms != NULL && geoms[i] != NULL) {
Material *mat = give_current_material(ob, i + 1);
if (mat != NULL && mat->a < 1.0f) {
diff --git a/source/blender/draw/engines/workbench/workbench_effect_dof.c b/source/blender/draw/engines/workbench/workbench_effect_dof.c
index 22840a2a756..169b91a6474 100644
--- a/source/blender/draw/engines/workbench/workbench_effect_dof.c
+++ b/source/blender/draw/engines/workbench/workbench_effect_dof.c
@@ -94,9 +94,9 @@ static void workbench_dof_setup_samples(struct GPUUniformBuffer **ubo,
}
float *samp = *data;
- for (int i = 0; i <= KERNEL_RAD; ++i) {
- for (int j = -KERNEL_RAD; j <= KERNEL_RAD; ++j) {
- for (int k = -KERNEL_RAD; k <= KERNEL_RAD; ++k) {
+ for (int i = 0; i <= KERNEL_RAD; i++) {
+ for (int j = -KERNEL_RAD; j <= KERNEL_RAD; j++) {
+ for (int k = -KERNEL_RAD; k <= KERNEL_RAD; k++) {
if (abs(j) > i || abs(k) > i) {
continue;
}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_taa.c b/source/blender/draw/engines/workbench/workbench_effect_taa.c
index 06442060623..772d859392b 100644
--- a/source/blender/draw/engines/workbench/workbench_effect_taa.c
+++ b/source/blender/draw/engines/workbench/workbench_effect_taa.c
@@ -139,7 +139,7 @@ void workbench_taa_engine_init(WORKBENCH_Data *vedata)
/* reset complete drawing when navigating. */
if (effect_info->jitter_index != 0) {
- if (rv3d && rv3d->rflag & RV3D_NAVIGATING) {
+ if (rv3d && rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING)) {
effect_info->jitter_index = 0;
}
}
diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c
index 4c1fce550e8..d731b167c06 100644
--- a/source/blender/draw/engines/workbench/workbench_forward.c
+++ b/source/blender/draw/engines/workbench/workbench_forward.c
@@ -63,8 +63,6 @@ static struct {
struct GPUTexture *transparent_accum_tx; /* ref only, not alloced */
struct GPUTexture *transparent_revealage_tx; /* ref only, not alloced */
struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */
-
- int next_object_id;
} e_data = {{{{NULL}}}};
/* Shaders */
@@ -98,6 +96,18 @@ static char *workbench_build_forward_vert(bool is_hair)
return str;
}
+static char *workbench_build_forward_outline_frag(void)
+{
+ DynStr *ds = BLI_dynstr_new();
+
+ BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_forward_depth_frag_glsl);
+
+ char *str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ return str;
+}
+
static char *workbench_build_forward_transparent_accum_frag(void)
{
DynStr *ds = BLI_dynstr_new();
@@ -129,12 +139,6 @@ static char *workbench_build_forward_composite_frag(void)
return str;
}
-static void workbench_init_object_data(DrawData *dd)
-{
- WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd;
- data->object_id = ((e_data.next_object_id++) & 0xff) + 1;
-}
-
WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_Data *vedata,
Object *ob,
Material *mat,
@@ -149,18 +153,11 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_
WORKBENCH_PassList *psl = vedata->psl;
WORKBENCH_PrivateData *wpd = stl->g_data;
WORKBENCH_MaterialData *material;
- WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure(
- &ob->id,
- &draw_engine_workbench_solid,
- sizeof(WORKBENCH_ObjectData),
- &workbench_init_object_data,
- NULL);
WORKBENCH_MaterialData material_template;
DRWShadingGroup *grp;
/* Solid */
workbench_material_update_data(wpd, ob, mat, &material_template, color_type);
- material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1;
material_template.color_type = color_type;
material_template.ima = ima;
material_template.iuser = iuser;
@@ -186,11 +183,17 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_
DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
workbench_material_copy(material, &material_template);
if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
- BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE);
+ BKE_studiolight_ensure_flag(wpd->studio_light,
+ STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE |
+ STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE);
DRW_shgroup_uniform_texture(
- grp, "matcapImage", wpd->studio_light->equirect_radiance_gputexture);
+ grp, "matcapDiffuseImage", wpd->studio_light->matcap_diffuse.gputexture);
+ if (workbench_is_specular_highlight_enabled(wpd)) {
+ DRW_shgroup_uniform_texture(
+ grp, "matcapSpecularImage", wpd->studio_light->matcap_specular.gputexture);
+ }
}
- if (SPECULAR_HIGHLIGHT_ENABLED(wpd) || MATCAP_ENABLED(wpd)) {
+ if (workbench_is_specular_highlight_enabled(wpd) || MATCAP_ENABLED(wpd)) {
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
}
if (SHADOW_ENABLED(wpd)) {
@@ -199,7 +202,7 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_
DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus);
}
- workbench_material_shgroup_uniform(wpd, grp, material, ob, false, false, interp);
+ workbench_material_shgroup_uniform(wpd, grp, material, ob, false, interp);
material->shgrp = grp;
/* Depth */
@@ -213,8 +216,6 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_
material->shgrp_object_outline = DRW_shgroup_create(sh_data->object_outline_sh,
psl->object_outline_pass);
}
- material->object_id = engine_object_data->object_id;
- DRW_shgroup_uniform_int(material->shgrp_object_outline, "object_id", &material->object_id, 1);
if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
DRW_shgroup_state_enable(material->shgrp_object_outline, DRW_STATE_CLIP_PLANES);
}
@@ -286,26 +287,30 @@ void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUSh
char *defines_texture = workbench_material_build_defines(wpd, true, false, false);
char *defines_hair = workbench_material_build_defines(wpd, false, true, false);
char *forward_vert = workbench_build_forward_vert(false);
+ char *forward_frag = workbench_build_forward_outline_frag();
char *forward_hair_vert = workbench_build_forward_vert(true);
+ const char *define_id_pass = "#define OBJECT_ID_PASS_ENABLED\n";
+
sh_data->object_outline_sh = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg_data->lib, forward_vert, NULL},
- .frag = (const char *[]){datatoc_workbench_forward_depth_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines, NULL},
+ .frag = (const char *[]){forward_frag, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, defines, define_id_pass, NULL},
});
sh_data->object_outline_texture_sh = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg_data->lib, forward_vert, NULL},
- .frag = (const char *[]){datatoc_workbench_forward_depth_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines_texture, NULL},
+ .frag = (const char *[]){forward_frag, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, defines_texture, define_id_pass, NULL},
});
sh_data->object_outline_hair_sh = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg_data->lib, forward_hair_vert, NULL},
- .frag = (const char *[]){datatoc_workbench_forward_depth_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines_hair, NULL},
+ .frag = (const char *[]){forward_frag, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, defines_hair, define_id_pass, NULL},
});
MEM_freeN(forward_hair_vert);
MEM_freeN(forward_vert);
+ MEM_freeN(forward_frag);
MEM_freeN(defines);
MEM_freeN(defines_texture);
MEM_freeN(defines_hair);
@@ -521,25 +526,30 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O
DRWShadingGroup *shgrp = DRW_shgroup_hair_create(
ob, psys, md, psl->transparent_accum_pass, shader);
DRW_shgroup_uniform_block(shgrp, "world_block", wpd->world_ubo);
- workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, false, interp);
+ workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, interp);
DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
/* Hairs have lots of layer and can rapidly become the most prominent surface.
* So lower their alpha artificially. */
float hair_alpha = XRAY_ALPHA(wpd) * 0.33f;
DRW_shgroup_uniform_float_copy(shgrp, "alpha", hair_alpha);
if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
- BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE);
+ BKE_studiolight_ensure_flag(wpd->studio_light,
+ STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE |
+ STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE);
DRW_shgroup_uniform_texture(
- shgrp, "matcapImage", wpd->studio_light->equirect_radiance_gputexture);
+ shgrp, "matcapDiffuseImage", wpd->studio_light->matcap_diffuse.gputexture);
+ if (workbench_is_specular_highlight_enabled(wpd)) {
+ DRW_shgroup_uniform_texture(
+ shgrp, "matcapSpecularImage", wpd->studio_light->matcap_specular.gputexture);
+ }
}
- if (SPECULAR_HIGHLIGHT_ENABLED(wpd) || MATCAP_ENABLED(wpd)) {
+ if (workbench_is_specular_highlight_enabled(wpd) || MATCAP_ENABLED(wpd)) {
DRW_shgroup_uniform_vec2(shgrp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
}
WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
shgrp = DRW_shgroup_hair_create(
ob, psys, md, vedata->psl->object_outline_pass, sh_data->object_outline_hair_sh);
- DRW_shgroup_uniform_int(shgrp, "object_id", &material->object_id, 1);
}
}
}
@@ -550,7 +560,8 @@ static void workbench_forward_cache_populate_texture_paint_mode(WORKBENCH_Data *
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+ const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
WORKBENCH_MaterialData *material;
/* Force workbench to render active object textured when in texture paint mode */
@@ -625,7 +636,8 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
WORKBENCH_MaterialData *material;
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+ const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
const int materials_len = MAX2(1, ob->totcol);
const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
const bool use_texture_paint_drawing = !(DRW_state_is_image_render() &&
@@ -689,7 +701,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
if (use_sculpt_pbvh) {
struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len);
- for (int i = 0; i < materials_len; ++i) {
+ for (int i = 0; i < materials_len; i++) {
struct Material *mat = give_current_material(ob, i + 1);
material = workbench_forward_get_or_create_material_data(
vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
@@ -708,7 +720,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
struct GPUBatch **mat_geom = DRW_cache_object_surface_material_get(
ob, gpumat_array, materials_len, NULL, NULL, NULL);
if (mat_geom) {
- for (int i = 0; i < materials_len; ++i) {
+ for (int i = 0; i < materials_len; i++) {
if (mat_geom[i] == NULL) {
continue;
}
diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c
index 6699a1954ba..0f9551a8cc9 100644
--- a/source/blender/draw/engines/workbench/workbench_materials.c
+++ b/source/blender/draw/engines/workbench/workbench_materials.c
@@ -44,20 +44,15 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd,
WORKBENCH_MaterialData *data,
int color_type)
{
- copy_v3_fl3(data->diffuse_color, 0.8f, 0.8f, 0.8f);
- copy_v3_v3(data->base_color, data->diffuse_color);
- copy_v3_fl3(data->specular_color, 0.05f, 0.05f, 0.05f); /* Dielectric: 5% reflective. */
data->metallic = 0.0f;
data->roughness = 0.632455532f; /* sqrtf(0.4f); */
data->alpha = wpd->shading.xray_alpha;
if (color_type == V3D_SHADING_SINGLE_COLOR) {
- copy_v3_v3(data->diffuse_color, wpd->shading.single_color);
- copy_v3_v3(data->base_color, data->diffuse_color);
+ copy_v3_v3(data->base_color, wpd->shading.single_color);
}
else if (color_type == V3D_SHADING_ERROR_COLOR) {
- copy_v3_fl3(data->diffuse_color, 0.8, 0.0, 0.8);
- copy_v3_v3(data->base_color, data->diffuse_color);
+ copy_v3_fl3(data->base_color, 0.8, 0.0, 0.8);
}
else if (color_type == V3D_SHADING_RANDOM_COLOR) {
uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name);
@@ -67,30 +62,24 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd,
float hue = BLI_hash_int_01(hash);
float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE};
- hsv_to_rgb_v(hsv, data->diffuse_color);
- copy_v3_v3(data->base_color, data->diffuse_color);
+ hsv_to_rgb_v(hsv, data->base_color);
}
else if (ELEM(color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_VERTEX_COLOR)) {
- copy_v3_v3(data->diffuse_color, ob->color);
- copy_v3_v3(data->base_color, data->diffuse_color);
data->alpha *= ob->color[3];
+ copy_v3_v3(data->base_color, ob->color);
}
else {
/* V3D_SHADING_MATERIAL_COLOR or V3D_SHADING_TEXTURE_COLOR */
if (mat) {
data->alpha *= mat->a;
- if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) {
- copy_v3_v3(data->base_color, &mat->r);
- mul_v3_v3fl(data->diffuse_color, &mat->r, 1.0f - mat->metallic);
- mul_v3_v3fl(data->specular_color, &mat->r, mat->metallic);
- add_v3_fl(data->specular_color, 0.05f * (1.0f - mat->metallic));
+ copy_v3_v3(data->base_color, &mat->r);
+ if (workbench_is_specular_highlight_enabled(wpd)) {
data->metallic = mat->metallic;
data->roughness = sqrtf(mat->roughness); /* Remap to disney roughness. */
}
- else {
- copy_v3_v3(data->base_color, &mat->r);
- copy_v3_v3(data->diffuse_color, &mat->r);
- }
+ }
+ else {
+ copy_v3_fl(data->base_color, 0.8f);
}
}
}
@@ -121,7 +110,7 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd,
if (SSAO_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) {
BLI_dynstr_append(ds, "#define WB_CAVITY\n");
}
- if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) {
+ if (workbench_is_specular_highlight_enabled(wpd)) {
BLI_dynstr_append(ds, "#define V3D_SHADING_SPECULAR_HIGHLIGHT\n");
}
if (STUDIOLIGHT_ENABLED(wpd)) {
@@ -160,34 +149,40 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd,
return str;
}
-uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template, bool is_ghost)
+uint workbench_material_get_hash(WORKBENCH_MaterialData *mat, bool is_ghost)
{
- uint input[4];
- uint result;
- float *color = material_template->diffuse_color;
- input[0] = (uint)(color[0] * 512);
- input[1] = (uint)(color[1] * 512);
- input[2] = (uint)(color[2] * 512);
- input[3] = material_template->object_id;
- result = BLI_ghashutil_uinthash_v4_murmur(input);
-
- color = material_template->specular_color;
- input[0] = (uint)(color[0] * 512);
- input[1] = (uint)(color[1] * 512);
- input[2] = (uint)(color[2] * 512);
- input[3] = (uint)(material_template->roughness * 512);
- result += BLI_ghashutil_uinthash_v4_murmur(input);
-
- result += BLI_ghashutil_uinthash((uint)(material_template->alpha * 512));
- result += BLI_ghashutil_uinthash((uint)is_ghost);
- result += BLI_ghashutil_uinthash(material_template->color_type);
-
- /* add texture reference */
- if (material_template->ima) {
- result += BLI_ghashutil_inthash_p_murmur(material_template->ima);
- }
-
- return result;
+ union {
+ struct {
+ /* WHATCH: Keep in sync with View3DShading.color_type max value. */
+ uchar color_type;
+ uchar diff_r;
+ uchar diff_g;
+ uchar diff_b;
+
+ uchar alpha;
+ uchar ghost;
+ uchar metal;
+ uchar roughness;
+
+ void *ima;
+ };
+ /* HACK to ensure input is 4 uint long. */
+ uint a[4];
+ } input = {.color_type = (uchar)(mat->color_type),
+ .diff_r = (uchar)(mat->base_color[0] * 0xFF),
+ .diff_g = (uchar)(mat->base_color[1] * 0xFF),
+ .diff_b = (uchar)(mat->base_color[2] * 0xFF),
+
+ .alpha = (uint)(mat->alpha * 0xFF),
+ .ghost = (uchar)is_ghost,
+ .metal = (uchar)(mat->metallic * 0xFF),
+ .roughness = (uchar)(mat->roughness * 0xFF),
+
+ .ima = mat->ima};
+
+ BLI_assert(sizeof(input) == sizeof(uint) * 4);
+
+ return BLI_ghashutil_uinthash_v4((uint *)&input);
}
int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd)
@@ -195,11 +190,12 @@ int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd)
/* NOTE: change MAX_COMPOSITE_SHADERS accordingly when modifying this function. */
int index = 0;
/* 2 bits FLAT/STUDIO/MATCAP + Specular highlight */
- index = SPECULAR_HIGHLIGHT_ENABLED(wpd) ? 3 : wpd->shading.light;
+ index = wpd->shading.light;
SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_SHADOW, 1 << 2);
SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_CAVITY, 1 << 3);
SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE, 1 << 4);
SET_FLAG_FROM_TEST(index, workbench_is_matdata_pass_enabled(wpd), 1 << 5);
+ SET_FLAG_FROM_TEST(index, workbench_is_specular_highlight_enabled(wpd), 1 << 6);
BLI_assert(index < MAX_COMPOSITE_SHADERS);
return index;
}
@@ -246,12 +242,13 @@ int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd,
/* NOTE: change MAX_ACCUM_SHADERS accordingly when modifying this function. */
int index = 0;
/* 2 bits FLAT/STUDIO/MATCAP + Specular highlight */
- index = SPECULAR_HIGHLIGHT_ENABLED(wpd) ? 3 : wpd->shading.light;
+ index = wpd->shading.light;
SET_FLAG_FROM_TEST(index, use_textures, 1 << 2);
SET_FLAG_FROM_TEST(index, use_vertex_colors, 1 << 3);
SET_FLAG_FROM_TEST(index, is_hair, 1 << 4);
/* 1 bits SHADOWS (only facing factor) */
SET_FLAG_FROM_TEST(index, SHADOW_ENABLED(wpd), 1 << 5);
+ SET_FLAG_FROM_TEST(index, workbench_is_specular_highlight_enabled(wpd), 1 << 6);
BLI_assert(index < MAX_ACCUM_SHADERS);
return index;
}
@@ -264,8 +261,8 @@ int workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd,
int color_type = wpd->shading.color_type;
const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
- if ((color_type == V3D_SHADING_TEXTURE_COLOR && (ima == NULL || use_sculpt_pbvh)) ||
- (ob->dt < OB_TEXTURE)) {
+ if ((color_type == V3D_SHADING_TEXTURE_COLOR) &&
+ (ima == NULL || use_sculpt_pbvh || (ob->dt < OB_TEXTURE))) {
color_type = V3D_SHADING_MATERIAL_COLOR;
}
if (color_type == V3D_SHADING_VERTEX_COLOR && (me == NULL || me->mloopcol == NULL)) {
@@ -313,35 +310,28 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
DRWShadingGroup *grp,
WORKBENCH_MaterialData *material,
Object *ob,
- const bool use_metallic,
const bool deferred,
const int interp)
{
- if (!deferred || workbench_is_matdata_pass_enabled(wpd)) {
- if (workbench_material_determine_color_type(wpd, material->ima, ob, false) ==
- V3D_SHADING_TEXTURE_COLOR) {
- GPUTexture *tex = GPU_texture_from_blender(material->ima, material->iuser, GL_TEXTURE_2D);
- DRW_shgroup_uniform_texture(grp, "image", tex);
- DRW_shgroup_uniform_bool_copy(
- grp, "imagePremultiplied", (material->ima->alpha_mode == IMA_ALPHA_PREMUL));
- DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST));
- }
- else {
- DRW_shgroup_uniform_vec3(grp,
- "materialDiffuseColor",
- (use_metallic) ? material->base_color : material->diffuse_color,
- 1);
- }
+ if (!(!deferred || workbench_is_matdata_pass_enabled(wpd))) {
+ return;
+ }
- if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) {
- if (use_metallic) {
- DRW_shgroup_uniform_float(grp, "materialMetallic", &material->metallic, 1);
- }
- else {
- DRW_shgroup_uniform_vec3(grp, "materialSpecularColor", material->specular_color, 1);
- }
- DRW_shgroup_uniform_float(grp, "materialRoughness", &material->roughness, 1);
- }
+ const bool use_highlight = workbench_is_specular_highlight_enabled(wpd);
+ const bool use_texture = (V3D_SHADING_TEXTURE_COLOR == workbench_material_determine_color_type(
+ wpd, material->ima, ob, false));
+ if (use_texture) {
+ GPUTexture *tex = GPU_texture_from_blender(material->ima, material->iuser, GL_TEXTURE_2D);
+ DRW_shgroup_uniform_texture(grp, "image", tex);
+ DRW_shgroup_uniform_bool_copy(
+ grp, "imagePremultiplied", (material->ima->alpha_mode == IMA_ALPHA_PREMUL));
+ DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST));
+ }
+
+ DRW_shgroup_uniform_vec4(grp, "materialColorAndMetal", material->base_color, 1);
+
+ if (use_highlight) {
+ DRW_shgroup_uniform_float(grp, "materialRoughness", &material->roughness, 1);
}
if (WORLD_CLIPPING_ENABLED(wpd)) {
@@ -352,10 +342,7 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
void workbench_material_copy(WORKBENCH_MaterialData *dest_material,
const WORKBENCH_MaterialData *source_material)
{
- dest_material->object_id = source_material->object_id;
copy_v3_v3(dest_material->base_color, source_material->base_color);
- copy_v3_v3(dest_material->diffuse_color, source_material->diffuse_color);
- copy_v3_v3(dest_material->specular_color, source_material->specular_color);
dest_material->metallic = source_material->metallic;
dest_material->roughness = source_material->roughness;
dest_material->ima = source_material->ima;
diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h
index 255b036eebb..252be3570d7 100644
--- a/source/blender/draw/engines/workbench/workbench_private.h
+++ b/source/blender/draw/engines/workbench/workbench_private.h
@@ -36,9 +36,9 @@
#define WORKBENCH_ENGINE "BLENDER_WORKBENCH"
#define M_GOLDEN_RATION_CONJUGATE 0.618033988749895
-#define MAX_COMPOSITE_SHADERS (1 << 6)
+#define MAX_COMPOSITE_SHADERS (1 << 7)
#define MAX_PREPASS_SHADERS (1 << 7)
-#define MAX_ACCUM_SHADERS (1 << 6)
+#define MAX_ACCUM_SHADERS (1 << 7)
#define MAX_CAVITY_SHADERS (1 << 3)
#define TEXTURE_DRAWING_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR)
@@ -75,11 +75,9 @@
V3D_SHADING_VERTEX_COLOR))
#define IS_NAVIGATING(wpd) \
- ((DRW_context_state_get()->rv3d) && (DRW_context_state_get()->rv3d->rflag & RV3D_NAVIGATING))
+ ((DRW_context_state_get()->rv3d) && \
+ (DRW_context_state_get()->rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING)))
-#define SPECULAR_HIGHLIGHT_ENABLED(wpd) \
- (STUDIOLIGHT_ENABLED(wpd) && (wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT) && \
- (!STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)))
#define OBJECT_OUTLINE_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE)
#define OBJECT_ID_PASS_ENABLED(wpd) (OBJECT_OUTLINE_ENABLED(wpd) || CURVATURE_ENABLED(wpd))
#define NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) \
@@ -284,13 +282,8 @@ typedef struct WORKBENCH_EffectInfo {
} WORKBENCH_EffectInfo;
typedef struct WORKBENCH_MaterialData {
- float base_color[3];
- float diffuse_color[3];
- float specular_color[3];
- float alpha;
- float metallic;
- float roughness;
- int object_id;
+ float base_color[3], metallic;
+ float roughness, alpha;
int color_type;
int interp;
Image *ima;
@@ -311,11 +304,19 @@ typedef struct WORKBENCH_ObjectData {
float shadow_min[3], shadow_max[3];
BoundBox shadow_bbox;
bool shadow_bbox_dirty;
-
- int object_id;
} WORKBENCH_ObjectData;
/* inline helper functions */
+BLI_INLINE bool workbench_is_specular_highlight_enabled(WORKBENCH_PrivateData *wpd)
+{
+ if ((wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT)) {
+ if (STUDIOLIGHT_ENABLED(wpd) || MATCAP_ENABLED(wpd)) {
+ return (wpd->studio_light->flag & STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS) != 0;
+ }
+ }
+ return false;
+}
+
BLI_INLINE bool workbench_is_taa_enabled(WORKBENCH_PrivateData *wpd)
{
if (DRW_state_is_image_render()) {
@@ -493,7 +494,6 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
DRWShadingGroup *grp,
WORKBENCH_MaterialData *material,
Object *ob,
- const bool use_metallic,
const bool deferred,
const int interp);
void workbench_material_copy(WORKBENCH_MaterialData *dest_material,
diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c
index b4e5e98c92b..899fbdc9b71 100644
--- a/source/blender/draw/engines/workbench/workbench_render.c
+++ b/source/blender/draw/engines/workbench/workbench_render.c
@@ -24,6 +24,8 @@
#include "BLI_rect.h"
+#include "DNA_node_types.h"
+
#include "BKE_report.h"
#include "DRW_render.h"
diff --git a/source/blender/draw/engines/workbench/workbench_studiolight.c b/source/blender/draw/engines/workbench/workbench_studiolight.c
index 1a09498b228..ac27ff0b736 100644
--- a/source/blender/draw/engines/workbench/workbench_studiolight.c
+++ b/source/blender/draw/engines/workbench/workbench_studiolight.c
@@ -77,7 +77,7 @@ void studiolight_update_world(WORKBENCH_PrivateData *wpd,
/* Use Geomerics non-linear SH. */
mul_v3_v3fl(wd->spherical_harmonics_coefs[0], sl->spherical_harmonics_coefs[0], M_1_PI);
/* Swizzle to make shader code simpler. */
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
copy_v3_fl3(wd->spherical_harmonics_coefs[i + 1],
-sl->spherical_harmonics_coefs[3][i],
sl->spherical_harmonics_coefs[2][i],
@@ -89,7 +89,7 @@ void studiolight_update_world(WORKBENCH_PrivateData *wpd,
/* Precompute as much as we can. See shader code for derivation. */
float len_r1[3], lr1_r0[3], p[3], a[3];
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
mul_v3_fl(wd->spherical_harmonics_coefs[i + 1], 0.5f);
len_r1[i] = len_v3(wd->spherical_harmonics_coefs[i + 1]);
mul_v3_fl(wd->spherical_harmonics_coefs[i + 1], 1.0f / len_r1[i]);
@@ -179,7 +179,7 @@ void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_dire
mul_v3_mat3_m4v3(wpd->shadow_near_corners[3], wpd->shadow_inv, frustum_corners.vec[4]);
INIT_MINMAX(wpd->shadow_near_min, wpd->shadow_near_max);
- for (int i = 0; i < 4; ++i) {
+ for (int i = 0; i < 4; i++) {
minmax_v3v3_v3(wpd->shadow_near_min, wpd->shadow_near_max, wpd->shadow_near_corners[i]);
}
@@ -206,7 +206,7 @@ static BoundBox *studiolight_object_shadow_bbox_get(WORKBENCH_PrivateData *wpd,
/* From object space to shadow space */
BoundBox *bbox = BKE_object_boundbox_get(ob);
- for (int i = 0; i < 8; ++i) {
+ for (int i = 0; i < 8; i++) {
float corner[3];
mul_v3_m4v3(corner, tmp_mat, bbox->vec[i]);
minmax_v3v3_v3(oed->shadow_min, oed->shadow_max, corner);
@@ -217,7 +217,7 @@ static BoundBox *studiolight_object_shadow_bbox_get(WORKBENCH_PrivateData *wpd,
/* Get extended AABB in world space. */
BKE_boundbox_init_from_minmax(&oed->shadow_bbox, oed->shadow_min, oed->shadow_max);
- for (int i = 0; i < 8; ++i) {
+ for (int i = 0; i < 8; i++) {
mul_m4_v3(wpd->shadow_mat, oed->shadow_bbox.vec[i]);
}
oed->shadow_bbox_dirty = false;
@@ -243,7 +243,7 @@ float studiolight_object_shadow_distance(WORKBENCH_PrivateData *wpd,
int corners[4] = {0, 3, 4, 7};
float dist = 1e4f, dist_isect;
- for (int i = 0; i < 4; ++i) {
+ for (int i = 0; i < 4; i++) {
if (isect_ray_plane_v3(shadow_bbox->vec[corners[i]],
wpd->cached_shadow_direction,
wpd->shadow_far_plane,
@@ -284,16 +284,16 @@ bool studiolight_camera_in_object_shadow(WORKBENCH_PrivateData *wpd,
}
/* Test projected near rectangle sides */
- float pts[4][2] = {
+ const float pts[4][2] = {
{oed->shadow_min[0], oed->shadow_min[1]},
{oed->shadow_min[0], oed->shadow_max[1]},
{oed->shadow_max[0], oed->shadow_min[1]},
{oed->shadow_max[0], oed->shadow_max[1]},
};
- for (int i = 0; i < 2; ++i) {
+ for (int i = 0; i < 2; i++) {
float min_dst = FLT_MAX, max_dst = -FLT_MAX;
- for (int j = 0; j < 4; ++j) {
+ for (int j = 0; j < 4; j++) {
float dst = dot_v2v2(wpd->shadow_near_sides[i], pts[j]);
/* Do min max */
if (min_dst > dst) {
diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c
index 1beb02ea3a0..e017661b6cd 100644
--- a/source/blender/draw/engines/workbench/workbench_volume.c
+++ b/source/blender/draw/engines/workbench/workbench_volume.c
@@ -27,6 +27,7 @@
#include "BLI_rand.h"
#include "BLI_dynstr.h"
+#include "BLI_string_utils.h"
#include "DNA_modifier_types.h"
#include "DNA_object_force_types.h"
@@ -54,6 +55,7 @@ static struct {
extern char datatoc_workbench_volume_vert_glsl[];
extern char datatoc_workbench_volume_frag_glsl[];
extern char datatoc_common_view_lib_glsl[];
+extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic)
{
@@ -78,12 +80,16 @@ static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic)
char *defines = BLI_dynstr_get_cstring(ds);
BLI_dynstr_free(ds);
+ char *libs = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_gpu_shader_common_obinfos_lib_glsl);
+
e_data.volume_sh[id] = DRW_shader_create_with_lib(datatoc_workbench_volume_vert_glsl,
NULL,
datatoc_workbench_volume_frag_glsl,
- datatoc_common_view_lib_glsl,
+ libs,
defines);
+ MEM_freeN(libs);
MEM_freeN(defines);
}
@@ -101,7 +107,7 @@ void workbench_volume_engine_init(void)
void workbench_volume_engine_free(void)
{
- for (int i = 0; i < VOLUME_SH_MAX; ++i) {
+ for (int i = 0; i < VOLUME_SH_MAX; i++) {
DRW_SHADER_FREE_SAFE(e_data.volume_sh[i]);
}
DRW_TEXTURE_FREE_SAFE(e_data.dummy_tex);
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 10ab7c13631..2c51eb8b7f8 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -75,15 +75,13 @@ struct RenderEngineType;
struct bContext;
struct rcti;
+typedef struct DRWCallBuffer DRWCallBuffer;
typedef struct DRWInterface DRWInterface;
typedef struct DRWPass DRWPass;
typedef struct DRWShadingGroup DRWShadingGroup;
typedef struct DRWUniform DRWUniform;
typedef struct DRWView DRWView;
-/* Opaque type to avoid usage as a DRWCall but it is exactly the same thing. */
-typedef struct DRWCallBuffer DRWCallBuffer;
-
/* TODO Put it somewhere else? */
typedef struct BoundSphere {
float center[3], radius;
@@ -346,6 +344,7 @@ typedef enum {
/** Use dual source blending. WARNING: Only one color buffer allowed. */
DRW_STATE_BLEND_CUSTOM = (1 << 23),
+ DRW_STATE_SHADOW_OFFSET = (1 << 27),
DRW_STATE_CLIP_PLANES = (1 << 28),
DRW_STATE_WIRE_SMOOTH = (1 << 29),
DRW_STATE_FIRST_VERTEX_CONVENTION = (1 << 30),
@@ -403,35 +402,29 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
Object *ob,
float (*obmat)[4],
struct GPUBatch *geom,
- uint v_sta,
- uint v_ct,
bool bypass_culling,
void *user_data);
/* If ob is NULL, unit modelmatrix is assumed and culling is bypassed. */
-#define DRW_shgroup_call(shgrp, geom, ob) \
- DRW_shgroup_call_ex(shgrp, ob, NULL, geom, 0, 0, false, NULL)
+#define DRW_shgroup_call(shgrp, geom, ob) DRW_shgroup_call_ex(shgrp, ob, NULL, geom, false, NULL)
/* Same as DRW_shgroup_call but override the obmat. Not culled. */
#define DRW_shgroup_call_obmat(shgrp, geom, obmat) \
- DRW_shgroup_call_ex(shgrp, NULL, obmat, geom, 0, 0, false, NULL)
+ DRW_shgroup_call_ex(shgrp, NULL, obmat, geom, false, NULL)
/* TODO(fclem) remove this when we have DRWView */
/* user_data is used by DRWCallVisibilityFn defined in DRWView. */
#define DRW_shgroup_call_with_callback(shgrp, geom, ob, user_data) \
- DRW_shgroup_call_ex(shgrp, ob, NULL, geom, 0, 0, false, user_data)
+ DRW_shgroup_call_ex(shgrp, ob, NULL, geom, false, user_data)
/* Same as DRW_shgroup_call but bypass culling even if ob is not NULL. */
#define DRW_shgroup_call_no_cull(shgrp, geom, ob) \
- DRW_shgroup_call_ex(shgrp, ob, NULL, geom, 0, 0, true, NULL)
+ DRW_shgroup_call_ex(shgrp, ob, NULL, geom, true, NULL)
-/* Only draw a certain range of geom. */
-#define DRW_shgroup_call_range(shgrp, geom, ob, v_sta, v_ct) \
- DRW_shgroup_call_ex(shgrp, ob, NULL, geom, v_sta, v_ct, false, NULL)
-
-/* Same as DRW_shgroup_call_range but override the obmat. Special for gpencil. */
-#define DRW_shgroup_call_range_obmat(shgrp, geom, obmat, v_sta, v_ct) \
- DRW_shgroup_call_ex(shgrp, NULL, obmat, geom, v_sta, v_ct, false, NULL)
+void DRW_shgroup_call_range(DRWShadingGroup *shgroup,
+ struct GPUBatch *geom,
+ uint v_sta,
+ uint v_ct);
void DRW_shgroup_call_procedural_points(DRWShadingGroup *sh, Object *ob, uint point_ct);
void DRW_shgroup_call_procedural_lines(DRWShadingGroup *sh, Object *ob, uint line_ct);
@@ -468,6 +461,16 @@ void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state);
void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state);
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask);
+/* Issue a clear command. */
+void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup,
+ eGPUFrameBufferBits channels,
+ uchar r,
+ uchar g,
+ uchar b,
+ uchar a,
+ float depth,
+ uchar stencil);
+
void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup,
const char *name,
const struct GPUTexture *tex);
@@ -524,17 +527,17 @@ void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const
void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float (*value)[4]);
/* Store value instead of referencing it. */
void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value);
+void DRW_shgroup_uniform_ivec2_copy(DRWShadingGroup *shgrp, const char *name, const int *value);
+void DRW_shgroup_uniform_ivec3_copy(DRWShadingGroup *shgrp, const char *name, const int *value);
+void DRW_shgroup_uniform_ivec4_copy(DRWShadingGroup *shgrp, const char *name, const int *value);
void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value);
void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, const float value);
void DRW_shgroup_uniform_vec2_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
+void DRW_shgroup_uniform_vec3_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
+void DRW_shgroup_uniform_vec4_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup);
-/* TODO: workaround functions waiting for the clearing operation to be available inside the
- * shgroups. */
-DRWShadingGroup *DRW_shgroup_get_next(DRWShadingGroup *shgroup);
-uint DRW_shgroup_stencil_mask_get(DRWShadingGroup *shgroup);
-
/* Passes */
DRWPass *DRW_pass_create(const char *name, DRWState state);
/* TODO Replace with passes inheritance. */
diff --git a/source/blender/draw/intern/draw_anim_viz.c b/source/blender/draw/intern/draw_anim_viz.c
index 72459309133..7e0110cbb99 100644
--- a/source/blender/draw/intern/draw_anim_viz.c
+++ b/source/blender/draw/intern/draw_anim_viz.c
@@ -215,7 +215,7 @@ static void MPATH_cache_motion_path(MPATH_PassList *psl,
DRW_shgroup_uniform_vec3(shgrp, "customColor", mpath->color, 1);
}
/* Only draw the required range. */
- DRW_shgroup_call_range(shgrp, mpath_batch_line_get(mpath), NULL, start_index, len);
+ DRW_shgroup_call_range(shgrp, mpath_batch_line_get(mpath), start_index, len);
}
/* Draw points. */
@@ -231,7 +231,7 @@ static void MPATH_cache_motion_path(MPATH_PassList *psl,
DRW_shgroup_uniform_vec3(shgrp, "customColor", mpath->color, 1);
}
/* Only draw the required range. */
- DRW_shgroup_call_range(shgrp, mpath_batch_points_get(mpath), NULL, start_index, len);
+ DRW_shgroup_call_range(shgrp, mpath_batch_points_get(mpath), start_index, len);
/* Draw frame numbers at each framestep value */
bool show_kf_no = (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) != 0;
@@ -289,10 +289,9 @@ static void MPATH_cache_populate(void *vedata, Object *ob)
}
}
}
- else {
- if (ob->mpath) {
- MPATH_cache_motion_path(psl, ob, NULL, &ob->avs, ob->mpath);
- }
+
+ if (ob->mpath) {
+ MPATH_cache_motion_path(psl, ob, NULL, &ob->avs, ob->mpath);
}
}
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 520932bc429..019098e5b90 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -296,15 +296,15 @@ static GPUVertBuf *sphere_wire_vbo(const float rad)
/* a single ring of vertices */
float p[NSEGMENTS][2];
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
p[i][0] = rad * cosf(angle);
p[i][1] = rad * sinf(angle);
}
- for (int axis = 0; axis < 3; ++axis) {
- for (int i = 0; i < NSEGMENTS; ++i) {
- for (int j = 0; j < 2; ++j) {
+ for (int axis = 0; axis < 3; axis++) {
+ for (int i = 0; i < NSEGMENTS; i++) {
+ for (int j = 0; j < 2; j++) {
float cv[2], v[3];
cv[0] = p[(i + j) % NSEGMENTS][0];
@@ -347,12 +347,13 @@ GPUBatch *DRW_cache_fullscreen_quad_get(void)
attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
attr_id.uvs = GPU_vertformat_attr_add(&format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
GPU_vertformat_alias_add(&format, "texCoord");
+ GPU_vertformat_alias_add(&format, "orco"); /* Fix driver bug (see T70004) */
}
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, 3);
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
GPU_vertbuf_attr_set(vbo, attr_id.pos, i, pos[i]);
GPU_vertbuf_attr_set(vbo, attr_id.uvs, i, uvs[i]);
}
@@ -382,7 +383,7 @@ GPUBatch *DRW_cache_quad_get(void)
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, 4);
- for (int i = 0; i < 4; ++i) {
+ for (int i = 0; i < 4; i++) {
GPU_vertbuf_attr_set(vbo, attr_id.pos, i, pos[i]);
GPU_vertbuf_attr_set(vbo, attr_id.uvs, i, uvs[i]);
}
@@ -437,8 +438,8 @@ GPUBatch *DRW_cache_grid_get(void)
GPU_vertbuf_data_alloc(vbo, 8 * 8 * 2 * 3);
uint v_idx = 0;
- for (int i = 0; i < 8; ++i) {
- for (int j = 0; j < 8; ++j) {
+ for (int i = 0; i < 8; i++) {
+ for (int j = 0; j < 8; j++) {
float pos0[2] = {(float)i / 8.0f, (float)j / 8.0f};
float pos1[2] = {(float)(i + 1) / 8.0f, (float)j / 8.0f};
float pos2[2] = {(float)i / 8.0f, (float)(j + 1) / 8.0f};
@@ -510,7 +511,7 @@ GPUBatch *DRW_cache_cube_get(void)
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, 36);
- for (int i = 0; i < 36; ++i) {
+ for (int i = 0; i < 36; i++) {
GPU_vertbuf_attr_set(vbo, attr_id.pos, i, verts[indices[i]]);
}
@@ -549,7 +550,7 @@ GPUBatch *DRW_cache_empty_cube_get(void)
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, 24);
- for (int i = 0; i < 24; ++i) {
+ for (int i = 0; i < 24; i++) {
GPU_vertbuf_attr_set(vbo, attr_id.pos, i, verts[indices[i]]);
}
@@ -592,7 +593,7 @@ GPUBatch *DRW_cache_circle_get(void)
GPUBatch *DRW_cache_square_get(void)
{
if (!SHC.drw_square) {
- float p[4][3] = {
+ const float p[4][3] = {
{1.0f, 0.0f, 1.0f}, {1.0f, 0.0f, -1.0f}, {-1.0f, 0.0f, -1.0f}, {-1.0f, 0.0f, 1.0f}};
/* Position Only 3D format */
@@ -751,7 +752,7 @@ GPUBatch *DRW_cache_gpencil_axes_get(void)
}
/* draw cube */
- for (int i = 0; i < 24; ++i) {
+ for (int i = 0; i < 24; i++) {
GPU_vertbuf_attr_set(vbo, pos_id, i + 6, verts[indices[i]]);
}
@@ -982,7 +983,7 @@ GPUBatch *DRW_cache_empty_cone_get(void)
if (!SHC.drw_empty_cone) {
/* a single ring of vertices */
float p[NSEGMENTS][2];
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
p[i][0] = cosf(angle);
p[i][1] = sinf(angle);
@@ -1000,7 +1001,7 @@ GPUBatch *DRW_cache_empty_cone_get(void)
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 4);
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float cv[2], v[3];
cv[0] = p[(i) % NSEGMENTS][0];
cv[1] = p[(i) % NSEGMENTS][1];
@@ -1032,7 +1033,7 @@ GPUBatch *DRW_cache_empty_cylinder_get(void)
if (!SHC.drw_empty_cylinder) {
/* a single ring of vertices */
float p[NSEGMENTS][2];
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
p[i][0] = cosf(angle);
p[i][1] = sinf(angle);
@@ -1050,7 +1051,7 @@ GPUBatch *DRW_cache_empty_cylinder_get(void)
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 6);
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float cv[2], pv[2], v[3];
cv[0] = p[(i) % NSEGMENTS][0];
cv[1] = p[(i) % NSEGMENTS][1];
@@ -1121,7 +1122,7 @@ GPUBatch *DRW_cache_empty_capsule_cap_get(void)
if (!SHC.drw_empty_capsule_cap) {
/* a single ring of vertices */
float p[NSEGMENTS][2];
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
p[i][0] = cosf(angle);
p[i][1] = sinf(angle);
@@ -1141,7 +1142,7 @@ GPUBatch *DRW_cache_empty_capsule_cap_get(void)
/* Base circle */
int vidx = 0;
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float v[3] = {0.0f, 0.0f, 0.0f};
copy_v2_v2(v, p[(i) % NSEGMENTS]);
GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
@@ -1149,7 +1150,7 @@ GPUBatch *DRW_cache_empty_capsule_cap_get(void)
GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
}
- for (int i = 0; i < NSEGMENTS / 2; ++i) {
+ for (int i = 0; i < NSEGMENTS / 2; i++) {
float v[3] = {0.0f, 0.0f, 0.0f};
int ci = i % NSEGMENTS;
int pi = (i + 1) % NSEGMENTS;
@@ -1690,7 +1691,7 @@ GPUBatch *DRW_cache_light_spot_get(void)
float n[NSEGMENTS][3];
float neg[NSEGMENTS][3];
float half_angle = 2 * M_PI / ((float)NSEGMENTS * 2);
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
p[i][0] = cosf(angle);
p[i][1] = sinf(angle);
@@ -1715,7 +1716,7 @@ GPUBatch *DRW_cache_light_spot_get(void)
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 4);
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float cv[2], v[3];
cv[0] = p[i % NSEGMENTS][0];
cv[1] = p[i % NSEGMENTS][1];
@@ -1757,7 +1758,7 @@ GPUBatch *DRW_cache_light_spot_volume_get(void)
if (!SHC.drw_light_spot_volume) {
/* a single ring of vertices */
float p[NSEGMENTS][2];
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
p[i][0] = cosf(angle);
p[i][1] = sinf(angle);
@@ -1775,7 +1776,7 @@ GPUBatch *DRW_cache_light_spot_volume_get(void)
GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 3);
uint v_idx = 0;
- for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int i = 0; i < NSEGMENTS; i++) {
float cv[2], v[3];
ARRAY_SET_ITEMS(v, 0.0f, 0.0f, 0.0f);
@@ -1801,7 +1802,7 @@ GPUBatch *DRW_cache_light_spot_volume_get(void)
GPUBatch *DRW_cache_light_spot_square_get(void)
{
if (!SHC.drw_light_spot_square) {
- float p[5][3] = {
+ const float p[5][3] = {
{0.0f, 0.0f, 0.0f},
{1.0f, 1.0f, -1.0f},
{1.0f, -1.0f, -1.0f},
@@ -1824,7 +1825,7 @@ GPUBatch *DRW_cache_light_spot_square_get(void)
GPU_vertbuf_data_alloc(vbo, 16);
/* piramid sides */
- for (int i = 1; i <= 4; ++i) {
+ for (int i = 1; i <= 4; i++) {
GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[0]);
GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[i]);
@@ -1840,7 +1841,7 @@ GPUBatch *DRW_cache_light_spot_square_get(void)
GPUBatch *DRW_cache_light_spot_square_volume_get(void)
{
if (!SHC.drw_light_spot_square_volume) {
- float p[5][3] = {
+ const float p[5][3] = {
{0.0f, 0.0f, 0.0f},
{1.0f, 1.0f, -1.0f},
{1.0f, -1.0f, -1.0f},
@@ -1863,7 +1864,7 @@ GPUBatch *DRW_cache_light_spot_square_volume_get(void)
GPU_vertbuf_data_alloc(vbo, 12);
/* piramid sides */
- for (int i = 1; i <= 4; ++i) {
+ for (int i = 1; i <= 4; i++) {
GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[0]);
GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[((i + 1) % 4) + 1]);
GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[(i % 4) + 1]);
@@ -1952,7 +1953,7 @@ GPUBatch *DRW_cache_lightprobe_cube_get(void)
int v_idx = 0;
const float sin_pi_3 = 0.86602540378f;
const float cos_pi_3 = 0.5f;
- float v[7][3] = {
+ const float v[7][3] = {
{0.0f, 1.0f, 0.0f},
{sin_pi_3, cos_pi_3, 0.0f},
{sin_pi_3, -cos_pi_3, 0.0f},
@@ -1974,7 +1975,7 @@ GPUBatch *DRW_cache_lightprobe_cube_get(void)
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, (6 + 3) * 2);
- for (int i = 0; i < 6; ++i) {
+ for (int i = 0; i < 6; i++) {
GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[i]);
GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[(i + 1) % 6]);
}
@@ -2021,7 +2022,7 @@ GPUBatch *DRW_cache_lightprobe_grid_get(void)
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, (6 * 2 + 3) * 2);
- for (int i = 0; i < 6; ++i) {
+ for (int i = 0; i < 6; i++) {
float tmp_v1[3], tmp_v2[3], tmp_tr[3];
copy_v3_v3(tmp_v1, v[i]);
copy_v3_v3(tmp_v2, v[(i + 1) % 6]);
@@ -2029,7 +2030,7 @@ GPUBatch *DRW_cache_lightprobe_grid_get(void)
GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v2);
/* Internal wires. */
- for (int j = 1; j < 2; ++j) {
+ for (int j = 1; j < 2; j++) {
mul_v3_v3fl(tmp_tr, v[(i / 2) * 2 + 1], -0.5f * j);
add_v3_v3v3(tmp_v1, v[i], tmp_tr);
add_v3_v3v3(tmp_v2, v[(i + 1) % 6], tmp_tr);
@@ -2057,7 +2058,7 @@ GPUBatch *DRW_cache_lightprobe_planar_get(void)
if (!SHC.drw_lightprobe_planar) {
int v_idx = 0;
const float sin_pi_3 = 0.86602540378f;
- float v[4][3] = {
+ const float v[4][3] = {
{0.0f, 0.5f, 0.0f},
{sin_pi_3, 0.0f, 0.0f},
{0.0f, -0.5f, 0.0f},
@@ -2076,7 +2077,7 @@ GPUBatch *DRW_cache_lightprobe_planar_get(void)
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, 4 * 2);
- for (int i = 0; i < 4; ++i) {
+ for (int i = 0; i < 4; i++) {
GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[i]);
GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[(i + 1) % 4]);
}
@@ -2214,7 +2215,7 @@ GPUBatch *DRW_cache_bone_octahedral_get(void)
GPU_vertbuf_data_alloc(vbo, 24);
for (int i = 0; i < 8; i++) {
- for (int j = 0; j < 3; ++j) {
+ for (int j = 0; j < 3; j++) {
GPU_vertbuf_attr_set(vbo, attr_id.nor, v_idx, bone_octahedral_solid_normals[i]);
GPU_vertbuf_attr_set(vbo,
attr_id.snor,
@@ -2710,7 +2711,7 @@ GPUBatch *DRW_cache_bone_stick_get(void)
GPU_indexbuf_init_ex(&elb, GPU_PRIM_TRI_FAN, (CIRCLE_RESOL + 2) * 2 + 6 + 2, vcount);
/* head/tail points */
- for (int i = 0; i < 2; ++i) {
+ for (int i = 0; i < 2; i++) {
/* center vertex */
copy_v2_fl(pos, 0.0f);
flag = (i == 0) ? POS_HEAD : POS_TAIL;
@@ -2735,7 +2736,7 @@ GPUBatch *DRW_cache_bone_stick_get(void)
/* Bone rectangle */
pos[0] = 0.0f;
- for (int i = 0; i < 6; ++i) {
+ for (int i = 0; i < 6; i++) {
pos[1] = (i == 0 || i == 3) ? 0.0f : ((i < 3) ? 1.0f : -1.0f);
flag = ((i < 2 || i > 4) ? POS_HEAD : POS_TAIL) | ((i == 0 || i == 3) ? 0 : COL_WIRE) |
COL_BONE | POS_BONE;
@@ -2896,8 +2897,8 @@ GPUBatch *DRW_cache_bone_arrows_get(void)
set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, pos, c);
/* Axis end marker */
- for (int j = 1; j < MARKER_FILL_LAYER + 1; ++j) {
- for (int i = 0; i < MARKER_LEN; ++i) {
+ for (int j = 1; j < MARKER_FILL_LAYER + 1; j++) {
+ for (int i = 0; i < MARKER_LEN; i++) {
float tmp[2];
mul_v2_v2fl(tmp, axis_marker[i], j / (float)MARKER_FILL_LAYER);
set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, tmp, c);
@@ -2924,8 +2925,8 @@ GPUBatch *DRW_cache_bone_arrows_get(void)
/* Axis name shadows */
copy_v3_fl(c, 0.0f);
c[axis] = 0.3f;
- for (int j = 0; j < SHADOW_RES; ++j) {
- for (int i = 0; i < axis_v_len; ++i) {
+ for (int j = 0; j < SHADOW_RES; j++) {
+ for (int i = 0; i < axis_v_len; i++) {
float tmp[2];
add_v2_v2v2(tmp, axis_verts[i], axis_name_shadow[j]);
set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, tmp, c);
@@ -2935,7 +2936,7 @@ GPUBatch *DRW_cache_bone_arrows_get(void)
/* Axis name */
copy_v3_fl(c, 0.1f);
c[axis] = 1.0f;
- for (int i = 0; i < axis_v_len; ++i) {
+ for (int i = 0; i < axis_v_len; i++) {
set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, axis_verts[i], c);
}
}
@@ -2990,12 +2991,12 @@ GPUBatch *DRW_cache_bone_dof_sphere_get(void)
GPU_vertbuf_data_alloc(vbo, n * n * 6 * 4);
uint v = 0;
- for (q = 0; q < 4; ++q) {
+ for (q = 0; q < 4; q++) {
pz = 0.0f;
- for (i = 1; i < n; ++i) {
+ for (i = 1; i < n; i++) {
z = staticSine[i];
px = 0.0f;
- for (j = 1; j <= (n - i); ++j) {
+ for (j = 1; j <= (n - i); j++) {
x = staticSine[j];
if (j == n - i) {
set_vert(px, z, q);
@@ -3937,7 +3938,7 @@ GPUBatch *DRW_cache_cursor_get(bool crosshair_lines)
GPU_vertbuf_data_alloc(vbo, vert_len);
int v = 0;
- for (int i = 0; i < segments; ++i) {
+ for (int i = 0; i < segments; i++) {
float angle = (float)(2 * M_PI) * ((float)i / (float)segments);
float x = f10 * cosf(angle);
float y = f10 * sinf(angle);
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index 9305dc6eef7..75b8d820884 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -20,8 +20,8 @@
* \ingroup draw
*/
-#ifndef __DRAW_CACHE_EXTRACT_MESH_H__
-#define __DRAW_CACHE_EXTRACT_MESH_H__
+#ifndef __DRAW_CACHE_EXTRACT_H__
+#define __DRAW_CACHE_EXTRACT_H__
/* Vertex Group Selection and display options */
typedef struct DRW_MeshWeightState {
@@ -136,8 +136,8 @@ typedef enum DRWBatchFlag {
MBC_EDIT_LNOR = (1 << 6),
MBC_EDIT_FACEDOTS = (1 << 7),
MBC_EDIT_MESH_ANALYSIS = (1 << 8),
- MBC_EDITUV_FACES_STRECH_AREA = (1 << 9),
- MBC_EDITUV_FACES_STRECH_ANGLE = (1 << 10),
+ MBC_EDITUV_FACES_STRETCH_AREA = (1 << 9),
+ MBC_EDITUV_FACES_STRETCH_ANGLE = (1 << 10),
MBC_EDITUV_FACES = (1 << 11),
MBC_EDITUV_EDGES = (1 << 12),
MBC_EDITUV_VERTS = (1 << 13),
@@ -157,7 +157,7 @@ typedef enum DRWBatchFlag {
} DRWBatchFlag;
#define MBC_EDITUV \
- (MBC_EDITUV_FACES_STRECH_AREA | MBC_EDITUV_FACES_STRECH_ANGLE | MBC_EDITUV_FACES | \
+ (MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | \
MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_EDITUV_FACEDOTS | MBC_WIRE_LOOPS_UVS)
#define FOREACH_MESH_BUFFER_CACHE(batch_cache, mbc) \
@@ -183,8 +183,8 @@ typedef struct MeshBatchCache {
GPUBatch *edit_fdots;
GPUBatch *edit_mesh_analysis;
/* Edit UVs */
- GPUBatch *edituv_faces_strech_area;
- GPUBatch *edituv_faces_strech_angle;
+ GPUBatch *edituv_faces_stretch_area;
+ GPUBatch *edituv_faces_stretch_angle;
GPUBatch *edituv_faces;
GPUBatch *edituv_edges;
GPUBatch *edituv_verts;
@@ -234,6 +234,12 @@ typedef struct MeshBatchCache {
/* Valid only if edge_detection is up to date. */
bool is_manifold;
+ /* Total areas for drawing UV Stretching. Contains the summed area in mesh
+ * space (`tot_area`) and the summed area in uv space (`tot_uvarea`).
+ *
+ * Only valid after `DRW_mesh_batch_cache_create_requested` has been called. */
+ float tot_area, tot_uv_area;
+
bool no_loose_wire;
} MeshBatchCache;
@@ -247,4 +253,4 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
const ToolSettings *ts,
const bool use_hide);
-#endif /* __DRAW_CACHE_EXTRACT_MESH_H__ */
+#endif /* __DRAW_CACHE_EXTRACT_H__ */
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c
index b0a0766eedb..40a36acc3d9 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.c
@@ -60,7 +60,6 @@
#include "GPU_batch.h"
#include "GPU_extensions.h"
-#include "GPU_material.h"
#include "DRW_render.h"
@@ -523,7 +522,7 @@ static void extract_tris_finish(const MeshRenderData *mr, void *ibo, void *_data
/* HACK Create ibo subranges and assign them to each GPUBatch. */
if (mr->use_final_mesh && mr->cache->surface_per_mat && mr->cache->surface_per_mat[0]) {
BLI_assert(mr->cache->surface_per_mat[0]->elem == ibo);
- for (int i = 0; i < mr->mat_len; ++i) {
+ for (int i = 0; i < mr->mat_len; i++) {
/* Multiply by 3 because these are triangle indices. */
int start = data->tri_mat_start[i] * 3;
int len = data->tri_mat_end[i] * 3 - data->tri_mat_start[i] * 3;
@@ -950,10 +949,8 @@ BLI_INLINE void lines_adjacency_triangle(
GPUIndexBufBuilder *elb = &data->elb;
/* Iter around the triangle's edges. */
for (int e = 0; e < 3; e++) {
- uint tmp = v1;
- v1 = v2, v2 = v3, v3 = tmp;
- tmp = l1;
- l1 = l2, l2 = l3, l3 = tmp;
+ SHIFT3(uint, v3, v2, v1);
+ SHIFT3(uint, l3, l2, l1);
bool inv_indices = (v2 > v3);
void **pval;
@@ -1186,8 +1183,7 @@ static void extract_edituv_lines_loop_mesh(const MeshRenderData *mr,
{
int loopend = mpoly->totloop + mpoly->loopstart - 1;
int loop_next_idx = (loop_idx == loopend) ? mpoly->loopstart : (loop_idx + 1);
- const bool real_edge = (mr->extract_type == MR_EXTRACT_MAPPED &&
- mr->e_origindex[mloop->e] != ORIGINDEX_NONE);
+ const bool real_edge = (mr->e_origindex == NULL || mr->e_origindex[mloop->e] != ORIGINDEX_NONE);
edituv_edge_add(data,
(mpoly->flag & ME_HIDE) != 0 || !real_edge,
(mpoly->flag & ME_FACE_SEL) != 0,
@@ -1433,7 +1429,7 @@ static void extract_pos_nor_loop_mesh(const MeshRenderData *mr,
int l,
const MLoop *mloop,
int UNUSED(p),
- const MPoly *mpoly,
+ const MPoly *UNUSED(mpoly),
void *_data)
{
MeshExtract_PosNor_Data *data = _data;
@@ -1442,12 +1438,15 @@ static void extract_pos_nor_loop_mesh(const MeshRenderData *mr,
copy_v3_v3(vert->pos, mvert->co);
vert->nor = data->packed_nor[mloop->v];
/* Flag for paint mode overlay. */
- if (mpoly->flag & ME_HIDE)
+ if (mvert->flag & ME_HIDE) {
vert->nor.w = -1;
- else if (mpoly->flag & ME_FACE_SEL)
+ }
+ else if (mvert->flag & SELECT) {
vert->nor.w = 1;
- else
+ }
+ else {
vert->nor.w = 0;
+ }
}
static void extract_pos_nor_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *_data)
@@ -1526,7 +1525,7 @@ static void *extract_lnor_init(const MeshRenderData *mr, void *buf)
{
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
- GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
GPU_vertformat_alias_add(&format, "lnor");
}
GPUVertBuf *vbo = buf;
@@ -1561,6 +1560,16 @@ static void extract_lnor_loop_mesh(
else {
((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(mr->poly_normals[p]);
}
+ /* Flag for paint mode overlay. */
+ if (mpoly->flag & ME_HIDE) {
+ ((GPUPackedNormal *)data)[l].w = -1;
+ }
+ else if (mpoly->flag & ME_FACE_SEL) {
+ ((GPUPackedNormal *)data)[l].w = 1;
+ }
+ else {
+ ((GPUPackedNormal *)data)[l].w = 0;
+ }
}
static const MeshExtract extract_lnor = {
@@ -2577,7 +2586,7 @@ static void *extract_edituv_data_init(const MeshRenderData *mr, void *buf)
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
- CustomData *cd_ldata = &mr->me->ldata;
+ CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
MeshExtract_EditUVData_Data *data = MEM_callocN(sizeof(*data), __func__);
data->vbo_data = (EditLoopData *)vbo->data;
@@ -2663,7 +2672,7 @@ static void *extract_stretch_area_init(const MeshRenderData *mr, void *buf)
{
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
- GPU_vertformat_attr_add(&format, "stretch", GPU_COMP_U16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ GPU_vertformat_attr_add(&format, "ratio", GPU_COMP_U16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
GPUVertBuf *vbo = buf;
@@ -2690,7 +2699,7 @@ BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_t
static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void *UNUSED(data))
{
- float totarea = 0, totuvarea = 0;
+ float tot_area = 0.0f, tot_uv_area = 0.0f;
float *area_ratio = MEM_mallocN(sizeof(float) * mr->poly_len, __func__);
if (mr->extract_type == MR_EXTRACT_BMESH) {
@@ -2703,8 +2712,8 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void *
BM_ITER_MESH_INDEX (efa, &f_iter, mr->bm, BM_FACES_OF_MESH, f) {
float area = BM_face_calc_area(efa);
float uvarea = BM_face_calc_area_uv(efa, uv_ofs);
- totarea += area;
- totuvarea += uvarea;
+ tot_area += area;
+ tot_uv_area += uvarea;
area_ratio[f] = area_ratio_get(area, uvarea);
}
}
@@ -2714,8 +2723,8 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void *
for (int p = 0; p < mr->poly_len; p++, mpoly++) {
float area = BKE_mesh_calc_poly_area(mpoly, &mr->mloop[mpoly->loopstart], mr->mvert);
float uvarea = BKE_mesh_calc_poly_uv_area(mpoly, uv_data);
- totarea += area;
- totuvarea += uvarea;
+ tot_area += area;
+ tot_uv_area += uvarea;
area_ratio[p] = area_ratio_get(area, uvarea);
}
}
@@ -2724,21 +2733,13 @@ static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void *
BLI_assert(0);
}
- float tot_ratio, inv_tot_ratio;
- if (totarea < FLT_EPSILON || totuvarea < FLT_EPSILON) {
- tot_ratio = 0.0f;
- inv_tot_ratio = 0.0f;
- }
- else {
- tot_ratio = totarea / totuvarea;
- inv_tot_ratio = totuvarea / totarea;
- }
+ mr->cache->tot_area = tot_area;
+ mr->cache->tot_uv_area = tot_uv_area;
/* Convert in place to avoid an extra allocation */
uint16_t *poly_stretch = (uint16_t *)area_ratio;
for (int p = 0; p < mr->poly_len; p++) {
- float stretch = area_ratio_to_stretch(area_ratio[p], tot_ratio, inv_tot_ratio);
- poly_stretch[p] = (1.0f - stretch) * 65534.0f;
+ poly_stretch[p] = area_ratio[p] * 65534.0f;
}
/* Copy face data for each loop. */
@@ -2809,8 +2810,8 @@ static void compute_normalize_edge_vectors(float auv[2][2],
float av[2][3],
const float uv[2],
const float uv_prev[2],
- const float co[2],
- const float co_prev[2])
+ const float co[3],
+ const float co_prev[3])
{
/* Move previous edge. */
copy_v2_v2(auv[0], auv[1]);
@@ -2973,7 +2974,7 @@ static const MeshExtract extract_stretch_angle = {
NULL,
extract_stretch_angle_finish,
0,
- true,
+ false,
};
/** \} */
@@ -4315,7 +4316,7 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
TaskPool *task_pool;
task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create(task_scheduler, NULL);
+ task_pool = BLI_task_pool_create_suspended(task_scheduler, NULL);
size_t counters_size = (sizeof(mbc) / sizeof(void *)) * sizeof(int32_t);
int32_t *task_counters = MEM_callocN(counters_size, __func__);
@@ -4325,7 +4326,8 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
if (mbc.buf.name) { \
extract_task_create( \
task_pool, mr, &extract_##name, mbc.buf.name, &task_counters[counter_used++]); \
- }
+ } \
+ ((void)0)
EXTRACT(vbo, pos_nor);
EXTRACT(vbo, lnor);
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index 3e33346c7d8..cdc1791b153 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -150,8 +150,10 @@ struct GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(struct Mesh *me);
/* Object mode Wireframe overlays */
struct GPUBatch *DRW_mesh_batch_cache_get_wireframes_face(struct Mesh *me);
/* edit-mesh UV editor */
-struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_area(struct Mesh *me);
-struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_angle(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(struct Mesh *me,
+ float **tot_area,
+ float **tot_uv_area);
+struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(struct Mesh *me);
diff --git a/source/blender/draw/intern/draw_cache_impl_curve.c b/source/blender/draw/intern/draw_cache_impl_curve.c
index 241cd68bc3a..ab800e42cc0 100644
--- a/source/blender/draw/intern/draw_cache_impl_curve.c
+++ b/source/blender/draw/intern/draw_cache_impl_curve.c
@@ -464,7 +464,7 @@ static void curve_batch_cache_init(Curve *cu)
cache->surf_per_mat = MEM_mallocN(sizeof(*cache->surf_per_mat) * cache->mat_len, __func__);
/* TODO Might be wiser to alloc in one chunk. */
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
cache->surf_per_mat_tris[i] = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf");
cache->surf_per_mat[i] = MEM_callocN(sizeof(GPUBatch), "GPUBatch");
}
@@ -516,24 +516,24 @@ static void curve_batch_cache_clear(Curve *cu)
return;
}
- for (int i = 0; i < sizeof(cache->ordered) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->ordered) / sizeof(void *); i++) {
GPUVertBuf **vbo = (GPUVertBuf **)&cache->ordered;
GPU_VERTBUF_DISCARD_SAFE(vbo[i]);
}
- for (int i = 0; i < sizeof(cache->edit) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->edit) / sizeof(void *); i++) {
GPUVertBuf **vbo = (GPUVertBuf **)&cache->edit;
GPU_VERTBUF_DISCARD_SAFE(vbo[i]);
}
- for (int i = 0; i < sizeof(cache->ibo) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->ibo) / sizeof(void *); i++) {
GPUIndexBuf **ibo = (GPUIndexBuf **)&cache->ibo;
GPU_INDEXBUF_DISCARD_SAFE(ibo[i]);
}
- for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); i++) {
GPUBatch **batch = (GPUBatch **)&cache->batch;
GPU_BATCH_DISCARD_SAFE(batch[i]);
}
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
GPU_INDEXBUF_DISCARD_SAFE(cache->surf_per_mat_tris[i]);
GPU_BATCH_DISCARD_SAFE(cache->surf_per_mat[i]);
}
@@ -772,7 +772,7 @@ static void curve_create_edit_data_and_handles(CurveRenderData *rdata,
GPU_indexbuf_add_line_verts(elbp_lines, vbo_len_used + 1, vbo_len_used + 2);
}
if (vbo_data) {
- char vflag[3] = {
+ const char vflag[3] = {
beztriple_vflag_get(rdata, bezt->f1, bezt->h1, a, nu_id),
beztriple_vflag_get(rdata, bezt->f2, bezt->h1, a, nu_id),
beztriple_vflag_get(rdata, bezt->f3, bezt->h2, a, nu_id),
@@ -891,7 +891,7 @@ GPUBatch **DRW_curve_batch_cache_get_surface_shaded(struct Curve *cu,
curve_cd_calc_used_gpu_layers(&cache->cd_needed, gpumat_array, gpumat_array_len);
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
DRW_batch_request(&cache->surf_per_mat[i]);
}
return cache->surf_per_mat;
@@ -929,7 +929,7 @@ void DRW_curve_batch_cache_create_requested(Object *ob)
/* Verify that all surface batches have needed attribute layers. */
/* TODO(fclem): We could be a bit smarter here and only do it per material. */
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
if ((cache->cd_used & cache->cd_needed) != cache->cd_needed) {
/* We can't discard batches at this point as they have been
* referenced for drawing. Just clear them in place. */
@@ -979,7 +979,7 @@ void DRW_curve_batch_cache_create_requested(Object *ob)
if (DRW_batch_requested(cache->batch.edit_normals, GPU_PRIM_LINES)) {
DRW_vbo_request(cache->batch.edit_normals, &cache->edit.curves_nor);
}
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
if (DRW_batch_requested(cache->surf_per_mat[i], GPU_PRIM_TRIS)) {
if (cache->mat_len > 1) {
DRW_ibo_request(cache->surf_per_mat[i], &cache->surf_per_mat_tris[i]);
@@ -1014,7 +1014,7 @@ void DRW_curve_batch_cache_create_requested(Object *ob)
DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.edit_verts_points, CU_DATATYPE_OVERLAY);
DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.edit_lines, CU_DATATYPE_OVERLAY);
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->surf_per_mat_tris[i], CU_DATATYPE_SURFACE);
}
@@ -1080,7 +1080,7 @@ void DRW_curve_batch_cache_create_requested(Object *ob)
#ifdef DEBUG
/* Make sure all requested batches have been setup. */
- for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); i++) {
BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0));
}
#endif
diff --git a/source/blender/draw/intern/draw_cache_impl_lattice.c b/source/blender/draw/intern/draw_cache_impl_lattice.c
index 8b3864684b5..01cd2b52ae3 100644
--- a/source/blender/draw/intern/draw_cache_impl_lattice.c
+++ b/source/blender/draw/intern/draw_cache_impl_lattice.c
@@ -420,7 +420,7 @@ static GPUVertBuf *lattice_batch_cache_get_pos(LatticeRenderData *rdata,
cache->pos = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(cache->pos, vert_len);
- for (int i = 0; i < vert_len; ++i) {
+ for (int i = 0; i < vert_len; i++) {
const BPoint *bp = lattice_render_data_vert_bpoint(rdata, i);
GPU_vertbuf_attr_set(cache->pos, attr_id.pos, i, bp->vec);
@@ -516,7 +516,7 @@ static void lattice_batch_cache_create_overlay_batches(Lattice *lt)
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, vert_len);
- for (int i = 0; i < vert_len; ++i) {
+ for (int i = 0; i < vert_len; i++) {
const BPoint *bp = lattice_render_data_vert_bpoint(rdata, i);
char vflag = 0;
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 884d39343c6..4a69aa3e008 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -55,7 +55,6 @@
#include "bmesh.h"
#include "GPU_batch.h"
-#include "GPU_extensions.h"
#include "GPU_material.h"
#include "DRW_render.h"
@@ -502,14 +501,17 @@ static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache)
GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_points);
GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_fdots);
}
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_strech_area);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_strech_angle);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_area);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_angle);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_edges);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_verts);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_fdots);
GPU_BATCH_DISCARD_SAFE(cache->batch.wire_loops_uvs);
+ cache->tot_area = 0.0f;
+ cache->tot_uv_area = 0.0f;
+
cache->batch_ready &= ~MBC_EDITUV;
}
@@ -549,6 +551,7 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode)
{
GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.lines_paint_mask);
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.pos_nor);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.lnor);
}
GPU_BATCH_DISCARD_SAFE(cache->batch.surface);
GPU_BATCH_DISCARD_SAFE(cache->batch.wire_loops);
@@ -576,8 +579,8 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode)
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edituv_data);
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_edituv_data);
}
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_strech_area);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_strech_angle);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_area);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_angle);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_edges);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_verts);
@@ -599,14 +602,14 @@ static void mesh_batch_cache_clear(Mesh *me)
{
GPUVertBuf **vbos = (GPUVertBuf **)&mbufcache->vbo;
GPUIndexBuf **ibos = (GPUIndexBuf **)&mbufcache->ibo;
- for (int i = 0; i < sizeof(mbufcache->vbo) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(mbufcache->vbo) / sizeof(void *); i++) {
GPU_VERTBUF_DISCARD_SAFE(vbos[i]);
}
- for (int i = 0; i < sizeof(mbufcache->ibo) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(mbufcache->ibo) / sizeof(void *); i++) {
GPU_INDEXBUF_DISCARD_SAFE(ibos[i]);
}
}
- for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); i++) {
GPUBatch **batch = (GPUBatch **)&cache->batch;
GPU_BATCH_DISCARD_SAFE(batch[i]);
}
@@ -752,7 +755,7 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me,
*auto_layer_is_srgb = cache->auto_layer_is_srgb;
*auto_layer_count = cache->auto_layer_len;
}
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
DRW_batch_request(&cache->surface_per_mat[i]);
}
return cache->surface_per_mat;
@@ -763,7 +766,7 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(Mesh *me)
MeshBatchCache *cache = mesh_batch_cache_get(me);
mesh_batch_cache_add_request(cache, MBC_SURF_PER_MAT);
texpaint_request_active_uv(cache, me);
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
DRW_batch_request(&cache->surface_per_mat[i]);
}
return cache->surface_per_mat;
@@ -873,20 +876,34 @@ GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(Mesh *me)
/** \name UV Image editor API
* \{ */
-GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_area(Mesh *me)
+/* Creates the GPUBatch for drawing the UV Stretching Area Overlay.
+ * Optional retrieves the total area or total uv area of the mesh.
+ *
+ * The `cache->tot_area` and cache->tot_uv_area` update are calculation are
+ * only valid after calling `DRW_mesh_batch_cache_create_requested`. */
+GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Mesh *me,
+ float **tot_area,
+ float **tot_uv_area)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
texpaint_request_active_uv(cache, me);
- mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRECH_AREA);
- return DRW_batch_request(&cache->batch.edituv_faces_strech_area);
+ mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_AREA);
+
+ if (tot_area != NULL) {
+ *tot_area = &cache->tot_area;
+ }
+ if (tot_uv_area != NULL) {
+ *tot_uv_area = &cache->tot_uv_area;
+ }
+ return DRW_batch_request(&cache->batch.edituv_faces_stretch_area);
}
-GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_angle(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
texpaint_request_active_uv(cache, me);
- mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRECH_ANGLE);
- return DRW_batch_request(&cache->batch.edituv_faces_strech_angle);
+ mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_ANGLE);
+ return DRW_batch_request(&cache->batch.edituv_faces_stretch_angle);
}
GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(Mesh *me)
@@ -999,12 +1016,37 @@ void DRW_mesh_batch_cache_create_requested(
}
}
+ /* HACK: if MBC_SURF_PER_MAT is requested and ibo.tris is already available, it won't have it's
+ * index ranges initialized. So discard ibo.tris in order to recreate it.
+ * This needs to happen before saved_elem_ranges is populated. */
+ if ((batch_requested & MBC_SURF_PER_MAT) != 0 && (cache->batch_ready & MBC_SURF_PER_MAT) == 0) {
+ FOREACH_MESH_BUFFER_CACHE(cache, mbuffercache)
+ {
+ GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.tris);
+ }
+ /* Clear all batches that reference ibo.tris. */
+ GPU_BATCH_CLEAR_SAFE(cache->batch.surface);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.surface_weights);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edit_mesh_analysis);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edit_triangles);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edit_lnor);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edit_selection_faces);
+ for (int i = 0; i < cache->mat_len; i++) {
+ GPU_BATCH_CLEAR_SAFE(cache->surface_per_mat[i]);
+ }
+
+ cache->batch_ready &= ~(MBC_SURFACE | MBC_SURFACE_WEIGHTS | MBC_EDIT_MESH_ANALYSIS |
+ MBC_EDIT_TRIANGLES | MBC_EDIT_LNOR | MBC_EDIT_SELECTION_FACES);
+ }
+
if (batch_requested &
- (MBC_SURFACE | MBC_SURF_PER_MAT | MBC_WIRE_LOOPS_UVS | MBC_EDITUV_FACES_STRECH_AREA |
- MBC_EDITUV_FACES_STRECH_ANGLE | MBC_EDITUV_FACES | MBC_EDITUV_EDGES | MBC_EDITUV_VERTS)) {
+ (MBC_SURFACE | MBC_SURF_PER_MAT | MBC_WIRE_LOOPS_UVS | MBC_EDITUV_FACES_STRETCH_AREA |
+ MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | MBC_EDITUV_EDGES | MBC_EDITUV_VERTS)) {
/* Modifiers will only generate an orco layer if the mesh is deformed. */
if (cache->cd_needed.orco != 0) {
- if (CustomData_get_layer(&me->vdata, CD_ORCO) == NULL) {
+ /* Orco is always extracted from final mesh. */
+ Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me;
+ if (CustomData_get_layer(&me_final->vdata, CD_ORCO) == NULL) {
/* Skip orco calculation */
cache->cd_needed.orco = 0;
}
@@ -1036,7 +1078,7 @@ void DRW_mesh_batch_cache_create_requested(
* This is only if the cd_needed changes so it is ok to keep them.*/
if (cache->surface_per_mat[0] && cache->surface_per_mat[0]->elem) {
saved_elem_ranges = MEM_callocN(sizeof(saved_elem_ranges) * cache->mat_len, __func__);
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
saved_elem_ranges[i] = cache->surface_per_mat[i]->elem;
/* Avoid deletion as the batch is owner. */
cache->surface_per_mat[i]->elem = NULL;
@@ -1045,7 +1087,7 @@ void DRW_mesh_batch_cache_create_requested(
}
/* We can't discard batches at this point as they have been
* referenced for drawing. Just clear them in place. */
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
GPU_BATCH_CLEAR_SAFE(cache->surface_per_mat[i]);
}
GPU_BATCH_CLEAR_SAFE(cache->batch.surface);
@@ -1077,8 +1119,8 @@ void DRW_mesh_batch_cache_create_requested(
/* We only clear the batches as they may already have been
* referenced. */
GPU_BATCH_CLEAR_SAFE(cache->batch.wire_loops_uvs);
- GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_strech_area);
- GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_strech_angle);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_stretch_area);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_stretch_angle);
GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces);
GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_edges);
GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_verts);
@@ -1140,6 +1182,8 @@ void DRW_mesh_batch_cache_create_requested(
}
if (DRW_batch_requested(cache->batch.wire_loops, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.wire_loops, &mbufcache->ibo.lines_paint_mask);
+ /* Order matters. First ones override latest vbos' attribs. */
+ DRW_vbo_request(cache->batch.wire_loops, &mbufcache->vbo.lnor);
DRW_vbo_request(cache->batch.wire_loops, &mbufcache->vbo.pos_nor);
}
if (DRW_batch_requested(cache->batch.wire_edges, GPU_PRIM_LINES)) {
@@ -1161,7 +1205,7 @@ void DRW_mesh_batch_cache_create_requested(
}
/* Per Material */
- for (int i = 0; i < cache->mat_len; ++i) {
+ for (int i = 0; i < cache->mat_len; i++) {
if (DRW_batch_requested(cache->surface_per_mat[i], GPU_PRIM_TRIS)) {
if (saved_elem_ranges && saved_elem_ranges[i]) {
/* XXX assign old element buffer range (it did not change).*/
@@ -1258,17 +1302,17 @@ void DRW_mesh_batch_cache_create_requested(
DRW_vbo_request(cache->batch.edituv_faces, &mbufcache->vbo.uv);
DRW_vbo_request(cache->batch.edituv_faces, &mbufcache->vbo.edituv_data);
}
- if (DRW_batch_requested(cache->batch.edituv_faces_strech_area, GPU_PRIM_TRIS)) {
- DRW_ibo_request(cache->batch.edituv_faces_strech_area, &mbufcache->ibo.edituv_tris);
- DRW_vbo_request(cache->batch.edituv_faces_strech_area, &mbufcache->vbo.uv);
- DRW_vbo_request(cache->batch.edituv_faces_strech_area, &mbufcache->vbo.edituv_data);
- DRW_vbo_request(cache->batch.edituv_faces_strech_area, &mbufcache->vbo.stretch_area);
+ if (DRW_batch_requested(cache->batch.edituv_faces_stretch_area, GPU_PRIM_TRIS)) {
+ DRW_ibo_request(cache->batch.edituv_faces_stretch_area, &mbufcache->ibo.edituv_tris);
+ DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbufcache->vbo.uv);
+ DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbufcache->vbo.edituv_data);
+ DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbufcache->vbo.stretch_area);
}
- if (DRW_batch_requested(cache->batch.edituv_faces_strech_angle, GPU_PRIM_TRIS)) {
- DRW_ibo_request(cache->batch.edituv_faces_strech_angle, &mbufcache->ibo.edituv_tris);
- DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &mbufcache->vbo.uv);
- DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &mbufcache->vbo.edituv_data);
- DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &mbufcache->vbo.stretch_angle);
+ if (DRW_batch_requested(cache->batch.edituv_faces_stretch_angle, GPU_PRIM_TRIS)) {
+ DRW_ibo_request(cache->batch.edituv_faces_stretch_angle, &mbufcache->ibo.edituv_tris);
+ DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbufcache->vbo.uv);
+ DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbufcache->vbo.edituv_data);
+ DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbufcache->vbo.stretch_angle);
}
if (DRW_batch_requested(cache->batch.edituv_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.edituv_edges, &mbufcache->ibo.edituv_lines);
@@ -1305,25 +1349,25 @@ void DRW_mesh_batch_cache_create_requested(
#ifdef DEBUG
check:
/* Make sure all requested batches have been setup. */
- for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); i++) {
BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0));
}
- for (int i = 0; i < sizeof(cache->final.vbo) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->final.vbo) / sizeof(void *); i++) {
BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->final.vbo)[i]));
}
- for (int i = 0; i < sizeof(cache->final.ibo) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->final.ibo) / sizeof(void *); i++) {
BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->final.ibo)[i]));
}
- for (int i = 0; i < sizeof(cache->cage.vbo) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->cage.vbo) / sizeof(void *); i++) {
BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->cage.vbo)[i]));
}
- for (int i = 0; i < sizeof(cache->cage.ibo) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->cage.ibo) / sizeof(void *); i++) {
BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->cage.ibo)[i]));
}
- for (int i = 0; i < sizeof(cache->uv_cage.vbo) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->uv_cage.vbo) / sizeof(void *); i++) {
BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->uv_cage.vbo)[i]));
}
- for (int i = 0; i < sizeof(cache->uv_cage.ibo) / sizeof(void *); ++i) {
+ for (int i = 0; i < sizeof(cache->uv_cage.ibo) / sizeof(void *); i++) {
BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->uv_cage.ibo)[i]));
}
#endif
diff --git a/source/blender/draw/intern/draw_cache_impl_metaball.c b/source/blender/draw/intern/draw_cache_impl_metaball.c
index 60f15338412..e3bfcbde3ef 100644
--- a/source/blender/draw/intern/draw_cache_impl_metaball.c
+++ b/source/blender/draw/intern/draw_cache_impl_metaball.c
@@ -212,7 +212,7 @@ GPUBatch **DRW_metaball_batch_cache_get_surface_shaded(Object *ob,
cache->shaded_triangles = MEM_callocN(sizeof(*cache->shaded_triangles) * cache->mat_len,
__func__);
cache->shaded_triangles[0] = DRW_metaball_batch_cache_get_triangles_with_normals(ob);
- for (int i = 1; i < cache->mat_len; ++i) {
+ for (int i = 1; i < cache->mat_len; i++) {
cache->shaded_triangles[i] = NULL;
}
}
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
index 6cd03d14bfd..3c586e6daec 100644
--- a/source/blender/draw/intern/draw_cache_impl_particles.c
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -190,18 +190,18 @@ static void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache)
DRW_TEXTURE_FREE_SAFE(hair_cache->strand_tex);
DRW_TEXTURE_FREE_SAFE(hair_cache->strand_seg_tex);
- for (int i = 0; i < MAX_MTFACE; ++i) {
+ for (int i = 0; i < MAX_MTFACE; i++) {
GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_uv_buf[i]);
DRW_TEXTURE_FREE_SAFE(hair_cache->uv_tex[i]);
}
- for (int i = 0; i < MAX_MCOL; ++i) {
+ for (int i = 0; i < MAX_MCOL; i++) {
GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_col_buf[i]);
DRW_TEXTURE_FREE_SAFE(hair_cache->col_tex[i]);
}
- for (int i = 0; i < MAX_HAIR_SUBDIV; ++i) {
+ for (int i = 0; i < MAX_HAIR_SUBDIV; i++) {
GPU_VERTBUF_DISCARD_SAFE(hair_cache->final[i].proc_buf);
DRW_TEXTURE_FREE_SAFE(hair_cache->final[i].proc_tex);
- for (int j = 0; j < MAX_THICKRES; ++j) {
+ for (int j = 0; j < MAX_THICKRES; j++) {
GPU_BATCH_DISCARD_SAFE(hair_cache->final[i].proc_hairs[j]);
}
}
@@ -1335,15 +1335,6 @@ static void particle_batch_cache_ensure_pos(Object *object,
sim.psmd = psys_get_modifier(object, psys);
sim.psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
- if (psys->part->phystype == PART_PHYS_KEYED) {
- if (psys->flag & PSYS_KEYED) {
- psys_count_keyed_targets(&sim);
- if (psys->totkeyed == 0) {
- return;
- }
- }
- }
-
GPU_VERTBUF_DISCARD_SAFE(point_cache->pos);
if (format.attr_len == 0) {
@@ -1551,6 +1542,9 @@ static void ensure_edit_inner_points_count(const PTCacheEdit *edit, ParticleBatc
cache->edit_inner_point_len = 0;
for (int point_index = 0; point_index < edit->totpoint; point_index++) {
const PTCacheEditPoint *point = &edit->points[point_index];
+ if (point->flag & PEP_HIDE) {
+ continue;
+ }
BLI_assert(point->totkey >= 1);
cache->edit_inner_point_len += (point->totkey - 1);
}
@@ -1572,6 +1566,9 @@ static void particle_batch_cache_ensure_edit_inner_pos(PTCacheEdit *edit,
int global_key_index = 0;
for (int point_index = 0; point_index < edit->totpoint; point_index++) {
const PTCacheEditPoint *point = &edit->points[point_index];
+ if (point->flag & PEP_HIDE) {
+ continue;
+ }
for (int key_index = 0; key_index < point->totkey - 1; key_index++) {
PTCacheEditKey *key = &point->keys[key_index];
float color = (key->flag & PEK_SELECT) ? 1.0f : 0.0f;
@@ -1602,7 +1599,14 @@ static void ensure_edit_tip_points_count(const PTCacheEdit *edit, ParticleBatchC
if (cache->edit_tip_pos != NULL) {
return;
}
- cache->edit_tip_point_len = edit->totpoint;
+ cache->edit_tip_point_len = 0;
+ for (int point_index = 0; point_index < edit->totpoint; point_index++) {
+ const PTCacheEditPoint *point = &edit->points[point_index];
+ if (point->flag & PEP_HIDE) {
+ continue;
+ }
+ cache->edit_tip_point_len += 1;
+ }
}
static void particle_batch_cache_ensure_edit_tip_pos(PTCacheEdit *edit, ParticleBatchCache *cache)
@@ -1617,13 +1621,18 @@ static void particle_batch_cache_ensure_edit_tip_pos(PTCacheEdit *edit, Particle
cache->edit_tip_pos = GPU_vertbuf_create_with_format(edit_point_format);
GPU_vertbuf_data_alloc(cache->edit_tip_pos, cache->edit_tip_point_len);
+ int global_point_index = 0;
for (int point_index = 0; point_index < edit->totpoint; point_index++) {
const PTCacheEditPoint *point = &edit->points[point_index];
+ if (point->flag & PEP_HIDE) {
+ continue;
+ }
PTCacheEditKey *key = &point->keys[point->totkey - 1];
float color = (key->flag & PEK_SELECT) ? 1.0f : 0.0f;
- GPU_vertbuf_attr_set(cache->edit_tip_pos, pos_id, point_index, key->world_co);
- GPU_vertbuf_attr_set(cache->edit_tip_pos, color_id, point_index, &color);
+ GPU_vertbuf_attr_set(cache->edit_tip_pos, pos_id, global_point_index, key->world_co);
+ GPU_vertbuf_attr_set(cache->edit_tip_pos, color_id, global_point_index, &color);
+ global_point_index++;
}
}
diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c
index ac3e7e4ce67..7f679dd5581 100644
--- a/source/blender/draw/intern/draw_common.c
+++ b/source/blender/draw/intern/draw_common.c
@@ -243,6 +243,7 @@ extern char datatoc_gpu_shader_point_varying_color_frag_glsl[];
extern char datatoc_object_mball_handles_vert_glsl[];
extern char datatoc_object_empty_axes_vert_glsl[];
+extern char datatoc_object_color_axes_vert_glsl[];
typedef struct COMMON_Shaders {
struct GPUShader *shape_outline;
@@ -262,6 +263,7 @@ typedef struct COMMON_Shaders {
struct GPUShader *volume_velocity_needle_sh;
struct GPUShader *volume_velocity_sh;
struct GPUShader *empty_axes_sh;
+ struct GPUShader *color_axes_sh;
struct GPUShader *mball_handles;
} COMMON_Shaders;
@@ -294,13 +296,13 @@ static struct {
void DRW_globals_free(void)
{
struct GPUVertFormat **format = &g_formats.instance_screenspace;
- for (int i = 0; i < sizeof(g_formats) / sizeof(void *); ++i, ++format) {
+ for (int i = 0; i < sizeof(g_formats) / sizeof(void *); i++, format++) {
MEM_SAFE_FREE(*format);
}
for (int j = 0; j < GPU_SHADER_CFG_LEN; j++) {
struct GPUShader **shader = &g_shaders[j].shape_outline;
- for (int i = 0; i < sizeof(g_shaders[j]) / sizeof(void *); ++i, ++shader) {
+ for (int i = 0; i < sizeof(g_shaders[j]) / sizeof(void *); i++, shader++) {
DRW_SHADER_FREE_SAFE(*shader);
}
}
@@ -549,6 +551,37 @@ struct DRWCallBuffer *buffer_instance_empty_axes(DRWPass *pass,
return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_sized, geom);
}
+struct DRWCallBuffer *buffer_instance_color_axes(DRWPass *pass,
+ struct GPUBatch *geom,
+ DRWShadingGroup **r_grp,
+ eGPUShaderConfig sh_cfg)
+{
+ COMMON_Shaders *sh_data = &g_shaders[sh_cfg];
+ if (sh_data->color_axes_sh == NULL) {
+ const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
+ sh_data->color_axes_sh = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg_data->lib, datatoc_object_color_axes_vert_glsl, NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, NULL},
+ });
+ }
+
+ DRW_shgroup_instance_format(g_formats.instance_sized,
+ {
+ {"color", DRW_ATTR_FLOAT, 3},
+ {"size", DRW_ATTR_FLOAT, 1},
+ {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16},
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_create(sh_data->color_axes_sh, pass);
+ DRW_shgroup_uniform_vec3(grp, "screenVecs[0]", DRW_viewport_screenvecs_get(), 2);
+ if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
+ DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
+ }
+ *r_grp = grp;
+ return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_sized, geom);
+}
+
struct DRWCallBuffer *buffer_instance_outline(DRWPass *pass,
struct GPUBatch *geom,
const int *baseid,
@@ -1062,7 +1095,7 @@ struct GPUShader *volume_velocity_shader_get(bool use_needle)
NULL,
datatoc_gpu_shader_flat_color_frag_glsl,
datatoc_common_view_lib_glsl,
- "#define USE_NEEDLE");
+ "#define USE_NEEDLE\n");
}
return sh_data->volume_velocity_needle_sh;
}
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index 8e6b8895dd3..9899b6c0194 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -160,6 +160,10 @@ struct DRWCallBuffer *buffer_instance_screen_aligned(struct DRWPass *pass,
struct DRWCallBuffer *buffer_instance_empty_axes(struct DRWPass *pass,
struct GPUBatch *geom,
eGPUShaderConfig sh_cfg);
+struct DRWCallBuffer *buffer_instance_color_axes(struct DRWPass *pass,
+ struct GPUBatch *geom,
+ struct DRWShadingGroup **r_grp,
+ eGPUShaderConfig sh_cfg);
struct DRWCallBuffer *buffer_instance_scaled(struct DRWPass *pass,
struct GPUBatch *geom,
eGPUShaderConfig sh_cfg);
diff --git a/source/blender/draw/intern/draw_debug.c b/source/blender/draw/intern/draw_debug.c
index 9681ffd9d3d..6b05bb07c0f 100644
--- a/source/blender/draw/intern/draw_debug.c
+++ b/source/blender/draw/intern/draw_debug.c
@@ -63,7 +63,7 @@ void DRW_debug_polygon_v3(const float (*v)[3], const int vert_len, const float c
{
BLI_assert(vert_len > 1);
- for (int i = 0; i < vert_len; ++i) {
+ for (int i = 0; i < vert_len; i++) {
DRW_debug_line_v3v3(v[i], v[(i + 1) % vert_len], color);
}
}
@@ -117,7 +117,7 @@ void DRW_debug_m4_as_bbox(const float m[4][4], const float color[4], const bool
}
BKE_boundbox_init_from_minmax(&bb, min, max);
- for (int i = 0; i < 8; ++i) {
+ for (int i = 0; i < 8; i++) {
mul_project_m4_v3(project_matrix, bb.vec[i]);
}
DRW_debug_bbox(&bb, color);
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
index 44ed01c47aa..58085cf08c6 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.c
@@ -151,13 +151,13 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
}
/* TODO optimize this. Only bind the ones GPUMaterial needs. */
- for (int i = 0; i < hair_cache->num_uv_layers; ++i) {
- for (int n = 0; n < MAX_LAYER_NAME_CT && hair_cache->uv_layer_names[i][n][0] != '\0'; ++n) {
+ for (int i = 0; i < hair_cache->num_uv_layers; i++) {
+ for (int n = 0; n < MAX_LAYER_NAME_CT && hair_cache->uv_layer_names[i][n][0] != '\0'; n++) {
DRW_shgroup_uniform_texture(shgrp, hair_cache->uv_layer_names[i][n], hair_cache->uv_tex[i]);
}
}
- for (int i = 0; i < hair_cache->num_col_layers; ++i) {
- for (int n = 0; n < MAX_LAYER_NAME_CT && hair_cache->col_layer_names[i][n][0] != '\0'; ++n) {
+ for (int i = 0; i < hair_cache->num_col_layers; i++) {
+ for (int n = 0; n < MAX_LAYER_NAME_CT && hair_cache->col_layer_names[i][n][0] != '\0'; n++) {
DRW_shgroup_uniform_texture(
shgrp, hair_cache->col_layer_names[i][n], hair_cache->col_tex[i]);
}
@@ -201,30 +201,33 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
/* Transform Feedback subdiv. */
if (need_ft_update) {
int final_points_len = hair_cache->final[subdiv].strands_res * hair_cache->strands_len;
- GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM);
+ if (final_points_len) {
+ GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM);
#ifdef USE_TRANSFORM_FEEDBACK
- DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create(
- tf_shader, g_tf_pass, hair_cache->final[subdiv].proc_buf);
+ DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create(
+ tf_shader, g_tf_pass, hair_cache->final[subdiv].proc_buf);
#else
- DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass);
-
- ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__);
- pr_call->next = g_tf_calls;
- pr_call->vbo = hair_cache->final[subdiv].proc_buf;
- pr_call->shgrp = tf_shgrp;
- pr_call->vert_len = final_points_len;
- g_tf_calls = pr_call;
- DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1);
- DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1);
- DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1);
+ DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass);
+
+ ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__);
+ pr_call->next = g_tf_calls;
+ pr_call->vbo = hair_cache->final[subdiv].proc_buf;
+ pr_call->shgrp = tf_shgrp;
+ pr_call->vert_len = final_points_len;
+ g_tf_calls = pr_call;
+ DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1);
+ DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1);
+ DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1);
#endif
- DRW_shgroup_uniform_texture(tf_shgrp, "hairPointBuffer", hair_cache->point_tex);
- DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", hair_cache->strand_tex);
- DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandSegBuffer", hair_cache->strand_seg_tex);
- DRW_shgroup_uniform_int(tf_shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1);
- DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len);
+ DRW_shgroup_uniform_texture(tf_shgrp, "hairPointBuffer", hair_cache->point_tex);
+ DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", hair_cache->strand_tex);
+ DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandSegBuffer", hair_cache->strand_seg_tex);
+ DRW_shgroup_uniform_int(
+ tf_shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1);
+ DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len);
+ }
}
return shgrp;
@@ -323,7 +326,7 @@ void DRW_hair_update(void)
void DRW_hair_free(void)
{
- for (int i = 0; i < PART_REFINE_MAX_SHADER; ++i) {
+ for (int i = 0; i < PART_REFINE_MAX_SHADER; i++) {
DRW_SHADER_FREE_SAFE(g_refine_shaders[i]);
}
}
diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c
index 8f26cc72a02..81b10e095c3 100644
--- a/source/blender/draw/intern/draw_instance_data.c
+++ b/source/blender/draw/intern/draw_instance_data.c
@@ -64,7 +64,7 @@ typedef struct DRWTempBufferHandle {
/** Format pointer for reuse. */
GPUVertFormat *format;
/** Touched vertex length for resize. */
- uint *vert_len;
+ int *vert_len;
} DRWTempBufferHandle;
static ListBase g_idatalists = {NULL, NULL};
@@ -112,7 +112,7 @@ static void instance_batch_free(GPUBatch *geom, void *UNUSED(user_data))
*/
GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist,
GPUVertFormat *format,
- uint *vert_len)
+ int *vert_len)
{
BLI_assert(format != NULL);
BLI_assert(vert_len != NULL);
@@ -298,7 +298,7 @@ void DRW_instance_data_list_free(DRWInstanceDataList *idatalist)
{
DRWInstanceData *idata, *next_idata;
- for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) {
+ for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; i++) {
for (idata = idatalist->idata_head[i]; idata; idata = next_idata) {
next_idata = idata->next;
DRW_instance_data_free(idata);
@@ -319,7 +319,7 @@ void DRW_instance_data_list_reset(DRWInstanceDataList *idatalist)
{
DRWInstanceData *idata;
- for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) {
+ for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; i++) {
for (idata = idatalist->idata_head[i]; idata; idata = idata->next) {
idata->used = false;
}
@@ -331,7 +331,7 @@ void DRW_instance_data_list_free_unused(DRWInstanceDataList *idatalist)
DRWInstanceData *idata, *next_idata;
/* Remove unused data blocks and sanitize each list. */
- for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) {
+ for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; i++) {
idatalist->idata_tail[i] = NULL;
for (idata = idatalist->idata_head[i]; idata; idata = next_idata) {
next_idata = idata->next;
@@ -360,7 +360,7 @@ void DRW_instance_data_list_resize(DRWInstanceDataList *idatalist)
{
DRWInstanceData *idata;
- for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) {
+ for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; i++) {
for (idata = idatalist->idata_head[i]; idata; idata = idata->next) {
BLI_mempool_clear_ex(idata->mempool, BLI_mempool_len(idata->mempool));
}
diff --git a/source/blender/draw/intern/draw_instance_data.h b/source/blender/draw/intern/draw_instance_data.h
index 2ede68e16d8..524c4cd96d8 100644
--- a/source/blender/draw/intern/draw_instance_data.h
+++ b/source/blender/draw/intern/draw_instance_data.h
@@ -40,7 +40,7 @@ DRWInstanceData *DRW_instance_data_request(DRWInstanceDataList *idatalist, uint
GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist,
GPUVertFormat *format,
- uint *vert_len);
+ int *vert_len);
GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist,
GPUVertBuf *buf,
GPUBatch *geom);
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 3d8a7bb1e30..6387cecc01f 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -33,6 +33,7 @@
#include "BKE_anim.h"
#include "BKE_colortools.h"
+#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_editmesh.h"
#include "BKE_global.h"
@@ -41,6 +42,7 @@
#include "BKE_main.h"
#include "BKE_mball.h"
#include "BKE_mesh.h"
+#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_paint.h"
@@ -65,7 +67,6 @@
#include "GPU_uniformbuffer.h"
#include "GPU_viewport.h"
#include "GPU_matrix.h"
-#include "GPU_select.h"
#include "IMB_colormanagement.h"
@@ -98,10 +99,6 @@
#include "DRW_select_buffer.h"
-#ifdef USE_GPU_SELECT
-# include "GPU_select.h"
-#endif
-
/** Render State: No persistent data between draw calls. */
DRWManager DST = {NULL};
@@ -540,8 +537,11 @@ static void drw_viewport_cache_resize(void)
GPU_texture_free(*tex);
}
- BLI_memblock_clear(DST.vmempool->calls, NULL);
- BLI_memblock_clear(DST.vmempool->states, NULL);
+ BLI_memblock_clear(DST.vmempool->commands, NULL);
+ BLI_memblock_clear(DST.vmempool->commands_small, NULL);
+ BLI_memblock_clear(DST.vmempool->callbuffers, NULL);
+ BLI_memblock_clear(DST.vmempool->obmats, NULL);
+ BLI_memblock_clear(DST.vmempool->obinfos, NULL);
BLI_memblock_clear(DST.vmempool->cullstates, NULL);
BLI_memblock_clear(DST.vmempool->shgroups, NULL);
BLI_memblock_clear(DST.vmempool->uniforms, NULL);
@@ -589,28 +589,28 @@ static void drw_context_state_init(void)
}
}
-static DRWCallState *draw_unit_state_create(void)
+static void draw_unit_state_create(void)
{
- DRWCallState *state = BLI_memblock_alloc(DST.vmempool->states);
- state->flag = 0;
- state->matflag = 0;
+ DRWObjectInfos *infos = BLI_memblock_alloc(DST.vmempool->obinfos);
+ DRWObjectMatrix *mats = BLI_memblock_alloc(DST.vmempool->obmats);
+ DRWCullingState *culling = BLI_memblock_alloc(DST.vmempool->cullstates);
- unit_m4(state->model);
- unit_m4(state->modelinverse);
+ unit_m4(mats->model);
+ unit_m4(mats->modelinverse);
- copy_v3_fl(state->orcotexfac[0], 0.0f);
- copy_v3_fl(state->orcotexfac[1], 1.0f);
+ copy_v3_fl(infos->orcotexfac[0], 0.0f);
+ copy_v3_fl(infos->orcotexfac[1], 1.0f);
- state->ob_index = 0;
- state->ob_random = 0.0f;
- copy_v3_fl(state->ob_color, 1.0f);
+ infos->ob_index = 0;
+ infos->ob_random = 0.0f;
+ infos->ob_neg_scale = 1.0f;
+ copy_v3_fl(infos->ob_color, 1.0f);
/* TODO(fclem) get rid of this. */
- state->culling = BLI_memblock_alloc(DST.vmempool->cullstates);
- state->culling->bsphere.radius = -1.0f;
- state->culling->user_data = NULL;
+ culling->bsphere.radius = -1.0f;
+ culling->user_data = NULL;
- return state;
+ DRW_handle_increment(&DST.resource_handle);
}
/* It also stores viewport variable to an immutable place: DST
@@ -635,33 +635,48 @@ static void drw_viewport_var_init(void)
DST.vmempool = GPU_viewport_mempool_get(DST.viewport);
- if (DST.vmempool->calls == NULL) {
- DST.vmempool->calls = BLI_memblock_create(sizeof(DRWCall));
+ if (DST.vmempool->commands == NULL) {
+ DST.vmempool->commands = BLI_memblock_create(sizeof(DRWCommandChunk));
+ }
+ if (DST.vmempool->commands_small == NULL) {
+ DST.vmempool->commands_small = BLI_memblock_create(sizeof(DRWCommandSmallChunk));
+ }
+ if (DST.vmempool->callbuffers == NULL) {
+ DST.vmempool->callbuffers = BLI_memblock_create(sizeof(DRWCallBuffer));
+ }
+ if (DST.vmempool->obmats == NULL) {
+ uint chunk_len = sizeof(DRWObjectMatrix) * DRW_RESOURCE_CHUNK_LEN;
+ DST.vmempool->obmats = BLI_memblock_create_ex(sizeof(DRWObjectMatrix), chunk_len);
}
- if (DST.vmempool->states == NULL) {
- DST.vmempool->states = BLI_memblock_create(sizeof(DRWCallState));
+ if (DST.vmempool->obinfos == NULL) {
+ uint chunk_len = sizeof(DRWObjectInfos) * DRW_RESOURCE_CHUNK_LEN;
+ DST.vmempool->obinfos = BLI_memblock_create_ex(sizeof(DRWObjectInfos), chunk_len);
}
if (DST.vmempool->cullstates == NULL) {
- DST.vmempool->cullstates = BLI_memblock_create(sizeof(DRWCullingState));
+ uint chunk_len = sizeof(DRWCullingState) * DRW_RESOURCE_CHUNK_LEN;
+ DST.vmempool->cullstates = BLI_memblock_create_ex(sizeof(DRWCullingState), chunk_len);
}
if (DST.vmempool->shgroups == NULL) {
DST.vmempool->shgroups = BLI_memblock_create(sizeof(DRWShadingGroup));
}
if (DST.vmempool->uniforms == NULL) {
- DST.vmempool->uniforms = BLI_memblock_create(sizeof(DRWUniform));
+ DST.vmempool->uniforms = BLI_memblock_create(sizeof(DRWUniformChunk));
}
if (DST.vmempool->views == NULL) {
DST.vmempool->views = BLI_memblock_create(sizeof(DRWView));
}
if (DST.vmempool->passes == NULL) {
- DST.vmempool->passes = BLI_memblock_create(sizeof(DRWPass));
+ uint chunk_len = sizeof(DRWPass) * DRW_RESOURCE_CHUNK_LEN;
+ DST.vmempool->passes = BLI_memblock_create_ex(sizeof(DRWPass), chunk_len);
}
if (DST.vmempool->images == NULL) {
DST.vmempool->images = BLI_memblock_create(sizeof(GPUTexture *));
}
- /* Alloc default unit state */
- DST.unit_state = draw_unit_state_create();
+ DST.resource_handle = 0;
+ DST.pass_handle = 0;
+
+ draw_unit_state_create();
DST.idatalist = GPU_viewport_instance_data_list_get(DST.viewport);
DRW_instance_data_list_reset(DST.idatalist);
@@ -675,8 +690,6 @@ static void drw_viewport_var_init(void)
DST.default_framebuffer = NULL;
DST.vmempool = NULL;
-
- DST.unit_state = NULL;
}
DST.primary_view_ct = 0;
@@ -719,6 +732,10 @@ static void drw_viewport_var_init(void)
G_draw.view_ubo = DRW_uniformbuffer_create(sizeof(DRWViewUboStorage), NULL);
}
+ if (DST.draw_list == NULL) {
+ DST.draw_list = GPU_draw_list_create(DRW_DRAWLIST_LEN);
+ }
+
memset(DST.object_instance_data, 0x0, sizeof(DST.object_instance_data));
}
@@ -1023,7 +1040,7 @@ void DRW_cache_free_old_batches(Main *bmain)
for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, false);
if (depsgraph == NULL) {
continue;
}
@@ -1102,7 +1119,7 @@ static void drw_engines_world_update(Scene *scene)
static void drw_engines_cache_populate(Object *ob)
{
- DST.ob_state = NULL;
+ DST.ob_handle = 0;
/* HACK: DrawData is copied by COW from the duplicated object.
* This is valid for IDs that cannot be instantiated but this
@@ -1548,6 +1565,20 @@ void DRW_draw_view(const bContext *C)
DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, viewport, C);
}
+static bool is_object_visible_in_viewport(View3D *v3d, Object *ob)
+{
+ if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) {
+ return false;
+ }
+
+ if ((v3d->flag & V3D_LOCAL_COLLECTIONS) &&
+ ((v3d->local_collections_uuid & ob->runtime.local_collections_bits) == 0)) {
+ return false;
+ }
+
+ return true;
+}
+
/**
* Used for both regular and off-screen drawing.
* Need to reset DST before calling this function
@@ -1623,7 +1654,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
if ((object_type_exclude_viewport & (1 << ob->type)) != 0) {
continue;
}
- if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) {
+ if (!is_object_visible_in_viewport(v3d, ob)) {
continue;
}
DST.dupli_parent = data_.dupli_parent;
@@ -1766,7 +1797,9 @@ void DRW_draw_render_loop(struct Depsgraph *depsgraph,
DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, viewport, NULL);
}
-/* @viewport CAN be NULL, in this case we create one. */
+/**
+ * \param viewport: can be NULL, in this case we create one.
+ */
void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
RenderEngineType *engine_type,
ARegion *ar,
@@ -1904,6 +1937,8 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph
RenderResult *render_result = RE_engine_get_result(engine);
RenderLayer *render_layer = RE_GetRenderLayer(render_result, view_layer->name);
+ DST.buffer_finish_called = false;
+
DRW_render_gpencil_to_image(engine, render_layer, &render_rect);
/* Force cache to reset. */
@@ -2014,13 +2049,15 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
RE_SetActiveRenderView(render, render_view->name);
drw_view_reset();
engine_type->draw_engine->render_to_image(data, engine, render_layer, &render_rect);
+ DST.buffer_finish_called = false;
+
/* grease pencil: render result is merged in the previous render result. */
if (DRW_render_check_grease_pencil(depsgraph)) {
DRW_state_reset();
drw_view_reset();
DRW_render_gpencil_to_image(engine, render_layer, &render_rect);
+ DST.buffer_finish_called = false;
}
- DST.buffer_finish_called = false;
}
RE_engine_end_result(engine, render_result, false, false, false);
@@ -2066,7 +2103,7 @@ void DRW_render_object_iter(
if ((object_type_exclude_viewport & (1 << ob->type)) == 0) {
DST.dupli_parent = data_.dupli_parent;
DST.dupli_source = data_.dupli_object_current;
- DST.ob_state = NULL;
+ DST.ob_handle = 0;
drw_duplidata_load(DST.dupli_source);
if (!DST.dupli_source) {
@@ -2173,6 +2210,7 @@ void DRW_render_instance_buffer_finish(void)
BLI_assert(!DST.buffer_finish_called && "DRW_render_instance_buffer_finish called twice!");
DST.buffer_finish_called = true;
DRW_instance_buffer_finish(DST.idatalist);
+ drw_resource_buffer_finish(DST.vmempool);
}
/**
@@ -2196,7 +2234,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
Object *obact = OBACT(view_layer);
Object *obedit = OBEDIT_FROM_OBACT(obact);
#ifndef USE_GPU_SELECT
- UNUSED_VARS(vc, scene, view_layer, v3d, ar, rect);
+ UNUSED_VARS(scene, view_layer, v3d, ar, rect);
#else
RegionView3D *rv3d = ar->regiondata;
@@ -2204,24 +2242,43 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
drw_state_prepare_clean_for_draw(&DST);
bool use_obedit = false;
- int obedit_mode = 0;
+ /* obedit_ctx_mode is used for selecting the right draw engines */
+ eContextObjectMode obedit_ctx_mode;
+ /* object_mode is used for filtering objects in the depsgraph */
+ eObjectMode object_mode;
+ int object_type = 0;
if (obedit != NULL) {
+ object_type = obedit->type;
+ object_mode = obedit->mode;
if (obedit->type == OB_MBALL) {
use_obedit = true;
- obedit_mode = CTX_MODE_EDIT_METABALL;
+ obedit_ctx_mode = CTX_MODE_EDIT_METABALL;
}
else if (obedit->type == OB_ARMATURE) {
use_obedit = true;
- obedit_mode = CTX_MODE_EDIT_ARMATURE;
+ obedit_ctx_mode = CTX_MODE_EDIT_ARMATURE;
}
}
if (v3d->overlay.flag & V3D_OVERLAY_BONE_SELECT) {
if (!(v3d->flag2 & V3D_HIDE_OVERLAYS)) {
/* Note: don't use "BKE_object_pose_armature_get" here, it breaks selection. */
Object *obpose = OBPOSE_FROM_OBACT(obact);
+ if (obpose == NULL) {
+ Object *obweight = OBWEIGHTPAINT_FROM_OBACT(obact);
+ if (obweight) {
+ /* Only use Armature pose selection, when connected armature is in pose mode. */
+ Object *ob_armature = modifiers_isDeformedByArmature(obweight);
+ if (ob_armature && ob_armature->mode == OB_MODE_POSE) {
+ obpose = ob_armature;
+ }
+ }
+ }
+
if (obpose) {
use_obedit = true;
- obedit_mode = CTX_MODE_POSE;
+ object_type = obpose->type;
+ object_mode = obpose->mode;
+ obedit_ctx_mode = CTX_MODE_POSE;
}
}
}
@@ -2235,8 +2292,8 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
/* Get list of enabled engines */
if (use_obedit) {
- drw_engines_enable_from_paint_mode(obedit_mode);
- drw_engines_enable_from_mode(obedit_mode);
+ drw_engines_enable_from_paint_mode(obedit_ctx_mode);
+ drw_engines_enable_from_mode(obedit_ctx_mode);
}
else if (!draw_surface) {
/* grease pencil selection */
@@ -2283,7 +2340,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
drw_engines_world_update(scene);
if (use_obedit) {
- FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, obact->type, obact->mode, ob_iter) {
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, object_type, object_mode, ob_iter) {
drw_engines_cache_populate(ob_iter);
}
FOREACH_OBJECT_IN_MODE_END;
@@ -2293,10 +2350,9 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
v3d->object_type_exclude_select);
bool filter_exclude = false;
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob) {
- if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) {
+ if (!is_object_visible_in_viewport(v3d, ob)) {
continue;
}
-
if ((ob->base_flag & BASE_SELECTABLE) &&
(object_type_exclude_select & (1 << ob->type)) == 0) {
if (object_filter_fn != NULL) {
@@ -2386,8 +2442,38 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
/**
* object mode select-loop, see: ED_view3d_draw_depth_loop (legacy drawing).
*/
-static void drw_draw_depth_loop_imp(void)
+static void drw_draw_depth_loop_imp(struct Depsgraph *depsgraph,
+ ARegion *ar,
+ View3D *v3d,
+ GPUViewport *viewport,
+ const bool use_opengl_context)
{
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ RegionView3D *rv3d = ar->regiondata;
+
+ if (use_opengl_context) {
+ DRW_opengl_context_enable();
+ }
+
+ DST.viewport = viewport;
+ DST.options.is_depth = true;
+
+ /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */
+ DST.draw_ctx = (DRWContextState){
+ .ar = ar,
+ .rv3d = rv3d,
+ .v3d = v3d,
+ .scene = scene,
+ .view_layer = view_layer,
+ .obact = OBACT(view_layer),
+ .engine_type = engine_type,
+ .depsgraph = depsgraph,
+ };
+
+ drw_engines_data_validate();
+
/* Setup framebuffer */
DefaultFramebufferList *fbl = (DefaultFramebufferList *)GPU_viewport_framebuffer_list_get(
DST.viewport);
@@ -2409,17 +2495,14 @@ static void drw_draw_depth_loop_imp(void)
drw_engines_cache_init();
drw_engines_world_update(DST.draw_ctx.scene);
- View3D *v3d = DST.draw_ctx.v3d;
const int object_type_exclude_viewport = v3d->object_type_exclude_viewport;
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (DST.draw_ctx.depsgraph, ob) {
if ((object_type_exclude_viewport & (1 << ob->type)) != 0) {
continue;
}
-
- if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) {
+ if (!is_object_visible_in_viewport(v3d, ob)) {
continue;
}
-
DST.dupli_parent = data_.dupli_parent;
DST.dupli_source = data_.dupli_object_current;
drw_duplidata_load(DST.dupli_source);
@@ -2447,6 +2530,20 @@ static void drw_draw_depth_loop_imp(void)
/* TODO: Reading depth for operators should be done here. */
GPU_framebuffer_restore();
+
+ drw_engines_disable();
+
+ drw_viewport_cache_resize();
+
+#ifdef DEBUG
+ /* Avoid accidental reuse. */
+ drw_state_ensure_not_reused(&DST);
+#endif
+
+ /* Changin context */
+ if (use_opengl_context) {
+ DRW_opengl_context_disable();
+ }
}
/**
@@ -2458,55 +2555,18 @@ void DRW_draw_depth_loop(struct Depsgraph *depsgraph,
GPUViewport *viewport,
bool use_opengl_context)
{
- Scene *scene = DEG_get_evaluated_scene(depsgraph);
- RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
- ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
- RegionView3D *rv3d = ar->regiondata;
-
- if (use_opengl_context) {
- DRW_opengl_context_enable();
- }
-
/* Reset before using it. */
drw_state_prepare_clean_for_draw(&DST);
- DST.viewport = viewport;
- DST.options.is_depth = true;
-
- /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */
- DST.draw_ctx = (DRWContextState){
- .ar = ar,
- .rv3d = rv3d,
- .v3d = v3d,
- .scene = scene,
- .view_layer = view_layer,
- .obact = OBACT(view_layer),
- .engine_type = engine_type,
- .depsgraph = depsgraph,
- };
-
/* Get list of enabled engines */
{
drw_engines_enable_basic();
if (DRW_state_draw_support()) {
drw_engines_enable_from_object_mode();
}
- drw_engines_data_validate();
}
- drw_draw_depth_loop_imp();
-
- drw_engines_disable();
-
-#ifdef DEBUG
- /* Avoid accidental reuse. */
- drw_state_ensure_not_reused(&DST);
-#endif
-
- /* Changin context */
- if (use_opengl_context) {
- DRW_opengl_context_disable();
- }
+ drw_draw_depth_loop_imp(depsgraph, ar, v3d, viewport, use_opengl_context);
}
/**
@@ -2517,43 +2577,12 @@ void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph,
View3D *v3d,
GPUViewport *viewport)
{
- Scene *scene = DEG_get_evaluated_scene(depsgraph);
- ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
- RegionView3D *rv3d = ar->regiondata;
-
- DRW_opengl_context_enable();
-
/* Reset before using it. */
drw_state_prepare_clean_for_draw(&DST);
- DST.viewport = viewport;
- DST.options.is_depth = true;
-
- /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */
- DST.draw_ctx = (DRWContextState){
- .ar = ar,
- .rv3d = rv3d,
- .v3d = v3d,
- .scene = scene,
- .view_layer = view_layer,
- .obact = OBACT(view_layer),
- .depsgraph = depsgraph,
- };
-
use_drw_engine(&draw_engine_gpencil_type);
- drw_engines_data_validate();
-
- drw_draw_depth_loop_imp();
-
- drw_engines_disable();
-
-#ifdef DEBUG
- /* Avoid accidental reuse. */
- drw_state_ensure_not_reused(&DST);
-#endif
- /* Changin context */
- DRW_opengl_context_disable();
+ drw_draw_depth_loop_imp(depsgraph, ar, v3d, viewport, true);
}
void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *ar, View3D *v3d, const rcti *rect)
@@ -2601,7 +2630,13 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *ar, View3D *v3d, const rc
drw_engines_cache_finish();
+#if 0 /* This is a workaround to a nasty bug that seems to be a nasty driver bug. (See T69377) */
DRW_render_instance_buffer_finish();
+#else
+ DST.buffer_finish_called = true;
+ // DRW_instance_buffer_finish(DST.idatalist);
+ drw_resource_buffer_finish(DST.vmempool);
+#endif
}
/* Start Drawing */
@@ -2905,6 +2940,10 @@ void DRW_engines_free(void)
MEM_SAFE_FREE(DST.uniform_names.buffer);
+ if (DST.draw_list) {
+ GPU_draw_list_discard(DST.draw_list);
+ }
+
DRW_opengl_context_disable();
}
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 85f6cf05e83..709116c78e5 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -28,8 +28,10 @@
#include "DRW_engine.h"
#include "DRW_render.h"
+#include "BLI_assert.h"
#include "BLI_linklist.h"
#include "BLI_threads.h"
+#include "BLI_memblock.h"
#include "GPU_batch.h"
#include "GPU_context.h"
@@ -43,6 +45,9 @@
/* Use draw manager to call GPU_select, see: DRW_draw_select_loop */
#define USE_GPU_SELECT
+/* Use drawcall batching using instanced rendering. */
+#define USE_BATCHING 1
+
// #define DRW_DEBUG_CULLING
#define DRW_DEBUG_USE_UNIFORM_NAME 0
#define DRW_UNIFORM_BUFFER_NAME 64
@@ -90,20 +95,6 @@
* > DRWUniform
*/
-/* Used by DRWCallState.flag */
-enum {
- DRW_CALL_NEGSCALE = (1 << 1),
-};
-
-/* Used by DRWCallState.matflag */
-enum {
- DRW_CALL_MODELINVERSE = (1 << 0),
- DRW_CALL_MODELVIEWPROJECTION = (1 << 1),
- DRW_CALL_ORCOTEXFAC = (1 << 2),
- DRW_CALL_OBJECTINFO = (1 << 3),
- DRW_CALL_OBJECTCOLOR = (1 << 4),
-};
-
typedef struct DRWCullingState {
uint32_t mask;
/* Culling: Using Bounding Sphere for now for faster culling.
@@ -113,38 +104,161 @@ typedef struct DRWCullingState {
void *user_data;
} DRWCullingState;
-typedef struct DRWCallState {
- DRWCullingState *culling;
- uchar flag;
- uchar matflag; /* Which matrices to compute. */
- short ob_index;
- /* Matrices */
+/* Minimum max UBO size is 64KiB. We take the largest
+ * UBO struct and alloc the max number.
+ * ((1 << 16) / sizeof(DRWObjectMatrix)) = 512
+ * Keep in sync with common_view_lib.glsl */
+#define DRW_RESOURCE_CHUNK_LEN 512
+
+/**
+ * Identifier used to sort similar drawcalls together.
+ * Also used to reference elements inside memory blocks.
+ *
+ * From MSB to LSB
+ * 1 bit for negative scale.
+ * 22 bits for chunk id.
+ * 9 bits for resource id inside the chunk. (can go up to 511)
+ * |-|----------------------|---------|
+ *
+ * Use manual bit-shift and mask instead of bit-fields to avoid
+ * compiler dependent behavior that would mess the ordering of
+ * the members thus changing the sorting order.
+ */
+typedef uint32_t DRWResourceHandle;
+
+BLI_INLINE uint32_t DRW_handle_negative_scale_get(const DRWResourceHandle *handle)
+{
+ return (*handle & 0x80000000) != 0;
+}
+
+BLI_INLINE uint32_t DRW_handle_chunk_get(const DRWResourceHandle *handle)
+{
+ return (*handle & 0x7FFFFFFF) >> 9;
+}
+
+BLI_INLINE uint32_t DRW_handle_id_get(const DRWResourceHandle *handle)
+{
+ return (*handle & 0x000001FF);
+}
+
+BLI_INLINE void DRW_handle_increment(DRWResourceHandle *handle)
+{
+ *handle += 1;
+}
+
+BLI_INLINE void DRW_handle_negative_scale_enable(DRWResourceHandle *handle)
+{
+ *handle |= 0x80000000;
+}
+
+BLI_INLINE void *DRW_memblock_elem_from_handle(struct BLI_memblock *memblock,
+ const DRWResourceHandle *handle)
+{
+ int elem = DRW_handle_id_get(handle);
+ int chunk = DRW_handle_chunk_get(handle);
+ return BLI_memblock_elem_get(memblock, chunk, elem);
+}
+
+typedef struct DRWObjectMatrix {
float model[4][4];
float modelinverse[4][4];
- float orcotexfac[2][3];
- float ob_random;
+} DRWObjectMatrix;
+
+typedef struct DRWObjectInfos {
+ float orcotexfac[2][4];
float ob_color[4];
-} DRWCallState;
+ float ob_index;
+ float pad; /* UNUSED*/
+ float ob_random;
+ float ob_neg_scale;
+} DRWObjectInfos;
+
+BLI_STATIC_ASSERT_ALIGN(DRWObjectMatrix, 16)
+BLI_STATIC_ASSERT_ALIGN(DRWObjectInfos, 16)
-typedef struct DRWCall {
- struct DRWCall *next;
- DRWCallState *state;
+typedef enum {
+ /* Draw Commands */
+ DRW_CMD_DRAW = 0, /* Only sortable type. Must be 0. */
+ DRW_CMD_DRAW_RANGE = 1,
+ DRW_CMD_DRAW_INSTANCE = 2,
+ DRW_CMD_DRAW_PROCEDURAL = 3,
+ /* Other Commands */
+ DRW_CMD_CLEAR = 12,
+ DRW_CMD_DRWSTATE = 13,
+ DRW_CMD_STENCIL = 14,
+ DRW_CMD_SELECTID = 15,
+ /* Needs to fit in 4bits */
+} eDRWCommandType;
+
+#define DRW_MAX_DRAW_CMD_TYPE DRW_CMD_DRAW_PROCEDURAL
+
+typedef struct DRWCommandDraw {
+ GPUBatch *batch;
+ DRWResourceHandle handle;
+} DRWCommandDraw;
+/* Assume DRWResourceHandle to be 0. */
+typedef struct DRWCommandDrawRange {
GPUBatch *batch;
uint vert_first;
uint vert_count;
+} DRWCommandDrawRange;
+
+typedef struct DRWCommandDrawInstance {
+ GPUBatch *batch;
+ DRWResourceHandle handle;
uint inst_count;
+} DRWCommandDrawInstance;
-#ifdef USE_GPU_SELECT
- /* TODO(fclem) remove once we have a dedicated selection engine. */
- int select_id;
- GPUVertBuf *inst_selectid;
-#endif
-} DRWCall;
+typedef struct DRWCommandDrawProcedural {
+ GPUBatch *batch;
+ DRWResourceHandle handle;
+ uint vert_count;
+} DRWCommandDrawProcedural;
+
+typedef struct DRWCommandSetMutableState {
+ /** State changes (or'd or and'd with the pass's state) */
+ DRWState enable;
+ DRWState disable;
+} DRWCommandSetMutableState;
+
+typedef struct DRWCommandSetStencil {
+ uint mask;
+} DRWCommandSetStencil;
+
+typedef struct DRWCommandSetSelectID {
+ GPUVertBuf *select_buf;
+ uint select_id;
+} DRWCommandSetSelectID;
+
+typedef struct DRWCommandClear {
+ eGPUFrameBufferBits clear_channels;
+ uchar r, g, b, a; /* [0..1] for each channels. Normalized. */
+ float depth; /* [0..1] for depth. Normalized. */
+ uchar stencil; /* Stencil value [0..255] */
+} DRWCommandClear;
+
+typedef union DRWCommand {
+ DRWCommandDraw draw;
+ DRWCommandDrawRange range;
+ DRWCommandDrawInstance instance;
+ DRWCommandDrawProcedural procedural;
+ DRWCommandSetMutableState state;
+ DRWCommandSetStencil stencil;
+ DRWCommandSetSelectID select_id;
+ DRWCommandClear clear;
+} DRWCommand;
+
+/* Used for agregating calls into GPUVertBufs. */
+struct DRWCallBuffer {
+ GPUVertBuf *buf;
+ GPUVertBuf *buf_select;
+ int count;
+};
/* Used by DRWUniform.type */
typedef enum {
- DRW_UNIFORM_INT,
+ DRW_UNIFORM_INT = 0,
DRW_UNIFORM_INT_COPY,
DRW_UNIFORM_FLOAT,
DRW_UNIFORM_FLOAT_COPY,
@@ -153,55 +267,56 @@ typedef enum {
DRW_UNIFORM_TEXTURE_REF,
DRW_UNIFORM_BLOCK,
DRW_UNIFORM_BLOCK_PERSIST,
+ DRW_UNIFORM_TFEEDBACK_TARGET,
+ /** Per drawcall uniforms/UBO */
+ DRW_UNIFORM_BLOCK_OBMATS,
+ DRW_UNIFORM_BLOCK_OBINFOS,
+ DRW_UNIFORM_RESOURCE_CHUNK,
+ /** Legacy / Fallback */
+ DRW_UNIFORM_BASE_INSTANCE,
+ DRW_UNIFORM_MODEL_MATRIX,
+ DRW_UNIFORM_MODEL_MATRIX_INVERSE,
+ DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX,
+ /* WARNING: set DRWUniform->type
+ * bit length accordingly. */
} DRWUniformType;
struct DRWUniform {
- DRWUniform *next; /* single-linked list */
union {
/* For reference or array/vector types. */
const void *pvalue;
/* Single values. */
- float fvalue[2];
- int ivalue[2];
+ float fvalue[4];
+ int ivalue[4];
};
- int name_ofs; /* name offset in name buffer. */
int location;
- char type; /* DRWUniformType */
- char length; /* cannot be more than 16 */
- char arraysize; /* cannot be more than 16 too */
+ uint32_t type : 5; /* DRWUniformType */
+ uint32_t length : 5; /* cannot be more than 16 */
+ uint32_t arraysize : 5; /* cannot be more than 16 too */
+ uint32_t name_ofs : 17; /* name offset in name buffer. */
};
struct DRWShadingGroup {
DRWShadingGroup *next;
- GPUShader *shader; /* Shader to bind */
- DRWUniform *uniforms; /* Uniforms pointers */
+ GPUShader *shader; /* Shader to bind */
+ struct DRWUniformChunk *uniforms; /* Uniforms pointers */
struct {
- DRWCall *first, *last; /* Linked list of DRWCall */
- } calls;
+ /* Chunks of draw calls. */
+ struct DRWCommandChunk *first, *last;
+ } cmd;
- /** TODO Maybe remove from here */
- struct GPUVertBuf *tfeedback_target;
-
- /** State changes for this batch only (or'd with the pass's state) */
- DRWState state_extra;
- /** State changes for this batch only (and'd with the pass's state) */
- DRWState state_extra_disable;
- /** Stencil mask to use for stencil test / write operations */
- uint stencil_mask;
-
- /* Builtin matrices locations */
- int model;
- int modelinverse;
- int modelviewprojection;
- int orcotexfac;
- int callid;
- int objectinfo;
- int objectcolor;
- uchar matflag; /* Matrices needed, same as DRWCall.flag */
-
- DRWPass *pass_parent; /* backlink to pass we're in */
+ union {
+ struct {
+ int objectinfo; /* Equal to 1 if the shader needs obinfos. */
+ DRWResourceHandle pass_handle; /* Memblock key to parent pass. */
+ };
+ struct {
+ float distance; /* Distance from camera. */
+ uint original_index; /* Original position inside the shgroup list. */
+ } z_sorting;
+ };
};
#define MAX_PASS_NAME 32
@@ -213,6 +328,7 @@ struct DRWPass {
DRWShadingGroup *last;
} shgroups;
+ DRWResourceHandle handle;
DRWState state;
char name[MAX_PASS_NAME];
};
@@ -232,6 +348,8 @@ typedef struct DRWViewUboStorage {
float viewcamtexcofac[4];
} DRWViewUboStorage;
+BLI_STATIC_ASSERT_ALIGN(DRWViewUboStorage, 16)
+
#define MAX_CULLED_VIEWS 32
struct DRWView {
@@ -253,13 +371,45 @@ struct DRWView {
void *user_data;
};
-/* TODO(fclem): Future awaits */
-#if 0
-typedef struct ModelUboStorage {
- float model[4][4];
- float modelinverse[4][4];
-} ModelUboStorage;
-#endif
+/* ------------ Data Chunks --------------- */
+/**
+ * In order to keep a cache friendly data structure,
+ * we alloc most of our little data into chunks of multiple item.
+ * Iteration, allocation and memory usage are better.
+ * We loose a bit of memory by allocating more than what we need
+ * but it's counterbalanced by not needing the linked-list pointers
+ * for each item.
+ **/
+
+typedef struct DRWUniformChunk {
+ struct DRWUniformChunk *next; /* single-linked list */
+ uint32_t uniform_len;
+ uint32_t uniform_used;
+ DRWUniform uniforms[10];
+} DRWUniformChunk;
+
+typedef struct DRWCommandChunk {
+ struct DRWCommandChunk *next;
+ uint32_t command_len;
+ uint32_t command_used;
+ /* 4bits for each command. */
+ uint64_t command_type[6];
+ /* -- 64 bytes aligned -- */
+ DRWCommand commands[96];
+ /* -- 64 bytes aligned -- */
+} DRWCommandChunk;
+
+typedef struct DRWCommandSmallChunk {
+ struct DRWCommandChunk *next;
+ uint32_t command_len;
+ uint32_t command_used;
+ /* 4bits for each command. */
+ /* TODO reduce size of command_type. */
+ uint64_t command_type[6];
+ DRWCommand commands[6];
+} DRWCommandSmallChunk;
+
+BLI_STATIC_ASSERT_ALIGN(DRWCommandChunk, 16);
/* ------------- DRAW DEBUG ------------ */
@@ -280,21 +430,31 @@ typedef struct DRWDebugSphere {
#define DST_MAX_SLOTS 64 /* Cannot be changed without modifying RST.bound_tex_slots */
#define MAX_CLIP_PLANES 6 /* GL_MAX_CLIP_PLANES is at least 6 */
#define STENCIL_UNDEFINED 256
+#define DRW_DRAWLIST_LEN 256
typedef struct DRWManager {
/* TODO clean up this struct a bit */
/* Cache generation */
ViewportMemoryPool *vmempool;
DRWInstanceDataList *idatalist;
- DRWInstanceData *object_instance_data[MAX_INSTANCE_DATA_SIZE];
- /* Default Unit model matrix state without culling. */
- DRWCallState *unit_state;
/* State of the object being evaluated if already allocated. */
- DRWCallState *ob_state;
+ DRWResourceHandle ob_handle;
+ /** True if current DST.ob_state has its matching DRWObjectInfos init. */
+ bool ob_state_obinfo_init;
+ /** Handle of current object resource in object resource arrays (DRWObjectMatrices/Infos). */
+ DRWResourceHandle resource_handle;
+ /** Handle of next DRWPass to be allocated. */
+ DRWResourceHandle pass_handle;
+
+ /** Dupli state. NULL if not dupli. */
struct DupliObject *dupli_source;
struct Object *dupli_parent;
struct Object *dupli_origin;
+ /** Ghash containing original objects. */
struct GHash *dupli_ghash;
- void **dupli_datas; /* Array of dupli_data (one for each enabled engine) to handle duplis. */
+ /** TODO(fclem) try to remove usage of this. */
+ DRWInstanceData *object_instance_data[MAX_INSTANCE_DATA_SIZE];
+ /* Array of dupli_data (one for each enabled engine) to handle duplis. */
+ void **dupli_datas;
/* Rendering state */
GPUShader *shader;
@@ -357,6 +517,8 @@ typedef struct DRWManager {
/** Mutex to lock the drw manager and avoid concurrent context usage. */
TicketMutex *gl_context_mutex;
+ GPUDrawList *draw_list;
+
/** GPU Resource State: Memory storage between drawing. */
struct {
/* High end GPUs supports up to 32 binds per shader stage.
@@ -397,9 +559,13 @@ void drw_state_set(DRWState state);
void drw_debug_draw(void);
void drw_debug_init(void);
+eDRWCommandType command_type_get(uint64_t *command_type_bits, int index);
+
void drw_batch_cache_validate(Object *ob);
void drw_batch_cache_generate_requested(struct Object *ob);
+void drw_resource_buffer_finish(ViewportMemoryPool *vmempool);
+
/* Procedural Drawing */
GPUBatch *drw_cache_procedural_points_get(void);
GPUBatch *drw_cache_procedural_lines_get(void);
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index 8b7cb9c1dad..dcf526679bf 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -34,6 +34,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
+#include "BLI_alloca.h"
#include "BLI_hash.h"
#include "BLI_link_utils.h"
#include "BLI_mempool.h"
@@ -51,6 +52,36 @@
/** \name Uniform Buffer Object (DRW_uniformbuffer)
* \{ */
+static void draw_call_sort(DRWCommand *array, DRWCommand *array_tmp, int array_len)
+{
+ /* Count unique batches. Tt's not really important if
+ * there is collisions. If there is a lot of different batches,
+ * the sorting benefit will be negligible.
+ * So at least sort fast! */
+ uchar idx[128] = {0};
+ /* Shift by 6 positions knowing each GPUBatch is > 64 bytes */
+#define KEY(a) ((((size_t)((a).draw.batch)) >> 6) % ARRAY_SIZE(idx))
+ BLI_assert(array_len <= ARRAY_SIZE(idx));
+
+ for (int i = 0; i < array_len; i++) {
+ /* Early out if nothing to sort. */
+ if (++idx[KEY(array[i])] == array_len) {
+ return;
+ }
+ }
+ /* Cumulate batch indices */
+ for (int i = 1; i < ARRAY_SIZE(idx); i++) {
+ idx[i] += idx[i - 1];
+ }
+ /* Traverse in reverse to not change the order of the resource ids. */
+ for (int src = array_len - 1; src >= 0; src--) {
+ array_tmp[--idx[KEY(array[src])]] = array[src];
+ }
+#undef KEY
+
+ memcpy(array, array_tmp, sizeof(*array) * array_len);
+}
+
GPUUniformBuffer *DRW_uniformbuffer_create(int size, const void *data)
{
return GPU_uniformbuffer_create(size, data, NULL);
@@ -66,20 +97,94 @@ void DRW_uniformbuffer_free(GPUUniformBuffer *ubo)
GPU_uniformbuffer_free(ubo);
}
+void drw_resource_buffer_finish(ViewportMemoryPool *vmempool)
+{
+ int chunk_id = DRW_handle_chunk_get(&DST.resource_handle);
+ int elem_id = DRW_handle_id_get(&DST.resource_handle);
+ int ubo_len = 1 + chunk_id - ((elem_id == 0) ? 1 : 0);
+ size_t list_size = sizeof(GPUUniformBuffer *) * ubo_len;
+
+ /* TODO find a better system. currently a lot of obinfos UBO are going to be unused
+ * if not rendering with Eevee. */
+
+ if (vmempool->matrices_ubo == NULL) {
+ vmempool->matrices_ubo = MEM_callocN(list_size, __func__);
+ vmempool->obinfos_ubo = MEM_callocN(list_size, __func__);
+ vmempool->ubo_len = ubo_len;
+ }
+
+ /* Remove unecessary buffers */
+ for (int i = ubo_len; i < vmempool->ubo_len; i++) {
+ GPU_uniformbuffer_free(vmempool->matrices_ubo[i]);
+ GPU_uniformbuffer_free(vmempool->obinfos_ubo[i]);
+ }
+
+ if (ubo_len != vmempool->ubo_len) {
+ vmempool->matrices_ubo = MEM_recallocN(vmempool->matrices_ubo, list_size);
+ vmempool->obinfos_ubo = MEM_recallocN(vmempool->obinfos_ubo, list_size);
+ vmempool->ubo_len = ubo_len;
+ }
+
+ /* Create/Update buffers. */
+ for (int i = 0; i < ubo_len; i++) {
+ void *data_obmat = BLI_memblock_elem_get(vmempool->obmats, i, 0);
+ void *data_infos = BLI_memblock_elem_get(vmempool->obinfos, i, 0);
+ if (vmempool->matrices_ubo[i] == NULL) {
+ vmempool->matrices_ubo[i] = GPU_uniformbuffer_create(
+ sizeof(DRWObjectMatrix) * DRW_RESOURCE_CHUNK_LEN, data_obmat, NULL);
+ vmempool->obinfos_ubo[i] = GPU_uniformbuffer_create(
+ sizeof(DRWObjectInfos) * DRW_RESOURCE_CHUNK_LEN, data_infos, NULL);
+ }
+ else {
+ GPU_uniformbuffer_update(vmempool->matrices_ubo[i], data_obmat);
+ GPU_uniformbuffer_update(vmempool->obinfos_ubo[i], data_infos);
+ }
+ }
+
+ /* Aligned alloc to avoid unaligned memcpy. */
+ DRWCommandChunk *chunk_tmp = MEM_mallocN_aligned(sizeof(DRWCommandChunk), 16, "tmp call chunk");
+ DRWCommandChunk *chunk;
+ BLI_memblock_iter iter;
+ BLI_memblock_iternew(vmempool->commands, &iter);
+ while ((chunk = BLI_memblock_iterstep(&iter))) {
+ bool sortable = true;
+ /* We can only sort chunks that contain DRWCommandDraw only. */
+ for (int i = 0; i < ARRAY_SIZE(chunk->command_type) && sortable; i++) {
+ if (chunk->command_type[i] != 0) {
+ sortable = false;
+ }
+ }
+ if (sortable) {
+ draw_call_sort(chunk->commands, chunk_tmp->commands, chunk->command_used);
+ }
+ }
+ MEM_freeN(chunk_tmp);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Uniforms (DRW_shgroup_uniform)
* \{ */
-static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup,
- int loc,
- DRWUniformType type,
- const void *value,
- int length,
- int arraysize)
+static DRWUniform *drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup,
+ int loc,
+ DRWUniformType type,
+ const void *value,
+ int length,
+ int arraysize)
{
- DRWUniform *uni = BLI_memblock_alloc(DST.vmempool->uniforms);
+ DRWUniformChunk *unichunk = shgroup->uniforms;
+ /* Happens on first uniform or if chunk is full. */
+ if (!unichunk || unichunk->uniform_used == unichunk->uniform_len) {
+ unichunk = BLI_memblock_alloc(DST.vmempool->uniforms);
+ unichunk->uniform_len = ARRAY_SIZE(shgroup->uniforms->uniforms);
+ unichunk->uniform_used = 0;
+ BLI_LINKS_PREPEND(shgroup->uniforms, unichunk);
+ }
+
+ DRWUniform *uni = unichunk->uniforms + unichunk->uniform_used++;
+
uni->location = loc;
uni->type = type;
uni->length = length;
@@ -87,11 +192,11 @@ static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup,
switch (type) {
case DRW_UNIFORM_INT_COPY:
- BLI_assert(length <= 2);
+ BLI_assert(length <= 4);
memcpy(uni->ivalue, value, sizeof(int) * length);
break;
case DRW_UNIFORM_FLOAT_COPY:
- BLI_assert(length <= 2);
+ BLI_assert(length <= 4);
memcpy(uni->fvalue, value, sizeof(float) * length);
break;
default:
@@ -99,7 +204,7 @@ static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup,
break;
}
- BLI_LINKS_PREPEND(shgroup->uniforms, uni);
+ return uni;
}
static void drw_shgroup_builtin_uniform(
@@ -136,7 +241,8 @@ static void drw_shgroup_uniform(DRWShadingGroup *shgroup,
BLI_assert(arraysize > 0 && arraysize <= 16);
BLI_assert(length >= 0 && length <= 16);
- drw_shgroup_uniform_create_ex(shgroup, location, type, value, length, arraysize);
+ DRWUniform *uni = drw_shgroup_uniform_create_ex(
+ shgroup, location, type, value, length, arraysize);
/* If location is -2, the uniform has not yet been queried.
* We save the name for query just before drawing. */
@@ -155,7 +261,7 @@ static void drw_shgroup_uniform(DRWShadingGroup *shgroup,
memcpy(dst, name, len); /* Copies NULL terminator. */
DST.uniform_names.buffer_ofs += len;
- shgroup->uniforms->name_ofs = ofs;
+ uni->name_ofs = ofs;
}
}
@@ -286,6 +392,21 @@ void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, co
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, &value, 1, 1);
}
+void DRW_shgroup_uniform_ivec2_copy(DRWShadingGroup *shgroup, const char *name, const int *value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, value, 2, 1);
+}
+
+void DRW_shgroup_uniform_ivec3_copy(DRWShadingGroup *shgroup, const char *name, const int *value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, value, 3, 1);
+}
+
+void DRW_shgroup_uniform_ivec4_copy(DRWShadingGroup *shgroup, const char *name, const int *value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, value, 4, 1);
+}
+
void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value)
{
int ival = value;
@@ -302,13 +423,23 @@ void DRW_shgroup_uniform_vec2_copy(DRWShadingGroup *shgroup, const char *name, c
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, value, 2, 1);
}
+void DRW_shgroup_uniform_vec3_copy(DRWShadingGroup *shgroup, const char *name, const float *value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, value, 3, 1);
+}
+
+void DRW_shgroup_uniform_vec4_copy(DRWShadingGroup *shgroup, const char *name, const float *value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, value, 4, 1);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Draw Call (DRW_calls)
* \{ */
-static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[3])
+static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[4])
{
ID *ob_data = (ob) ? ob->data : NULL;
float *texcoloc = NULL;
@@ -316,13 +447,11 @@ static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[3])
if (ob_data != NULL) {
switch (GS(ob_data->name)) {
case ID_ME:
- BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize);
+ BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, &texcosize);
break;
case ID_CU: {
Curve *cu = (Curve *)ob_data;
- if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_curve_texspace_calc(cu);
- }
+ BKE_curve_texspace_ensure(cu);
texcoloc = cu->loc;
texcosize = cu->size;
break;
@@ -351,159 +480,283 @@ static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[3])
}
}
-static void drw_call_state_update_matflag(DRWCallState *state,
- DRWShadingGroup *shgroup,
- Object *ob)
+BLI_INLINE void drw_call_matrix_init(DRWObjectMatrix *ob_mats, Object *ob, float (*obmat)[4])
{
- uchar new_flags = ((state->matflag ^ shgroup->matflag) & shgroup->matflag);
-
- /* HACK: Here we set the matflags bit to 1 when computing the value
- * so that it's not recomputed for other drawcalls.
- * This is the opposite of what draw_matrices_model_prepare() does. */
- state->matflag |= shgroup->matflag;
-
- if (new_flags & DRW_CALL_MODELINVERSE) {
- if (ob) {
- copy_m4_m4(state->modelinverse, ob->imat);
- }
- else {
- invert_m4_m4(state->modelinverse, state->model);
- }
+ copy_m4_m4(ob_mats->model, obmat);
+ if (ob) {
+ copy_m4_m4(ob_mats->modelinverse, ob->imat);
}
-
- /* Orco factors: We compute this at creation to not have to save the *ob_data */
- if (new_flags & DRW_CALL_ORCOTEXFAC) {
- drw_call_calc_orco(ob, state->orcotexfac);
- }
-
- if (new_flags & DRW_CALL_OBJECTINFO) {
- state->ob_index = ob ? ob->index : 0;
- uint random;
- if (DST.dupli_source) {
- random = DST.dupli_source->random_id;
- }
- else {
- random = BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
- }
- state->ob_random = random * (1.0f / (float)0xFFFFFFFF);
- }
-
- if (new_flags & DRW_CALL_OBJECTCOLOR) {
- copy_v4_v4(state->ob_color, ob->color);
+ else {
+ /* WATCH: Can be costly. */
+ invert_m4_m4(ob_mats->modelinverse, ob_mats->model);
}
}
-static DRWCallState *drw_call_state_create(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob)
+static void drw_call_obinfos_init(DRWObjectInfos *ob_infos, Object *ob)
{
- DRWCallState *state = BLI_memblock_alloc(DST.vmempool->states);
- state->flag = 0;
- state->matflag = 0;
-
- /* Matrices */
- copy_m4_m4(state->model, obmat);
-
- if (ob && (ob->transflag & OB_NEG_SCALE)) {
- state->flag |= DRW_CALL_NEGSCALE;
- }
-
- drw_call_state_update_matflag(state, shgroup, ob);
-
- DRWCullingState *cull = BLI_memblock_alloc(DST.vmempool->cullstates);
- state->culling = cull;
+ BLI_assert(ob);
+ /* Index. */
+ ob_infos->ob_index = ob->index;
+ /* Orco factors. */
+ drw_call_calc_orco(ob, ob_infos->orcotexfac);
+ /* Random float value. */
+ uint random = (DST.dupli_source) ?
+ DST.dupli_source->random_id :
+ /* TODO(fclem) this is rather costly to do at runtime. Maybe we can
+ * put it in ob->runtime and make depsgraph ensure it is up to date. */
+ BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
+ ob_infos->ob_random = random * (1.0f / (float)0xFFFFFFFF);
+ /* Negative scalling. */
+ ob_infos->ob_neg_scale = (ob->transflag & OB_NEG_SCALE) ? -1.0f : 1.0f;
+ /* Object Color. */
+ copy_v4_v4(ob_infos->ob_color, ob->color);
+}
+static void drw_call_culling_init(DRWCullingState *cull, Object *ob)
+{
BoundBox *bbox;
if (ob != NULL && (bbox = BKE_object_boundbox_get(ob))) {
float corner[3];
/* Get BoundSphere center and radius from the BoundBox. */
mid_v3_v3v3(cull->bsphere.center, bbox->vec[0], bbox->vec[6]);
- mul_v3_m4v3(corner, obmat, bbox->vec[0]);
- mul_m4_v3(obmat, cull->bsphere.center);
+ mul_v3_m4v3(corner, ob->obmat, bbox->vec[0]);
+ mul_m4_v3(ob->obmat, cull->bsphere.center);
cull->bsphere.radius = len_v3v3(cull->bsphere.center, corner);
}
else {
- /* TODO(fclem) Bypass alloc if we can (see if eevee's
- * probe visibility collection still works). */
/* Bypass test. */
cull->bsphere.radius = -1.0f;
}
+ /* Reset user data */
+ cull->user_data = NULL;
+}
+
+static DRWResourceHandle drw_resource_handle_new(float (*obmat)[4], Object *ob)
+{
+ DRWCullingState *culling = BLI_memblock_alloc(DST.vmempool->cullstates);
+ DRWObjectMatrix *ob_mats = BLI_memblock_alloc(DST.vmempool->obmats);
+ /* FIXME Meh, not always needed but can be accessed after creation.
+ * Also it needs to have the same resource handle. */
+ DRWObjectInfos *ob_infos = BLI_memblock_alloc(DST.vmempool->obinfos);
+ UNUSED_VARS(ob_infos);
+
+ DRWResourceHandle handle = DST.resource_handle;
+ DRW_handle_increment(&DST.resource_handle);
+
+ if (ob && (ob->transflag & OB_NEG_SCALE)) {
+ DRW_handle_negative_scale_enable(&handle);
+ }
+
+ drw_call_matrix_init(ob_mats, ob, obmat);
+ drw_call_culling_init(culling, ob);
+ /* ob_infos is init only if needed. */
- return state;
+ return handle;
}
-static DRWCallState *drw_call_state_object(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob)
+static DRWResourceHandle drw_resource_handle(DRWShadingGroup *shgroup,
+ float (*obmat)[4],
+ Object *ob)
{
if (ob == NULL) {
if (obmat == NULL) {
- BLI_assert(DST.unit_state);
- return DST.unit_state;
+ DRWResourceHandle handle = 0;
+ return handle;
}
else {
- return drw_call_state_create(shgroup, obmat, ob);
+ return drw_resource_handle_new(obmat, NULL);
}
}
else {
- if (DST.ob_state == NULL) {
- DST.ob_state = drw_call_state_create(shgroup, obmat, ob);
+ if (DST.ob_handle == 0) {
+ DST.ob_handle = drw_resource_handle_new(obmat, ob);
+ DST.ob_state_obinfo_init = false;
}
- else {
- /* If the DRWCallState is reused, add necessary matrices. */
- drw_call_state_update_matflag(DST.ob_state, shgroup, ob);
+
+ if (shgroup->objectinfo) {
+ if (!DST.ob_state_obinfo_init) {
+ DST.ob_state_obinfo_init = true;
+ DRWObjectInfos *ob_infos = DRW_memblock_elem_from_handle(DST.vmempool->obinfos,
+ &DST.ob_handle);
+
+ drw_call_obinfos_init(ob_infos, ob);
+ }
}
- return DST.ob_state;
+ return DST.ob_handle;
}
}
+static void command_type_set(uint64_t *command_type_bits, int index, eDRWCommandType type)
+{
+ command_type_bits[index / 16] |= ((uint64_t)type) << ((index % 16) * 4);
+}
+
+eDRWCommandType command_type_get(uint64_t *command_type_bits, int index)
+{
+ return ((command_type_bits[index / 16] >> ((index % 16) * 4)) & 0xF);
+}
+
+static void *drw_command_create(DRWShadingGroup *shgroup, eDRWCommandType type)
+{
+ DRWCommandChunk *chunk = shgroup->cmd.last;
+
+ if (chunk == NULL) {
+ DRWCommandSmallChunk *smallchunk = BLI_memblock_alloc(DST.vmempool->commands_small);
+ smallchunk->command_len = ARRAY_SIZE(smallchunk->commands);
+ smallchunk->command_used = 0;
+ smallchunk->command_type[0] = 0x0lu;
+ chunk = (DRWCommandChunk *)smallchunk;
+ BLI_LINKS_APPEND(&shgroup->cmd, chunk);
+ }
+ else if (chunk->command_used == chunk->command_len) {
+ chunk = BLI_memblock_alloc(DST.vmempool->commands);
+ chunk->command_len = ARRAY_SIZE(chunk->commands);
+ chunk->command_used = 0;
+ memset(chunk->command_type, 0x0, sizeof(chunk->command_type));
+ BLI_LINKS_APPEND(&shgroup->cmd, chunk);
+ }
+
+ command_type_set(chunk->command_type, chunk->command_used, type);
+
+ return chunk->commands + chunk->command_used++;
+}
+
+static void drw_command_draw(DRWShadingGroup *shgroup, GPUBatch *batch, DRWResourceHandle handle)
+{
+ DRWCommandDraw *cmd = drw_command_create(shgroup, DRW_CMD_DRAW);
+ cmd->batch = batch;
+ cmd->handle = handle;
+}
+
+static void drw_command_draw_range(DRWShadingGroup *shgroup,
+ GPUBatch *batch,
+ uint start,
+ uint count)
+{
+ DRWCommandDrawRange *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_RANGE);
+ cmd->batch = batch;
+ cmd->vert_first = start;
+ cmd->vert_count = count;
+}
+
+static void drw_command_draw_instance(DRWShadingGroup *shgroup,
+ GPUBatch *batch,
+ DRWResourceHandle handle,
+ uint count)
+{
+ DRWCommandDrawInstance *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_INSTANCE);
+ cmd->batch = batch;
+ cmd->handle = handle;
+ cmd->inst_count = count;
+}
+
+static void drw_command_draw_procedural(DRWShadingGroup *shgroup,
+ GPUBatch *batch,
+ DRWResourceHandle handle,
+ uint vert_count)
+{
+ DRWCommandDrawProcedural *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_PROCEDURAL);
+ cmd->batch = batch;
+ cmd->handle = handle;
+ cmd->vert_count = vert_count;
+}
+
+static void drw_command_set_select_id(DRWShadingGroup *shgroup, GPUVertBuf *buf, uint select_id)
+{
+ /* Only one can be valid. */
+ BLI_assert(buf == NULL || select_id == -1);
+ DRWCommandSetSelectID *cmd = drw_command_create(shgroup, DRW_CMD_SELECTID);
+ cmd->select_buf = buf;
+ cmd->select_id = select_id;
+}
+
+static void drw_command_set_stencil_mask(DRWShadingGroup *shgroup, uint mask)
+{
+ BLI_assert(mask <= 0xFF);
+ DRWCommandSetStencil *cmd = drw_command_create(shgroup, DRW_CMD_STENCIL);
+ cmd->mask = mask;
+}
+
+static void drw_command_clear(DRWShadingGroup *shgroup,
+ eGPUFrameBufferBits channels,
+ uchar r,
+ uchar g,
+ uchar b,
+ uchar a,
+ float depth,
+ uchar stencil)
+{
+ DRWCommandClear *cmd = drw_command_create(shgroup, DRW_CMD_CLEAR);
+ cmd->clear_channels = channels;
+ cmd->r = r;
+ cmd->g = g;
+ cmd->b = b;
+ cmd->a = a;
+ cmd->depth = depth;
+ cmd->stencil = stencil;
+}
+
+static void drw_command_set_mutable_state(DRWShadingGroup *shgroup,
+ DRWState enable,
+ DRWState disable)
+{
+ /* TODO Restrict what state can be changed. */
+ DRWCommandSetMutableState *cmd = drw_command_create(shgroup, DRW_CMD_DRWSTATE);
+ cmd->enable = enable;
+ cmd->disable = disable;
+}
+
void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
Object *ob,
float (*obmat)[4],
struct GPUBatch *geom,
- uint v_sta,
- uint v_ct,
bool bypass_culling,
void *user_data)
{
BLI_assert(geom != NULL);
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : obmat, ob);
+ drw_command_draw(shgroup, geom, handle);
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
-
- call->state = drw_call_state_object(shgroup, ob ? ob->obmat : obmat, ob);
- call->batch = geom;
- call->vert_first = v_sta;
- call->vert_count = v_ct; /* 0 means auto from batch. */
- call->inst_count = 0;
-#ifdef USE_GPU_SELECT
- call->select_id = DST.select_id;
- call->inst_selectid = NULL;
-#endif
- if (call->state->culling) {
- call->state->culling->user_data = user_data;
+ /* Culling data. */
+ if (user_data || bypass_culling) {
+ DRWCullingState *culling = DRW_memblock_elem_from_handle(DST.vmempool->cullstates,
+ &DST.ob_handle);
+
+ if (user_data) {
+ culling->user_data = user_data;
+ }
if (bypass_culling) {
/* NOTE this will disable culling for the whole object. */
- call->state->culling->bsphere.radius = -1.0f;
+ culling->bsphere.radius = -1.0f;
}
}
}
+void DRW_shgroup_call_range(DRWShadingGroup *shgroup, struct GPUBatch *geom, uint v_sta, uint v_ct)
+{
+ BLI_assert(geom != NULL);
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ drw_command_draw_range(shgroup, geom, v_sta, v_ct);
+}
+
static void drw_shgroup_call_procedural_add_ex(DRWShadingGroup *shgroup,
GPUBatch *geom,
Object *ob,
uint vert_count)
{
-
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
-
- call->state = drw_call_state_object(shgroup, ob ? ob->obmat : NULL, ob);
- call->batch = geom;
- call->vert_first = 0;
- call->vert_count = vert_count;
- call->inst_count = 0;
-#ifdef USE_GPU_SELECT
- call->select_id = DST.select_id;
- call->inst_selectid = NULL;
-#endif
+ BLI_assert(vert_count > 0);
+ BLI_assert(geom != NULL);
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob);
+ drw_command_draw_procedural(shgroup, geom, handle, vert_count);
}
void DRW_shgroup_call_procedural_points(DRWShadingGroup *shgroup, Object *ob, uint point_len)
@@ -524,25 +777,18 @@ void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *shgroup, Object *ob,
drw_shgroup_call_procedural_add_ex(shgroup, geom, ob, tria_count * 3);
}
+/* Should be removed */
void DRW_shgroup_call_instances(DRWShadingGroup *shgroup,
Object *ob,
struct GPUBatch *geom,
uint count)
{
BLI_assert(geom != NULL);
-
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
-
- call->state = drw_call_state_object(shgroup, ob ? ob->obmat : NULL, ob);
- call->batch = geom;
- call->vert_first = 0;
- call->vert_count = 0; /* Auto from batch. */
- call->inst_count = count;
-#ifdef USE_GPU_SELECT
- call->select_id = DST.select_id;
- call->inst_selectid = NULL;
-#endif
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob);
+ drw_command_draw_instance(shgroup, geom, handle, count);
}
void DRW_shgroup_call_instances_with_attribs(DRWShadingGroup *shgroup,
@@ -552,25 +798,16 @@ void DRW_shgroup_call_instances_with_attribs(DRWShadingGroup *shgroup,
{
BLI_assert(geom != NULL);
BLI_assert(inst_attributes->verts[0] != NULL);
-
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob);
GPUVertBuf *buf_inst = inst_attributes->verts[0];
-
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
-
- call->state = drw_call_state_object(shgroup, ob ? ob->obmat : NULL, ob);
- call->batch = DRW_temp_batch_instance_request(DST.idatalist, buf_inst, geom);
- call->vert_first = 0;
- call->vert_count = 0; /* Auto from batch. */
- call->inst_count = buf_inst->vertex_len;
-#ifdef USE_GPU_SELECT
- call->select_id = DST.select_id;
- call->inst_selectid = NULL;
-#endif
+ GPUBatch *batch = DRW_temp_batch_instance_request(DST.idatalist, buf_inst, geom);
+ drw_command_draw(shgroup, batch, handle);
}
-// #define SCULPT_DEBUG_BUFFERS
-
+#define SCULPT_DEBUG_BUFFERS (G.debug_value == 889)
typedef struct DRWSculptCallbackData {
Object *ob;
DRWShadingGroup **shading_groups;
@@ -578,13 +815,11 @@ typedef struct DRWSculptCallbackData {
bool use_mats;
bool use_mask;
bool fast_mode; /* Set by draw manager. Do not init. */
-#ifdef SCULPT_DEBUG_BUFFERS
- int node_nr;
-#endif
+
+ int debug_node_nr;
} DRWSculptCallbackData;
-#ifdef SCULPT_DEBUG_BUFFERS
-# define SCULPT_DEBUG_COLOR(id) (sculpt_debug_colors[id % 9])
+#define SCULPT_DEBUG_COLOR(id) (sculpt_debug_colors[id % 9])
static float sculpt_debug_colors[9][4] = {
{1.0f, 0.2f, 0.2f, 1.0f},
{0.2f, 1.0f, 0.2f, 1.0f},
@@ -596,59 +831,72 @@ static float sculpt_debug_colors[9][4] = {
{0.2f, 1.0f, 0.7f, 1.0f},
{0.7f, 0.2f, 1.0f, 1.0f},
};
-#endif
static void sculpt_draw_cb(DRWSculptCallbackData *scd, GPU_PBVH_Buffers *buffers)
{
- GPUBatch *geom = GPU_pbvh_buffers_batch_get(buffers, scd->fast_mode, scd->use_wire);
- short index = 0;
-
/* Meh... use_mask is a bit misleading here. */
if (scd->use_mask && !GPU_pbvh_buffers_has_mask(buffers)) {
return;
}
+ GPUBatch *geom = GPU_pbvh_buffers_batch_get(buffers, scd->fast_mode, scd->use_wire);
+ short index = 0;
+
if (scd->use_mats) {
index = GPU_pbvh_buffers_material_index_get(buffers);
}
DRWShadingGroup *shgrp = scd->shading_groups[index];
if (geom != NULL && shgrp != NULL) {
-#ifdef SCULPT_DEBUG_BUFFERS
- /* Color each buffers in different colors. Only work in solid/Xray mode. */
- shgrp = DRW_shgroup_create_sub(shgrp);
- DRW_shgroup_uniform_vec3(shgrp, "materialDiffuseColor", SCULPT_DEBUG_COLOR(scd->node_nr++), 1);
-#endif
+ if (SCULPT_DEBUG_BUFFERS) {
+ /* Color each buffers in different colors. Only work in solid/Xray mode. */
+ shgrp = DRW_shgroup_create_sub(shgrp);
+ DRW_shgroup_uniform_vec3(
+ shgrp, "materialDiffuseColor", SCULPT_DEBUG_COLOR(scd->debug_node_nr++), 1);
+ }
/* DRW_shgroup_call_no_cull reuses matrices calculations for all the drawcalls of this
* object. */
DRW_shgroup_call_no_cull(shgrp, geom, scd->ob);
}
}
-#ifdef SCULPT_DEBUG_BUFFERS
static void sculpt_debug_cb(void *user_data,
const float bmin[3],
const float bmax[3],
PBVHNodeFlags flag)
{
- int *node_nr = (int *)user_data;
+ int *debug_node_nr = (int *)user_data;
BoundBox bb;
BKE_boundbox_init_from_minmax(&bb, bmin, bmax);
-# if 0 /* Nodes hierarchy. */
+#if 0 /* Nodes hierarchy. */
if (flag & PBVH_Leaf) {
DRW_debug_bbox(&bb, (float[4]){0.0f, 1.0f, 0.0f, 1.0f});
}
else {
DRW_debug_bbox(&bb, (float[4]){0.5f, 0.5f, 0.5f, 0.6f});
}
-# else /* Color coded leaf bounds. */
+#else /* Color coded leaf bounds. */
if (flag & PBVH_Leaf) {
- DRW_debug_bbox(&bb, SCULPT_DEBUG_COLOR((*node_nr)++));
+ DRW_debug_bbox(&bb, SCULPT_DEBUG_COLOR((*debug_node_nr)++));
}
-# endif
-}
#endif
+}
+
+static void drw_sculpt_get_frustum_planes(Object *ob, float planes[6][4])
+{
+ /* TODO: take into account partial redraw for clipping planes. */
+ DRW_view_frustum_planes_get(DRW_view_default_get(), planes);
+
+ /* Transform clipping planes to object space. Transforming a plane with a
+ * 4x4 matrix is done by multiplying with the transpose inverse.
+ * The inverse cancels out here since we transform by inverse(obmat). */
+ float tmat[4][4];
+ transpose_m4_m4(tmat, ob->obmat);
+ for (int i = 0; i < 6; i++) {
+ mul_m4_v4(tmat, planes[i]);
+ }
+}
static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd, bool use_vcol)
{
@@ -658,31 +906,46 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd, bool use_vcol)
return;
}
- float(*planes)[4] = NULL; /* TODO proper culling. */
- scd->fast_mode = false;
-
const DRWContextState *drwctx = DRW_context_state_get();
+ RegionView3D *rv3d = drwctx->rv3d;
+
+ /* Frustum planes to show only visible PBVH nodes. */
+ float planes[6][4];
+ drw_sculpt_get_frustum_planes(scd->ob, planes);
+ PBVHFrustumPlanes frustum = {.planes = planes, .num_planes = 6};
+
+ /* Fast mode to show low poly multires while navigating. */
+ scd->fast_mode = false;
if (drwctx->evil_C != NULL) {
Paint *p = BKE_paint_get_active_from_context(drwctx->evil_C);
if (p && (p->flags & PAINT_FAST_NAVIGATE)) {
- scd->fast_mode = (drwctx->rv3d->rflag & RV3D_NAVIGATING) != 0;
+ scd->fast_mode = rv3d && (rv3d->rflag & RV3D_NAVIGATING);
}
}
+ /* Update draw buffers only for visible nodes while painting.
+ * But do update them otherwise so navigating stays smooth. */
+ const bool update_only_visible = rv3d && (rv3d->rflag & RV3D_PAINTING);
+
Mesh *mesh = scd->ob->data;
BKE_pbvh_update_normals(pbvh, mesh->runtime.subdiv_ccg);
- BKE_pbvh_update_draw_buffers(pbvh, use_vcol);
- BKE_pbvh_draw_cb(pbvh, planes, (void (*)(void *, GPU_PBVH_Buffers *))sculpt_draw_cb, scd);
+ BKE_pbvh_draw_cb(pbvh,
+ use_vcol,
+ update_only_visible,
+ &frustum,
+ (void (*)(void *, GPU_PBVH_Buffers *))sculpt_draw_cb,
+ scd);
-#ifdef SCULPT_DEBUG_BUFFERS
- int node_nr = 0;
- DRW_debug_modelmat(scd->ob->obmat);
- BKE_pbvh_draw_debug_cb(
- pbvh,
- (void (*)(void *d, const float min[3], const float max[3], PBVHNodeFlags f))sculpt_debug_cb,
- &node_nr);
-#endif
+ if (SCULPT_DEBUG_BUFFERS) {
+ int debug_node_nr = 0;
+ DRW_debug_modelmat(scd->ob->obmat);
+ BKE_pbvh_draw_debug_cb(
+ pbvh,
+ (void (*)(
+ void *d, const float min[3], const float max[3], PBVHNodeFlags f))sculpt_debug_cb,
+ &debug_node_nr);
+ }
}
void DRW_shgroup_call_sculpt(
@@ -719,27 +982,26 @@ DRWCallBuffer *DRW_shgroup_call_buffer(DRWShadingGroup *shgroup,
BLI_assert(ELEM(prim_type, GPU_PRIM_POINTS, GPU_PRIM_LINES, GPU_PRIM_TRI_FAN));
BLI_assert(format != NULL);
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
-
- call->state = drw_call_state_object(shgroup, NULL, NULL);
- GPUVertBuf *buf = DRW_temp_buffer_request(DST.idatalist, format, &call->vert_count);
- call->batch = DRW_temp_batch_request(DST.idatalist, buf, prim_type);
- call->vert_first = 0;
- call->vert_count = 0;
- call->inst_count = 0;
+ DRWCallBuffer *callbuf = BLI_memblock_alloc(DST.vmempool->callbuffers);
+ callbuf->buf = DRW_temp_buffer_request(DST.idatalist, format, &callbuf->count);
+ callbuf->buf_select = NULL;
+ callbuf->count = 0;
-#ifdef USE_GPU_SELECT
if (G.f & G_FLAG_PICKSEL) {
/* Not actually used for rendering but alloced in one chunk. */
if (inst_select_format.attr_len == 0) {
GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT);
}
- call->inst_selectid = DRW_temp_buffer_request(
- DST.idatalist, &inst_select_format, &call->vert_count);
+ callbuf->buf_select = DRW_temp_buffer_request(
+ DST.idatalist, &inst_select_format, &callbuf->count);
+ drw_command_set_select_id(shgroup, callbuf->buf_select, -1);
}
-#endif
- return (DRWCallBuffer *)call;
+
+ DRWResourceHandle handle = drw_resource_handle(shgroup, NULL, NULL);
+ GPUBatch *batch = DRW_temp_batch_request(DST.idatalist, callbuf->buf, prim_type);
+ drw_command_draw(shgroup, batch, handle);
+
+ return callbuf;
}
DRWCallBuffer *DRW_shgroup_call_buffer_instance(DRWShadingGroup *shgroup,
@@ -749,56 +1011,52 @@ DRWCallBuffer *DRW_shgroup_call_buffer_instance(DRWShadingGroup *shgroup,
BLI_assert(geom != NULL);
BLI_assert(format != NULL);
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
-
- call->state = drw_call_state_object(shgroup, NULL, NULL);
- GPUVertBuf *buf = DRW_temp_buffer_request(DST.idatalist, format, &call->inst_count);
- call->batch = DRW_temp_batch_instance_request(DST.idatalist, buf, geom);
- call->vert_first = 0;
- call->vert_count = 0; /* Auto from batch. */
- call->inst_count = 0;
+ DRWCallBuffer *callbuf = BLI_memblock_alloc(DST.vmempool->callbuffers);
+ callbuf->buf = DRW_temp_buffer_request(DST.idatalist, format, &callbuf->count);
+ callbuf->buf_select = NULL;
+ callbuf->count = 0;
-#ifdef USE_GPU_SELECT
if (G.f & G_FLAG_PICKSEL) {
/* Not actually used for rendering but alloced in one chunk. */
if (inst_select_format.attr_len == 0) {
GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT);
}
- call->inst_selectid = DRW_temp_buffer_request(
- DST.idatalist, &inst_select_format, &call->inst_count);
+ callbuf->buf_select = DRW_temp_buffer_request(
+ DST.idatalist, &inst_select_format, &callbuf->count);
+ drw_command_set_select_id(shgroup, callbuf->buf_select, -1);
}
-#endif
- return (DRWCallBuffer *)call;
+
+ DRWResourceHandle handle = drw_resource_handle(shgroup, NULL, NULL);
+ GPUBatch *batch = DRW_temp_batch_instance_request(DST.idatalist, callbuf->buf, geom);
+ drw_command_draw(shgroup, batch, handle);
+
+ return callbuf;
}
void DRW_buffer_add_entry_array(DRWCallBuffer *callbuf, const void *attr[], uint attr_len)
{
- DRWCall *call = (DRWCall *)callbuf;
- const bool is_instance = call->batch->inst != NULL;
- GPUVertBuf *buf = is_instance ? call->batch->inst : call->batch->verts[0];
- uint count = is_instance ? call->inst_count++ : call->vert_count++;
- const bool resize = (count == buf->vertex_alloc);
+ GPUVertBuf *buf = callbuf->buf;
+ const bool resize = (callbuf->count == buf->vertex_alloc);
BLI_assert(attr_len == buf->format.attr_len);
UNUSED_VARS_NDEBUG(attr_len);
if (UNLIKELY(resize)) {
- GPU_vertbuf_data_resize(buf, count + DRW_BUFFER_VERTS_CHUNK);
+ GPU_vertbuf_data_resize(buf, callbuf->count + DRW_BUFFER_VERTS_CHUNK);
}
- for (int i = 0; i < attr_len; ++i) {
- GPU_vertbuf_attr_set(buf, i, count, attr[i]);
+ for (int i = 0; i < attr_len; i++) {
+ GPU_vertbuf_attr_set(buf, i, callbuf->count, attr[i]);
}
-#ifdef USE_GPU_SELECT
if (G.f & G_FLAG_PICKSEL) {
if (UNLIKELY(resize)) {
- GPU_vertbuf_data_resize(call->inst_selectid, count + DRW_BUFFER_VERTS_CHUNK);
+ GPU_vertbuf_data_resize(callbuf->buf_select, callbuf->count + DRW_BUFFER_VERTS_CHUNK);
}
- GPU_vertbuf_attr_set(call->inst_selectid, 0, count, &DST.select_id);
+ GPU_vertbuf_attr_set(callbuf->buf_select, 0, callbuf->count, &DST.select_id);
}
-#endif
+
+ callbuf->count++;
}
/** \} */
@@ -811,7 +1069,54 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
{
shgroup->uniforms = NULL;
+ /* TODO(fclem) make them builtin. */
int view_ubo_location = GPU_shader_get_uniform_block(shader, "viewBlock");
+ int model_ubo_location = GPU_shader_get_uniform_block(shader, "modelBlock");
+ int info_ubo_location = GPU_shader_get_uniform_block(shader, "infoBlock");
+ int baseinst_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_BASE_INSTANCE);
+ int chunkid_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_RESOURCE_CHUNK);
+
+ if (chunkid_location != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, chunkid_location, DRW_UNIFORM_RESOURCE_CHUNK, NULL, 0, 1);
+ }
+
+ if (baseinst_location != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, baseinst_location, DRW_UNIFORM_BASE_INSTANCE, NULL, 0, 1);
+ }
+
+ if (model_ubo_location != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, model_ubo_location, DRW_UNIFORM_BLOCK_OBMATS, NULL, 0, 1);
+ }
+ else {
+ int model = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL);
+ int modelinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL_INV);
+ int modelviewprojection = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP);
+ if (model != -1) {
+ drw_shgroup_uniform_create_ex(shgroup, model, DRW_UNIFORM_MODEL_MATRIX, NULL, 0, 1);
+ }
+ if (modelinverse != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, modelinverse, DRW_UNIFORM_MODEL_MATRIX_INVERSE, NULL, 0, 1);
+ }
+ if (modelviewprojection != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, modelviewprojection, DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX, NULL, 0, 1);
+ }
+ }
+
+ if (info_ubo_location != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, info_ubo_location, DRW_UNIFORM_BLOCK_OBINFOS, NULL, 0, 1);
+
+ /* Abusing this loc to tell shgroup we need the obinfos. */
+ shgroup->objectinfo = 1;
+ }
+ else {
+ shgroup->objectinfo = 0;
+ }
if (view_ubo_location != -1) {
drw_shgroup_uniform_create_ex(
@@ -834,31 +1139,6 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW_INV) == -1);
BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW) == -1);
BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_NORMAL) == -1);
-
- shgroup->model = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL);
- shgroup->modelinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL_INV);
- shgroup->modelviewprojection = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP);
- shgroup->orcotexfac = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_ORCO);
- shgroup->objectinfo = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_OBJECT_INFO);
- shgroup->objectcolor = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_OBJECT_COLOR);
- shgroup->callid = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_CALLID);
-
- shgroup->matflag = 0;
- if (shgroup->modelinverse > -1) {
- shgroup->matflag |= DRW_CALL_MODELINVERSE;
- }
- if (shgroup->modelviewprojection > -1) {
- shgroup->matflag |= DRW_CALL_MODELVIEWPROJECTION;
- }
- if (shgroup->orcotexfac > -1) {
- shgroup->matflag |= DRW_CALL_ORCOTEXFAC;
- }
- if (shgroup->objectinfo > -1) {
- shgroup->matflag |= DRW_CALL_OBJECTINFO;
- }
- if (shgroup->objectcolor > -1) {
- shgroup->matflag |= DRW_CALL_OBJECTCOLOR;
- }
}
static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass *pass)
@@ -868,13 +1148,9 @@ static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass
BLI_LINKS_APPEND(&pass->shgroups, shgroup);
shgroup->shader = shader;
- shgroup->state_extra = 0;
- shgroup->state_extra_disable = ~0x0;
- shgroup->stencil_mask = 0;
- shgroup->calls.first = NULL;
- shgroup->calls.last = NULL;
- shgroup->tfeedback_target = NULL;
- shgroup->pass_parent = pass;
+ shgroup->cmd.first = NULL;
+ shgroup->cmd.last = NULL;
+ shgroup->pass_handle = pass->handle;
return shgroup;
}
@@ -939,7 +1215,7 @@ GPUVertFormat *DRW_shgroup_instance_format_array(const DRWInstanceAttrFormat att
{
GPUVertFormat *format = MEM_callocN(sizeof(GPUVertFormat), "GPUVertFormat");
- for (int i = 0; i < arraysize; ++i) {
+ for (int i = 0; i < arraysize; i++) {
GPU_vertformat_attr_add(format,
attrs[i].name,
(attrs[i].type == DRW_ATTR_INT) ? GPU_COMP_I32 : GPU_COMP_F32,
@@ -975,7 +1251,7 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader,
BLI_assert(tf_target != NULL);
DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
drw_shgroup_init(shgroup, shader);
- shgroup->tfeedback_target = tf_target;
+ drw_shgroup_uniform_create_ex(shgroup, 0, DRW_UNIFORM_TFEEDBACK_TARGET, tf_target, 0, 1);
return shgroup;
}
@@ -985,37 +1261,42 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader,
*/
void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state)
{
- shgroup->state_extra |= state;
+ drw_command_set_mutable_state(shgroup, state, 0x0);
}
void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state)
{
- shgroup->state_extra_disable &= ~state;
+ drw_command_set_mutable_state(shgroup, 0x0, state);
}
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask)
{
- BLI_assert(mask <= 255);
- shgroup->stencil_mask = mask;
-}
-
-bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup)
-{
- return shgroup->calls.first == NULL;
+ drw_command_set_stencil_mask(shgroup, mask);
}
-/* This is a workaround function waiting for the clearing operation to be available inside the
- * shgroups. */
-DRWShadingGroup *DRW_shgroup_get_next(DRWShadingGroup *shgroup)
+void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup,
+ eGPUFrameBufferBits channels,
+ uchar r,
+ uchar g,
+ uchar b,
+ uchar a,
+ float depth,
+ uchar stencil)
{
- return shgroup->next;
+ drw_command_clear(shgroup, channels, r, g, b, a, depth, stencil);
}
-/* This is a workaround function waiting for the clearing operation to be available inside the
- * shgroups. */
-uint DRW_shgroup_stencil_mask_get(DRWShadingGroup *shgroup)
+bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup)
{
- return shgroup->stencil_mask;
+ DRWCommandChunk *chunk = shgroup->cmd.first;
+ for (; chunk; chunk = chunk->next) {
+ for (int i = 0; i < chunk->command_used; i++) {
+ if (command_type_get(chunk->command_type, i) <= DRW_MAX_DRAW_CMD_TYPE) {
+ return false;
+ }
+ }
+ }
+ return true;
}
DRWShadingGroup *DRW_shgroup_create_sub(DRWShadingGroup *shgroup)
@@ -1023,11 +1304,14 @@ DRWShadingGroup *DRW_shgroup_create_sub(DRWShadingGroup *shgroup)
DRWShadingGroup *shgroup_new = BLI_memblock_alloc(DST.vmempool->shgroups);
*shgroup_new = *shgroup;
- shgroup_new->uniforms = NULL;
- shgroup_new->calls.first = NULL;
- shgroup_new->calls.last = NULL;
+ drw_shgroup_init(shgroup_new, shgroup_new->shader);
+ shgroup_new->cmd.first = NULL;
+ shgroup_new->cmd.last = NULL;
- BLI_LINKS_INSERT_AFTER(&shgroup->pass_parent->shgroups, shgroup, shgroup_new);
+ DRWPass *parent_pass = DRW_memblock_elem_from_handle(DST.vmempool->passes,
+ &shgroup->pass_handle);
+
+ BLI_LINKS_INSERT_AFTER(&parent_pass->shgroups, shgroup, shgroup_new);
return shgroup_new;
}
@@ -1522,6 +1806,8 @@ DRWPass *DRW_pass_create(const char *name, DRWState state)
pass->shgroups.first = NULL;
pass->shgroups.last = NULL;
+ pass->handle = DST.pass_handle;
+ DRW_handle_increment(&DST.pass_handle);
return pass;
}
@@ -1565,42 +1851,22 @@ typedef struct ZSortData {
const float *origin;
} ZSortData;
-static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b)
+static int pass_shgroup_dist_sort(const void *a, const void *b)
{
- const ZSortData *zsortdata = (ZSortData *)thunk;
const DRWShadingGroup *shgrp_a = (const DRWShadingGroup *)a;
const DRWShadingGroup *shgrp_b = (const DRWShadingGroup *)b;
- const DRWCall *call_a = (DRWCall *)shgrp_a->calls.first;
- const DRWCall *call_b = (DRWCall *)shgrp_b->calls.first;
-
- if (call_a == NULL) {
- return -1;
- }
- if (call_b == NULL) {
- return -1;
- }
-
- float tmp[3];
- sub_v3_v3v3(tmp, zsortdata->origin, call_a->state->model[3]);
- const float a_sq = dot_v3v3(zsortdata->axis, tmp);
- sub_v3_v3v3(tmp, zsortdata->origin, call_b->state->model[3]);
- const float b_sq = dot_v3v3(zsortdata->axis, tmp);
-
- if (a_sq < b_sq) {
+ if (shgrp_a->z_sorting.distance < shgrp_b->z_sorting.distance) {
return 1;
}
- else if (a_sq > b_sq) {
+ else if (shgrp_a->z_sorting.distance > shgrp_b->z_sorting.distance) {
return -1;
}
else {
- /* If there is a depth prepass put it before */
- if ((shgrp_a->state_extra & DRW_STATE_WRITE_DEPTH) != 0) {
+ /* If distances are the same, keep original order. */
+ if (shgrp_a->z_sorting.original_index > shgrp_b->z_sorting.original_index) {
return -1;
}
- else if ((shgrp_b->state_extra & DRW_STATE_WRITE_DEPTH) != 0) {
- return 1;
- }
else {
return 0;
}
@@ -1611,35 +1877,61 @@ static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b)
#define SORT_IMPL_LINKTYPE DRWShadingGroup
-#define SORT_IMPL_USE_THUNK
#define SORT_IMPL_FUNC shgroup_sort_fn_r
#include "../../blenlib/intern/list_sort_impl.h"
#undef SORT_IMPL_FUNC
-#undef SORT_IMPL_USE_THUNK
#undef SORT_IMPL_LINKTYPE
/**
* Sort Shading groups by decreasing Z of their first draw call.
- * This is useful for order dependent effect such as transparency.
+ * This is useful for order dependent effect such as alpha-blending.
*/
void DRW_pass_sort_shgroup_z(DRWPass *pass)
{
const float(*viewinv)[4] = DST.view_active->storage.viewinv;
- ZSortData zsortdata = {viewinv[2], viewinv[3]};
-
- if (pass->shgroups.first && pass->shgroups.first->next) {
- pass->shgroups.first = shgroup_sort_fn_r(
- pass->shgroups.first, pass_shgroup_dist_sort, &zsortdata);
+ if (!(pass->shgroups.first && pass->shgroups.first->next)) {
+ /* Nothing to sort */
+ return;
+ }
- /* Find the next last */
- DRWShadingGroup *last = pass->shgroups.first;
- while ((last = last->next)) {
- /* Do nothing */
+ uint index = 0;
+ DRWShadingGroup *shgroup = pass->shgroups.first;
+ do {
+ DRWResourceHandle handle = 0;
+ /* Find first DRWCommandDraw. */
+ DRWCommandChunk *cmd_chunk = shgroup->cmd.first;
+ for (; cmd_chunk && handle == 0; cmd_chunk = cmd_chunk->next) {
+ for (int i = 0; i < cmd_chunk->command_used && handle == 0; i++) {
+ if (DRW_CMD_DRAW == command_type_get(cmd_chunk->command_type, i)) {
+ handle = cmd_chunk->commands[i].draw.handle;
+ }
+ }
}
- pass->shgroups.last = last;
+ /* To be sorted a shgroup needs to have at least one draw command. */
+ BLI_assert(handle != 0);
+
+ DRWObjectMatrix *obmats = DRW_memblock_elem_from_handle(DST.vmempool->obmats, &handle);
+
+ /* Compute distance to camera. */
+ float tmp[3];
+ sub_v3_v3v3(tmp, viewinv[3], obmats->model[3]);
+ shgroup->z_sorting.distance = dot_v3v3(viewinv[2], tmp);
+ shgroup->z_sorting.original_index = index++;
+
+ } while ((shgroup = shgroup->next));
+
+ /* Sort using computed distances. */
+ pass->shgroups.first = shgroup_sort_fn_r(pass->shgroups.first, pass_shgroup_dist_sort);
+
+ /* Find the new last */
+ DRWShadingGroup *last = pass->shgroups.first;
+ while ((last = last->next)) {
+ /* Reset the pass id for debugging. */
+ last->pass_handle = pass->handle;
}
+ pass->shgroups.last = last;
}
/** \} */
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index 50408015fbc..3de9ce74dbc 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -28,7 +28,6 @@
#include "BKE_global.h"
-#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "intern/gpu_shader_private.h"
#include "intern/gpu_primitive_private.h"
@@ -37,16 +36,41 @@
# include "GPU_select.h"
#endif
-#ifdef USE_GPU_SELECT
void DRW_select_load_id(uint id)
{
+#ifdef USE_GPU_SELECT
BLI_assert(G.f & G_FLAG_PICKSEL);
DST.select_id = id;
-}
#endif
+}
#define DEBUG_UBO_BINDING
+typedef struct DRWCommandsState {
+ GPUBatch *batch;
+ int resource_chunk;
+ int base_inst;
+ int inst_count;
+ int v_first;
+ int v_count;
+ bool neg_scale;
+ /* Resource location. */
+ int obmats_loc;
+ int obinfos_loc;
+ int baseinst_loc;
+ int chunkid_loc;
+ /* Legacy matrix support. */
+ int obmat_loc;
+ int obinv_loc;
+ int mvp_loc;
+ /* Selection ID state. */
+ GPUVertBuf *select_buf;
+ uint select_id;
+ /* Drawing State */
+ DRWState drw_state_enabled;
+ DRWState drw_state_disabled;
+} DRWCommandsState;
+
/* -------------------------------------------------------------------- */
/** \name Draw State (DRW_state)
* \{ */
@@ -279,17 +303,34 @@ void drw_state_set(DRWState state)
}
}
+ /* Shadow Bias */
+ {
+ int test;
+ if ((test = CHANGED_TO(DRW_STATE_SHADOW_OFFSET))) {
+ if (test == 1) {
+ glEnable(GL_POLYGON_OFFSET_FILL);
+ glEnable(GL_POLYGON_OFFSET_LINE);
+ /* 2.0 Seems to be the lowest possible slope bias that works in every case. */
+ glPolygonOffset(2.0f, 1.0f);
+ }
+ else {
+ glDisable(GL_POLYGON_OFFSET_FILL);
+ glDisable(GL_POLYGON_OFFSET_LINE);
+ }
+ }
+ }
+
/* Clip Planes */
{
int test;
if ((test = CHANGED_TO(DRW_STATE_CLIP_PLANES))) {
if (test == 1) {
- for (int i = 0; i < DST.view_active->clip_planes_len; ++i) {
+ for (int i = 0; i < DST.view_active->clip_planes_len; i++) {
glEnable(GL_CLIP_DISTANCE0 + i);
}
}
else {
- for (int i = 0; i < MAX_CLIP_PLANES; ++i) {
+ for (int i = 0; i < MAX_CLIP_PLANES; i++) {
glDisable(GL_CLIP_DISTANCE0 + i);
}
}
@@ -391,9 +432,10 @@ void DRW_state_reset(void)
/** \name Culling (DRW_culling)
* \{ */
-static bool draw_call_is_culled(DRWCall *call, DRWView *view)
+static bool draw_call_is_culled(const DRWResourceHandle *handle, DRWView *view)
{
- return (call->state->culling->mask & view->culling_mask) != 0;
+ DRWCullingState *culling = DRW_memblock_elem_from_handle(DST.vmempool->cullstates, handle);
+ return (culling->mask & view->culling_mask) != 0;
}
/* Set active view for rendering. */
@@ -572,66 +614,96 @@ static void draw_compute_culling(DRWView *view)
/** \name Draw (DRW_draw)
* \{ */
-static void draw_geometry_prepare(DRWShadingGroup *shgroup, DRWCall *call)
+BLI_INLINE void draw_legacy_matrix_update(DRWShadingGroup *shgroup,
+ DRWResourceHandle *handle,
+ float obmat_loc,
+ float obinv_loc,
+ float mvp_loc)
{
- BLI_assert(call);
- DRWCallState *state = call->state;
-
- if (shgroup->model != -1) {
- GPU_shader_uniform_vector(shgroup->shader, shgroup->model, 16, 1, (float *)state->model);
+ /* Still supported for compatibility with gpu_shader_* but should be forbidden. */
+ DRWObjectMatrix *ob_mats = DRW_memblock_elem_from_handle(DST.vmempool->obmats, handle);
+ if (obmat_loc != -1) {
+ GPU_shader_uniform_vector(shgroup->shader, obmat_loc, 16, 1, (float *)ob_mats->model);
}
- if (shgroup->modelinverse != -1) {
- GPU_shader_uniform_vector(
- shgroup->shader, shgroup->modelinverse, 16, 1, (float *)state->modelinverse);
- }
- if (shgroup->objectinfo != -1) {
- float infos[4];
- infos[0] = state->ob_index;
- // infos[1]; /* UNUSED. */
- infos[2] = state->ob_random;
- infos[3] = (state->flag & DRW_CALL_NEGSCALE) ? -1.0f : 1.0f;
- GPU_shader_uniform_vector(shgroup->shader, shgroup->objectinfo, 4, 1, (float *)infos);
- }
- if (shgroup->objectcolor != -1) {
- GPU_shader_uniform_vector(
- shgroup->shader, shgroup->objectcolor, 4, 1, (float *)state->ob_color);
- }
- if (shgroup->orcotexfac != -1) {
- GPU_shader_uniform_vector(
- shgroup->shader, shgroup->orcotexfac, 3, 2, (float *)state->orcotexfac);
+ if (obinv_loc != -1) {
+ GPU_shader_uniform_vector(shgroup->shader, obinv_loc, 16, 1, (float *)ob_mats->modelinverse);
}
/* Still supported for compatibility with gpu_shader_* but should be forbidden
* and is slow (since it does not cache the result). */
- if (shgroup->modelviewprojection != -1) {
+ if (mvp_loc != -1) {
float mvp[4][4];
- mul_m4_m4m4(mvp, DST.view_active->storage.persmat, state->model);
- GPU_shader_uniform_vector(shgroup->shader, shgroup->modelviewprojection, 16, 1, (float *)mvp);
+ mul_m4_m4m4(mvp, DST.view_active->storage.persmat, ob_mats->model);
+ GPU_shader_uniform_vector(shgroup->shader, mvp_loc, 16, 1, (float *)mvp);
}
}
+BLI_INLINE void draw_geometry_bind(DRWShadingGroup *shgroup, GPUBatch *geom)
+{
+ /* XXX hacking #GPUBatch. we don't want to call glUseProgram! (huge performance loss) */
+ if (DST.batch) {
+ DST.batch->program_in_use = false;
+ }
+
+ DST.batch = geom;
+
+ GPU_batch_program_set_no_use(
+ geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader));
+
+ geom->program_in_use = true; /* XXX hacking #GPUBatch */
+
+ GPU_batch_bind(geom);
+}
+
BLI_INLINE void draw_geometry_execute(DRWShadingGroup *shgroup,
GPUBatch *geom,
- uint vert_first,
- uint vert_count,
- uint inst_first,
- uint inst_count)
+ int vert_first,
+ int vert_count,
+ int inst_first,
+ int inst_count,
+ int baseinst_loc)
{
+ /* inst_count can be -1. */
+ inst_count = max_ii(0, inst_count);
+
+ if (baseinst_loc != -1) {
+ /* Fallback when ARB_shader_draw_parameters is not supported. */
+ GPU_shader_uniform_vector_int(shgroup->shader, baseinst_loc, 1, 1, (int *)&inst_first);
+ /* Avoids VAO reconfiguration on older hardware. (see GPU_batch_draw_advanced) */
+ inst_first = 0;
+ }
+
/* bind vertex array */
if (DST.batch != geom) {
- DST.batch = geom;
-
- GPU_batch_program_set_no_use(
- geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader));
-
- GPU_batch_bind(geom);
+ draw_geometry_bind(shgroup, geom);
}
- /* XXX hacking #GPUBatch. we don't want to call glUseProgram! (huge performance loss) */
- geom->program_in_use = true;
-
GPU_batch_draw_advanced(geom, vert_first, vert_count, inst_first, inst_count);
+}
- geom->program_in_use = false; /* XXX hacking #GPUBatch */
+BLI_INLINE void draw_indirect_call(DRWShadingGroup *shgroup, DRWCommandsState *state)
+{
+ if (state->inst_count == 0) {
+ return;
+ }
+ if (state->baseinst_loc == -1) {
+ /* bind vertex array */
+ if (DST.batch != state->batch) {
+ GPU_draw_list_submit(DST.draw_list);
+ draw_geometry_bind(shgroup, state->batch);
+ }
+ GPU_draw_list_command_add(
+ DST.draw_list, state->v_first, state->v_count, state->base_inst, state->inst_count);
+ }
+ /* Fallback when unsupported */
+ else {
+ draw_geometry_execute(shgroup,
+ state->batch,
+ state->v_first,
+ state->v_count,
+ state->base_inst,
+ state->inst_count,
+ state->baseinst_loc);
+ }
}
enum {
@@ -703,6 +775,9 @@ static void bind_ubo(GPUUniformBuffer *ubo, char bind_type)
/* UBO isn't bound yet. Find an empty slot and bind it. */
idx = get_empty_slot_index(DST.RST.bound_ubo_slots);
+ /* [0..1] are reserved ubo slots. */
+ idx += 2;
+
if (idx < GPU_max_ubo_binds()) {
GPUUniformBuffer **gpu_ubo_slot = &DST.RST.bound_ubos[idx];
/* Unbind any previous UBO. */
@@ -722,10 +797,13 @@ static void bind_ubo(GPUUniformBuffer *ubo, char bind_type)
}
}
else {
+ BLI_assert(idx < 64);
/* This UBO slot was released but the UBO is
* still bound here. Just flag the slot again. */
BLI_assert(DST.RST.bound_ubos[idx] == ubo);
}
+ /* Remove offset for flag bitfield. */
+ idx -= 2;
set_bound_flags(&DST.RST.bound_ubo_slots, &DST.RST.bound_ubo_slots_persist, idx, bind_type);
}
@@ -754,7 +832,7 @@ static bool ubo_bindings_validate(DRWShadingGroup *shgroup)
glGetIntegerv(GL_CURRENT_PROGRAM, &program);
glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &active_blocks);
- for (uint i = 0; i < active_blocks; ++i) {
+ for (uint i = 0; i < active_blocks; i++) {
int binding = 0;
int buffer = 0;
@@ -769,8 +847,12 @@ static bool ubo_bindings_validate(DRWShadingGroup *shgroup)
printf("Trying to draw with missing UBO binding.\n");
valid = false;
}
+
+ DRWPass *parent_pass = DRW_memblock_elem_from_handle(DST.vmempool->passes,
+ &shgroup->pass_handle);
+
printf("Pass : %s, Shader : %s, Block : %s\n",
- shgroup->pass_parent->name,
+ parent_pass->name,
shgroup->shader->name,
blockname);
}
@@ -802,119 +884,331 @@ static void release_ubo_slots(bool with_persist)
}
}
-static void draw_update_uniforms(DRWShadingGroup *shgroup)
+static void draw_update_uniforms(DRWShadingGroup *shgroup,
+ DRWCommandsState *state,
+ bool *use_tfeedback)
{
- for (DRWUniform *uni = shgroup->uniforms; uni; uni = uni->next) {
- GPUTexture *tex;
- GPUUniformBuffer *ubo;
- if (uni->location == -2) {
- uni->location = GPU_shader_get_uniform_ensure(shgroup->shader,
- DST.uniform_names.buffer + uni->name_ofs);
- if (uni->location == -1) {
- continue;
+ for (DRWUniformChunk *unichunk = shgroup->uniforms; unichunk; unichunk = unichunk->next) {
+ DRWUniform *uni = unichunk->uniforms;
+ for (int i = 0; i < unichunk->uniform_used; i++, uni++) {
+ GPUTexture *tex;
+ GPUUniformBuffer *ubo;
+ if (uni->location == -2) {
+ uni->location = GPU_shader_get_uniform_ensure(shgroup->shader,
+ DST.uniform_names.buffer + uni->name_ofs);
+ if (uni->location == -1) {
+ continue;
+ }
+ }
+ const void *data = uni->pvalue;
+ if (ELEM(uni->type, DRW_UNIFORM_INT_COPY, DRW_UNIFORM_FLOAT_COPY)) {
+ data = uni->fvalue;
+ }
+ switch (uni->type) {
+ case DRW_UNIFORM_INT_COPY:
+ case DRW_UNIFORM_INT:
+ GPU_shader_uniform_vector_int(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, data);
+ break;
+ case DRW_UNIFORM_FLOAT_COPY:
+ case DRW_UNIFORM_FLOAT:
+ GPU_shader_uniform_vector(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, data);
+ break;
+ case DRW_UNIFORM_TEXTURE:
+ tex = (GPUTexture *)uni->pvalue;
+ BLI_assert(tex);
+ bind_texture(tex, BIND_TEMP);
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_TEXTURE_PERSIST:
+ tex = (GPUTexture *)uni->pvalue;
+ BLI_assert(tex);
+ bind_texture(tex, BIND_PERSIST);
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_TEXTURE_REF:
+ tex = *((GPUTexture **)uni->pvalue);
+ BLI_assert(tex);
+ bind_texture(tex, BIND_TEMP);
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_BLOCK:
+ ubo = (GPUUniformBuffer *)uni->pvalue;
+ bind_ubo(ubo, BIND_TEMP);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ case DRW_UNIFORM_BLOCK_PERSIST:
+ ubo = (GPUUniformBuffer *)uni->pvalue;
+ bind_ubo(ubo, BIND_PERSIST);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ case DRW_UNIFORM_BLOCK_OBMATS:
+ state->obmats_loc = uni->location;
+ ubo = DST.vmempool->matrices_ubo[0];
+ GPU_uniformbuffer_bind(ubo, 0);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ case DRW_UNIFORM_BLOCK_OBINFOS:
+ state->obinfos_loc = uni->location;
+ ubo = DST.vmempool->obinfos_ubo[0];
+ GPU_uniformbuffer_bind(ubo, 1);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ case DRW_UNIFORM_RESOURCE_CHUNK:
+ state->chunkid_loc = uni->location;
+ GPU_shader_uniform_int(shgroup->shader, uni->location, 0);
+ break;
+ case DRW_UNIFORM_TFEEDBACK_TARGET:
+ BLI_assert(data && (*use_tfeedback == false));
+ *use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader,
+ ((GPUVertBuf *)data)->vbo_id);
+ break;
+ /* Legacy/Fallback support. */
+ case DRW_UNIFORM_BASE_INSTANCE:
+ state->baseinst_loc = uni->location;
+ break;
+ case DRW_UNIFORM_MODEL_MATRIX:
+ state->obmat_loc = uni->location;
+ break;
+ case DRW_UNIFORM_MODEL_MATRIX_INVERSE:
+ state->obinv_loc = uni->location;
+ break;
+ case DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX:
+ state->mvp_loc = uni->location;
+ break;
}
- }
- const void *data = uni->pvalue;
- if (ELEM(uni->type, DRW_UNIFORM_INT_COPY, DRW_UNIFORM_FLOAT_COPY)) {
- data = uni->fvalue;
- }
- switch (uni->type) {
- case DRW_UNIFORM_INT_COPY:
- case DRW_UNIFORM_INT:
- GPU_shader_uniform_vector_int(
- shgroup->shader, uni->location, uni->length, uni->arraysize, data);
- break;
- case DRW_UNIFORM_FLOAT_COPY:
- case DRW_UNIFORM_FLOAT:
- GPU_shader_uniform_vector(
- shgroup->shader, uni->location, uni->length, uni->arraysize, data);
- break;
- case DRW_UNIFORM_TEXTURE:
- tex = (GPUTexture *)uni->pvalue;
- BLI_assert(tex);
- bind_texture(tex, BIND_TEMP);
- GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
- break;
- case DRW_UNIFORM_TEXTURE_PERSIST:
- tex = (GPUTexture *)uni->pvalue;
- BLI_assert(tex);
- bind_texture(tex, BIND_PERSIST);
- GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
- break;
- case DRW_UNIFORM_TEXTURE_REF:
- tex = *((GPUTexture **)uni->pvalue);
- BLI_assert(tex);
- bind_texture(tex, BIND_TEMP);
- GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
- break;
- case DRW_UNIFORM_BLOCK:
- ubo = (GPUUniformBuffer *)uni->pvalue;
- bind_ubo(ubo, BIND_TEMP);
- GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
- break;
- case DRW_UNIFORM_BLOCK_PERSIST:
- ubo = (GPUUniformBuffer *)uni->pvalue;
- bind_ubo(ubo, BIND_PERSIST);
- GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
- break;
}
}
BLI_assert(ubo_bindings_validate(shgroup));
}
-BLI_INLINE bool draw_select_do_call(DRWShadingGroup *shgroup, DRWCall *call)
+BLI_INLINE void draw_select_buffer(DRWShadingGroup *shgroup,
+ DRWCommandsState *state,
+ GPUBatch *batch,
+ const DRWResourceHandle *handle)
{
-#ifdef USE_GPU_SELECT
- if ((G.f & G_FLAG_PICKSEL) == 0) {
- return false;
+ const bool is_instancing = (batch->inst != NULL);
+ int start = 0;
+ int count = 1;
+ int tot = is_instancing ? batch->inst->vertex_len : batch->verts[0]->vertex_len;
+ /* Hack : get "vbo" data without actually drawing. */
+ int *select_id = (void *)state->select_buf->data;
+
+ /* Batching */
+ if (!is_instancing) {
+ /* FIXME: Meh a bit nasty. */
+ if (batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_TRIS)) {
+ count = 3;
+ }
+ else if (batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_LINES)) {
+ count = 2;
+ }
}
- if (call->inst_selectid != NULL) {
- const bool is_instancing = (call->inst_count != 0);
- uint start = 0;
- uint count = 1;
- uint tot = is_instancing ? call->inst_count : call->vert_count;
- /* Hack : get vbo data without actually drawing. */
- GPUVertBufRaw raw;
- GPU_vertbuf_attr_get_raw_data(call->inst_selectid, 0, &raw);
- int *select_id = GPU_vertbuf_raw_step(&raw);
-
- /* Batching */
- if (!is_instancing) {
- /* FIXME: Meh a bit nasty. */
- if (call->batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_TRIS)) {
- count = 3;
- }
- else if (call->batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_LINES)) {
- count = 2;
- }
+
+ while (start < tot) {
+ GPU_select_load_id(select_id[start]);
+ if (is_instancing) {
+ draw_geometry_execute(shgroup, batch, 0, 0, start, count, state->baseinst_loc);
+ }
+ else {
+ draw_geometry_execute(
+ shgroup, batch, start, count, DRW_handle_id_get(handle), 0, state->baseinst_loc);
}
+ start += count;
+ }
+}
- while (start < tot) {
- GPU_select_load_id(select_id[start]);
- if (is_instancing) {
- draw_geometry_execute(shgroup, call->batch, 0, 0, start, count);
- }
- else {
- draw_geometry_execute(shgroup, call->batch, start, count, 0, 0);
+typedef struct DRWCommandIterator {
+ int cmd_index;
+ DRWCommandChunk *curr_chunk;
+} DRWCommandIterator;
+
+static void draw_command_iter_begin(DRWCommandIterator *iter, DRWShadingGroup *shgroup)
+{
+ iter->curr_chunk = shgroup->cmd.first;
+ iter->cmd_index = 0;
+}
+
+static DRWCommand *draw_command_iter_step(DRWCommandIterator *iter, eDRWCommandType *cmd_type)
+{
+ if (iter->curr_chunk) {
+ if (iter->cmd_index == iter->curr_chunk->command_len) {
+ iter->curr_chunk = iter->curr_chunk->next;
+ iter->cmd_index = 0;
+ }
+ if (iter->curr_chunk) {
+ *cmd_type = command_type_get(iter->curr_chunk->command_type, iter->cmd_index);
+ if (iter->cmd_index < iter->curr_chunk->command_used) {
+ return iter->curr_chunk->commands + iter->cmd_index++;
}
- start += count;
}
- return true;
}
+ return NULL;
+}
+
+static void draw_call_resource_bind(DRWCommandsState *state, const DRWResourceHandle *handle)
+{
+ /* Front face is not a resource but it is inside the resource handle. */
+ bool neg_scale = DRW_handle_negative_scale_get(handle);
+ if (neg_scale != state->neg_scale) {
+ glFrontFace((neg_scale) ? GL_CW : GL_CCW);
+ state->neg_scale = neg_scale;
+ }
+
+ int chunk = DRW_handle_chunk_get(handle);
+ if (state->resource_chunk != chunk) {
+ if (state->chunkid_loc != -1) {
+ GPU_shader_uniform_int(NULL, state->chunkid_loc, chunk);
+ }
+ if (state->obmats_loc != -1) {
+ GPU_uniformbuffer_unbind(DST.vmempool->matrices_ubo[state->resource_chunk]);
+ GPU_uniformbuffer_bind(DST.vmempool->matrices_ubo[chunk], 0);
+ }
+ if (state->obinfos_loc != -1) {
+ GPU_uniformbuffer_unbind(DST.vmempool->obinfos_ubo[state->resource_chunk]);
+ GPU_uniformbuffer_bind(DST.vmempool->obinfos_ubo[chunk], 1);
+ }
+ state->resource_chunk = chunk;
+ }
+}
+
+static void draw_call_batching_flush(DRWShadingGroup *shgroup, DRWCommandsState *state)
+{
+ draw_indirect_call(shgroup, state);
+ GPU_draw_list_submit(DST.draw_list);
+
+ state->batch = NULL;
+ state->inst_count = 0;
+ state->base_inst = -1;
+}
+
+static void draw_call_single_do(DRWShadingGroup *shgroup,
+ DRWCommandsState *state,
+ GPUBatch *batch,
+ DRWResourceHandle handle,
+ int vert_first,
+ int vert_count,
+ int inst_count)
+{
+ draw_call_batching_flush(shgroup, state);
+
+ draw_call_resource_bind(state, &handle);
+
+ /* TODO This is Legacy. Need to be removed. */
+ if (state->obmats_loc == -1 &&
+ (state->obmat_loc != -1 || state->obinv_loc != -1 || state->mvp_loc != -1)) {
+ draw_legacy_matrix_update(
+ shgroup, &handle, state->obmat_loc, state->obinv_loc, state->mvp_loc);
+ }
+
+ if (G.f & G_FLAG_PICKSEL) {
+ if (state->select_buf != NULL) {
+ draw_select_buffer(shgroup, state, batch, &handle);
+ return;
+ }
+ else {
+ GPU_select_load_id(state->select_id);
+ }
+ }
+
+ draw_geometry_execute(shgroup,
+ batch,
+ vert_first,
+ vert_count,
+ DRW_handle_id_get(&handle),
+ inst_count,
+ state->baseinst_loc);
+}
+
+static void draw_call_batching_start(DRWCommandsState *state)
+{
+ state->neg_scale = false;
+ state->resource_chunk = 0;
+ state->base_inst = 0;
+ state->inst_count = 0;
+ state->v_first = 0;
+ state->v_count = 0;
+ state->batch = NULL;
+
+ state->select_id = -1;
+ state->select_buf = NULL;
+}
+
+/* NOTE: Does not support batches with instancing VBOs. */
+static void draw_call_batching_do(DRWShadingGroup *shgroup,
+ DRWCommandsState *state,
+ DRWCommandDraw *call)
+{
+ /* If any condition requires to interupt the merging. */
+ bool neg_scale = DRW_handle_negative_scale_get(&call->handle);
+ int chunk = DRW_handle_chunk_get(&call->handle);
+ int id = DRW_handle_id_get(&call->handle);
+ if ((state->neg_scale != neg_scale) || /* Need to change state. */
+ (state->resource_chunk != chunk) || /* Need to change UBOs. */
+ (state->batch != call->batch) /* Need to change VAO. */
+ ) {
+ draw_call_batching_flush(shgroup, state);
+
+ state->batch = call->batch;
+ state->v_first = (call->batch->elem) ? call->batch->elem->index_start : 0;
+ state->v_count = (call->batch->elem) ? call->batch->elem->index_len :
+ call->batch->verts[0]->vertex_len;
+ state->inst_count = 1;
+ state->base_inst = id;
+
+ draw_call_resource_bind(state, &call->handle);
+
+ GPU_draw_list_init(DST.draw_list, state->batch);
+ }
+ /* Is the id consecutive? */
+ else if (id != state->base_inst + state->inst_count) {
+ /* We need to add a draw command for the pending instances. */
+ draw_indirect_call(shgroup, state);
+ state->inst_count = 1;
+ state->base_inst = id;
+ }
+ /* We avoid a drawcall by merging with the precedent
+ * drawcall using instancing. */
else {
- GPU_select_load_id(call->select_id);
- return false;
+ state->inst_count++;
+ }
+}
+
+/* Flush remaining pending drawcalls. */
+static void draw_call_batching_finish(DRWShadingGroup *shgroup, DRWCommandsState *state)
+{
+ draw_call_batching_flush(shgroup, state);
+
+ /* Reset state */
+ if (state->neg_scale) {
+ glFrontFace(GL_CCW);
+ }
+ if (state->obmats_loc != -1) {
+ GPU_uniformbuffer_unbind(DST.vmempool->matrices_ubo[state->resource_chunk]);
+ }
+ if (state->obinfos_loc != -1) {
+ GPU_uniformbuffer_unbind(DST.vmempool->obinfos_ubo[state->resource_chunk]);
}
-#else
- return false;
-#endif
}
static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
{
BLI_assert(shgroup->shader);
+ DRWCommandsState state = {
+ .obmats_loc = -1,
+ .obinfos_loc = -1,
+ .baseinst_loc = -1,
+ .chunkid_loc = -1,
+ .obmat_loc = -1,
+ .obinv_loc = -1,
+ .mvp_loc = -1,
+ .drw_state_enabled = 0,
+ .drw_state_disabled = 0,
+ };
+
const bool shader_changed = (DST.shader != shgroup->shader);
bool use_tfeedback = false;
@@ -924,56 +1218,116 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
}
GPU_shader_bind(shgroup->shader);
DST.shader = shgroup->shader;
+ /* XXX hacking gawain */
+ if (DST.batch) {
+ DST.batch->program_in_use = false;
+ }
DST.batch = NULL;
}
- if (shgroup->tfeedback_target != NULL) {
- use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader,
- shgroup->tfeedback_target->vbo_id);
- }
-
release_ubo_slots(shader_changed);
release_texture_slots(shader_changed);
- drw_state_set((pass_state & shgroup->state_extra_disable) | shgroup->state_extra);
- drw_stencil_set(shgroup->stencil_mask);
+ draw_update_uniforms(shgroup, &state, &use_tfeedback);
- draw_update_uniforms(shgroup);
+ drw_state_set(pass_state);
/* Rendering Calls */
{
- bool prev_neg_scale = false;
- int callid = 0;
- for (DRWCall *call = shgroup->calls.first; call; call = call->next) {
-
- if (draw_call_is_culled(call, DST.view_active)) {
- continue;
- }
-
- /* XXX small exception/optimisation for outline rendering. */
- if (shgroup->callid != -1) {
- GPU_shader_uniform_vector_int(shgroup->shader, shgroup->callid, 1, 1, &callid);
- callid += 1;
- }
-
- /* Negative scale objects */
- bool neg_scale = call->state->flag & DRW_CALL_NEGSCALE;
- if (neg_scale != prev_neg_scale) {
- glFrontFace((neg_scale) ? GL_CW : GL_CCW);
- prev_neg_scale = neg_scale;
+ DRWCommandIterator iter;
+ DRWCommand *cmd;
+ eDRWCommandType cmd_type;
+
+ draw_command_iter_begin(&iter, shgroup);
+
+ draw_call_batching_start(&state);
+
+ while ((cmd = draw_command_iter_step(&iter, &cmd_type))) {
+
+ switch (cmd_type) {
+ case DRW_CMD_DRWSTATE:
+ case DRW_CMD_STENCIL:
+ draw_call_batching_flush(shgroup, &state);
+ break;
+ case DRW_CMD_DRAW:
+ case DRW_CMD_DRAW_PROCEDURAL:
+ case DRW_CMD_DRAW_INSTANCE:
+ if (draw_call_is_culled(&cmd->instance.handle, DST.view_active)) {
+ continue;
+ }
+ break;
+ default:
+ break;
}
- draw_geometry_prepare(shgroup, call);
-
- if (draw_select_do_call(shgroup, call)) {
- continue;
+ switch (cmd_type) {
+ case DRW_CMD_CLEAR:
+ GPU_framebuffer_clear(
+#ifndef NDEBUG
+ GPU_framebuffer_active_get(),
+#else
+ NULL,
+#endif
+ cmd->clear.clear_channels,
+ (float[4]){cmd->clear.r / 255.0f,
+ cmd->clear.g / 255.0f,
+ cmd->clear.b / 255.0f,
+ cmd->clear.a / 255.0f},
+ cmd->clear.depth,
+ cmd->clear.stencil);
+ break;
+ case DRW_CMD_DRWSTATE:
+ state.drw_state_enabled |= cmd->state.enable;
+ state.drw_state_disabled |= cmd->state.disable;
+ drw_state_set((pass_state & ~state.drw_state_disabled) | state.drw_state_enabled);
+ break;
+ case DRW_CMD_STENCIL:
+ drw_stencil_set(cmd->stencil.mask);
+ break;
+ case DRW_CMD_SELECTID:
+ state.select_id = cmd->select_id.select_id;
+ state.select_buf = cmd->select_id.select_buf;
+ break;
+ case DRW_CMD_DRAW:
+ if (!USE_BATCHING || state.obmats_loc == -1 || (G.f & G_FLAG_PICKSEL) ||
+ cmd->draw.batch->inst) {
+ draw_call_single_do(shgroup, &state, cmd->draw.batch, cmd->draw.handle, 0, 0, 0);
+ }
+ else {
+ draw_call_batching_do(shgroup, &state, &cmd->draw);
+ }
+ break;
+ case DRW_CMD_DRAW_PROCEDURAL:
+ draw_call_single_do(shgroup,
+ &state,
+ cmd->procedural.batch,
+ cmd->procedural.handle,
+ 0,
+ cmd->procedural.vert_count,
+ 1);
+ break;
+ case DRW_CMD_DRAW_INSTANCE:
+ draw_call_single_do(shgroup,
+ &state,
+ cmd->instance.batch,
+ cmd->instance.handle,
+ 0,
+ 0,
+ cmd->instance.inst_count);
+ break;
+ case DRW_CMD_DRAW_RANGE:
+ draw_call_single_do(shgroup,
+ &state,
+ cmd->range.batch,
+ (DRWResourceHandle)0,
+ cmd->range.vert_first,
+ cmd->range.vert_count,
+ 1);
+ break;
}
-
- draw_geometry_execute(
- shgroup, call->batch, call->vert_first, call->vert_count, 0, call->inst_count);
}
- /* Reset state */
- glFrontFace(GL_CCW);
+
+ draw_call_batching_finish(shgroup, &state);
}
if (use_tfeedback) {
@@ -1049,6 +1403,17 @@ static void drw_draw_pass_ex(DRWPass *pass,
DST.shader = NULL;
}
+ if (DST.batch) {
+ DST.batch->program_in_use = false;
+ DST.batch = NULL;
+ }
+
+ /* Fix T67342 for some reason. AMD Pro driver bug. */
+ if ((DST.state & DRW_STATE_BLEND_CUSTOM) != 0 &&
+ GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_OFFICIAL)) {
+ drw_state_set(DST.state & ~DRW_STATE_BLEND_CUSTOM);
+ }
+
/* HACK: Rasterized discard can affect clear commands which are not
* part of a DRWPass (as of now). So disable rasterized discard here
* if it has been enabled. */
diff --git a/source/blender/draw/intern/draw_manager_profiling.c b/source/blender/draw/intern/draw_manager_profiling.c
index bab69cf7a57..76382132230 100644
--- a/source/blender/draw/intern/draw_manager_profiling.c
+++ b/source/blender/draw/intern/draw_manager_profiling.c
@@ -63,7 +63,7 @@ static struct DRWTimerPool {
void DRW_stats_free(void)
{
if (DTP.timers != NULL) {
- for (int i = 0; i < DTP.timer_count; ++i) {
+ for (int i = 0; i < DTP.timer_count; i++) {
DRWTimer *timer = &DTP.timers[i];
glDeleteQueries(2, timer->query);
}
@@ -169,7 +169,7 @@ void DRW_stats_reset(void)
GLuint64 lvl_time[MAX_NESTED_TIMER] = {0};
/* Swap queries for the next frame and sum up each lvl time. */
- for (int i = DTP.timer_increment - 1; i >= 0; --i) {
+ for (int i = DTP.timer_increment - 1; i >= 0; i--) {
DRWTimer *timer = &DTP.timers[i];
SWAP(GLuint, timer->query[0], timer->query[1]);
@@ -323,7 +323,7 @@ void DRW_stats_draw(const rcti *rect)
BLI_strncpy(stat_string, "GPU Render Timings", sizeof(stat_string));
draw_stat(rect, 0, v++, stat_string, sizeof(stat_string));
- for (int i = 0; i < DTP.timer_increment; ++i) {
+ for (int i = 0; i < DTP.timer_increment; i++) {
double time_ms, time_percent;
DRWTimer *timer = &DTP.timers[i];
DRWTimer *timer_parent = (timer->lvl > 0) ? &DTP.timers[lvl_index[timer->lvl - 1]] : NULL;
diff --git a/source/blender/draw/modes/edit_armature_mode.c b/source/blender/draw/modes/edit_armature_mode.c
index dfe5a4b7a2f..20195b7d9f9 100644
--- a/source/blender/draw/modes/edit_armature_mode.c
+++ b/source/blender/draw/modes/edit_armature_mode.c
@@ -74,7 +74,7 @@ static void EDIT_ARMATURE_cache_init(void *vedata)
}
stl->g_data->transparent_bones = (draw_ctx->v3d->shading.type == OB_WIRE);
- for (int i = 0; i < 2; ++i) {
+ for (int i = 0; i < 2; i++) {
/* Solid bones */
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK;
psl->bone_solid[i] = DRW_pass_create("Bone Solid Pass", state | DRW_STATE_WRITE_DEPTH);
diff --git a/source/blender/draw/modes/edit_curve_mode.c b/source/blender/draw/modes/edit_curve_mode.c
index e68e03c2438..afaaba0712f 100644
--- a/source/blender/draw/modes/edit_curve_mode.c
+++ b/source/blender/draw/modes/edit_curve_mode.c
@@ -126,7 +126,7 @@ static void EDIT_CURVE_engine_init(void *UNUSED(vedata))
datatoc_edit_curve_overlay_normals_vert_glsl,
NULL},
.frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, "#define IN_PLACE_INSTANCES\n", NULL},
});
}
@@ -270,7 +270,7 @@ static void EDIT_CURVE_cache_populate(void *vedata, Object *ob)
geom = DRW_cache_curve_edge_wire_get(ob);
if (geom) {
- DRW_shgroup_call(wire_shgrp, geom, ob);
+ DRW_shgroup_call_no_cull(wire_shgrp, geom, ob);
}
if ((cu->flag & CU_3D) && (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_NORMALS) != 0) {
@@ -280,12 +280,12 @@ static void EDIT_CURVE_cache_populate(void *vedata, Object *ob)
geom = DRW_cache_curve_edge_overlay_get(ob);
if (geom) {
- DRW_shgroup_call(stl->g_data->overlay_edge_shgrp, geom, ob);
+ DRW_shgroup_call_no_cull(stl->g_data->overlay_edge_shgrp, geom, ob);
}
geom = DRW_cache_curve_vert_overlay_get(ob, stl->g_data->show_handles);
if (geom) {
- DRW_shgroup_call(stl->g_data->overlay_vert_shgrp, geom, ob);
+ DRW_shgroup_call_no_cull(stl->g_data->overlay_vert_shgrp, geom, ob);
}
}
}
@@ -294,12 +294,12 @@ static void EDIT_CURVE_cache_populate(void *vedata, Object *ob)
if (BKE_object_is_in_editmode(ob)) {
struct GPUBatch *geom = DRW_cache_curve_edge_overlay_get(ob);
if (geom) {
- DRW_shgroup_call(stl->g_data->overlay_edge_shgrp, geom, ob);
+ DRW_shgroup_call_no_cull(stl->g_data->overlay_edge_shgrp, geom, ob);
}
geom = DRW_cache_curve_vert_overlay_get(ob, false);
if (geom) {
- DRW_shgroup_call(stl->g_data->overlay_vert_shgrp, geom, ob);
+ DRW_shgroup_call_no_cull(stl->g_data->overlay_vert_shgrp, geom, ob);
}
}
}
diff --git a/source/blender/draw/modes/edit_mesh_mode.c b/source/blender/draw/modes/edit_mesh_mode.c
index f8247d7929e..30fb6c9845c 100644
--- a/source/blender/draw/modes/edit_mesh_mode.c
+++ b/source/blender/draw/modes/edit_mesh_mode.c
@@ -23,8 +23,6 @@
#include "DRW_engine.h"
#include "DRW_render.h"
-#include "GPU_extensions.h"
-
#include "DNA_mesh_types.h"
#include "DNA_view3d_types.h"
@@ -91,7 +89,6 @@ typedef struct EDIT_MESH_PassList {
typedef struct EDIT_MESH_FramebufferList {
struct GPUFrameBuffer *occlude_wire_fb;
- struct GPUFrameBuffer *ghost_wire_fb;
} EDIT_MESH_FramebufferList;
typedef struct EDIT_MESH_StorageList {
@@ -106,8 +103,6 @@ typedef struct EDIT_MESH_Data {
EDIT_MESH_StorageList *stl;
} EDIT_MESH_Data;
-#define MAX_SHADERS 16
-
/** Can only contain shaders (freed as array). */
typedef struct EDIT_MESH_Shaders {
/* weight */
@@ -161,12 +156,6 @@ typedef struct EDIT_MESH_PrivateData {
EDIT_MESH_ComponentShadingGroupList edit_shgrps;
EDIT_MESH_ComponentShadingGroupList edit_in_front_shgrps;
- DRWShadingGroup *vert_shgrp_in_front;
- DRWShadingGroup *edge_shgrp_in_front;
- DRWShadingGroup *face_shgrp_in_front;
- DRWShadingGroup *face_cage_shgrp_in_front;
- DRWShadingGroup *facedot_shgrp_in_front;
-
DRWShadingGroup *facefill_occluded_shgrp;
DRWShadingGroup *facefill_occluded_cage_shgrp;
DRWShadingGroup *mesh_analysis_shgrp;
@@ -459,7 +448,12 @@ static void EDIT_MESH_cache_init(void *vedata)
}
if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGES) == 0) {
if ((tsettings->selectmode & SCE_SELECT_EDGE) == 0) {
- g_data->do_edges = false;
+ if ((v3d->shading.type < OB_SOLID) || (v3d->shading.flag & V3D_SHADING_XRAY)) {
+ /* Special case, when drawing wire, draw edges, see: T67637. */
+ }
+ else {
+ g_data->do_edges = false;
+ }
}
}
if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CREASES) == 0) {
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c
index 06e5b521514..05a915185df 100644
--- a/source/blender/draw/modes/object_mode.c
+++ b/source/blender/draw/modes/object_mode.c
@@ -234,6 +234,7 @@ typedef struct OBJECT_ShadingGroupList {
/* Helpers */
DRWCallBuffer *relationship_lines;
DRWCallBuffer *constraint_lines;
+ DRWCallBuffer *origin_xform;
/* Camera */
DRWCallBuffer *camera;
@@ -285,15 +286,10 @@ typedef struct OBJECT_PrivateData {
DRWShadingGroup *outlines_transform;
/* Lightprobes */
- DRWCallBuffer *lightprobes_cube_select;
- DRWCallBuffer *lightprobes_cube_select_dupli;
- DRWCallBuffer *lightprobes_cube_active;
- DRWCallBuffer *lightprobes_cube_transform;
-
- DRWCallBuffer *lightprobes_planar_select;
- DRWCallBuffer *lightprobes_planar_select_dupli;
- DRWCallBuffer *lightprobes_planar_active;
- DRWCallBuffer *lightprobes_planar_transform;
+ DRWShadingGroup *probe_outlines_transform;
+ DRWShadingGroup *probe_outlines_select;
+ DRWShadingGroup *probe_outlines_select_dupli;
+ DRWShadingGroup *probe_outlines_active;
/* Objects Centers */
DRWCallBuffer *center_active;
@@ -302,17 +298,6 @@ typedef struct OBJECT_PrivateData {
DRWCallBuffer *center_selected_lib;
DRWCallBuffer *center_deselected_lib;
- /* Outlines id offset (accessed as an array) */
- int id_ofs_active;
- int id_ofs_select;
- int id_ofs_select_dupli;
- int id_ofs_transform;
-
- int id_ofs_prb_active;
- int id_ofs_prb_select;
- int id_ofs_prb_select_dupli;
- int id_ofs_prb_transform;
-
bool xray_enabled;
bool xray_enabled_and_not_wire;
} OBJECT_PrivateData; /* Transient data */
@@ -416,7 +401,10 @@ static void OBJECT_engine_init(void *vedata)
if (!sh_data->outline_resolve) {
/* Outline */
sh_data->outline_prepass = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, datatoc_gpu_shader_3D_vert_glsl, NULL},
+ .vert = (const char *[]){sh_cfg_data->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_object_outline_prepass_vert_glsl,
+ NULL},
.frag = (const char *[]){datatoc_object_outline_prepass_frag_glsl, NULL},
.defs = (const char *[]){sh_cfg_data->def, NULL},
});
@@ -430,7 +418,7 @@ static void OBJECT_engine_init(void *vedata)
datatoc_object_outline_prepass_geom_glsl,
NULL},
.frag = (const char *[]){datatoc_object_outline_prepass_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, "#define USE_GEOM\n", NULL},
});
sh_data->outline_resolve = DRW_shader_create_fullscreen(
@@ -538,10 +526,11 @@ static void OBJECT_engine_init(void *vedata)
/* Lightprobes */
sh_data->lightprobe_grid = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg_data->lib,
+ datatoc_common_view_lib_glsl,
datatoc_common_globals_lib_glsl,
datatoc_object_lightprobe_grid_vert_glsl,
NULL},
- .frag = (const char *[]){datatoc_gpu_shader_flat_id_frag_glsl, NULL},
+ .frag = (const char *[]){datatoc_object_outline_prepass_frag_glsl, NULL},
.defs = (const char *[]){sh_cfg_data->def, NULL},
});
@@ -696,12 +685,12 @@ static void OBJECT_engine_free(void)
}
static DRWShadingGroup *shgroup_outline(DRWPass *pass,
- const int *ofs,
+ int outline_id,
GPUShader *sh,
eGPUShaderConfig sh_cfg)
{
DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_int(grp, "baseId", ofs, 1);
+ DRW_shgroup_uniform_int_copy(grp, "outlineId", outline_id);
if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
@@ -740,128 +729,89 @@ static DRWShadingGroup *shgroup_points(DRWPass *pass,
return grp;
}
-static int *shgroup_theme_id_to_probe_outline_counter(OBJECT_StorageList *stl,
- int theme_id,
- const int base_flag)
-{
- if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
- switch (theme_id) {
- case TH_ACTIVE:
- case TH_SELECT:
- return &stl->g_data->id_ofs_prb_select_dupli;
- case TH_TRANSFORM:
- default:
- return &stl->g_data->id_ofs_prb_transform;
- }
- }
-
- switch (theme_id) {
- case TH_ACTIVE:
- return &stl->g_data->id_ofs_prb_active;
- case TH_SELECT:
- return &stl->g_data->id_ofs_prb_select;
- case TH_TRANSFORM:
- default:
- return &stl->g_data->id_ofs_prb_transform;
- }
-}
-
-static int *shgroup_theme_id_to_outline_counter(OBJECT_StorageList *stl,
- int theme_id,
- const int base_flag)
+static DRWShadingGroup *shgroup_theme_id_to_outline_or_null(OBJECT_StorageList *stl,
+ int theme_id,
+ const int base_flag)
{
if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
switch (theme_id) {
case TH_ACTIVE:
case TH_SELECT:
- return &stl->g_data->id_ofs_select_dupli;
+ return stl->g_data->outlines_select_dupli;
case TH_TRANSFORM:
+ return stl->g_data->outlines_transform;
default:
- return &stl->g_data->id_ofs_transform;
+ return NULL;
}
}
switch (theme_id) {
case TH_ACTIVE:
- return &stl->g_data->id_ofs_active;
- case TH_SELECT:
- return &stl->g_data->id_ofs_select;
- case TH_TRANSFORM:
- default:
- return &stl->g_data->id_ofs_transform;
- }
-}
-
-static DRWCallBuffer *buffer_theme_id_to_probe_planar_outline_shgrp(OBJECT_StorageList *stl,
- int theme_id)
-{
- /* does not increment counter */
- switch (theme_id) {
- case TH_ACTIVE:
- return stl->g_data->lightprobes_planar_active;
+ return stl->g_data->outlines_active;
case TH_SELECT:
- return stl->g_data->lightprobes_planar_select;
+ return stl->g_data->outlines_select;
case TH_TRANSFORM:
+ return stl->g_data->outlines_transform;
default:
- return stl->g_data->lightprobes_planar_transform;
+ return NULL;
}
}
-static DRWCallBuffer *buffer_theme_id_to_probe_cube_outline_shgrp(OBJECT_StorageList *stl,
+static DRWShadingGroup *shgroup_theme_id_to_probe_outline_or_null(OBJECT_StorageList *stl,
int theme_id,
const int base_flag)
{
- /* does not increment counter */
+ if (UNLIKELY(DRW_state_is_select())) {
+ return stl->g_data->probe_outlines_select;
+ }
+
if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
switch (theme_id) {
case TH_ACTIVE:
case TH_SELECT:
- return stl->g_data->lightprobes_cube_select_dupli;
+ return stl->g_data->probe_outlines_select_dupli;
case TH_TRANSFORM:
+ return stl->g_data->probe_outlines_transform;
default:
- return stl->g_data->lightprobes_cube_transform;
+ return NULL;
}
}
switch (theme_id) {
case TH_ACTIVE:
- return stl->g_data->lightprobes_cube_active;
+ return stl->g_data->probe_outlines_active;
case TH_SELECT:
- return stl->g_data->lightprobes_cube_select;
+ return stl->g_data->probe_outlines_select;
case TH_TRANSFORM:
+ return stl->g_data->probe_outlines_transform;
default:
- return stl->g_data->lightprobes_cube_transform;
+ return NULL;
}
}
-static DRWShadingGroup *shgroup_theme_id_to_outline_or_null(OBJECT_StorageList *stl,
- int theme_id,
- const int base_flag)
+static int shgroup_theme_id_to_outline_id(int theme_id, const int base_flag)
{
- int *counter = shgroup_theme_id_to_outline_counter(stl, theme_id, base_flag);
- *counter += 1;
-
if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
switch (theme_id) {
case TH_ACTIVE:
case TH_SELECT:
- return stl->g_data->outlines_select_dupli;
+ return 2;
case TH_TRANSFORM:
- return stl->g_data->outlines_transform;
+ return 0;
default:
- return NULL;
+ return -1;
}
}
switch (theme_id) {
case TH_ACTIVE:
- return stl->g_data->outlines_active;
+ return 3;
case TH_SELECT:
- return stl->g_data->outlines_select;
+ return 1;
case TH_TRANSFORM:
- return stl->g_data->outlines_transform;
+ return 0;
default:
- return NULL;
+ return -1;
}
}
@@ -1345,7 +1295,8 @@ static void OBJECT_cache_init(void *vedata)
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
OBJECT_PrivateData *g_data;
const DRWContextState *draw_ctx = DRW_context_state_get();
- OBJECT_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ eGPUShaderConfig cfg = draw_ctx->sh_cfg;
+ OBJECT_Shaders *sh_data = &e_data.sh_data[cfg];
const float outline_width = UI_GetThemeValuef(TH_OUTLINE_WIDTH);
const bool do_outline_expand = (U.pixelsize > 1.0) || (outline_width > 2.0f);
@@ -1366,59 +1317,25 @@ static void OBJECT_cache_init(void *vedata)
{
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- psl->outlines = DRW_pass_create("Outlines Depth Pass", state);
+ psl->lightprobes = DRW_pass_create("Outlines Probe Pass", state);
GPUShader *sh = sh_data->outline_prepass;
+ g_data->probe_outlines_transform = shgroup_outline(psl->lightprobes, 0, sh, cfg);
+ g_data->probe_outlines_select = shgroup_outline(psl->lightprobes, 1, sh, cfg);
+ g_data->probe_outlines_select_dupli = shgroup_outline(psl->lightprobes, 2, sh, cfg);
+ g_data->probe_outlines_active = shgroup_outline(psl->lightprobes, 3, sh, cfg);
+
+ psl->outlines = DRW_pass_create("Outlines Depth Pass", state);
+
if (g_data->xray_enabled_and_not_wire) {
sh = sh_data->outline_prepass_wire;
}
- g_data->outlines_select = shgroup_outline(
- psl->outlines, &g_data->id_ofs_select, sh, draw_ctx->sh_cfg);
- g_data->outlines_select_dupli = shgroup_outline(
- psl->outlines, &g_data->id_ofs_select_dupli, sh, draw_ctx->sh_cfg);
- g_data->outlines_transform = shgroup_outline(
- psl->outlines, &g_data->id_ofs_transform, sh, draw_ctx->sh_cfg);
- g_data->outlines_active = shgroup_outline(
- psl->outlines, &g_data->id_ofs_active, sh, draw_ctx->sh_cfg);
-
- g_data->id_ofs_select = 0;
- g_data->id_ofs_select_dupli = 0;
- g_data->id_ofs_active = 0;
- g_data->id_ofs_transform = 0;
- }
-
- {
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- DRWPass *pass = psl->lightprobes = DRW_pass_create("Object Probe Pass", state);
- struct GPUBatch *sphere = DRW_cache_sphere_get();
- struct GPUBatch *quad = DRW_cache_quad_get();
-
- /* Cubemap */
- g_data->lightprobes_cube_select = buffer_instance_outline(
- pass, sphere, &g_data->id_ofs_prb_select, draw_ctx->sh_cfg);
- g_data->lightprobes_cube_select_dupli = buffer_instance_outline(
- pass, sphere, &g_data->id_ofs_prb_select_dupli, draw_ctx->sh_cfg);
- g_data->lightprobes_cube_active = buffer_instance_outline(
- pass, sphere, &g_data->id_ofs_prb_active, draw_ctx->sh_cfg);
- g_data->lightprobes_cube_transform = buffer_instance_outline(
- pass, sphere, &g_data->id_ofs_prb_transform, draw_ctx->sh_cfg);
-
- /* Planar */
- g_data->lightprobes_planar_select = buffer_instance_outline(
- pass, quad, &g_data->id_ofs_prb_select, draw_ctx->sh_cfg);
- g_data->lightprobes_planar_select_dupli = buffer_instance_outline(
- pass, quad, &g_data->id_ofs_prb_select_dupli, draw_ctx->sh_cfg);
- g_data->lightprobes_planar_active = buffer_instance_outline(
- pass, quad, &g_data->id_ofs_prb_active, draw_ctx->sh_cfg);
- g_data->lightprobes_planar_transform = buffer_instance_outline(
- pass, quad, &g_data->id_ofs_prb_transform, draw_ctx->sh_cfg);
-
- g_data->id_ofs_prb_select = 0;
- g_data->id_ofs_prb_select_dupli = 0;
- g_data->id_ofs_prb_active = 0;
- g_data->id_ofs_prb_transform = 0;
+ g_data->outlines_transform = shgroup_outline(psl->outlines, 0, sh, cfg);
+ g_data->outlines_select = shgroup_outline(psl->outlines, 1, sh, cfg);
+ g_data->outlines_select_dupli = shgroup_outline(psl->outlines, 2, sh, cfg);
+ g_data->outlines_active = shgroup_outline(psl->outlines, 3, sh, cfg);
}
{
@@ -1437,7 +1354,6 @@ static void OBJECT_cache_init(void *vedata)
DRW_shgroup_uniform_texture_ref(grp, "sceneDepth", &dtxl->depth);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_float_copy(grp, "alphaOcclu", alphaOcclu);
- DRW_shgroup_uniform_int(grp, "idOffsets", &stl->g_data->id_ofs_active, 4);
DRW_shgroup_call(grp, quad, NULL);
/* This is the bleed pass if do_outline_expand is false. */
@@ -1516,7 +1432,7 @@ static void OBJECT_cache_init(void *vedata)
psl->camera_images_front = DRW_pass_create("Camera Images Front", state);
}
- for (int i = 0; i < 2; ++i) {
+ for (int i = 0; i < 2; i++) {
OBJECT_ShadingGroupList *sgl = (i == 1) ? &stl->g_data->sgl_ghost : &stl->g_data->sgl;
/* Solid bones */
@@ -1539,7 +1455,7 @@ static void OBJECT_cache_init(void *vedata)
sgl->bone_axes = psl->bone_axes[i] = DRW_pass_create("Bone Axes Pass", state);
}
- for (int i = 0; i < 2; ++i) {
+ for (int i = 0; i < 2; i++) {
OBJECT_ShadingGroupList *sgl = (i == 1) ? &stl->g_data->sgl_ghost : &stl->g_data->sgl;
/* Non Meshes Pass (Camera, empties, lights ...) */
@@ -1735,6 +1651,16 @@ static void OBJECT_cache_init(void *vedata)
sgl->constraint_lines = buffer_dynlines_dashed_uniform_color(
sgl->non_meshes, gb->colorGridAxisZ, draw_ctx->sh_cfg);
+ {
+ DRWShadingGroup *grp_axes;
+ sgl->origin_xform = buffer_instance_color_axes(
+ sgl->non_meshes, DRW_cache_bone_arrows_get(), &grp_axes, draw_ctx->sh_cfg);
+
+ DRW_shgroup_state_disable(grp_axes, DRW_STATE_DEPTH_LESS_EQUAL);
+ DRW_shgroup_state_enable(grp_axes, DRW_STATE_DEPTH_ALWAYS);
+ DRW_shgroup_state_enable(grp_axes, DRW_STATE_WIRE_SMOOTH);
+ }
+
/* Force Field Curve Guide End (here because of stipple) */
/* TODO port to shader stipple */
geom = DRW_cache_screenspace_circle_get();
@@ -1954,9 +1880,10 @@ static void DRW_shgroup_light(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLaye
}
if (la->mode & LA_SHOW_CONE) {
-
- DRW_buffer_add_entry(sgl->light_spot_volume_rect, cone_inside, &one, shapemat);
- DRW_buffer_add_entry(sgl->light_spot_volume_rect_outside, cone_outside, &one, shapemat);
+ if (!DRW_state_is_select()) {
+ DRW_buffer_add_entry(sgl->light_spot_volume_rect, cone_inside, &one, shapemat);
+ DRW_buffer_add_entry(sgl->light_spot_volume_rect_outside, cone_outside, &one, shapemat);
+ }
}
}
else {
@@ -1970,8 +1897,10 @@ static void DRW_shgroup_light(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLaye
}
if (la->mode & LA_SHOW_CONE) {
- DRW_buffer_add_entry(sgl->light_spot_volume, cone_inside, &one, shapemat);
- DRW_buffer_add_entry(sgl->light_spot_volume_outside, cone_outside, &one, shapemat);
+ if (!DRW_state_is_select()) {
+ DRW_buffer_add_entry(sgl->light_spot_volume, cone_inside, &one, shapemat);
+ DRW_buffer_add_entry(sgl->light_spot_volume_outside, cone_outside, &one, shapemat);
+ }
}
}
@@ -2143,7 +2072,7 @@ static void camera_view3d_stereoscopy_display_extra(OBJECT_ShadingGroupList *sgl
static float one = 1.0f;
float plane_mat[4][4], scale_mat[4][4];
float scale_factor[3] = {1.0f, 1.0f, 1.0f};
- float color_plane[2][4] = {
+ const float color_plane[2][4] = {
{0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha},
{0.0f, 0.0f, 0.0f, 1.0f},
};
@@ -2169,7 +2098,7 @@ static void camera_view3d_stereoscopy_display_extra(OBJECT_ShadingGroupList *sgl
/* Draw convergence volume. */
if (is_stereo3d_volume && !is_select) {
static float one = 1.0f;
- float color_volume[3][4] = {
+ const float color_volume[3][4] = {
{0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha},
{1.0f, 0.0f, 0.0f, v3d->stereo3d_volume_alpha},
{0.0f, 0.0f, 0.0f, 1.0f},
@@ -2295,7 +2224,7 @@ static void camera_view3d_reconstruction(OBJECT_ShadingGroupList *sgl,
DRW_shgroup_empty_ex(sgl, bundle_mat, &v3d->bundle_size, v3d->bundle_drawtype, color);
}
- float bundle_color_v4[4] = {
+ const float bundle_color_v4[4] = {
bundle_color[0],
bundle_color[1],
bundle_color[2],
@@ -2755,15 +2684,6 @@ static void DRW_shgroup_speaker(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLa
DRW_buffer_add_entry(sgl->speaker, color, &one, ob->obmat);
}
-typedef struct OBJECT_LightProbeEngineData {
- DrawData dd;
-
- float increment_x[3];
- float increment_y[3];
- float increment_z[3];
- float corner[3];
-} OBJECT_LightProbeEngineData;
-
static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data,
OBJECT_StorageList *stl,
OBJECT_PassList *psl,
@@ -2780,13 +2700,10 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data,
OBJECT_ShadingGroupList *sgl = (ob->dtx & OB_DRAWXRAY) ? &stl->g_data->sgl_ghost :
&stl->g_data->sgl;
- OBJECT_LightProbeEngineData *prb_data = (OBJECT_LightProbeEngineData *)DRW_drawdata_ensure(
- &ob->id, &draw_engine_object_type, sizeof(OBJECT_LightProbeEngineData), NULL, NULL);
-
if (DRW_state_is_select() || do_outlines) {
- int *call_id = shgroup_theme_id_to_probe_outline_counter(stl, theme_id, ob->base_flag);
-
if (prb->type == LIGHTPROBE_TYPE_GRID) {
+ float corner[3];
+ float increment[3][3];
/* Update transforms */
float cell_dim[3], half_cell_dim[3];
cell_dim[0] = 2.0f / (float)(prb->grid_resolution_x);
@@ -2796,65 +2713,41 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data,
mul_v3_v3fl(half_cell_dim, cell_dim, 0.5f);
/* First cell. */
- copy_v3_fl(prb_data->corner, -1.0f);
- add_v3_v3(prb_data->corner, half_cell_dim);
- mul_m4_v3(ob->obmat, prb_data->corner);
+ copy_v3_fl(corner, -1.0f);
+ add_v3_v3(corner, half_cell_dim);
+ mul_m4_v3(ob->obmat, corner);
/* Opposite neighbor cell. */
- copy_v3_fl3(prb_data->increment_x, cell_dim[0], 0.0f, 0.0f);
- add_v3_v3(prb_data->increment_x, half_cell_dim);
- add_v3_fl(prb_data->increment_x, -1.0f);
- mul_m4_v3(ob->obmat, prb_data->increment_x);
- sub_v3_v3(prb_data->increment_x, prb_data->corner);
-
- copy_v3_fl3(prb_data->increment_y, 0.0f, cell_dim[1], 0.0f);
- add_v3_v3(prb_data->increment_y, half_cell_dim);
- add_v3_fl(prb_data->increment_y, -1.0f);
- mul_m4_v3(ob->obmat, prb_data->increment_y);
- sub_v3_v3(prb_data->increment_y, prb_data->corner);
-
- copy_v3_fl3(prb_data->increment_z, 0.0f, 0.0f, cell_dim[2]);
- add_v3_v3(prb_data->increment_z, half_cell_dim);
- add_v3_fl(prb_data->increment_z, -1.0f);
- mul_m4_v3(ob->obmat, prb_data->increment_z);
- sub_v3_v3(prb_data->increment_z, prb_data->corner);
+ copy_v3_fl3(increment[0], cell_dim[0], 0.0f, 0.0f);
+ copy_v3_fl3(increment[1], 0.0f, cell_dim[1], 0.0f);
+ copy_v3_fl3(increment[2], 0.0f, 0.0f, cell_dim[2]);
+
+ for (int i = 0; i < 3; i++) {
+ add_v3_v3(increment[i], half_cell_dim);
+ add_v3_fl(increment[i], -1.0f);
+ mul_m4_v3(ob->obmat, increment[i]);
+ sub_v3_v3(increment[i], corner);
+ }
+ int outline_id = shgroup_theme_id_to_outline_id(theme_id, ob->base_flag);
uint cell_count = prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z;
DRWShadingGroup *grp = DRW_shgroup_create(sh_data->lightprobe_grid, psl->lightprobes);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_int_copy(grp, "call_id", *call_id);
- DRW_shgroup_uniform_int(grp, "baseId", call_id, 1); /* that's correct */
- DRW_shgroup_uniform_vec3(grp, "corner", prb_data->corner, 1);
- DRW_shgroup_uniform_vec3(grp, "increment_x", prb_data->increment_x, 1);
- DRW_shgroup_uniform_vec3(grp, "increment_y", prb_data->increment_y, 1);
- DRW_shgroup_uniform_vec3(grp, "increment_z", prb_data->increment_z, 1);
- DRW_shgroup_uniform_ivec3(grp, "grid_resolution", &prb->grid_resolution_x, 1);
+ DRW_shgroup_uniform_int_copy(grp, "outlineId", outline_id);
+ DRW_shgroup_uniform_vec3_copy(grp, "corner", corner);
+ DRW_shgroup_uniform_vec3_copy(grp, "increment_x", increment[0]);
+ DRW_shgroup_uniform_vec3_copy(grp, "increment_y", increment[1]);
+ DRW_shgroup_uniform_vec3_copy(grp, "increment_z", increment[2]);
+ DRW_shgroup_uniform_ivec3_copy(grp, "grid_resolution", &prb->grid_resolution_x);
if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
}
DRW_shgroup_call_procedural_points(grp, NULL, cell_count);
- *call_id += 1;
}
- else if (prb->type == LIGHTPROBE_TYPE_CUBE) {
- float draw_size = 1.0f;
- float probe_cube_mat[4][4];
- // prb_data->draw_size = prb->data_draw_size * 0.1f;
- // unit_m4(prb_data->probe_cube_mat);
- // copy_v3_v3(prb_data->probe_cube_mat[3], ob->obmat[3]);
-
- DRWCallBuffer *buf = buffer_theme_id_to_probe_cube_outline_shgrp(
+ else if (prb->type == LIGHTPROBE_TYPE_PLANAR && (prb->flag & LIGHTPROBE_FLAG_SHOW_DATA)) {
+ DRWShadingGroup *grp = shgroup_theme_id_to_probe_outline_or_null(
stl, theme_id, ob->base_flag);
- /* TODO remove or change the drawing of the cube probes. This line draws nothing on purpose
- * to keep the call ids correct. */
- zero_m4(probe_cube_mat);
- DRW_buffer_add_entry(buf, call_id, &draw_size, probe_cube_mat);
- *call_id += 1;
- }
- else if (prb->flag & LIGHTPROBE_FLAG_SHOW_DATA) {
- float draw_size = 1.0f;
- DRWCallBuffer *buf = buffer_theme_id_to_probe_planar_outline_shgrp(stl, theme_id);
- DRW_buffer_add_entry(buf, call_id, &draw_size, ob->obmat);
- *call_id += 1;
+ DRW_shgroup_call_no_cull(grp, DRW_cache_quad_get(), ob);
}
}
@@ -2971,7 +2864,7 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data,
{0.0, 0.0, 0.0, 1.0}},
};
- for (int i = 0; i < 6; ++i) {
+ for (int i = 0; i < 6; i++) {
float clipmat[4][4];
normalize_m4_m4(clipmat, ob->obmat);
mul_m4_m4m4(clipmat, clipmat, cubefacemat[i]);
@@ -3127,13 +3020,11 @@ static void DRW_shgroup_texture_space(OBJECT_ShadingGroupList *sgl, Object *ob,
switch (GS(ob_data->name)) {
case ID_ME:
- BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize);
+ BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, &texcosize);
break;
case ID_CU: {
Curve *cu = (Curve *)ob_data;
- if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_curve_texspace_calc(cu);
- }
+ BKE_curve_texspace_ensure(cu);
texcoloc = cu->loc;
texcosize = cu->size;
break;
@@ -3675,6 +3566,19 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
DRW_shgroup_bounds(sgl, ob, theme_id);
}
+ /* Helpers for when we're transforming origins. */
+ if (draw_ctx->object_mode == OB_MODE_OBJECT) {
+ if (scene->toolsettings->transform_flag & SCE_XFORM_DATA_ORIGIN) {
+ if (ob->base_flag & BASE_SELECTED) {
+ if (!DRW_state_is_select()) {
+ const float color[4] = {0.75, 0.75, 0.75, 0.5};
+ float axes_size = 1.0f;
+ DRW_buffer_add_entry(sgl->origin_xform, color, &axes_size, ob->obmat);
+ }
+ }
+ }
+ }
+
/* don't show object extras in set's */
if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) {
if ((draw_ctx->object_mode & (OB_MODE_ALL_PAINT | OB_MODE_ALL_PAINT_GPENCIL)) == 0) {
@@ -3685,7 +3589,7 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
DRW_shgroup_relationship_lines(sgl, draw_ctx->depsgraph, scene, ob);
}
- const bool draw_extra = (ob->dtx != 0);
+ const bool draw_extra = ob->dtx & (OB_DRAWNAME | OB_TEXSPACE | OB_DRAWBOUNDOX);
if (draw_extra && (theme_id == TH_UNDEFINED)) {
theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
}
@@ -3758,19 +3662,7 @@ static void OBJECT_draw_scene(void *vedata)
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
- int id_len_select = g_data->id_ofs_select;
- int id_len_select_dupli = g_data->id_ofs_select_dupli;
- int id_len_active = g_data->id_ofs_active;
- int id_len_transform = g_data->id_ofs_transform;
-
- int id_len_prb_select = g_data->id_ofs_prb_select;
- int id_len_prb_select_dupli = g_data->id_ofs_prb_select_dupli;
- int id_len_prb_active = g_data->id_ofs_prb_active;
- int id_len_prb_transform = g_data->id_ofs_prb_transform;
-
- int outline_calls = id_len_select + id_len_select_dupli + id_len_active + id_len_transform;
- outline_calls += id_len_prb_select + id_len_prb_select_dupli + id_len_prb_active +
- id_len_prb_transform;
+ int do_outlines = !DRW_pass_is_empty(psl->outlines) || !DRW_pass_is_empty(psl->lightprobes);
float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
@@ -3778,35 +3670,24 @@ static void OBJECT_draw_scene(void *vedata)
/* Don't draw Transparent passes in MSAA buffer. */
// DRW_draw_pass(psl->bone_envelope); /* Never drawn in Object mode currently. */
- DRW_draw_pass(stl->g_data->sgl.transp_shapes);
+ DRW_draw_pass(g_data->sgl.transp_shapes);
MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl);
- DRW_draw_pass(stl->g_data->sgl.bone_solid);
- DRW_draw_pass(stl->g_data->sgl.bone_wire);
- DRW_draw_pass(stl->g_data->sgl.bone_outline);
- DRW_draw_pass(stl->g_data->sgl.non_meshes);
+ DRW_draw_pass(g_data->sgl.bone_solid);
+ DRW_draw_pass(g_data->sgl.bone_wire);
+ DRW_draw_pass(g_data->sgl.bone_outline);
+ DRW_draw_pass(g_data->sgl.non_meshes);
DRW_draw_pass(psl->particle);
- DRW_draw_pass(stl->g_data->sgl.bone_axes);
+ DRW_draw_pass(g_data->sgl.bone_axes);
MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl);
- DRW_draw_pass(stl->g_data->sgl.image_empties);
+ DRW_draw_pass(g_data->sgl.image_empties);
- if (DRW_state_is_fbo() && outline_calls > 0) {
+ if (DRW_state_is_fbo() && do_outlines) {
DRW_stats_group_start("Outlines");
- g_data->id_ofs_active = 1;
- g_data->id_ofs_select = g_data->id_ofs_active + id_len_active + id_len_prb_active + 1;
- g_data->id_ofs_select_dupli = g_data->id_ofs_select + id_len_select + id_len_prb_select + 1;
- g_data->id_ofs_transform = g_data->id_ofs_select_dupli + id_len_select_dupli +
- id_len_prb_select_dupli + 1;
-
- g_data->id_ofs_prb_active = g_data->id_ofs_active + id_len_active;
- g_data->id_ofs_prb_select = g_data->id_ofs_select + id_len_select;
- g_data->id_ofs_prb_select_dupli = g_data->id_ofs_select_dupli + id_len_select_dupli;
- g_data->id_ofs_prb_transform = g_data->id_ofs_transform + id_len_transform;
-
/* Render filled polygon on a separate framebuffer */
GPU_framebuffer_bind(fbl->outlines_fb);
GPU_framebuffer_clear_color_depth(fbl->outlines_fb, clearcol, 1.0f);
@@ -3841,7 +3722,7 @@ static void OBJECT_draw_scene(void *vedata)
}
/* Combine with scene buffer last */
- if (outline_calls > 0) {
+ if (do_outlines) {
DRW_draw_pass(psl->outlines_resolve);
}
}
diff --git a/source/blender/draw/modes/overlay_mode.c b/source/blender/draw/modes/overlay_mode.c
index a5b1133abf4..9106e89663d 100644
--- a/source/blender/draw/modes/overlay_mode.c
+++ b/source/blender/draw/modes/overlay_mode.c
@@ -23,8 +23,6 @@
#include "DNA_mesh_types.h"
#include "DNA_view3d_types.h"
-#include "BIF_glutil.h"
-
#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_object.h"
@@ -77,7 +75,6 @@ typedef struct OVERLAY_PrivateData {
DRWShadingGroup *face_wires_shgrp;
DRWShadingGroup *face_wires_xray_shgrp;
DRWView *view_wires;
- BLI_mempool *wire_color_mempool;
View3DOverlay overlay;
float wire_step_param;
bool clear_stencil;
@@ -208,10 +205,6 @@ static void overlay_cache_init(void *vedata)
if (v3d->shading.type == OB_WIRE) {
g_data->overlay.flag |= V3D_OVERLAY_WIREFRAMES;
-
- if (ELEM(v3d->shading.wire_color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_RANDOM_COLOR)) {
- g_data->wire_color_mempool = BLI_mempool_create(sizeof(float[3]), 0, 512, 0);
- }
}
{
@@ -246,17 +239,11 @@ static void overlay_cache_init(void *vedata)
geometry_shader_uniforms(g_data->face_wires_shgrp);
geometry_shader_uniforms(g_data->face_wires_xray_shgrp);
}
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(g_data->face_wires_shgrp, DRW_STATE_CLIP_PLANES);
- DRW_shgroup_state_enable(g_data->face_wires_xray_shgrp, DRW_STATE_CLIP_PLANES);
- }
-
g_data->wire_step_param = stl->g_data->overlay.wireframe_threshold - 254.0f / 255.0f;
}
}
static void overlay_wire_color_get(const View3D *v3d,
- const OVERLAY_PrivateData *pd,
const Object *ob,
const bool use_coloring,
float **rim_col,
@@ -305,8 +292,10 @@ static void overlay_wire_color_get(const View3D *v3d,
if (v3d->shading.type == OB_WIRE) {
if (ELEM(v3d->shading.wire_color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_RANDOM_COLOR)) {
- *wire_col = BLI_mempool_alloc(pd->wire_color_mempool);
- *rim_col = BLI_mempool_alloc(pd->wire_color_mempool);
+ /* Theses stays valid until next call. So we need to copy them when using them as uniform. */
+ static float wire_col_val[3], rim_col_val[3];
+ *wire_col = wire_col_val;
+ *rim_col = rim_col_val;
if (v3d->shading.wire_color_type == V3D_SHADING_OBJECT_COLOR) {
linearrgb_to_srgb_v3_v3(*wire_col, ob->color);
@@ -400,7 +389,8 @@ static void overlay_cache_populate(void *vedata, Object *ob)
if ((!pd->show_overlays) ||
(((ob != draw_ctx->object_edit) && !is_edit_mode) || has_edit_mesh_cage) ||
ob->type != OB_MESH) {
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+ const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
const bool all_wires = (ob->dtx & OB_DRAW_ALL_EDGES);
const bool is_wire = (ob->dt < OB_SOLID);
const bool is_xray = (ob->dtx & OB_DRAWXRAY);
@@ -419,6 +409,10 @@ static void overlay_cache_populate(void *vedata, Object *ob)
shgrp = DRW_shgroup_create_sub(pd->face_wires_shgrp);
}
+ if (draw_ctx->rv3d->rflag & RV3D_CLIPPING) {
+ DRW_shgroup_state_enable(shgrp, DRW_STATE_CLIP_PLANES);
+ }
+
float wire_step_param = 10.0f;
if (!use_sculpt_pbvh) {
wire_step_param = (all_wires) ? 1.0f : pd->wire_step_param;
@@ -427,9 +421,9 @@ static void overlay_cache_populate(void *vedata, Object *ob)
if (!(DRW_state_is_select() || DRW_state_is_depth())) {
float *rim_col, *wire_col;
- overlay_wire_color_get(v3d, pd, ob, use_coloring, &rim_col, &wire_col);
- DRW_shgroup_uniform_vec3(shgrp, "wireColor", wire_col, 1);
- DRW_shgroup_uniform_vec3(shgrp, "rimColor", rim_col, 1);
+ overlay_wire_color_get(v3d, ob, use_coloring, &rim_col, &wire_col);
+ DRW_shgroup_uniform_vec3_copy(shgrp, "wireColor", wire_col);
+ DRW_shgroup_uniform_vec3_copy(shgrp, "rimColor", rim_col);
DRW_shgroup_stencil_mask(shgrp,
(is_xray && (is_wire || !pd->clear_stencil)) ? 0x00 : 0xFF);
}
@@ -506,12 +500,6 @@ static void overlay_draw_scene(void *vedata)
/* TODO(fclem): find a way to unify the multisample pass together
* (non meshes + armature + wireframe) */
MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl);
-
- /* XXX TODO(fclem) do not discard data after drawing! Store them per viewport. */
- if (stl->g_data->wire_color_mempool) {
- BLI_mempool_destroy(stl->g_data->wire_color_mempool);
- stl->g_data->wire_color_mempool = NULL;
- }
}
static void overlay_engine_free(void)
diff --git a/source/blender/draw/modes/pose_mode.c b/source/blender/draw/modes/pose_mode.c
index 3a5c87688fe..91e4e2335de 100644
--- a/source/blender/draw/modes/pose_mode.c
+++ b/source/blender/draw/modes/pose_mode.c
@@ -127,7 +127,7 @@ static void POSE_cache_init(void *vedata)
POSE_PrivateData *ppd = stl->g_data;
ppd->transparent_bones = (draw_ctx->v3d->shading.type == OB_WIRE);
- for (int i = 0; i < 2; ++i) {
+ for (int i = 0; i < 2; i++) {
/* Solid bones */
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK;
psl->bone_solid[i] = DRW_pass_create("Bone Solid Pass", state | DRW_STATE_WRITE_DEPTH);
diff --git a/source/blender/draw/modes/shaders/common_view_lib.glsl b/source/blender/draw/modes/shaders/common_view_lib.glsl
index 20a54947db7..76089d1ae41 100644
--- a/source/blender/draw/modes/shaders/common_view_lib.glsl
+++ b/source/blender/draw/modes/shaders/common_view_lib.glsl
@@ -1,4 +1,5 @@
#define COMMON_VIEW_LIB
+#define DRW_RESOURCE_CHUNK_LEN 512
/* keep in sync with DRWManager.view_data */
layout(std140) uniform viewBlock
@@ -23,8 +24,77 @@ layout(std140) uniform viewBlock
_world_clip_planes_calc_clip_distance(p, clipPlanes)
#endif
+uniform int resourceChunk;
+
+#ifdef GPU_VERTEX_SHADER
+# ifdef GL_ARB_shader_draw_parameters
+# define baseInstance gl_BaseInstanceARB
+# else /* no ARB_shader_draw_parameters */
+uniform int baseInstance;
+# endif
+
+# ifdef IN_PLACE_INSTANCES
+/* When drawing instances of an object at the same position. */
+# define instanceId 0
+# elif defined(GPU_DEPRECATED_AMD_DRIVER)
+/* A driver bug make it so that when using an attribute with GL_INT_2_10_10_10_REV as format,
+ * the gl_InstanceID is incremented by the 2 bit component of the attrib.
+ * Ignore gl_InstanceID then. */
+# define instanceId 0
+# else
+# define instanceId gl_InstanceID
+# endif
+
+# define resource_id (baseInstance + instanceId)
+
+/* Use this to declare and pass the value if
+ * the fragment shader uses the resource_id. */
+# define RESOURCE_ID_VARYING flat out int resourceIDFrag;
+# define RESOURCE_ID_VARYING_GEOM flat out int resourceIDGeom;
+# define PASS_RESOURCE_ID resourceIDFrag = resource_id;
+# define PASS_RESOURCE_ID_GEOM resourceIDGeom = resource_id;
+#endif
+
+/* If used in a fragment / geometry shader, we pass
+ * resource_id as varying. */
+#ifdef GPU_GEOMETRY_SHADER
+# define RESOURCE_ID_VARYING \
+ flat out int resourceIDFrag; \
+ flat in int resourceIDGeom[];
+
+# define resource_id resourceIDGeom
+# define PASS_RESOURCE_ID(i) resourceIDFrag = resource_id[i];
+#endif
+
+#ifdef GPU_FRAGMENT_SHADER
+flat in int resourceIDFrag;
+# define resource_id resourceIDFrag
+#endif
+
+#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && !defined(OS_MAC)
+struct ObjectMatrices {
+ mat4 drw_modelMatrix;
+ mat4 drw_modelMatrixInverse;
+};
+
+layout(std140) uniform modelBlock
+{
+ ObjectMatrices drw_matrices[DRW_RESOURCE_CHUNK_LEN];
+};
+
+# define ModelMatrix (drw_matrices[resource_id].drw_modelMatrix)
+# define ModelMatrixInverse (drw_matrices[resource_id].drw_modelMatrixInverse)
+
+#else /* GPU_INTEL */
+/* Intel GPU seems to suffer performance impact when the model matrix is in UBO storage.
+ * So for now we just force using the legacy path. */
+/* Note that this is also a workaround of a problem on osx (amd or nvidia)
+ * and older amd driver on windows. */
uniform mat4 ModelMatrix;
uniform mat4 ModelMatrixInverse;
+#endif
+
+#define resource_handle (resourceChunk * DRW_RESOURCE_CHUNK_LEN + resource_id)
/** Transform shortcuts. */
/* Rule of thumb: Try to reuse world positions and normals because converting though viewspace
diff --git a/source/blender/draw/modes/shaders/object_color_axes_vert.glsl b/source/blender/draw/modes/shaders/object_color_axes_vert.glsl
new file mode 100644
index 00000000000..239dec30c42
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_color_axes_vert.glsl
@@ -0,0 +1,35 @@
+
+uniform mat4 ViewProjectionMatrix;
+uniform vec3 screenVecs[3];
+
+/* ---- Instantiated Attrs ---- */
+in float axis; /* position on the axis. [0.0-1.0] is X axis, [1.0-2.0] is Y, etc... */
+in vec2 screenPos;
+in vec3 colorAxis;
+
+/* ---- Per instance Attrs ---- */
+in mat4 InstanceModelMatrix;
+in vec4 color;
+
+flat out vec4 finalColor;
+
+void main()
+{
+ float draw_size = 4.0;
+ vec3 chosen_axis = InstanceModelMatrix[int(axis)].xyz;
+ vec3 loc = InstanceModelMatrix[3].xyz;
+ vec3 wpos = loc + chosen_axis * fract(axis) * draw_size;
+ vec3 spos = screenVecs[0].xyz * screenPos.x + screenVecs[1].xyz * screenPos.y;
+ /* Scale uniformly by axis length */
+ spos *= length(chosen_axis) * draw_size;
+
+ vec4 pos_4d = vec4(wpos + spos, 1.0);
+ gl_Position = ViewProjectionMatrix * pos_4d;
+
+ finalColor.rgb = mix(colorAxis, color.rgb, color.a);
+ finalColor.a = 1.0;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(pos_4d.xyz);
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/object_empty_image_frag.glsl b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl
index 7dfbf469adc..e33aa6cdcc1 100644
--- a/source/blender/draw/modes/shaders/object_empty_image_frag.glsl
+++ b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl
@@ -37,9 +37,15 @@ void main()
if (depthMode == DEPTH_BACK) {
gl_FragDepth = 0.999999;
+#ifdef USE_WIRE
+ gl_FragDepth -= 1e-5;
+#endif
}
else if (depthMode == DEPTH_FRONT) {
gl_FragDepth = 0.000001;
+#ifdef USE_WIRE
+ gl_FragDepth -= 1e-5;
+#endif
}
else if (depthMode == DEPTH_UNCHANGED) {
gl_FragDepth = gl_FragCoord.z;
diff --git a/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl b/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
index d27d55c3fd6..144024a7d5d 100644
--- a/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
+++ b/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
@@ -1,18 +1,11 @@
-uniform mat4 ViewProjectionMatrix;
-
-uniform float sphere_size;
uniform ivec3 grid_resolution;
uniform vec3 corner;
uniform vec3 increment_x;
uniform vec3 increment_y;
uniform vec3 increment_z;
-uniform vec3 screen_vecs[2];
-
-uniform int call_id; /* we don't want the builtin callId which would be 0. */
-uniform int baseId;
-flat out uint finalId;
+flat out int objectId;
void main()
{
@@ -29,7 +22,8 @@ void main()
gl_Position = ViewProjectionMatrix * vec4(ws_cell_location, 1.0);
gl_PointSize = 2.0f;
- finalId = uint(baseId + call_id);
+ /* ID 0 is nothing (background) */
+ objectId = resource_handle + 1;
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(ws_cell_location);
diff --git a/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl b/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl
index 7668a0c2c94..7b86d477a39 100644
--- a/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl
+++ b/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl
@@ -7,30 +7,9 @@ uniform usampler2D outlineId;
uniform sampler2D outlineDepth;
uniform sampler2D sceneDepth;
-uniform int idOffsets[4];
-
uniform float alphaOcclu;
uniform vec2 viewportSize;
-vec4 convert_id_to_color(int id)
-{
- if (id == 0) {
- return vec4(0.0);
- }
- if (id < idOffsets[1]) {
- return colorActive;
- }
- else if (id < idOffsets[2]) {
- return colorSelect;
- }
- else if (id < idOffsets[3]) {
- return colorDupliSelect;
- }
- else {
- return colorTransform;
- }
-}
-
void main()
{
ivec2 texel = ivec2(gl_FragCoord.xy);
@@ -85,7 +64,24 @@ void main()
const float epsilon = 3.0 / 8388608.0;
bool occluded = (ref_depth > scene_depth + epsilon);
- FragColor = convert_id_to_color(int(ref_id));
+ /* WATCH: Keep in sync with outlineId of the prepass. */
+ uint color_id = ref_id >> 14u;
+ if (ref_id == 0u) {
+ FragColor = vec4(0.0);
+ }
+ else if (color_id == 1u) {
+ FragColor = colorSelect;
+ }
+ else if (color_id == 2u) {
+ FragColor = colorDupliSelect;
+ }
+ else if (color_id == 3u) {
+ FragColor = colorActive;
+ }
+ else {
+ FragColor = colorTransform;
+ }
+
FragColor.a *= (occluded) ? alphaOcclu : 1.0;
FragColor.a = (outline) ? FragColor.a : 0.0;
}
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl
index c3447456ea6..5d6c4881b5b 100644
--- a/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl
+++ b/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl
@@ -1,10 +1,18 @@
-uniform int callId;
-uniform int baseId;
+
+/* Should be 2 bits only [0..3]. */
+uniform int outlineId;
+
+flat in int objectId;
/* using uint because 16bit uint can contain more ids than int. */
out uint outId;
+/* Replace top 2 bits (of the 16bit output) by outlineId.
+ * This leaves 16K different IDs to create outlines between objects.
+ * SHIFT = (32 - (16 - 2)) */
+#define SHIFT 18u
+
void main()
{
- outId = uint(baseId + callId);
+ outId = (uint(outlineId) << 14u) | ((uint(objectId) << SHIFT) >> SHIFT);
}
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl
index 5a3eb38fb6b..b32913dcd60 100644
--- a/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl
+++ b/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl
@@ -2,12 +2,15 @@
layout(lines_adjacency) in;
layout(line_strip, max_vertices = 2) out;
-in vec4 pPos[];
in vec3 vPos[];
+in int objectId_g[];
+
+flat out int objectId;
void vert_from_gl_in(int v)
{
- gl_Position = pPos[v];
+ gl_Position = gl_in[v].gl_Position;
+ objectId = objectId_g[v];
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_set_clip_distance(gl_in[v].gl_ClipDistance);
#endif
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl
index e34afe95b5e..7740f9a4af2 100644
--- a/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl
+++ b/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl
@@ -1,16 +1,27 @@
in vec3 pos;
-out vec4 pPos;
+#ifdef USE_GEOM
out vec3 vPos;
+out int objectId_g;
+# define objectId objectId_g
+#else
+
+flat out int objectId;
+#endif
void main()
{
vec3 world_pos = point_object_to_world(pos);
+#ifdef USE_GEOM
vPos = point_world_to_view(world_pos);
- pPos = point_world_to_ndc(world_pos);
+#endif
+ gl_Position = point_world_to_ndc(world_pos);
/* Small bias to always be on top of the geom. */
- pPos.z -= 1e-3;
+ gl_Position.z -= 1e-3;
+
+ /* ID 0 is nothing (background) */
+ objectId = resource_handle + 1;
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
diff --git a/source/blender/draw/modes/shaders/paint_face_vert.glsl b/source/blender/draw/modes/shaders/paint_face_vert.glsl
index d135071c15c..af362f24a85 100644
--- a/source/blender/draw/modes/shaders/paint_face_vert.glsl
+++ b/source/blender/draw/modes/shaders/paint_face_vert.glsl
@@ -8,4 +8,4 @@ void main()
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
#endif
-} \ No newline at end of file
+}
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 7e913014a87..0fc137295d0 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -3114,6 +3114,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, gpl, ANIMTYPE_GPLAYER);
/* update other layer status */
BKE_gpencil_layer_setactive(gpd, gpl);
+ BKE_gpencil_layer_autolock_set(gpd, false);
}
/* Grease Pencil updates */
@@ -3338,7 +3339,7 @@ static void ANIM_OT_channel_select_keys(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Select Channel keyframes";
+ ot->name = "Select Channel Keyframes";
ot->idname = "ANIM_OT_channel_select_keys";
ot->description = "Select all keyframes of channel under mouse";
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index 7ab50afe3a1..40b2706cc75 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -442,7 +442,7 @@ static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, flo
}
else {
float step_size = (bezt->vec[1][0] - prev_bezt->vec[1][0]) / resol;
- for (int j = 0; j <= resol; ++j) {
+ for (int j = 0; j <= resol; j++) {
float eval_time = prev_bezt->vec[1][0] + step_size * j;
float eval_value = evaluate_fcurve_only_curve(fcu, eval_time);
max_coord = max_ff(max_coord, eval_value);
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index a78a63f1347..48493c9e961 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -630,9 +630,8 @@ static bAnimListElem *make_new_animlistelem(void *data,
/* do specifics */
switch (datatype) {
case ANIMTYPE_SUMMARY: {
- /* nothing to include for now... this is just a dummy wrappy around all the other channels
- * in the DopeSheet, and gets included at the start of the list
- */
+ /* Nothing to include for now... this is just a dummy wrapper around
+ * all the other channels in the DopeSheet, and gets included at the start of the list. */
ale->key_data = NULL;
ale->datatype = ALE_ALL;
break;
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index ded59466370..2a35acdefcb 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -486,7 +486,7 @@ static void draw_marker(
float name_y = UI_DPI_FAC * 18;
/* Give an offset to the marker name when selected,
* or when near the current frame (5 frames range, starting from the current one). */
- if ((marker->flag & SELECT) || (IN_RANGE_INCL(marker->frame, cfra, cfra - 4))) {
+ if ((marker->flag & SELECT) || (cfra - 4 <= marker->frame && marker->frame <= cfra)) {
name_y += UI_DPI_FAC * 10;
}
draw_marker_name(fstyle, marker, xpos, name_y);
diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c
index bd4886817cd..30bf837f6c0 100644
--- a/source/blender/editors/animation/anim_motion_paths.c
+++ b/source/blender/editors/animation/anim_motion_paths.c
@@ -36,6 +36,7 @@
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_query.h"
#include "GPU_batch.h"
@@ -67,6 +68,37 @@ typedef struct MPathTarget {
/* ........ */
+/* update scene for current frame */
+static void motionpaths_calc_update_scene(Main *bmain, struct Depsgraph *depsgraph)
+{
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+}
+
+Depsgraph *animviz_depsgraph_build(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ ListBase *targets)
+{
+ /* Allocate dependency graph. */
+ Depsgraph *depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_VIEWPORT);
+
+ /* Make a flat array of IDs for the DEG API. */
+ const int num_ids = BLI_listbase_count(targets);
+ ID **ids = MEM_malloc_arrayN(sizeof(ID *), num_ids, "animviz IDS");
+ int current_id_index = 0;
+ for (MPathTarget *mpt = targets->first; mpt != NULL; mpt = mpt->next) {
+ ids[current_id_index++] = &mpt->ob->id;
+ }
+
+ /* Build graph from all requested IDs. */
+ DEG_graph_build_from_ids(depsgraph, bmain, scene, view_layer, ids, num_ids);
+ MEM_freeN(ids);
+
+ /* Update once so we can access pointers of evaluated animation data. */
+ motionpaths_calc_update_scene(bmain, depsgraph);
+ return depsgraph;
+}
+
/* get list of motion paths to be baked for the given object
* - assumes the given list is ready to be used
*/
@@ -106,24 +138,6 @@ void animviz_get_object_motionpaths(Object *ob, ListBase *targets)
/* ........ */
-/* update scene for current frame */
-static void motionpaths_calc_update_scene(Main *bmain, struct Depsgraph *depsgraph)
-{
- /* Do all updates
- * - if this is too slow, resort to using a more efficient way
- * that doesn't force complete update, but for now, this is the
- * most accurate way!
- *
- * TODO(segey): Bring back partial updates, which became impossible
- * with the new depsgraph due to unsorted nature of bases.
- *
- * TODO(sergey): Use evaluation context dedicated to motion paths.
- */
- BKE_scene_graph_update_for_newframe(depsgraph, bmain);
-}
-
-/* ........ */
-
/* perform baking for the targets on the current frame */
static void motionpaths_calc_bake_targets(ListBase *targets, int cframe)
{
@@ -201,6 +215,135 @@ static void motionpaths_calc_bake_targets(ListBase *targets, int cframe)
}
}
+/* Get pointer to animviz settings for the given target. */
+static bAnimVizSettings *animviz_target_settings_get(MPathTarget *mpt)
+{
+ if (mpt->pchan != NULL) {
+ return &mpt->ob->pose->avs;
+ }
+ return &mpt->ob->avs;
+}
+
+static void motionpath_get_global_framerange(ListBase *targets, int *r_sfra, int *r_efra)
+{
+ *r_sfra = INT_MAX;
+ *r_efra = INT_MIN;
+ for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
+ *r_sfra = min_ii(*r_sfra, mpt->mpath->start_frame);
+ *r_efra = max_ii(*r_efra, mpt->mpath->end_frame);
+ }
+}
+
+static int motionpath_get_prev_keyframe(MPathTarget *mpt, DLRBT_Tree *fcu_keys, int current_frame)
+{
+ /* If the current frame is outside of the configured motion path range we ignore update of this
+ * motion path by using invalid frame range where start frame is above the end frame. */
+ if (current_frame <= mpt->mpath->start_frame) {
+ return INT_MAX;
+ }
+
+ float current_frame_float = current_frame;
+ DLRBT_Node *node = BLI_dlrbTree_search_prev(fcu_keys, compare_ak_cfraPtr, &current_frame_float);
+ if (node == NULL) {
+ return mpt->mpath->start_frame;
+ }
+
+ ActKeyColumn *key_data = (ActKeyColumn *)node;
+ return key_data->cfra;
+}
+
+static int motionpath_get_prev_prev_keyframe(MPathTarget *mpt,
+ DLRBT_Tree *fcu_keys,
+ int current_frame)
+{
+ int frame = motionpath_get_prev_keyframe(mpt, fcu_keys, current_frame);
+ return motionpath_get_prev_keyframe(mpt, fcu_keys, frame);
+}
+
+static int motionpath_get_next_keyframe(MPathTarget *mpt, DLRBT_Tree *fcu_keys, int current_frame)
+{
+ /* If the current frame is outside of the configured motion path range we ignore update of this
+ * motion path by using invalid frame range where start frame is above the end frame. */
+ if (current_frame >= mpt->mpath->end_frame) {
+ return INT_MIN;
+ }
+
+ float current_frame_float = current_frame;
+ DLRBT_Node *node = BLI_dlrbTree_search_next(fcu_keys, compare_ak_cfraPtr, &current_frame_float);
+ if (node == NULL) {
+ return mpt->mpath->end_frame;
+ }
+
+ ActKeyColumn *key_data = (ActKeyColumn *)node;
+ return key_data->cfra;
+}
+
+static int motionpath_get_next_next_keyframe(MPathTarget *mpt,
+ DLRBT_Tree *fcu_keys,
+ int current_frame)
+{
+ int frame = motionpath_get_next_keyframe(mpt, fcu_keys, current_frame);
+ return motionpath_get_next_keyframe(mpt, fcu_keys, frame);
+}
+
+static bool motionpath_check_can_use_keyframe_range(MPathTarget *UNUSED(mpt),
+ AnimData *adt,
+ ListBase *fcurve_list)
+{
+ if (adt == NULL || fcurve_list == NULL) {
+ return false;
+ }
+ /* NOTE: We might needed to do a full frame range update if there is a specific setup of NLA
+ * or drivers or modifiers on the f-curves. */
+ return true;
+}
+
+static void motionpath_calculate_update_range(MPathTarget *mpt,
+ AnimData *adt,
+ ListBase *fcurve_list,
+ int current_frame,
+ int *r_sfra,
+ int *r_efra)
+{
+ /* Similar to the case when there is only a single keyframe: need to update en entire range to
+ * a constant value. */
+ if (!motionpath_check_can_use_keyframe_range(mpt, adt, fcurve_list)) {
+ *r_sfra = mpt->mpath->start_frame;
+ *r_efra = mpt->mpath->end_frame;
+ return;
+ }
+
+ *r_sfra = INT_MAX;
+ *r_efra = INT_MIN;
+
+ /* NOTE: Iterate over individual f-curves, and check their keyframes individually and pick a
+ * widest range from them. This is because it's possible to have more narrow keyframe on a
+ * channel which wasn't edited.
+ * Could be optimized further by storing some flags about which channels has been modified so
+ * we ignore all others (which can potentially make an update range unnecessary wide). */
+ for (FCurve *fcu = fcurve_list->first; fcu != NULL; fcu = fcu->next) {
+ DLRBT_Tree fcu_keys;
+ BLI_dlrbTree_init(&fcu_keys);
+ fcurve_to_keylist(adt, fcu, &fcu_keys, 0);
+
+ int fcu_sfra = motionpath_get_prev_prev_keyframe(mpt, &fcu_keys, current_frame);
+ int fcu_efra = motionpath_get_next_next_keyframe(mpt, &fcu_keys, current_frame);
+
+ /* Extend range furher, since accelleration compensation propagates even further away. */
+ if (fcu->auto_smoothing != FCURVE_SMOOTH_NONE) {
+ fcu_sfra = motionpath_get_prev_prev_keyframe(mpt, &fcu_keys, fcu_sfra);
+ fcu_efra = motionpath_get_next_next_keyframe(mpt, &fcu_keys, fcu_efra);
+ }
+
+ if (fcu_sfra <= fcu_efra) {
+ *r_sfra = min_ii(*r_sfra, fcu_sfra);
+ *r_efra = max_ii(*r_efra, fcu_efra);
+ }
+
+ BLI_dlrbTree_free(&fcu_keys);
+ }
+}
+
/* Perform baking of the given object's and/or its bones' transforms to motion paths
* - scene: current scene
* - ob: object whose flagged motionpaths should get calculated
@@ -211,39 +354,36 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
Main *bmain,
Scene *scene,
ListBase *targets,
- bool restore,
- bool current_frame_only)
+ eAnimvizCalcRange range,
+ bool restore)
{
- /* sanity check */
+ /* Sanity check. */
if (ELEM(NULL, targets, targets->first)) {
return;
}
- /* Compute frame range to bake within.
- * TODO: this method could be improved...
- * 1) max range for standard baking
- * 2) minimum range for recalc baking (i.e. between keyframes, but how?) */
- int sfra = INT_MAX;
- int efra = INT_MIN;
-
- for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
- /* try to increase area to do (only as much as needed) */
- sfra = MIN2(sfra, mpt->mpath->start_frame);
- efra = MAX2(efra, mpt->mpath->end_frame);
- }
-
- if (efra <= sfra) {
- return;
- }
-
- /* Limit frame range if we are updating just the current frame. */
- /* set frame values */
- int cfra = CFRA;
- if (current_frame_only) {
- if (cfra < sfra || cfra > efra) {
- return;
- }
- sfra = efra = cfra;
+ const int cfra = CFRA;
+ int sfra = INT_MAX, efra = INT_MIN;
+ switch (range) {
+ case ANIMVIZ_CALC_RANGE_CURRENT_FRAME:
+ motionpath_get_global_framerange(targets, &sfra, &efra);
+ if (sfra > efra) {
+ return;
+ }
+ if (cfra < sfra || cfra > efra) {
+ return;
+ }
+ sfra = efra = cfra;
+ break;
+ case ANIMVIZ_CALC_RANGE_CHANGED:
+ /* Nothing to do here, will be handled later when iterating through the targets. */
+ break;
+ case ANIMVIZ_CALC_RANGE_FULL:
+ motionpath_get_global_framerange(targets, &sfra, &efra);
+ if (sfra > efra) {
+ return;
+ }
+ break;
}
/* get copies of objects/bones to get the calculated results from
@@ -271,16 +411,10 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
/* build list of all keyframes in active action for object or pchan */
BLI_dlrbTree_init(&mpt->keys);
+ ListBase *fcurve_list = NULL;
if (adt) {
- bAnimVizSettings *avs;
-
/* get pointer to animviz settings for each target */
- if (mpt->pchan) {
- avs = &mpt->ob->pose->avs;
- }
- else {
- avs = &mpt->ob->avs;
- }
+ bAnimVizSettings *avs = animviz_target_settings_get(mpt);
/* it is assumed that keyframes for bones are all grouped in a single group
* unless an option is set to always use the whole action
@@ -289,13 +423,28 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
bActionGroup *agrp = BKE_action_group_find_name(adt->action, mpt->pchan->name);
if (agrp) {
+ fcurve_list = &agrp->channels;
agroup_to_keylist(adt, agrp, &mpt->keys, 0);
}
}
else {
+ fcurve_list = &adt->action->curves;
action_to_keylist(adt, adt->action, &mpt->keys, 0);
}
}
+
+ if (range == ANIMVIZ_CALC_RANGE_CHANGED) {
+ int mpt_sfra, mpt_efra;
+ motionpath_calculate_update_range(mpt, adt, fcurve_list, cfra, &mpt_sfra, &mpt_efra);
+ if (mpt_sfra <= mpt_efra) {
+ sfra = min_ii(sfra, mpt_sfra);
+ efra = max_ii(efra, mpt_efra);
+ }
+ }
+ }
+
+ if (sfra > efra) {
+ return;
}
/* calculate path over requested range */
@@ -306,7 +455,7 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
efra,
efra - sfra + 1);
for (CFRA = sfra; CFRA <= efra; CFRA++) {
- if (current_frame_only) {
+ if (range == ANIMVIZ_CALC_RANGE_CURRENT_FRAME) {
/* For current frame, only update tagged. */
BKE_scene_graph_update_tagged(depsgraph, bmain);
}
@@ -324,7 +473,7 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
* may be a temporary one that works on a subset of the data.
* We always have to restore the current frame though. */
CFRA = cfra;
- if (!current_frame_only && restore) {
+ if (range != ANIMVIZ_CALC_RANGE_CURRENT_FRAME && restore) {
motionpaths_calc_update_scene(bmain, depsgraph);
}
@@ -334,16 +483,10 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
/* clear recalc flags from targets */
for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
- bAnimVizSettings *avs;
bMotionPath *mpath = mpt->mpath;
/* get pointer to animviz settings for each target */
- if (mpt->pchan) {
- avs = &mpt->ob->pose->avs;
- }
- else {
- avs = &mpt->ob->avs;
- }
+ bAnimVizSettings *avs = animviz_target_settings_get(mpt);
/* clear the flag requesting recalculation of targets */
avs->recalc &= ~ANIMVIZ_RECALC_PATHS;
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 7b9e6a10f44..61c8da08954 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -62,13 +62,11 @@
/* Get (or add relevant data to be able to do so) F-Curve from the driver stack,
* for the given Animation Data block. This assumes that all the destinations are valid.
- *
- * - add: 0 - don't add anything if not found,
- * 1 - add new Driver FCurve (with keyframes for visual tweaking),
- * 2 - add new Driver FCurve (with generator, for script backwards compatibility)
- * -1 - add new Driver FCurve without driver stuff (for pasting)
*/
-FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_index, short add)
+FCurve *verify_driver_fcurve(ID *id,
+ const char rna_path[],
+ const int array_index,
+ eDriverFCurveCreationMode creation_mode)
{
AnimData *adt;
FCurve *fcu;
@@ -80,7 +78,7 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
/* init animdata if none available yet */
adt = BKE_animdata_from_id(id);
- if ((adt == NULL) && (add)) {
+ if (adt == NULL && creation_mode != DRIVER_FCURVE_LOOKUP_ONLY) {
adt = BKE_animdata_add_id(id);
}
if (adt == NULL) {
@@ -94,9 +92,9 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
*/
fcu = list_find_fcurve(&adt->drivers, rna_path, array_index);
- if ((fcu == NULL) && (add)) {
+ if (fcu == NULL && creation_mode != DRIVER_FCURVE_LOOKUP_ONLY) {
/* use default settings to make a F-Curve */
- fcu = alloc_driver_fcurve(rna_path, array_index, add);
+ fcu = alloc_driver_fcurve(rna_path, array_index, creation_mode);
/* just add F-Curve to end of driver list */
BLI_addtail(&adt->drivers, fcu);
@@ -106,7 +104,9 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
return fcu;
}
-struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index, short add)
+struct FCurve *alloc_driver_fcurve(const char rna_path[],
+ const int array_index,
+ eDriverFCurveCreationMode creation_mode)
{
FCurve *fcu = MEM_callocN(sizeof(FCurve), "FCurve");
@@ -119,18 +119,12 @@ struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index,
}
fcu->array_index = array_index;
- /* If add is negative, don't init this data yet,
- * since it will be filled in by the pasted driver. */
- if (add > 0) {
- BezTriple *bezt;
- size_t i;
-
+ if (!ELEM(creation_mode, DRIVER_FCURVE_LOOKUP_ONLY, DRIVER_FCURVE_EMPTY)) {
/* add some new driver data */
fcu->driver = MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
/* F-Modifier or Keyframes? */
- // FIXME: replace these magic numbers with defines
- if (add == 2) {
+ if (creation_mode == DRIVER_FCURVE_GENERATOR) {
/* Python API Backwards compatibility hack:
* Create FModifier so that old scripts won't break
* for now before 2.7 series -- (September 4, 2013)
@@ -142,14 +136,10 @@ struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index,
* - These are configured to 0,0 and 1,1 to give a 1-1 mapping
* which can be easily tweaked from there.
*/
- insert_vert_fcurve(fcu, 0.0f, 0.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
- insert_vert_fcurve(fcu, 1.0f, 1.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
-
- /* configure this curve to extrapolate */
- for (i = 0, bezt = fcu->bezt; (i < fcu->totvert) && bezt; i++, bezt++) {
- bezt->h1 = bezt->h2 = HD_VECT;
- }
-
+ insert_vert_fcurve(
+ fcu, 0.0f, 0.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST | INSERTKEY_NO_USERPREF);
+ insert_vert_fcurve(
+ fcu, 1.0f, 1.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST | INSERTKEY_NO_USERPREF);
fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
calchandles_fcurve(fcu);
}
@@ -177,7 +167,8 @@ static int add_driver_with_target(ReportList *UNUSED(reports),
int driver_type)
{
FCurve *fcu;
- short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? 2 : 1;
+ short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? DRIVER_FCURVE_GENERATOR :
+ DRIVER_FCURVE_KEYFRAMES;
const char *prop_name = RNA_property_identifier(src_prop);
/* Create F-Curve with Driver */
@@ -593,7 +584,7 @@ bool ANIM_remove_driver(ReportList *UNUSED(reports),
* Note: here is one of the places where we don't want new F-Curve + Driver added!
* so 'add' var must be 0
*/
- fcu = verify_driver_fcurve(id, rna_path, array_index, 0);
+ fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_LOOKUP_ONLY);
if (fcu) {
BLI_remlink(&adt->drivers, fcu);
free_fcurve(fcu);
@@ -653,7 +644,7 @@ bool ANIM_copy_driver(
}
/* try to get F-Curve with Driver */
- fcu = verify_driver_fcurve(id, rna_path, array_index, 0);
+ fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_LOOKUP_ONLY);
/* clear copy/paste buffer first (for consistency with other copy/paste buffers) */
ANIM_drivers_copybuf_free();
@@ -711,7 +702,7 @@ bool ANIM_paste_driver(
}
/* create Driver F-Curve, but without data which will be copied across... */
- fcu = verify_driver_fcurve(id, rna_path, array_index, -1);
+ fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_EMPTY);
if (fcu) {
/* copy across the curve data from the buffer curve
@@ -855,7 +846,7 @@ void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const ch
ANIM_driver_vars_copybuf_free();
/* Create a dummy driver F-Curve. */
- FCurve *fcu = alloc_driver_fcurve(NULL, 0, 1);
+ FCurve *fcu = alloc_driver_fcurve(NULL, 0, DRIVER_FCURVE_KEYFRAMES);
ChannelDriver *driver = fcu->driver;
/* Create a variable. */
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index b42e8102c5b..705351522f8 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -197,7 +197,7 @@ static void draw_modifier__generator(uiLayout *layout,
&data->poly_order,
1,
100,
- 0,
+ 1,
0,
TIP_("'Order' of the Polynomial (for a polynomial with n terms, 'order' is n-1)"));
UI_but_func_set(but, validate_fmodifier_cb, fcm, fcurve_owner_id);
@@ -335,7 +335,7 @@ static void draw_modifier__generator(uiLayout *layout,
&data->poly_order,
1,
100,
- 0,
+ 1,
0,
TIP_("'Order' of the Polynomial (for a polynomial with n terms, 'order' is n-1)"));
UI_but_func_set(but, validate_fmodifier_cb, fcm, fcurve_owner_id);
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index ca7e0eae136..c174ce83bea 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -45,7 +45,6 @@
#include "BKE_fcurve.h"
-#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_state.h"
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index c4c10549da3..64857dd1874 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -908,8 +908,10 @@ static void bones_merge(
newbone->parent = start->parent;
/* TODO, copy more things to the new bone */
- newbone->flag = start->flag & (BONE_HINGE | BONE_NO_DEFORM | BONE_NO_SCALE |
- BONE_NO_CYCLICOFFSET | BONE_NO_LOCAL_LOCATION | BONE_DONE);
+ newbone->flag = start->flag & (BONE_HINGE | BONE_NO_DEFORM | BONE_NO_CYCLICOFFSET |
+ BONE_NO_LOCAL_LOCATION | BONE_DONE);
+
+ newbone->inherit_scale_mode = start->inherit_scale_mode;
/* Step 2a: reparent any side chains which may be parented to any bone in the chain
* of bones to merge - potentially several tips for side chains leading to some tree exist.
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index eff621d7b71..c37f9ce126b 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -251,12 +251,13 @@ void *get_bone_from_selectbuffer(Base **bases,
/* x and y are mouse coords (area space) */
void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel, Base **r_base)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
rcti rect;
unsigned int buffer[MAXPICKBUF];
short hits;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
// rect.xmin = ... mouseco!
rect.xmin = rect.xmax = xy[0];
@@ -648,8 +649,9 @@ bool ED_armature_edit_deselect_all_visible_multi_ex(struct Base **bases, uint ba
bool ED_armature_edit_deselect_all_visible_multi(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &bases_len);
@@ -674,12 +676,13 @@ static int ebone_select_flag(EditBone *ebone)
bool ED_armature_edit_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
EditBone *nearBone = NULL;
int selmask;
Base *basact = NULL;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
vc.mval[0] = mval[0];
vc.mval[1] = mval[1];
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
index 08de699a70b..c772590ed21 100644
--- a/source/blender/editors/armature/armature_skinning.c
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -234,7 +234,7 @@ static void envelope_bone_weighting(Object *ob,
iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, NULL, i, use_topology) : -1;
/* for each skinnable bone */
- for (j = 0; j < numbones; ++j) {
+ for (j = 0; j < numbones; j++) {
if (!selected[j]) {
continue;
}
@@ -346,7 +346,7 @@ static void add_verts_to_dgroups(ReportList *reports,
tip = MEM_callocN(numbones * sizeof(float) * 3, "tip");
selected = MEM_callocN(numbones * sizeof(int), "selected");
- for (j = 0; j < numbones; ++j) {
+ for (j = 0; j < numbones; j++) {
bone = bonelist[j];
dgroup = dgrouplist[j];
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index cd299906b4c..2b18fc15f63 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -491,6 +491,7 @@ static EditBone *make_boneList_rec(ListBase *edbo,
eBone->parent = parent;
BLI_strncpy(eBone->name, curBone->name, sizeof(eBone->name));
eBone->flag = curBone->flag;
+ eBone->inherit_scale_mode = curBone->inherit_scale_mode;
/* fix selection flags */
if (eBone->flag & BONE_SELECTED) {
@@ -719,6 +720,7 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm)
newBone->arm_roll = eBone->roll;
newBone->flag = eBone->flag;
+ newBone->inherit_scale_mode = eBone->inherit_scale_mode;
if (eBone == arm->act_edbone) {
/* don't change active selection, this messes up separate which uses
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 8f4896c0b82..ad115896a43 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -182,12 +182,25 @@ static bool pose_has_protected_selected(Object *ob, short warn)
/* ********************************************** */
/* Motion Paths */
+static eAnimvizCalcRange pose_path_convert_range(ePosePathCalcRange range)
+{
+ switch (range) {
+ case POSE_PATH_CALC_RANGE_CURRENT_FRAME:
+ return ANIMVIZ_CALC_RANGE_CURRENT_FRAME;
+ case POSE_PATH_CALC_RANGE_CHANGED:
+ return ANIMVIZ_CALC_RANGE_CHANGED;
+ case POSE_PATH_CALC_RANGE_FULL:
+ return ANIMVIZ_CALC_RANGE_FULL;
+ }
+ return ANIMVIZ_CALC_RANGE_FULL;
+}
+
/* For the object with pose/action: update paths for those that have got them
* This should selectively update paths that exist...
*
* To be called from various tools that do incremental updates
*/
-void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool current_frame_only)
+void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, ePosePathCalcRange range)
{
/* Transform doesn't always have context available to do update. */
if (C == NULL) {
@@ -195,12 +208,12 @@ void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool curre
}
Main *bmain = CTX_data_main(C);
- /* NOTE: Dependency graph will be evaluated at all the frames, but we first need to access some
- * nested pointers, like animation data. */
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- ListBase targets = {NULL, NULL};
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ Depsgraph *depsgraph;
bool free_depsgraph = false;
+ ListBase targets = {NULL, NULL};
/* set flag to force recalc, then grab the relevant bones to target */
ob->pose->avs.recalc |= ANIMVIZ_RECALC_PATHS;
animviz_get_object_motionpaths(ob, &targets);
@@ -210,7 +223,21 @@ void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool curre
TIMEIT_START(pose_path_calc);
#endif
- animviz_calc_motionpaths(depsgraph, bmain, scene, &targets, !free_depsgraph, current_frame_only);
+ /* For a single frame update it's faster to re-use existing dependency graph and avoid overhead
+ * of building all the relations and so on for a temporary one. */
+ if (range == POSE_PATH_CALC_RANGE_CURRENT_FRAME) {
+ /* NOTE: Dependency graph will be evaluated at all the frames, but we first need to access some
+ * nested pointers, like animation data. */
+ depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ free_depsgraph = false;
+ }
+ else {
+ depsgraph = animviz_depsgraph_build(bmain, scene, view_layer, &targets);
+ free_depsgraph = true;
+ }
+
+ animviz_calc_motionpaths(
+ depsgraph, bmain, scene, &targets, pose_path_convert_range(range), !free_depsgraph);
#ifdef DEBUG_TIME
TIMEIT_END(pose_path_calc);
@@ -218,13 +245,13 @@ void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool curre
BLI_freelistN(&targets);
- if (!current_frame_only) {
+ if (range != POSE_PATH_CALC_RANGE_CURRENT_FRAME) {
/* Tag armature object for copy on write - so paths will draw/redraw.
* For currently frame only we update evaluated object directly. */
DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
- /* Free temporary depsgraph instance */
+ /* Free temporary depsgraph. */
if (free_depsgraph) {
DEG_graph_free(depsgraph);
}
@@ -293,7 +320,7 @@ static int pose_calculate_paths_exec(bContext *C, wmOperator *op)
/* calculate the bones that now have motionpaths... */
/* TODO: only make for the selected bones? */
- ED_pose_recalculate_paths(C, scene, ob, false);
+ ED_pose_recalculate_paths(C, scene, ob, POSE_PATH_CALC_RANGE_FULL);
#ifdef DEBUG_TIME
TIMEIT_END(recalc_pose_paths);
@@ -371,7 +398,7 @@ static int pose_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
/* calculate the bones that now have motionpaths... */
/* TODO: only make for the selected bones? */
- ED_pose_recalculate_paths(C, scene, ob, false);
+ ED_pose_recalculate_paths(C, scene, ob, POSE_PATH_CALC_RANGE_FULL);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index a59067e60c1..c3a7d45f598 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -368,8 +368,9 @@ bool ED_pose_deselect_all_multi_ex(Base **bases,
bool ED_pose_deselect_all_multi(bContext *C, int select_mode, const bool ignore_visibility)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_mode(vc.view_layer,
vc.v3d,
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 6274eb549da..616daf94e57 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -1003,7 +1003,7 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p
pose_slide_refresh(C, pso);
/* set cursor to indicate modal */
- WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_EW_SCROLL);
/* header print */
pose_slide_draw_status(pso);
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 854fb237929..55c9b661074 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -241,13 +241,21 @@ static void applyarmature_process_selected_rec(bArmature *arm,
/* Parent effects on the bone transform that have to be removed. */
BKE_bone_offset_matrix_get(bone, offs_bone);
- BKE_bone_parent_transform_calc_from_matrices(
- bone->flag, offs_bone, bone->parent->arm_mat, pchan_eval->parent->pose_mat, &old_bpt);
+ BKE_bone_parent_transform_calc_from_matrices(bone->flag,
+ bone->inherit_scale_mode,
+ offs_bone,
+ bone->parent->arm_mat,
+ pchan_eval->parent->pose_mat,
+ &old_bpt);
/* Applied parent effects that have to be kept, if any. */
float(*new_parent_pose)[4] = pstate ? pstate->new_rest_mat : bone->parent->arm_mat;
- BKE_bone_parent_transform_calc_from_matrices(
- bone->flag, offs_bone, bone->parent->arm_mat, new_parent_pose, &new_bpt);
+ BKE_bone_parent_transform_calc_from_matrices(bone->flag,
+ bone->inherit_scale_mode,
+ offs_bone,
+ bone->parent->arm_mat,
+ new_parent_pose,
+ &new_bpt);
BKE_bone_parent_transform_invert(&old_bpt);
BKE_bone_parent_transform_combine(&new_bpt, &old_bpt, &invparent);
@@ -283,8 +291,12 @@ static void applyarmature_process_selected_rec(bArmature *arm,
/* Include applied parent effects. */
BKE_bone_offset_matrix_get(bone, offs_bone);
- BKE_bone_parent_transform_calc_from_matrices(
- bone->flag, offs_bone, pstate->bone->arm_mat, pstate->new_rest_mat, &bpt);
+ BKE_bone_parent_transform_calc_from_matrices(bone->flag,
+ bone->inherit_scale_mode,
+ offs_bone,
+ pstate->bone->arm_mat,
+ pstate->new_rest_mat,
+ &bpt);
unit_m4(new_pstate.new_rest_mat);
BKE_bone_parent_transform_apply(&bpt, new_pstate.new_rest_mat, new_pstate.new_rest_mat);
@@ -306,8 +318,12 @@ static void applyarmature_process_selected_rec(bArmature *arm,
/* Compute the channel coordinate space matrices for the new rest state. */
invert_m4_m4(inv_parent_arm, pstate->new_arm_mat);
mul_m4_m4m4(offs_bone, inv_parent_arm, new_pstate.new_arm_mat);
- BKE_bone_parent_transform_calc_from_matrices(
- bone->flag, offs_bone, pstate->new_arm_mat, pstate->new_arm_mat, &bpt);
+ BKE_bone_parent_transform_calc_from_matrices(bone->flag,
+ bone->inherit_scale_mode,
+ offs_bone,
+ pstate->new_arm_mat,
+ pstate->new_arm_mat,
+ &bpt);
/* Re-apply the location to keep the final effect. */
invert_m4(bpt.loc_mat);
@@ -527,16 +543,14 @@ static void set_pose_keys(Object *ob)
* \param chan: Bone that pose to paste comes from
* \param selOnly: Only paste on selected bones
* \param flip: Flip on x-axis
- * \return Whether the bone that we pasted to if we succeeded
+ * \return The channel of the bone that was pasted to, or NULL if no paste was performed.
*/
static bPoseChannel *pose_bone_do_paste(Object *ob,
bPoseChannel *chan,
const bool selOnly,
const bool flip)
{
- bPoseChannel *pchan;
char name[MAXBONENAME];
- short paste_ok;
/* get the name - if flipping, we must flip this first */
if (flip) {
@@ -551,131 +565,126 @@ static bPoseChannel *pose_bone_do_paste(Object *ob,
* 2) if selection-masking is on, channel is selected -
* only selected bones get pasted on, allowing making both sides symmetrical.
*/
- pchan = BKE_pose_channel_find_name(ob->pose, name);
-
- if (selOnly) {
- paste_ok = ((pchan) && (pchan->bone->flag & BONE_SELECTED));
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, name);
+ if (pchan == NULL) {
+ return NULL;
}
- else {
- paste_ok = (pchan != NULL);
+ if (selOnly && (pchan->bone->flag & BONE_SELECTED) == 0) {
+ return NULL;
}
- /* continue? */
- if (paste_ok) {
- /* only loc rot size
- * - only copies transform info for the pose
- */
- copy_v3_v3(pchan->loc, chan->loc);
- copy_v3_v3(pchan->size, chan->size);
- pchan->flag = chan->flag;
-
- /* check if rotation modes are compatible (i.e. do they need any conversions) */
- if (pchan->rotmode == chan->rotmode) {
- /* copy the type of rotation in use */
- if (pchan->rotmode > 0) {
- copy_v3_v3(pchan->eul, chan->eul);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- copy_v3_v3(pchan->rotAxis, chan->rotAxis);
- pchan->rotAngle = chan->rotAngle;
- }
- else {
- copy_qt_qt(pchan->quat, chan->quat);
- }
- }
- else if (pchan->rotmode > 0) {
- /* quat/axis-angle to euler */
- if (chan->rotmode == ROT_MODE_AXISANGLE) {
- axis_angle_to_eulO(pchan->eul, pchan->rotmode, chan->rotAxis, chan->rotAngle);
- }
- else {
- quat_to_eulO(pchan->eul, pchan->rotmode, chan->quat);
- }
+ /* only loc rot size
+ * - only copies transform info for the pose
+ */
+ copy_v3_v3(pchan->loc, chan->loc);
+ copy_v3_v3(pchan->size, chan->size);
+ pchan->flag = chan->flag;
+
+ /* check if rotation modes are compatible (i.e. do they need any conversions) */
+ if (pchan->rotmode == chan->rotmode) {
+ /* copy the type of rotation in use */
+ if (pchan->rotmode > 0) {
+ copy_v3_v3(pchan->eul, chan->eul);
}
else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- /* quat/euler to axis angle */
- if (chan->rotmode > 0) {
- eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode);
- }
- else {
- quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat);
- }
+ copy_v3_v3(pchan->rotAxis, chan->rotAxis);
+ pchan->rotAngle = chan->rotAngle;
}
else {
- /* euler/axis-angle to quat */
- if (chan->rotmode > 0) {
- eulO_to_quat(pchan->quat, chan->eul, chan->rotmode);
- }
- else {
- axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
- }
+ copy_qt_qt(pchan->quat, chan->quat);
+ }
+ }
+ else if (pchan->rotmode > 0) {
+ /* quat/axis-angle to euler */
+ if (chan->rotmode == ROT_MODE_AXISANGLE) {
+ axis_angle_to_eulO(pchan->eul, pchan->rotmode, chan->rotAxis, chan->rotAngle);
+ }
+ else {
+ quat_to_eulO(pchan->eul, pchan->rotmode, chan->quat);
+ }
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ /* quat/euler to axis angle */
+ if (chan->rotmode > 0) {
+ eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode);
+ }
+ else {
+ quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat);
+ }
+ }
+ else {
+ /* euler/axis-angle to quat */
+ if (chan->rotmode > 0) {
+ eulO_to_quat(pchan->quat, chan->eul, chan->rotmode);
}
+ else {
+ axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
+ }
+ }
- /* B-Bone posing options should also be included... */
- pchan->curve_in_x = chan->curve_in_x;
- pchan->curve_in_y = chan->curve_in_y;
- pchan->curve_out_x = chan->curve_out_x;
- pchan->curve_out_y = chan->curve_out_y;
-
- pchan->roll1 = chan->roll1;
- pchan->roll2 = chan->roll2;
- pchan->ease1 = chan->ease1;
- pchan->ease2 = chan->ease2;
- pchan->scale_in_x = chan->scale_in_x;
- pchan->scale_in_y = chan->scale_in_y;
- pchan->scale_out_x = chan->scale_out_x;
- pchan->scale_out_y = chan->scale_out_y;
-
- /* paste flipped pose? */
- if (flip) {
- pchan->loc[0] *= -1;
-
- pchan->curve_in_x *= -1;
- pchan->curve_out_x *= -1;
- pchan->roll1 *= -1; // XXX?
- pchan->roll2 *= -1; // XXX?
-
- /* has to be done as eulers... */
- if (pchan->rotmode > 0) {
- pchan->eul[1] *= -1;
- pchan->eul[2] *= -1;
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- float eul[3];
+ /* B-Bone posing options should also be included... */
+ pchan->curve_in_x = chan->curve_in_x;
+ pchan->curve_in_y = chan->curve_in_y;
+ pchan->curve_out_x = chan->curve_out_x;
+ pchan->curve_out_y = chan->curve_out_y;
+
+ pchan->roll1 = chan->roll1;
+ pchan->roll2 = chan->roll2;
+ pchan->ease1 = chan->ease1;
+ pchan->ease2 = chan->ease2;
+ pchan->scale_in_x = chan->scale_in_x;
+ pchan->scale_in_y = chan->scale_in_y;
+ pchan->scale_out_x = chan->scale_out_x;
+ pchan->scale_out_y = chan->scale_out_y;
+
+ /* paste flipped pose? */
+ if (flip) {
+ pchan->loc[0] *= -1;
- axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
- eul[1] *= -1;
- eul[2] *= -1;
- eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
- }
- else {
- float eul[3];
+ pchan->curve_in_x *= -1;
+ pchan->curve_out_x *= -1;
+ pchan->roll1 *= -1; // XXX?
+ pchan->roll2 *= -1; // XXX?
- normalize_qt(pchan->quat);
- quat_to_eul(eul, pchan->quat);
- eul[1] *= -1;
- eul[2] *= -1;
- eul_to_quat(pchan->quat, eul);
- }
+ /* has to be done as eulers... */
+ if (pchan->rotmode > 0) {
+ pchan->eul[1] *= -1;
+ pchan->eul[2] *= -1;
}
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ float eul[3];
- /* ID properties */
- if (chan->prop) {
- if (pchan->prop) {
- /* if we have existing properties on a bone, just copy over the values of
- * matching properties (i.e. ones which will have some impact) on to the
- * target instead of just blinding replacing all [
- */
- IDP_SyncGroupValues(pchan->prop, chan->prop);
- }
- else {
- /* no existing properties, so assume that we want copies too? */
- pchan->prop = IDP_CopyProperty(chan->prop);
- }
+ axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
+ eul[1] *= -1;
+ eul[2] *= -1;
+ eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
+ }
+ else {
+ float eul[3];
+
+ normalize_qt(pchan->quat);
+ quat_to_eul(eul, pchan->quat);
+ eul[1] *= -1;
+ eul[2] *= -1;
+ eul_to_quat(pchan->quat, eul);
+ }
+ }
+
+ /* ID properties */
+ if (chan->prop) {
+ if (pchan->prop) {
+ /* if we have existing properties on a bone, just copy over the values of
+ * matching properties (i.e. ones which will have some impact) on to the
+ * target instead of just blinding replacing all [
+ */
+ IDP_SyncGroupValues(pchan->prop, chan->prop);
+ }
+ else {
+ /* no existing properties, so assume that we want copies too? */
+ pchan->prop = IDP_CopyProperty(chan->prop);
}
}
- /* return whether paste went ahead */
return pchan;
}
@@ -815,7 +824,7 @@ static int pose_paste_exec(bContext *C, wmOperator *op)
/* Recalculate paths if any of the bones have paths... */
if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
- ED_pose_recalculate_paths(C, scene, ob, false);
+ ED_pose_recalculate_paths(C, scene, ob, POSE_PATH_CALC_RANGE_FULL);
}
/* Notifiers for updates, */
@@ -1096,7 +1105,7 @@ static int pose_clear_transform_generic_exec(bContext *C,
/* now recalculate paths */
if ((ob_iter->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
- ED_pose_recalculate_paths(C, scene, ob_iter, false);
+ ED_pose_recalculate_paths(C, scene, ob_iter, POSE_PATH_CALC_RANGE_FULL);
}
BLI_freelistN(&dsources);
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index fbaf2c896d0..3f6db956643 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -327,7 +327,8 @@ void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks,
if (ob->id.tag & LIB_TAG_DOIT) {
if (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) {
// ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear
- ED_pose_recalculate_paths(C, scene, ob, false);
+ /* TODO(sergey): Should ensure we can use more narrow update range here. */
+ ED_pose_recalculate_paths(C, scene, ob, POSE_PATH_CALC_RANGE_FULL);
}
}
}
diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c
index 3d2ac009072..81c9c759188 100644
--- a/source/blender/editors/curve/curve_ops.c
+++ b/source/blender/editors/curve/curve_ops.c
@@ -33,10 +33,7 @@
#include "WM_types.h"
#include "ED_curve.h"
-#include "ED_object.h"
#include "ED_screen.h"
-#include "ED_select_utils.h"
-#include "ED_transform.h"
#include "curve_intern.h"
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index d7650db546d..994d844287c 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -56,13 +56,11 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "ED_keyframes_edit.h"
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_transform_snap_object_context.h"
#include "ED_types.h"
-#include "ED_util.h"
#include "ED_view3d.h"
#include "ED_curve.h"
@@ -692,7 +690,7 @@ static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
if (oldbezt) {
int j;
- for (j = 0; j < 3; ++j) {
+ for (j = 0; j < 3; j++) {
sub_v3_v3v3(ofs[i], bezt->vec[j], oldbezt->vec[j]);
i++;
}
@@ -4876,6 +4874,7 @@ void CURVE_OT_make_segment(wmOperatorType *ot)
bool ED_curve_editnurb_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
Nurb *nu;
BezTriple *bezt = NULL;
@@ -4884,7 +4883,7 @@ bool ED_curve_editnurb_select_pick(
short hand;
view3d_operator_needs_opengl(C);
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
copy_v2_v2_int(vc.mval, mval);
if (ED_curve_pick_vert(&vc, 1, &nu, &bezt, &bp, &hand, &basact)) {
@@ -5635,9 +5634,10 @@ static int add_vertex_exec(bContext *C, wmOperator *op)
static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
if (vc.rv3d && !RNA_struct_property_is_set(op->ptr, "location")) {
Curve *cu;
@@ -7136,7 +7136,6 @@ static int match_texture_space_exec(bContext *C, wmOperator *UNUSED(op))
copy_v3_v3(curve->loc, loc);
copy_v3_v3(curve->size, size);
- zero_v3(curve->rot);
curve->texflag &= ~CU_AUTOSPACE;
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index 4912ae5451d..d97223de9b8 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -44,7 +44,6 @@
#include "ED_object.h"
#include "ED_screen.h"
-#include "ED_undo.h"
#include "ED_view3d.h"
#include "ED_curve.h"
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index c7c19aa2d02..4c4bac6a249 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -31,7 +31,6 @@
#include "BKE_curve.h"
#include "BKE_fcurve.h"
#include "BKE_report.h"
-#include "BKE_layer.h"
#include "DEG_depsgraph.h"
@@ -575,9 +574,10 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
BLI_assert(op->customdata == NULL);
struct CurveDrawData *cdd = MEM_callocN(sizeof(*cdd), __func__);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
if (is_invoke) {
- ED_view3d_viewcontext_init(C, &cdd->vc);
+ ED_view3d_viewcontext_init(C, &cdd->vc, depsgraph);
if (ELEM(NULL, cdd->vc.ar, cdd->vc.rv3d, cdd->vc.v3d, cdd->vc.win, cdd->vc.scene)) {
MEM_freeN(cdd);
BKE_report(op->reports, RPT_ERROR, "Unable to access 3D viewport");
@@ -586,7 +586,7 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
}
else {
cdd->vc.bmain = CTX_data_main(C);
- cdd->vc.depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ cdd->vc.depsgraph = depsgraph;
cdd->vc.scene = CTX_data_scene(C);
cdd->vc.view_layer = CTX_data_view_layer(C);
cdd->vc.obedit = CTX_data_edit_object(C);
@@ -1064,7 +1064,7 @@ static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
cdd->draw_handle_view = ED_region_draw_cb_activate(
cdd->vc.ar->type, curve_draw_stroke_3d, op, REGION_DRAW_POST_VIEW);
- WM_cursor_modal_set(cdd->vc.win, BC_PAINTBRUSHCURSOR);
+ WM_cursor_modal_set(cdd->vc.win, WM_CURSOR_PAINT_BRUSH);
{
View3D *v3d = cdd->vc.v3d;
diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c
index f67ccf1e4bd..9df79a082e1 100644
--- a/source/blender/editors/curve/editcurve_select.c
+++ b/source/blender/editors/curve/editcurve_select.c
@@ -37,7 +37,6 @@
#include "BKE_fcurve.h"
#include "BKE_layer.h"
#include "BKE_report.h"
-#include "BKE_object.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -278,8 +277,9 @@ bool ED_curve_deselect_all_multi_ex(Base **bases, int bases_len)
bool ED_curve_deselect_all_multi(struct bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &bases_len);
@@ -684,6 +684,7 @@ void CURVE_OT_select_linked(wmOperatorType *ot)
static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
Nurb *nu;
BezTriple *bezt;
@@ -693,7 +694,7 @@ static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent
Base *basact = NULL;
view3d_operator_needs_opengl(C);
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
copy_v2_v2_int(vc.mval, event->mval);
if (!ED_curve_pick_vert(&vc, 1, &nu, &bezt, &bp, NULL, &basact)) {
@@ -1311,7 +1312,7 @@ static void select_nth_bezt(Nurb *nu, BezTriple *bezt, const struct CheckerInter
while (a--) {
const int depth = abs(start - a);
- if (WM_operator_properties_checker_interval_test(params, depth)) {
+ if (!WM_operator_properties_checker_interval_test(params, depth)) {
select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
}
@@ -1334,7 +1335,7 @@ static void select_nth_bp(Nurb *nu, BPoint *bp, const struct CheckerIntervalPara
while (a--) {
const int depth = abs(pnt - startpnt) + abs(row - startrow);
- if (WM_operator_properties_checker_interval_test(params, depth)) {
+ if (!WM_operator_properties_checker_interval_test(params, depth)) {
select_bpoint(bp, DESELECT, SELECT, HIDDEN);
}
@@ -1960,6 +1961,7 @@ static void curve_select_shortest_path_surf(Nurb *nu, int vert_src, int vert_dst
static int edcu_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
Nurb *nu_dst;
BezTriple *bezt_dst;
@@ -1969,7 +1971,7 @@ static int edcu_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE
Base *basact = NULL;
view3d_operator_needs_opengl(C);
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
copy_v2_v2_int(vc.mval, event->mval);
if (!ED_curve_pick_vert(&vc, 1, &nu_dst, &bezt_dst, &bp_dst, NULL, &basact)) {
diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c
index 835abd1a630..f21b4f06246 100644
--- a/source/blender/editors/curve/editcurve_undo.c
+++ b/source/blender/editors/curve/editcurve_undo.c
@@ -40,9 +40,7 @@
#include "DEG_depsgraph.h"
-#include "ED_object.h"
#include "ED_undo.h"
-#include "ED_util.h"
#include "ED_curve.h"
#include "WM_types.h"
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 781eb2634fb..603b0967ace 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -60,7 +60,6 @@
#include "ED_curve.h"
#include "ED_object.h"
#include "ED_screen.h"
-#include "ED_util.h"
#include "ED_view3d.h"
#include "UI_interface.h"
@@ -2201,6 +2200,7 @@ void FONT_OT_unlink(wmOperatorType *ot)
bool ED_curve_editfont_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *obedit = CTX_data_edit_object(C);
Curve *cu = obedit->data;
ViewContext vc;
@@ -2212,7 +2212,7 @@ bool ED_curve_editfont_select_pick(
const float dist = ED_view3d_select_dist_px();
float dist_sq_best = dist * dist;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c
index 2f8f15bc6c7..ae858ec4c24 100644
--- a/source/blender/editors/curve/editfont_undo.c
+++ b/source/blender/editors/curve/editfont_undo.c
@@ -29,7 +29,6 @@
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
#include "BKE_context.h"
#include "BKE_font.h"
@@ -39,7 +38,6 @@
#include "ED_object.h"
#include "ED_curve.h"
-#include "ED_util.h"
#include "WM_types.h"
#include "WM_api.h"
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 69738d2e008..8a3a078bdd2 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -645,6 +645,8 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
brush.sculpt.clay_strips
brush.sculpt.crease
brush.sculpt.draw
+ brush.sculpt.draw_sharp
+ brush.sculpt.elastic_deform
brush.sculpt.fill
brush.sculpt.flatten
brush.sculpt.grab
@@ -653,6 +655,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
brush.sculpt.mask
brush.sculpt.nudge
brush.sculpt.pinch
+ brush.sculpt.pose
brush.sculpt.rotate
brush.sculpt.scrape
brush.sculpt.simplify
@@ -736,6 +739,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.sculpt.border_hide
ops.sculpt.border_mask
ops.sculpt.lasso_mask
+ ops.sculpt.mesh_filter
ops.transform.bone_envelope
ops.transform.bone_size
ops.transform.edge_slide
@@ -836,6 +840,8 @@ if(WITH_BLENDER)
data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_block.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_marker.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_fill.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_airbrush.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_chisel.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_soft.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_hard.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_stroke.png SRC)
diff --git a/source/blender/editors/gizmo_library/gizmo_draw_utils.c b/source/blender/editors/gizmo_library/gizmo_draw_utils.c
index f1d8c1ac6b0..cffafc56693 100644
--- a/source/blender/editors/gizmo_library/gizmo_draw_utils.c
+++ b/source/blender/editors/gizmo_library/gizmo_draw_utils.c
@@ -31,7 +31,6 @@
#include "GPU_batch.h"
#include "GPU_glew.h"
#include "GPU_immediate.h"
-#include "GPU_state.h"
#include "MEM_guardedalloc.h"
@@ -66,7 +65,7 @@ void wm_gizmo_geometryinfo_draw(const GizmoGeomInfo *info,
/* Elements */
GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, info->ntris, info->nverts);
- for (int i = 0; i < info->ntris; ++i) {
+ for (int i = 0; i < info->ntris; i++) {
const unsigned short *idx = &info->indices[i * 3];
GPU_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]);
}
diff --git a/source/blender/editors/gizmo_library/gizmo_library_presets.c b/source/blender/editors/gizmo_library/gizmo_library_presets.c
index ae43894b7b6..fe0893ae3ff 100644
--- a/source/blender/editors/gizmo_library/gizmo_library_presets.c
+++ b/source/blender/editors/gizmo_library/gizmo_library_presets.c
@@ -31,9 +31,6 @@
#include "BKE_context.h"
-#include "GPU_draw.h"
-#include "GPU_immediate.h"
-#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
#include "GPU_select.h"
@@ -57,7 +54,7 @@
* Given a single axis, orient the matrix to a different direction.
*/
static void single_axis_convert(int src_axis,
- float src_mat[4][4],
+ const float src_mat[4][4],
int dst_axis,
float dst_mat[4][4])
{
@@ -76,7 +73,7 @@ static void single_axis_convert(int src_axis,
* Use for all geometry.
*/
static void ed_gizmo_draw_preset_geometry(const struct wmGizmo *gz,
- float mat[4][4],
+ const float mat[4][4],
int select_id,
const GizmoGeomInfo *info)
{
diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c
index c175bfb90ab..24571f67fdb 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c
@@ -31,7 +31,6 @@
#include "BKE_context.h"
-#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
#include "GPU_state.h"
diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
index fa9c0f1fbb2..6a28c626a81 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
@@ -38,7 +38,6 @@
#include "BKE_context.h"
-#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
diff --git a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
index 1a132c2957a..ecbc503e084 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
@@ -258,9 +258,9 @@ static int gizmo_button2d_test_select(bContext *C, wmGizmo *gz, const int mval[2
static int gizmo_button2d_cursor_get(wmGizmo *gz)
{
if (RNA_boolean_get(gz->ptr, "show_drag")) {
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
- return CURSOR_STD;
+ return WM_CURSOR_DEFAULT;
}
static void gizmo_button2d_free(wmGizmo *gz)
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
index ba3b8c2602e..ef4fd23b64d 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
@@ -752,30 +752,30 @@ static int gizmo_cage2d_get_cursor(wmGizmo *gz)
int highlight_part = gz->highlight_part;
if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
switch (highlight_part) {
case ED_GIZMO_CAGE2D_PART_TRANSLATE:
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X:
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X:
- return CURSOR_X_MOVE;
+ return WM_CURSOR_X_MOVE;
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y:
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y:
- return CURSOR_Y_MOVE;
+ return WM_CURSOR_Y_MOVE;
/* TODO diagonal cursor */
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y:
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y:
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y:
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y:
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
case ED_GIZMO_CAGE2D_PART_ROTATE:
- return BC_CROSSCURSOR;
+ return WM_CURSOR_CROSS;
default:
- return CURSOR_STD;
+ return WM_CURSOR_DEFAULT;
}
}
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
index 406f76bc65e..723be3cfe6b 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
@@ -424,10 +424,10 @@ static void gizmo_cage3d_draw(const bContext *C, wmGizmo *gz)
static int gizmo_cage3d_get_cursor(wmGizmo *gz)
{
if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
- return CURSOR_STD;
+ return WM_CURSOR_DEFAULT;
}
typedef struct RectTransformInteraction {
diff --git a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
index 6d8ab096a26..d3121711e28 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
@@ -273,7 +273,7 @@ static void dial_ghostarc_draw(const float angle_ofs,
static void dial_ghostarc_get_angles(const wmGizmo *gz,
const wmEvent *event,
const ARegion *ar,
- float mat[4][4],
+ const float mat[4][4],
const float co_outer[3],
float *r_start,
float *r_delta)
diff --git a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
index 37ee95d5058..5342f8695b2 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
@@ -412,7 +412,7 @@ static void gizmo_move_property_update(wmGizmo *gz, wmGizmoProperty *gz_prop)
static int gizmo_move_cursor_get(wmGizmo *UNUSED(gz))
{
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c
index 697d06aa098..67bf64a2903 100644
--- a/source/blender/editors/gpencil/annotate_draw.c
+++ b/source/blender/editors/gpencil/annotate_draw.c
@@ -55,7 +55,6 @@
#include "BIF_glutil.h"
#include "GPU_immediate.h"
-#include "GPU_draw.h"
#include "GPU_state.h"
#include "ED_gpencil.h"
@@ -96,7 +95,7 @@ static void annotation_draw_stroke_buffer(const tGPspoint *points,
short thickness,
short dflag,
short sflag,
- float ink[4])
+ const float ink[4])
{
int draw_points = 0;
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index 22f1753a810..7a10547f35c 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -1560,10 +1560,10 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
static void gpencil_draw_cursor_set(tGPsdata *p)
{
if (p->paintmode == GP_PAINTMODE_ERASER) {
- WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */
+ WM_cursor_modal_set(p->win, WM_CURSOR_ERASER);
}
else {
- WM_cursor_modal_set(p->win, BC_PAINTBRUSHCURSOR);
+ WM_cursor_modal_set(p->win, WM_CURSOR_PAINT_BRUSH);
}
}
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 7c76f3aeab6..80795b825b0 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -62,7 +62,6 @@
#include "BIF_glutil.h"
#include "GPU_immediate.h"
-#include "GPU_draw.h"
#include "GPU_state.h"
#include "ED_gpencil.h"
@@ -268,8 +267,11 @@ static void gp_calc_2d_bounding_box(
}
/* calc texture coordinates using flat projected points */
-static void gp_calc_stroke_text_coordinates(
- const float (*points2d)[2], int totpoints, float minv[2], float maxv[2], float (*r_uv)[2])
+static void gp_calc_stroke_text_coordinates(const float (*points2d)[2],
+ int totpoints,
+ const float minv[2],
+ float maxv[2],
+ float (*r_uv)[2])
{
float d[2];
d[0] = maxv[0] - minv[0];
diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c
index c4528518009..139697ad0e3 100644
--- a/source/blender/editors/gpencil/gpencil_add_monkey.c
+++ b/source/blender/editors/gpencil/gpencil_add_monkey.c
@@ -54,7 +54,7 @@ static int gpencil_monkey_color(
short *totcol = give_totcolp(ob);
Material *ma = NULL;
for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
+ ma = BKE_material_gpencil_get(ob, i + 1);
if (STREQ(ma->id.name, pct->name)) {
return i;
}
diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c
index 80e239c9ae5..74617599eaa 100644
--- a/source/blender/editors/gpencil/gpencil_add_stroke.c
+++ b/source/blender/editors/gpencil/gpencil_add_stroke.c
@@ -53,7 +53,7 @@ static int gp_stroke_material(Main *bmain, Object *ob, const ColorTemplate *pct,
short *totcol = give_totcolp(ob);
Material *ma = NULL;
for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
+ ma = BKE_material_gpencil_get(ob, i + 1);
if (STREQ(ma->id.name, pct->name)) {
return i;
}
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c
index d1c4f271321..af9cadfb938 100644
--- a/source/blender/editors/gpencil/gpencil_brush.c
+++ b/source/blender/editors/gpencil/gpencil_brush.c
@@ -52,6 +52,7 @@
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_material.h"
#include "BKE_object_deform.h"
#include "BKE_report.h"
@@ -71,10 +72,6 @@
#include "ED_screen.h"
#include "ED_view3d.h"
-#include "GPU_immediate.h"
-#include "GPU_immediate_util.h"
-#include "GPU_state.h"
-
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -113,6 +110,7 @@ typedef struct tGP_BrushEditData {
/* Is the brush currently painting? */
bool is_painting;
bool is_weight_mode;
+ bool is_transformed;
/* Start of new sculpt stroke */
bool first;
@@ -536,7 +534,7 @@ static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso)
// XXX: screen-space strokes in 3D space will suffer!
if (gso->sa->spacetype == SPACE_VIEW3D) {
RegionView3D *rv3d = gso->ar->regiondata;
- float *rvec = gso->scene->cursor.location;
+ float *rvec = gso->object->loc;
float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
float mval_f[2];
@@ -569,7 +567,7 @@ static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso)
/* Apply grab transform to all relevant points of the affected strokes */
static void gp_brush_grab_apply_cached(tGP_BrushEditData *gso,
bGPDstroke *gps,
- float diff_mat[4][4])
+ const float diff_mat[4][4])
{
tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
int i;
@@ -661,7 +659,7 @@ static void gp_brush_calc_midpoint(tGP_BrushEditData *gso)
* See: gpencil_paint.c :: gp_stroke_convertcoords()
*/
RegionView3D *rv3d = gso->ar->regiondata;
- const float *rvec = gso->scene->cursor.location;
+ const float *rvec = gso->object->loc;
float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
float mval_f[2];
@@ -1330,9 +1328,12 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
if (!BLI_findlink(&ob->defbase, gso->vrgroup)) {
gso->vrgroup = -1;
}
+ /* Check if some modifier can transform the stroke. */
+ gso->is_transformed = BKE_gpencil_has_transform_modifiers(ob);
}
else {
gso->vrgroup = -1;
+ gso->is_transformed = false;
}
gso->sa = CTX_wm_area(C);
@@ -1401,7 +1402,7 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
gpsculpt_brush_header_set(C, gso);
/* setup cursor drawing */
- // WM_cursor_modal_set(CTX_wm_window(C), BC_CROSSCURSOR);
+ // WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_CROSS);
if (gso->sa->spacetype != SPACE_VIEW3D) {
ED_gpencil_toggle_brush_cursor(C, true, NULL);
}
@@ -1467,7 +1468,7 @@ static bool gpsculpt_brush_poll(bContext *C)
/* Init Sculpt Stroke ---------------------------------- */
-static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
+static void gpsculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso)
{
bGPdata *gpd = gso->gpd;
@@ -1491,9 +1492,11 @@ static void gpsculpt_brush_init_stroke(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.
*/
- // XXX: should this be allowed when framelock is enabled?
if (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);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
}
}
@@ -1508,12 +1511,17 @@ static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
* For strokes with one point only this is impossible to calculate because there isn't a
* valid reference point.
*/
-static float gpsculpt_rotation_eval_get(GP_SpaceConversion *gsc,
+static float gpsculpt_rotation_eval_get(tGP_BrushEditData *gso,
bGPDstroke *gps_eval,
bGPDspoint *pt_eval,
int idx_eval)
{
+ /* If multiframe or no modifiers, return 0. */
+ if ((GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd)) || (!gso->is_transformed)) {
+ return 0.0f;
+ }
+ GP_SpaceConversion *gsc = &gso->gsc;
bGPDstroke *gps_orig = gps_eval->runtime.gps_orig;
bGPDspoint *pt_orig = &gps_orig->points[pt_eval->runtime.idx_orig];
bGPDspoint *pt_prev_eval = NULL;
@@ -1559,7 +1567,7 @@ static float gpsculpt_rotation_eval_get(GP_SpaceConversion *gsc,
/* Apply brush operation to points in this stroke */
static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
bGPDstroke *gps,
- float diff_mat[4][4],
+ const float diff_mat[4][4],
GP_BrushApplyCb apply)
{
GP_SpaceConversion *gsc = &gso->gsc;
@@ -1568,12 +1576,16 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
const int radius = (gp_brush->flag & GP_SCULPT_FLAG_PRESSURE_RADIUS) ?
gso->gp_brush->size * gso->pressure :
gso->gp_brush->size;
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd);
+ bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
+ bGPDspoint *pt_active = NULL;
bGPDspoint *pt1, *pt2;
bGPDspoint *pt = NULL;
int pc1[2] = {0};
int pc2[2] = {0};
int i;
+ int index;
bool include_last = false;
bool changed = false;
float rot_eval = 0.0f;
@@ -1583,6 +1595,7 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
+ pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
/* do boundbox check first */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
@@ -1590,9 +1603,9 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
round_v2i_v2fl(mval_i, gso->mval);
if (len_v2v2_int(mval_i, pc1) <= radius) {
/* apply operation to this point */
- if (pt->runtime.pt_orig != NULL) {
- rot_eval = gpsculpt_rotation_eval_get(&gso->gsc, gps, pt, 0);
- changed = apply(gso, gps->runtime.gps_orig, rot_eval, pt->runtime.idx_orig, radius, pc1);
+ if (pt_active != NULL) {
+ rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, 0);
+ changed = apply(gso, gps_active, rot_eval, 0, radius, pc1);
}
}
}
@@ -1635,9 +1648,11 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
/* To each point individually... */
pt = &gps->points[i];
- if (pt->runtime.pt_orig != NULL) {
- rot_eval = gpsculpt_rotation_eval_get(&gso->gsc, gps, pt, i);
- ok = apply(gso, gps->runtime.gps_orig, rot_eval, pt->runtime.idx_orig, radius, pc1);
+ pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
+ index = (!is_multiedit) ? pt->runtime.idx_orig : i;
+ if (pt_active != NULL) {
+ rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i);
+ ok = apply(gso, gps_active, rot_eval, index, radius, pc1);
}
/* Only do the second point if this is the last segment,
@@ -1650,9 +1665,11 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
*/
if (i + 1 == gps->totpoints - 1) {
pt = &gps->points[i + 1];
- if (pt->runtime.pt_orig != NULL) {
- rot_eval = gpsculpt_rotation_eval_get(&gso->gsc, gps, pt, i + 1);
- ok |= apply(gso, gps->runtime.gps_orig, rot_eval, pt->runtime.idx_orig, radius, pc2);
+ pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
+ index = (!is_multiedit) ? pt->runtime.idx_orig : i + 1;
+ if (pt_active != NULL) {
+ rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i + 1);
+ ok |= apply(gso, gps_active, rot_eval, index, radius, pc2);
include_last = false;
}
}
@@ -1669,10 +1686,11 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
* (but wasn't added then, to avoid double-ups).
*/
pt = &gps->points[i];
- if (pt->runtime.pt_orig != NULL) {
- rot_eval = gpsculpt_rotation_eval_get(&gso->gsc, gps, pt, i);
- changed |= apply(
- gso, gps->runtime.gps_orig, rot_eval, pt->runtime.idx_orig, radius, pc1);
+ pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
+ index = (!is_multiedit) ? pt->runtime.idx_orig : i;
+ if (pt_active != NULL) {
+ rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i);
+ changed |= apply(gso, gps_active, rot_eval, index, radius, pc1);
include_last = false;
}
}
@@ -1684,11 +1702,15 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
}
/* Apply sculpt brushes to strokes in the given frame */
-static bool gpsculpt_brush_do_frame(
- bContext *C, tGP_BrushEditData *gso, bGPDlayer *gpl, bGPDframe *gpf, float diff_mat[4][4])
+static bool gpsculpt_brush_do_frame(bContext *C,
+ tGP_BrushEditData *gso,
+ bGPDlayer *gpl,
+ bGPDframe *gpf,
+ const float diff_mat[4][4])
{
bool changed = false;
Object *ob = CTX_data_active_object(C);
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd);
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
/* skip strokes that are invalid for current view */
@@ -1721,18 +1743,19 @@ static bool gpsculpt_brush_do_frame(
case GP_SCULPT_TYPE_GRAB: /* Grab points */
{
- if (gps->runtime.gps_orig != NULL) {
+ bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
+ if (gps_active != NULL) {
if (gso->first) {
/* First time this brush stroke is being applied:
* 1) Prepare data buffers (init/clear) for this stroke
* 2) Use the points now under the cursor
*/
- gp_brush_grab_stroke_init(gso, gps->runtime.gps_orig);
+ gp_brush_grab_stroke_init(gso, gps_active);
changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_grab_store_points);
}
else {
/* Apply effect to the stored points */
- gp_brush_grab_apply_cached(gso, gps->runtime.gps_orig, diff_mat);
+ gp_brush_grab_apply_cached(gso, gps_active, diff_mat);
changed |= true;
}
}
@@ -1863,8 +1886,7 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
}
/* affect strokes in this frame */
- changed |= gpsculpt_brush_do_frame(
- C, gso, gpl, (gpf == gpl->actframe) ? gpf_eval : gpf, diff_mat);
+ changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpf, diff_mat);
}
}
}
@@ -2080,7 +2102,7 @@ static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *eve
ARegion *ar = CTX_wm_region(C);
/* ensure that we'll have a new frame to draw on */
- gpsculpt_brush_init_stroke(gso);
+ gpsculpt_brush_init_stroke(C, gso);
/* apply first dab... */
gso->is_painting = true;
@@ -2195,7 +2217,7 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even
gso->is_painting = true;
gso->first = true;
- gpsculpt_brush_init_stroke(gso);
+ gpsculpt_brush_init_stroke(C, gso);
gpsculpt_brush_apply_event(C, op, event);
break;
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index c22e3bda0b1..67ffc6adc9f 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -492,58 +492,53 @@ static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op)
bGPdata *gpd_src = (bGPdata *)ob_src->data;
bGPDlayer *gpl_src = BKE_gpencil_layer_getactive(gpd_src);
- /* sanity checks */
+ /* Sanity checks. */
if (ELEM(NULL, gpd_src, gpl_src, ob_dst)) {
return OPERATOR_CANCELLED;
}
- /* cannot copy itself and check destination type */
+ /* Cannot copy itself and check destination type. */
if ((ob_src == ob_dst) || (ob_dst->type != OB_GPENCIL)) {
return OPERATOR_CANCELLED;
}
bGPdata *gpd_dst = (bGPdata *)ob_dst->data;
- /* make copy of layer */
- bGPDlayer *gpl_dst = MEM_dupallocN(gpl_src);
- gpl_dst->prev = gpl_dst->next = NULL;
- BLI_addtail(&gpd_dst->layers, gpl_dst);
- BLI_uniquename(&gpd_dst->layers,
- gpl_dst,
- DATA_("GP_Layer"),
- '.',
- offsetof(bGPDlayer, info),
- sizeof(gpl_dst->info));
+ /* Create new layer. */
+ bGPDlayer *gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl_src->info, true);
+ /* Need to copy some variables (not all). */
+ gpl_dst->onion_flag = gpl_src->onion_flag;
+ gpl_dst->thickness = gpl_src->thickness;
+ gpl_dst->line_change = gpl_src->line_change;
+ copy_v4_v4(gpl_dst->tintcolor, gpl_src->tintcolor);
+ gpl_dst->opacity = gpl_src->opacity;
- /* copy frames */
- BLI_listbase_clear(&gpl_dst->frames);
+ /* Create all frames. */
for (bGPDframe *gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
if ((mode == GP_LAYER_COPY_OBJECT_ACT_FRAME) && (gpf_src != gpl_src->actframe)) {
continue;
}
- /* make a copy of source frame */
- bGPDframe *gpf_dst = MEM_dupallocN(gpf_src);
- gpf_dst->prev = gpf_dst->next = NULL;
- BLI_addtail(&gpl_dst->frames, gpf_dst);
+ /* Create new frame. */
+ bGPDframe *gpf_dst = BKE_gpencil_frame_addnew(gpl_dst, gpf_src->framenum);
- /* copy strokes */
- BLI_listbase_clear(&gpf_dst->strokes);
+ /* Copy strokes. */
for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
- /* make copy of source stroke */
+ /* Make copy of source stroke. */
bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
- /* check if material is in destination object,
- * otherwise add the slot with the material
- */
+ /* Check if material is in destination object,
+ * otherwise add the slot with the material. */
Material *ma_src = give_current_material(ob_src, gps_src->mat_nr + 1);
- int idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
+ if (ma_src != NULL) {
+ int idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
- /* Reassign the stroke material to the right slot in destination object. */
- gps_dst->mat_nr = idx;
+ /* Reassign the stroke material to the right slot in destination object. */
+ gps_dst->mat_nr = idx;
+ }
- /* add new stroke to frame */
+ /* Add new stroke to frame. */
BLI_addtail(&gpf_dst->strokes, gps_dst);
}
}
@@ -566,7 +561,7 @@ void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot)
};
/* identifiers */
- ot->name = "Duplicate Layer to new Object";
+ ot->name = "Duplicate Layer to New Object";
ot->idname = "GPENCIL_OT_layer_duplicate_object";
ot->description = "Make a copy of the active Grease Pencil layer to new object";
@@ -797,7 +792,7 @@ static int gp_frame_clean_loose_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_frame_clean_loose(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Clean Loose points";
+ ot->name = "Clean Loose Points";
ot->idname = "GPENCIL_OT_frame_clean_loose";
ot->description = "Remove loose points";
@@ -840,6 +835,10 @@ static int gp_hide_exec(bContext *C, wmOperator *op)
if (gpl != layer) {
gpl->flag |= GP_LAYER_HIDE;
}
+ else {
+ /* Be sure the active layer is unhidden. */
+ gpl->flag &= ~GP_LAYER_HIDE;
+ }
}
}
else {
@@ -1385,9 +1384,9 @@ static int gp_stroke_arrange_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_stroke_arrange(wmOperatorType *ot)
{
static const EnumPropertyItem slot_move[] = {
+ {GP_STROKE_MOVE_TOP, "TOP", 0, "Bring to Front", ""},
{GP_STROKE_MOVE_UP, "UP", 0, "Bring Forward", ""},
{GP_STROKE_MOVE_DOWN, "DOWN", 0, "Send Backward", ""},
- {GP_STROKE_MOVE_TOP, "TOP", 0, "Bring to Front", ""},
{GP_STROKE_MOVE_BOTTOM, "BOTTOM", 0, "Send to Back", ""},
{0, NULL, 0, NULL, NULL}};
@@ -1419,7 +1418,7 @@ static int gp_stroke_change_color_exec(bContext *C, wmOperator *op)
bGPdata *gpd = ED_gpencil_data_get_active(C);
Object *ob = CTX_data_active_object(C);
if (name[0] == '\0') {
- ma = give_current_material(ob, ob->actcol);
+ ma = BKE_material_gpencil_get(ob, ob->actcol);
}
else {
ma = (Material *)BKE_libblock_find_name(bmain, ID_MA, name);
@@ -1539,9 +1538,10 @@ static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op))
}
/* unlock color */
Material *tmp_ma = give_current_material(ob, gps->mat_nr + 1);
-
- tmp_ma->gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
- DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE);
+ if (tmp_ma) {
+ tmp_ma->gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
+ DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE);
+ }
}
}
}
@@ -1580,7 +1580,9 @@ void GPENCIL_OT_stroke_lock_color(wmOperatorType *ot)
/* ******************* Brush create presets ************************** */
static int gp_brush_presets_create_exec(bContext *C, wmOperator *UNUSED(op))
{
- BKE_brush_gpencil_presets(C);
+ Main *bmain = CTX_data_main(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ BKE_brush_gpencil_presets(bmain, ts);
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -2291,7 +2293,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
short *totcol = give_totcolp(ob_src);
for (short i = 0; i < *totcol; i++) {
- Material *tmp_ma = give_current_material(ob_src, i + 1);
+ Material *tmp_ma = BKE_material_gpencil_get(ob_src, i + 1);
BKE_gpencil_object_material_ensure(bmain, ob_dst, tmp_ma);
}
@@ -2325,7 +2327,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
/* Reassign material. Look old material and try to find in destination. */
- ma_src = give_current_material(ob_src, gps->mat_nr + 1);
+ ma_src = BKE_material_gpencil_get(ob_src, gps->mat_nr + 1);
gps->mat_nr = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
bGPDspoint *pt;
@@ -2433,7 +2435,7 @@ static int gpencil_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
}
for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
+ ma = BKE_material_gpencil_get(ob, i + 1);
if (ma) {
gp_style = ma->gp_style;
gp_style->flag |= GP_STYLE_COLOR_LOCKED;
@@ -2453,7 +2455,7 @@ static int gpencil_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
continue;
}
- ma = give_current_material(ob, gps->mat_nr + 1);
+ ma = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
gp_style = ma->gp_style;
@@ -2496,7 +2498,7 @@ static int gpencil_color_isolate_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
Object *ob = CTX_data_active_object(C);
- Material *active_ma = give_current_material(ob, ob->actcol);
+ Material *active_ma = BKE_material_gpencil_get(ob, ob->actcol);
MaterialGPencilStyle *active_color = BKE_material_gpencil_settings_get(ob, ob->actcol);
MaterialGPencilStyle *gp_style;
@@ -2516,7 +2518,7 @@ static int gpencil_color_isolate_exec(bContext *C, wmOperator *op)
Material *ma = NULL;
short *totcol = give_totcolp(ob);
for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
+ ma = BKE_material_gpencil_get(ob, i + 1);
/* Skip if this is the active one */
if ((ma == NULL) || (ma == active_ma)) {
continue;
@@ -2536,7 +2538,7 @@ static int gpencil_color_isolate_exec(bContext *C, wmOperator *op)
if (isolate) {
/* Set flags on all "other" colors */
for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
+ ma = BKE_material_gpencil_get(ob, i + 1);
if (ma == NULL) {
continue;
}
@@ -2553,7 +2555,7 @@ static int gpencil_color_isolate_exec(bContext *C, wmOperator *op)
else {
/* Clear flags - Restore everything else */
for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
+ ma = BKE_material_gpencil_get(ob, i + 1);
if (ma == NULL) {
continue;
}
@@ -2618,7 +2620,7 @@ static int gpencil_color_hide_exec(bContext *C, wmOperator *op)
/* hide unselected */
MaterialGPencilStyle *color = NULL;
for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
+ ma = BKE_material_gpencil_get(ob, i + 1);
if (ma) {
color = ma->gp_style;
if (active_color != color) {
@@ -2681,7 +2683,7 @@ static int gpencil_color_reveal_exec(bContext *C, wmOperator *UNUSED(op))
MaterialGPencilStyle *gp_style = NULL;
for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
+ ma = BKE_material_gpencil_get(ob, i + 1);
if (ma) {
gp_style = ma->gp_style;
gp_style->flag &= ~GP_STYLE_COLOR_HIDE;
@@ -2734,7 +2736,7 @@ static int gpencil_color_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
MaterialGPencilStyle *gp_style = NULL;
for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
+ ma = BKE_material_gpencil_get(ob, i + 1);
if (ma) {
gp_style = ma->gp_style;
gp_style->flag |= GP_STYLE_COLOR_LOCKED;
@@ -2787,7 +2789,7 @@ static int gpencil_color_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
MaterialGPencilStyle *gp_style = NULL;
for (short i = 0; i < *totcol; i++) {
- ma = give_current_material(ob, i + 1);
+ ma = BKE_material_gpencil_get(ob, i + 1);
if (ma) {
gp_style = ma->gp_style;
gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
@@ -2913,6 +2915,54 @@ void GPENCIL_OT_color_select(wmOperatorType *ot)
RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
+/* ***************** Set selected stroke material the active material ************************ */
+
+static int gpencil_set_active_material_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bool changed = false;
+
+ /* Sanity checks. */
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Loop all selected strokes. */
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* Change Active material. */
+ ob->actcol = gps->mat_nr + 1;
+ changed = true;
+ break;
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+
+ /* notifiers */
+ if (changed) {
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_set_active_material(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set active material";
+ ot->idname = "GPENCIL_OT_set_active_material";
+ ot->description = "Set the selected stroke material as the active material";
+
+ /* callbacks */
+ ot->exec = gpencil_set_active_material_exec;
+ ot->poll = gpencil_active_color_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* Parent GPencil object to Lattice */
bool ED_gpencil_add_lattice_modifier(const bContext *C,
ReportList *reports,
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 9fd1d031bb1..c4f18c60f4d 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -237,11 +237,38 @@ static int gpencil_selectmode_toggle_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
const int mode = RNA_int_get(op->ptr, "mode");
+ bool changed = false;
+
+ if (ts->gpencil_selectmode_edit == mode) {
+ return OPERATOR_FINISHED;
+ }
/* Just set mode */
ts->gpencil_selectmode_edit = mode;
+ /* If the mode is Stroke, extend selection. */
+ if ((ob) && (ts->gpencil_selectmode_edit == GP_SELECTMODE_STROKE)) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ /* Extend selection to all points in all selected strokes. */
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ if ((gps->flag & GP_STROKE_SELECT) && (gps->totpoints > 1)) {
+ changed = true;
+ bGPDspoint *pt;
+ for (int i = 0; i < gps->totpoints; i++) {
+ pt = &gps->points[i];
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ }
+ }
+ CTX_DATA_END;
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ }
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
@@ -328,7 +355,7 @@ static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op)
Paint *paint = &ts->gp_paint->paint;
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
- BKE_brush_gpencil_presets(C);
+ BKE_brush_gpencil_presets(bmain, ts);
}
BKE_paint_toolslots_brush_validate(bmain, &ts->gp_paint->paint);
}
@@ -1191,10 +1218,15 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
GHash *ma_to_name = gp_strokes_copypastebuf_colors_material_to_name_create(bmain);
for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
if (ED_gpencil_stroke_can_use(C, gps)) {
+ Material *ma = give_current_material(ob, gps->mat_nr + 1);
+ /* Avoid default material. */
+ if (ma == NULL) {
+ continue;
+ }
+
char **ma_name_val;
if (!BLI_ghash_ensure_p(
gp_strokes_copypastebuf_colors, &gps->mat_nr, (void ***)&ma_name_val)) {
- Material *ma = give_current_material(ob, gps->mat_nr + 1);
char *ma_name = BLI_ghash_lookup(ma_to_name, ma);
*ma_name_val = MEM_dupallocN(ma_name);
}
@@ -1241,8 +1273,8 @@ static bool gp_strokes_paste_poll(bContext *C)
}
typedef enum eGP_PasteMode {
- GP_COPY_ONLY = -1,
- GP_COPY_MERGE = 1,
+ GP_COPY_BY_LAYER = -1,
+ GP_COPY_TO_ACTIVE = 1,
} eGP_PasteMode;
static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
@@ -1275,7 +1307,7 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
/* no active layer - let's just create one */
gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
}
- else if ((gpencil_layer_is_editable(gpl) == false) && (type == GP_COPY_MERGE)) {
+ else if ((gpencil_layer_is_editable(gpl) == false) && (type == GP_COPY_TO_ACTIVE)) {
BKE_report(
op->reports, RPT_ERROR, "Can not paste strokes when active layer is hidden or locked");
return OPERATOR_CANCELLED;
@@ -1328,7 +1360,7 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
if (ED_gpencil_stroke_can_use(C, gps)) {
/* Need to verify if layer exists */
- if (type != GP_COPY_MERGE) {
+ if (type != GP_COPY_TO_ACTIVE) {
gpl = BLI_findstring(&gpd->layers, gps->runtime.tmp_layerinfo, offsetof(bGPDlayer, info));
if (gpl == NULL) {
/* no layer - use active (only if layer deleted before paste) */
@@ -1361,7 +1393,7 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
/* Remap material */
Material *ma = BLI_ghash_lookup(new_colors, POINTER_FROM_INT(new_stroke->mat_nr));
new_stroke->mat_nr = BKE_gpencil_object_material_get_index(ob, ma);
- BLI_assert(new_stroke->mat_nr >= 0); /* have to add the material first */
+ CLAMP_MIN(new_stroke->mat_nr, 0);
}
}
}
@@ -1379,15 +1411,15 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_paste(wmOperatorType *ot)
{
static const EnumPropertyItem copy_type[] = {
- {GP_COPY_ONLY, "COPY", 0, "Copy", ""},
- {GP_COPY_MERGE, "MERGE", 0, "Merge", ""},
+ {GP_COPY_TO_ACTIVE, "ACTIVE", 0, "Paste to Active", ""},
+ {GP_COPY_BY_LAYER, "LAYER", 0, "Paste by Layer", ""},
{0, NULL, 0, NULL, NULL},
};
/* identifiers */
ot->name = "Paste Strokes";
ot->idname = "GPENCIL_OT_paste";
- ot->description = "Paste previously copied strokes or copy and merge in active layer";
+ ot->description = "Paste previously copied strokes to active layer or to original layer";
/* callbacks */
ot->exec = gp_strokes_paste_exec;
@@ -1397,33 +1429,18 @@ void GPENCIL_OT_paste(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", copy_type, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", copy_type, GP_COPY_TO_ACTIVE, "Type", "");
}
/* ******************* Move To Layer ****************************** */
-static int gp_move_to_layer_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
-{
- uiPopupMenu *pup;
- uiLayout *layout;
-
- /* call the menu, which will call this operator again, hence the canceled */
- pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
- layout = UI_popup_menu_layout(pup);
- uiItemsEnumO(layout, "GPENCIL_OT_move_to_layer", "layer");
- UI_popup_menu_end(C, pup);
-
- return OPERATOR_INTERFACE;
-}
-
-// FIXME: allow moving partial strokes
static int gp_move_to_layer_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = CTX_data_gpencil_data(C);
Scene *scene = CTX_data_scene(C);
bGPDlayer *target_layer = NULL;
ListBase strokes = {NULL, NULL};
- int layer_num = RNA_enum_get(op->ptr, "layer");
+ int layer_num = RNA_int_get(op->ptr, "layer");
const bool use_autolock = (bool)(gpd->flag & GP_DATA_AUTOLOCK_LAYERS);
if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
@@ -1436,23 +1453,16 @@ static int gp_move_to_layer_exec(bContext *C, wmOperator *op)
gpd->flag &= ~GP_DATA_AUTOLOCK_LAYERS;
}
- /* Get layer or create new one */
- if (layer_num == -1) {
- /* Create layer */
- target_layer = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
- }
- else {
- /* Try to get layer */
- target_layer = BLI_findlink(&gpd->layers, layer_num);
+ /* Try to get layer */
+ target_layer = BLI_findlink(&gpd->layers, layer_num);
- if (target_layer == NULL) {
- /* back autolock status */
- if (use_autolock) {
- gpd->flag |= GP_DATA_AUTOLOCK_LAYERS;
- }
- BKE_reportf(op->reports, RPT_ERROR, "There is no layer number %d", layer_num);
- return OPERATOR_CANCELLED;
+ if (target_layer == NULL) {
+ /* back autolock status */
+ if (use_autolock) {
+ gpd->flag |= GP_DATA_AUTOLOCK_LAYERS;
}
+ BKE_reportf(op->reports, RPT_ERROR, "There is no layer number %d", layer_num);
+ return OPERATOR_CANCELLED;
}
/* Extract all strokes to move to this layer
@@ -1520,16 +1530,14 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot)
"Move selected strokes to another layer"; // XXX: allow moving individual points too?
/* callbacks */
- ot->invoke = gp_move_to_layer_invoke;
ot->exec = gp_move_to_layer_exec;
ot->poll = gp_stroke_edit_poll; // XXX?
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* gp layer to use (dynamic enum) */
- ot->prop = RNA_def_enum(ot->srna, "layer", DummyRNA_DEFAULT_items, 0, "Grease Pencil Layer", "");
- RNA_def_enum_funcs(ot->prop, ED_gpencil_layers_with_new_enum_itemf);
+ /* GPencil layer to use. */
+ ot->prop = RNA_def_int(ot->srna, "layer", 0, 0, INT_MAX, "Grease Pencil Layer", "", 0, INT_MAX);
}
/* ********************* Add Blank Frame *************************** */
@@ -3040,7 +3048,7 @@ static void gpencil_flip_stroke(bGPDstroke *gps)
static void gpencil_stroke_copy_point(bGPDstroke *gps,
bGPDspoint *point,
int idx,
- float delta[3],
+ const float delta[3],
float pressure,
float strength,
float deltatime)
@@ -4092,7 +4100,7 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
/* add duplicate materials */
/* XXX same material can be in multiple slots. */
- ma = give_current_material(ob, gps->mat_nr + 1);
+ ma = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma);
@@ -4165,7 +4173,7 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
}
- ma = give_current_material(ob, gps->mat_nr + 1);
+ ma = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
gps->mat_nr = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma);
}
}
@@ -4508,6 +4516,10 @@ static int gpencil_cutter_lasso_select(bContext *C,
/* dissolve selected points */
bGPDstroke *gpsn;
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl->flag & GP_LAYER_LOCKED) {
+ continue;
+ }
+
bGPDframe *gpf = gpl->actframe;
if (gpf == NULL) {
continue;
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index 5637e755198..993ec15248f 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -48,6 +48,7 @@
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_paint.h"
+#include "BKE_report.h"
#include "ED_gpencil.h"
#include "ED_screen.h"
@@ -61,7 +62,6 @@
#include "IMB_imbuf_types.h"
#include "GPU_immediate.h"
-#include "GPU_draw.h"
#include "GPU_matrix.h"
#include "GPU_framebuffer.h"
#include "GPU_state.h"
@@ -1038,7 +1038,15 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
gps->flag |= GP_STROKE_CYCLIC;
gps->flag |= GP_STROKE_3DSPACE;
- gps->mat_nr = BKE_gpencil_object_material_ensure(tgpf->bmain, tgpf->ob, tgpf->mat);
+ gps->mat_nr = BKE_gpencil_object_material_get_index_from_brush(tgpf->ob, brush);
+ if (gps->mat_nr < 0) {
+ if (tgpf->ob->actcol - 1 < 0) {
+ gps->mat_nr = 0;
+ }
+ else {
+ gps->mat_nr = tgpf->ob->actcol - 1;
+ }
+ }
/* allocate memory for storage points */
gps->totpoints = tgpf->sbuffer_used;
@@ -1346,8 +1354,28 @@ static int gpencil_fill_init(bContext *C, wmOperator *op)
/* start of interactive part of operator */
static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
+ Object *ob = CTX_data_active_object(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
tGPDfill *tgpf = NULL;
+ /* Fill tool needs a material (cannot use default material) */
+ bool valid = true;
+ if ((brush) && (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED)) {
+ if (brush->gpencil_settings->material == NULL) {
+ valid = false;
+ }
+ }
+ else {
+ if (give_current_material(ob, ob->actcol) == NULL) {
+ valid = false;
+ }
+ }
+ if (!valid) {
+ BKE_report(op->reports, RPT_ERROR, "Fill tool needs active material.");
+ return OPERATOR_CANCELLED;
+ }
+
/* try to initialize context data needed */
if (!gpencil_fill_init(C, op)) {
gpencil_fill_exit(C, op);
@@ -1366,7 +1394,7 @@ static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
tgpf->ar->type, gpencil_fill_draw_3d, tgpf, REGION_DRAW_POST_VIEW);
}
- WM_cursor_modal_set(CTX_wm_window(C), BC_PAINTBRUSHCURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_PAINT_BRUSH);
gpencil_fill_status_indicators(C, tgpf);
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index c2a9eae272f..a8f8ec0e8c5 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -528,6 +528,7 @@ void GPENCIL_OT_color_reveal(struct wmOperatorType *ot);
void GPENCIL_OT_color_lock_all(struct wmOperatorType *ot);
void GPENCIL_OT_color_unlock_all(struct wmOperatorType *ot);
void GPENCIL_OT_color_select(struct wmOperatorType *ot);
+void GPENCIL_OT_set_active_material(struct wmOperatorType *ot);
/* convert old 2.7 files to 2.8 */
void GPENCIL_OT_convert_old_files(struct wmOperatorType *ot);
@@ -669,7 +670,9 @@ struct GP_EditableStrokes_Iter {
ED_gpencil_parent_location(depsgraph_, obact_, gpd_, gpl, gpstroke_iter.diff_mat); \
invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \
/* get evaluated frame with modifiers applied */ \
- bGPDframe *gpf_eval_ = &obeval_->runtime.gpencil_evaluated_frames[idx_eval]; \
+ bGPDframe *gpf_eval_ = (!is_multiedit_) ? \
+ &obeval_->runtime.gpencil_evaluated_frames[idx_eval] : \
+ gpf_; \
/* loop over strokes */ \
for (bGPDstroke *gps = gpf_eval_->strokes.first; gps; gps = gps->next) { \
/* skip strokes that are invalid for current view */ \
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index 86de9a75a56..1438c33a972 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -560,7 +560,7 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent
tgpi->ar->type, gpencil_interpolate_draw_3d, tgpi, REGION_DRAW_POST_VIEW);
/* set cursor to indicate modal */
- WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_EW_SCROLL);
/* update shift indicator in header */
gpencil_interpolate_status_indicators(C, tgpi);
diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c
index cb11bb4cd63..36cef3ccdc0 100644
--- a/source/blender/editors/gpencil/gpencil_merge.c
+++ b/source/blender/editors/gpencil/gpencil_merge.c
@@ -35,6 +35,7 @@
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_gpencil.h"
+#include "BKE_main.h"
#include "BKE_material.h"
#include "WM_api.h"
@@ -97,6 +98,7 @@ static void gpencil_insert_points_to_stroke(bGPDstroke *gps,
static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpoints)
{
+ Main *bmain = CTX_data_main(C);
ToolSettings *ts = CTX_data_tool_settings(C);
Object *ob = CTX_data_active_object(C);
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
@@ -111,7 +113,7 @@ static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpo
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
/* create new brushes */
- BKE_brush_gpencil_presets(C);
+ BKE_brush_gpencil_presets(bmain, ts);
}
Brush *brush = paint->brush;
@@ -449,7 +451,7 @@ static bool gp_strokes_merge_poll(bContext *C)
/* check material */
Material *ma = NULL;
- ma = give_current_material(ob, ob->actcol);
+ ma = BKE_material_gpencil_get(ob, ob->actcol);
if ((ma == NULL) || (ma->gp_style == NULL)) {
return false;
}
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index acdf5c2be4f..ce410f3e52d 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -264,6 +264,8 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_move_to_layer);
WM_operatortype_append(GPENCIL_OT_layer_change);
+ WM_operatortype_append(GPENCIL_OT_set_active_material);
+
WM_operatortype_append(GPENCIL_OT_snap_to_grid);
WM_operatortype_append(GPENCIL_OT_snap_to_cursor);
WM_operatortype_append(GPENCIL_OT_snap_cursor_to_selected);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 900883bd0af..f29e782c618 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -113,6 +113,28 @@ typedef enum eGPencil_PaintFlags {
GP_PAINTFLAG_REQ_VECTOR = (1 << 6),
} eGPencil_PaintFlags;
+/* Temporary Guide data */
+typedef struct tGPguide {
+ /** guide spacing */
+ float spacing;
+ /** half guide spacing */
+ float half_spacing;
+ /** origin */
+ float origin[2];
+ /** rotated point */
+ float rot_point[2];
+ /** rotated point */
+ float rot_angle;
+ /** initial stroke direction */
+ float stroke_angle;
+ /** initial origin direction */
+ float origin_angle;
+ /** initial origin distance */
+ float origin_distance;
+ /** initial line for guides */
+ float unit[2];
+} tGPguide;
+
/* Temporary 'Stroke' Operation data
* "p" = op->customdata
*/
@@ -224,12 +246,7 @@ typedef struct tGPsdata {
float totpixlen;
/* guide */
- /** guide spacing */
- float guide_spacing;
- /** half guide spacing */
- float half_spacing;
- /** origin */
- float origin[2];
+ tGPguide guide;
ReportList *reports;
} tGPsdata;
@@ -581,6 +598,7 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
float sco[2] = {0.0f};
float a[2], b[2], c[2], d[2];
float pressure = 0.0f;
+ float strength = 0.0f;
const float average_fac = 1.0f / steps;
/* Compute smoothed coordinate by taking the ones nearby */
@@ -588,21 +606,25 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
copy_v2_v2(a, &pta->x);
madd_v2_v2fl(sco, a, average_fac);
pressure += pta->pressure * average_fac;
+ strength += pta->strength * average_fac;
}
if (ptb) {
copy_v2_v2(b, &ptb->x);
madd_v2_v2fl(sco, b, average_fac);
pressure += ptb->pressure * average_fac;
+ strength += ptb->strength * average_fac;
}
if (ptc) {
copy_v2_v2(c, &ptc->x);
madd_v2_v2fl(sco, c, average_fac);
pressure += ptc->pressure * average_fac;
+ strength += ptc->strength * average_fac;
}
if (ptd) {
copy_v2_v2(d, &ptd->x);
madd_v2_v2fl(sco, d, average_fac);
pressure += ptd->pressure * average_fac;
+ strength += ptd->strength * average_fac;
}
/* Based on influence factor, blend between original and optimal smoothed coordinate. */
@@ -610,10 +632,156 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
copy_v2_v2(&ptc->x, c);
/* Interpolate pressure. */
ptc->pressure = interpf(ptc->pressure, pressure, inf);
+ /* Interpolate strength. */
+ ptc->strength = interpf(ptc->strength, strength, inf);
+}
+
+/* Helper: Apply smooth to segment from Index to Index */
+static void gp_smooth_segment(bGPdata *gpd, const float inf, int from_idx, int to_idx)
+{
+ const short num_points = to_idx - from_idx;
+ /* Do nothing if not enough points to smooth out */
+ if ((num_points < 3) || (inf == 0.0f)) {
+ return;
+ }
+
+ if (from_idx <= 2) {
+ return;
+ }
+
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ const float average_fac = 0.25f;
+
+ for (int i = from_idx; i < to_idx + 1; i++) {
+
+ tGPspoint *pta = i >= 3 ? &points[i - 3] : NULL;
+ tGPspoint *ptb = i >= 2 ? &points[i - 2] : NULL;
+ tGPspoint *ptc = i >= 1 ? &points[i - 1] : &points[i];
+ tGPspoint *ptd = &points[i];
+
+ float sco[2] = {0.0f};
+
+ /* Compute smoothed coordinate by taking the ones nearby */
+ if (pta) {
+ madd_v2_v2fl(sco, &pta->x, average_fac);
+ }
+ else {
+ madd_v2_v2fl(sco, &ptc->x, average_fac);
+ }
+
+ if (ptb) {
+ madd_v2_v2fl(sco, &ptb->x, average_fac);
+ }
+ else {
+ madd_v2_v2fl(sco, &ptc->x, average_fac);
+ }
+
+ madd_v2_v2fl(sco, &ptc->x, average_fac);
+
+ madd_v2_v2fl(sco, &ptd->x, average_fac);
+
+ /* Based on influence factor, blend between original and optimal smoothed coordinate. */
+ interp_v2_v2v2(&ptc->x, &ptc->x, sco, inf);
+ }
+}
+
+/* Smooth all the sections created with fake events to avoid abrupt transitions.
+ *
+ * As the fake events add points between two real events, this produces a straight line, but if
+ * there is 3 or more real points that used fakes, the stroke is not smooth and produces abrupt
+ * angles.
+ * This function reads these segments and finds the real points and smooth with the surrounding
+ * points. */
+static void gp_smooth_fake_segments(tGPsdata *p)
+{
+ bGPdata *gpd = p->gpd;
+ Brush *brush = p->brush;
+
+ if (brush->gpencil_settings->input_samples < 2) {
+ return;
+ }
+
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ tGPspoint *pt = NULL;
+ /* Index where segment starts. */
+ int from_idx = 0;
+ /* Index where segment ends. */
+ int to_idx = 0;
+
+ bool doit = false;
+ /* Loop all points except the extremes. */
+ for (int i = 1; i < gpd->runtime.sbuffer_used - 1; i++) {
+ pt = &points[i];
+ bool is_fake = (bool)(pt->tflag & GP_TPOINT_FAKE);
+ to_idx = i;
+
+ /* Detect fake points in the stroke. */
+ if ((!doit) && (is_fake)) {
+ from_idx = i;
+ doit = true;
+ }
+ /* If detect control point after fake points, select a segment with same length in both sides,
+ * except if it is more than stroke length. */
+ if ((doit) && (!is_fake)) {
+ if (i + (i - from_idx) < gpd->runtime.sbuffer_used - 1) {
+ to_idx = i + (i - from_idx);
+ /* Smooth this segments (need loop to get cumulative smooth). */
+ for (int r = 0; r < 5; r++) {
+ gp_smooth_segment(gpd, 0.1f, from_idx, to_idx);
+ }
+ }
+ else {
+ break;
+ }
+ /* Reset to new segments. */
+ from_idx = i;
+ doit = false;
+ }
+ }
+}
+
+/* Smooth the section added with fake events when pen moves very fast. */
+static void gp_smooth_fake_events(tGPsdata *p, int size_before, int size_after)
+{
+ bGPdata *gpd = p->gpd;
+ const short totpoints = size_after - size_before - 1;
+ /* Do nothing if not enough data to smooth out. */
+ if (totpoints < 1) {
+ return;
+ }
+
+ /* Back two points to get smoother effect. */
+ size_before -= 2;
+ CLAMP_MIN(size_before, 1);
+
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ /* Extreme points. */
+ const tGPspoint *pta = &points[size_before - 1];
+ const tGPspoint *ptb = &points[size_after - 1];
+ tGPspoint *pt1, *pt2;
+ int i;
+
+ /* Get total length of the segment to smooth. */
+ float totlen = 0.0f;
+ for (i = size_before; i < size_after; i++) {
+ pt1 = &points[i - 1];
+ pt2 = &points[i];
+ totlen += len_v2v2(&pt1->x, &pt2->x);
+ }
+ /* Smooth interpolating the position of the points. */
+ float pointlen = 0.0f;
+ for (i = size_before; i < size_after - 1; i++) {
+ pt1 = &points[i - 1];
+ pt2 = &points[i];
+ pointlen += len_v2v2(&pt1->x, &pt2->x);
+ pt2->pressure = interpf(ptb->pressure, pta->pressure, pointlen / totlen);
+ pt2->strength = interpf(ptb->strength, pta->strength, pointlen / totlen);
+ }
}
/* add current stroke-point to buffer (returns whether point was successfully added) */
-static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure, double curtime)
+static short gp_stroke_addpoint(
+ tGPsdata *p, const float mval[2], float pressure, double curtime, bool is_fake)
{
bGPdata *gpd = p->gpd;
Brush *brush = p->brush;
@@ -672,6 +840,14 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
/* get pointer to destination point */
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_used);
+ /* Set if point was created by fake events. */
+ if (is_fake) {
+ pt->tflag |= GP_TPOINT_FAKE;
+ }
+ else {
+ pt->tflag &= ~GP_TPOINT_FAKE;
+ }
+
/* store settings */
/* pressure */
if (brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE) {
@@ -829,7 +1005,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
bGPDspoint *pts;
MDeformVert *dvert = NULL;
- /* first time point is adding to temporary buffer -- need to allocate new point in stroke */
+ /* First time point is adding to temporary buffer (need to allocate new point in stroke) */
if (gpd->runtime.sbuffer_used == 0) {
gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
if (gps->dvert != NULL) {
@@ -920,6 +1096,22 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
(!is_depth);
int i, totelem;
+ /* For very low pressure at the end, truncate stroke. */
+ if (p->paintmode == GP_PAINTMODE_DRAW) {
+ int last_i = gpd->runtime.sbuffer_used - 1;
+ while (last_i > 0) {
+ ptc = (tGPspoint *)gpd->runtime.sbuffer + last_i;
+ if (ptc->pressure > 0.001f) {
+ break;
+ }
+ else {
+ gpd->runtime.sbuffer_used = last_i - 1;
+ CLAMP_MIN(gpd->runtime.sbuffer_used, 1);
+ }
+
+ last_i--;
+ }
+ }
/* Since strokes are so fine,
* when using their depth we need a margin otherwise they might get missed. */
int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
@@ -1170,6 +1362,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
}
}
+ /* Smooth any point created with fake events when the mouse/pen move very fast. */
+ gp_smooth_fake_segments(p);
+
pt = gps->points;
dvert = gps->dvert;
@@ -1218,6 +1413,13 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
reduce += 0.25f; /* reduce the factor */
}
}
+
+ /* Simplify adaptive */
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
+ (brush->gpencil_settings->simplify_f > 0.0f)) {
+ BKE_gpencil_simplify_stroke(gps, brush->gpencil_settings->simplify_f);
+ }
+
/* smooth thickness */
if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
(brush->gpencil_settings->thick_smoothfac > 0.0f)) {
@@ -1244,6 +1446,14 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* Save material index */
gps->mat_nr = BKE_gpencil_object_material_get_index_from_brush(p->ob, p->brush);
+ if (gps->mat_nr < 0) {
+ if (p->ob->actcol - 1 < 0) {
+ gps->mat_nr = 0;
+ }
+ else {
+ gps->mat_nr = p->ob->actcol - 1;
+ }
+ }
/* calculate UVs along the stroke */
ED_gpencil_calc_stroke_uv(obact, gps);
@@ -1802,6 +2012,7 @@ static void gp_set_default_eraser(Main *bmain, Brush *brush_dft)
/* initialize a drawing brush */
static void gp_init_drawing_brush(bContext *C, tGPsdata *p)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = CTX_data_tool_settings(C);
@@ -1810,7 +2021,7 @@ static void gp_init_drawing_brush(bContext *C, tGPsdata *p)
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
/* create new brushes */
- BKE_brush_gpencil_presets(C);
+ BKE_brush_gpencil_presets(bmain, ts);
changed = true;
}
/* be sure curves are initializated */
@@ -2457,10 +2668,10 @@ static void gpencil_draw_cursor_set(tGPsdata *p)
#if 0
Brush *brush = p->brush;
if ((p->paintmode == GP_PAINTMODE_ERASER) || (brush->gpencil_tool == GPAINT_TOOL_ERASE)) {
- WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */
+ WM_cursor_modal_set(p->win, WM_CURSOR_CROSS); /* XXX need a better cursor */
}
else {
- WM_cursor_modal_set(p->win, CURSOR_NONE);
+ WM_cursor_modal_set(p->win, WM_CURSOR_NONE);
}
#endif
}
@@ -2537,7 +2748,8 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
/* ------------------------------- */
/* create a new stroke point at the point indicated by the painting context */
-static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgraph *depsgraph)
+static void gpencil_draw_apply(
+ bContext *C, wmOperator *op, tGPsdata *p, Depsgraph *depsgraph, bool is_fake)
{
bGPdata *gpd = p->gpd;
tGPspoint *pt = NULL;
@@ -2566,7 +2778,7 @@ static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgra
}
/* try to add point */
- short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
+ short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime, is_fake);
/* handle errors while adding point */
if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) {
@@ -2580,12 +2792,12 @@ static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgra
/* XXX We only need to reuse previous point if overflow! */
if (ok == GP_STROKEADD_OVERFLOW) {
p->inittime = p->ocurtime;
- gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime);
+ gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime, is_fake);
}
else {
p->inittime = p->curtime;
}
- gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
+ gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime, is_fake);
}
else if (ok == GP_STROKEADD_INVALID) {
/* the painting operation cannot continue... */
@@ -2634,19 +2846,26 @@ static void gp_rotate_v2_v2v2fl(float v[2],
static float gp_snap_to_grid_fl(float v, const float offset, const float spacing)
{
if (spacing > 0.0f) {
- return roundf(v / spacing) * spacing + fmodf(offset, spacing);
+ v -= spacing * 0.5f;
+ v -= offset;
+ v = roundf((v + spacing * 0.5f) / spacing) * spacing;
+ v += offset;
+ return v;
}
else {
return v;
}
}
-static void UNUSED_FUNCTION(gp_snap_to_grid_v2)(float v[2],
- const float offset[2],
- const float spacing)
+/* Helper to snap value to grid */
+static void gp_snap_to_rotated_grid_fl(float v[2],
+ const float origin[2],
+ const float spacing,
+ const float angle)
{
- v[0] = gp_snap_to_grid_fl(v[0], offset[0], spacing);
- v[1] = gp_snap_to_grid_fl(v[1], offset[1], spacing);
+ gp_rotate_v2_v2v2fl(v, v, origin, -angle);
+ v[1] = gp_snap_to_grid_fl(v[1], origin[1], spacing);
+ gp_rotate_v2_v2v2fl(v, v, origin, angle);
}
/* get reference point - screen coords to buffer coords */
@@ -2684,9 +2903,113 @@ static void gp_origin_get(tGPsdata *p, float origin[2])
gp_point_3d_to_xy(gsc, p->gpd->runtime.sbuffer_sflag, location, origin);
}
+/* speed guide initial values */
+static void gpencil_speed_guide_init(tGPsdata *p, GP_Sculpt_Guide *guide)
+{
+ /* calculate initial guide values */
+ RegionView3D *rv3d = p->ar->regiondata;
+ float scale = 1.0f;
+ if (rv3d->is_persp) {
+ float vec[3];
+ gp_get_3d_reference(p, vec);
+ mul_m4_v3(rv3d->persmat, vec);
+ scale = vec[2] * rv3d->pixsize;
+ }
+ else {
+ scale = rv3d->pixsize;
+ }
+ p->guide.spacing = guide->spacing / scale;
+ p->guide.half_spacing = p->guide.spacing * 0.5f;
+ gp_origin_get(p, p->guide.origin);
+
+ /* reference for angled snap */
+ copy_v2_v2(p->guide.unit, p->mvali);
+ p->guide.unit[0] += 1.0f;
+
+ float xy[2];
+ sub_v2_v2v2(xy, p->mvali, p->guide.origin);
+ p->guide.origin_angle = atan2f(xy[1], xy[0]) + (M_PI * 2.0f);
+
+ p->guide.origin_distance = len_v2v2(p->mvali, p->guide.origin);
+ if (guide->use_snapping && (guide->spacing > 0.0f)) {
+ p->guide.origin_distance = gp_snap_to_grid_fl(
+ p->guide.origin_distance, 0.0f, p->guide.spacing);
+ }
+
+ if (ELEM(guide->type, GP_GUIDE_RADIAL)) {
+ float angle;
+ float half_angle = guide->angle_snap * 0.5f;
+ angle = p->guide.origin_angle + guide->angle;
+ angle = fmodf(angle + half_angle, guide->angle_snap);
+ angle -= half_angle;
+ gp_rotate_v2_v2v2fl(p->guide.rot_point, p->mvali, p->guide.origin, -angle);
+ }
+ else {
+ gp_rotate_v2_v2v2fl(p->guide.rot_point, p->guide.unit, p->mvali, guide->angle);
+ }
+}
+
+/* apply speed guide */
+static void gpencil_speed_guide(tGPsdata *p, GP_Sculpt_Guide *guide)
+{
+ switch (guide->type) {
+ default:
+ case GP_GUIDE_CIRCULAR: {
+ dist_ensure_v2_v2fl(p->mval, p->guide.origin, p->guide.origin_distance);
+ break;
+ }
+ case GP_GUIDE_RADIAL: {
+ if (guide->use_snapping && (guide->angle_snap > 0.0f)) {
+ closest_to_line_v2(p->mval, p->mval, p->guide.rot_point, p->guide.origin);
+ }
+ else {
+ closest_to_line_v2(p->mval, p->mval, p->mvali, p->guide.origin);
+ }
+ break;
+ }
+ case GP_GUIDE_PARALLEL: {
+ closest_to_line_v2(p->mval, p->mval, p->mvali, p->guide.rot_point);
+ if (guide->use_snapping && (guide->spacing > 0.0f)) {
+ gp_snap_to_rotated_grid_fl(p->mval, p->guide.origin, p->guide.spacing, guide->angle);
+ }
+ break;
+ }
+ case GP_GUIDE_ISO: {
+ closest_to_line_v2(p->mval, p->mval, p->mvali, p->guide.rot_point);
+ if (guide->use_snapping && (guide->spacing > 0.0f)) {
+ gp_snap_to_rotated_grid_fl(p->mval, p->guide.origin, p->guide.spacing, p->guide.rot_angle);
+ }
+ break;
+ }
+ case GP_GUIDE_GRID: {
+ if (guide->use_snapping && (guide->spacing > 0.0f)) {
+ closest_to_line_v2(p->mval, p->mval, p->mvali, p->guide.rot_point);
+ if (p->straight == STROKE_HORIZONTAL) {
+ p->mval[1] = gp_snap_to_grid_fl(p->mval[1], p->guide.origin[1], p->guide.spacing);
+ }
+ else {
+ p->mval[0] = gp_snap_to_grid_fl(p->mval[0], p->guide.origin[0], p->guide.spacing);
+ }
+ }
+ else if (p->straight == STROKE_HORIZONTAL) {
+ p->mval[1] = p->mvali[1]; /* replace y */
+ }
+ else {
+ p->mval[0] = p->mvali[0]; /* replace x */
+ }
+ break;
+ }
+ }
+}
+
/* handle draw event */
-static void gpencil_draw_apply_event(
- bContext *C, wmOperator *op, const wmEvent *event, Depsgraph *depsgraph, float x, float y)
+static void gpencil_draw_apply_event(bContext *C,
+ wmOperator *op,
+ const wmEvent *event,
+ Depsgraph *depsgraph,
+ float x,
+ float y,
+ const bool is_fake)
{
tGPsdata *p = op->customdata;
GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
@@ -2718,6 +3041,10 @@ static void gpencil_draw_apply_event(
p->straight = STROKE_VERTICAL;
}
}
+ /* reset if a stroke angle is required */
+ if ((p->flags & GP_PAINTFLAG_REQ_VECTOR) && ((dx == 0) || (dy == 0))) {
+ p->straight = 0;
+ }
}
}
@@ -2765,6 +3092,14 @@ static void gpencil_draw_apply_event(
/* special exception for start of strokes (i.e. maybe for just a dot) */
if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
+
+ /* special exception here for too high pressure values on first touch in
+ * windows for some tablets, then we just skip first touch...
+ */
+ if (tablet && (p->pressure >= 0.99f)) {
+ return;
+ }
+
p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
/* set values */
@@ -2776,55 +3111,61 @@ static void gpencil_draw_apply_event(
/* save initial mouse */
copy_v2_v2(p->mvali, p->mval);
- /* calculate once and store snapping distance and origin */
- RegionView3D *rv3d = p->ar->regiondata;
- float scale = 1.0f;
- if (rv3d->is_persp) {
- float vec[3];
- gp_get_3d_reference(p, vec);
- mul_m4_v3(rv3d->persmat, vec);
- scale = vec[2] * rv3d->pixsize;
- }
- else {
- scale = rv3d->pixsize;
- }
- p->guide_spacing = guide->spacing / scale;
- p->half_spacing = p->guide_spacing * 0.5f;
- gp_origin_get(p, p->origin);
-
- /* special exception here for too high pressure values on first touch in
- * windows for some tablets, then we just skip first touch...
- */
- if (tablet && (p->pressure >= 0.99f)) {
- return;
+ if (is_speed_guide && !ELEM(p->paintmode, GP_PAINTMODE_ERASER, GP_PAINTMODE_SET_CP) &&
+ ((guide->use_snapping && (guide->type == GP_GUIDE_GRID)) ||
+ (guide->type == GP_GUIDE_ISO))) {
+ p->flags |= GP_PAINTFLAG_REQ_VECTOR;
}
- /* special exception for grid snapping
- * it requires direction which needs at least two points
- */
- if (!ELEM(p->paintmode, GP_PAINTMODE_ERASER, GP_PAINTMODE_SET_CP) && is_speed_guide &&
- guide->use_snapping && (guide->type == GP_GUIDE_GRID)) {
- p->flags |= GP_PAINTFLAG_REQ_VECTOR;
+ /* calculate initial guide values */
+ if (is_speed_guide) {
+ gpencil_speed_guide_init(p, guide);
}
}
/* wait for vector then add initial point */
- if (p->flags & GP_PAINTFLAG_REQ_VECTOR) {
+ if (is_speed_guide && p->flags & GP_PAINTFLAG_REQ_VECTOR) {
if (p->straight == 0) {
return;
}
p->flags &= ~GP_PAINTFLAG_REQ_VECTOR;
+ /* get initial point */
+ float pt[2];
+ sub_v2_v2v2(pt, p->mval, p->mvali);
+
+ /* get stroke angle for grids */
+ if (ELEM(guide->type, GP_GUIDE_ISO)) {
+ p->guide.stroke_angle = atan2f(pt[1], pt[0]);
+ /* determine iso angle, less weight is given for vertical strokes */
+ if (((p->guide.stroke_angle >= 0.0f) && (p->guide.stroke_angle < DEG2RAD(75))) ||
+ (p->guide.stroke_angle < DEG2RAD(-105))) {
+ p->guide.rot_angle = guide->angle;
+ }
+ else if (((p->guide.stroke_angle < 0.0f) && (p->guide.stroke_angle > DEG2RAD(-75))) ||
+ (p->guide.stroke_angle > DEG2RAD(105))) {
+ p->guide.rot_angle = -guide->angle;
+ }
+ else {
+ p->guide.rot_angle = DEG2RAD(90);
+ }
+ gp_rotate_v2_v2v2fl(p->guide.rot_point, p->guide.unit, p->mvali, p->guide.rot_angle);
+ }
+ else if (ELEM(guide->type, GP_GUIDE_GRID)) {
+ gp_rotate_v2_v2v2fl(p->guide.rot_point,
+ p->guide.unit,
+ p->mvali,
+ (p->straight == STROKE_VERTICAL) ? M_PI_2 : 0.0f);
+ }
+
/* create fake events */
float tmp[2];
- float pt[2];
copy_v2_v2(tmp, p->mval);
- sub_v2_v2v2(pt, p->mval, p->mvali);
- gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]);
+ gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], false);
if (len_v2v2(p->mval, p->mvalo)) {
sub_v2_v2v2(pt, p->mval, p->mvalo);
- gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]);
+ gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], false);
}
copy_v2_v2(p->mval, tmp);
}
@@ -2833,83 +3174,7 @@ static void gpencil_draw_apply_event(
if ((p->paintmode != GP_PAINTMODE_ERASER) && ((p->straight) || (is_speed_guide))) {
/* guided stroke */
if (is_speed_guide) {
- switch (guide->type) {
- default:
- case GP_GUIDE_CIRCULAR: {
- float distance;
- distance = len_v2v2(p->mvali, p->origin);
-
- if (guide->use_snapping && (guide->spacing > 0.0f)) {
- distance = gp_snap_to_grid_fl(distance, 0.0f, p->guide_spacing);
- }
-
- dist_ensure_v2_v2fl(p->mval, p->origin, distance);
- break;
- }
- case GP_GUIDE_RADIAL: {
- if (guide->use_snapping && (guide->angle_snap > 0.0f)) {
- float point[2];
- float xy[2];
- float angle;
- float half_angle = guide->angle_snap * 0.5f;
- sub_v2_v2v2(xy, p->mvali, p->origin);
- angle = atan2f(xy[1], xy[0]);
- angle += (M_PI * 2.0f);
- angle = fmodf(angle + half_angle, guide->angle_snap);
- angle -= half_angle;
- gp_rotate_v2_v2v2fl(point, p->mvali, p->origin, -angle);
- closest_to_line_v2(p->mval, p->mval, point, p->origin);
- }
- else {
- closest_to_line_v2(p->mval, p->mval, p->mvali, p->origin);
- }
- break;
- }
- case GP_GUIDE_PARALLEL: {
- float point[2];
- float unit[2];
- copy_v2_v2(unit, p->mvali);
- unit[0] += 1.0f; /* start from horizontal */
- gp_rotate_v2_v2v2fl(point, unit, p->mvali, guide->angle);
- closest_to_line_v2(p->mval, p->mval, p->mvali, point);
-
- if (guide->use_snapping && (guide->spacing > 0.0f)) {
- gp_rotate_v2_v2v2fl(p->mval, p->mval, p->origin, -guide->angle);
- p->mval[1] = gp_snap_to_grid_fl(
- p->mval[1] - p->half_spacing, p->origin[1], p->guide_spacing);
- gp_rotate_v2_v2v2fl(p->mval, p->mval, p->origin, guide->angle);
- }
- break;
- }
- case GP_GUIDE_GRID: {
- if (guide->use_snapping && (guide->spacing > 0.0f)) {
- float point[2];
- float unit[2];
- float angle;
- copy_v2_v2(unit, p->mvali);
- unit[0] += 1.0f; /* start from horizontal */
- angle = (p->straight == STROKE_VERTICAL) ? M_PI_2 : 0.0f;
- gp_rotate_v2_v2v2fl(point, unit, p->mvali, angle);
- closest_to_line_v2(p->mval, p->mval, p->mvali, point);
-
- if (p->straight == STROKE_HORIZONTAL) {
- p->mval[1] = gp_snap_to_grid_fl(
- p->mval[1] - p->half_spacing, p->origin[1], p->guide_spacing);
- }
- else {
- p->mval[0] = gp_snap_to_grid_fl(
- p->mval[0] - p->half_spacing, p->origin[0], p->guide_spacing);
- }
- }
- else if (p->straight == STROKE_HORIZONTAL) {
- p->mval[1] = p->mvali[1]; /* replace y */
- }
- else {
- p->mval[0] = p->mvali[0]; /* replace x */
- }
- break;
- }
- }
+ gpencil_speed_guide(p, guide);
}
else if (p->straight == STROKE_HORIZONTAL) {
p->mval[1] = p->mvali[1]; /* replace y */
@@ -2931,7 +3196,7 @@ static void gpencil_draw_apply_event(
RNA_float_set(&itemptr, "time", p->curtime - p->inittime);
/* apply the current latest drawing point */
- gpencil_draw_apply(C, op, p, depsgraph);
+ gpencil_draw_apply(C, op, p, depsgraph, is_fake);
/* force refresh */
/* just active area for now, since doing whole screen is too slow */
@@ -2997,7 +3262,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
}
/* apply this data as necessary now (as per usual) */
- gpencil_draw_apply(C, op, p, depsgraph);
+ gpencil_draw_apply(C, op, p, depsgraph, false);
}
RNA_END;
@@ -3131,7 +3396,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
if (paintmode != GP_PAINTMODE_ERASER) {
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
if ((gpl) && ((gpl->flag & GP_LAYER_LOCKED) || (gpl->flag & GP_LAYER_HIDE))) {
- BKE_report(op->reports, RPT_ERROR, "Active layer is locked or hide");
+ BKE_report(op->reports, RPT_ERROR, "Active layer is locked or hidden");
return OPERATOR_CANCELLED;
}
}
@@ -3170,8 +3435,6 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
/* TODO: set any additional settings that we can take from the events?
* TODO? if tablet is erasing, force eraser to be on? */
- /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */
-
/* if eraser is on, draw radial aid */
if (p->paintmode == GP_PAINTMODE_ERASER) {
gpencil_draw_toggle_eraser_cursor(C, p, true);
@@ -3192,7 +3455,8 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
p->status = GP_STATUS_PAINTING;
/* handle the initial drawing - i.e. for just doing a simple dot */
- gpencil_draw_apply_event(C, op, event, CTX_data_ensure_evaluated_depsgraph(C), 0.0f, 0.0f);
+ gpencil_draw_apply_event(
+ C, op, event, CTX_data_ensure_evaluated_depsgraph(C), 0.0f, 0.0f, false);
op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
else {
@@ -3309,24 +3573,21 @@ static void gpencil_move_last_stroke_to_back(bContext *C)
BLI_insertlinkbefore(&gpf->strokes, gpf->strokes.first, gps);
}
-/* add events for missing mouse movements when the artist draw very fast */
-static void gpencil_add_missing_events(bContext *C,
- wmOperator *op,
- const wmEvent *event,
- tGPsdata *p)
+/* Add fake events for missing mouse movements when the artist draw very fast */
+static bool gpencil_add_fake_events(bContext *C, wmOperator *op, const wmEvent *event, tGPsdata *p)
{
Brush *brush = p->brush;
GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
int input_samples = brush->gpencil_settings->input_samples;
-
+ bool added_events = false;
/* ensure sampling when using circular guide */
if (guide->use_guide && (guide->type == GP_GUIDE_CIRCULAR)) {
input_samples = GP_MAX_INPUT_SAMPLES;
}
if (input_samples == 0) {
- return;
+ return added_events;
}
RegionView3D *rv3d = p->ar->regiondata;
@@ -3376,7 +3637,8 @@ static void gpencil_add_missing_events(bContext *C,
interp_v2_v2v2(pt, a, b, 0.5f);
sub_v2_v2v2(pt, b, pt);
/* create fake event */
- gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]);
+ gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], true);
+ added_events = true;
}
else if (dist >= factor) {
int slices = 2 + (int)((dist - 1.0) / factor);
@@ -3385,9 +3647,11 @@ static void gpencil_add_missing_events(bContext *C,
interp_v2_v2v2(pt, a, b, n * i);
sub_v2_v2v2(pt, b, pt);
/* create fake event */
- gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]);
+ gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], true);
+ added_events = true;
}
}
+ return added_events;
}
/* events handling during interactive drawing part of operator */
@@ -3396,6 +3660,8 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
tGPsdata *p = op->customdata;
ToolSettings *ts = CTX_data_tool_settings(C);
GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
+ tGPspoint *points = (tGPspoint *)p->gpd->runtime.sbuffer;
+
/* default exit state - pass through to support MMB view nav, etc. */
int estate = OPERATOR_PASS_THROUGH;
@@ -3420,7 +3686,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* special mode for editing control points */
if (p->paintmode == GP_PAINTMODE_SET_CP) {
wmWindow *win = p->win;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
bool drawmode = false;
switch (event->type) {
@@ -3518,7 +3784,8 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
/* toggle painting mode upon mouse-button movement
- * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox only)
+ * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox
+ * only)
* - RIGHTMOUSE = polyline (hotkey) / eraser (all)
* (Disabling RIGHTMOUSE case here results in bugs like [#32647])
* also making sure we have a valid event value, to not exit too early
@@ -3692,11 +3959,23 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* handle drawing event */
/* printf("\t\tGP - add point\n"); */
+ int size_before = p->gpd->runtime.sbuffer_used;
+ bool added_events = false;
if (((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) && (p->paintmode != GP_PAINTMODE_ERASER)) {
- gpencil_add_missing_events(C, op, event, p);
+ added_events = gpencil_add_fake_events(C, op, event, p);
}
- gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph_pointer(C), 0.0f, 0.0f);
+ gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph_pointer(C), 0.0f, 0.0f, false);
+ int size_after = p->gpd->runtime.sbuffer_used;
+
+ /* Last point of the event is always real (not fake). */
+ tGPspoint *pt = &points[size_after - 1];
+ pt->tflag &= ~GP_TPOINT_FAKE;
+
+ /* Smooth the fake events to get smoother strokes, specially at ends. */
+ if (added_events) {
+ gp_smooth_fake_events(p, size_before, size_after);
+ }
/* finish painting operation if anything went wrong just now */
if (p->status == GP_STATUS_ERROR) {
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index e4b2e5540ea..c42c1c4d4c0 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -330,7 +330,15 @@ static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi)
gps->flag |= GP_STROKE_3DSPACE;
- gps->mat_nr = BKE_gpencil_object_material_get_index(tgpi->ob, tgpi->mat);
+ gps->mat_nr = BKE_gpencil_object_material_get_index_from_brush(tgpi->ob, tgpi->brush);
+ if (gps->mat_nr < 0) {
+ if (tgpi->ob->actcol - 1 < 0) {
+ gps->mat_nr = 0;
+ }
+ else {
+ gps->mat_nr = tgpi->ob->actcol - 1;
+ }
+ }
/* allocate memory for storage points, but keep empty */
gps->totpoints = 0;
@@ -1126,7 +1134,7 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
/* if brush doesn't exist, create a new set (fix damaged files from old versions) */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
- BKE_brush_gpencil_presets(C);
+ BKE_brush_gpencil_presets(bmain, ts);
}
/* Set Draw brush. */
@@ -1206,7 +1214,7 @@ static int gpencil_primitive_invoke(bContext *C, wmOperator *op, const wmEvent *
op->flag |= OP_IS_MODAL_CURSOR_REGION;
/* set cursor to indicate modal */
- WM_cursor_modal_set(win, BC_CROSSCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_CROSS);
/* update sindicator in header */
gpencil_primitive_status_indicators(C, tgpi);
@@ -1311,18 +1319,18 @@ static void gpencil_primitive_edit_event_handling(
if (tgpi->flag == IN_CURVE_EDIT) {
if ((a < BIG_SIZE_CTL && tgpi->tot_stored_edges == 0) || b < BIG_SIZE_CTL) {
move = MOVE_ENDS;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
else if (tgpi->curve) {
move = MOVE_CP;
- WM_cursor_modal_set(win, BC_HANDCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_HAND);
}
else {
- WM_cursor_modal_set(win, BC_CROSSCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_CROSS);
}
}
else if (tgpi->flag == IN_PROGRESS) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
switch (event->type) {
@@ -1394,7 +1402,7 @@ static void gpencil_primitive_edit_event_handling(
case EKEY: {
if (tgpi->flag == IN_CURVE_EDIT && !ELEM(tgpi->type, GP_STROKE_BOX, GP_STROKE_CIRCLE)) {
tgpi->flag = IN_PROGRESS;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
gpencil_primitive_add_segment(tgpi);
copy_v2_v2(tgpi->start, tgpi->end);
copy_v2_v2(tgpi->origin, tgpi->start);
@@ -1657,7 +1665,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
{
if ((event->val == KM_PRESS)) {
tgpi->flag = IN_MOVE;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
break;
}
@@ -1670,7 +1678,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
else {
tgpi->flag = IN_BRUSH_SIZE;
}
- WM_cursor_modal_set(win, BC_NS_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NS_SCROLL);
}
break;
}
@@ -1696,7 +1704,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case TABKEY: {
if (tgpi->flag == IN_CURVE_EDIT) {
tgpi->flag = IN_PROGRESS;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
gp_primitive_update_cps(tgpi);
gpencil_primitive_update(C, op, tgpi);
}
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index f4484624d5a..be265ed4bd5 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -832,7 +832,8 @@ void GPENCIL_OT_select_less(wmOperatorType *ot)
* from gpencil_paint.c #gp_stroke_eraser_dostroke().
* It would be great to de-duplicate the logic here sometime, but that can wait.
*/
-static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
+static bool gp_stroke_do_circle_sel(bGPdata *gpd,
+ bGPDlayer *gpl,
bGPDstroke *gps,
GP_SpaceConversion *gsc,
const int mx,
@@ -840,16 +841,18 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
const int radius,
const bool select,
rcti *rect,
- float diff_mat[4][4],
+ const float diff_mat[4][4],
const int selectmode,
const float scale)
{
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
bGPDspoint *pt1 = NULL;
bGPDspoint *pt2 = NULL;
- bGPDstroke *gps_orig = gps->runtime.gps_orig;
int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
int i;
bool changed = false;
+ bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
+ bGPDspoint *pt_active = NULL;
if (gps->totpoints == 1) {
bGPDspoint pt_temp;
@@ -862,12 +865,12 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius * radius) {
/* change selection */
if (select) {
- gps_orig->points->flag |= GP_SPOINT_SELECT;
- gps_orig->flag |= GP_STROKE_SELECT;
+ gps_active->points->flag |= GP_SPOINT_SELECT;
+ gps_active->flag |= GP_STROKE_SELECT;
}
else {
- gps_orig->points->flag &= ~GP_SPOINT_SELECT;
- gps_orig->flag &= ~GP_STROKE_SELECT;
+ gps_active->points->flag &= ~GP_SPOINT_SELECT;
+ gps_active->flag &= ~GP_STROKE_SELECT;
}
return true;
@@ -907,20 +910,24 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
*/
hit = true;
if (select) {
- if (pt1->runtime.pt_orig != NULL) {
- pt1->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
+ pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1;
+ if (pt_active != NULL) {
+ pt_active->flag |= GP_SPOINT_SELECT;
}
- if (pt2->runtime.pt_orig != NULL) {
- pt2->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
+ pt_active = (!is_multiedit) ? pt2->runtime.pt_orig : pt2;
+ if (pt_active != NULL) {
+ pt_active->flag |= GP_SPOINT_SELECT;
}
changed = true;
}
else {
- if (pt1->runtime.pt_orig != NULL) {
- pt1->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
+ pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1;
+ if (pt_active != NULL) {
+ pt_active->flag &= ~GP_SPOINT_SELECT;
}
- if (pt2->runtime.pt_orig != NULL) {
- pt2->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
+ pt_active = (!is_multiedit) ? pt2->runtime.pt_orig : pt2;
+ if (pt_active != NULL) {
+ pt_active->flag &= ~GP_SPOINT_SELECT;
}
changed = true;
}
@@ -935,28 +942,29 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
/* if stroke mode expand selection */
if ((hit) && (selectmode == GP_SELECTMODE_STROKE)) {
for (i = 0, pt1 = gps->points; i < gps->totpoints; i++, pt1++) {
- if (pt1->runtime.pt_orig != NULL) {
+ pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1;
+ if (pt_active != NULL) {
if (select) {
- pt1->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
+ pt_active->flag |= GP_SPOINT_SELECT;
}
else {
- pt1->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
+ pt_active->flag &= ~GP_SPOINT_SELECT;
}
}
}
}
/* expand selection to segment */
- if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select) &&
- (pt1->runtime.pt_orig != NULL)) {
+ pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1;
+ if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select) && (pt_active != NULL)) {
float r_hita[3], r_hitb[3];
bool hit_select = (bool)(pt1->flag & GP_SPOINT_SELECT);
ED_gpencil_select_stroke_segment(
- gpl, gps_orig, pt1->runtime.pt_orig, hit_select, false, scale, r_hita, r_hitb);
+ gpl, gps_active, pt_active, hit_select, false, scale, r_hita, r_hitb);
}
/* Ensure that stroke selection is in sync with its points */
- BKE_gpencil_stroke_sync_selection(gps_orig);
+ BKE_gpencil_stroke_sync_selection(gps_active);
}
return changed;
@@ -1016,8 +1024,18 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
/* find visible strokes, and select if hit */
GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
{
- changed |= gp_stroke_do_circle_sel(
- gpl, gps, &gsc, mx, my, radius, select, &rect, gpstroke_iter.diff_mat, selectmode, scale);
+ changed |= gp_stroke_do_circle_sel(gpd,
+ gpl,
+ gps,
+ &gsc,
+ mx,
+ my,
+ radius,
+ select,
+ &rect,
+ gpstroke_iter.diff_mat,
+ selectmode,
+ scale);
}
GP_EVALUATED_STROKES_END(gpstroke_iter);
@@ -1090,6 +1108,8 @@ static int gpencil_generic_select_exec(bContext *C,
((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0));
const bool segmentmode = ((selectmode == GP_SELECTMODE_SEGMENT) &&
((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0));
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
const float scale = ts->gp_sculpt.isect_threshold;
@@ -1125,36 +1145,32 @@ static int gpencil_generic_select_exec(bContext *C,
/* select/deselect points */
GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
{
+ bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
bGPDspoint *pt;
int i;
bool hit = false;
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->runtime.pt_orig == NULL) {
+ if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) {
continue;
}
+ bGPDspoint *pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
/* convert point coords to screenspace */
const bool is_inside = is_inside_fn(gps, pt, &gsc, gpstroke_iter.diff_mat, user_data);
if (strokemode == false) {
- const bool is_select = (pt->runtime.pt_orig->flag & GP_SPOINT_SELECT) != 0;
+ const bool is_select = (pt_active->flag & GP_SPOINT_SELECT) != 0;
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(pt->runtime.pt_orig->flag, sel_op_result, GP_SPOINT_SELECT);
+ SET_FLAG_FROM_TEST(pt_active->flag, sel_op_result, GP_SPOINT_SELECT);
changed = true;
/* expand selection to segment */
if ((sel_op_result != -1) && (segmentmode)) {
- bool hit_select = (bool)(pt->runtime.pt_orig->flag & GP_SPOINT_SELECT);
+ bool hit_select = (bool)(pt_active->flag & GP_SPOINT_SELECT);
float r_hita[3], r_hitb[3];
- ED_gpencil_select_stroke_segment(gpl,
- gps->runtime.gps_orig,
- pt->runtime.pt_orig,
- hit_select,
- false,
- scale,
- r_hita,
- r_hitb);
+ ED_gpencil_select_stroke_segment(
+ gpl, gps_active, pt_active, hit_select, false, scale, r_hita, r_hitb);
}
}
}
@@ -1168,19 +1184,21 @@ static int gpencil_generic_select_exec(bContext *C,
/* if stroke mode expand selection */
if (strokemode) {
- const bool is_select = BKE_gpencil_stroke_select_check(gps->runtime.gps_orig);
+ const bool is_select = BKE_gpencil_stroke_select_check(gps_active);
const bool is_inside = hit;
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->runtime.pt_orig == NULL) {
+ if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) {
continue;
}
+ bGPDspoint *pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
+
if (sel_op_result) {
- pt->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
+ pt_active->flag |= GP_SPOINT_SELECT;
}
else {
- pt->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
+ pt_active->flag &= ~GP_SPOINT_SELECT;
}
}
changed = true;
@@ -1188,7 +1206,7 @@ static int gpencil_generic_select_exec(bContext *C,
}
/* Ensure that stroke selection is in sync with its points */
- BKE_gpencil_stroke_sync_selection(gps->runtime.gps_orig);
+ BKE_gpencil_stroke_sync_selection(gps_active);
}
GP_EVALUATED_STROKES_END(gpstroke_iter);
@@ -1369,6 +1387,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
bGPdata *gpd = ED_gpencil_data_get_active(C);
ToolSettings *ts = CTX_data_tool_settings(C);
const float scale = ts->gp_sculpt.isect_threshold;
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
/* "radius" is simply a threshold (screen space) to make it easier to test with a tolerance */
const float radius = 0.50f * U.widget_unit;
@@ -1414,13 +1433,14 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
/* XXX: maybe we should go from the top of the stack down instead... */
GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
{
+ bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
bGPDspoint *pt;
int i;
/* firstly, check for hit-point */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
int xy[2];
- if (pt->runtime.pt_orig == NULL) {
+ if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) {
continue;
}
@@ -1437,8 +1457,8 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
/* only use this point if it is a better match than the current hit - T44685 */
if (pt_distance < hit_distance) {
hit_layer = gpl;
- hit_stroke = gps->runtime.gps_orig;
- hit_point = pt->runtime.pt_orig;
+ hit_stroke = gps_active;
+ hit_point = (!is_multiedit) ? pt->runtime.pt_orig : pt;
hit_distance = pt_distance;
}
}
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 2a0f16a4bbf..b194d28a8b8 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -46,6 +46,7 @@
#include "BKE_action.h"
#include "BKE_colortools.h"
+#include "BKE_collection.h"
#include "BKE_deform.h"
#include "BKE_main.h"
#include "BKE_brush.h"
@@ -57,6 +58,7 @@
#include "BKE_tracking.h"
#include "WM_api.h"
+#include "WM_types.h"
#include "WM_toolsystem.h"
#include "RNA_access.h"
@@ -401,17 +403,7 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
/* Create new layer */
/* TODO: have some way of specifying that we don't want this? */
- {
- /* "New Layer" entry */
- item_tmp.identifier = "__CREATE__";
- item_tmp.name = "New Layer";
- item_tmp.value = -1;
- item_tmp.icon = ICON_ADD;
- RNA_enum_item_add(&item, &totitem, &item_tmp);
- /* separator */
- RNA_enum_item_add_separator(&item, &totitem);
- }
const int tot = BLI_listbase_count(&gpd->layers);
/* Existing layers */
for (gpl = gpd->layers.last, i = 0; gpl; gpl = gpl->prev, i++) {
@@ -428,6 +420,17 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
RNA_enum_item_add(&item, &totitem, &item_tmp);
}
+ {
+ /* separator */
+ RNA_enum_item_add_separator(&item, &totitem);
+
+ /* "New Layer" entry */
+ item_tmp.identifier = "__CREATE__";
+ item_tmp.name = "New Layer";
+ item_tmp.value = -1;
+ item_tmp.icon = ICON_ADD;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -1388,7 +1391,7 @@ void ED_gpencil_add_defaults(bContext *C, Object *ob)
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
/* create new brushes */
- BKE_brush_gpencil_presets(C);
+ BKE_brush_gpencil_presets(bmain, ts);
}
/* ensure a color exists and is assigned to object */
@@ -1949,7 +1952,7 @@ void ED_gpencil_setup_modes(bContext *C, bGPdata *gpd, int newmode)
/* helper to convert 2d to 3d for simple drawing buffer */
static void gpencil_stroke_convertcoords(ARegion *ar,
const tGPspoint *point2D,
- float origin[3],
+ const float origin[3],
float out[3])
{
float mval_f[2] = {(float)point2D->x, (float)point2D->y};
@@ -2063,7 +2066,7 @@ void ED_gpencil_update_color_uv(Main *bmain, Material *mat)
if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
continue;
}
- gps_ma = give_current_material(ob, gps->mat_nr + 1);
+ gps_ma = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
/* update */
if ((gps_ma) && (gps_ma == mat)) {
ED_gpencil_calc_stroke_uv(ob, gps);
@@ -2081,8 +2084,8 @@ static bool gpencil_check_collision(bGPDstroke *gps,
bGPDstroke **gps_array,
GHash *all_2d,
int totstrokes,
- float p2d_a1[2],
- float p2d_a2[2],
+ const float p2d_a1[2],
+ const float p2d_a2[2],
float r_hit[2])
{
bool hit = false;
@@ -2161,7 +2164,7 @@ static void gp_copy_points(bGPDstroke *gps, bGPDspoint *pt, bGPDspoint *pt_final
}
static void gp_insert_point(
- bGPDstroke *gps, bGPDspoint *a_pt, bGPDspoint *b_pt, float co_a[3], float co_b[3])
+ bGPDstroke *gps, bGPDspoint *a_pt, bGPDspoint *b_pt, const float co_a[3], float co_b[3])
{
bGPDspoint *temp_points;
int totnewpoints, oldtotpoints;
@@ -2558,3 +2561,24 @@ tGPspoint *ED_gpencil_sbuffer_ensure(tGPspoint *buffer_array,
return buffer_array;
}
+
+/* Tag all scene grease pencil object to update. */
+void ED_gpencil_tag_scene_gpencil(Scene *scene)
+{
+ /* mark all grease pencil datablocks of the scene */
+ FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, ob) {
+ if (ob->type == OB_GPENCIL) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
+ FOREACH_SCENE_COLLECTION_END;
+
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+
+ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
+}
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index cb6c66ed795..bf9b69f12e1 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -834,12 +834,28 @@ void ED_drivers_editor_init(struct bContext *C, struct ScrArea *sa);
/* ************************************************ */
+typedef enum eAnimvizCalcRange {
+ /* Update motion paths at the current frame only. */
+ ANIMVIZ_CALC_RANGE_CURRENT_FRAME,
+
+ /* Try to limit updates to a close neighborhood of the current frame. */
+ ANIMVIZ_CALC_RANGE_CHANGED,
+
+ /* Update an entire range of the motion paths. */
+ ANIMVIZ_CALC_RANGE_FULL,
+} eAnimvizCalcRange;
+
+struct Depsgraph *animviz_depsgraph_build(struct Main *bmain,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ struct ListBase *targets);
+
void animviz_calc_motionpaths(struct Depsgraph *depsgraph,
struct Main *bmain,
struct Scene *scene,
ListBase *targets,
- bool restore,
- bool current_frame_only);
+ eAnimvizCalcRange range,
+ bool restore);
void animviz_get_object_motionpaths(struct Object *ob, ListBase *targets);
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 48d0a5fe8be..7ac42967dda 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -73,6 +73,7 @@ typedef struct EditBone {
* animation are automatically relative to the bones' rest positions*/
int flag;
int layer;
+ char inherit_scale_mode;
/* Envelope distance & weight */
float dist, weight;
@@ -283,10 +284,18 @@ bool ED_pose_deselect_all_multi(struct bContext *C, int select_mode, const bool
bool ED_pose_deselect_all(struct Object *ob, int select_mode, const bool ignore_visibility);
void ED_pose_bone_select_tag_update(struct Object *ob);
void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select);
+
+/* Corresponds to eAnimvizCalcRange. */
+typedef enum ePosePathCalcRange {
+ POSE_PATH_CALC_RANGE_CURRENT_FRAME,
+ POSE_PATH_CALC_RANGE_CHANGED,
+ POSE_PATH_CALC_RANGE_FULL,
+} ePosePathCalcRange;
void ED_pose_recalculate_paths(struct bContext *C,
struct Scene *scene,
struct Object *ob,
- bool current_frame_only);
+ ePosePathCalcRange range);
+
struct Object *ED_pose_object_from_context(struct bContext *C);
/* meshlaplacian.c */
diff --git a/source/blender/editors/include/ED_datafiles.h b/source/blender/editors/include/ED_datafiles.h
index 43d7117a1b2..ada90205b4a 100644
--- a/source/blender/editors/include/ED_datafiles.h
+++ b/source/blender/editors/include/ED_datafiles.h
@@ -285,6 +285,12 @@ extern char datatoc_gp_brush_marker_png[];
extern int datatoc_gp_brush_fill_png_size;
extern char datatoc_gp_brush_fill_png[];
+extern int datatoc_gp_brush_airbrush_png_size;
+extern char datatoc_gp_brush_airbrush_png[];
+
+extern int datatoc_gp_brush_chisel_png_size;
+extern char datatoc_gp_brush_chisel_png[];
+
extern int datatoc_gp_brush_erase_soft_png_size;
extern char datatoc_gp_brush_erase_soft_png[];
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 7273f857a41..83890c1621c 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -29,22 +29,39 @@ struct FileSelectParams;
struct ScrArea;
struct SpaceFile;
struct bContext;
+struct bScreen;
+struct uiBlock;
struct wmWindowManager;
#define FILE_LAYOUT_HOR 1
#define FILE_LAYOUT_VER 2
-#define MAX_FILE_COLUMN 4
-
-typedef enum FileListColumns {
+typedef enum FileAttributeColumnType {
+ COLUMN_NONE = -1,
COLUMN_NAME = 0,
- COLUMN_DATE,
- COLUMN_TIME,
+ COLUMN_DATETIME,
COLUMN_SIZE,
-} FileListColumns;
+
+ ATTRIBUTE_COLUMN_MAX
+} FileAttributeColumnType;
+
+typedef struct FileAttributeColumn {
+ /** UI name for this column */
+ const char *name;
+
+ float width;
+ /* The sort type to use when sorting by this column. */
+ int sort_type; /* eFileSortType */
+
+ /* Alignment of column texts, header text is always left aligned */
+ int text_align; /* eFontStyle_Align */
+} FileAttributeColumn;
typedef struct FileLayout {
/* view settings - XXX - move into own struct */
+ int offset_top;
+ /* Height of the header for the different FileAttributeColumn's. */
+ int attribute_column_header_h;
int prv_w;
int prv_h;
int tile_w;
@@ -54,13 +71,17 @@ typedef struct FileLayout {
int prv_border_x;
int prv_border_y;
int rows;
- int columns;
+ /* Those are the major layout columns the files are distributed across, not to be confused with
+ * 'attribute_columns' array below. */
+ int flow_columns;
int width;
int height;
int flag;
int dirty;
int textheight;
- float column_widths[MAX_FILE_COLUMN];
+ /* The columns for each item (name, modification date/time, size). Not to be confused with the
+ * 'flow_columns' above. */
+ FileAttributeColumn attribute_columns[ATTRIBUTE_COLUMN_MAX];
/* When we change display size, we may have to update static strings like size of files... */
short curr_size;
@@ -71,11 +92,14 @@ typedef struct FileSelection {
int last;
} FileSelection;
+struct View2D;
struct rcti;
struct FileSelectParams *ED_fileselect_get_params(struct SpaceFile *sfile);
short ED_fileselect_set_params(struct SpaceFile *sfile);
+void ED_fileselect_set_params_from_userdef(struct SpaceFile *sfile);
+void ED_fileselect_params_to_userdef(struct SpaceFile *sfile, int temp_win_size[]);
void ED_fileselect_reset_params(struct SpaceFile *sfile);
@@ -87,6 +111,17 @@ int ED_fileselect_layout_numfiles(FileLayout *layout, struct ARegion *ar);
int ED_fileselect_layout_offset(FileLayout *layout, int x, int y);
FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const struct rcti *rect);
+void ED_fileselect_layout_maskrect(const FileLayout *layout,
+ const struct View2D *v2d,
+ struct rcti *r_rect);
+bool ED_fileselect_layout_is_inside_pt(const FileLayout *layout,
+ const struct View2D *v2d,
+ int x,
+ int y);
+bool ED_fileselect_layout_isect_rect(const FileLayout *layout,
+ const struct View2D *v2d,
+ const struct rcti *rect,
+ struct rcti *r_dst);
void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y);
void ED_operatormacros_file(void);
@@ -102,6 +137,11 @@ void ED_file_read_bookmarks(void);
void ED_file_change_dir(struct bContext *C);
+void ED_file_path_button(struct bScreen *screen,
+ const struct SpaceFile *sfile,
+ struct FileSelectParams *params,
+ struct uiBlock *block);
+
/* File menu stuff */
/* FSMenuEntry's without paths indicate separators */
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 470eb58c72b..0ff1b8bb40b 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -71,8 +71,15 @@ typedef struct tGPspoint {
float uv_rot; /* uv rotation for dor mode */
float rnd[3]; /* rnd value */
bool rnd_dirty; /* rnd flag */
+ short tflag; /* Internal flag */
} tGPspoint;
+/* tGPspoint->flag */
+typedef enum etGPspoint_tFlag {
+ /* Created by Fake event (used when mouse/pen move very fast while drawing). */
+ GP_TPOINT_FAKE = (1 << 0),
+} etGPspoint_tFlag;
+
/* used to sort by zdepth gpencil objects in viewport */
/* TODO: this could be a system parameter in userprefs screen */
#define GP_CACHE_BLOCK_SIZE 16
@@ -288,4 +295,7 @@ struct tGPspoint *ED_gpencil_sbuffer_ensure(struct tGPspoint *buffer_array,
short *buffer_size,
short *buffer_used,
const bool clear);
+/* Tag all scene grease pencil object to update. */
+void ED_gpencil_tag_scene_gpencil(struct Scene *scene);
+
#endif /* __ED_GPENCIL_H__ */
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index 7d69f86dbf8..69742af9f50 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -77,6 +77,7 @@ void ED_image_mouse_pos(struct SpaceImage *sima,
struct ARegion *ar,
const int mval[2],
float co[2]);
+void ED_image_view_center_to_point(struct SpaceImage *sima, float x, float y);
void ED_image_point_pos(
struct SpaceImage *sima, struct ARegion *ar, float x, float y, float *xr, float *yr);
void ED_image_point_pos__reverse(struct SpaceImage *sima,
@@ -94,6 +95,7 @@ bool ED_space_image_paint_curve(const struct bContext *C);
bool ED_space_image_check_show_maskedit(struct SpaceImage *sima, struct ViewLayer *view_layer);
bool ED_space_image_maskedit_poll(struct bContext *C);
bool ED_space_image_maskedit_mask_poll(struct bContext *C);
+bool ED_space_image_cursor_poll(struct bContext *C);
void ED_image_draw_info(struct Scene *scene,
struct ARegion *ar,
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 42e5add2ef0..16b3c9c240a 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -310,15 +310,24 @@ extern EnumPropertyItem prop_driver_create_mapping_types[];
/* -------- */
+typedef enum eDriverFCurveCreationMode {
+ DRIVER_FCURVE_LOOKUP_ONLY = 0, /* Don't add anything if not found. */
+ DRIVER_FCURVE_KEYFRAMES = 1, /* Add with keyframes, for visual tweaking. */
+ DRIVER_FCURVE_GENERATOR = 2, /* Add with generator, for script backwards compatibility. */
+ DRIVER_FCURVE_EMPTY = 3 /* Add without data, for pasting. */
+} eDriverFCurveCreationMode;
+
/* Low-level call to add a new driver F-Curve. This shouldn't be used directly for most tools,
* although there are special cases where this approach is preferable.
*/
struct FCurve *verify_driver_fcurve(struct ID *id,
const char rna_path[],
const int array_index,
- short add);
+ eDriverFCurveCreationMode creation_mode);
-struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index, short add);
+struct FCurve *alloc_driver_fcurve(const char rna_path[],
+ const int array_index,
+ eDriverFCurveCreationMode creation_mode);
/* -------- */
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 0b2adfed531..d8d62ad6f08 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -138,13 +138,21 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree,
struct View3D *v3d,
struct Object *obedit);
+/* editmesh_automerge.c */
+void EDBM_automerge(struct Object *ob, bool update, const char hflag, const float dist);
+void EDBM_automerge_and_split(struct Object *ob,
+ bool split_edges,
+ bool split_faces,
+ bool update,
+ const char hflag,
+ const float dist);
+
/* editmesh_undo.c */
void ED_mesh_undosys_type(struct UndoType *ut);
/* editmesh_select.c */
void EDBM_select_mirrored(
struct BMEditMesh *em, const int axis, const bool extend, int *r_totmirr, int *r_totfail);
-void EDBM_automerge(struct Scene *scene, struct Object *ob, bool update, const char hflag);
struct BMVert *EDBM_vert_find_nearest_ex(struct ViewContext *vc,
float *r_dist,
@@ -188,8 +196,11 @@ bool EDBM_unified_findnearest(struct ViewContext *vc,
bool EDBM_unified_findnearest_from_raycast(struct ViewContext *vc,
struct Base **bases,
const uint bases_len,
- bool use_boundary,
- int *r_base_index,
+ bool use_boundary_vertices,
+ bool use_boundary_edges,
+ int *r_base_index_vert,
+ int *r_base_index_edge,
+ int *r_base_index_face,
struct BMVert **r_eve,
struct BMEdge **r_eed,
struct BMFace **r_efa);
@@ -203,11 +214,12 @@ void EDBM_selectmode_convert(struct BMEditMesh *em,
const short selectmode_new);
/* user access this */
-bool EDBM_selectmode_toggle(struct bContext *C,
- const short selectmode_new,
- const int action,
- const bool use_extend,
- const bool use_expand);
+bool EDBM_selectmode_set_multi(struct bContext *C, const short selectmode);
+bool EDBM_selectmode_toggle_multi(struct bContext *C,
+ const short selectmode_new,
+ const int action,
+ const bool use_extend,
+ const bool use_expand);
bool EDBM_selectmode_disable(struct Scene *scene,
struct BMEditMesh *em,
@@ -239,15 +251,30 @@ void EDBM_preselect_edgering_update_from_edge(struct EditMesh_PreSelEdgeRing *ps
/* editmesh_preselect_elem.c */
struct EditMesh_PreSelElem;
+typedef enum eEditMesh_PreSelPreviewAction {
+ PRESELECT_ACTION_TRANSFORM = 1,
+ PRESELECT_ACTION_CREATE = 2,
+ PRESELECT_ACTION_DELETE = 3,
+} eEditMesh_PreSelPreviewAction;
+
struct EditMesh_PreSelElem *EDBM_preselect_elem_create(void);
void EDBM_preselect_elem_destroy(struct EditMesh_PreSelElem *psel);
void EDBM_preselect_elem_clear(struct EditMesh_PreSelElem *psel);
+void EDBM_preselect_preview_clear(struct EditMesh_PreSelElem *psel);
void EDBM_preselect_elem_draw(struct EditMesh_PreSelElem *psel, const float matrix[4][4]);
void EDBM_preselect_elem_update_from_single(struct EditMesh_PreSelElem *psel,
struct BMesh *bm,
struct BMElem *ele,
const float (*coords)[3]);
+void EDBM_preselect_elem_update_preview(struct EditMesh_PreSelElem *psel,
+ struct ViewContext *vc,
+ struct BMesh *bm,
+ struct BMElem *ele,
+ const int mval[2]);
+void EDBM_preselect_action_set(struct EditMesh_PreSelElem *psel,
+ eEditMesh_PreSelPreviewAction action);
+eEditMesh_PreSelPreviewAction EDBM_preselect_action_get(struct EditMesh_PreSelElem *psel);
/* mesh_ops.c */
void ED_operatortypes_mesh(void);
void ED_operatormacros_mesh(void);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index c481c19a552..38d75aa57e9 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -238,9 +238,17 @@ void ED_object_single_user(struct Main *bmain, struct Scene *scene, struct Objec
/* object motion paths */
void ED_objects_clear_paths(struct bContext *C, bool only_selected);
+
+/* Corresponds to eAnimvizCalcRange. */
+typedef enum eObjectPathCalcRange {
+ OBJECT_PATH_CALC_RANGE_CURRENT_FRAME,
+ OBJECT_PATH_CALC_RANGE_CHANGED,
+ OBJECT_PATH_CALC_RANGE_FULL,
+} eObjectPathCalcRange;
+
void ED_objects_recalculate_paths(struct bContext *C,
struct Scene *scene,
- bool current_frame_only);
+ eObjectPathCalcRange range);
/* constraints */
struct ListBase *get_active_constraints(struct Object *ob);
diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h
index 88cc8a85897..fec4beea809 100644
--- a/source/blender/editors/include/ED_paint.h
+++ b/source/blender/editors/include/ED_paint.h
@@ -40,13 +40,44 @@ void ED_imapaint_dirty_region(
struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h, bool find_old);
void ED_imapaint_bucket_fill(struct bContext *C, float color[3], struct wmOperator *op);
-/* paint_image_undo.c */
+/* image_undo.c */
void ED_image_undo_push_begin(const char *name, int paint_mode);
+void ED_image_undo_push_begin_with_image(const char *name,
+ struct Image *image,
+ struct ImBuf *ibuf);
+
void ED_image_undo_push_end(void);
void ED_image_undo_restore(struct UndoStep *us);
void ED_image_undosys_type(struct UndoType *ut);
+void *ED_image_paint_tile_find(struct ListBase *undo_tiles,
+ struct Image *ima,
+ struct ImBuf *ibuf,
+ int x_tile,
+ int y_tile,
+ unsigned short **r_mask,
+ bool validate);
+void *ED_image_paint_tile_push(struct ListBase *undo_tiles,
+ struct Image *ima,
+ struct ImBuf *ibuf,
+ struct ImBuf **tmpibuf,
+ int x_tile,
+ int y_tile,
+ unsigned short **r_mask,
+ bool **r_valid,
+ bool use_thread_lock,
+ bool find_prev);
+void ED_image_paint_tile_lock_init(void);
+void ED_image_paint_tile_lock_end(void);
+
+struct ListBase *ED_image_paint_tile_list_get(void);
+
+#define ED_IMAGE_UNDO_TILE_BITS 6
+#define ED_IMAGE_UNDO_TILE_SIZE (1 << ED_IMAGE_UNDO_TILE_BITS)
+#define ED_IMAGE_UNDO_TILE_NUMBER(size) \
+ (((size) + ED_IMAGE_UNDO_TILE_SIZE - 1) >> ED_IMAGE_UNDO_TILE_BITS)
+
/* paint_curve_undo.c */
void ED_paintcurve_undo_push_begin(const char *name);
void ED_paintcurve_undo_push_end(void);
diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h
index 3ef3c0ba937..0c973f4ca88 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -40,12 +40,18 @@ int PE_start_edit(struct PTCacheEdit *edit);
/* access */
struct PTCacheEdit *PE_get_current_from_psys(struct ParticleSystem *psys);
-struct PTCacheEdit *PE_get_current(struct Scene *scene, struct Object *ob);
+struct PTCacheEdit *PE_get_current(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob);
struct PTCacheEdit *PE_create_current(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
void PE_current_changed(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
-int PE_minmax(struct Scene *scene, struct ViewLayer *view_layer, float min[3], float max[3]);
+int PE_minmax(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ float min[3],
+ float max[3]);
struct ParticleEditSettings *PE_settings(struct Scene *scene);
/* update calls */
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index d0fab134dcc..7c3aac6c688 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -66,6 +66,7 @@ void ED_region_do_listen(struct wmWindow *win,
void ED_region_do_layout(struct bContext *C, struct ARegion *ar);
void ED_region_do_draw(struct bContext *C, struct ARegion *ar);
void ED_region_exit(struct bContext *C, struct ARegion *ar);
+void ED_region_remove(struct bContext *C, struct ScrArea *sa, struct ARegion *ar);
void ED_region_pixelspace(struct ARegion *ar);
void ED_region_update_rect(struct ARegion *ar);
void ED_region_init(struct ARegion *ar);
@@ -238,6 +239,14 @@ struct ScrArea *ED_screen_state_toggle(struct bContext *C,
struct wmWindow *win,
struct ScrArea *sa,
const short state);
+ScrArea *ED_screen_temp_space_open(struct bContext *C,
+ const char *title,
+ int x,
+ int y,
+ int sizex,
+ int sizey,
+ eSpace_Type space_type,
+ int display_type);
void ED_screens_header_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg);
void ED_screens_footer_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg);
void ED_screens_navigation_bar_tools_menu_create(struct bContext *C,
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index d907ba4e581..0273c8c73ab 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -39,6 +39,11 @@ bool ED_sculpt_mask_box_select(struct bContext *C,
const struct rcti *rect,
bool select);
+/* transform */
+void ED_sculpt_update_modal_transform(struct bContext *C);
+void ED_sculpt_init_transform(struct bContext *C);
+void ED_sculpt_end_transform(struct bContext *C);
+
/* sculpt_undo.c */
void ED_sculpt_undosys_type(struct UndoType *ut);
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index 192af8f5273..8c70fc9a157 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -90,6 +90,11 @@ enum TfmMode {
#define CTX_PAINT_CURVE (1 << 8)
#define CTX_GPENCIL_STROKES (1 << 9)
#define CTX_CURSOR (1 << 10)
+/** When transforming object's, adjust the object data so it stays in the same place. */
+#define CTX_OBMODE_XFORM_OBDATA (1 << 11)
+/** Transform object parents without moving their children. */
+#define CTX_OBMODE_XFORM_SKIP_CHILDREN (1 << 12)
+#define CTX_SCULPT (1 << 13)
/* Standalone call to get the transformation center corresponding to the current situation
* returns 1 if successful, 0 otherwise (usually means there's no selection)
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 139b306b533..28280fae3a8 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -521,7 +521,9 @@ int view3d_opengl_select(struct ViewContext *vc,
/* view3d_select.c */
float ED_view3d_select_dist_px(void);
-void ED_view3d_viewcontext_init(struct bContext *C, struct ViewContext *vc);
+void ED_view3d_viewcontext_init(struct bContext *C,
+ struct ViewContext *vc,
+ struct Depsgraph *depsgraph);
void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact);
void view3d_operator_needs_opengl(const struct bContext *C);
void view3d_region_operator_needs_opengl(struct wmWindow *win, struct ARegion *ar);
@@ -741,4 +743,8 @@ void ED_view3d_buttons_region_layout_ex(const struct bContext *C,
struct ARegion *ar,
const char *category_override);
+/* view3d_view.c */
+bool ED_view3d_local_collections_set(struct Main *bmain, struct View3D *v3d);
+void ED_view3d_local_collections_reset(struct bContext *C, const bool reset_all);
+
#endif /* __ED_VIEW3D_H__ */
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 41ac1b6b452..4e4db46adf6 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -42,6 +42,9 @@
#ifndef DEF_ICON_SHADING
# define DEF_ICON_SHADING DEF_ICON
#endif
+#ifndef DEF_ICON_FOLDER
+# define DEF_ICON_FOLDER DEF_ICON
+#endif
#ifndef DEF_ICON_COLOR
# define DEF_ICON_COLOR DEF_ICON
#endif
@@ -88,7 +91,7 @@ DEF_ICON(REMOVE)
DEF_ICON(PANEL_CLOSE)
DEF_ICON(COPY_ID)
DEF_ICON(EYEDROPPER)
-DEF_ICON_BLANK(92)
+DEF_ICON(CHECKMARK)
DEF_ICON(AUTO)
DEF_ICON(CHECKBOX_DEHLT) /* de-Highlight - Checkbox OFF */
DEF_ICON(CHECKBOX_HLT) /* Highlight - Checkbox ON */
@@ -666,7 +669,7 @@ DEF_ICON(PARTICLE_PATH)
/* EDITING */
DEF_ICON_BLANK(669)
-DEF_ICON_BLANK(670)
+DEF_ICON(SNAP_FACE_CENTER)
DEF_ICON(SNAP_PERPENDICULAR)
DEF_ICON(SNAP_MIDPOINT)
DEF_ICON(SNAP_OFF)
@@ -713,7 +716,7 @@ DEF_ICON(UV_SYNC_SELECT)
DEF_ICON_BLANK(240)
DEF_ICON_BLANK(241)
DEF_ICON_BLANK(242)
-DEF_ICON_BLANK(243)
+DEF_ICON(TRANSFORM_ORIGINS)
DEF_ICON(GIZMO)
DEF_ICON(ORIENTATION_CURSOR)
DEF_ICON(NORMALS_VERTEX)
@@ -793,7 +796,7 @@ DEF_ICON(NEWFOLDER)
DEF_ICON_BLANK(794)
DEF_ICON(FILE_PARENT)
DEF_ICON(FILE_REFRESH)
-DEF_ICON(FILE_FOLDER)
+DEF_ICON_FOLDER(FILE_FOLDER)
DEF_ICON(FILE_BLANK)
DEF_ICON(FILE_BLEND)
DEF_ICON(FILE_IMAGE)
@@ -823,7 +826,7 @@ DEF_ICON(BACK)
DEF_ICON(FORWARD)
DEF_ICON_BLANK(825)
DEF_ICON_BLANK(826)
-DEF_ICON_BLANK(827)
+DEF_ICON(FILE_ARCHIVE)
DEF_ICON(FILE_CACHE)
DEF_ICON(FILE_VOLUME)
DEF_ICON(FILE_3D)
@@ -855,9 +858,9 @@ DEF_ICON_BLANK(855)
DEF_ICON_BLANK(856)
DEF_ICON_BLANK(857)
DEF_ICON_BLANK(858)
-DEF_ICON_BLANK(859)
-DEF_ICON_BLANK(860)
-DEF_ICON_BLANK(861)
+DEF_ICON(DESKTOP)
+DEF_ICON(EXTERNAL_DRIVE)
+DEF_ICON(NETWORK_DRIVE)
/* SEQUENCE / IMAGE EDITOR */
DEF_ICON(SEQ_SEQUENCER)
@@ -934,6 +937,8 @@ DEF_ICON_COLOR(GPBRUSH_INKNOISE)
DEF_ICON_COLOR(GPBRUSH_BLOCK)
DEF_ICON_COLOR(GPBRUSH_MARKER)
DEF_ICON_COLOR(GPBRUSH_FILL)
+DEF_ICON_COLOR(GPBRUSH_AIRBRUSH)
+DEF_ICON_COLOR(GPBRUSH_CHISEL)
DEF_ICON_COLOR(GPBRUSH_ERASE_SOFT)
DEF_ICON_COLOR(GPBRUSH_ERASE_HARD)
DEF_ICON_COLOR(GPBRUSH_ERASE_STROKE)
@@ -1034,6 +1039,7 @@ DEF_ICON_COLOR(EVENT_RETURN)
#undef DEF_ICON_OBJECT_DATA
#undef DEF_ICON_MODIFIER
#undef DEF_ICON_SHADING
+#undef DEF_ICON_FOLDER
#undef DEF_ICON_VECTOR
#undef DEF_ICON_COLOR
#undef DEF_ICON_FUND
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index a61daa11c36..f5721c008b2 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -32,6 +32,7 @@
struct ARegion;
struct AutoComplete;
+struct FileSelectParams;
struct ID;
struct IDProperty;
struct ImBuf;
@@ -89,7 +90,7 @@ typedef struct uiPopupBlockHandle uiPopupBlockHandle;
* For #ARegion.overlap regions, pass events though if they don't overlap
* the regions contents (the usable part of the #View2D and buttons).
*
- * The margin is needed so it's not possible to accidentally click inbetween buttons.
+ * The margin is needed so it's not possible to accidentally click in between buttons.
*/
#define UI_REGION_OVERLAP_MARGIN (U.widget_unit / 3)
@@ -520,8 +521,10 @@ typedef bool (*uiMenuStepFunc)(struct bContext *C, int direction, void *arg1);
/* interface_query.c */
bool UI_but_has_tooltip_label(const uiBut *but);
bool UI_but_is_tool(const uiBut *but);
+bool UI_but_is_utf8(const uiBut *but);
#define UI_but_is_decorator(but) ((but)->func == ui_but_anim_decorate_cb)
+bool UI_block_is_empty_ex(const uiBlock *block, const bool skip_title);
bool UI_block_is_empty(const uiBlock *block);
bool UI_block_can_add_separator(const uiBlock *block);
@@ -1596,6 +1599,11 @@ void UI_but_func_hold_set(uiBut *but, uiButHandleHoldFunc func, void *argN);
void UI_but_func_pushed_state_set(uiBut *but, uiButPushedStateFunc func, void *arg);
+PointerRNA *UI_but_extra_operator_icon_add(uiBut *but,
+ const char *opname,
+ short opcontext,
+ int icon);
+
/* Autocomplete
*
* Tab complete helper functions, for use in uiButCompleteFunc callbacks.
@@ -1803,6 +1811,7 @@ void uiLayoutSetActivateInit(uiLayout *layout, bool active);
void uiLayoutSetEnabled(uiLayout *layout, bool enabled);
void uiLayoutSetRedAlert(uiLayout *layout, bool redalert);
void uiLayoutSetAlignment(uiLayout *layout, char alignment);
+void uiLayoutSetFixedSize(uiLayout *layout, bool fixed_size);
void uiLayoutSetKeepAspect(uiLayout *layout, bool keepaspect);
void uiLayoutSetScaleX(uiLayout *layout, float scale);
void uiLayoutSetScaleY(uiLayout *layout, float scale);
@@ -1820,6 +1829,7 @@ bool uiLayoutGetActivateInit(uiLayout *layout);
bool uiLayoutGetEnabled(uiLayout *layout);
bool uiLayoutGetRedAlert(uiLayout *layout);
int uiLayoutGetAlignment(uiLayout *layout);
+bool uiLayoutGetFixedSize(uiLayout *layout);
bool uiLayoutGetKeepAspect(uiLayout *layout);
int uiLayoutGetWidth(uiLayout *layout);
float uiLayoutGetScaleX(uiLayout *layout);
@@ -2081,6 +2091,9 @@ void uiTemplateColormanagedViewSettings(struct uiLayout *layout,
const char *propname);
int uiTemplateRecentFiles(struct uiLayout *layout, int rows);
+void uiTemplateFileSelectPath(uiLayout *layout,
+ struct bContext *C,
+ struct FileSelectParams *params);
/* items */
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname);
@@ -2441,6 +2454,8 @@ void UI_widgetbase_draw_cache_end(void);
void UI_theme_init_default(void);
void UI_style_init_default(void);
+void UI_interface_tag_script_reload(void);
+
/* Special drawing for toolbar, mainly workarounds for inflexible icon sizing. */
#define USE_UI_TOOLBAR_HACK
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index 29022adac6c..76ab4a53eb8 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -234,6 +234,8 @@ typedef enum ThemeColorID {
TH_DIS_MARKER,
TH_PATH_BEFORE,
TH_PATH_AFTER,
+ TH_PATH_KEYFRAME_BEFORE,
+ TH_PATH_KEYFRAME_AFTER,
TH_CAMERA_PATH,
TH_LOCK_MARKER,
@@ -273,6 +275,7 @@ typedef enum ThemeColorID {
TH_ICON_OBJECT_DATA,
TH_ICON_MODIFIER,
TH_ICON_SHADING,
+ TH_ICON_FOLDER,
TH_ICON_FUND,
TH_SCROLL_TEXT,
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 66c8eadbd74..f05100e9065 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -1469,6 +1469,187 @@ void ui_but_override_flag(uiBut *but)
}
}
+/** \name Button Extra Operator Icons
+ *
+ * Extra icons are shown on the right hand side of buttons. They can be clicked to invoke custom
+ * operators.
+ * There are some predefined here, which get added to buttons automatically based on button data
+ * (type, flags, state, etc).
+ * \{ */
+
+/**
+ * Predefined types for generic extra operator icons (uiButExtraOpIcon).
+ */
+typedef enum PredefinedExtraOpIconType {
+ PREDEFINED_EXTRA_OP_ICON_NONE = 1,
+ PREDEFINED_EXTRA_OP_ICON_CLEAR,
+ PREDEFINED_EXTRA_OP_ICON_EYEDROPPER,
+} PredefinedExtraOpIconType;
+
+static PointerRNA *ui_but_extra_operator_icon_add_ptr(uiBut *but,
+ wmOperatorType *optype,
+ short opcontext,
+ int icon)
+{
+ uiButExtraOpIcon *extra_op_icon = MEM_mallocN(sizeof(*extra_op_icon), __func__);
+
+ extra_op_icon->icon = (BIFIconID)icon;
+ extra_op_icon->optype_params = MEM_callocN(sizeof(*extra_op_icon->optype_params),
+ "uiButExtraOpIcon.optype_hook");
+ extra_op_icon->optype_params->optype = optype;
+ extra_op_icon->optype_params->opptr = MEM_callocN(sizeof(*extra_op_icon->optype_params->opptr),
+ "uiButExtraOpIcon.optype_hook.opptr");
+ WM_operator_properties_create_ptr(extra_op_icon->optype_params->opptr,
+ extra_op_icon->optype_params->optype);
+ extra_op_icon->optype_params->opcontext = opcontext;
+
+ BLI_addtail(&but->extra_op_icons, extra_op_icon);
+
+ return extra_op_icon->optype_params->opptr;
+}
+
+static void ui_but_extra_operator_icon_free(uiButExtraOpIcon *extra_icon)
+{
+ WM_operator_properties_free(extra_icon->optype_params->opptr);
+ MEM_freeN(extra_icon->optype_params->opptr);
+ MEM_freeN(extra_icon->optype_params);
+ MEM_freeN(extra_icon);
+}
+
+void ui_but_extra_operator_icons_free(uiBut *but)
+{
+
+ for (uiButExtraOpIcon *op_icon = but->extra_op_icons.first, *op_icon_next; op_icon;
+ op_icon = op_icon_next) {
+ op_icon_next = op_icon->next;
+ ui_but_extra_operator_icon_free(op_icon);
+ }
+ BLI_listbase_clear(&but->extra_op_icons);
+}
+
+PointerRNA *UI_but_extra_operator_icon_add(uiBut *but,
+ const char *opname,
+ short opcontext,
+ int icon)
+{
+ wmOperatorType *optype = WM_operatortype_find(opname, false);
+
+ if (optype) {
+ return ui_but_extra_operator_icon_add_ptr(but, optype, opcontext, icon);
+ }
+
+ return NULL;
+}
+
+static bool ui_but_icon_extra_is_visible_text_clear(const uiBut *but)
+{
+ BLI_assert(but->type == UI_BTYPE_TEXT);
+ return ((but->flag & UI_BUT_VALUE_CLEAR) && but->drawstr[0]);
+}
+
+static bool ui_but_icon_extra_is_visible_search_unlink(const uiBut *but)
+{
+ BLI_assert(ELEM(but->type, UI_BTYPE_SEARCH_MENU));
+ return ((but->editstr == NULL) && (but->drawstr[0] != '\0') && (but->flag & UI_BUT_VALUE_CLEAR));
+}
+
+static bool ui_but_icon_extra_is_visible_search_eyedropper(uiBut *but)
+{
+ StructRNA *type;
+ short idcode;
+
+ BLI_assert(but->type == UI_BTYPE_SEARCH_MENU && (but->flag & UI_BUT_VALUE_CLEAR));
+
+ if (but->rnaprop == NULL) {
+ return false;
+ }
+
+ type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop);
+ idcode = RNA_type_to_ID_code(type);
+
+ return ((but->editstr == NULL) && (idcode == ID_OB || OB_DATA_SUPPORT_ID(idcode)));
+}
+
+static PredefinedExtraOpIconType ui_but_icon_extra_get(uiBut *but)
+{
+ switch (but->type) {
+ case UI_BTYPE_TEXT:
+ if (ui_but_icon_extra_is_visible_text_clear(but)) {
+ return PREDEFINED_EXTRA_OP_ICON_CLEAR;
+ }
+ break;
+ case UI_BTYPE_SEARCH_MENU:
+ if ((but->flag & UI_BUT_VALUE_CLEAR) == 0) {
+ /* pass */
+ }
+ else if (ui_but_icon_extra_is_visible_search_unlink(but)) {
+ return PREDEFINED_EXTRA_OP_ICON_CLEAR;
+ }
+ else if (ui_but_icon_extra_is_visible_search_eyedropper(but)) {
+ return PREDEFINED_EXTRA_OP_ICON_EYEDROPPER;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return PREDEFINED_EXTRA_OP_ICON_NONE;
+}
+
+/**
+ * While some extra operator icons have to be set explicitly upon button creating, this code adds
+ * some generic ones based on button data. Currently these are mutually exclusive, so there's only
+ * ever one predefined extra icon.
+ */
+static void ui_but_predefined_extra_operator_icons_add(uiBut *but)
+{
+ PredefinedExtraOpIconType extra_icon = ui_but_icon_extra_get(but);
+ wmOperatorType *optype = NULL;
+ BIFIconID icon = ICON_NONE;
+
+ switch (extra_icon) {
+ case PREDEFINED_EXTRA_OP_ICON_EYEDROPPER: {
+ static wmOperatorType *id_eyedropper_ot = NULL;
+ if (!id_eyedropper_ot) {
+ id_eyedropper_ot = WM_operatortype_find("UI_OT_eyedropper_id", false);
+ }
+ BLI_assert(id_eyedropper_ot);
+
+ optype = id_eyedropper_ot;
+ icon = ICON_EYEDROPPER;
+
+ break;
+ }
+ case PREDEFINED_EXTRA_OP_ICON_CLEAR: {
+ static wmOperatorType *clear_ot = NULL;
+ if (!clear_ot) {
+ clear_ot = WM_operatortype_find("UI_OT_button_string_clear", false);
+ }
+ BLI_assert(clear_ot);
+
+ optype = clear_ot;
+ icon = ICON_PANEL_CLOSE;
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (optype) {
+ for (uiButExtraOpIcon *op_icon = but->extra_op_icons.first; op_icon; op_icon = op_icon->next) {
+ if ((op_icon->optype_params->optype == optype) && (op_icon->icon == icon)) {
+ /* Don't add the same operator icon twice (happens if button is kept alive while active).
+ */
+ return;
+ }
+ }
+ ui_but_extra_operator_icon_add_ptr(but, optype, WM_OP_INVOKE_DEFAULT, (int)icon);
+ }
+}
+
+/** \} */
+
void UI_block_update_from_old(const bContext *C, uiBlock *block)
{
uiBut *but_old;
@@ -1541,6 +1722,7 @@ void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2], int r_x
if (UI_but_is_decorator(but)) {
ui_but_anim_decorate_update_from_flag(but);
}
+ ui_but_predefined_extra_operator_icons_add(but);
}
/* handle pending stuff */
@@ -2281,69 +2463,6 @@ uiBut *ui_but_drag_multi_edit_get(uiBut *but)
return but_iter;
}
-/** \name Check to show extra icons
- *
- * Extra icons are shown on the right hand side of buttons.
- * This could (should!) definitely become more generic, but for now this is good enough.
- * \{ */
-
-static bool ui_but_icon_extra_is_visible_text_clear(const uiBut *but)
-{
- BLI_assert(but->type == UI_BTYPE_TEXT);
- return ((but->flag & UI_BUT_VALUE_CLEAR) && but->drawstr[0]);
-}
-
-static bool ui_but_icon_extra_is_visible_search_unlink(const uiBut *but)
-{
- BLI_assert(ELEM(but->type, UI_BTYPE_SEARCH_MENU));
- return ((but->editstr == NULL) && (but->drawstr[0] != '\0') && (but->flag & UI_BUT_VALUE_CLEAR));
-}
-
-static bool ui_but_icon_extra_is_visible_search_eyedropper(uiBut *but)
-{
- StructRNA *type;
- short idcode;
-
- BLI_assert(but->type == UI_BTYPE_SEARCH_MENU && (but->flag & UI_BUT_VALUE_CLEAR));
-
- if (but->rnaprop == NULL) {
- return false;
- }
-
- type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop);
- idcode = RNA_type_to_ID_code(type);
-
- return ((but->editstr == NULL) && (idcode == ID_OB || OB_DATA_SUPPORT_ID(idcode)));
-}
-
-uiButExtraIconType ui_but_icon_extra_get(uiBut *but)
-{
- switch (but->type) {
- case UI_BTYPE_TEXT:
- if (ui_but_icon_extra_is_visible_text_clear(but)) {
- return UI_BUT_ICONEXTRA_CLEAR;
- }
- break;
- case UI_BTYPE_SEARCH_MENU:
- if ((but->flag & UI_BUT_VALUE_CLEAR) == 0) {
- /* pass */
- }
- else if (ui_but_icon_extra_is_visible_search_unlink(but)) {
- return UI_BUT_ICONEXTRA_CLEAR;
- }
- else if (ui_but_icon_extra_is_visible_search_eyedropper(but)) {
- return UI_BUT_ICONEXTRA_EYEDROPPER;
- }
- break;
- default:
- break;
- }
-
- return UI_BUT_ICONEXTRA_NONE;
-}
-
-/** \} */
-
static double ui_get_but_scale_unit(uiBut *but, double value)
{
UnitSettings *unit = but->block->unit;
@@ -2509,7 +2628,7 @@ void ui_but_string_get_ex(uiBut *but,
else if (buf && buf != str) {
BLI_assert(maxlen <= buf_len + 1);
/* string was too long, we have to truncate */
- if (ui_but_is_utf8(but)) {
+ if (UI_but_is_utf8(but)) {
BLI_strncpy_utf8(str, buf, maxlen);
}
else {
@@ -2834,7 +2953,7 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str)
if (!but->poin) {
str = "";
}
- else if (ui_but_is_utf8(but)) {
+ else if (UI_but_is_utf8(but)) {
BLI_strncpy_utf8(but->poin, str, but->hardmax);
}
else {
@@ -3087,6 +3206,7 @@ static void ui_but_free(const bContext *C, uiBut *but)
if (but->dragpoin && (but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
MEM_freeN(but->dragpoin);
}
+ ui_but_extra_operator_icons_free(but);
BLI_assert(UI_butstore_is_registered(but->block, but) == false);
@@ -3586,6 +3706,14 @@ static uiBut *ui_def_but(uiBlock *block,
(a1 != 0.0f && a1 != 1.0f)) == false);
}
+ /* Number buttons must have a click-step,
+ * assert instead of correcting the value to ensure the caller knows what they're doing. */
+ if ((type & BUTTYPE) == UI_BTYPE_NUM) {
+ if (ELEM((type & UI_BUT_POIN_TYPES), UI_BUT_POIN_CHAR, UI_BUT_POIN_SHORT, UI_BUT_POIN_INT)) {
+ BLI_assert((int)a1 > 0);
+ }
+ }
+
if (type & UI_BUT_POIN_TYPES) { /* a pointer is required */
if (poin == NULL) {
BLI_assert(0);
@@ -4242,7 +4370,7 @@ static uiBut *ui_def_but_operator_ptr(uiBlock *block,
}
}
- if ((!tip || tip[0] == '\0') && ot && ot->srna) {
+ if ((!tip || tip[0] == '\0') && ot && ot->srna && !ot->get_description) {
tip = RNA_struct_ui_description(ot->srna);
}
@@ -6342,6 +6470,9 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
else if (but->tip && but->tip[0]) {
tmp = BLI_strdup(but->tip);
}
+ else if (but->optype && but->optype->get_description) {
+ tmp = WM_operatortype_description(C, but->optype, but->opptr);
+ }
else {
type = BUT_GET_RNA_TIP; /* Fail-safe solution... */
}
@@ -6558,3 +6689,8 @@ void UI_exit(void)
ui_resources_free();
ui_but_clipboard_free();
}
+
+void UI_interface_tag_script_reload(void)
+{
+ ui_interface_tag_script_reload_queries();
+}
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 168c6051327..c8baa1a7c7b 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -243,7 +243,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str)
}
/* create driver */
- fcu = verify_driver_fcurve(id, path, but->rnaindex, 1);
+ fcu = verify_driver_fcurve(id, path, but->rnaindex, DRIVER_FCURVE_KEYFRAMES);
if (fcu) {
ChannelDriver *driver = fcu->driver;
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index 0884a9ea470..b84b07adba5 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -176,11 +176,21 @@ static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg)
UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT);
UI_block_direction_set(block, UI_DIR_CENTER_Y);
- layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, 200, 20, 0, style);
-
+ layout = UI_block_layout(block,
+ UI_LAYOUT_VERTICAL,
+ UI_LAYOUT_PANEL,
+ 0,
+ 0,
+ U.widget_unit * 10,
+ U.widget_unit * 2,
+ 0,
+ style);
+
+ uiItemL(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Change Shortcut"), ICON_HAND);
uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT | UI_ITEM_R_IMMEDIATE, "", ICON_NONE);
- UI_block_bounds_set_popup(block, 6, (const int[2]){-50, 26});
+ UI_block_bounds_set_popup(
+ block, 6 * U.dpi_fac, (const int[2]){-100 * U.dpi_fac, 36 * U.dpi_fac});
shortcut_free_operator_property(prop);
@@ -227,11 +237,21 @@ static uiBlock *menu_add_shortcut(bContext *C, ARegion *ar, void *arg)
UI_block_func_handle_set(block, but_shortcut_name_func, but);
UI_block_direction_set(block, UI_DIR_CENTER_Y);
- layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, 200, 20, 0, style);
-
+ layout = UI_block_layout(block,
+ UI_LAYOUT_VERTICAL,
+ UI_LAYOUT_PANEL,
+ 0,
+ 0,
+ U.widget_unit * 10,
+ U.widget_unit * 2,
+ 0,
+ style);
+
+ uiItemL(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Assign Shortcut"), ICON_HAND);
uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT | UI_ITEM_R_IMMEDIATE, "", ICON_NONE);
- UI_block_bounds_set_popup(block, 6, (const int[2]){-50, 26});
+ UI_block_bounds_set_popup(
+ block, 6 * U.dpi_fac, (const int[2]){-100 * U.dpi_fac, 36 * U.dpi_fac});
#ifdef USE_KEYMAP_ADD_HACK
g_kmi_id_hack = kmi_id;
@@ -470,8 +490,9 @@ static void ui_but_menu_add_path_operators(uiLayout *layout, PointerRNA *ptr, Pr
bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
{
- /* having this menu for some buttons makes no sense */
- if (but->type == UI_BTYPE_IMAGE) {
+ /* ui_but_is_interactive() may let some buttons through that should not get a context menu - it
+ * doesn't make sense for them. */
+ if (ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_IMAGE)) {
return false;
}
@@ -878,13 +899,13 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
if (is_array_component) {
uiItemBooleanO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy All To Selected"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy All to Selected"),
ICON_NONE,
"UI_OT_copy_to_selected_button",
"all",
true);
uiItemBooleanO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Single To Selected"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Single to Selected"),
ICON_NONE,
"UI_OT_copy_to_selected_button",
"all",
@@ -892,7 +913,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
}
else {
uiItemBooleanO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy To Selected"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy to Selected"),
ICON_NONE,
"UI_OT_copy_to_selected_button",
"all",
@@ -907,7 +928,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
if (ptr->owner_id && !is_whole_array &&
ELEM(type, PROP_BOOLEAN, PROP_INT, PROP_FLOAT, PROP_ENUM)) {
uiItemO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy As New Driver"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy as New Driver"),
ICON_NONE,
"UI_OT_copy_as_driver_button");
}
@@ -929,7 +950,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
but->search_func == ui_rna_collection_search_cb)) &&
ui_jump_to_target_button_poll(C)) {
uiItemO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Jump To Target"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Jump to Target"),
ICON_NONE,
"UI_OT_jump_to_target_button");
uiItemS(layout);
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 76630de96db..72c31c7b39e 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -750,7 +750,7 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(ar),
/**
* Draw title and text safe areas.
*
- * \Note This functionn is to be used with the 2D dashed shader enabled.
+ * \note This function is to be used with the 2D dashed shader enabled.
*
* \param pos: is a PRIM_FLOAT, 2, GPU_FETCH_FLOAT vertex attribute.
* \param line_origin: is a PRIM_FLOAT, 2, GPU_FETCH_FLOAT vertex attribute.
@@ -1849,9 +1849,17 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, const uiWidgetColors *wcol, cons
cumap = (CurveMapping *)but->poin;
}
+ float clip_size_x = BLI_rctf_size_x(&cumap->curr);
+ float clip_size_y = BLI_rctf_size_y(&cumap->curr);
+
+ /* zero-sized curve */
+ if (clip_size_x == 0.0f || clip_size_y == 0.0f) {
+ return;
+ }
+
/* calculate offset and zoom */
- float zoomx = (BLI_rcti_size_x(rect) - 2.0f) / BLI_rctf_size_x(&cumap->curr);
- float zoomy = (BLI_rcti_size_y(rect) - 2.0f) / BLI_rctf_size_y(&cumap->curr);
+ float zoomx = (BLI_rcti_size_x(rect) - 2.0f) / clip_size_x;
+ float zoomy = (BLI_rcti_size_y(rect) - 2.0f) / clip_size_y;
float offsx = cumap->curr.xmin - (1.0f / zoomx);
float offsy = cumap->curr.ymin - (1.0f / zoomy);
@@ -2220,8 +2228,8 @@ void ui_draw_but_TRACKPREVIEW(ARegion *UNUSED(ar),
/* Do stipple cross with geometry */
immBegin(GPU_PRIM_LINES, 7 * 2 * 2);
float pos_sel[8] = {-10.0f, -7.0f, -4.0f, -1.0f, 2.0f, 5.0f, 8.0f, 11.0f};
- for (int axe = 0; axe < 2; ++axe) {
- for (int i = 0; i < 7; ++i) {
+ for (int axe = 0; axe < 2; axe++) {
+ for (int i = 0; i < 7; i++) {
float x1 = pos_sel[i] * (1 - axe);
float y1 = pos_sel[i] * axe;
float x2 = pos_sel[i + 1] * (1 - axe);
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 68c12fe7652..0cf357c508b 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -290,7 +290,7 @@ static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
{
/* init */
if (eyedropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
@@ -332,7 +332,7 @@ void UI_OT_eyedropper_color(wmOperatorType *ot)
/* identifiers */
ot->name = "Eyedropper";
ot->idname = "UI_OT_eyedropper_color";
- ot->description = "Sample a color from the Blender Window to store in a property";
+ ot->description = "Sample a color from the Blender window to store in a property";
/* api callbacks */
ot->invoke = eyedropper_invoke;
diff --git a/source/blender/editors/interface/interface_eyedropper_colorband.c b/source/blender/editors/interface/interface_eyedropper_colorband.c
index ffe93e48936..479cf9ccffe 100644
--- a/source/blender/editors/interface/interface_eyedropper_colorband.c
+++ b/source/blender/editors/interface/interface_eyedropper_colorband.c
@@ -304,7 +304,7 @@ static int eyedropper_colorband_invoke(bContext *C, wmOperator *op, const wmEven
{
/* init */
if (eyedropper_colorband_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c
index 336fae45895..fd5a46e7716 100644
--- a/source/blender/editors/interface/interface_eyedropper_datablock.c
+++ b/source/blender/editors/interface/interface_eyedropper_datablock.c
@@ -314,7 +314,7 @@ static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED
{
/* init */
if (datadropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c
index 2e51701e01d..8a48ca19db2 100644
--- a/source/blender/editors/interface/interface_eyedropper_depth.c
+++ b/source/blender/editors/interface/interface_eyedropper_depth.c
@@ -311,7 +311,7 @@ static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
{
/* init */
if (depthdropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/interface_eyedropper_driver.c
index e6fc52bc3bc..cc13367c190 100644
--- a/source/blender/editors/interface/interface_eyedropper_driver.c
+++ b/source/blender/editors/interface/interface_eyedropper_driver.c
@@ -180,7 +180,7 @@ static int driverdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
{
/* init */
if (driverdropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 13bfaa95077..e0442ebcca2 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -153,6 +153,13 @@ typedef enum uiHandleButtonState {
BUTTON_STATE_EXIT,
} uiHandleButtonState;
+typedef enum uiMenuScrollType {
+ MENU_SCROLL_UP,
+ MENU_SCROLL_DOWN,
+ MENU_SCROLL_TOP,
+ MENU_SCROLL_BOTTOM,
+} uiMenuScrollType;
+
#ifdef USE_ALLSELECT
/* Unfortunately there's no good way handle more generally:
@@ -2673,15 +2680,19 @@ void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR],
/** \name Button Text Selection/Editing
* \{ */
-static void ui_textedit_string_clear_and_exit(bContext *C, uiBut *but, uiHandleButtonData *data)
+void ui_but_active_string_clear_and_exit(bContext *C, uiBut *but)
{
+ if (!but->active) {
+ return;
+ }
+
/* most likely NULL, but let's check, and give it temp zero string */
- if (!data->str) {
- data->str = MEM_callocN(1, "temp str");
+ if (!but->active->str) {
+ but->active->str = MEM_callocN(1, "temp str");
}
- data->str[0] = 0;
+ but->active->str[0] = 0;
- ui_apply_but_TEX(C, but, data);
+ ui_apply_but_TEX(C, but, but->active);
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
@@ -2702,7 +2713,7 @@ static void ui_textedit_string_set(uiBut *but, uiHandleButtonData *data, const c
ui_textedit_string_ensure_max_length(but, data, strlen(str) + 1);
}
- if (ui_but_is_utf8(but)) {
+ if (UI_but_is_utf8(but)) {
BLI_strncpy_utf8(data->str, str, data->maxlen);
}
else {
@@ -2760,7 +2771,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
startx += UI_DPI_ICON_SIZE / aspect;
}
}
- /* but this extra .05 makes clicks inbetween characters feel nicer */
+ /* But this extra .05 makes clicks in between characters feel nicer. */
startx += ((UI_TEXT_MARGIN_X + 0.05f) * U.widget_unit) / aspect;
/* mouse dragged outside the widget to the left */
@@ -2887,7 +2898,7 @@ static bool ui_textedit_insert_buf(uiBut *but,
}
if ((len + step >= data->maxlen) && (data->maxlen - (len + 1) > 0)) {
- if (ui_but_is_utf8(but)) {
+ if (UI_but_is_utf8(but)) {
/* shorten 'step' to a utf8 aligned size that fits */
BLI_strnlen_utf8_ex(buf, data->maxlen - (len + 1), &step);
}
@@ -2911,7 +2922,7 @@ static bool ui_textedit_insert_ascii(uiBut *but, uiHandleButtonData *data, char
{
char buf[2] = {ascii, '\0'};
- if (ui_but_is_utf8(but) && (BLI_str_utf8_size(buf) == -1)) {
+ if (UI_but_is_utf8(but) && (BLI_str_utf8_size(buf) == -1)) {
printf(
"%s: entering invalid ascii char into an ascii key (%d)\n", __func__, (int)(uchar)ascii);
@@ -3092,7 +3103,7 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in
pbuf = WM_clipboard_text_get_firstline(false, &buf_len);
if (pbuf) {
- if (ui_but_is_utf8(but)) {
+ if (UI_but_is_utf8(but)) {
buf_len -= BLI_utf8_invalid_strip(pbuf, (size_t)buf_len);
}
@@ -3247,7 +3258,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
ui_but_update(but);
- WM_cursor_modal_set(win, BC_TEXTEDITCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_TEXT_EDIT);
#ifdef WITH_INPUT_IME
if (is_num_but == false && BLT_lang_is_ime_supported()) {
@@ -3261,7 +3272,7 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
wmWindow *win = CTX_wm_window(C);
if (but) {
- if (ui_but_is_utf8(but)) {
+ if (UI_but_is_utf8(but)) {
int strip = BLI_utf8_invalid_strip(but->editstr, strlen(but->editstr));
/* not a file?, strip non utf-8 chars */
if (strip) {
@@ -3768,6 +3779,19 @@ static void ui_numedit_apply(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
ED_region_tag_redraw(data->region);
}
+static void ui_but_extra_operator_icon_apply(bContext *C, uiBut *but, uiButExtraOpIcon *op_icon)
+{
+ WM_operator_name_call_ptr(C,
+ op_icon->optype_params->optype,
+ op_icon->optype_params->opcontext,
+ op_icon->optype_params->opptr);
+
+ /* Force recreation of extra operator icons (pseudo update). */
+ ui_but_extra_operator_icons_free(but);
+
+ WM_event_add_mousemove(C);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -3911,6 +3935,46 @@ static uiBut *ui_but_list_row_text_activate(bContext *C,
/** \name Events for Various Button Types
* \{ */
+static uiButExtraOpIcon *ui_but_extra_operator_icon_mouse_over_get(uiBut *but,
+ uiHandleButtonData *data,
+ const wmEvent *event)
+{
+ float xmax = but->rect.xmax;
+ const float icon_size = BLI_rctf_size_y(&but->rect);
+ int x = event->x, y = event->y;
+
+ ui_window_to_block(data->region, but->block, &x, &y);
+ if (!BLI_rctf_isect_pt(&but->rect, x, y)) {
+ return NULL;
+ }
+
+ /* Inverse order, from right to left. */
+ for (uiButExtraOpIcon *op_icon = but->extra_op_icons.last; op_icon; op_icon = op_icon->prev) {
+ if ((x > (xmax - icon_size)) && x < xmax) {
+ return op_icon;
+ }
+ xmax -= icon_size;
+ }
+
+ return NULL;
+}
+
+static bool ui_do_but_extra_operator_icon(bContext *C,
+ uiBut *but,
+ uiHandleButtonData *data,
+ const wmEvent *event)
+{
+ uiButExtraOpIcon *op_icon = ui_but_extra_operator_icon_mouse_over_get(but, data, event);
+
+ if (op_icon) {
+ ui_but_extra_operator_icon_apply(C, but, op_icon);
+ button_activate_exit(C, but, data, false, false);
+ return true;
+ }
+
+ return false;
+}
+
#ifdef USE_DRAG_TOGGLE
/* Shared by any button that supports drag-toggle. */
static bool ui_do_but_ANY_drag_toggle(
@@ -4098,23 +4162,6 @@ static int ui_do_but_KEYEVT(bContext *C,
return WM_UI_HANDLER_CONTINUE;
}
-static bool ui_but_is_mouse_over_icon_extra(const ARegion *region,
- uiBut *but,
- const int mouse_xy[2])
-{
- int x = mouse_xy[0], y = mouse_xy[1];
- rcti icon_rect;
-
- BLI_assert(ui_but_icon_extra_get(but) != UI_BUT_ICONEXTRA_NONE);
-
- ui_window_to_block(region, but->block, &x, &y);
-
- BLI_rcti_rctf_copy(&icon_rect, &but->rect);
- icon_rect.xmin = icon_rect.xmax - (BLI_rcti_size_y(&icon_rect));
-
- return BLI_rcti_isect_pt(&icon_rect, x, y);
-}
-
static int ui_do_but_TAB(
bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
@@ -4162,21 +4209,14 @@ static int ui_do_but_TEX(
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS) {
- if (ELEM(event->type, PADENTER, RETKEY) && (!ui_but_is_utf8(but))) {
+ if (ELEM(event->type, PADENTER, RETKEY) && (!UI_but_is_utf8(but))) {
/* pass - allow filesel, enter to execute */
}
else if (but->dt == UI_EMBOSS_NONE && !event->ctrl) {
/* pass */
}
- else {
- const bool has_icon_extra = ui_but_icon_extra_get(but) == UI_BUT_ICONEXTRA_CLEAR;
-
- if (has_icon_extra && ui_but_is_mouse_over_icon_extra(data->region, but, &event->x)) {
- ui_textedit_string_clear_and_exit(C, but, data);
- }
- else {
- button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
- }
+ else if (!ui_but_extra_operator_icon_mouse_over_get(but, data, event)) {
+ button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
return WM_UI_HANDLER_BREAK;
}
}
@@ -4196,27 +4236,12 @@ static int ui_do_but_TEX(
static int ui_do_but_SEARCH_UNLINK(
bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
- const uiButExtraIconType extra_icon_type = ui_but_icon_extra_get(but);
- const bool has_icon_extra = (extra_icon_type != UI_BUT_ICONEXTRA_NONE);
-
/* unlink icon is on right */
- if ((ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY)) && (has_icon_extra == true) &&
- (ui_but_is_mouse_over_icon_extra(data->region, but, &event->x) == true)) {
+ if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY)) {
/* doing this on KM_PRESS calls eyedropper after clicking unlink icon */
- if (event->val == KM_RELEASE) {
- /* unlink */
- if (extra_icon_type == UI_BUT_ICONEXTRA_CLEAR) {
- ui_textedit_string_clear_and_exit(C, but, data);
- }
- /* eyedropper */
- else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {
- WM_operator_name_call(C, "UI_OT_eyedropper_id", WM_OP_INVOKE_DEFAULT, NULL);
- }
- else {
- BLI_assert(0);
- }
+ if ((event->val == KM_RELEASE) && ui_do_but_extra_operator_icon(C, but, data, event)) {
+ return WM_UI_HANDLER_BREAK;
}
- return WM_UI_HANDLER_BREAK;
}
return ui_do_but_TEX(C, block, but, data, event);
}
@@ -4299,7 +4324,7 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
if (data->state == BUTTON_STATE_HIGHLIGHT) {
/* first handle click on icondrag type button */
- if (event->type == LEFTMOUSE && but->dragpoin) {
+ if ((event->type == LEFTMOUSE) && (event->val == KM_PRESS) && but->dragpoin) {
if (ui_but_contains_point_px_icon(but, data->region, event)) {
/* tell the button to wait and keep checking further events to
@@ -4311,7 +4336,7 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
}
}
#ifdef USE_DRAG_TOGGLE
- if (event->type == LEFTMOUSE && ui_but_is_drag_toggle(but)) {
+ if ((event->type == LEFTMOUSE) && (event->val == KM_PRESS) && ui_but_is_drag_toggle(but)) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
data->dragstartx = event->x;
data->dragstarty = event->y;
@@ -4660,7 +4685,7 @@ static void ui_numedit_set_active(uiBut *but)
}
else {
if (data->changed_cursor == false) {
- WM_cursor_modal_set(data->window, CURSOR_X_MOVE);
+ WM_cursor_modal_set(data->window, WM_CURSOR_X_MOVE);
data->changed_cursor = true;
}
}
@@ -6976,6 +7001,14 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
if (event->type == EVT_DROP) {
ui_but_drop(C, event, but, data);
}
+
+ if ((data->state == BUTTON_STATE_HIGHLIGHT) &&
+ ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) &&
+ (event->val == KM_RELEASE) &&
+ /* Only returns true if the event was handled. */
+ ui_do_but_extra_operator_icon(C, but, data, event)) {
+ return WM_UI_HANDLER_BREAK;
+ }
}
if (but->flag & UI_BUT_DISABLED) {
@@ -7531,7 +7564,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
if (but->type == UI_BTYPE_GRIP) {
const bool horizontal = (BLI_rctf_size_x(&but->rect) < BLI_rctf_size_y(&but->rect));
- WM_cursor_modal_set(data->window, horizontal ? CURSOR_X_MOVE : CURSOR_Y_MOVE);
+ WM_cursor_modal_set(data->window, horizontal ? WM_CURSOR_X_MOVE : WM_CURSOR_Y_MOVE);
}
else if (but->type == UI_BTYPE_NUM) {
ui_numedit_set_active(but);
@@ -9095,6 +9128,10 @@ static int ui_handle_menu_event(bContext *C,
}
case UPARROWKEY:
case DOWNARROWKEY:
+ case PAGEUPKEY:
+ case PAGEDOWNKEY:
+ case HOMEKEY:
+ case ENDKEY:
case MOUSEPAN:
/* arrowkeys: only handle for block_loop blocks */
if (IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) {
@@ -9110,8 +9147,22 @@ static int ui_handle_menu_event(bContext *C,
}
if (val == KM_PRESS) {
- const bool is_next = (ELEM(type, DOWNARROWKEY, WHEELDOWNMOUSE) ==
- ((block->flag & UI_BLOCK_IS_FLIP) != 0));
+ /* Determine scroll operation. */
+ uiMenuScrollType scrolltype;
+ bool ui_block_flipped = (block->flag & UI_BLOCK_IS_FLIP) != 0;
+
+ if (ELEM(type, PAGEUPKEY, HOMEKEY)) {
+ scrolltype = ui_block_flipped ? MENU_SCROLL_TOP : MENU_SCROLL_BOTTOM;
+ }
+ else if (ELEM(type, PAGEDOWNKEY, ENDKEY)) {
+ scrolltype = ui_block_flipped ? MENU_SCROLL_BOTTOM : MENU_SCROLL_TOP;
+ }
+ else if (ELEM(type, UPARROWKEY, WHEELUPMOUSE)) {
+ scrolltype = ui_block_flipped ? MENU_SCROLL_UP : MENU_SCROLL_DOWN;
+ }
+ else {
+ scrolltype = ui_block_flipped ? MENU_SCROLL_DOWN : MENU_SCROLL_UP;
+ }
if (ui_menu_pass_event_to_parent_if_nonactive(menu, but, level, retval)) {
break;
@@ -9123,16 +9174,24 @@ static int ui_handle_menu_event(bContext *C,
but = ui_region_find_active_but(ar);
if (but) {
- /* next button */
- but = is_next ? ui_but_next(but) : ui_but_prev(but);
- }
-
- if (!but) {
- /* wrap button */
- uiBut *but_wrap;
- but_wrap = is_next ? ui_but_first(block) : ui_but_last(block);
- if (but_wrap) {
- but = but_wrap;
+ /* Apply scroll operation. */
+ if (scrolltype == MENU_SCROLL_DOWN) {
+ but = ui_but_next(but);
+ if (but == NULL) {
+ but = ui_but_first(block);
+ }
+ }
+ else if (scrolltype == MENU_SCROLL_UP) {
+ but = ui_but_prev(but);
+ if (but == NULL) {
+ but = ui_but_last(block);
+ }
+ }
+ else if (scrolltype == MENU_SCROLL_TOP) {
+ but = ui_but_first(block);
+ }
+ else if (scrolltype == MENU_SCROLL_BOTTOM) {
+ but = ui_but_last(block);
}
}
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 1674374396f..b844e237366 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -27,7 +27,6 @@
#include "MEM_guardedalloc.h"
-#include "GPU_draw.h"
#include "GPU_matrix.h"
#include "GPU_batch.h"
#include "GPU_immediate.h"
@@ -154,8 +153,8 @@ typedef struct IconType {
} IconType;
/* ******************* STATIC LOCAL VARS ******************* */
-/* static here to cache results of icon directory scan, so it's not
- * scanning the filesystem each time the menu is drawn */
+/* Static here to cache results of icon directory scan, so it's not
+ * scanning the file-system each time the menu is drawn. */
static struct ListBase iconfilelist = {NULL, NULL};
static IconTexture icongltex = {{0, 0}, 0, 0, 0, 0.0f, 0.0f};
@@ -169,6 +168,7 @@ static const IconType icontypes[] = {
# define DEF_ICON_OBJECT_DATA(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_OBJECT_DATA},
# define DEF_ICON_MODIFIER(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_MODIFIER},
# define DEF_ICON_SHADING(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_SHADING},
+# define DEF_ICON_FOLDER(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_FOLDER},
# define DEF_ICON_FUND(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_FUND},
# define DEF_ICON_VECTOR(name) {ICON_TYPE_VECTOR, 0},
# define DEF_ICON_COLOR(name) {ICON_TYPE_COLOR_TEXTURE, 0},
@@ -553,6 +553,8 @@ static void init_brush_icons(void)
INIT_BRUSH_ICON(ICON_GPBRUSH_BLOCK, gp_brush_block);
INIT_BRUSH_ICON(ICON_GPBRUSH_MARKER, gp_brush_marker);
INIT_BRUSH_ICON(ICON_GPBRUSH_FILL, gp_brush_fill);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_AIRBRUSH, gp_brush_airbrush);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_CHISEL, gp_brush_chisel);
INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_SOFT, gp_brush_erase_soft);
INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_HARD, gp_brush_erase_hard);
INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_STROKE, gp_brush_erase_stroke);
@@ -775,7 +777,7 @@ static ImBuf *create_mono_icon_with_border(ImBuf *buf,
const int blurred_alpha_offset = by * (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) + bx;
const int offset_write = (sy + by) * buf->x + (sx + bx);
const float blurred_alpha = blurred_alpha_buffer[blurred_alpha_offset];
- float border_srgb[4] = {
+ const float border_srgb[4] = {
0, 0, 0, MIN2(1.0, blurred_alpha * border_sharpness) * border_intensity};
const unsigned int color_read = buf->rect[offset_write];
@@ -2059,6 +2061,12 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
case GP_BRUSH_ICON_FILL:
br->id.icon_id = ICON_GPBRUSH_FILL;
break;
+ case GP_BRUSH_ICON_AIRBRUSH:
+ br->id.icon_id = ICON_GPBRUSH_AIRBRUSH;
+ break;
+ case GP_BRUSH_ICON_CHISEL:
+ br->id.icon_id = ICON_GPBRUSH_CHISEL;
+ break;
case GP_BRUSH_ICON_ERASE_SOFT:
br->id.icon_id = ICON_GPBRUSH_ERASE_SOFT;
break;
@@ -2244,6 +2252,8 @@ int UI_idcode_icon_get(const int idcode)
return ICON_FONT_DATA;
case ID_WO:
return ICON_WORLD_DATA;
+ case ID_WS:
+ return ICON_WORKSPACE;
default:
return ICON_NONE;
}
diff --git a/source/blender/editors/interface/interface_icons_event.c b/source/blender/editors/interface/interface_icons_event.c
index 0992ee95fd7..e1ce77b8b61 100644
--- a/source/blender/editors/interface/interface_icons_event.c
+++ b/source/blender/editors/interface/interface_icons_event.c
@@ -29,8 +29,6 @@
#include "MEM_guardedalloc.h"
-#include "GPU_draw.h"
-#include "GPU_matrix.h"
#include "GPU_batch.h"
#include "GPU_immediate.h"
#include "GPU_state.h"
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index a5d9d35e2fe..4351b75eb86 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -78,14 +78,6 @@ enum {
/* warn: rest of uiBut->flag in UI_interface.h */
};
-/* some buttons display icons only under special conditions
- * (e.g. 'x' icon in search menu) - used with ui_but_icon_extra_get */
-typedef enum uiButExtraIconType {
- UI_BUT_ICONEXTRA_NONE = 1,
- UI_BUT_ICONEXTRA_CLEAR,
- UI_BUT_ICONEXTRA_EYEDROPPER,
-} uiButExtraIconType;
-
/* uiBut->dragflag */
enum {
UI_BUT_DRAGPOIN_FREE = (1 << 0),
@@ -262,6 +254,8 @@ struct uiBut {
short opcontext;
uchar menu_key; /* 'a'-'z', always lower case */
+ ListBase extra_op_icons; /* uiButExtraOpIcon */
+
/* Draggable data, type is WM_DRAG_... */
char dragtype;
short dragflag;
@@ -293,6 +287,16 @@ typedef struct uiButTab {
struct MenuType *menu;
} uiButTab;
+/**
+ * Additional, superimposed icon for a button, invoking an operator.
+ */
+typedef struct uiButExtraOpIcon {
+ struct uiButExtraOpIcon *next, *prev;
+
+ BIFIconID icon;
+ struct wmOperatorCallParams *optype_params;
+} uiButExtraOpIcon;
+
typedef struct ColorPicker {
struct ColorPicker *next, *prev;
/** Color data, may be HSV or HSL. */
@@ -497,14 +501,17 @@ extern bool ui_but_string_set_eval_num(struct bContext *C,
const char *str,
double *value) ATTR_NONNULL();
extern int ui_but_string_get_max_length(uiBut *but);
+/* Clear & exit the active button's string. */
+extern void ui_but_active_string_clear_and_exit(struct bContext *C, uiBut *but) ATTR_NONNULL();
extern uiBut *ui_but_drag_multi_edit_get(uiBut *but);
void ui_def_but_icon(uiBut *but, const int icon, const int flag);
void ui_def_but_icon_clear(uiBut *but);
-extern uiButExtraIconType ui_but_icon_extra_get(uiBut *but);
extern void ui_but_default_set(struct bContext *C, const bool all, const bool use_afterfunc);
+void ui_but_extra_operator_icons_free(uiBut *but);
+
extern void ui_but_rna_menu_convert_to_panel_type(struct uiBut *but, const char *panel_type);
extern void ui_but_rna_menu_convert_to_menu_type(struct uiBut *but, const char *menu_type);
extern bool ui_but_menu_draw_as_popover(const uiBut *but);
@@ -892,7 +899,6 @@ bool ui_but_is_editable(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_editable_as_text(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_toggle(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_interactive(const uiBut *but, const bool labeledit) ATTR_WARN_UNUSED_RESULT;
-bool ui_but_is_utf8(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_popover_once_compat(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_has_array_value(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
void ui_but_pie_dir(RadialDirection dir, float vec[2]);
@@ -987,4 +993,7 @@ void ui_rna_collection_search_cb(const struct bContext *C,
/* interface_ops.c */
bool ui_jump_to_target_button_poll(struct bContext *C);
+/* interface_queries.c */
+void ui_interface_tag_script_reload_queries(void);
+
#endif /* __INTERFACE_INTERN_H__ */
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 529cb0712df..a6f8ba4560d 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -63,7 +63,9 @@
* giving more room for the text at the expense of nicely aligned text. */
#define UI_PROP_SEP_ICON_WIDTH_EXCEPTION
-/************************ Structs and Defines *************************/
+/* -------------------------------------------------------------------- */
+/** \name Structs and Defines
+ * \{ */
#define UI_OPERATOR_ERROR_RET(_ot, _opname, return_statement) \
if (ot == NULL) { \
@@ -128,8 +130,8 @@ typedef struct uiItem {
} uiItem;
enum {
- UI_ITEM_FIXED = 1 << 0,
- UI_ITEM_MIN = 1 << 1,
+ UI_ITEM_AUTO_FIXED_SIZE = 1 << 0,
+ UI_ITEM_FIXED_SIZE = 1 << 1,
UI_ITEM_BOX_ITEM = 1 << 2, /* The item is "inside" a box item */
UI_ITEM_PROP_SEP = 1 << 3,
@@ -211,7 +213,11 @@ typedef struct uiLayoutItemRoot {
uiLayout litem;
} uiLayoutItemRoot;
-/************************** Item ***************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Item
+ * \{ */
static const char *ui_item_name_add_colon(const char *name, char namestr[UI_MAX_NAME_STR])
{
@@ -301,7 +307,7 @@ static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool
return unit_x; /* No icon or name. */
}
if (layout->alignment != UI_LAYOUT_ALIGN_EXPAND) {
- layout->item.flag |= UI_ITEM_MIN;
+ layout->item.flag |= UI_ITEM_FIXED_SIZE;
}
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
float margin = compact ? 1.25 : 1.50;
@@ -408,7 +414,11 @@ static void ui_item_move(uiItem *item, int delta_xmin, int delta_xmax)
}
}
-/******************** Special RNA Items *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Special RNA Items
+ * \{ */
int uiLayoutGetLocalDir(const uiLayout *layout)
{
@@ -1088,7 +1098,11 @@ void UI_context_active_but_prop_get_filebrowser(const bContext *C,
}
}
-/********************* Button Items *************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Button Items
+ * \{ */
/**
* Update a buttons tip with an enum's description if possible.
@@ -1096,7 +1110,8 @@ void UI_context_active_but_prop_get_filebrowser(const bContext *C,
static void ui_but_tip_from_enum_item(uiBut *but, const EnumPropertyItem *item)
{
if (but->tip == NULL || but->tip[0] == '\0') {
- if (item->description && item->description[0]) {
+ if (item->description && item->description[0] &&
+ !(but->optype && but->optype->get_description)) {
but->tip = item->description;
}
}
@@ -3235,7 +3250,11 @@ void uiItemTabsEnumR_prop(
ui_item_enum_expand_tabs(layout, C, block, ptr, prop, NULL, UI_UNIT_Y, icon_only);
}
-/**************************** Layout Items ***************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Layout Items
+ * \{ */
/* single-row layout */
static void ui_litem_estimate_row(uiLayout *litem)
@@ -3250,7 +3269,7 @@ static void ui_litem_estimate_row(uiLayout *litem)
for (item = litem->items.first; item; item = item->next) {
ui_item_size(item, &itemw, &itemh);
- min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN);
+ min_size_flag = min_size_flag && (item->flag & UI_ITEM_FIXED_SIZE);
litem->w += itemw;
litem->h = MAX2(itemh, litem->h);
@@ -3261,7 +3280,7 @@ static void ui_litem_estimate_row(uiLayout *litem)
}
if (min_size_flag) {
- litem->item.flag |= UI_ITEM_MIN;
+ litem->item.flag |= UI_ITEM_FIXED_SIZE;
}
}
@@ -3307,7 +3326,7 @@ static void ui_litem_layout_row(uiLayout *litem)
extra_pixel = 0.0f;
for (item = litem->items.first; item; item = item->next) {
- if (item->flag & UI_ITEM_FIXED) {
+ if (item->flag & UI_ITEM_AUTO_FIXED_SIZE) {
continue;
}
@@ -3323,18 +3342,19 @@ static void ui_litem_layout_row(uiLayout *litem)
x += neww;
- bool min_flag = item->flag & UI_ITEM_MIN;
+ bool min_flag = item->flag & UI_ITEM_FIXED_SIZE;
/* ignore min flag for rows with right or center alignment */
if (item->type != ITEM_BUTTON &&
ELEM(((uiLayout *)item)->alignment, UI_LAYOUT_ALIGN_RIGHT, UI_LAYOUT_ALIGN_CENTER) &&
- litem->alignment == UI_LAYOUT_ALIGN_EXPAND && ((uiItem *)litem)->flag & UI_ITEM_MIN) {
+ litem->alignment == UI_LAYOUT_ALIGN_EXPAND &&
+ ((uiItem *)litem)->flag & UI_ITEM_FIXED_SIZE) {
min_flag = false;
}
if ((neww < minw || min_flag) && w != 0) {
/* fixed size */
- item->flag |= UI_ITEM_FIXED;
- if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_MIN) {
+ item->flag |= UI_ITEM_AUTO_FIXED_SIZE;
+ if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_FIXED_SIZE) {
minw = itemw;
}
fixedw += minw;
@@ -3343,7 +3363,7 @@ static void ui_litem_layout_row(uiLayout *litem)
}
else {
/* keep free size */
- item->flag &= ~UI_ITEM_FIXED;
+ item->flag &= ~UI_ITEM_AUTO_FIXED_SIZE;
freew += itemw;
}
}
@@ -3361,9 +3381,9 @@ static void ui_litem_layout_row(uiLayout *litem)
ui_item_size(item, &itemw, &itemh);
minw = ui_litem_min_width(itemw);
- if (item->flag & UI_ITEM_FIXED) {
+ if (item->flag & UI_ITEM_AUTO_FIXED_SIZE) {
/* fixed minimum size items */
- if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_MIN) {
+ if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_FIXED_SIZE) {
minw = itemw;
}
itemw = ui_item_fit(
@@ -3404,7 +3424,7 @@ static void ui_litem_layout_row(uiLayout *litem)
uiItem *last_item = litem->items.last;
extra_pixel = litem->w - (x - litem->x);
if (extra_pixel > 0 && litem->alignment == UI_LAYOUT_ALIGN_EXPAND && last_free_item &&
- last_item && last_item->flag & UI_ITEM_FIXED) {
+ last_item && last_item->flag & UI_ITEM_AUTO_FIXED_SIZE) {
ui_item_move(last_free_item, 0, extra_pixel);
for (item = last_free_item->next; item; item = item->next) {
ui_item_move(item, extra_pixel, extra_pixel);
@@ -3430,7 +3450,7 @@ static void ui_litem_estimate_column(uiLayout *litem, bool is_box)
for (item = litem->items.first; item; item = item->next) {
ui_item_size(item, &itemw, &itemh);
- min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN);
+ min_size_flag = min_size_flag && (item->flag & UI_ITEM_FIXED_SIZE);
litem->w = MAX2(litem->w, itemw);
litem->h += itemh;
@@ -3441,7 +3461,7 @@ static void ui_litem_estimate_column(uiLayout *litem, bool is_box)
}
if (min_size_flag) {
- litem->item.flag |= UI_ITEM_MIN;
+ litem->item.flag |= UI_ITEM_FIXED_SIZE;
}
}
@@ -4260,7 +4280,7 @@ static void ui_litem_layout_absolute(uiLayout *litem)
static void ui_litem_estimate_split(uiLayout *litem)
{
ui_litem_estimate_row(litem);
- litem->item.flag &= ~UI_ITEM_MIN;
+ litem->item.flag &= ~UI_ITEM_FIXED_SIZE;
}
static void ui_litem_layout_split(uiLayout *litem)
@@ -4733,7 +4753,11 @@ int uiLayoutGetEmboss(uiLayout *layout)
}
}
-/********************** Layout *******************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Layout
+ * \{ */
static void ui_item_scale(uiLayout *litem, const float scale[2])
{
@@ -5076,7 +5100,7 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but)
/* XXX uiBut hasn't scaled yet
* we can flag the button as not expandable, depending on its size */
if (w <= 2 * UI_UNIT_X && (!but->str || but->str[0] == '\0')) {
- bitem->item.flag |= UI_ITEM_MIN;
+ bitem->item.flag |= UI_ITEM_FIXED_SIZE;
}
if (layout->child_items_layout) {
@@ -5096,6 +5120,21 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but)
}
}
+void uiLayoutSetFixedSize(uiLayout *layout, bool fixed_size)
+{
+ if (fixed_size) {
+ layout->item.flag |= UI_ITEM_FIXED_SIZE;
+ }
+ else {
+ layout->item.flag &= ~UI_ITEM_FIXED_SIZE;
+ }
+}
+
+bool uiLayoutGetFixedSize(uiLayout *layout)
+{
+ return (layout->item.flag & UI_ITEM_FIXED_SIZE) != 0;
+}
+
void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext)
{
layout->root->opcontext = opcontext;
@@ -5267,3 +5306,5 @@ void UI_paneltype_draw(bContext *C, PanelType *pt, uiLayout *layout)
CTX_store_set(C, NULL);
}
}
+
+/** \} */
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 0afd67e5e66..4e56a02997b 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -100,10 +100,12 @@ static bool copy_data_path_button_poll(bContext *C)
static int copy_data_path_button_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
PointerRNA ptr;
PropertyRNA *prop;
char *path;
int index;
+ ID *id;
const bool full_path = RNA_boolean_get(op->ptr, "full_path");
@@ -111,18 +113,20 @@ static int copy_data_path_button_exec(bContext *C, wmOperator *op)
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.owner_id != NULL) {
-
if (full_path) {
-
if (prop) {
- path = RNA_path_full_property_py_ex(&ptr, prop, index, true);
+ path = RNA_path_full_property_py_ex(bmain, &ptr, prop, index, true);
}
else {
- path = RNA_path_full_struct_py(&ptr);
+ path = RNA_path_full_struct_py(bmain, &ptr);
}
}
else {
- path = RNA_path_from_ID_to_property(&ptr, prop);
+ path = RNA_path_from_real_ID_to_property_index(bmain, &ptr, prop, 0, -1, &id);
+
+ if (!path) {
+ path = RNA_path_from_ID_to_property(&ptr, prop);
+ }
}
if (path) {
@@ -185,8 +189,9 @@ static bool copy_as_driver_button_poll(bContext *C)
return 0;
}
-static int copy_as_driver_button_exec(bContext *C, wmOperator *UNUSED(op))
+static int copy_as_driver_button_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
PointerRNA ptr;
PropertyRNA *prop;
int index;
@@ -195,14 +200,19 @@ static int copy_as_driver_button_exec(bContext *C, wmOperator *UNUSED(op))
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.owner_id && ptr.data && prop) {
+ ID *id;
int dim = RNA_property_array_dimension(&ptr, prop, NULL);
- char *path = RNA_path_from_ID_to_property_index(&ptr, prop, dim, index);
+ char *path = RNA_path_from_real_ID_to_property_index(bmain, &ptr, prop, dim, index, &id);
if (path) {
- ANIM_copy_as_driver(ptr.owner_id, path, RNA_property_identifier(prop));
+ ANIM_copy_as_driver(id, path, RNA_property_identifier(prop));
MEM_freeN(path);
return OPERATOR_FINISHED;
}
+ else {
+ BKE_reportf(op->reports, RPT_ERROR, "Could not compute a valid data path");
+ return OPERATOR_CANCELLED;
+ }
}
return OPERATOR_CANCELLED;
@@ -211,7 +221,7 @@ static int copy_as_driver_button_exec(bContext *C, wmOperator *UNUSED(op))
static void UI_OT_copy_as_driver_button(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Copy As New Driver";
+ ot->name = "Copy as New Driver";
ot->idname = "UI_OT_copy_as_driver_button";
ot->description =
"Create a new driver with this property as input, and copy it to the "
@@ -443,7 +453,7 @@ static int unset_property_button_exec(bContext *C, wmOperator *UNUSED(op))
static void UI_OT_unset_property_button(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Unset property";
+ ot->name = "Unset Property";
ot->idname = "UI_OT_unset_property_button";
ot->description = "Clear the property and use default or generated value in operators";
@@ -934,7 +944,7 @@ static int copy_to_selected_button_exec(bContext *C, wmOperator *op)
static void UI_OT_copy_to_selected_button(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Copy To Selected";
+ ot->name = "Copy to Selected";
ot->idname = "UI_OT_copy_to_selected_button";
ot->description = "Copy property from this object to selected objects or bones";
@@ -1082,7 +1092,7 @@ static int jump_to_target_button_exec(bContext *C, wmOperator *UNUSED(op))
static void UI_OT_jump_to_target_button(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Jump To Target";
+ ot->name = "Jump to Target";
ot->idname = "UI_OT_jump_to_target_button";
ot->description = "Switch to the target object or bone";
@@ -1580,6 +1590,34 @@ static void UI_OT_button_execute(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Text Button Clear Operator
+ * \{ */
+
+static int button_string_clear_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ uiBut *but = UI_context_active_but_get(C);
+
+ if (but) {
+ ui_but_active_string_clear_and_exit(C, but);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void UI_OT_button_string_clear(wmOperatorType *ot)
+{
+ ot->name = "Clear Button String";
+ ot->idname = "UI_OT_button_string_clear";
+ ot->description = "Unsets the text of the active button";
+
+ ot->poll = ED_operator_regionactive;
+ ot->exec = button_string_clear_exec;
+ ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Drop Color Operator
* \{ */
@@ -1704,6 +1742,7 @@ void ED_operatortypes_ui(void)
#endif
WM_operatortype_append(UI_OT_reloadtranslation);
WM_operatortype_append(UI_OT_button_execute);
+ WM_operatortype_append(UI_OT_button_string_clear);
/* external */
WM_operatortype_append(UI_OT_eyedropper_color);
diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c
index d0efb3714bc..34b1070f8b4 100644
--- a/source/blender/editors/interface/interface_query.c
+++ b/source/blender/editors/interface/interface_query.c
@@ -100,7 +100,7 @@ bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
}
/* file selectors are exempt from utf-8 checks */
-bool ui_but_is_utf8(const uiBut *but)
+bool UI_but_is_utf8(const uiBut *but)
{
if (but->rnaprop) {
const int subtype = RNA_property_subtype(but->rnaprop);
@@ -137,15 +137,15 @@ bool ui_but_has_array_value(const uiBut *but)
PROP_COORDS));
}
+static wmOperatorType *g_ot_tool_set_by_id = NULL;
bool UI_but_is_tool(const uiBut *but)
{
/* very evil! */
if (but->optype != NULL) {
- static wmOperatorType *ot = NULL;
- if (ot == NULL) {
- ot = WM_operatortype_find("WM_OT_tool_set_by_id", false);
+ if (g_ot_tool_set_by_id == NULL) {
+ g_ot_tool_set_by_id = WM_operatortype_find("WM_OT_tool_set_by_id", false);
}
- if (but->optype == ot) {
+ if (but->optype == g_ot_tool_set_by_id) {
return true;
}
}
@@ -463,14 +463,33 @@ bool ui_block_is_popup_any(const uiBlock *block)
return (ui_block_is_menu(block) || ui_block_is_popover(block) || ui_block_is_pie_menu(block));
}
-bool UI_block_is_empty(const uiBlock *block)
+static const uiBut *ui_but_next_non_separator(const uiBut *but)
{
- for (const uiBut *but = block->buttons.first; but; but = but->next) {
+ for (; but; but = but->next) {
if (!ELEM(but->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE)) {
- return false;
+ return but;
}
}
- return true;
+ return NULL;
+}
+
+bool UI_block_is_empty_ex(const uiBlock *block, const bool skip_title)
+{
+ const uiBut *but = block->buttons.first;
+ if (skip_title) {
+ /* Skip the first label, since popups often have a title,
+ * we may want to consider the block empty in this case. */
+ but = ui_but_next_non_separator(but);
+ if (but && but->type == UI_BTYPE_LABEL) {
+ but = but->next;
+ }
+ }
+ return (ui_but_next_non_separator(but) == NULL);
+}
+
+bool UI_block_is_empty(const uiBlock *block)
+{
+ return UI_block_is_empty_ex(block, false);
}
bool UI_block_can_add_separator(const uiBlock *block)
@@ -596,3 +615,14 @@ ARegion *ui_screen_region_find_mouse_over(bScreen *screen, const wmEvent *event)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Manage Internal State
+ * \{ */
+
+void ui_interface_tag_script_reload_queries(void)
+{
+ g_ot_tool_set_by_id = NULL;
+}
+
+/** \} */
diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c
index ab3a86ec9e1..fed3c0b3d11 100644
--- a/source/blender/editors/interface/interface_region_menu_popup.c
+++ b/source/blender/editors/interface/interface_region_menu_popup.c
@@ -474,7 +474,7 @@ void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
bool UI_popup_menu_end_or_cancel(bContext *C, uiPopupMenu *pup)
{
- if (!UI_block_is_empty(pup->block)) {
+ if (!UI_block_is_empty_ex(pup->block, true)) {
UI_popup_menu_end(C, pup);
return true;
}
diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c
index 2073117d51c..63dee77e90e 100644
--- a/source/blender/editors/interface/interface_region_popup.c
+++ b/source/blender/editors/interface/interface_region_popup.c
@@ -765,7 +765,7 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C,
UI_but_tooltip_timer_remove(C, activebut);
}
/* standard cursor by default */
- WM_cursor_set(window, CURSOR_STD);
+ WM_cursor_set(window, WM_CURSOR_DEFAULT);
/* create handle */
handle = MEM_callocN(sizeof(uiPopupBlockHandle), "uiPopupBlockHandle");
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index f2ca9cebf7b..3f20e8247b9 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -860,10 +860,10 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
/* move ownership (no need for re-alloc) */
if (but->rnaprop) {
field->text = RNA_path_full_property_py_ex(
- &but->rnapoin, but->rnaprop, but->rnaindex, true);
+ CTX_data_main(C), &but->rnapoin, but->rnaprop, but->rnaindex, true);
}
else {
- field->text = RNA_path_full_struct_py(&but->rnapoin);
+ field->text = RNA_path_full_struct_py(CTX_data_main(C), &but->rnapoin);
}
}
}
@@ -932,18 +932,14 @@ static uiTooltipData *ui_tooltip_data_from_gizmo(bContext *C, wmGizmo *gz)
NULL;
if (gzop != NULL) {
/* Description */
- const char *info = RNA_struct_ui_description(gzop->type->srna);
- if (!(info && info[0])) {
- info = RNA_struct_ui_name(gzop->type->srna);
- }
+ char *info = WM_operatortype_description(C, gzop->type, &gzop->ptr);
+
+ if (info != NULL) {
+ char *text = info;
- if (info && info[0]) {
- char *text = NULL;
if (gzop_actions[i].prefix != NULL) {
text = BLI_sprintfN("%s: %s", gzop_actions[i].prefix, info);
- }
- else {
- text = BLI_strdup(info);
+ MEM_freeN(info);
}
if (text != NULL) {
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 1c6618bc509..fe484676ddd 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -76,6 +76,7 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
+#include "ED_fileselect.h"
#include "ED_screen.h"
#include "ED_object.h"
#include "ED_render.h"
@@ -104,6 +105,24 @@ void UI_template_fix_linking(void)
{
}
+/* -------------------------------------------------------------------- */
+/** \name Header Template
+ * \{ */
+
+void uiTemplateHeader(uiLayout *layout, bContext *C)
+{
+ uiBlock *block;
+
+ block = uiLayoutAbsoluteBlock(layout);
+ ED_area_header_switchbutton(C, block, 0);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Search Menu Helpers
+ * \{ */
+
/**
* Add a block button for the search menu for templateID and templateSearch.
*/
@@ -264,17 +283,11 @@ static uiBlock *template_common_search_menu(const bContext *C,
return block;
}
-/********************** Header Template *************************/
-
-void uiTemplateHeader(uiLayout *layout, bContext *C)
-{
- uiBlock *block;
-
- block = uiLayoutAbsoluteBlock(layout);
- ED_area_header_switchbutton(C, block, 0);
-}
+/** \} */
-/********************** Search Callbacks *************************/
+/* -------------------------------------------------------------------- */
+/** \name Search Callbacks
+ * \{ */
typedef struct TemplateID {
PointerRNA ptr;
@@ -450,7 +463,12 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
template_ui.scale);
}
-/************************ ID Template ***************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID Template
+ * \{ */
+
/* This is for browsing and editing the ID-blocks used */
/* for new/open operators */
@@ -516,12 +534,15 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
if (id) {
Main *bmain = CTX_data_main(C);
if (BKE_override_library_is_enabled() && CTX_wm_window(C)->eventstate->shift) {
- ID *override_id = BKE_override_library_create_from_id(bmain, id);
- if (override_id != NULL) {
- BKE_main_id_clear_newpoins(bmain);
-
- /* Assign new pointer, takes care of updates/notifiers */
- RNA_id_pointer_create(override_id, &idptr);
+ if (ID_IS_OVERRIDABLE_LIBRARY(id)) {
+ /* Only remap that specific ID usage to overriding local data-block. */
+ ID *override_id = BKE_override_library_create_from_id(bmain, id, false);
+ if (override_id != NULL) {
+ BKE_main_id_clear_newpoins(bmain);
+
+ /* Assign new pointer, takes care of updates/notifiers */
+ RNA_id_pointer_create(override_id, &idptr);
+ }
}
}
else {
@@ -538,7 +559,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
break;
case UI_ID_OVERRIDE:
if (id && id->override_library) {
- BKE_override_library_free(&id->override_library);
+ BKE_override_library_free(&id->override_library, true);
/* reassign to get get proper updates/notifiers */
idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL);
@@ -1364,7 +1385,11 @@ void uiTemplateIDTabs(uiLayout *layout,
false);
}
-/************************ ID Chooser Template ***************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID Chooser Template
+ * \{ */
/**
* This is for selecting the type of ID-block to use,
@@ -1437,7 +1462,11 @@ void uiTemplateAnyID(uiLayout *layout,
uiItemFullR(sub, ptr, propID, 0, 0, 0, "", ICON_NONE);
}
-/********************* Search Template ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Search Template
+ * \{ */
typedef struct TemplateSearch {
uiRNACollectionSearch search_data;
@@ -1683,7 +1712,11 @@ void uiTemplateSearchPreview(uiLayout *layout,
}
}
-/********************* RNA Path Builder Template ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name RNA Path Builder Template
+ * \{ */
/* ---------- */
@@ -1720,7 +1753,11 @@ void uiTemplatePathBuilder(uiLayout *layout,
* searching of nested properties to 'build' the path */
}
-/************************ Modifier Template *************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Modifier Template
+ * \{ */
#define ERROR_LIBDATA_MESSAGE TIP_("Can't edit external library data")
@@ -2065,7 +2102,11 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr)
return NULL;
}
-/************************ Grease Pencil Modifier Template *************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Grease Pencil Modifier Template
+ * \{ */
static uiLayout *gpencil_draw_modifier(uiLayout *layout, Object *ob, GpencilModifierData *md)
{
@@ -2200,7 +2241,11 @@ uiLayout *uiTemplateGpencilModifier(uiLayout *layout, bContext *UNUSED(C), Point
return NULL;
}
-/************************ Shader FX Template *************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Grease Pencil Shader FX Template
+ * \{ */
static uiLayout *gpencil_draw_shaderfx(uiLayout *layout, Object *ob, ShaderFxData *md)
{
@@ -2318,7 +2363,11 @@ uiLayout *uiTemplateShaderFx(uiLayout *layout, bContext *UNUSED(C), PointerRNA *
return NULL;
}
-/************************ Redo Buttons Template *************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Redo Buttons Template
+ * \{ */
static void template_operator_redo_property_buts_draw(
const bContext *C, wmOperator *op, uiLayout *layout, int layout_flags, bool *r_has_advanced)
@@ -2384,7 +2433,11 @@ void uiTemplateOperatorRedoProperties(uiLayout *layout, const bContext *C)
}
}
-/************************ Constraint Template *************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Constraint Template
+ * \{ */
static void constraint_active_func(bContext *UNUSED(C), void *ob_v, void *con_v)
{
@@ -2600,7 +2653,11 @@ uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr)
return draw_constraint(layout, ob, con);
}
-/************************* Preview Template ***************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Preview Template
+ * \{ */
#include "DNA_light_types.h"
#include "DNA_material_types.h"
@@ -2862,7 +2919,11 @@ void uiTemplatePreview(uiLayout *layout,
}
}
-/********************** ColorRamp Template **************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ColorRamp Template
+ * \{ */
typedef struct RNAUpdateCb {
PointerRNA ptr;
@@ -3207,7 +3268,7 @@ static void colorband_buttons_layout(uiLayout *layout,
&coba->cur,
0.0,
(float)(MAX2(0, coba->tot - 1)),
- 0,
+ 1,
0,
TIP_("Choose active color stop"));
row = uiLayoutRow(split, false);
@@ -3237,7 +3298,7 @@ static void colorband_buttons_layout(uiLayout *layout,
&coba->cur,
0.0,
(float)(MAX2(0, coba->tot - 1)),
- 0,
+ 1,
0,
TIP_("Choose active color stop"));
row = uiLayoutRow(subsplit, false);
@@ -3293,7 +3354,12 @@ void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname
MEM_freeN(cb);
}
-/********************* Icon Template ************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Icon Template
+ * \{ */
+
/**
* \param icon_scale: Scale of the icon, 1x == button height.
*/
@@ -3320,7 +3386,12 @@ void uiTemplateIcon(uiLayout *layout, int icon_value, float icon_scale)
ui_def_but_icon(but, icon_value, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
}
-/********************* Icon viewer Template ************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Icon viewer Template
+ * \{ */
+
typedef struct IconViewMenuArgs {
PointerRNA ptr;
PropertyRNA *prop;
@@ -3480,7 +3551,11 @@ void uiTemplateIconView(uiLayout *layout,
}
}
-/********************* Histogram Template ************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Histogram Template
+ * \{ */
void uiTemplateHistogram(uiLayout *layout, PointerRNA *ptr, const char *propname)
{
@@ -3530,7 +3605,11 @@ void uiTemplateHistogram(uiLayout *layout, PointerRNA *ptr, const char *propname
"");
}
-/********************* Waveform Template ************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Waveform Template
+ * \{ */
void uiTemplateWaveform(uiLayout *layout, PointerRNA *ptr, const char *propname)
{
@@ -3592,7 +3671,11 @@ void uiTemplateWaveform(uiLayout *layout, PointerRNA *ptr, const char *propname)
"");
}
-/********************* Vectorscope Template ************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector-Scope Template
+ * \{ */
void uiTemplateVectorscope(uiLayout *layout, PointerRNA *ptr, const char *propname)
{
@@ -3654,7 +3737,11 @@ void uiTemplateVectorscope(uiLayout *layout, PointerRNA *ptr, const char *propna
"");
}
-/********************* CurveMapping Template ************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name CurveMapping Template
+ * \{ */
static void curvemap_buttons_zoom_in(bContext *C, void *cumap_v, void *UNUSED(arg))
{
@@ -3745,12 +3832,11 @@ static uiBlock *curvemap_clipping_func(bContext *C, ARegion *ar, void *cumap_v)
float width = 8 * UI_UNIT_X;
block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
-
- /* use this for a fake extra empty space around the buttons */
- uiDefBut(block, UI_BTYPE_LABEL, 0, "", -4, 16, width + 8, 6 * UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
+ UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_MOVEMOUSE_QUIT);
+ UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
bt = uiDefButBitI(block,
- UI_BTYPE_TOGGLE,
+ UI_BTYPE_CHECKBOX,
CUMA_DO_CLIP,
1,
IFACE_("Use Clipping"),
@@ -3770,7 +3856,7 @@ static uiBlock *curvemap_clipping_func(bContext *C, ARegion *ar, void *cumap_v)
uiDefButF(block,
UI_BTYPE_NUM,
0,
- IFACE_("Min X "),
+ IFACE_("Min X:"),
0,
4 * UI_UNIT_Y,
width,
@@ -3784,7 +3870,7 @@ static uiBlock *curvemap_clipping_func(bContext *C, ARegion *ar, void *cumap_v)
uiDefButF(block,
UI_BTYPE_NUM,
0,
- IFACE_("Min Y "),
+ IFACE_("Min Y:"),
0,
3 * UI_UNIT_Y,
width,
@@ -3798,7 +3884,7 @@ static uiBlock *curvemap_clipping_func(bContext *C, ARegion *ar, void *cumap_v)
uiDefButF(block,
UI_BTYPE_NUM,
0,
- IFACE_("Max X "),
+ IFACE_("Max X:"),
0,
2 * UI_UNIT_Y,
width,
@@ -3812,7 +3898,7 @@ static uiBlock *curvemap_clipping_func(bContext *C, ARegion *ar, void *cumap_v)
uiDefButF(block,
UI_BTYPE_NUM,
0,
- IFACE_("Max Y "),
+ IFACE_("Max Y:"),
0,
UI_UNIT_Y,
width,
@@ -3824,7 +3910,8 @@ static uiBlock *curvemap_clipping_func(bContext *C, ARegion *ar, void *cumap_v)
2,
"");
- UI_block_direction_set(block, UI_DIR_RIGHT);
+ UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
+ UI_block_direction_set(block, UI_DIR_DOWN);
return block;
}
@@ -4415,7 +4502,11 @@ void uiTemplateCurveMapping(uiLayout *layout,
MEM_freeN(cb);
}
-/********************* ColorPicker Template ************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ColorPicker Template
+ * \{ */
#define WHEEL_SIZE (5 * U.widget_unit)
@@ -4762,7 +4853,11 @@ void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, const char *propn
RNA_boolean_set(opptr, "use_accumulate", false);
}
-/********************* Layer Buttons Template ************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Layer Buttons Template
+ * \{ */
static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
{
@@ -4776,7 +4871,7 @@ static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
/* Normally clicking only selects one layer */
RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, cur, true);
- for (i = 0; i < tot; ++i) {
+ for (i = 0; i < tot; i++) {
if (i != cur) {
RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, i, false);
}
@@ -4867,7 +4962,12 @@ void uiTemplateLayers(uiLayout *layout,
}
}
-/************************* List Template **************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name List Template
+ * \{ */
+
static void uilist_draw_item_default(struct uiList *ui_list,
struct bContext *UNUSED(C),
struct uiLayout *layout,
@@ -5752,7 +5852,11 @@ void uiTemplateList(uiLayout *layout,
}
}
-/************************* Operator Search Template **************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Search Template
+ * \{ */
static void operator_call_cb(bContext *C, void *UNUSED(arg1), void *arg2)
{
@@ -5857,7 +5961,11 @@ void uiTemplateOperatorSearch(uiLayout *layout)
UI_but_func_operator_search(but);
}
-/************************* Operator Redo Properties Template **************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Redo Properties Template
+ * \{ */
#ifdef USE_OP_RESET_BUT
static void ui_layout_operator_buts__reset_cb(bContext *UNUSED(C),
@@ -5961,6 +6069,7 @@ eAutoPropButsReturn uiTemplateOperatorPropertyButs(const bContext *C,
RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
/* main draw call */
return_info = uiDefAutoButsRNA(
@@ -6033,7 +6142,11 @@ eAutoPropButsReturn uiTemplateOperatorPropertyButs(const bContext *C,
return return_info;
}
-/************************* Running Jobs Template **************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Running Jobs Template
+ * \{ */
#define B_STOPRENDER 1
#define B_STOPCAST 2
@@ -6308,7 +6421,11 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
}
}
-/************************* Reports for Last Operator Template **************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reports for Last Operator Template
+ * \{ */
void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
{
@@ -6444,7 +6561,11 @@ void uiTemplateInputStatus(uiLayout *layout, struct bContext *C)
}
}
-/********************************* Keymap *************************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Keymap Template
+ * \{ */
static void keymap_item_modified(bContext *UNUSED(C), void *kmi_p, void *UNUSED(unused))
{
@@ -6533,7 +6654,11 @@ void uiTemplateKeymapItemProperties(uiLayout *layout, PointerRNA *ptr)
}
}
-/********************************* Color management *************************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Management Template
+ * \{ */
void uiTemplateColorspaceSettings(uiLayout *layout, PointerRNA *ptr, const char *propname)
{
@@ -6593,7 +6718,11 @@ void uiTemplateColormanagedViewSettings(uiLayout *layout,
}
}
-/********************************* Component Menu *************************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Component Menu
+ * \{ */
typedef struct ComponentMenuArgs {
PointerRNA ptr;
@@ -6622,7 +6751,7 @@ static uiBlock *component_menu(bContext *C, ARegion *ar, void *args_v)
uiItemR(layout, &args->ptr, args->propname, UI_ITEM_R_EXPAND, "", ICON_NONE);
- UI_block_bounds_set_normal(block, 6);
+ UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
UI_block_direction_set(block, UI_DIR_DOWN);
return block;
@@ -6651,7 +6780,11 @@ void uiTemplateComponentMenu(uiLayout *layout,
UI_block_align_end(block);
}
-/************************* Node Socket Icon **************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Socket Icon Template
+ * \{ */
void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float *color)
{
@@ -6672,7 +6805,11 @@ void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float *color)
UI_block_align_end(block);
}
-/********************************* Cache File *********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cache File Template
+ * \{ */
void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname)
{
@@ -6752,7 +6889,11 @@ void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const c
#endif
}
-/******************************* Recent Files *******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Recent Files Template
+ * \{ */
int uiTemplateRecentFiles(uiLayout *layout, int rows)
{
@@ -6776,3 +6917,19 @@ int uiTemplateRecentFiles(uiLayout *layout, int rows)
return i;
}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name FileSelectParams Path Button Template
+ * \{ */
+
+void uiTemplateFileSelectPath(uiLayout *layout, bContext *C, FileSelectParams *params)
+{
+ bScreen *screen = CTX_wm_screen(C);
+ SpaceFile *sfile = CTX_wm_space_file(C);
+
+ ED_file_path_button(screen, sfile, params, uiLayoutGetBlock(layout));
+}
+
+/** \} */
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index d16986ede8f..9f1b11d1354 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -58,6 +58,10 @@
# include "WM_types.h"
#endif
+/* -------------------------------------------------------------------- */
+/** \name Local Enums/Defines
+ * \{ */
+
/* icons are 80% of height of button (16 pixels inside 20 height) */
#define ICON_SIZE_FROM_BUTRECT(rect) (0.8f * BLI_rcti_size_y(rect))
@@ -126,7 +130,66 @@ enum {
#define UI_BUT_UPDATE_DELAY ((void)0)
#define UI_BUT_UNDO ((void)0)
-/* ************** widget base functions ************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Color Utilities
+ * \{ */
+
+static void color_blend_v3_v3(uchar cp[3], const uchar cpstate[3], const float fac)
+{
+ if (fac != 0.0f) {
+ cp[0] = (int)((1.0f - fac) * cp[0] + fac * cpstate[0]);
+ cp[1] = (int)((1.0f - fac) * cp[1] + fac * cpstate[1]);
+ cp[2] = (int)((1.0f - fac) * cp[2] + fac * cpstate[2]);
+ }
+}
+
+static void color_blend_v4_v4v4(uchar r_col[4],
+ const uchar col1[4],
+ const uchar col2[4],
+ const float fac)
+{
+ const int faci = unit_float_to_uchar_clamp(fac);
+ const int facm = 255 - faci;
+
+ r_col[0] = (faci * col1[0] + facm * col2[0]) / 256;
+ r_col[1] = (faci * col1[1] + facm * col2[1]) / 256;
+ r_col[2] = (faci * col1[2] + facm * col2[2]) / 256;
+ r_col[3] = (faci * col1[3] + facm * col2[3]) / 256;
+}
+
+static void color_add_v3_i(uchar cp[3], int tint)
+{
+ cp[0] = clamp_i(cp[0] + tint, 0, 255);
+ cp[1] = clamp_i(cp[1] + tint, 0, 255);
+ cp[2] = clamp_i(cp[2] + tint, 0, 255);
+}
+
+static void color_ensure_contrast_v3(uchar cp[3], const uchar cp_other[3], int contrast)
+{
+ BLI_assert(contrast > 0);
+ const int item_value = rgb_to_grayscale_byte(cp);
+ const int inner_value = rgb_to_grayscale_byte(cp_other);
+ const int delta = item_value - inner_value;
+ if (delta >= 0) {
+ if (contrast > delta) {
+ color_add_v3_i(cp, contrast - delta);
+ }
+ }
+ else {
+ if (contrast > -delta) {
+ color_add_v3_i(cp, -contrast - delta);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Widget Base Type
+ * \{ */
+
/**
* - in: roundbox codes for corner types and radius
* - return: array of `[size][2][x, y]` points, the edges of the roundbox, + UV coords
@@ -193,7 +256,11 @@ typedef struct uiWidgetType {
} uiWidgetType;
-/* *********************** draw data ************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Shape Preset Data
+ * \{ */
static const float cornervec[WIDGET_CURVE_RESOLU][2] = {
{0.0, 0.0},
@@ -220,10 +287,6 @@ const float ui_pixel_jitter[UI_PIXEL_AA_JITTER][2] = {
#define WIDGET_AA_JITTER UI_PIXEL_AA_JITTER
#define jit ui_pixel_jitter
-/* -------------------------------------------------------------------- */
-/** \name Shape Preset Data
- * \{ */
-
static const float g_shape_preset_number_arrow_vert[3][2] = {
{-0.352077, 0.532607},
{-0.352077, -0.549313},
@@ -307,12 +370,14 @@ static const uint g_shape_preset_hold_action_face[2][3] = {{2, 0, 1}, {3, 5, 4}}
/** \} */
-/* **************** Batch creations ****************** */
-/**
+/* -------------------------------------------------------------------- */
+/** \name #GPUBatch Creation
+ *
* In order to speed up UI drawing we create some batches that are then
* modified by specialized shaders to draw certain elements really fast.
* TODO: find a better place. Maybe it's own file?
- */
+ *
+ * \{ */
/* offset in triavec[] in shader per type */
static const int tria_ofs[ROUNDBOX_TRIA_MAX] = {
@@ -402,7 +467,7 @@ static void roundbox_batch_add_tria(GPUVertBufRaw *vflag_step, int tria, uint32_
const int tria_num =
ELEM(tria, ROUNDBOX_TRIA_CHECK, ROUNDBOX_TRIA_HOLD_ACTION_ARROW, ROUNDBOX_TRIA_MENU) ? 1 : 2;
/* for each tria */
- for (int t = 0; t < tria_num; ++t) {
+ for (int t = 0; t < tria_num; t++) {
for (int j = 0; j < WIDGET_AA_JITTER; j++) {
/* restart */
set_roundbox_vertex_data(vflag_step, last_data);
@@ -596,7 +661,11 @@ GPUBatch *ui_batch_roundbox_shadow_get(void)
#undef EMBOSS
#undef NO_AA
-/* ************************************************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw Triangle Arrow
+ * \{ */
void UI_draw_anti_tria(
float x1, float y1, float x2, float y2, float x3, float y3, const float color[4])
@@ -696,6 +765,12 @@ static void widget_init(uiWidgetBase *wtb)
wtb->uniform_params.alpha_discard = 1.0f;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw Round Box
+ * \{ */
+
/* helper call, makes shadow rect, with 'sun' above menu, so only shadow to left/right/bottom */
/* return tot */
static int round_box_shadow_edges(
@@ -954,6 +1029,8 @@ static void round_box_edges(uiWidgetBase *wt, int roundboxalign, const rcti *rec
round_box__edges(wt, roundboxalign, rect, rad, rad - U.pixelsize);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Shape Preset Mini API
* \{ */
@@ -1075,7 +1152,7 @@ static void widget_draw_vertex_buffer(uint pos,
uint totvert)
{
immBegin(mode, totvert);
- for (int i = 0; i < totvert; ++i) {
+ for (int i = 0; i < totvert; i++) {
if (quads_col) {
immAttr4ubv(col, quads_col[i]);
}
@@ -1133,6 +1210,10 @@ static void shape_preset_trias_from_rect_checkmark(uiWidgetTrias *tria, const rc
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Widget Base Drawing
+ * \{ */
+
/* prepares shade colors */
static void shadecolors4(
uchar coltop[4], uchar coldown[4], const uchar *color, short shadetop, short shadedown)
@@ -1148,20 +1229,6 @@ static void shadecolors4(
coldown[3] = color[3];
}
-static void round_box_shade_col4_r(uchar r_col[4],
- const uchar col1[4],
- const uchar col2[4],
- const float fac)
-{
- const int faci = unit_float_to_uchar_clamp(fac);
- const int facm = 255 - faci;
-
- r_col[0] = (faci * col1[0] + facm * col2[0]) / 256;
- r_col[1] = (faci * col1[1] + facm * col2[1]) / 256;
- r_col[2] = (faci * col1[2] + facm * col2[2]) / 256;
- r_col[3] = (faci * col1[3] + facm * col2[3]) / 256;
-}
-
static void widget_verts_to_triangle_strip(uiWidgetBase *wtb,
const int totvert,
float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2])
@@ -1225,6 +1292,12 @@ static void widgetbase_set_uniform_colors_ubv(uiWidgetBase *wtb,
rgba_float_args_set_ch(wtb->uniform_params.color_tria, tria[0], tria[1], tria[2], tria[3]);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Widget Base Drawing #GPUBatch Cache
+ * \{ */
+
/* keep in sync with shader */
#define MAX_WIDGET_BASE_BATCH 6
#define MAX_WIDGET_PARAMETERS 11
@@ -1238,7 +1311,7 @@ static struct {
void UI_widgetbase_draw_cache_flush(void)
{
- float checker_params[3] = {
+ const float checker_params[3] = {
UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 8.0f};
if (g_widget_base_batch.count == 0) {
@@ -1321,7 +1394,7 @@ static void draw_widgetbase_batch(GPUBatch *batch, uiWidgetBase *wtb)
}
}
else {
- float checker_params[3] = {
+ const float checker_params[3] = {
UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 8.0f};
/* draw single */
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
@@ -1400,7 +1473,11 @@ static void widgetbase_draw(uiWidgetBase *wtb, const uiWidgetColors *wcol)
widgetbase_draw_ex(wtb, wcol, false);
}
-/* *********************** text/icon ************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Text/Icon Drawing
+ * \{ */
#define UI_TEXT_CLIP_MARGIN (0.25f * U.widget_unit / but->block->aspect)
@@ -2188,7 +2265,7 @@ static void widget_draw_text(const uiFontStyle *fstyle,
drawstr_right = strrchr(drawstr + but->ofs, ':');
if (drawstr_right) {
drawstr_right++;
- drawstr_left_len = (drawstr_right - drawstr);
+ drawstr_left_len = (drawstr_right - drawstr - 1);
while (*drawstr_right == ' ') {
drawstr_right++;
@@ -2294,13 +2371,29 @@ static BIFIconID widget_icon_id(uiBut *but)
}
}
+static void widget_draw_extra_icons(const uiWidgetColors *wcol,
+ uiBut *but,
+ rcti *rect,
+ float alpha)
+{
+ /* inverse order, from right to left. */
+ for (uiButExtraOpIcon *op_icon = but->extra_op_icons.last; op_icon; op_icon = op_icon->prev) {
+ rcti temp = *rect;
+
+ temp.xmin = temp.xmax - (BLI_rcti_size_y(rect) * 1.08f);
+
+ widget_draw_icon(but, op_icon->icon, alpha, &temp, wcol->text);
+
+ rect->xmax -= ICON_SIZE_FROM_BUTRECT(rect);
+ }
+}
+
/* draws text and icons for buttons */
static void widget_draw_text_icon(const uiFontStyle *fstyle,
const uiWidgetColors *wcol,
uiBut *but,
rcti *rect)
{
- const uiButExtraIconType extra_icon_type = ui_but_icon_extra_get(but);
const bool show_menu_icon = ui_but_draw_menu_icon(but);
float alpha = (float)wcol->text[3] / 255.0f;
char password_str[UI_MAX_DRAW_STR];
@@ -2422,23 +2515,7 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
}
/* extra icons, e.g. 'x' icon to clear text or icon for eyedropper */
- if (extra_icon_type != UI_BUT_ICONEXTRA_NONE) {
- rcti temp = *rect;
-
- temp.xmin = temp.xmax - (BLI_rcti_size_y(rect) * 1.08f);
-
- if (extra_icon_type == UI_BUT_ICONEXTRA_CLEAR) {
- widget_draw_icon(but, ICON_PANEL_CLOSE, alpha, &temp, wcol->text);
- }
- else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {
- widget_draw_icon(but, ICON_EYEDROPPER, alpha, &temp, wcol->text);
- }
- else {
- BLI_assert(0);
- }
-
- rect->xmax -= ICON_SIZE_FROM_BUTRECT(rect);
- }
+ widget_draw_extra_icons(wcol, but, rect, alpha);
/* clip but->drawstr to fit in available space */
if (but->editstr && but->pos >= 0) {
@@ -2471,18 +2548,13 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
#undef UI_TEXT_CLIP_MARGIN
-/* *********************** widget types ************************************* */
-
-/* ************ button callbacks, state ***************** */
+/** \} */
-static void widget_state_blend(uchar cp[3], const uchar cpstate[3], const float fac)
-{
- if (fac != 0.0f) {
- cp[0] = (int)((1.0f - fac) * cp[0] + fac * cpstate[0]);
- cp[1] = (int)((1.0f - fac) * cp[1] + fac * cpstate[1]);
- cp[2] = (int)((1.0f - fac) * cp[2] + fac * cpstate[2]);
- }
-}
+/* -------------------------------------------------------------------- */
+/** \name Widget State Management
+ *
+ * Adjust widget display based on animated, driven, overridden ... etc.
+ * \{ */
/* put all widget colors on half alpha, use local storage */
static void ui_widget_color_disabled(uiWidgetType *wt)
@@ -2501,31 +2573,6 @@ static void ui_widget_color_disabled(uiWidgetType *wt)
wt->wcol_theme = &wcol_theme_s;
}
-static void rgb_tint(uchar cp[3], int tint)
-{
- cp[0] = clamp_i(cp[0] + tint, 0, 255);
- cp[1] = clamp_i(cp[1] + tint, 0, 255);
- cp[2] = clamp_i(cp[2] + tint, 0, 255);
-}
-
-static void rgb_ensure_contrast(uchar cp[3], const uchar cp_other[3], int contrast)
-{
- BLI_assert(contrast > 0);
- const int item_value = rgb_to_grayscale_byte(cp);
- const int inner_value = rgb_to_grayscale_byte(cp_other);
- const int delta = item_value - inner_value;
- if (delta >= 0) {
- if (contrast > delta) {
- rgb_tint(cp, contrast - delta);
- }
- }
- else {
- if (contrast > -delta) {
- rgb_tint(cp, -contrast - delta);
- }
- }
-}
-
static void widget_active_color(uchar cp[3])
{
cp[0] = cp[0] >= 240 ? 255 : cp[0] + 15;
@@ -2577,7 +2624,7 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag)
if (state & UI_SELECT) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
if (color_blend != NULL) {
- widget_state_blend(wt->wcol.inner, color_blend, wcol_state->blend);
+ color_blend_v3_v3(wt->wcol.inner, color_blend, wcol_state->blend);
}
copy_v3_v3_uchar(wt->wcol.text, wt->wcol.text_sel);
@@ -2587,8 +2634,12 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag)
}
}
else {
+ if (state & UI_BUT_ACTIVE_DEFAULT) {
+ copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
+ copy_v4_v4_uchar(wt->wcol.text, wt->wcol.text_sel);
+ }
if (color_blend != NULL) {
- widget_state_blend(wt->wcol.inner, color_blend, wcol_state->blend);
+ color_blend_v3_v3(wt->wcol.inner, color_blend, wcol_state->blend);
}
if (state & UI_ACTIVE) { /* mouse over? */
@@ -2599,10 +2650,10 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag)
if (state & UI_BUT_REDALERT) {
uchar red[4] = {255, 0, 0};
if (wt->draw) {
- widget_state_blend(wt->wcol.inner, red, 0.4f);
+ color_blend_v3_v3(wt->wcol.inner, red, 0.4f);
}
else {
- widget_state_blend(wt->wcol.text, red, 0.4f);
+ color_blend_v3_v3(wt->wcol.text, red, 0.4f);
}
}
@@ -2610,15 +2661,21 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag)
/* the button isn't SELECT but we're editing this so draw with sel color */
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
- widget_state_blend(wt->wcol.text, wt->wcol.text_sel, 0.85f);
+ color_blend_v3_v3(wt->wcol.text, wt->wcol.text_sel, 0.85f);
}
if (state & UI_BUT_NODE_ACTIVE) {
uchar blue[4] = {86, 128, 194};
- widget_state_blend(wt->wcol.inner, blue, 0.3f);
+ color_blend_v3_v3(wt->wcol.inner, blue, 0.3f);
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Widget Types
+ * \{ */
+
/* sliders use special hack which sets 'item' as inner when drawing filling */
static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag)
{
@@ -2633,8 +2690,8 @@ static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag)
* De-saturate so the color of the slider doesn't conflict with the blend color,
* which can make the color hard to see when the slider is set to full (see T66102). */
wt->wcol.item[0] = wt->wcol.item[1] = wt->wcol.item[2] = rgb_to_grayscale_byte(wt->wcol.item);
- widget_state_blend(wt->wcol.item, color_blend, wcol_state->blend);
- rgb_ensure_contrast(wt->wcol.item, wt->wcol.inner, 30);
+ color_blend_v3_v3(wt->wcol.item, color_blend, wcol_state->blend);
+ color_ensure_contrast_v3(wt->wcol.item, wt->wcol.inner, 30);
}
if (state & UI_SELECT) {
@@ -2677,7 +2734,7 @@ static void widget_state_pie_menu_item(uiWidgetType *wt, int state, int UNUSED(d
/* active and disabled (not so common) */
if ((state & UI_BUT_DISABLED) && (state & UI_ACTIVE)) {
- widget_state_blend(wt->wcol.text, wt->wcol.text_sel, 0.5f);
+ color_blend_v3_v3(wt->wcol.text, wt->wcol.text_sel, 0.5f);
/* draw the backdrop at low alpha, helps navigating with keys
* when disabled items are active */
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.item);
@@ -2690,7 +2747,7 @@ static void widget_state_pie_menu_item(uiWidgetType *wt, int state, int UNUSED(d
}
else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
/* regular disabled */
- widget_state_blend(wt->wcol.text, wt->wcol.inner, 0.5f);
+ color_blend_v3_v3(wt->wcol.text, wt->wcol.inner, 0.5f);
}
if (state & UI_SELECT) {
@@ -2712,7 +2769,7 @@ static void widget_state_menu_item(uiWidgetType *wt, int state, int UNUSED(drawf
/* draw the backdrop at low alpha, helps navigating with keys
* when disabled items are active */
wt->wcol.text[3] = 128;
- widget_state_blend(wt->wcol.inner, wt->wcol.text, 0.5f);
+ color_blend_v3_v3(wt->wcol.inner, wt->wcol.text, 0.5f);
wt->wcol.inner[3] = 64;
}
else {
@@ -2722,7 +2779,7 @@ static void widget_state_menu_item(uiWidgetType *wt, int state, int UNUSED(drawf
}
else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
/* regular disabled */
- widget_state_blend(wt->wcol.text, wt->wcol.inner, 0.5f);
+ color_blend_v3_v3(wt->wcol.text, wt->wcol.inner, 0.5f);
}
if (state & UI_ACTIVE) {
@@ -2731,7 +2788,11 @@ static void widget_state_menu_item(uiWidgetType *wt, int state, int UNUSED(drawf
}
}
-/* ************ menu backdrop ************************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw Menu Backdrop
+ * \{ */
/* outside of rect, rad to left/bottom/right */
static void widget_softshadow(const rcti *rect, int roundboxalign, const float radin)
@@ -2982,7 +3043,11 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const
ui_hsv_cursor(xpos, ypos);
}
-/* ************ custom buttons, old stuff ************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw Custom Buttons
+ * \{ */
/* draws in resolution of 48x4 colors */
void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, const float alpha)
@@ -3268,25 +3333,11 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
ui_hsv_cursor(x, y);
}
-/* Generic round-box drawing. */
-static void ui_draw_roundbox(const rcti *rect, const float rad, const uiWidgetColors *wcol)
-{
- uiWidgetBase wtb;
- widget_init(&wtb);
- round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
- widgetbase_draw(&wtb, wcol);
-
- /* We are drawing on top of widget bases. Flush cache. */
- GPU_blend(true);
- UI_widgetbase_draw_cache_flush();
- GPU_blend(false);
-}
-
-/* ************ separator, for menus etc ***************** */
+/** Separator for menus. */
static void ui_draw_separator(const rcti *rect, const uiWidgetColors *wcol)
{
int y = rect->ymin + BLI_rcti_size_y(rect) / 2 - 1;
- uchar col[4] = {
+ const uchar col[4] = {
wcol->text[0],
wcol->text[1],
wcol->text[2],
@@ -3310,7 +3361,12 @@ static void ui_draw_separator(const rcti *rect, const uiWidgetColors *wcol)
immUnbindProgram();
}
-/* ************ button callbacks, draw ***************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Button Draw Callbacks
+ * \{ */
+
static void widget_numbut_draw(
uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, bool emboss)
{
@@ -4068,7 +4124,7 @@ static void widget_state_label(uiWidgetType *wt, int state, int drawflag)
if (state & UI_BUT_REDALERT) {
uchar red[4] = {255, 0, 0};
- widget_state_blend(wt->wcol.text, red, 0.4f);
+ color_blend_v3_v3(wt->wcol.text, red, 0.4f);
}
}
@@ -4465,7 +4521,7 @@ static int widget_roundbox_set(uiBut *but, rcti *rect)
}
/* align with open menu */
- if (but->active && (but->type != UI_BTYPE_POPOVER)) {
+ if (but->active && (but->type != UI_BTYPE_POPOVER) && !ui_but_menu_draw_as_popover(but)) {
int direction = ui_but_menu_direction(but);
if (direction == UI_DIR_UP) {
@@ -4497,10 +4553,6 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
const uiFontStyle *fstyle = &style->widget;
uiWidgetType *wt = NULL;
-#ifdef USE_UI_POPOVER_ONCE
- const rcti rect_orig = *rect;
-#endif
-
/* handle menus separately */
if (but->dt == UI_EMBOSS_PULLDOWN) {
switch (but->type) {
@@ -4786,6 +4838,14 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
ui_widget_color_disabled(wt);
}
+#ifdef USE_UI_POPOVER_ONCE
+ if (but->block->flag & UI_BLOCK_POPOVER_ONCE) {
+ if ((state & UI_ACTIVE) && ui_but_is_popover_once_compat(but)) {
+ state |= UI_BUT_ACTIVE_DEFAULT;
+ }
+ }
+#endif
+
wt->state(wt, state, drawflag);
if (wt->custom) {
wt->custom(but, &wt->wcol, rect, state, roundboxalign);
@@ -4798,42 +4858,10 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
GPU_blend(true);
}
- bool show_semi_highlight = false;
-
-#ifdef USE_UI_POPOVER_ONCE
- if (but->block->flag & UI_BLOCK_POPOVER_ONCE) {
- if ((state & UI_ACTIVE) && ui_but_is_popover_once_compat(but)) {
- show_semi_highlight = true;
- }
- }
-#endif
- if (but->flag & UI_BUT_ACTIVE_DEFAULT) {
- show_semi_highlight = true;
- }
-
- if (show_semi_highlight) {
- uiWidgetType wt_back = *wt;
- uiWidgetType *wt_temp = widget_type(UI_WTYPE_MENU_ITEM);
- wt_temp->state(wt_temp, state, drawflag);
- copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
- wt->wcol.inner[3] = 128;
- wt->wcol.roundness = 0.5f;
- ui_draw_roundbox(&rect_orig,
- 0.25f * min_ff(BLI_rcti_size_x(&rect_orig), BLI_rcti_size_y(&rect_orig)),
- &wt_temp->wcol);
- *wt = wt_back;
- }
-
wt->text(fstyle, &wt->wcol, but, rect);
if (disabled) {
GPU_blend(false);
}
-
- // if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
- // if (but->dt != UI_EMBOSS_PULLDOWN) {
- // widget_disabled(&disablerect);
- // }
- // }
}
}
@@ -4886,7 +4914,9 @@ static void ui_draw_popover_back_impl(const uiWidgetColors *wcol,
{
/* tsk, this isn't nice. */
const float unit_half = unit_size / 2;
- const float cent_x = mval_origin ? mval_origin[0] : BLI_rcti_cent_x(rect);
+ const float cent_x = mval_origin ?
+ CLAMPIS(mval_origin[0], rect->xmin + unit_size, rect->xmax - unit_size) :
+ BLI_rcti_cent_x(rect);
rect->ymax -= unit_half;
rect->ymin += unit_half;
@@ -4990,14 +5020,14 @@ static void draw_disk_shaded(float start,
if (shaded) {
fac = (y1 + radius_ext) * radius_ext_scale;
- round_box_shade_col4_r(r_col, col1, col2, fac);
+ color_blend_v4_v4v4(r_col, col1, col2, fac);
immAttr4ubv(col, r_col);
}
immVertex2f(pos, c * radius_int, s * radius_int);
if (shaded) {
fac = (y2 + radius_ext) * radius_ext_scale;
- round_box_shade_col4_r(r_col, col1, col2, fac);
+ color_blend_v4_v4v4(r_col, col1, col2, fac);
immAttr4ubv(col, r_col);
}
immVertex2f(pos, c * radius_ext, s * radius_ext);
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 7c5d5401d08..8a570933a33 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -779,6 +779,12 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_PATH_AFTER:
cp = ts->path_after;
break;
+ case TH_PATH_KEYFRAME_BEFORE:
+ cp = ts->path_keyframe_before;
+ break;
+ case TH_PATH_KEYFRAME_AFTER:
+ cp = ts->path_keyframe_after;
+ break;
case TH_CAMERA_PATH:
cp = ts->camera_path;
break;
@@ -905,6 +911,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_ICON_SHADING:
cp = btheme->tui.icon_shading;
break;
+ case TH_ICON_FOLDER:
+ cp = btheme->tui.icon_folder;
+ break;
case TH_ICON_FUND: {
/* Development fund icon color is not part of theme. */
static const uchar red[4] = {204, 48, 72, 255};
@@ -1391,8 +1400,9 @@ bool UI_GetIconThemeColor4ubv(int colorid, uchar col[4])
/* Always color development fund icon. */
}
else if (!((theme_spacetype == SPACE_OUTLINER && theme_regionid == RGN_TYPE_WINDOW) ||
- (theme_spacetype == SPACE_PROPERTIES && theme_regionid == RGN_TYPE_NAV_BAR))) {
- /* Only colored icons in outliner and popups, overall UI is intended
+ (theme_spacetype == SPACE_PROPERTIES && theme_regionid == RGN_TYPE_NAV_BAR) ||
+ (theme_spacetype == SPACE_FILE && theme_regionid == RGN_TYPE_WINDOW))) {
+ /* Only colored icons in specific places, overall UI is intended
* to stay monochrome and out of the way except a few places where it
* is important to communicate different data types. */
return false;
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index c760ddcca6f..b1a060089ee 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -61,7 +61,9 @@
static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mask_scrollers);
-/* *********************************************************************** */
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
BLI_INLINE int clamp_float_to_int(const float f)
{
@@ -94,6 +96,12 @@ BLI_INLINE void clamp_rctf_to_rcti(rcti *dst, const rctf *src)
/* XXX still unresolved: scrolls hide/unhide vs region mask handling */
/* XXX there's V2D_SCROLL_HORIZONTAL_HIDE and V2D_SCROLL_HORIZONTAL_FULLR ... */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Scroll & Mask Utilities
+ * \{ */
+
/**
* helper to allow scrollbars to dynamically hide
* - returns a copy of the scrollbar settings with the flags to display
@@ -219,7 +227,11 @@ static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scr
}
}
-/* Refresh and Validation */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View2D Refresh and Validation (Spatial)
+ * \{ */
/**
* Initialize all relevant View2D data (including view rects if first time)
@@ -1123,8 +1135,11 @@ void UI_view2d_zoom_cache_reset(void)
BLF_cache_clear();
}
-/* *********************************************************************** */
-/* View Matrix Setup */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View2D Matrix Setup
+ * \{ */
/* mapping function to ensure 'cur' draws extended over the area where sliders are */
static void view2d_map_cur_using_mask(const View2D *v2d, rctf *r_curmasked)
@@ -1245,8 +1260,11 @@ void UI_view2d_view_restore(const bContext *C)
// ED_region_pixelspace(CTX_wm_region(C));
}
-/* *********************************************************************** */
-/* Gridlines */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Grid-Line Drawing
+ * \{ */
/* Draw a constant grid in given 2d-region */
void UI_view2d_constant_grid_draw(View2D *v2d, float step)
@@ -1347,7 +1365,7 @@ void UI_view2d_multi_grid_draw(View2D *v2d, int colorid, float step, int level_s
immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
immBeginAtMost(GPU_PRIM_LINES, vertex_count);
- for (int level = 0; level < totlevels; ++level) {
+ for (int level = 0; level < totlevels; level++) {
UI_GetThemeColorShade3ubv(colorid, offset, grid_line_color);
int i = (int)(v2d->cur.xmin / lstep);
@@ -1356,7 +1374,7 @@ void UI_view2d_multi_grid_draw(View2D *v2d, int colorid, float step, int level_s
}
float start = i * lstep;
- for (; start < v2d->cur.xmax; start += lstep, ++i) {
+ for (; start < v2d->cur.xmax; start += lstep, i++) {
if (i == 0 || (level < totlevels - 1 && i % level_size == 0)) {
continue;
}
@@ -1373,7 +1391,7 @@ void UI_view2d_multi_grid_draw(View2D *v2d, int colorid, float step, int level_s
}
start = i * lstep;
- for (; start < v2d->cur.ymax; start += lstep, ++i) {
+ for (; start < v2d->cur.ymax; start += lstep, i++) {
if (i == 0 || (level < totlevels - 1 && i % level_size == 0)) {
continue;
}
@@ -1405,8 +1423,11 @@ void UI_view2d_multi_grid_draw(View2D *v2d, int colorid, float step, int level_s
immUnbindProgram();
}
-/* *********************************************************************** */
-/* Scrollers */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Scrollers
+ * \{ */
/**
* View2DScrollers is typedef'd in UI_view2d.h
@@ -1648,8 +1669,11 @@ void UI_view2d_scrollers_free(View2DScrollers *scrollers)
MEM_freeN(scrollers);
}
-/* *********************************************************************** */
-/* List View Utilities */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name List View Utilities
+ * \{ */
/**
* Get the 'cell' (row, column) that the given 2D-view coordinates
@@ -1693,8 +1717,11 @@ void UI_view2d_listview_view_to_cell(float columnwidth,
}
}
-/* *********************************************************************** */
-/* Coordinate Conversions */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Coordinate Conversions
+ * \{ */
float UI_view2d_region_to_view_x(const struct View2D *v2d, float x)
{
@@ -1872,8 +1899,11 @@ bool UI_view2d_view_to_region_rcti_clip(View2D *v2d, const rctf *rect_src, rcti
}
}
-/* *********************************************************************** */
-/* Utilities */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
/* View2D data by default resides in region, so get from region stored in context */
View2D *UI_view2d_fromcontext(const bContext *C)
@@ -2075,7 +2105,11 @@ char UI_view2d_rect_in_scrollers(const ARegion *ar, const View2D *v2d, const rct
return UI_view2d_rect_in_scrollers_ex(ar, v2d, rect, &scroll_dummy);
}
-/* ******************* view2d text drawing cache ******************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View2D Text Drawing Cache
+ * \{ */
typedef struct View2DString {
struct View2DString *next;
@@ -2205,4 +2239,4 @@ void UI_view2d_text_cache_draw(ARegion *ar)
}
}
-/* ******************************************************** */
+/** \} */
diff --git a/source/blender/editors/interface/view2d_gizmo_navigate.c b/source/blender/editors/interface/view2d_gizmo_navigate.c
index 9b15f2309a1..d0281ad1eef 100644
--- a/source/blender/editors/interface/view2d_gizmo_navigate.c
+++ b/source/blender/editors/interface/view2d_gizmo_navigate.c
@@ -227,13 +227,13 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
int icon_mini_slot = 0;
gz = navgroup->gz_array[GZ_INDEX_ZOOM];
- gz->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++);
- gz->matrix_basis[3][1] = co[1];
+ gz->matrix_basis[3][0] = co[0];
+ gz->matrix_basis[3][1] = co[1] - (icon_offset_mini * icon_mini_slot++);
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
gz = navgroup->gz_array[GZ_INDEX_MOVE];
- gz->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++);
- gz->matrix_basis[3][1] = co[1];
+ gz->matrix_basis[3][0] = co[0];
+ gz->matrix_basis[3][1] = co[1] - (icon_offset_mini * icon_mini_slot++);
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
}
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 032fb7e4cc2..5cf7cb4e7c4 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -256,13 +256,13 @@ static int view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
RNA_int_set(op->ptr, "deltay", 0);
if (v2d->keepofs & V2D_LOCKOFS_X) {
- WM_cursor_modal_set(window, BC_NS_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_NS_SCROLL);
}
else if (v2d->keepofs & V2D_LOCKOFS_Y) {
- WM_cursor_modal_set(window, BC_EW_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_EW_SCROLL);
}
else {
- WM_cursor_modal_set(window, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_NSEW_SCROLL);
}
/* add temp handler */
@@ -1113,13 +1113,13 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, const wmEvent *even
}
if (v2d->keepofs & V2D_LOCKOFS_X) {
- WM_cursor_modal_set(window, BC_NS_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_NS_SCROLL);
}
else if (v2d->keepofs & V2D_LOCKOFS_Y) {
- WM_cursor_modal_set(window, BC_EW_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_EW_SCROLL);
}
else {
- WM_cursor_modal_set(window, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_NSEW_SCROLL);
}
/* add temp handler */
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index 2f3e73f32d5..573dfcde88a 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -576,7 +576,7 @@ static int get_sequence_len(char *filename, int *ofs)
(*ofs) = frame_curr;
while (cache_frame && (cache_frame->framenr == frame_curr)) {
- ++frame_curr;
+ frame_curr++;
cache_frame = cache_frame->next;
}
@@ -604,6 +604,9 @@ static void ui_alembic_import_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemL(row, IFACE_("Options:"), ICON_NONE);
row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "relative_path", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "set_frame_range", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
@@ -691,7 +694,7 @@ void WM_OT_alembic_import(wmOperatorType *ot)
FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
FILE_BLENDER,
FILE_SAVE,
- WM_FILESEL_FILEPATH,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
diff --git a/source/blender/editors/lattice/editlattice_select.c b/source/blender/editors/lattice/editlattice_select.c
index 7e89ed9511f..837c5b1c6bd 100644
--- a/source/blender/editors/lattice/editlattice_select.c
+++ b/source/blender/editors/lattice/editlattice_select.c
@@ -89,8 +89,9 @@ bool ED_lattice_deselect_all_multi_ex(struct Base **bases, const uint bases_len)
bool ED_lattice_deselect_all_multi(struct bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &bases_len);
@@ -634,11 +635,12 @@ static BPoint *findnearestLattvert(ViewContext *vc, int sel, Base **r_base)
bool ED_lattice_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
BPoint *bp = NULL;
Base *basact = NULL;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
vc.mval[0] = mval[0];
vc.mval[1] = mval[1];
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index 683e6d8a2b0..4624611419e 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -230,7 +230,7 @@ static void setup_vertex_point(Mask *mask,
int point_index = reference_point - spline->points;
int delta = new_point == spline->points ? 1 : -1;
int i = 0;
- for (i = 0; i < spline->tot_point - 1; ++i) {
+ for (i = 0; i < spline->tot_point - 1; i++) {
MaskSplinePoint *current_point;
point_index += delta;
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index c00223a3c49..7247697dcb7 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -43,7 +43,6 @@
#include "BIF_glutil.h"
#include "GPU_immediate.h"
-#include "GPU_draw.h"
#include "GPU_shader.h"
#include "GPU_matrix.h"
#include "GPU_state.h"
@@ -391,7 +390,7 @@ static void mask_draw_array(unsigned int pos,
unsigned int vertex_len)
{
immBegin(prim_type, vertex_len);
- for (unsigned int i = 0; i < vertex_len; ++i) {
+ for (unsigned int i = 0; i < vertex_len; i++) {
immVertex2fv(pos, points[i]);
}
immEnd();
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index 9a779db4812..88da40b947f 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -43,6 +43,7 @@ set(SRC
editface.c
editmesh_add.c
editmesh_add_gizmo.c
+ editmesh_automerge.c
editmesh_bevel.c
editmesh_bisect.c
editmesh_extrude.c
@@ -54,6 +55,7 @@ set(SRC
editmesh_knife.c
editmesh_knife_project.c
editmesh_loopcut.c
+ editmesh_mask_extract.c
editmesh_path.c
editmesh_polybuild.c
editmesh_preselect_edgering.c
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 9a70b0a8d36..b7f506a8a41 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -46,8 +46,6 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "GPU_draw.h"
-
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
diff --git a/source/blender/editors/mesh/editmesh_add_gizmo.c b/source/blender/editors/mesh/editmesh_add_gizmo.c
index f6729fb56e1..66832ceba7f 100644
--- a/source/blender/editors/mesh/editmesh_add_gizmo.c
+++ b/source/blender/editors/mesh/editmesh_add_gizmo.c
@@ -78,7 +78,7 @@ static void calc_initial_placement_point_from_view(bContext *C,
float orient_matrix[3][3];
BKE_scene_cursor_to_mat4(&scene->cursor, cursor_matrix);
- float dots[3] = {
+ const float dots[3] = {
dot_v3v3(rv3d->viewinv[2], cursor_matrix[0]),
dot_v3v3(rv3d->viewinv[2], cursor_matrix[1]),
dot_v3v3(rv3d->viewinv[2], cursor_matrix[2]),
diff --git a/source/blender/editors/mesh/editmesh_automerge.c b/source/blender/editors/mesh/editmesh_automerge.c
new file mode 100644
index 00000000000..fb8ee85f9db
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_automerge.c
@@ -0,0 +1,160 @@
+/*
+ * 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 edmesh
+ *
+ * Utility functions for merging geometry once transform has finished:
+ *
+ * - #EDBM_automerge
+ * - #EDBM_automerge_and_split
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_editmesh.h"
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "ED_mesh.h"
+
+#include "tools/bmesh_intersect_edges.h"
+
+//#define DEBUG_TIME
+#ifdef DEBUG_TIME
+# include "PIL_time.h"
+#endif
+
+/* use bmesh operator flags for a few operators */
+#define BMO_ELE_TAG 1
+
+/* -------------------------------------------------------------------- */
+/** \name Auto-Merge Selection
+ *
+ * Used after transform operations.
+ * \{ */
+
+void EDBM_automerge(Object *obedit, bool update, const char hflag, const float dist)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ int totvert_prev = bm->totvert;
+
+ BMOperator findop, weldop;
+
+ /* Search for doubles among all vertices, but only merge non-VERT_KEEP
+ * vertices into VERT_KEEP vertices. */
+ BMO_op_initf(bm,
+ &findop,
+ BMO_FLAG_DEFAULTS,
+ "find_doubles verts=%av keep_verts=%Hv dist=%f",
+ hflag,
+ dist);
+
+ 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);
+
+ if ((totvert_prev != bm->totvert) && update) {
+ EDBM_update_generic(em, true, true);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Auto-Merge & Split Selection
+ *
+ * Used after transform operations.
+ * \{ */
+
+void EDBM_automerge_and_split(Object *obedit,
+ bool UNUSED(split_edges),
+ bool split_faces,
+ bool update,
+ const char hflag,
+ const float dist)
+{
+ bool ok = false;
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+
+#ifdef DEBUG_TIME
+ em->bm = BM_mesh_copy(bm);
+
+ double t1 = PIL_check_seconds_timer();
+ EDBM_automerge(obedit, false, hflag, dist);
+ t1 = PIL_check_seconds_timer() - t1;
+
+ BM_mesh_free(em->bm);
+ em->bm = bm;
+ double t2 = PIL_check_seconds_timer();
+#endif
+
+ BMOperator weldop;
+ BMOpSlot *slot_targetmap;
+
+ BMO_op_init(bm, &weldop, BMO_FLAG_DEFAULTS, "weld_verts");
+ slot_targetmap = BMO_slot_get(weldop.slots_in, "targetmap");
+
+ GHash *ghash_targetmap = BMO_SLOT_AS_GHASH(slot_targetmap);
+
+ ok = BM_mesh_intersect_edges(bm, hflag, dist, ghash_targetmap);
+
+ if (ok) {
+ BMO_op_exec(bm, &weldop);
+
+ BMEdge **edgenet = NULL;
+ int edgenet_alloc_len = 0;
+ if (split_faces) {
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, ghash_targetmap) {
+ BMVert *v = BLI_ghashIterator_getValue(&gh_iter);
+ // BLI_assert(BM_elem_flag_test(v, hflag) || hflag == BM_ELEM_TAG);
+ BM_vert_weld_linked_wire_edges_into_linked_faces(
+ bm, v, dist, &edgenet, &edgenet_alloc_len);
+ }
+ }
+
+ if (edgenet) {
+ MEM_freeN(edgenet);
+ }
+ }
+
+ BMO_op_finish(bm, &weldop);
+
+#ifdef DEBUG_TIME
+ t2 = PIL_check_seconds_timer() - t2;
+ printf("t1: %lf; t2: %lf; fac: %lf\n", t1, t2, t1 / t2);
+#endif
+
+ if (LIKELY(ok) && update) {
+ EDBM_update_generic(em, true, true);
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index b4ef2620895..7afd72f33c9 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -148,9 +148,10 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op)
BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%.1f%%", RNA_float_get(op->ptr, "offset_pct"));
}
else {
+ double offset_val = (double)RNA_float_get(op->ptr, "offset");
bUnit_AsString2(offset_str,
NUM_STR_REP_LEN,
- (double)RNA_float_get(op->ptr, "offset"),
+ offset_val * sce->unit.scale_length,
3,
B_UNIT_LENGTH,
&sce->unit,
diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c
index 283e147b77b..4a511bbb5a2 100644
--- a/source/blender/editors/mesh/editmesh_bisect.c
+++ b/source/blender/editors/mesh/editmesh_bisect.c
@@ -455,7 +455,7 @@ void MESH_OT_bisect(struct wmOperatorType *ot)
0.00001,
0.1);
- WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
+ WM_operator_properties_gesture_straightline(ot, WM_CURSOR_EDIT);
#ifdef USE_GIZMO
WM_gizmogrouptype_append(MESH_GGT_bisect);
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 5b16cfd00f5..c1c8a208471 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -145,10 +145,10 @@ static bool edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const ch
}
/* extrudes individual edges */
-static bool edbm_extrude_edges_indiv(BMEditMesh *em,
- wmOperator *op,
- const char hflag,
- const bool use_normal_flip)
+bool edbm_extrude_edges_indiv(BMEditMesh *em,
+ wmOperator *op,
+ const char hflag,
+ const bool use_normal_flip)
{
BMesh *bm = em->bm;
BMOperator bmop;
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index 370cc6a2a6d..ec740447f93 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -101,17 +101,19 @@ static int bm_face_isect_pair_swap(BMFace *f, void *UNUSED(user_data))
/**
* Use for intersect and boolean.
*/
-static void edbm_intersect_select(BMEditMesh *em)
+static void edbm_intersect_select(BMEditMesh *em, bool do_select)
{
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+ if (do_select) {
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
- if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
- BMIter iter;
- BMEdge *e;
+ if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
+ BMIter iter;
+ BMEdge *e;
- BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- BM_edge_select_set(em->bm, e, true);
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BM_edge_select_set(em->bm, e, true);
+ }
}
}
}
@@ -210,10 +212,9 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op)
em->bm, BM_elem_cb_check_hflag_enabled_simple(const BMFace *, BM_ELEM_SELECT));
}
- if (has_isect) {
- edbm_intersect_select(em);
- }
- else {
+ edbm_intersect_select(em, has_isect);
+
+ if (!has_isect) {
isect_len++;
}
}
@@ -317,10 +318,9 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op)
boolean_operation,
eps);
- if (has_isect) {
- edbm_intersect_select(em);
- }
- else {
+ edbm_intersect_select(em, has_isect);
+
+ if (!has_isect) {
isect_len++;
}
}
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 61f9dc43c0f..395c614f328 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -2777,7 +2777,7 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
op->flag |= OP_IS_MODAL_CURSOR_REGION;
/* add a modal handler for this operator - handles loop selection */
- WM_cursor_modal_set(CTX_wm_window(C), BC_KNIFECURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_KNIFE);
WM_event_add_modal_handler(C, op);
knifetool_update_mval_i(kcd, event->mval);
@@ -2804,8 +2804,8 @@ wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf)
static const EnumPropertyItem modal_items[] = {
{KNF_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
{KNF_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
- {KNF_MODAL_MIDPOINT_ON, "SNAP_MIDPOINTS_ON", 0, "Snap To Midpoints On", ""},
- {KNF_MODAL_MIDPOINT_OFF, "SNAP_MIDPOINTS_OFF", 0, "Snap To Midpoints Off", ""},
+ {KNF_MODAL_MIDPOINT_ON, "SNAP_MIDPOINTS_ON", 0, "Snap to Midpoints On", ""},
+ {KNF_MODAL_MIDPOINT_OFF, "SNAP_MIDPOINTS_OFF", 0, "Snap to Midpoints Off", ""},
{KNF_MODEL_IGNORE_SNAP_ON, "IGNORE_SNAP_ON", 0, "Ignore Snapping On", ""},
{KNF_MODEL_IGNORE_SNAP_OFF, "IGNORE_SNAP_OFF", 0, "Ignore Snapping Off", ""},
{KNF_MODAL_ANGLE_SNAP_TOGGLE, "ANGLE_SNAP_TOGGLE", 0, "Toggle Angle Snapping", ""},
diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c
index 3d34a4ad3b5..a709bd010aa 100644
--- a/source/blender/editors/mesh/editmesh_knife_project.c
+++ b/source/blender/editors/mesh/editmesh_knife_project.c
@@ -22,6 +22,7 @@
*/
#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "BLI_math.h"
@@ -142,10 +143,21 @@ static int knifeproject_exec(bContext *C, wmOperator *op)
/* select only tagged faces */
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
- /* not essential, but switch out of vertex mode since the
- * selected regions wont be nicely isolated after flushing.
- * note: call after de-select to avoid selection flushing */
- EDBM_selectmode_disable(scene, em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
+ CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
+ if (ob->type == OB_MESH) {
+ Mesh *me = (Mesh *)ob->data;
+ BMEditMesh *embm = me->edit_mesh;
+ if (embm) {
+ /* not essential, but switch out of vertex mode since the
+ * selected regions wont be nicely isolated after flushing.
+ * note: call after de-select to avoid selection flushing.
+ * note: do this on all participating meshes so this is in sync
+ * e.g. for later selection picking, see T68852.*/
+ EDBM_selectmode_disable(scene, embm, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
+ }
+ }
+ }
+ CTX_DATA_END;
BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index 2ddd654f824..3be94cf99c1 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -39,10 +39,6 @@
#include "BKE_unit.h"
#include "BKE_layer.h"
-#include "GPU_immediate.h"
-#include "GPU_matrix.h"
-#include "GPU_state.h"
-
#include "UI_interface.h"
#include "ED_screen.h"
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
new file mode 100644
index 00000000000..d066e9ecddc
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -0,0 +1,273 @@
+/*
+ * 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 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edmesh
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_editmesh.h"
+#include "BKE_layer.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_paint.h"
+#include "BKE_report.h"
+#include "BKE_shrinkwrap.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+#include "WM_types.h"
+#include "WM_api.h"
+
+#include "ED_mesh.h"
+#include "ED_screen.h"
+#include "ED_object.h"
+#include "ED_sculpt.h"
+#include "ED_view3d.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "mesh_intern.h" /* own include */
+
+static bool paint_mask_extract_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ if (ob->mode == OB_MODE_SCULPT) {
+ if (ob->sculpt->bm) {
+ CTX_wm_operator_poll_msg_set(C, "The mask can not be extracted with dyntopo activated.");
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+ return ED_operator_object_active_editable_mesh(C);
+}
+
+static int paint_mask_extract_exec(bContext *C, wmOperator *op)
+{
+ struct Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ Scene *scene = CTX_data_scene(C);
+
+ Mesh *mesh = ob->data;
+ Mesh *new_mesh = BKE_mesh_copy(bmain, mesh);
+
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(new_mesh);
+ BMesh *bm;
+ bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = true,
+ }));
+
+ BM_mesh_bm_from_me(bm,
+ new_mesh,
+ (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
+
+ BMEditMesh *em = BKE_editmesh_create(bm, false);
+ BMVert *v;
+ BMEdge *ed;
+ BMFace *f;
+ BMIter iter;
+ BMIter face_iter;
+
+ /* Delete all unmasked faces */
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+
+ float mask_threshold = RNA_float_get(op->ptr, "mask_threshold");
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ bool delete_face = false;
+ BM_ITER_ELEM (v, &face_iter, f, BM_VERTS_OF_FACE) {
+ float mask = BM_elem_float_data_get(&bm->vdata, v, CD_PAINT_MASK);
+ delete_face = mask < mask_threshold;
+ }
+ BM_elem_flag_set(f, BM_ELEM_TAG, delete_face);
+ }
+
+ BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_FACES);
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+
+ if (RNA_boolean_get(op->ptr, "add_boundary_loop")) {
+ BM_ITER_MESH (ed, &iter, bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_set(ed, BM_ELEM_TAG, BM_edge_is_boundary(ed));
+ }
+ edbm_extrude_edges_indiv(em, op, BM_ELEM_TAG, false);
+
+ int smooth_iterations = RNA_int_get(op->ptr, "smooth_iterations");
+ for (int repeat = 0; repeat < smooth_iterations; repeat++) {
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_elem_flag_set(v, BM_ELEM_TAG, !BM_vert_is_boundary(v));
+ }
+ for (int i = 0; i < 3; i++) {
+ if (!EDBM_op_callf(em,
+ op,
+ "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b "
+ "mirror_clip_z=%b "
+ "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b",
+ BM_ELEM_TAG,
+ 1.0,
+ false,
+ false,
+ false,
+ 0.1,
+ true,
+ true,
+ true)) {
+ continue;
+ }
+ }
+
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_elem_flag_set(v, BM_ELEM_TAG, BM_vert_is_boundary(v));
+ }
+ for (int i = 0; i < 1; i++) {
+ if (!EDBM_op_callf(em,
+ op,
+ "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b "
+ "mirror_clip_z=%b "
+ "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b",
+ BM_ELEM_TAG,
+ 0.5,
+ false,
+ false,
+ false,
+ 0.1,
+ true,
+ true,
+ true)) {
+ continue;
+ }
+ }
+ }
+ }
+
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+ BKE_editmesh_free_derivedmesh(em);
+
+ BKE_mesh_free(new_mesh);
+ new_mesh = BKE_mesh_from_bmesh_nomain(bm,
+ (&(struct BMeshToMeshParams){
+ .calc_object_remap = false,
+ }),
+ mesh);
+
+ BM_mesh_free(bm);
+
+ if (new_mesh->totvert == 0) {
+ BKE_mesh_free(new_mesh);
+ return OPERATOR_FINISHED;
+ }
+
+ ushort local_view_bits = 0;
+ if (v3d && v3d->localvd) {
+ local_view_bits = v3d->local_view_uuid;
+ }
+ Object *new_ob = ED_object_add_type(C, OB_MESH, NULL, ob->loc, ob->rot, false, local_view_bits);
+ BKE_mesh_nomain_to_mesh(new_mesh, new_ob->data, new_ob, &CD_MASK_EVERYTHING, true);
+
+ BKE_mesh_free(new_mesh);
+
+ if (RNA_boolean_get(op->ptr, "apply_shrinkwrap")) {
+ BKE_shrinkwrap_mesh_nearest_surface_deform(C, new_ob, ob);
+ }
+
+ if (RNA_boolean_get(op->ptr, "add_solidify")) {
+ ED_object_modifier_add(
+ op->reports, bmain, scene, new_ob, "mask_extract_solidify", eModifierType_Solidify);
+ SolidifyModifierData *sfmd = (SolidifyModifierData *)modifiers_findByName(
+ new_ob, "mask_extract_solidify");
+ if (sfmd) {
+ sfmd->offset = -0.05f;
+ }
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, new_ob);
+ BKE_mesh_batch_cache_dirty_tag(new_ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&new_ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, new_ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_paint_mask_extract(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Mask Extract";
+ ot->description = "Create a new mesh object from the current paint mask";
+ ot->idname = "MESH_OT_paint_mask_extract";
+
+ /* api callbacks */
+ ot->poll = paint_mask_extract_poll;
+ ot->invoke = WM_operator_props_popup_confirm;
+ ot->exec = paint_mask_extract_exec;
+
+ ot->flag = OPTYPE_REGISTER;
+
+ RNA_def_float(
+ ot->srna,
+ "mask_threshold",
+ 0.5f,
+ 0.0f,
+ 1.0f,
+ "Threshold",
+ "Minimum mask value to consider the vertex valid to extract a face from the original mesh",
+ 0.0f,
+ 1.0f);
+ RNA_def_boolean(ot->srna,
+ "add_boundary_loop",
+ true,
+ "Add Boundary Loop",
+ "Add an extra edge loop to better preserve the shape when applying a "
+ "subdivision surface modifier");
+ RNA_def_int(ot->srna,
+ "smooth_iterations",
+ 4,
+ 0,
+ INT_MAX,
+ "Smooth Iterations",
+ "Smooth iterations applied to the extracted mesh",
+ 0,
+ 20);
+ RNA_def_boolean(ot->srna,
+ "apply_shrinkwrap",
+ true,
+ "Project to Sculpt",
+ "Project the extracted mesh into the original sculpt");
+ RNA_def_boolean(ot->srna,
+ "add_solidify",
+ true,
+ "Extract as Solid",
+ "Extract the mask as a solid object with a solidify modifier");
+}
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index 6fd0ee83b6c..06c41b78c37 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -239,8 +239,7 @@ static void mouse_mesh_shortest_path_vert(Scene *UNUSED(scene),
}
} while ((node = node->next));
- /* We need to start as if just *after* a 'skip' block... */
- int depth = op_params->interval_params.skip;
+ int depth = -1;
node = path;
do {
if ((is_path_ordered == false) ||
@@ -430,8 +429,7 @@ static void mouse_mesh_shortest_path_edge(Scene *scene,
}
} while ((node = node->next));
- /* We need to start as if just *after* a 'skip' block... */
- int depth = op_params->interval_params.skip;
+ int depth = -1;
node = path;
do {
if ((is_path_ordered == false) ||
@@ -561,8 +559,7 @@ static void mouse_mesh_shortest_path_face(Scene *UNUSED(scene),
}
} while ((node = node->next));
- /* We need to start as if just *after* a 'skip' block... */
- int depth = op_params->interval_params.skip;
+ int depth = -1;
node = path;
do {
if ((is_path_ordered == false) ||
diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c
index 088d1672cc9..21c850160dd 100644
--- a/source/blender/editors/mesh/editmesh_polybuild.c
+++ b/source/blender/editors/mesh/editmesh_polybuild.c
@@ -122,15 +122,160 @@ static bool edbm_preselect_or_active_init_viewcontext(bContext *C,
return ok;
}
+static int edbm_polybuild_transform_at_cursor_invoke(bContext *C,
+ wmOperator *UNUSED(op),
+ const wmEvent *UNUSED(event))
+{
+ ViewContext vc;
+ Base *basact = NULL;
+ BMElem *ele_act = NULL;
+ edbm_preselect_or_active_init_viewcontext(C, &vc, &basact, &ele_act);
+ BMEditMesh *em = vc.em;
+ BMesh *bm = em->bm;
+
+ invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
+ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
+
+ if (!ele_act) {
+ return OPERATOR_CANCELLED;
+ }
+
+ edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX);
+
+ edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
+
+ if (ele_act->head.htype == BM_VERT) {
+ BM_vert_select_set(bm, (BMVert *)ele_act, true);
+ }
+ if (ele_act->head.htype == BM_EDGE) {
+ BM_edge_select_set(bm, (BMEdge *)ele_act, true);
+ }
+ if (ele_act->head.htype == BM_FACE) {
+ BM_face_select_set(bm, (BMFace *)ele_act, true);
+ }
+
+ EDBM_mesh_normals_update(em);
+ EDBM_update_generic(em, true, true);
+ if (basact != NULL) {
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
+ }
+ }
+ BM_select_history_store(bm, ele_act);
+ WM_event_add_mousemove(C);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_polybuild_transform_at_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Poly Build Transform at Cursor";
+ ot->idname = "MESH_OT_polybuild_transform_at_cursor";
+
+ /* api callbacks */
+ ot->invoke = edbm_polybuild_transform_at_cursor_invoke;
+ ot->poll = EDBM_view3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* to give to transform */
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
+}
+
+static int edbm_polybuild_delete_at_cursor_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ bool changed = false;
+
+ ViewContext vc;
+ Base *basact = NULL;
+ BMElem *ele_act = NULL;
+ edbm_preselect_or_active_init_viewcontext(C, &vc, &basact, &ele_act);
+ BMEditMesh *em = vc.em;
+ BMesh *bm = em->bm;
+
+ invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
+ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
+
+ if (!ele_act) {
+ return OPERATOR_CANCELLED;
+ }
+
+ edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX);
+
+ if (ele_act->head.htype == BM_FACE) {
+ BMFace *f_act = (BMFace *)ele_act;
+ EDBM_flag_disable_all(em, BM_ELEM_TAG);
+ BM_elem_flag_enable(f_act, BM_ELEM_TAG);
+ if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_TAG, DEL_FACES)) {
+ return OPERATOR_CANCELLED;
+ }
+ changed = true;
+ }
+ if (ele_act->head.htype == BM_VERT) {
+ BMVert *v_act = (BMVert *)ele_act;
+ if (BM_vert_is_edge_pair(v_act)) {
+ BM_edge_collapse(bm, v_act->e, v_act, true, true);
+ changed = true;
+ }
+ else {
+ EDBM_flag_disable_all(em, BM_ELEM_TAG);
+ BM_elem_flag_enable(v_act, BM_ELEM_TAG);
+
+ if (!EDBM_op_callf(em,
+ op,
+ "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
+ BM_ELEM_TAG,
+ false,
+ false)) {
+ return OPERATOR_CANCELLED;
+ }
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ EDBM_mesh_normals_update(em);
+ EDBM_update_generic(em, true, true);
+ if (basact != NULL) {
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
+ }
+ }
+ WM_event_add_mousemove(C);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void MESH_OT_polybuild_delete_at_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Poly Build Delete at Cursor";
+ ot->idname = "MESH_OT_polybuild_delete_at_cursor";
+
+ /* api callbacks */
+ ot->invoke = edbm_polybuild_delete_at_cursor_invoke;
+ ot->poll = EDBM_view3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* to give to transform */
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Face at Cursor
* \{ */
-static int edbm_polybuild_face_at_cursor_invoke(bContext *C,
- wmOperator *UNUSED(op),
- const wmEvent *event)
+static int edbm_polybuild_face_at_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
float center[3];
bool changed = false;
@@ -168,20 +313,27 @@ static int edbm_polybuild_face_at_cursor_invoke(bContext *C,
mul_m4_v3(vc.obedit->obmat, center);
ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
mul_m4_v3(vc.obedit->imat, center);
-
- BMVert *v_tri[3];
- v_tri[0] = e_act->v1;
- v_tri[1] = e_act->v2;
- v_tri[2] = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
- if (e_act->l && e_act->l->v == v_tri[0]) {
- SWAP(BMVert *, v_tri[0], v_tri[1]);
+ if (f_reference->len == 3 && RNA_boolean_get(op->ptr, "create_quads")) {
+ const float fac = line_point_factor_v3(center, e_act->v1->co, e_act->v2->co);
+ BMVert *v_new = BM_edge_split(bm, e_act, e_act->v1, NULL, CLAMPIS(fac, 0.0f, 1.0f));
+ copy_v3_v3(v_new->co, center);
+ edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
+ BM_vert_select_set(bm, v_new, true);
+ BM_select_history_store(bm, v_new);
+ }
+ else {
+ BMVert *v_tri[3];
+ v_tri[0] = e_act->v1;
+ v_tri[1] = e_act->v2;
+ v_tri[2] = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
+ if (e_act->l && e_act->l->v == v_tri[0]) {
+ SWAP(BMVert *, v_tri[0], v_tri[1]);
+ }
+ BM_face_create_verts(bm, v_tri, 3, f_reference, BM_CREATE_NOP, true);
+ edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
+ BM_vert_select_set(bm, v_tri[2], true);
+ BM_select_history_store(bm, v_tri[2]);
}
- // BMFace *f_new =
- BM_face_create_verts(bm, v_tri, 3, f_reference, BM_CREATE_NOP, true);
-
- edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
- BM_vert_select_set(bm, v_tri[2], true);
- BM_select_history_store(bm, v_tri[2]);
changed = true;
}
else if (ele_act->head.htype == BM_VERT) {
@@ -281,6 +433,11 @@ void MESH_OT_polybuild_face_at_cursor(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ RNA_def_boolean(ot->srna,
+ "create_quads",
+ true,
+ "Create quads",
+ "Automatically split edges in triangles to maintain quad topology");
/* to give to transform */
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
}
diff --git a/source/blender/editors/mesh/editmesh_preselect_elem.c b/source/blender/editors/mesh/editmesh_preselect_elem.c
index a3e684a5493..05c4da68355 100644
--- a/source/blender/editors/mesh/editmesh_preselect_elem.c
+++ b/source/blender/editors/mesh/editmesh_preselect_elem.c
@@ -75,20 +75,49 @@ struct EditMesh_PreSelElem {
float (*verts)[3];
int verts_len;
+
+ float (*preview_tris)[3][3];
+ int preview_tris_len;
+ float (*preview_lines)[2][3];
+ int preview_lines_len;
+
+ eEditMesh_PreSelPreviewAction preview_action;
};
+void EDBM_preselect_action_set(struct EditMesh_PreSelElem *psel,
+ eEditMesh_PreSelPreviewAction action)
+{
+ psel->preview_action = action;
+}
+
+eEditMesh_PreSelPreviewAction EDBM_preselect_action_get(struct EditMesh_PreSelElem *psel)
+{
+ return psel->preview_action;
+}
+
struct EditMesh_PreSelElem *EDBM_preselect_elem_create(void)
{
struct EditMesh_PreSelElem *psel = MEM_callocN(sizeof(*psel), __func__);
+ psel->preview_action = PRESELECT_ACTION_TRANSFORM;
return psel;
}
void EDBM_preselect_elem_destroy(struct EditMesh_PreSelElem *psel)
{
EDBM_preselect_elem_clear(psel);
+ EDBM_preselect_preview_clear(psel);
MEM_freeN(psel);
}
+void EDBM_preselect_preview_clear(struct EditMesh_PreSelElem *psel)
+{
+ MEM_SAFE_FREE(psel->preview_tris);
+ psel->preview_tris_len = 0;
+
+ MEM_SAFE_FREE(psel->preview_lines);
+ psel->preview_lines_len = 0;
+}
+
void EDBM_preselect_elem_clear(struct EditMesh_PreSelElem *psel)
{
MEM_SAFE_FREE(psel->edges);
@@ -112,9 +141,42 @@ void EDBM_preselect_elem_draw(struct EditMesh_PreSelElem *psel, const float matr
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- immUniformColor3ub(255, 0, 255);
+
+ immUniformColor4ub(141, 171, 186, 100);
+ if (psel->preview_action != PRESELECT_ACTION_TRANSFORM) {
+ if (psel->preview_tris_len > 0) {
+ immBegin(GPU_PRIM_TRIS, psel->preview_tris_len * 3);
+
+ for (int i = 0; i < psel->preview_tris_len; i++) {
+ immVertex3fv(pos, psel->preview_tris[i][0]);
+ immVertex3fv(pos, psel->preview_tris[i][1]);
+ immVertex3fv(pos, psel->preview_tris[i][2]);
+ }
+ immEnd();
+ }
+
+ if (psel->preview_lines_len > 0) {
+
+ immUniformColor4ub(3, 161, 252, 200);
+ GPU_line_width(2.0f);
+ immBegin(GPU_PRIM_LINES, psel->preview_lines_len * 2);
+ for (int i = 0; i < psel->preview_lines_len; i++) {
+ immVertex3fv(pos, psel->preview_lines[i][0]);
+ immVertex3fv(pos, psel->preview_lines[i][1]);
+ }
+ immEnd();
+ }
+ }
+
+ if (psel->preview_action == PRESELECT_ACTION_DELETE) {
+ immUniformColor4ub(252, 49, 10, 200);
+ }
+ else {
+ immUniformColor4ub(3, 161, 252, 200);
+ }
if (psel->edges_len > 0) {
+ GPU_line_width(3.0f);
immBegin(GPU_PRIM_LINES, psel->edges_len * 2);
for (int i = 0; i < psel->edges_len; i++) {
@@ -126,7 +188,7 @@ void EDBM_preselect_elem_draw(struct EditMesh_PreSelElem *psel, const float matr
}
if (psel->verts_len > 0) {
- GPU_point_size(3.0f);
+ GPU_point_size(4.0f);
immBegin(GPU_PRIM_POINTS, psel->verts_len);
@@ -167,6 +229,122 @@ static void view3d_preselect_mesh_elem_update_from_edge(struct EditMesh_PreSelEl
psel->edges_len = 1;
}
+static void view3d_preselect_update_preview_triangle_from_vert(struct EditMesh_PreSelElem *psel,
+ ViewContext *vc,
+ BMesh *UNUSED(bm),
+ BMVert *eed,
+ const int mval[2])
+{
+ BMVert *v_act = eed;
+ BMEdge *e_pair[2] = {NULL};
+ float center[3];
+
+ if (v_act->e != NULL) {
+ for (uint allow_wire = 0; allow_wire < 2 && (e_pair[1] == NULL); allow_wire++) {
+ int i = 0;
+ BMEdge *e_iter = v_act->e;
+ do {
+ if ((BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == false) &&
+ (allow_wire ? BM_edge_is_wire(e_iter) : BM_edge_is_boundary(e_iter))) {
+ if (i == 2) {
+ e_pair[0] = e_pair[1] = NULL;
+ break;
+ }
+ e_pair[i++] = e_iter;
+ }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v_act)) != v_act->e);
+ }
+ }
+
+ if (e_pair[1] != NULL) {
+ mul_v3_m4v3(center, vc->obedit->obmat, v_act->co);
+ ED_view3d_win_to_3d_int(vc->v3d, vc->ar, center, mval, center);
+ mul_m4_v3(vc->obedit->imat, center);
+
+ psel->preview_tris = MEM_mallocN(sizeof(*psel->preview_tris) * 2, __func__);
+ psel->preview_lines = MEM_mallocN(sizeof(*psel->preview_lines) * 4, __func__);
+
+ copy_v3_v3(psel->preview_tris[0][0], e_pair[0]->v1->co);
+ copy_v3_v3(psel->preview_tris[0][1], e_pair[0]->v2->co);
+ copy_v3_v3(psel->preview_tris[0][2], center);
+
+ copy_v3_v3(psel->preview_tris[1][0], e_pair[1]->v1->co);
+ copy_v3_v3(psel->preview_tris[1][1], e_pair[1]->v2->co);
+ copy_v3_v3(psel->preview_tris[1][2], center);
+
+ copy_v3_v3(psel->preview_lines[0][0], e_pair[0]->v1->co);
+ copy_v3_v3(psel->preview_lines[0][1], e_pair[0]->v2->co);
+
+ copy_v3_v3(psel->preview_lines[1][0], e_pair[1]->v1->co);
+ copy_v3_v3(psel->preview_lines[1][1], e_pair[1]->v2->co);
+
+ copy_v3_v3(psel->preview_lines[2][0], center);
+ if (e_pair[0]->v1 == v_act) {
+ copy_v3_v3(psel->preview_lines[2][1], e_pair[0]->v2->co);
+ }
+ else {
+ copy_v3_v3(psel->preview_lines[2][1], e_pair[0]->v1->co);
+ }
+
+ copy_v3_v3(psel->preview_lines[3][0], center);
+ if (e_pair[1]->v1 == v_act) {
+ copy_v3_v3(psel->preview_lines[3][1], e_pair[1]->v2->co);
+ }
+ else {
+ copy_v3_v3(psel->preview_lines[3][1], e_pair[1]->v1->co);
+ }
+ psel->preview_tris_len = 2;
+ psel->preview_lines_len = 4;
+ }
+}
+
+static void view3d_preselect_update_preview_triangle_from_face(struct EditMesh_PreSelElem *psel,
+ ViewContext *UNUSED(vc),
+ BMesh *UNUSED(bm),
+ BMFace *efa,
+ const int UNUSED(mval[2]))
+{
+ float(*preview_lines)[2][3] = MEM_mallocN(sizeof(*psel->edges) * efa->len, __func__);
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ int i = 0;
+ do {
+ vcos_get_pair(&l_iter->e->v1, preview_lines[i++], NULL);
+ } while ((l_iter = l_iter->next) != l_first);
+ psel->preview_lines = preview_lines;
+ psel->preview_lines_len = efa->len;
+}
+
+static void view3d_preselect_update_preview_triangle_from_edge(struct EditMesh_PreSelElem *psel,
+ ViewContext *vc,
+ BMesh *UNUSED(bm),
+ BMEdge *eed,
+ const int mval[2])
+{
+ float center[3];
+ psel->preview_tris = MEM_mallocN(sizeof(*psel->preview_tris), __func__);
+ psel->preview_lines = MEM_mallocN(sizeof(*psel->preview_lines) * 3, __func__);
+ mid_v3_v3v3(center, eed->v1->co, eed->v2->co);
+ mul_m4_v3(vc->obedit->obmat, center);
+ ED_view3d_win_to_3d_int(vc->v3d, vc->ar, center, mval, center);
+ mul_m4_v3(vc->obedit->imat, center);
+
+ copy_v3_v3(psel->preview_tris[0][0], eed->v1->co);
+ copy_v3_v3(psel->preview_tris[0][1], eed->v2->co);
+ copy_v3_v3(psel->preview_tris[0][2], center);
+
+ copy_v3_v3(psel->preview_lines[0][0], eed->v1->co);
+ copy_v3_v3(psel->preview_lines[0][1], eed->v2->co);
+
+ copy_v3_v3(psel->preview_lines[1][0], eed->v2->co);
+ copy_v3_v3(psel->preview_lines[1][1], center);
+
+ copy_v3_v3(psel->preview_lines[2][0], center);
+ copy_v3_v3(psel->preview_lines[2][1], eed->v1->co);
+ psel->preview_tris_len = 1;
+ psel->preview_lines_len = 3;
+}
+
static void view3d_preselect_mesh_elem_update_from_face(struct EditMesh_PreSelElem *psel,
BMesh *UNUSED(bm),
BMFace *efa,
@@ -209,4 +387,28 @@ void EDBM_preselect_elem_update_from_single(struct EditMesh_PreSelElem *psel,
}
}
+void EDBM_preselect_elem_update_preview(struct EditMesh_PreSelElem *psel,
+ struct ViewContext *vc,
+ struct BMesh *bm,
+ struct BMElem *ele,
+ const int mval[2])
+{
+ EDBM_preselect_preview_clear(psel);
+
+ switch (ele->head.htype) {
+ case BM_VERT:
+ if (EDBM_preselect_action_get(psel) == PRESELECT_ACTION_CREATE) {
+ view3d_preselect_update_preview_triangle_from_vert(psel, vc, bm, (BMVert *)ele, mval);
+ }
+ break;
+ case BM_EDGE:
+ view3d_preselect_update_preview_triangle_from_edge(psel, vc, bm, (BMEdge *)ele, mval);
+ break;
+ case BM_FACE:
+ view3d_preselect_update_preview_triangle_from_face(psel, vc, bm, (BMFace *)ele, mval);
+ break;
+ default:
+ BLI_assert(0);
+ }
+}
/** \} */
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 94ffd9a34d6..3e59a884696 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -24,7 +24,6 @@
#include "MEM_guardedalloc.h"
#include "BLI_bitmap.h"
-#include "BLI_bitmap_draw_2d.h"
#include "BLI_listbase.h"
#include "BLI_linklist.h"
#include "BLI_linklist_stack.h"
@@ -32,16 +31,14 @@
#include "BLI_math_bits.h"
#include "BLI_rand.h"
#include "BLI_array.h"
+#include "BLI_heap.h"
+#include "BLI_utildefines_stack.h"
#include "BKE_context.h"
#include "BKE_report.h"
-#include "BKE_paint.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
-#include "IMB_imbuf_types.h"
-#include "IMB_imbuf.h"
-
#include "WM_api.h"
#include "WM_types.h"
@@ -67,7 +64,6 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
-#include "DRW_engine.h"
#include "DRW_select_buffer.h"
#include "mesh_intern.h" /* own include */
@@ -172,30 +168,6 @@ void EDBM_select_mirrored(
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Select Auto-Merge
- *
- * Used after transform operations.
- * \{ */
-
-void EDBM_automerge(Scene *scene, Object *obedit, bool update, const char hflag)
-{
- bool ok;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- ok = BMO_op_callf(em->bm,
- BMO_FLAG_DEFAULTS,
- "automerge verts=%hv dist=%f",
- hflag,
- scene->toolsettings->doublimit);
-
- if (LIKELY(ok) && update) {
- EDBM_update_generic(em, true, true);
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Back-Buffer OpenGL Selection
* \{ */
@@ -1031,8 +1003,11 @@ bool EDBM_unified_findnearest(ViewContext *vc,
bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
Base **bases,
const uint bases_len,
- bool use_boundary,
- int *r_base_index,
+ bool use_boundary_vertices,
+ bool use_boundary_edges,
+ int *r_base_index_vert,
+ int *r_base_index_edge,
+ int *r_base_index_face,
struct BMVert **r_eve,
struct BMEdge **r_eed,
struct BMFace **r_efa)
@@ -1045,10 +1020,30 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
uint base_index;
BMElem *ele;
} best = {0, NULL};
+ /* Currently unused, keep since we may want to pick the best. */
+ UNUSED_VARS(best);
+
+ struct {
+ uint base_index;
+ BMElem *ele;
+ } best_vert = {0, NULL};
+
+ struct {
+ uint base_index;
+ BMElem *ele;
+ } best_edge = {0, NULL};
+
+ struct {
+ uint base_index;
+ BMElem *ele;
+ } best_face = {0, NULL};
if (ED_view3d_win_to_ray_clipped(
vc->depsgraph, vc->ar, vc->v3d, mval_fl, ray_origin, ray_direction, true)) {
float dist_sq_best = FLT_MAX;
+ float dist_sq_best_vert = FLT_MAX;
+ float dist_sq_best_edge = FLT_MAX;
+ float dist_sq_best_face = FLT_MAX;
const bool use_vert = (r_eve != NULL);
const bool use_edge = (r_eed != NULL);
@@ -1078,18 +1073,23 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
BM_mesh_elem_index_ensure(bm, BM_VERT);
}
- if (use_boundary && (use_vert || use_edge)) {
+ if ((use_boundary_vertices || use_boundary_edges) && (use_vert || use_edge)) {
BMEdge *e;
BMIter eiter;
BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
if ((BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) && (BM_edge_is_boundary(e))) {
- if (use_vert) {
+ if (use_vert && use_boundary_vertices) {
for (uint j = 0; j < 2; j++) {
BMVert *v = *((&e->v1) + j);
float point[3];
mul_v3_m4v3(point, obedit->obmat, coords ? coords[BM_elem_index_get(v)] : v->co);
const float dist_sq_test = dist_squared_to_ray_v3_normalized(
ray_origin, ray_direction, point);
+ if (dist_sq_test < dist_sq_best_vert) {
+ dist_sq_best_vert = dist_sq_test;
+ best_vert.base_index = base_index;
+ best_vert.ele = (BMElem *)v;
+ }
if (dist_sq_test < dist_sq_best) {
dist_sq_best = dist_sq_test;
best.base_index = base_index;
@@ -1098,7 +1098,7 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
}
}
- if (use_edge) {
+ if (use_edge && use_boundary_edges) {
float point[3];
#if 0
const float dist_sq_test = dist_squared_ray_to_seg_v3(
@@ -1114,6 +1114,11 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
mul_m4_v3(obedit->obmat, point);
const float dist_sq_test = dist_squared_to_ray_v3_normalized(
ray_origin, ray_direction, point);
+ if (dist_sq_test < dist_sq_best_edge) {
+ dist_sq_best_edge = dist_sq_test;
+ best_edge.base_index = base_index;
+ best_edge.ele = (BMElem *)e;
+ }
if (dist_sq_test < dist_sq_best) {
dist_sq_best = dist_sq_test;
best.base_index = base_index;
@@ -1124,46 +1129,55 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
}
}
}
- else {
- /* Non boundary case. */
- if (use_vert) {
- BMVert *v;
- BMIter viter;
- BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == false) {
- float point[3];
- mul_v3_m4v3(point, obedit->obmat, v->co);
- const float dist_sq_test = dist_squared_to_ray_v3_normalized(
- ray_origin, ray_direction, v->co);
- if (dist_sq_test < dist_sq_best) {
- dist_sq_best = dist_sq_test;
- best.base_index = base_index;
- best.ele = (BMElem *)v;
- }
+ /* Non boundary case. */
+ if (use_vert && !use_boundary_vertices) {
+ BMVert *v;
+ BMIter viter;
+ BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == false) {
+ float point[3];
+ mul_v3_m4v3(point, obedit->obmat, coords ? coords[BM_elem_index_get(v)] : v->co);
+ const float dist_sq_test = dist_squared_to_ray_v3_normalized(
+ ray_origin, ray_direction, point);
+ if (dist_sq_test < dist_sq_best_vert) {
+ dist_sq_best_vert = dist_sq_test;
+ best_vert.base_index = base_index;
+ best_vert.ele = (BMElem *)v;
+ }
+ if (dist_sq_test < dist_sq_best) {
+ dist_sq_best = dist_sq_test;
+ best.base_index = base_index;
+ best.ele = (BMElem *)v;
}
}
}
- if (use_edge) {
- BMEdge *e;
- BMIter eiter;
- BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) {
- float point[3];
- if (coords) {
- mid_v3_v3v3(
- point, coords[BM_elem_index_get(e->v1)], coords[BM_elem_index_get(e->v2)]);
- }
- else {
- mid_v3_v3v3(point, e->v1->co, e->v2->co);
- }
- mul_m4_v3(obedit->obmat, point);
- const float dist_sq_test = dist_squared_to_ray_v3_normalized(
- ray_origin, ray_direction, point);
- if (dist_sq_test < dist_sq_best) {
- dist_sq_best = dist_sq_test;
- best.base_index = base_index;
- best.ele = (BMElem *)e;
- }
+ }
+
+ if (use_edge && !use_boundary_edges) {
+ BMEdge *e;
+ BMIter eiter;
+ BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) {
+ float point[3];
+ if (coords) {
+ mid_v3_v3v3(
+ point, coords[BM_elem_index_get(e->v1)], coords[BM_elem_index_get(e->v2)]);
+ }
+ else {
+ mid_v3_v3v3(point, e->v1->co, e->v2->co);
+ }
+ mul_m4_v3(obedit->obmat, point);
+ const float dist_sq_test = dist_squared_to_ray_v3_normalized(
+ ray_origin, ray_direction, point);
+ if (dist_sq_test < dist_sq_best_edge) {
+ dist_sq_best_edge = dist_sq_test;
+ best_edge.base_index = base_index;
+ best_edge.ele = (BMElem *)e;
+ }
+ if (dist_sq_test < dist_sq_best) {
+ dist_sq_best = dist_sq_test;
+ best.base_index = base_index;
+ best.ele = (BMElem *)e;
}
}
}
@@ -1184,6 +1198,11 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
mul_m4_v3(obedit->obmat, point);
const float dist_sq_test = dist_squared_to_ray_v3_normalized(
ray_origin, ray_direction, point);
+ if (dist_sq_test < dist_sq_best_face) {
+ dist_sq_best_face = dist_sq_test;
+ best_face.base_index = base_index;
+ best_face.ele = (BMElem *)f;
+ }
if (dist_sq_test < dist_sq_best) {
dist_sq_best = dist_sq_test;
best.base_index = base_index;
@@ -1195,7 +1214,10 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
}
}
- *r_base_index = best.base_index;
+ *r_base_index_vert = best_vert.base_index;
+ *r_base_index_edge = best_edge.base_index;
+ *r_base_index_face = best_face.base_index;
+
if (r_eve) {
*r_eve = NULL;
}
@@ -1206,22 +1228,17 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
*r_efa = NULL;
}
- if (best.ele) {
- switch (best.ele->head.htype) {
- case BM_VERT:
- *r_eve = (BMVert *)best.ele;
- break;
- case BM_EDGE:
- *r_eed = (BMEdge *)best.ele;
- break;
- case BM_FACE:
- *r_efa = (BMFace *)best.ele;
- break;
- default:
- BLI_assert(0);
- }
+ if (best_vert.ele) {
+ *r_eve = (BMVert *)best_vert.ele;
}
- return (best.ele != NULL);
+ if (best_edge.ele) {
+ *r_eed = (BMEdge *)best_edge.ele;
+ }
+ if (best_face.ele) {
+ *r_efa = (BMFace *)best_face.ele;
+ }
+
+ return (best_vert.ele != NULL || best_edge.ele != NULL || best_face.ele != NULL);
}
/** \} */
@@ -1328,7 +1345,7 @@ static int edbm_select_mode_exec(bContext *C, wmOperator *op)
const bool use_extend = RNA_boolean_get(op->ptr, "use_extend");
const bool use_expand = RNA_boolean_get(op->ptr, "use_expand");
- if (EDBM_selectmode_toggle(C, type, action, use_extend, use_expand)) {
+ if (EDBM_selectmode_toggle_multi(C, type, action, use_extend, use_expand)) {
return OPERATOR_FINISHED;
}
else {
@@ -1366,13 +1383,6 @@ void MESH_OT_select_mode(wmOperatorType *ot)
{
PropertyRNA *prop;
- static const EnumPropertyItem elem_items[] = {
- {SCE_SELECT_VERTEX, "VERT", ICON_VERTEXSEL, "Vertices", ""},
- {SCE_SELECT_EDGE, "EDGE", ICON_EDGESEL, "Edges", ""},
- {SCE_SELECT_FACE, "FACE", ICON_FACESEL, "Faces", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
static const EnumPropertyItem actions_items[] = {
{0, "DISABLE", 0, "Disable", "Disable selected markers"},
{1, "ENABLE", 0, "Enable", "Enable selected markers"},
@@ -1399,7 +1409,7 @@ void MESH_OT_select_mode(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "use_expand", false, "Expand", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- ot->prop = prop = RNA_def_enum(ot->srna, "type", elem_items, 0, "Type", "");
+ ot->prop = prop = RNA_def_enum(ot->srna, "type", rna_enum_mesh_select_mode_items, 0, "Type", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_enum(
@@ -2338,11 +2348,11 @@ void EDBM_selectmode_convert(BMEditMesh *em,
}
/* user facing function, does notification */
-bool EDBM_selectmode_toggle(bContext *C,
- const short selectmode_new,
- const int action,
- const bool use_extend,
- const bool use_expand)
+bool EDBM_selectmode_toggle_multi(bContext *C,
+ const short selectmode_new,
+ const int action,
+ const bool use_extend,
+ const bool use_expand)
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -2464,6 +2474,54 @@ bool EDBM_selectmode_toggle(bContext *C,
return ret;
}
+bool EDBM_selectmode_set_multi(bContext *C, const short selectmode)
+{
+ BLI_assert(selectmode != 0);
+ bool changed = false;
+
+ {
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = NULL;
+ if (obedit && obedit->type == OB_MESH) {
+ em = BKE_editmesh_from_object(obedit);
+ }
+ if (em == NULL) {
+ return changed;
+ }
+ }
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+
+ if (ts->selectmode != selectmode) {
+ ts->selectmode = selectmode;
+ changed = true;
+ }
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
+ if (em_iter->selectmode != ts->selectmode) {
+ em_iter->selectmode = ts->selectmode;
+ EDBM_selectmode_set(em_iter);
+ DEG_id_tag_update(ob_iter->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data);
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+ }
+ return changed;
+}
+
/**
* Use to disable a selectmode if its enabled, Using another mode as a fallback
* if the disabled mode is the only mode set.
@@ -2584,8 +2642,9 @@ bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, const uint bases_len)
bool EDBM_mesh_deselect_all_multi(struct bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &bases_len);
@@ -2599,39 +2658,334 @@ bool EDBM_mesh_deselect_all_multi(struct bContext *C)
/* -------------------------------------------------------------------- */
/** \name Select Interior Faces
*
- * \note This algorithm is limited to single faces and could be improved, see:
- * https://blender.stackexchange.com/questions/18916
+ * Overview of the algorithm:
+ * - Groups faces surrounded by edges with 3+ faces using them.
+ * - Calculates a cost of each face group comparing it's angle with the faces
+ * connected to it's non-manifold edges.
+ * - Mark the face group as interior, and mark connected face groups for recalculation.
+ * - Continue to remove the face groups with the highest 'cost'.
+ *
* \{ */
+struct BMFaceLink {
+ struct BMFaceLink *next, *prev;
+ BMFace *face;
+ float area;
+};
+
+static bool bm_interior_loop_filter_fn(const BMLoop *l, void *UNUSED(user_data))
+{
+ if (BM_elem_flag_test(l->e, BM_ELEM_TAG)) {
+ return false;
+ }
+ return true;
+}
+static bool bm_interior_edge_is_manifold_except_face_index(BMEdge *e,
+ int face_index,
+ BMLoop *r_l_pair[2])
+{
+
+ BMLoop *l_iter = e->l;
+ int loop_index = 0;
+ do {
+ BMFace *f = l_iter->f;
+ int i = BM_elem_index_get(f);
+ if (!ELEM(i, -1, face_index)) {
+ if (loop_index == 2) {
+ return false;
+ }
+ r_l_pair[loop_index++] = l_iter;
+ }
+ } while ((l_iter = l_iter->radial_next) != e->l);
+ return (loop_index == 2);
+}
+
+/**
+ * Calculate the cost of the face group.
+ * A higher value means it's more likely to remove first.
+ */
+static float bm_interior_face_group_calc_cost(ListBase *ls, const float *edge_lengths)
+{
+ /* Dividing by the area is important so larger face groups (which will become the outer shell)
+ * aren't detected as having a high cost. */
+ float area = 0.0f;
+ float cost = 0.0f;
+ bool found = false;
+ LISTBASE_FOREACH (struct BMFaceLink *, f_link, ls) {
+ BMFace *f = f_link->face;
+ area += f_link->area;
+ int i = BM_elem_index_get(f);
+ BLI_assert(i != -1);
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (BM_elem_flag_test(l_iter->e, BM_ELEM_TAG)) {
+ float cost_test = 0.0f;
+ int cost_count = 0;
+ /* All other faces. */
+ BMLoop *l_radial_iter = l_iter;
+ do {
+ int i_other = BM_elem_index_get(l_radial_iter->f);
+ if (!ELEM(i_other, -1, i)) {
+ float angle = angle_normalized_v3v3(f->no, l_radial_iter->f->no);
+ /* Ignore face direction since in the case on non-manifold faces connecting edges,
+ * the face flipping may not be meaningful. */
+ if (angle > DEG2RADF(90)) {
+ angle = DEG2RADF(180) - angle;
+ }
+ /* Avoid calculating it inline, pass in pre-calculated edge lengths. */
+#if 0
+ cost_test += BM_edge_calc_length(l_iter->e) * angle;
+#else
+ BLI_assert(edge_lengths[BM_elem_index_get(l_iter->e)] != -1.0f);
+ cost_test += edge_lengths[BM_elem_index_get(l_iter->e)] * angle;
+#endif
+ cost_count += 1;
+ }
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
+
+ if (cost_count >= 2) {
+ cost += cost_test;
+ found = true;
+ }
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ return found ? cost / area : FLT_MAX;
+}
+
bool EDBM_select_interior_faces(BMEditMesh *em)
{
BMesh *bm = em->bm;
BMIter iter;
- BMIter eiter;
- BMFace *efa;
- BMEdge *eed;
- bool ok;
bool changed = false;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- continue;
+ float *edge_lengths = MEM_mallocN(sizeof(*edge_lengths) * bm->totedge, __func__);
+
+ {
+ bool has_nonmanifold = false;
+ BMEdge *e;
+ int i;
+ BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
+ const bool is_over = BM_edge_face_count_is_over(e, 2);
+ if (is_over) {
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ has_nonmanifold = true;
+ edge_lengths[i] = BM_edge_calc_length(e);
+ }
+ else {
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
+ edge_lengths[i] = -1.0;
+ }
+
+ BM_elem_index_set(e, i); /* set_inline */
}
+ bm->elem_index_dirty &= ~BM_EDGE;
- ok = true;
- BM_ITER_ELEM (eed, &eiter, efa, BM_EDGES_OF_FACE) {
- if (!BM_edge_face_count_is_over(eed, 2)) {
- ok = false;
+ if (has_nonmanifold == false) {
+ MEM_freeN(edge_lengths);
+ return false;
+ }
+ }
+
+ /* group vars */
+ int *fgroup_array;
+ int(*fgroup_index)[2];
+ int fgroup_len;
+
+ fgroup_array = MEM_mallocN(sizeof(*fgroup_array) * bm->totface, __func__);
+ fgroup_len = BM_mesh_calc_face_groups(
+ bm, fgroup_array, &fgroup_index, bm_interior_loop_filter_fn, NULL, 0, BM_EDGE);
+
+ int *fgroup_recalc_stack = MEM_mallocN(sizeof(*fgroup_recalc_stack) * fgroup_len, __func__);
+ STACK_DECLARE(fgroup_recalc_stack);
+ STACK_INIT(fgroup_recalc_stack, fgroup_len);
+
+ BM_mesh_elem_table_ensure(bm, BM_FACE);
+
+ {
+ BMFace *f;
+ BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_index_set(f, -1); /* set_dirty! */
+ }
+ }
+ bm->elem_index_dirty |= BM_FACE;
+
+ ListBase *fgroup_listbase = MEM_callocN(sizeof(*fgroup_listbase) * fgroup_len, __func__);
+ struct BMFaceLink *f_link_array = MEM_callocN(sizeof(*f_link_array) * bm->totface, __func__);
+
+ for (int i = 0; i < fgroup_len; i++) {
+ const int fg_sta = fgroup_index[i][0];
+ const int fg_len = fgroup_index[i][1];
+ for (int j = 0; j < fg_len; j++) {
+ const int face_index = fgroup_array[fg_sta + j];
+ BMFace *f = BM_face_at_index(bm, face_index);
+ BM_elem_index_set(f, i);
+
+ struct BMFaceLink *f_link = &f_link_array[face_index];
+ f_link->face = f;
+ f_link->area = BM_face_calc_area(f);
+ BLI_addtail(&fgroup_listbase[i], f_link);
+ }
+ }
+
+ MEM_freeN(fgroup_array);
+ MEM_freeN(fgroup_index);
+
+ Heap *fgroup_heap = BLI_heap_new_ex(fgroup_len);
+ HeapNode **fgroup_table = MEM_mallocN(sizeof(*fgroup_table) * fgroup_len, __func__);
+ bool *fgroup_dirty = MEM_callocN(sizeof(*fgroup_dirty) * fgroup_len, __func__);
+
+ for (int i = 0; i < fgroup_len; i++) {
+ const float cost = bm_interior_face_group_calc_cost(&fgroup_listbase[i], edge_lengths);
+ if (cost != FLT_MAX) {
+ fgroup_table[i] = BLI_heap_insert(fgroup_heap, -cost, POINTER_FROM_INT(i));
+ }
+ else {
+ fgroup_table[i] = NULL;
+ }
+ }
+
+ /* Avoid re-running cost calculations for large face-groups which will end up forming the
+ * outer shell and not be considered interior.
+ * As these face groups become increasingly bigger - their chance of being considered
+ * interior reduces as does the time to calculate their cost.
+ *
+ * This delays recalculating them until they are considered can dates to remove
+ * which becomes less and less likely as they increase in area. */
+
+#define USE_DELAY_FACE_GROUP_COST_CALC
+
+ while (true) {
+
+#if defined(USE_DELAY_FACE_GROUP_COST_CALC)
+ while (!BLI_heap_is_empty(fgroup_heap)) {
+ HeapNode *node_min = BLI_heap_top(fgroup_heap);
+ const int i = POINTER_AS_INT(BLI_heap_node_ptr(node_min));
+ if (fgroup_dirty[i]) {
+ const float cost = bm_interior_face_group_calc_cost(&fgroup_listbase[i], edge_lengths);
+ if (cost != FLT_MAX) {
+ /* The cost may have improves (we may be able to skip this),
+ * however the cost should _never_ make this a choice. */
+ BLI_assert(-BLI_heap_node_value(node_min) >= cost);
+ BLI_heap_node_value_update(fgroup_heap, fgroup_table[i], -cost);
+ }
+ else {
+ BLI_heap_remove(fgroup_heap, fgroup_table[i]);
+ fgroup_table[i] = NULL;
+ }
+ fgroup_dirty[i] = false;
+ }
+ else {
break;
}
}
+#endif
- if (ok) {
- BM_face_select_set(bm, efa, true);
- changed = true;
+ if (BLI_heap_is_empty(fgroup_heap)) {
+ break;
}
+
+ const int i_min = POINTER_AS_INT(BLI_heap_pop_min(fgroup_heap));
+ BLI_assert(fgroup_table[i_min] != NULL);
+ BLI_assert(fgroup_dirty[i_min] == false);
+ fgroup_table[i_min] = NULL;
+ changed = true;
+
+ struct BMFaceLink *f_link;
+ while ((f_link = BLI_pophead(&fgroup_listbase[i_min]))) {
+ BMFace *f = f_link->face;
+ BM_face_select_set(bm, f, true);
+ BM_elem_index_set(f, -1); /* set-dirty */
+
+ BMLoop *l_iter, *l_first;
+
+ /* Loop over edges face edges, merging groups which are no longer separated
+ * by non-manifold edges (when manifold check ignores faces from this group). */
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BMLoop *l_pair[2];
+ if (bm_interior_edge_is_manifold_except_face_index(l_iter->e, i_min, l_pair)) {
+ BM_elem_flag_disable(l_iter->e, BM_ELEM_TAG);
+
+ int i_a = BM_elem_index_get(l_pair[0]->f);
+ int i_b = BM_elem_index_get(l_pair[1]->f);
+ if (i_a != i_b) {
+ /* Only for predictable results that don't depend on the order of radial loops,
+ * not essential. */
+ if (i_a > i_b) {
+ SWAP(int, i_a, i_b);
+ }
+
+ /* Merge the the groups. */
+ LISTBASE_FOREACH (LinkData *, n, &fgroup_listbase[i_b]) {
+ BMFace *f_iter = n->data;
+ BM_elem_index_set(f_iter, i_a);
+ }
+ BLI_movelisttolist(&fgroup_listbase[i_a], &fgroup_listbase[i_b]);
+
+ /* This may have been added to 'fgroup_recalc_stack', instead of removing it,
+ * just check the heap node isn't NULL before recalculating. */
+ BLI_heap_remove(fgroup_heap, fgroup_table[i_b]);
+ fgroup_table[i_b] = NULL;
+ /* Keep the dirty flag as-is for 'i_b', because it may be in the 'fgroup_recalc_stack'
+ * and we don't want to add it again.
+ * Instead rely on the 'fgroup_table[i_b]' being NULL as a secondary check. */
+
+ if (fgroup_dirty[i_a] == false) {
+ BLI_assert(fgroup_table[i_a] != NULL);
+ STACK_PUSH(fgroup_recalc_stack, i_a);
+ fgroup_dirty[i_a] = true;
+ }
+ }
+ }
+
+ /* Mark all connected groups for re-calculation. */
+ BMLoop *l_radial_iter = l_iter->radial_next;
+ if (l_radial_iter != l_iter) {
+ do {
+ int i_other = BM_elem_index_get(l_radial_iter->f);
+ if (!ELEM(i_other, -1, i_min)) {
+ if ((fgroup_table[i_other] != NULL) && (fgroup_dirty[i_other] == false)) {
+#if !defined(USE_DELAY_FACE_GROUP_COST_CALC)
+ STACK_PUSH(fgroup_recalc_stack, i_other);
+#endif
+ fgroup_dirty[i_other] = true;
+ }
+ }
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
+ }
+
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ for (int index = 0; index < STACK_SIZE(fgroup_recalc_stack); index++) {
+ const int i = fgroup_recalc_stack[index];
+ if (fgroup_table[i] != NULL && fgroup_dirty[i] == true) {
+ /* First update edge tags. */
+ const float cost = bm_interior_face_group_calc_cost(&fgroup_listbase[i], edge_lengths);
+ if (cost != FLT_MAX) {
+ BLI_heap_node_value_update(fgroup_heap, fgroup_table[i], -cost);
+ }
+ else {
+ BLI_heap_remove(fgroup_heap, fgroup_table[i]);
+ fgroup_table[i] = NULL;
+ }
+ }
+ fgroup_dirty[i] = false;
+ }
+ STACK_CLEAR(fgroup_recalc_stack);
}
+ MEM_freeN(edge_lengths);
+ MEM_freeN(f_link_array);
+ MEM_freeN(fgroup_listbase);
+ MEM_freeN(fgroup_recalc_stack);
+ MEM_freeN(fgroup_table);
+ MEM_freeN(fgroup_dirty);
+
+ BLI_heap_free(fgroup_heap, NULL);
+
return changed;
}
@@ -3719,7 +4073,7 @@ static void walker_deselect_nth(BMEditMesh *em,
if (!BM_elem_flag_test(ele, BM_ELEM_TAG)) {
/* Deselect elements that aren't at "nth" depth from active */
const int depth = BMW_current_depth(&walker) - 1;
- if (WM_operator_properties_checker_interval_test(op_params, depth)) {
+ if (!WM_operator_properties_checker_interval_test(op_params, depth)) {
BM_elem_select_set(bm, ele, false);
}
BM_elem_flag_enable(ele, BM_ELEM_TAG);
@@ -3866,7 +4220,8 @@ void MESH_OT_select_nth(wmOperatorType *ot)
void em_setup_viewcontext(bContext *C, ViewContext *vc)
{
- ED_view3d_viewcontext_init(C, vc);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ED_view3d_viewcontext_init(C, vc, depsgraph);
if (vc->obedit) {
vc->em = BKE_editmesh_from_object(vc->obedit);
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 2b0213dc1ef..4636d1ee71e 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -2044,7 +2044,11 @@ static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op)
}
if (tot_failed_all != 0) {
- BKE_reportf(op->reports, RPT_WARNING, "Unable to rotate %d edge(s)", tot_failed_all);
+ BKE_reportf(op->reports,
+ RPT_WARNING,
+ tot_failed_all == 1 ? "Unable to rotate %d edge" :
+ "Unable to rotate %d edges",
+ tot_failed_all);
}
return OPERATOR_FINISHED;
@@ -3131,12 +3135,7 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
BM_mesh_elem_hflag_enable_test(em->bm, htype_select, BM_ELEM_TAG, true, true, BM_ELEM_SELECT);
if (use_unselected) {
- EDBM_op_init(em, &bmop, op, "automerge verts=%hv dist=%f", BM_ELEM_SELECT, threshold);
- BMO_op_exec(em->bm, &bmop);
-
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- continue;
- }
+ EDBM_automerge(obedit, false, BM_ELEM_SELECT, threshold);
}
else {
EDBM_op_init(em, &bmop, op, "find_doubles verts=%hv dist=%f", BM_ELEM_SELECT, threshold);
@@ -3166,7 +3165,11 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
}
MEM_freeN(objects);
- BKE_reportf(op->reports, RPT_INFO, "Removed %d vertices", count_multi);
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ count_multi == 1 ? "Removed %d vertex" :
+ "Removed %d vertices",
+ count_multi);
return OPERATOR_FINISHED;
}
@@ -3877,7 +3880,7 @@ void MESH_OT_knife_cut(wmOperatorType *ot)
/* internal */
RNA_def_int(
- ot->srna, "cursor", BC_KNIFECURSOR, 0, BC_NUMCURSORS, "Cursor", "", 0, BC_NUMCURSORS);
+ ot->srna, "cursor", WM_CURSOR_KNIFE, 0, WM_CURSOR_NUM, "Cursor", "", 0, WM_CURSOR_NUM);
}
/** \} */
@@ -5711,7 +5714,7 @@ void MESH_OT_dissolve_limited(wmOperatorType *ot)
"use_dissolve_boundaries",
false,
"All Boundaries",
- "Dissolve all vertices inbetween face boundaries");
+ "Dissolve all vertices in between face boundaries");
RNA_def_enum_flag(ot->srna,
"delimit",
rna_enum_mesh_delimit_mode_items,
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 1a03879ed17..8d340d93c0a 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -79,6 +79,11 @@ struct BMElem *EDBM_elem_from_selectmode(struct BMEditMesh *em,
int EDBM_elem_to_index_any(struct BMEditMesh *em, struct BMElem *ele);
struct BMElem *EDBM_elem_from_index_any(struct BMEditMesh *em, int index);
+bool edbm_extrude_edges_indiv(struct BMEditMesh *em,
+ struct wmOperator *op,
+ const char hflag,
+ const bool use_normal_flip);
+
/* *** editmesh_add.c *** */
void MESH_OT_primitive_plane_add(struct wmOperatorType *ot);
void MESH_OT_primitive_cube_add(struct wmOperatorType *ot);
@@ -122,6 +127,8 @@ void MESH_GGT_spin_redo(struct wmGizmoGroupType *gzgt);
void MESH_OT_polybuild_face_at_cursor(struct wmOperatorType *ot);
void MESH_OT_polybuild_split_at_cursor(struct wmOperatorType *ot);
void MESH_OT_polybuild_dissolve_at_cursor(struct wmOperatorType *ot);
+void MESH_OT_polybuild_transform_at_cursor(struct wmOperatorType *ot);
+void MESH_OT_polybuild_delete_at_cursor(struct wmOperatorType *ot);
/* *** editmesh_inset.c *** */
void MESH_OT_inset(struct wmOperatorType *ot);
@@ -244,6 +251,9 @@ void MESH_OT_average_normals(struct wmOperatorType *ot);
void MESH_OT_smoothen_normals(struct wmOperatorType *ot);
void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot);
+/* *** editmesh_mask_extract.c *** */
+void MESH_OT_paint_mask_extract(struct wmOperatorType *ot);
+
struct wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf);
#ifdef WITH_FREESTYLE
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 102ce3efc22..4105f853868 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -148,6 +148,8 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_polybuild_face_at_cursor);
WM_operatortype_append(MESH_OT_polybuild_split_at_cursor);
WM_operatortype_append(MESH_OT_polybuild_dissolve_at_cursor);
+ WM_operatortype_append(MESH_OT_polybuild_transform_at_cursor);
+ WM_operatortype_append(MESH_OT_polybuild_delete_at_cursor);
WM_operatortype_append(MESH_OT_uv_texture_add);
WM_operatortype_append(MESH_OT_uv_texture_remove);
@@ -192,6 +194,8 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_symmetrize);
WM_operatortype_append(MESH_OT_symmetry_snap);
+ WM_operatortype_append(MESH_OT_paint_mask_extract);
+
WM_operatortype_append(MESH_OT_point_normals);
WM_operatortype_append(MESH_OT_merge_normals);
WM_operatortype_append(MESH_OT_split_normals);
@@ -334,6 +338,25 @@ void ED_operatormacros_mesh(void)
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
RNA_boolean_set(otmacro->ptr, "mirror", false);
+
+ ot = WM_operatortype_append_macro("MESH_OT_polybuild_transform_at_cursor_move",
+ "Transform at Cursor Move",
+ "",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ WM_operatortype_macro_define(ot, "MESH_OT_polybuild_transform_at_cursor");
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
+ RNA_boolean_set(otmacro->ptr, "mirror", false);
+
+ ot = WM_operatortype_append_macro("MESH_OT_polybuild_extrude_at_cursor_move",
+ "Extrude at Cursor Move",
+ "",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ WM_operatortype_macro_define(ot, "MESH_OT_polybuild_transform_at_cursor");
+ otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_edges_indiv");
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
+ RNA_boolean_set(otmacro->ptr, "mirror", false);
}
/* note mesh keymap also for other space? */
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 8d9d0e40f44..a918996563f 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -54,6 +54,7 @@
#include "BKE_multires.h"
#include "BKE_object.h"
#include "BKE_object_deform.h"
+#include "BKE_object_facemap.h"
#include "BKE_report.h"
#include "DEG_depsgraph.h"
@@ -81,7 +82,7 @@ static void join_mesh_single(Depsgraph *depsgraph,
Scene *scene,
Object *ob_dst,
Object *ob_src,
- float imat[4][4],
+ const float imat[4][4],
MVert **mvert_pp,
MEdge **medge_pp,
MLoop **mloop_pp,
@@ -267,6 +268,22 @@ static void join_mesh_single(Depsgraph *depsgraph,
mpoly->loopstart += *loopofs;
mpoly->mat_nr = matmap ? matmap[mpoly->mat_nr] : 0;
}
+
+ /* Face maps. */
+ int *fmap = CustomData_get(pdata, *polyofs, CD_FACEMAP);
+ int *fmap_src = CustomData_get(&me->pdata, 0, CD_FACEMAP);
+
+ /* Remap to correct new face-map indices, if needed. */
+ if (fmap_src) {
+ BLI_assert(fmap != NULL);
+ int *fmap_index_map;
+ int fmap_index_map_len;
+ fmap_index_map = BKE_object_facemap_index_map_create(ob_src, ob_dst, &fmap_index_map_len);
+ BKE_object_facemap_index_map_apply(fmap, me->totpoly, fmap_index_map, fmap_index_map_len);
+ if (fmap_index_map != NULL) {
+ MEM_freeN(fmap_index_map);
+ }
+ }
}
/* these are used for relinking (cannot be set earlier, or else reattaching goes wrong) */
@@ -403,7 +420,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
key->type = KEY_RELATIVE;
}
- /* first pass over objects - copying materials and vertexgroups across */
+ /* First pass over objects: Copying materials, vertex-groups & face-maps across. */
CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
/* only act if a mesh, and not the one we're joining to */
if ((ob != ob_iter) && (ob_iter->type == OB_MESH)) {
@@ -422,6 +439,19 @@ int join_mesh_exec(bContext *C, wmOperator *op)
ob->actdef = 1;
}
+ /* Join this object's face maps to the base one's. */
+ for (bFaceMap *fmap = ob_iter->fmaps.first; fmap; fmap = fmap->next) {
+ /* See if this group exists in the object (if it doesn't, add it to the end) */
+ if (BKE_object_facemap_find_name(ob, fmap->name) == NULL) {
+ bFaceMap *fmap_new = MEM_callocN(sizeof(bFaceMap), "join faceMap");
+ memcpy(fmap_new, fmap, sizeof(bFaceMap));
+ BLI_addtail(&ob->fmaps, fmap_new);
+ }
+ }
+ if (ob->fmaps.first && ob->actfmap == 0) {
+ ob->actfmap = 1;
+ }
+
if (me->totvert) {
/* Add this object's materials to the base one's if they don't exist already
* (but only if limits not exceeded yet) */
@@ -1110,7 +1140,8 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px,
return false;
}
- ED_view3d_viewcontext_init(C, &vc);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ED_view3d_select_id_validate(&vc);
if (dist_px) {
@@ -1291,7 +1322,8 @@ bool ED_mesh_pick_vert(
return false;
}
- ED_view3d_viewcontext_init(C, &vc);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ED_view3d_select_id_validate(&vc);
if (use_zbuf) {
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index 18ff7ae1a5e..64ae75a0ee8 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -693,13 +693,14 @@ void MBALL_OT_reveal_metaelems(wmOperatorType *ot)
* stiffness circle) */
bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
static MetaElem *startelem = NULL;
ViewContext vc;
int a, hits;
unsigned int buffer[MAXPICKBUF];
rcti rect;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
BLI_rcti_init_pt_radius(&rect, mval, 12);
@@ -835,8 +836,9 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese
bool ED_mball_deselect_all_multi(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &bases_len);
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 80d150506ad..d6816ddbe73 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -1071,7 +1071,7 @@ void OBJECT_OT_drop_named_image(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Add Empty Image/Drop Image To Empty";
+ ot->name = "Add Empty Image/Drop Image to Empty";
ot->description = "Add an empty image type to scene with data";
ot->idname = "OBJECT_OT_drop_named_image";
@@ -1581,7 +1581,11 @@ static int object_delete_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- BKE_reportf(op->reports, RPT_INFO, "Deleted %u object(s)", changed_count);
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ changed_count == 1 ? "Deleted %u object" :
+ "Deleted %u objects",
+ changed_count);
if (changed_count == 0) {
return OPERATOR_CANCELLED;
@@ -2009,6 +2013,7 @@ void OBJECT_OT_duplicates_make_real(wmOperatorType *ot)
static const EnumPropertyItem convert_target_items[] = {
{OB_CURVE, "CURVE", ICON_OUTLINER_OB_CURVE, "Curve from Mesh/Text", ""},
{OB_MESH, "MESH", ICON_OUTLINER_OB_MESH, "Mesh from Curve/Meta/Surf/Text", ""},
+ {OB_GPENCIL, "GPENCIL", ICON_OUTLINER_OB_GREASEPENCIL, "Grease Pencil from Curve", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -2133,12 +2138,14 @@ static int convert_exec(bContext *C, wmOperator *op)
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
Base *basen = NULL, *basact = NULL;
Object *ob1, *obact = CTX_data_active_object(C);
Curve *cu;
Nurb *nu;
MetaBall *mb;
Mesh *me;
+ Object *gpencil_ob = NULL;
const short target = RNA_enum_get(op->ptr, "target");
bool keep_original = RNA_boolean_get(op->ptr, "keep_original");
int a, mballConverted = 0;
@@ -2380,6 +2387,24 @@ static int convert_exec(bContext *C, wmOperator *op)
/* meshes doesn't use displist */
BKE_object_free_curve_cache(newob);
}
+ else if (target == OB_GPENCIL) {
+ if (ob->type != OB_CURVE) {
+ BKE_report(
+ op->reports, RPT_ERROR, "Convert Surfaces to Grease Pencil is not supported.");
+ }
+ else {
+ /* Create a new grease pencil object only if it was not created before.
+ * All curves selected are converted as strokes of the same grease pencil object.
+ * Nurbs Surface are not supported.
+ */
+ if (gpencil_ob == NULL) {
+ const float *cur = scene->cursor.location;
+ ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0;
+ gpencil_ob = ED_gpencil_add_object(C, scene, cur, local_view_bits);
+ }
+ BKE_gpencil_convert_curve(bmain, scene, gpencil_ob, ob, false, false, true);
+ }
+ }
}
else if (ob->type == OB_MBALL && target == OB_MESH) {
Object *baseob;
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index 70a9870e6ae..bc79521ee9b 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -371,7 +371,7 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op)
ob = base->object;
- multires_force_update(ob);
+ multires_flush_sculpt_updates(ob);
/* copy data stored in job descriptor */
bkr.scene = scene;
@@ -435,7 +435,7 @@ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj)
ob = base->object;
- multires_force_update(ob);
+ multires_flush_sculpt_updates(ob);
data = MEM_callocN(sizeof(MultiresBakerJobData), "multiresBaker derivedMesh_data");
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 410ccccbd0d..d9baec7c3ca 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -745,7 +745,7 @@ static int bake(Render *re,
{
/* We build a depsgraph for the baking,
* so we don't need to change the original data to adjust visibility and modifiers. */
- Depsgraph *depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
+ Depsgraph *depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
DEG_graph_build_from_view_layer(depsgraph, bmain, scene, view_layer);
int op_result = OPERATOR_CANCELLED;
diff --git a/source/blender/editors/object/object_collection.c b/source/blender/editors/object/object_collection.c
index fcaefaf220d..a00e5e7b198 100644
--- a/source/blender/editors/object/object_collection.c
+++ b/source/blender/editors/object/object_collection.c
@@ -186,7 +186,7 @@ void COLLECTION_OT_objects_add_active(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Add Selected To Active Collection";
+ ot->name = "Add Selected to Active Collection";
ot->description = "Add the object to an object collection that contains the active object";
ot->idname = "COLLECTION_OT_objects_add_active";
@@ -259,7 +259,7 @@ void COLLECTION_OT_objects_remove_active(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Remove Selected From Active Collection";
+ ot->name = "Remove Selected from Active Collection";
ot->description = "Remove the object from an object collection that contains the active object";
ot->idname = "COLLECTION_OT_objects_remove_active";
@@ -302,7 +302,7 @@ static int collection_objects_remove_all_exec(bContext *C, wmOperator *UNUSED(op
void COLLECTION_OT_objects_remove_all(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Remove From All Unlinked Collections";
+ ot->name = "Remove from All Unlinked Collections";
ot->description = "Remove selected objects from all collections not used in a scene";
ot->idname = "COLLECTION_OT_objects_remove_all";
@@ -361,7 +361,7 @@ void COLLECTION_OT_objects_remove(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Remove From Collection";
+ ot->name = "Remove from Collection";
ot->description = "Remove selected objects from a collection";
ot->idname = "COLLECTION_OT_objects_remove";
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 14813f9a936..8981221cb9c 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -496,7 +496,7 @@ static void test_constraint(
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the curve is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
if (ct->tar->type != OB_CURVE) {
con->flag |= CONSTRAINT_DISABLE;
@@ -514,7 +514,7 @@ static void test_constraint(
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the armature is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
if (ct->tar->type != OB_ARMATURE) {
con->flag |= CONSTRAINT_DISABLE;
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 0c2b5292716..4759a3cb0db 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -271,9 +271,11 @@ void OBJECT_OT_hide_view_set(wmOperatorType *ot)
static int object_hide_collection_exec(bContext *C, wmOperator *op)
{
wmWindow *win = CTX_wm_window(C);
+ View3D *v3d = CTX_wm_view3d(C);
int index = RNA_int_get(op->ptr, "collection_index");
- const bool extend = (win->eventstate->shift != 0) || RNA_boolean_get(op->ptr, "toggle");
+ const bool extend = (win->eventstate->shift != 0);
+ const bool toggle = RNA_boolean_get(op->ptr, "toggle");
if (win->eventstate->alt != 0) {
index += 10;
@@ -289,7 +291,21 @@ static int object_hide_collection_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
- BKE_layer_collection_isolate(scene, view_layer, lc, extend);
+ if (v3d->flag & V3D_LOCAL_COLLECTIONS) {
+ if ((lc->runtime_flag & LAYER_COLLECTION_VISIBLE) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+ if (toggle) {
+ lc->local_collections_bits ^= v3d->local_collections_uuid;
+ BKE_layer_collection_local_sync(view_layer, v3d);
+ }
+ else {
+ BKE_layer_collection_local_isolate(view_layer, v3d, lc, extend);
+ }
+ }
+ else {
+ BKE_layer_collection_isolate(scene, view_layer, lc, extend);
+ }
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -894,12 +910,25 @@ void OBJECT_OT_forcefield_toggle(wmOperatorType *ot)
/* ********************************************** */
/* Motion Paths */
+static eAnimvizCalcRange object_path_convert_range(eObjectPathCalcRange range)
+{
+ switch (range) {
+ case OBJECT_PATH_CALC_RANGE_CURRENT_FRAME:
+ return ANIMVIZ_CALC_RANGE_CURRENT_FRAME;
+ case OBJECT_PATH_CALC_RANGE_CHANGED:
+ return ANIMVIZ_CALC_RANGE_CHANGED;
+ case OBJECT_PATH_CALC_RANGE_FULL:
+ return ANIMVIZ_CALC_RANGE_FULL;
+ }
+ return ANIMVIZ_CALC_RANGE_FULL;
+}
+
/* For the objects with animation: update paths for those that have got them
* This should selectively update paths that exist...
*
* To be called from various tools that do incremental updates
*/
-void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_only)
+void ED_objects_recalculate_paths(bContext *C, Scene *scene, eObjectPathCalcRange range)
{
/* Transform doesn't always have context available to do update. */
if (C == NULL) {
@@ -907,11 +936,9 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_
}
Main *bmain = CTX_data_main(C);
- /* NOTE: Dependency graph will be evaluated at all the frames, but we first need to access some
- * nested pointers, like animation data. */
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- ListBase targets = {NULL, NULL};
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ListBase targets = {NULL, NULL};
/* loop over objects in scene */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
/* set flag to force recalc, then grab path(s) from object */
@@ -920,11 +947,27 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_
}
CTX_DATA_END;
+ Depsgraph *depsgraph;
+ bool free_depsgraph = false;
+ /* For a single frame update it's faster to re-use existing dependency graph and avoid overhead
+ * of building all the relations and so on for a temporary one. */
+ if (range == OBJECT_PATH_CALC_RANGE_CURRENT_FRAME) {
+ /* NOTE: Dependency graph will be evaluated at all the frames, but we first need to access some
+ * nested pointers, like animation data. */
+ depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ free_depsgraph = false;
+ }
+ else {
+ depsgraph = animviz_depsgraph_build(bmain, scene, view_layer, &targets);
+ free_depsgraph = true;
+ }
+
/* recalculate paths, then free */
- animviz_calc_motionpaths(depsgraph, bmain, scene, &targets, true, current_frame_only);
+ animviz_calc_motionpaths(
+ depsgraph, bmain, scene, &targets, object_path_convert_range(range), true);
BLI_freelistN(&targets);
- if (!current_frame_only) {
+ if (range != OBJECT_PATH_CALC_RANGE_CURRENT_FRAME) {
/* Tag objects for copy on write - so paths will draw/redraw
* For currently frame only we update evaluated object directly. */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
@@ -934,6 +977,11 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_
}
CTX_DATA_END;
}
+
+ /* Free temporary depsgraph. */
+ if (free_depsgraph) {
+ DEG_graph_free(depsgraph);
+ }
}
/* show popup to determine settings */
@@ -979,7 +1027,7 @@ static int object_calculate_paths_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* calculate the paths for objects that have them (and are tagged to get refreshed) */
- ED_objects_recalculate_paths(C, scene, false);
+ ED_objects_recalculate_paths(C, scene, OBJECT_PATH_CALC_RANGE_FULL);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -1044,7 +1092,7 @@ static int object_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
}
/* calculate the paths for objects that have them (and are tagged to get refreshed) */
- ED_objects_recalculate_paths(C, scene, false);
+ ED_objects_recalculate_paths(C, scene, OBJECT_PATH_CALC_RANGE_FULL);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -1342,27 +1390,12 @@ static bool object_mode_set_poll(bContext *C)
static int object_mode_set_exec(bContext *C, wmOperator *op)
{
- bool use_submode = STREQ(op->idname, "OBJECT_OT_mode_set_or_submode");
+ bool use_submode = STREQ(op->idname, "OBJECT_OT_mode_set_with_submode");
Object *ob = CTX_data_active_object(C);
eObjectMode mode = RNA_enum_get(op->ptr, "mode");
eObjectMode restore_mode = (ob) ? ob->mode : OB_MODE_OBJECT;
const bool toggle = RNA_boolean_get(op->ptr, "toggle");
- if (use_submode) {
- /* When not changing modes use submodes, see: T55162. */
- if (toggle == false) {
- if (mode == restore_mode) {
- switch (mode) {
- case OB_MODE_EDIT:
- WM_menu_name_call(C, "VIEW3D_MT_edit_mesh_select_mode", WM_OP_INVOKE_REGION_WIN);
- return OPERATOR_INTERFACE;
- default:
- break;
- }
- }
- }
- }
-
/* by default the operator assume is a mesh, but if gp object change mode */
if ((ob != NULL) && (ob->type == OB_GPENCIL) && (mode == OB_MODE_EDIT)) {
mode = OB_MODE_EDIT_GPENCIL;
@@ -1406,6 +1439,20 @@ static int object_mode_set_exec(bContext *C, wmOperator *op)
}
}
+ if (use_submode) {
+ if (ob->type == OB_MESH) {
+ if (ob->mode & OB_MODE_EDIT) {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "mesh_select_mode");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ int mesh_select_mode = RNA_property_enum_get(op->ptr, prop);
+ if (mesh_select_mode != 0) {
+ EDBM_selectmode_set_multi(C, mesh_select_mode);
+ }
+ }
+ }
+ }
+ }
+
return OPERATOR_FINISHED;
}
@@ -1435,30 +1482,20 @@ void OBJECT_OT_mode_set(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-void OBJECT_OT_mode_set_or_submode(wmOperatorType *ot)
+void OBJECT_OT_mode_set_with_submode(wmOperatorType *ot)
{
- PropertyRNA *prop;
+ OBJECT_OT_mode_set(ot);
/* identifiers */
- ot->name = "Set Object Mode or Submode";
- ot->description = "Sets the object interaction mode";
- ot->idname = "OBJECT_OT_mode_set_or_submode";
+ ot->name = "Set Object Mode with Submode";
+ ot->idname = "OBJECT_OT_mode_set_with_submode";
- /* api callbacks */
- ot->exec = object_mode_set_exec;
-
- ot->poll = object_mode_set_poll; // ED_operator_object_active_editable;
-
- /* flags */
- ot->flag = 0; /* no register/undo here, leave it to operators being called */
-
- ot->prop = RNA_def_enum(
- ot->srna, "mode", rna_enum_object_mode_items, OB_MODE_OBJECT, "Mode", "");
- RNA_def_enum_funcs(ot->prop, object_mode_set_itemsf);
- RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
-
- prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ /* properties */
+ /* we could add other types - particle for eg. */
+ PropertyRNA *prop;
+ prop = RNA_def_enum_flag(
+ ot->srna, "mesh_select_mode", rna_enum_mesh_select_mode_items, 0, "Mesh Mode", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
static ListBase selected_objects_get(bContext *C)
@@ -1691,7 +1728,7 @@ static int move_to_collection_invoke(bContext *C, wmOperator *op, const wmEvent
return move_to_collection_exec(C, op);
}
- Collection *master_collection = BKE_collection_master(scene);
+ Collection *master_collection = scene->master_collection;
/* We need the data to be allocated so it's available during menu drawing.
* Technically we could use wmOperator->customdata. However there is no free callback
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 4b369c10e4d..41205bc8778 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -71,7 +71,7 @@ void OBJECT_OT_hide_view_set(struct wmOperatorType *ot);
void OBJECT_OT_hide_view_clear(struct wmOperatorType *ot);
void OBJECT_OT_hide_collection(struct wmOperatorType *ot);
void OBJECT_OT_mode_set(struct wmOperatorType *ot);
-void OBJECT_OT_mode_set_or_submode(struct wmOperatorType *ot);
+void OBJECT_OT_mode_set_with_submode(struct wmOperatorType *ot);
void OBJECT_OT_editmode_toggle(struct wmOperatorType *ot);
void OBJECT_OT_posemode_toggle(struct wmOperatorType *ot);
void OBJECT_OT_proxy_make(struct wmOperatorType *ot);
@@ -281,6 +281,7 @@ void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot);
/* object_remesh.c */
void OBJECT_OT_voxel_remesh(struct wmOperatorType *ot);
+void OBJECT_OT_quadriflow_remesh(struct wmOperatorType *ot);
/* object_transfer_data.c */
void OBJECT_OT_data_transfer(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index f77d9874c06..abcb4afa37d 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -52,6 +52,7 @@
#include "BKE_editmesh.h"
#include "BKE_effect.h"
#include "BKE_global.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
@@ -110,6 +111,9 @@ static void object_force_modifier_update_for_bind(Depsgraph *depsgraph, Object *
else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
BKE_displist_make_curveTypes(depsgraph, scene_eval, ob_eval, false, false);
}
+ else if (ob->type == OB_GPENCIL) {
+ BKE_gpencil_modifiers_calc(depsgraph, scene_eval, ob_eval);
+ }
}
static void object_force_modifier_bind_simple_options(Depsgraph *depsgraph,
@@ -673,7 +677,7 @@ static int modifier_apply_obdata(
/* Multires: ensure that recent sculpting is applied */
if (md_eval->type == eModifierType_Multires) {
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
}
if (mmd && mmd->totlvl && mti->type == eModifierTypeType_OnlyDeform) {
@@ -2018,7 +2022,7 @@ static int correctivesmooth_bind_exec(bContext *C, wmOperator *op)
is_bind = (csmd->bind_coords != NULL);
MEM_SAFE_FREE(csmd->bind_coords);
- MEM_SAFE_FREE(csmd->delta_cache);
+ MEM_SAFE_FREE(csmd->delta_cache.deltas);
if (is_bind) {
/* toggle off */
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 38c06319450..f6b08b953a4 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -59,7 +59,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_origin_set);
WM_operatortype_append(OBJECT_OT_mode_set);
- WM_operatortype_append(OBJECT_OT_mode_set_or_submode);
+ WM_operatortype_append(OBJECT_OT_mode_set_with_submode);
WM_operatortype_append(OBJECT_OT_editmode_toggle);
WM_operatortype_append(OBJECT_OT_posemode_toggle);
WM_operatortype_append(OBJECT_OT_proxy_make);
@@ -259,6 +259,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_hide_collection);
WM_operatortype_append(OBJECT_OT_voxel_remesh);
+ WM_operatortype_append(OBJECT_OT_quadriflow_remesh);
}
void ED_operatormacros_object(void)
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 67364f275dd..d56791e5da0 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -1434,7 +1434,7 @@ static int make_links_scene_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- Collection *collection_to = BKE_collection_master(scene_to);
+ Collection *collection_to = scene_to->master_collection;
CTX_DATA_BEGIN (C, Base *, base, selected_bases) {
BKE_collection_object_add(bmain, collection_to, base->object);
}
@@ -1771,7 +1771,7 @@ static void single_object_users(
Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_collections)
{
/* duplicate all the objects of the scene (and matching collections, if required). */
- Collection *master_collection = BKE_collection_master(scene);
+ Collection *master_collection = scene->master_collection;
single_object_users_collection(bmain, scene, master_collection, flag, copy_collections, true);
/* duplicate collections that consist entirely of duplicated objects */
@@ -1817,6 +1817,10 @@ static void single_object_users(
if (v3d) {
ID_NEW_REMAP(v3d->camera);
}
+ /* Camera pointers of markers. */
+ for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) {
+ ID_NEW_REMAP(marker->camera);
+ }
/* Making single user may affect other scenes if they share
* with current one some collections in their ViewLayer. */
@@ -2046,6 +2050,13 @@ void ED_object_single_users(Main *bmain,
single_obdata_users(bmain, scene, NULL, NULL, 0);
single_object_action_users(bmain, scene, NULL, NULL, 0);
single_mat_users_expand(bmain);
+ /* Duplicating obdata and other IDs may require another update of the collections and objects
+ * pointers, especially reguarding drivers and custom props, see T66641.
+ * Note that this whole scene duplication code and 'make single user' functions have te be
+ * rewritten at some point to make use of proper modern ID management code,
+ * but that is no small task.
+ * For now we are doomed to that kind of band-aid to try to cover most of remapping cases. */
+ libblock_relink_collection(scene->master_collection);
}
/* Relink nodetrees' pointers that have been duplicated. */
@@ -2426,6 +2437,16 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
if (!ID_IS_LINKED(obact) && obact->instance_collection != NULL &&
ID_IS_LINKED(obact->instance_collection)) {
+ if (!ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection)) {
+ BKE_reportf(op->reports,
+ RPT_ERROR_INVALID_INPUT,
+ "Collection '%s' (instantiated by the active object) is not overridable",
+ obact->instance_collection->id.name + 2);
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+
Object *obcollection = obact;
Collection *collection = obcollection->instance_collection;
@@ -2503,7 +2524,14 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
/* Cleanup. */
BKE_main_id_clear_newpoins(bmain);
- BKE_main_id_tag_listbase(&bmain->objects, LIB_TAG_DOIT, false);
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ }
+ else if (!ID_IS_OVERRIDABLE_LIBRARY(obact)) {
+ BKE_reportf(op->reports,
+ RPT_ERROR_INVALID_INPUT,
+ "Active object '%s' is not overridable",
+ obact->id.name + 2);
+ return OPERATOR_CANCELLED;
}
/* Else, poll func ensures us that ID_IS_LINKED(obact) is true. */
else if (obact->type == OB_ARMATURE) {
@@ -2522,11 +2550,14 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
/* Cleanup. */
BKE_main_id_clear_newpoins(bmain);
- BKE_main_id_tag_listbase(&bmain->objects, LIB_TAG_DOIT, false);
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
}
/* TODO: probably more cases where we want to do automated smart things in the future! */
else {
- success = (BKE_override_library_create_from_id(bmain, &obact->id) != NULL);
+ /* For now, remapp all local usages of linked ID to local override one here. */
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, true);
+ success = (BKE_override_library_create_from_id(bmain, &obact->id, true) != NULL);
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
}
WM_event_add_notifier(C, NC_WINDOW, NULL);
diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c
index 5f464084a9b..2c05ae14f2e 100644
--- a/source/blender/editors/object/object_remesh.c
+++ b/source/blender/editors/object/object_remesh.c
@@ -40,12 +40,17 @@
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_mirror.h"
+#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_shrinkwrap.h"
#include "BKE_customdata.h"
#include "BKE_mesh_remesh_voxel.h"
@@ -73,13 +78,18 @@ static bool object_remesh_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
+ if (ob == NULL) {
+ return false;
+ }
+
if (BKE_object_is_in_editmode(ob)) {
- CTX_wm_operator_poll_msg_set(C, "The voxel remesher cannot run from edit mode.");
+ CTX_wm_operator_poll_msg_set(C, "The remesher cannot run from edit mode.");
return false;
}
if (ob->mode == OB_MODE_SCULPT && ob->sculpt->bm) {
- CTX_wm_operator_poll_msg_set(C, "The voxel remesher cannot run with dyntopo activated.");
+ CTX_wm_operator_poll_msg_set(C, "The remesher cannot run with dyntopo activated.");
+ return false;
}
return ED_operator_object_active_editable_mesh(C);
@@ -88,7 +98,6 @@ static bool object_remesh_poll(bContext *C)
static int voxel_remesh_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
- Main *bmain = CTX_data_main(C);
Mesh *mesh = ob->data;
Mesh *new_mesh;
@@ -102,29 +111,30 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
ED_sculpt_undo_geometry_begin(ob);
}
- new_mesh = BKE_mesh_remesh_voxel_to_mesh_nomain(mesh, mesh->remesh_voxel_size);
+ new_mesh = BKE_mesh_remesh_voxel_to_mesh_nomain(
+ mesh, mesh->remesh_voxel_size, mesh->remesh_voxel_adaptivity);
if (!new_mesh) {
return OPERATOR_CANCELLED;
}
- Mesh *obj_mesh_copy = NULL;
- if (mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK) {
- obj_mesh_copy = BKE_mesh_new_nomain_from_template(mesh, mesh->totvert, 0, 0, 0, 0);
- CustomData_copy(
- &mesh->vdata, &obj_mesh_copy->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, mesh->totvert);
- for (int i = 0; i < mesh->totvert; i++) {
- copy_v3_v3(obj_mesh_copy->mvert[i].co, mesh->mvert[i].co);
- }
+ if (mesh->flag & ME_REMESH_FIX_POLES && mesh->remesh_voxel_adaptivity <= 0.0f) {
+ new_mesh = BKE_mesh_remesh_voxel_fix_poles(new_mesh);
+ BKE_mesh_calc_normals(new_mesh);
}
- BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
+ if (mesh->flag & ME_REMESH_REPROJECT_VOLUME) {
+ BKE_mesh_runtime_clear_geometry(mesh);
+ BKE_shrinkwrap_remesh_target_project(new_mesh, mesh, ob);
+ }
if (mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK) {
- BKE_remesh_reproject_paint_mask(mesh, obj_mesh_copy);
- BKE_mesh_free(obj_mesh_copy);
+ BKE_mesh_runtime_clear_geometry(mesh);
+ BKE_remesh_reproject_paint_mask(new_mesh, mesh);
}
+ BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
+
if (mesh->flag & ME_REMESH_SMOOTH_NORMALS) {
BKE_mesh_smooth_flag_set(ob->data, true);
}
@@ -134,7 +144,6 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
}
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
- DEG_relations_tag_update(bmain);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
@@ -156,3 +165,497 @@ void OBJECT_OT_voxel_remesh(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+enum {
+ QUADRIFLOW_REMESH_RATIO = 1,
+ QUADRIFLOW_REMESH_EDGE_LENGTH,
+ QUADRIFLOW_REMESH_FACES,
+};
+
+/****************** quadriflow remesh operator *********************/
+
+#define QUADRIFLOW_MIRROR_BISECT_TOLERANCE 0.005f
+
+typedef enum eSymmetryAxes {
+ SYMMETRY_AXES_X = (1 << 0),
+ SYMMETRY_AXES_Y = (1 << 1),
+ SYMMETRY_AXES_Z = (1 << 2),
+} eSymmetryAxes;
+
+typedef struct QuadriFlowJob {
+ /* from wmJob */
+ struct Object *owner;
+ struct Main *bmain;
+ short *stop, *do_update;
+ float *progress;
+
+ int target_faces;
+ int seed;
+ bool use_paint_symmetry;
+ eSymmetryAxes symmetry_axes;
+
+ bool use_preserve_sharp;
+ bool use_preserve_boundary;
+ bool use_mesh_curvature;
+
+ bool preserve_paint_mask;
+ bool smooth_normals;
+
+ int success;
+} QuadriFlowJob;
+
+static void quadriflow_free_job(void *customdata)
+{
+ QuadriFlowJob *qj = customdata;
+ MEM_freeN(qj);
+}
+
+/* called by quadriflowjob, only to check job 'stop' value */
+static int quadriflow_break_job(void *customdata)
+{
+ QuadriFlowJob *qj = (QuadriFlowJob *)customdata;
+ // return *(qj->stop);
+
+ /* this is not nice yet, need to make the jobs list template better
+ * for identifying/acting upon various different jobs */
+ /* but for now we'll reuse the render break... */
+ bool should_break = (G.is_break);
+
+ if (should_break) {
+ qj->success = -1;
+ }
+
+ return should_break;
+}
+
+/* called by oceanbake, wmJob sends notifier */
+static void quadriflow_update_job(void *customdata, float progress, int *cancel)
+{
+ QuadriFlowJob *qj = customdata;
+
+ if (quadriflow_break_job(qj)) {
+ *cancel = 1;
+ }
+ else {
+ *cancel = 0;
+ }
+
+ *(qj->do_update) = true;
+ *(qj->progress) = progress;
+}
+
+static Mesh *remesh_symmetry_bisect(Main *bmain, Mesh *mesh, eSymmetryAxes symmetry_axes)
+{
+ MirrorModifierData mmd = {0};
+ mmd.tolerance = QUADRIFLOW_MIRROR_BISECT_TOLERANCE;
+
+ Mesh *mesh_bisect, *mesh_bisect_temp;
+ mesh_bisect = BKE_mesh_copy(bmain, mesh);
+
+ int axis;
+ float plane_co[3], plane_no[3];
+ zero_v3(plane_co);
+
+ for (char i = 0; i < 3; i++) {
+ eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
+ if (symmetry_axes & symm_it) {
+ axis = i;
+ mmd.flag = 0;
+ mmd.flag &= MOD_MIR_BISECT_AXIS_X << i;
+ zero_v3(plane_no);
+ plane_no[axis] = -1.0f;
+ mesh_bisect_temp = mesh_bisect;
+ mesh_bisect = BKE_mirror_bisect_on_mirror_plane(&mmd, mesh_bisect, axis, plane_co, plane_no);
+ if (mesh_bisect_temp != mesh_bisect) {
+ BKE_id_free(bmain, mesh_bisect_temp);
+ }
+ }
+ }
+
+ BKE_id_free(bmain, mesh);
+
+ return mesh_bisect;
+}
+
+static Mesh *remesh_symmetry_mirror(Object *ob, Mesh *mesh, eSymmetryAxes symmetry_axes)
+{
+ MirrorModifierData mmd = {0};
+ mmd.tolerance = QUADRIFLOW_MIRROR_BISECT_TOLERANCE;
+ Mesh *mesh_mirror, *mesh_mirror_temp;
+
+ mesh_mirror = mesh;
+
+ int axis;
+
+ for (char i = 0; i < 3; i++) {
+ eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
+ if (symmetry_axes & symm_it) {
+ axis = i;
+ mmd.flag = 0;
+ mmd.flag &= MOD_MIR_AXIS_X << i;
+ mesh_mirror_temp = mesh_mirror;
+ mesh_mirror = BKE_mirror_apply_mirror_on_axis(&mmd, NULL, ob, mesh_mirror, axis);
+ if (mesh_mirror_temp != mesh_mirror) {
+ BKE_id_free(NULL, mesh_mirror_temp);
+ }
+ }
+ }
+
+ return mesh_mirror;
+}
+
+static void quadriflow_start_job(void *customdata, short *stop, short *do_update, float *progress)
+{
+ QuadriFlowJob *qj = customdata;
+
+ qj->stop = stop;
+ qj->do_update = do_update;
+ qj->progress = progress;
+ qj->success = 1;
+
+ G.is_break = false; /* XXX shared with render - replace with job 'stop' switch */
+
+ Object *ob = qj->owner;
+ Mesh *mesh = ob->data;
+ Mesh *new_mesh;
+ Mesh *bisect_mesh;
+
+ /* Run Quadriflow bisect operations on a copy of the mesh to keep the code readable without
+ * freeing the original ID */
+ bisect_mesh = BKE_mesh_copy(qj->bmain, mesh);
+
+ /* Bisect the input mesh using the paint symmetry settings */
+ bisect_mesh = remesh_symmetry_bisect(qj->bmain, bisect_mesh, qj->symmetry_axes);
+
+ new_mesh = BKE_mesh_remesh_quadriflow_to_mesh_nomain(bisect_mesh,
+ qj->target_faces,
+ qj->seed,
+ qj->use_preserve_sharp,
+ qj->use_preserve_boundary ||
+ qj->use_paint_symmetry,
+ qj->use_mesh_curvature,
+ quadriflow_update_job,
+ (void *)qj);
+
+ BKE_id_free(qj->bmain, bisect_mesh);
+
+ if (!new_mesh) {
+ *do_update = true;
+ *stop = 0;
+ if (qj->success == 1) {
+ /* This is not a user cancelation event */
+ qj->success = 0;
+ }
+ return;
+ }
+
+ /* Mirror the Quadriflow result to build the final mesh */
+ if (new_mesh) {
+ new_mesh = remesh_symmetry_mirror(qj->owner, new_mesh, qj->symmetry_axes);
+ }
+
+ if (ob->mode == OB_MODE_SCULPT) {
+ ED_sculpt_undo_geometry_begin(ob);
+ }
+
+ if (qj->preserve_paint_mask) {
+ BKE_mesh_runtime_clear_geometry(mesh);
+ BKE_remesh_reproject_paint_mask(new_mesh, mesh);
+ }
+
+ BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
+
+ if (qj->smooth_normals) {
+ if (qj->use_paint_symmetry) {
+ BKE_mesh_calc_normals(ob->data);
+ }
+ BKE_mesh_smooth_flag_set(ob->data, true);
+ }
+
+ if (ob->mode == OB_MODE_SCULPT) {
+ ED_sculpt_undo_geometry_end(ob);
+ }
+
+ BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+
+ *do_update = true;
+ *stop = 0;
+}
+
+static void quadriflow_end_job(void *customdata)
+{
+ QuadriFlowJob *qj = customdata;
+
+ Object *ob = qj->owner;
+
+ WM_set_locked_interface(G_MAIN->wm.first, false);
+
+ if (qj->success > 0) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_reportf(RPT_INFO, "QuadriFlow: Completed remeshing!");
+ }
+ else {
+ if (qj->success == 0) {
+ WM_reportf(RPT_ERROR, "QuadriFlow: remeshing failed!");
+ }
+ else {
+ WM_report(RPT_WARNING, "QuadriFlow: remeshing canceled!");
+ }
+ }
+}
+
+static int quadriflow_remesh_exec(bContext *C, wmOperator *op)
+{
+ QuadriFlowJob *job = MEM_mallocN(sizeof(QuadriFlowJob), "QuadriFlowJob");
+
+ job->owner = CTX_data_active_object(C);
+ job->bmain = CTX_data_main(C);
+
+ job->target_faces = RNA_int_get(op->ptr, "target_faces");
+ job->seed = RNA_int_get(op->ptr, "seed");
+
+ job->use_paint_symmetry = RNA_boolean_get(op->ptr, "use_paint_symmetry");
+
+ job->use_preserve_sharp = RNA_boolean_get(op->ptr, "use_preserve_sharp");
+ job->use_preserve_boundary = RNA_boolean_get(op->ptr, "use_preserve_boundary");
+
+ job->use_mesh_curvature = RNA_boolean_get(op->ptr, "use_mesh_curvature");
+
+ job->preserve_paint_mask = RNA_boolean_get(op->ptr, "preserve_paint_mask");
+ job->smooth_normals = RNA_boolean_get(op->ptr, "smooth_normals");
+
+ /* Update the target face count if symmetry is enabled */
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ if (sd && job->use_paint_symmetry) {
+ job->symmetry_axes = (eSymmetryAxes)(sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL);
+ for (char i = 0; i < 3; i++) {
+ eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
+ if (job->symmetry_axes & symm_it) {
+ job->target_faces = job->target_faces / 2;
+ }
+ }
+ }
+ else {
+ job->use_paint_symmetry = false;
+ job->symmetry_axes = 0;
+ }
+
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ CTX_data_scene(C),
+ "QuadriFlow Remesh",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_QUADRIFLOW_REMESH);
+
+ WM_jobs_customdata_set(wm_job, job, quadriflow_free_job);
+ WM_jobs_timer(wm_job, 0.1, NC_GEOM | ND_DATA, NC_GEOM | ND_DATA);
+ WM_jobs_callbacks(wm_job, quadriflow_start_job, NULL, NULL, quadriflow_end_job);
+
+ WM_set_locked_interface(CTX_wm_manager(C), true);
+
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool quadriflow_check(bContext *C, wmOperator *op)
+{
+ int mode = RNA_enum_get(op->ptr, "mode");
+
+ if (mode == QUADRIFLOW_REMESH_EDGE_LENGTH) {
+ float area = RNA_float_get(op->ptr, "mesh_area");
+ if (area < 0.0f) {
+ Object *ob = CTX_data_active_object(C);
+ area = BKE_mesh_calc_area(ob->data);
+ RNA_float_set(op->ptr, "mesh_area", area);
+ }
+ int num_faces;
+ float edge_len = RNA_float_get(op->ptr, "target_edge_length");
+
+ num_faces = area / (edge_len * edge_len);
+ RNA_int_set(op->ptr, "target_faces", num_faces);
+ }
+ else if (mode == QUADRIFLOW_REMESH_RATIO) {
+ Object *ob = CTX_data_active_object(C);
+ Mesh *mesh = ob->data;
+
+ int num_faces;
+ float ratio = RNA_float_get(op->ptr, "target_ratio");
+
+ num_faces = mesh->totpoly * ratio;
+
+ RNA_int_set(op->ptr, "target_faces", num_faces);
+ }
+
+ return true;
+}
+
+/* Hide the target variables if they are not active */
+static bool quadriflow_poll_property(const bContext *C, wmOperator *op, const PropertyRNA *prop)
+{
+ const char *prop_id = RNA_property_identifier(prop);
+
+ if (STRPREFIX(prop_id, "target")) {
+ int mode = RNA_enum_get(op->ptr, "mode");
+
+ if (STREQ(prop_id, "target_edge_length") && mode != QUADRIFLOW_REMESH_EDGE_LENGTH) {
+ return false;
+ }
+ else if (STREQ(prop_id, "target_faces")) {
+ if (mode != QUADRIFLOW_REMESH_FACES) {
+ /* Make sure we can edit the target_faces value even if it doesn't start as EDITABLE */
+ float area = RNA_float_get(op->ptr, "mesh_area");
+ if (area < -0.8f) {
+ area += 0.2f;
+ /* Make sure we have up to date values from the start */
+ RNA_def_property_flag((PropertyRNA *)prop, PROP_EDITABLE);
+ quadriflow_check((bContext *)C, op);
+ }
+
+ /* Only disable input */
+ RNA_def_property_clear_flag((PropertyRNA *)prop, PROP_EDITABLE);
+ }
+ else {
+ RNA_def_property_flag((PropertyRNA *)prop, PROP_EDITABLE);
+ }
+ }
+ else if (STREQ(prop_id, "target_ratio") && mode != QUADRIFLOW_REMESH_RATIO) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static const EnumPropertyItem mode_type_items[] = {
+ {QUADRIFLOW_REMESH_RATIO,
+ "RATIO",
+ 0,
+ "Ratio",
+ "Specify target number of faces relative to the current mesh"},
+ {QUADRIFLOW_REMESH_EDGE_LENGTH,
+ "EDGE",
+ 0,
+ "Edge Length",
+ "Input target edge length in the new mesh"},
+ {QUADRIFLOW_REMESH_FACES, "FACES", 0, "Faces", "Input target number of faces in the new mesh"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "QuadriFlow Remesh";
+ ot->description =
+ "Create a new quad based mesh using the surface data of the current mesh. All data "
+ "layers will be lost";
+ ot->idname = "OBJECT_OT_quadriflow_remesh";
+
+ /* api callbacks */
+ ot->poll = object_remesh_poll;
+ ot->poll_property = quadriflow_poll_property;
+ ot->check = quadriflow_check;
+ ot->invoke = WM_operator_props_popup_confirm;
+ ot->exec = quadriflow_remesh_exec;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ PropertyRNA *prop;
+
+ /* properties */
+ RNA_def_boolean(ot->srna,
+ "use_paint_symmetry",
+ true,
+ "Use Paint Symmetry",
+ "Generates a symmetrycal mesh using the paint symmetry configuration");
+
+ RNA_def_boolean(ot->srna,
+ "use_preserve_sharp",
+ false,
+ "Preserve Sharp",
+ "Try to preserve sharp features on the mesh");
+
+ RNA_def_boolean(ot->srna,
+ "use_preserve_boundary",
+ false,
+ "Preserve Mesh Boundary",
+ "Try to preserve mesh boundary on the mesh");
+
+ RNA_def_boolean(ot->srna,
+ "use_mesh_curvature",
+ false,
+ "Use Mesh Curvature",
+ "Take the mesh curvature into account when remeshing");
+
+ RNA_def_boolean(ot->srna,
+ "preserve_paint_mask",
+ false,
+ "Preserve Paint Mask",
+ "Reproject the paint mask onto the new mesh");
+
+ RNA_def_boolean(ot->srna,
+ "smooth_normals",
+ false,
+ "Smooth Normals",
+ "Set the output mesh normals to smooth");
+
+ RNA_def_enum(ot->srna,
+ "mode",
+ mode_type_items,
+ 0,
+ "Mode",
+ "How to specify the amount of detail for the new mesh");
+
+ prop = RNA_def_float(ot->srna,
+ "target_ratio",
+ 1,
+ 0,
+ FLT_MAX,
+ "Ratio",
+ "Relative number of faces compared to the current mesh",
+ 0.0f,
+ 1.0f);
+
+ prop = RNA_def_float(ot->srna,
+ "target_edge_length",
+ 0.1f,
+ 0.0000001f,
+ FLT_MAX,
+ "Edge Length",
+ "Target edge length in the new mesh",
+ 0.00001f,
+ 1.0f);
+
+ prop = RNA_def_int(ot->srna,
+ "target_faces",
+ 1,
+ 1,
+ INT_MAX,
+ "Number of Faces",
+ "Approximate number of faces (quads) in the new mesh",
+ 1,
+ INT_MAX);
+
+ prop = RNA_def_float(
+ ot->srna,
+ "mesh_area",
+ -1.0f,
+ -FLT_MAX,
+ FLT_MAX,
+ "Old Object Face Area",
+ "This property is only used to cache the object area for later calculations",
+ 0.0f,
+ FLT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ RNA_def_int(ot->srna,
+ "seed",
+ 0,
+ 0,
+ INT_MAX,
+ "Seed",
+ "Random seed to use with the solver. Different seeds will cause the remesher to "
+ "come up with different quad layouts on the mesh",
+ 0,
+ 255);
+}
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 2a8b306b085..b534e1b9683 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -711,7 +711,7 @@ static int apply_objects_internal(bContext *C,
return OPERATOR_CANCELLED;
}
- for (int object_index = 0; object_index < num_objects; ++object_index) {
+ for (int object_index = 0; object_index < num_objects; object_index++) {
Object *ob = objects[object_index];
/* calculate rotation/scale matrix */
@@ -1086,7 +1086,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
/* reset flags */
- for (int object_index = 0; object_index < num_objects; ++object_index) {
+ for (int object_index = 0; object_index < num_objects; object_index++) {
Object *ob = objects[object_index];
ob->flag &= ~OB_DONE;
@@ -1106,7 +1106,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
}
- for (int object_index = 0; object_index < num_objects; ++object_index) {
+ for (int object_index = 0; object_index < num_objects; object_index++) {
Object *ob = objects[object_index];
if ((ob->flag & OB_DONE) == 0) {
@@ -1411,7 +1411,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
//{
/* use existing context looper */
- for (int other_object_index = 0; other_object_index < num_objects; ++other_object_index) {
+ for (int other_object_index = 0; other_object_index < num_objects; other_object_index++) {
Object *ob_other = objects[other_object_index];
if ((ob_other->flag & OB_DONE) == 0 &&
@@ -1679,7 +1679,7 @@ static void object_apply_location(Object *ob, const float loc[3])
}
static void object_orient_to_location(Object *ob,
- float rot_orig[3][3],
+ const float rot_orig[3][3],
const float axis[3],
const float location[3])
{
@@ -1715,8 +1715,9 @@ static void object_transform_axis_target_cancel(bContext *C, wmOperator *op)
static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
if (vc.obact == NULL || !object_is_target_compat(vc.obact)) {
/* Falls back to texture space transform. */
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 08fe5e818b2..d703cdfecb3 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -1319,8 +1319,8 @@ static void moveCloserToDistanceFromPlane(Depsgraph *depsgraph,
Object *ob,
Mesh *me,
int index,
- float norm[3],
- float coord[3],
+ const float norm[3],
+ const float coord[3],
float d,
float distToBe,
float strength,
@@ -3794,7 +3794,7 @@ static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr)
const bDeformGroup *def_a = def_a_ptr;
const bDeformGroup *def_b = def_b_ptr;
- return BLI_natstrcmp(def_a->name, def_b->name);
+ return BLI_strcasecmp_natural(def_a->name, def_b->name);
}
/**
diff --git a/source/blender/editors/object/object_warp.c b/source/blender/editors/object/object_warp.c
index 3a089acb330..836e38e3676 100644
--- a/source/blender/editors/object/object_warp.c
+++ b/source/blender/editors/object/object_warp.c
@@ -43,7 +43,7 @@
static void object_warp_calc_view_matrix(float r_mat_view[4][4],
float r_center_view[3],
Object *obedit,
- float viewmat[4][4],
+ const float viewmat[4][4],
const float center[3],
const float offset_angle)
{
@@ -62,7 +62,7 @@ static void object_warp_calc_view_matrix(float r_mat_view[4][4],
}
static void object_warp_transverts_minmax_x(TransVertStore *tvs,
- float mat_view[4][4],
+ const float mat_view[4][4],
const float center_view[3],
float *r_min,
float *r_max)
@@ -90,7 +90,7 @@ static void object_warp_transverts_minmax_x(TransVertStore *tvs,
}
static void object_warp_transverts(TransVertStore *tvs,
- float mat_view[4][4],
+ const float mat_view[4][4],
const float center_view[3],
const float angle_,
const float min,
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 68506c8addb..2ea0e9dc018 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -93,6 +93,7 @@
bool PE_poll(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
@@ -100,7 +101,7 @@ bool PE_poll(bContext *C)
return false;
}
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (edit == NULL) {
return false;
}
@@ -113,6 +114,7 @@ bool PE_poll(bContext *C)
bool PE_hair_poll(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
@@ -120,7 +122,7 @@ bool PE_hair_poll(bContext *C)
return false;
}
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (edit == NULL || edit->psys == NULL) {
return false;
}
@@ -149,8 +151,7 @@ void PE_free_ptcache_edit(PTCacheEdit *edit)
}
if (edit->points) {
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (point->keys) {
MEM_freeN(point->keys);
}
@@ -356,9 +357,9 @@ static PTCacheEdit *pe_get_current(Depsgraph *depsgraph, Scene *scene, Object *o
return edit;
}
-PTCacheEdit *PE_get_current(Scene *scene, Object *ob)
+PTCacheEdit *PE_get_current(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- return pe_get_current(NULL, scene, ob, 0);
+ return pe_get_current(depsgraph, scene, ob, 0);
}
PTCacheEdit *PE_create_current(Depsgraph *depsgraph, Scene *scene, Object *ob)
@@ -380,10 +381,8 @@ void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
KEY_K;
if (pset->flag & PE_FADE_TIME && pset->selectmode == SCE_SELECT_POINT) {
- LOOP_POINTS
- {
- LOOP_KEYS
- {
+ LOOP_POINTS {
+ LOOP_KEYS {
if (fabsf(cfra - *key->time) < pset->fade_frames) {
key->flag &= ~PEK_HIDE;
}
@@ -395,10 +394,8 @@ void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
}
}
else {
- LOOP_POINTS
- {
- LOOP_KEYS
- {
+ LOOP_POINTS {
+ LOOP_KEYS {
key->flag &= ~PEK_HIDE;
}
}
@@ -466,14 +463,15 @@ static void PE_set_data(bContext *C, PEData *data)
data->view_layer = CTX_data_view_layer(C);
data->ob = CTX_data_active_object(C);
data->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- data->edit = PE_get_current(data->scene, data->ob);
+ data->edit = PE_get_current(data->depsgraph, data->scene, data->ob);
}
static void PE_set_view3d_data(bContext *C, PEData *data)
{
PE_set_data(C, data);
- ED_view3d_viewcontext_init(C, &data->vc);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ED_view3d_viewcontext_init(C, &data->vc, depsgraph);
if (!XRAY_ENABLED(data->vc.v3d)) {
if (data->vc.v3d->flag & V3D_INVALID_BACKBUF) {
@@ -633,8 +631,7 @@ static bool point_is_selected(PTCacheEditPoint *point)
return 0;
}
- LOOP_SELECTED_KEYS
- {
+ LOOP_SELECTED_KEYS {
return 1;
}
@@ -649,8 +646,8 @@ typedef void (*ForHitPointFunc)(PEData *data, int point_index, float mouse_dista
typedef void (*ForKeyFunc)(PEData *data, int point_index, int key_index, bool is_inside);
typedef void (*ForKeyMatFunc)(PEData *data,
- float mat[4][4],
- float imat[4][4],
+ const float mat[4][4],
+ const float imat[4][4],
int point_index,
int key_index,
PTCacheEditKey *key);
@@ -684,8 +681,7 @@ static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, const enum ePartic
nearest_point = -1;
nearest_key = -1;
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
if (pset->selectmode == SCE_SELECT_END) {
if (point->totkey) {
/* only do end keys */
@@ -707,8 +703,7 @@ static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, const enum ePartic
}
else {
/* do all keys */
- LOOP_VISIBLE_KEYS
- {
+ LOOP_VISIBLE_KEYS {
if (flag & PSEL_NEAREST) {
if (key_inside_circle(data, dist, KEY_WCO, &dist)) {
nearest_point = p;
@@ -745,8 +740,7 @@ static void foreach_mouse_hit_point(PEData *data, ForHitPointFunc func, int sele
selected = 0;
}
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
if (pset->selectmode == SCE_SELECT_END) {
if (point->totkey) {
/* only do end keys */
@@ -762,8 +756,7 @@ static void foreach_mouse_hit_point(PEData *data, ForHitPointFunc func, int sele
}
else {
/* do all keys */
- LOOP_VISIBLE_KEYS
- {
+ LOOP_VISIBLE_KEYS {
if (selected == 0 || key->flag & PEK_SELECT) {
float mouse_distance;
if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) {
@@ -823,8 +816,7 @@ static void foreach_mouse_hit_key_iter(void *__restrict iter_data_v,
/* do all keys */
PTCacheEditKey *key;
int k;
- LOOP_VISIBLE_KEYS
- {
+ LOOP_VISIBLE_KEYS {
if (selected == 0 || key->flag & PEK_SELECT) {
float mouse_distance;
if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) {
@@ -866,8 +858,7 @@ static void foreach_selected_point(PEData *data, ForPointFunc func)
PTCacheEdit *edit = data->edit;
POINT_P;
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
func(data, p);
}
}
@@ -878,10 +869,8 @@ static void foreach_selected_key(PEData *data, ForKeyFunc func)
POINT_P;
KEY_K;
- LOOP_VISIBLE_POINTS
- {
- LOOP_SELECTED_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_SELECTED_KEYS {
func(data, p, k, true);
}
}
@@ -892,8 +881,7 @@ static void foreach_point(PEData *data, ForPointFunc func)
PTCacheEdit *edit = data->edit;
POINT_P;
- LOOP_POINTS
- {
+ LOOP_POINTS {
func(data, p);
}
}
@@ -905,11 +893,9 @@ static int count_selected_keys(Scene *scene, PTCacheEdit *edit)
KEY_K;
int sel = 0;
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
if (pset->selectmode == SCE_SELECT_POINT) {
- LOOP_SELECTED_KEYS
- {
+ LOOP_SELECTED_KEYS {
sel++;
}
}
@@ -1117,8 +1103,7 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
/* we delay settings the PARS_EDIT_RECALC for mirrored particles
* to avoid doing mirror twice */
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (point->flag & PEP_EDIT_RECALC) {
PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
@@ -1128,8 +1113,7 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
}
}
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (point->flag & PEP_EDIT_RECALC) {
if (edit->mirror_cache[p] != -1) {
edit->points[edit->mirror_cache[p]].flag |= PEP_EDIT_RECALC;
@@ -1173,13 +1157,11 @@ static void deflect_emitter_iter(void *__restrict iter_data_v,
psys_mat_hair_to_object(
object, psmd_eval->mesh_final, psys->part->from, psys->particles + iter, hairmat);
- LOOP_KEYS
- {
+ LOOP_KEYS {
mul_m4_v3(hairmat, key->co);
}
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (k == 0) {
dist_1st = len_v3v3((key + 1)->co, key->co);
dist_1st *= dist * emitterdist;
@@ -1215,8 +1197,7 @@ static void deflect_emitter_iter(void *__restrict iter_data_v,
invert_m4_m4(hairimat, hairmat);
- LOOP_KEYS
- {
+ LOOP_KEYS {
mul_m4_v3(hairimat, key->co);
}
}
@@ -1268,8 +1249,7 @@ static void apply_lengths_iter(void *__restrict iter_data_v,
}
PTCacheEditKey *key;
int k;
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (k) {
float dv1[3];
sub_v3_v3v3(dv1, key->co, (key - 1)->co);
@@ -1377,7 +1357,7 @@ static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
BLI_task_parallel_range(0, edit->totpoint, &iter_data, iterate_lengths_iter, &settings);
}
-/* set current distances to be kept between neighbouting keys */
+/* set current distances to be kept between neighboring keys */
void recalc_lengths(PTCacheEdit *edit)
{
POINT_P;
@@ -1387,8 +1367,7 @@ void recalc_lengths(PTCacheEdit *edit)
return;
}
- LOOP_EDITED_POINTS
- {
+ LOOP_EDITED_POINTS {
key = point->keys;
for (k = 0; k < point->totkey - 1; k++, key++) {
key->length = len_v3v3(key->co, (key + 1)->co);
@@ -1461,15 +1440,14 @@ void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), Part
static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob, int useflag)
{
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
HairKey *hkey;
POINT_P;
KEY_K;
/* flag all particles to be updated if not using flag */
if (!useflag) {
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->flag |= PEP_EDIT_RECALC;
}
}
@@ -1477,11 +1455,9 @@ static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob,
/* flush edit key flag to hair key flag to preserve selection
* on save */
if (edit->psys) {
- LOOP_POINTS
- {
+ LOOP_POINTS {
hkey = edit->psys->particles[p].hair;
- LOOP_KEYS
- {
+ LOOP_KEYS {
hkey->editflag = key->flag;
hkey++;
}
@@ -1491,8 +1467,7 @@ static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob,
psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering);
/* disable update flag */
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->flag &= ~PEP_EDIT_RECALC;
}
@@ -1511,15 +1486,13 @@ void update_world_cos(Object *ob, PTCacheEdit *edit)
return;
}
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
psys_mat_hair_to_global(
ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, hairmat);
}
- LOOP_KEYS
- {
+ LOOP_KEYS {
copy_v3_v3(key->world_co, key->co);
if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
mul_m4_v3(hairmat, key->world_co);
@@ -1541,10 +1514,8 @@ static void update_velocities(PTCacheEdit *edit)
frs_sec = edit->pid.flag & PTCACHE_VEL_PER_SEC ? 25.0f : 1.0f;
- LOOP_EDITED_POINTS
- {
- LOOP_KEYS
- {
+ LOOP_EDITED_POINTS {
+ LOOP_KEYS {
if (k == 0) {
dfra = *(key + 1)->time - *key->time;
@@ -1596,7 +1567,7 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla
/* use this to do partial particle updates, not usable when adding or
* removing, then a full redo is necessary and calling this may crash */
ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
POINT_P;
if (!edit) {
@@ -1605,8 +1576,7 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla
/* flag all particles to be updated if not using flag */
if (!useflag) {
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->flag |= PEP_EDIT_RECALC;
}
}
@@ -1624,14 +1594,19 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla
if (pset->flag & PE_AUTO_VELOCITY) {
update_velocities(edit);
}
- PE_hide_keys_time(scene, edit, CFRA);
+
+ /* Only do this for emitter particles because drawing PE_FADE_TIME is not respected in 2.8 yet
+ * and flagging with PEK_HIDE will prevent selection. This might get restored once this is
+ * supported in drawing (but doesn't make much sense for hair anyways). */
+ if (edit->psys->part->type == PART_EMITTER) {
+ PE_hide_keys_time(scene, edit, CFRA);
+ }
/* regenerate path caches */
psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering);
/* disable update flag */
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->flag &= ~PEP_EDIT_RECALC;
}
@@ -1686,8 +1661,7 @@ static void select_keys(PEData *data,
PTCacheEditPoint *point = edit->points + point_index;
KEY_K;
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (data->select) {
key->flag |= PEK_SELECT;
}
@@ -1780,17 +1754,15 @@ static int pe_select_all_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
POINT_P;
KEY_K;
int action = RNA_enum_get(op->ptr, "action");
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
- LOOP_VISIBLE_POINTS
- {
- LOOP_SELECTED_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_SELECTED_KEYS {
action = SEL_DESELECT;
break;
}
@@ -1802,10 +1774,8 @@ static int pe_select_all_exec(bContext *C, wmOperator *op)
}
bool changed = false;
- LOOP_VISIBLE_POINTS
- {
- LOOP_VISIBLE_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_VISIBLE_KEYS {
changed |= select_action_apply(point, key, action);
}
}
@@ -1841,7 +1811,7 @@ bool PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool desele
PEData data;
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(data.depsgraph, scene, ob);
POINT_P;
KEY_K;
@@ -1850,10 +1820,8 @@ bool PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool desele
}
if (!extend && !deselect && !toggle) {
- LOOP_VISIBLE_POINTS
- {
- LOOP_SELECTED_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_SELECTED_KEYS {
key->flag &= ~PEK_SELECT;
point->flag |= PEP_EDIT_RECALC;
}
@@ -2029,6 +1997,7 @@ static const EnumPropertyItem select_random_type_items[] = {
static int select_random_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
PEData data;
int type;
@@ -2048,26 +2017,22 @@ static int select_random_exec(bContext *C, wmOperator *op)
PE_set_data(C, &data);
data.select_action = SEL_SELECT;
- edit = PE_get_current(data.scene, data.ob);
+ edit = PE_get_current(depsgraph, data.scene, data.ob);
rng = BLI_rng_new_srandom(seed);
switch (type) {
case RAN_HAIR:
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT;
- LOOP_KEYS
- {
+ LOOP_KEYS {
data.is_changed |= select_action_apply(point, key, flag);
}
}
break;
case RAN_POINTS:
- LOOP_VISIBLE_POINTS
- {
- LOOP_VISIBLE_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_VISIBLE_KEYS {
int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT;
data.is_changed |= select_action_apply(point, key, flag);
}
@@ -2166,10 +2131,8 @@ bool PE_deselect_all_visible_ex(PTCacheEdit *edit)
POINT_P;
KEY_K;
- LOOP_VISIBLE_POINTS
- {
- LOOP_SELECTED_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_SELECTED_KEYS {
if ((key->flag & PEK_SELECT) != 0) {
key->flag &= ~PEK_SELECT;
point->flag |= PEP_EDIT_RECALC;
@@ -2182,9 +2145,10 @@ bool PE_deselect_all_visible_ex(PTCacheEdit *edit)
bool PE_deselect_all_visible(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (!PE_start_edit(edit)) {
return false;
}
@@ -2193,9 +2157,10 @@ bool PE_deselect_all_visible(bContext *C)
bool PE_box_select(bContext *C, const rcti *rect, const int sel_op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
PEData data;
if (!PE_start_edit(edit)) {
@@ -2229,9 +2194,10 @@ bool PE_box_select(bContext *C, const rcti *rect, const int sel_op)
bool PE_circle_select(bContext *C, const int sel_op, const int mval[2], float rad)
{
BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB));
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
PEData data;
if (!PE_start_edit(edit)) {
@@ -2260,11 +2226,12 @@ bool PE_circle_select(bContext *C, const int sel_op, const int mval[2], float ra
int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const int sel_op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
ARegion *ar = CTX_wm_region(C);
ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
POINT_P;
@@ -2287,16 +2254,14 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const
data.is_changed |= PE_deselect_all_visible_ex(edit);
}
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
if (edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
psys_mat_hair_to_global(
ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
}
if (pset->selectmode == SCE_SELECT_POINT) {
- LOOP_KEYS
- {
+ LOOP_VISIBLE_KEYS {
copy_v3_v3(co, key->co);
mul_m4_v3(mat, co);
const bool is_select = key->flag & PEK_SELECT;
@@ -2350,30 +2315,26 @@ static int hide_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
POINT_P;
KEY_K;
- if (RNA_enum_get(op->ptr, "unselected")) {
- LOOP_UNSELECTED_POINTS
- {
+ if (RNA_boolean_get(op->ptr, "unselected")) {
+ LOOP_UNSELECTED_POINTS {
point->flag |= PEP_HIDE;
point->flag |= PEP_EDIT_RECALC;
- LOOP_KEYS
- {
+ LOOP_KEYS {
key->flag &= ~PEK_SELECT;
}
}
}
else {
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
point->flag |= PEP_HIDE;
point->flag |= PEP_EDIT_RECALC;
- LOOP_KEYS
- {
+ LOOP_KEYS {
key->flag &= ~PEK_SELECT;
}
}
@@ -2410,19 +2371,17 @@ static int reveal_exec(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
const bool select = RNA_boolean_get(op->ptr, "select");
POINT_P;
KEY_K;
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (point->flag & PEP_HIDE) {
point->flag &= ~PEP_HIDE;
point->flag |= PEP_EDIT_RECALC;
- LOOP_KEYS
- {
+ LOOP_KEYS {
SET_FLAG_FROM_TEST(key->flag, select, PEK_SELECT);
}
}
@@ -2460,8 +2419,7 @@ static void select_less_keys(PEData *data, int point_index)
PTCacheEditPoint *point = edit->points + point_index;
KEY_K;
- LOOP_SELECTED_KEYS
- {
+ LOOP_SELECTED_KEYS {
if (k == 0) {
if (((key + 1)->flag & PEK_SELECT) == 0) {
key->flag |= PEK_TAG;
@@ -2479,8 +2437,7 @@ static void select_less_keys(PEData *data, int point_index)
}
}
- LOOP_KEYS
- {
+ LOOP_KEYS {
if ((key->flag & PEK_TAG) && (key->flag & PEK_SELECT)) {
key->flag &= ~(PEK_TAG | PEK_SELECT);
point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
@@ -2525,8 +2482,7 @@ static void select_more_keys(PEData *data, int point_index)
PTCacheEditPoint *point = edit->points + point_index;
KEY_K;
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (key->flag & PEK_SELECT) {
continue;
}
@@ -2548,8 +2504,7 @@ static void select_more_keys(PEData *data, int point_index)
}
}
- LOOP_KEYS
- {
+ LOOP_KEYS {
if ((key->flag & PEK_TAG) && (key->flag & PEK_SELECT) == 0) {
key->flag &= ~PEK_TAG;
key->flag |= PEK_SELECT;
@@ -2694,7 +2649,8 @@ void PARTICLE_OT_rekey(wmOperatorType *ot)
static void rekey_particle_to_time(
const bContext *C, Scene *scene, Object *ob, int pa_index, float path_time)
{
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys;
ParticleSimulationData sim = {0};
ParticleData *pa;
@@ -2709,7 +2665,7 @@ static void rekey_particle_to_time(
psys = edit->psys;
- sim.depsgraph = CTX_data_depsgraph_pointer(C);
+ sim.depsgraph = depsgraph;
sim.scene = scene;
sim.ob = ob;
sim.psys = psys;
@@ -2758,14 +2714,12 @@ static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror)
/* mirror tags */
psmd_eval = edit->psmd_eval;
- LOOP_TAGGED_POINTS
- {
+ LOOP_TAGGED_POINTS {
PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
}
}
- LOOP_TAGGED_POINTS
- {
+ LOOP_TAGGED_POINTS {
new_totpart--;
removed++;
}
@@ -2850,21 +2804,17 @@ static void remove_tagged_keys(Depsgraph *depsgraph, Object *ob, ParticleSystem
ParticleSystemModifierData *psmd_eval = (ParticleSystemModifierData *)modifier_get_evaluated(
depsgraph, ob, &psmd->modifier);
- LOOP_POINTS
- {
- LOOP_TAGGED_KEYS
- {
+ LOOP_POINTS {
+ LOOP_TAGGED_KEYS {
PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
break;
}
}
}
- LOOP_POINTS
- {
+ LOOP_POINTS {
new_totkey = point->totkey;
- LOOP_TAGGED_KEYS
- {
+ LOOP_TAGGED_KEYS {
new_totkey--;
}
/* we can't have elements with less than two keys*/
@@ -2874,13 +2824,11 @@ static void remove_tagged_keys(Depsgraph *depsgraph, Object *ob, ParticleSystem
}
remove_tagged_particles(ob, psys, pe_x_mirror(ob));
- LOOP_POINTS
- {
+ LOOP_POINTS {
pa = psys->particles + p;
new_totkey = pa->totkey;
- LOOP_TAGGED_KEYS
- {
+ LOOP_TAGGED_KEYS {
new_totkey--;
}
@@ -2889,8 +2837,7 @@ static void remove_tagged_keys(Depsgraph *depsgraph, Object *ob, ParticleSystem
nkey = new_keys = MEM_callocN(new_totkey * sizeof(PTCacheEditKey), "particle edit keys");
hkey = pa->hair;
- LOOP_KEYS
- {
+ LOOP_KEYS {
while (key->flag & PEK_TAG && hkey < pa->hair + pa->totkey) {
key++;
hkey++;
@@ -3062,9 +3009,10 @@ void PARTICLE_OT_subdivide(wmOperatorType *ot)
static int remove_doubles_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd_eval;
KDTree_3d *tree;
@@ -3087,8 +3035,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
tree = BLI_kdtree_3d_new(psys->totpart);
/* insert particles into kd tree */
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
psys_mat_hair_to_object(
ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
copy_v3_v3(co, point->keys->co);
@@ -3099,8 +3046,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
BLI_kdtree_3d_balance(tree);
/* tag particles to be removed */
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
psys_mat_hair_to_object(
ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
copy_v3_v3(co, point->keys->co);
@@ -3130,7 +3076,11 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BKE_reportf(op->reports, RPT_INFO, "Removed %d double particles", totremoved);
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ totremoved == 1 ? "Removed %d double particle" :
+ "Removed %d double particles",
+ totremoved);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
@@ -3166,10 +3116,11 @@ void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
static int weight_set_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ParticleEditSettings *pset = PE_settings(scene);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys = edit->psys;
POINT_P;
KEY_K;
@@ -3181,12 +3132,10 @@ static int weight_set_exec(bContext *C, wmOperator *op)
weight = brush->strength;
edit = psys->edit;
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
ParticleData *pa = psys->particles + p;
- LOOP_SELECTED_KEYS
- {
+ LOOP_SELECTED_KEYS {
hkey = pa->hair + k;
hkey->weight = interpf(weight, hkey->weight, factor);
}
@@ -3315,6 +3264,7 @@ static int delete_exec(bContext *C, wmOperator *op)
}
DEG_id_tag_update(&data.ob->id, ID_RECALC_GEOMETRY);
+ BKE_particle_batch_cache_dirty_tag(data.edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, data.ob);
return OPERATOR_FINISHED;
@@ -3346,11 +3296,11 @@ void PARTICLE_OT_delete(wmOperatorType *ot)
/*************************** mirror operator **************************/
-static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
+static void PE_mirror_x(Depsgraph *depsgraph, Scene *scene, Object *ob, int tagged)
{
Mesh *me = (Mesh *)(ob->data);
ParticleSystemModifierData *psmd_eval;
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys = edit->psys;
ParticleData *pa, *newpa, *new_pars;
PTCacheEditPoint *newpoint, *new_points;
@@ -3386,8 +3336,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
totpart = psys->totpart;
newtotpart = psys->totpart;
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
pa = psys->particles + p;
if (!tagged) {
@@ -3503,8 +3452,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
}
}
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->flag &= ~PEP_TAG;
}
@@ -3513,14 +3461,18 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
static int mirror_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
- PE_mirror_x(scene, ob, 0);
+ PE_mirror_x(depsgraph, scene, ob, 0);
update_world_cos(ob, edit);
+ psys_free_path_cache(NULL, edit);
+
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
+ BKE_particle_batch_cache_dirty_tag(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
return OPERATOR_FINISHED;
@@ -3681,8 +3633,7 @@ static void brush_length(PEData *data, int point_index, float UNUSED(mouse_dista
KEY_K;
float dvec[3], pvec[3] = {0.0f, 0.0f, 0.0f};
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (k == 0) {
copy_v3_v3(pvec, key->co);
}
@@ -3731,8 +3682,7 @@ static void brush_puff(PEData *data, int point_index, float mouse_distance)
unit_m4(imat);
}
- LOOP_KEYS
- {
+ LOOP_KEYS {
float kco[3];
if (k == 0) {
@@ -4504,10 +4454,11 @@ typedef struct BrushEdit {
static int brush_edit_init(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ARegion *ar = CTX_wm_region(C);
BrushEdit *bedit;
float min[3], max[3];
@@ -4518,7 +4469,7 @@ static int brush_edit_init(bContext *C, wmOperator *op)
/* set the 'distance factor' for grabbing (used in comb etc) */
INIT_MINMAX(min, max);
- PE_minmax(scene, view_layer, min, max);
+ PE_minmax(depsgraph, scene, view_layer, min, max);
mid_v3_v3v3(min, min, max);
bedit = MEM_callocN(sizeof(BrushEdit), "BrushEdit");
@@ -4744,7 +4695,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
if (ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_CUT) && (added || removed)) {
if (pset->brushtype == PE_BRUSH_ADD && pe_x_mirror(ob)) {
- PE_mirror_x(scene, ob, 1);
+ PE_mirror_x(depsgraph, scene, ob, 1);
}
update_world_cos(ob, edit);
@@ -4993,10 +4944,11 @@ static void shape_cut(PEData *data, int pa_index)
static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
Object *shapeob = pset->shape_object;
int selected = count_selected_keys(scene, edit);
int lock_root = pset->flag & PE_LOCK_FIRST;
@@ -5074,10 +5026,11 @@ void PARTICLE_OT_shape_cut(wmOperatorType *ot)
/************************ utilities ******************************/
-int PE_minmax(Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
+int PE_minmax(
+ Depsgraph *depsgraph, Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
{
Object *ob = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys;
ParticleSystemModifierData *psmd_eval = NULL;
POINT_P;
@@ -5096,15 +5049,13 @@ int PE_minmax(Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
unit_m4(mat);
}
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
if (psys) {
psys_mat_hair_to_global(
ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
}
- LOOP_SELECTED_KEYS
- {
+ LOOP_SELECTED_KEYS {
copy_v3_v3(co, key->co);
mul_m4_v3(mat, co);
DO_MINMAX(co, min, max);
@@ -5181,15 +5132,13 @@ void PE_create_particle_edit(
BLI_listbase_clear(&edit->pathcachebufs);
pa = psys->particles;
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->totkey = pa->totkey;
point->keys = MEM_callocN(point->totkey * sizeof(PTCacheEditKey), "ParticleEditKeys");
point->flag |= PEP_EDIT_RECALC;
hkey = pa->hair;
- LOOP_KEYS
- {
+ LOOP_KEYS {
key->co = hkey->co;
key->time = &hkey->time;
key->flag = hkey->editflag;
@@ -5217,8 +5166,7 @@ void PE_create_particle_edit(
}
for (pm = cache->mem_cache.first; pm; pm = pm->next) {
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (BKE_ptcache_mem_pointers_seek(p, pm) == 0) {
continue;
}
@@ -5421,8 +5369,7 @@ static float calculate_point_length(PTCacheEditPoint *point)
{
float length = 0.0f;
KEY_K;
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (k > 0) {
length += len_v3v3((key - 1)->co, key->co);
}
@@ -5435,10 +5382,9 @@ static float calculate_average_length(PTCacheEdit *edit)
int num_selected = 0;
float total_length = 0;
POINT_P;
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
total_length += calculate_point_length(point);
- ++num_selected;
+ num_selected++;
}
if (num_selected == 0) {
return 0.0f;
@@ -5450,8 +5396,7 @@ static void scale_point_factor(PTCacheEditPoint *point, float factor)
{
float orig_prev_co[3], prev_co[3];
KEY_K;
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (k == 0) {
copy_v3_v3(orig_prev_co, key->co);
copy_v3_v3(prev_co, key->co);
@@ -5484,8 +5429,7 @@ static void scale_point_to_length(PTCacheEditPoint *point, float length)
static void scale_points_to_length(PTCacheEdit *edit, float length)
{
POINT_P;
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
scale_point_to_length(point, length);
}
recalc_lengths(edit);
@@ -5497,7 +5441,7 @@ static int unify_length_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
float average_length = calculate_average_length(edit);
if (average_length == 0.0f) {
diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c
index 40d90676487..aee79523c87 100644
--- a/source/blender/editors/physics/particle_edit_undo.c
+++ b/source/blender/editors/physics/particle_edit_undo.c
@@ -109,8 +109,7 @@ static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
POINT_P;
KEY_K;
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (psys && psys->particles[p].hair) {
MEM_freeN(psys->particles[p].hair);
}
@@ -133,8 +132,7 @@ static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
edit->points = MEM_dupallocN(undo->points);
edit->totpoint = undo->totpoint;
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->keys = MEM_dupallocN(point->keys);
}
@@ -143,13 +141,11 @@ static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
psys->totpart = undo->totpoint;
- LOOP_POINTS
- {
+ LOOP_POINTS {
pa = psys->particles + p;
hkey = pa->hair = MEM_dupallocN(pa->hair);
- LOOP_KEYS
- {
+ LOOP_KEYS {
key->co = hkey->co;
key->time = &hkey->time;
hkey++;
@@ -174,10 +170,8 @@ static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
}
BKE_ptcache_mem_pointers_init(pm);
- LOOP_POINTS
- {
- LOOP_KEYS
- {
+ LOOP_POINTS {
+ LOOP_KEYS {
if ((int)key->ftime == (int)pm->frame) {
key->co = pm->cur[BPHYS_DATA_LOCATION];
key->vel = pm->cur[BPHYS_DATA_VELOCITY];
@@ -228,10 +222,11 @@ typedef struct ParticleUndoStep {
static bool particle_undosys_poll(struct bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
return (edit != NULL);
}
@@ -240,11 +235,12 @@ static bool particle_undosys_step_encode(struct bContext *C,
struct Main *UNUSED(bmain),
UndoStep *us_p)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
ParticleUndoStep *us = (ParticleUndoStep *)us_p;
ViewLayer *view_layer = CTX_data_view_layer(C);
us->scene_ref.ptr = CTX_data_scene(C);
us->object_ref.ptr = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(us->scene_ref.ptr, us->object_ref.ptr);
+ PTCacheEdit *edit = PE_get_current(depsgraph, us->scene_ref.ptr, us->object_ref.ptr);
undoptcache_from_editcache(&us->data, edit);
return true;
}
@@ -255,6 +251,7 @@ static void particle_undosys_step_decode(struct bContext *C,
int UNUSED(dir),
bool UNUSED(is_final))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
/* TODO(campbell): undo_system: use low-level API to set mode. */
ED_object_mode_set(C, OB_MODE_PARTICLE_EDIT);
BLI_assert(particle_undosys_poll(C));
@@ -262,7 +259,7 @@ static void particle_undosys_step_decode(struct bContext *C,
ParticleUndoStep *us = (ParticleUndoStep *)us_p;
Scene *scene = us->scene_ref.ptr;
Object *ob = us->object_ref.ptr;
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (edit) {
undoptcache_to_editcache(&us->data, edit);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index bb8a31966ef..cfb3a400f47 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -704,8 +704,8 @@ static bool remap_hair_emitter(Depsgraph *depsgraph,
Object *target_ob,
ParticleSystem *target_psys,
PTCacheEdit *target_edit,
- float from_mat[4][4],
- float to_mat[4][4],
+ const float from_mat[4][4],
+ const float to_mat[4][4],
bool from_global,
bool to_global)
{
@@ -1017,13 +1017,11 @@ static void copy_particle_edit(Depsgraph *depsgraph,
edit->points = MEM_dupallocN(edit_from->points);
pa = psys->particles;
- LOOP_POINTS
- {
+ LOOP_POINTS {
HairKey *hkey = pa->hair;
point->keys = MEM_dupallocN(point->keys);
- LOOP_KEYS
- {
+ LOOP_KEYS {
key->co = hkey->co;
key->time = &hkey->time;
key->flag = hkey->editflag;
@@ -1116,7 +1114,7 @@ static bool copy_particle_systems_to_object(const bContext *C,
tmp_psys = MEM_mallocN(sizeof(ParticleSystem *) * totpsys, "temporary particle system array");
- for (psys_from = PSYS_FROM_FIRST, i = 0; psys_from; psys_from = PSYS_FROM_NEXT(psys_from), ++i) {
+ for (psys_from = PSYS_FROM_FIRST, i = 0; psys_from; psys_from = PSYS_FROM_NEXT(psys_from), i++) {
psys = BKE_object_copy_particlesystem(psys_from, 0);
tmp_psys[i] = psys;
@@ -1140,6 +1138,7 @@ static bool copy_particle_systems_to_object(const bContext *C,
/* append to the object */
BLI_addtail(&ob_to->particlesystem, psys);
+ psys_unique_name(ob_to, psys, psys->name);
/* add a particle system modifier for each system */
md = modifier_new(eModifierType_ParticleSystem);
@@ -1167,7 +1166,7 @@ static bool copy_particle_systems_to_object(const bContext *C,
* the remapping otherwise makes final_dm invalid!
*/
for (psys = psys_start, psys_from = PSYS_FROM_FIRST, i = 0; psys;
- psys = psys->next, psys_from = PSYS_FROM_NEXT(psys_from), ++i) {
+ psys = psys->next, psys_from = PSYS_FROM_NEXT(psys_from), i++) {
float(*from_mat)[4], (*to_mat)[4];
switch (space) {
diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c
index a1d76174cc8..4b1d51ee6c2 100644
--- a/source/blender/editors/physics/rigidbody_constraint.c
+++ b/source/blender/editors/physics/rigidbody_constraint.c
@@ -81,14 +81,7 @@ static bool ED_operator_rigidbody_con_add_poll(bContext *C)
ID_IS_LINKED(&scene->rigidbody_world->constraints->id))) {
return false;
}
-
- if (ED_operator_object_active_editable(C)) {
- Object *ob = ED_object_active_context(C);
- return (ob && ob->type == OB_MESH);
- }
- else {
- return false;
- }
+ return ED_operator_object_active_editable(C);
}
bool ED_rigidbody_constraint_add(
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 55a71ee8989..053ca3d8f9f 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -80,8 +80,6 @@
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
-#include "GPU_shader.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index b6601807443..3e001ef25b5 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -1296,7 +1296,7 @@ static void icon_preview_endjob(void *customdata)
int i;
/* signal to gpu texture */
- for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ for (i = 0; i < NUM_ICON_SIZES; i++) {
if (prv_img->gputexture[i]) {
GPU_texture_free(prv_img->gputexture[i]);
prv_img->gputexture[i] = NULL;
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index 82e4d577777..3918737d560 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -194,7 +194,7 @@ void ED_render_engine_changed(Main *bmain)
update_ctx.scene = scene;
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
/* TDODO(sergey): Iterate over depsgraphs instead? */
- update_ctx.depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ update_ctx.depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
update_ctx.view_layer = view_layer;
ED_render_id_flush_update(&update_ctx, &scene->id);
}
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index 3154d5d0985..6873495e962 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -36,6 +36,8 @@
#include "BKE_screen.h"
#include "BKE_report.h"
+#include "BLT_translation.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -137,11 +139,11 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
SpaceImage *sima;
bool area_was_image = false;
- if (scene->r.displaymode == R_OUTPUT_NONE) {
+ if (U.render_display_type == USER_RENDER_DISPLAY_NONE) {
return NULL;
}
- if (scene->r.displaymode == R_OUTPUT_WINDOW) {
+ if (U.render_display_type == USER_RENDER_DISPLAY_WINDOW) {
int sizex = 30 * UI_DPI_FAC + (scene->r.xsch * scene->r.size) / 100;
int sizey = 60 * UI_DPI_FAC + (scene->r.ysch * scene->r.size) / 100;
@@ -154,14 +156,15 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
}
/* changes context! */
- if (WM_window_open_temp(C, mx, my, sizex, sizey, WM_WINDOW_RENDER) == NULL) {
+ if (WM_window_open_temp(C, IFACE_("Blender Render"), mx, my, sizex, sizey, SPACE_IMAGE) ==
+ NULL) {
BKE_report(reports, RPT_ERROR, "Failed to open window!");
return NULL;
}
sa = CTX_wm_area(C);
}
- else if (scene->r.displaymode == R_OUTPUT_SCREEN) {
+ else if (U.render_display_type == USER_RENDER_DISPLAY_SCREEN) {
sa = CTX_wm_area(C);
/* if the active screen is already in fullscreen mode, skip this and
diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c
index b04719d7782..7705278443f 100644
--- a/source/blender/editors/scene/scene_edit.c
+++ b/source/blender/editors/scene/scene_edit.c
@@ -29,21 +29,16 @@
#include "BKE_global.h"
#include "BKE_layer.h"
#include "BKE_library.h"
-#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_scene.h"
-#include "BKE_workspace.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "BLT_translation.h"
-#include "DNA_object_types.h"
-#include "DNA_workspace_types.h"
-
#include "ED_object.h"
#include "ED_render.h"
#include "ED_scene.h"
@@ -121,7 +116,7 @@ bool ED_scene_delete(bContext *C, Main *bmain, Scene *scene)
/* Depsgraph updates after scene becomes active in a window. */
void ED_scene_change_update(Main *bmain, Scene *scene, ViewLayer *layer)
{
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, layer, true);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, layer, true);
BKE_scene_set_background(bmain, scene);
DEG_graph_relations_update(depsgraph, bmain, scene, layer);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index a0f493d0011..c068fbdf7cb 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -30,6 +30,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_rand.h"
#include "BLI_utildefines.h"
#include "BLI_linklist_stack.h"
@@ -55,13 +56,11 @@
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
-#include "GPU_draw.h"
#include "GPU_state.h"
#include "GPU_framebuffer.h"
#include "BLF_api.h"
-#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_metadata.h"
@@ -544,20 +543,20 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
region_draw_azones(sa, ar);
/* for debugging unneeded area redraws and partial redraw */
-#if 0
- GPU_blend(true);
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor4f(drand48(), drand48(), drand48(), 0.1f);
- immRectf(pos,
- ar->drawrct.xmin - ar->winrct.xmin,
- ar->drawrct.ymin - ar->winrct.ymin,
- ar->drawrct.xmax - ar->winrct.xmin,
- ar->drawrct.ymax - ar->winrct.ymin);
- immUnbindProgram();
- GPU_blend(false);
-#endif
+ if (G.debug_value == 888) {
+ GPU_blend(true);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4f(BLI_thread_frand(0), BLI_thread_frand(0), BLI_thread_frand(0), 0.1f);
+ immRectf(pos,
+ ar->drawrct.xmin - ar->winrct.xmin,
+ ar->drawrct.ymin - ar->winrct.ymin,
+ ar->drawrct.xmax - ar->winrct.xmin,
+ ar->drawrct.ymax - ar->winrct.ymin);
+ immUnbindProgram();
+ GPU_blend(false);
+ }
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
@@ -813,7 +812,7 @@ static void area_azone_initialize(wmWindow *win, const bScreen *screen, ScrArea
return;
}
- float coords[4][4] = {
+ const float coords[4][4] = {
/* Bottom-left. */
{sa->totrct.xmin - U.pixelsize,
sa->totrct.ymin - U.pixelsize,
@@ -1265,9 +1264,6 @@ static void region_rect_recursive(
else if (ED_area_is_global(sa)) {
prefsizey = ED_region_global_size_y();
}
- else if (ar->regiontype == RGN_TYPE_UI && sa->spacetype == SPACE_FILE) {
- prefsizey = UI_UNIT_Y * 2 + (UI_UNIT_Y / 2);
- }
else {
prefsizey = UI_DPI_FAC * (ar->sizey > 1 ? ar->sizey + 0.5f : ar->type->prefsizey);
}
@@ -1831,7 +1827,7 @@ void ED_region_cursor_set(wmWindow *win, ScrArea *sa, ARegion *ar)
if (WM_cursor_set_from_tool(win, sa, ar)) {
return;
}
- WM_cursor_set(win, CURSOR_STD);
+ WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
}
@@ -2438,7 +2434,7 @@ void ED_region_panels_layout_ex(const bContext *C,
* instead they calculate offsets for the next panel to start drawing. */
Panel *panel = ar->panels.last;
if (panel != NULL) {
- int size_dyn[2] = {
+ const int size_dyn[2] = {
UI_UNIT_X * ((panel->flag & PNL_CLOSED) ? 8 : 14) / UI_DPI_FAC,
UI_panel_size_y(panel) / UI_DPI_FAC,
};
diff --git a/source/blender/editors/screen/area_query.c b/source/blender/editors/screen/area_query.c
index 420d70e63fb..46559efc614 100644
--- a/source/blender/editors/screen/area_query.c
+++ b/source/blender/editors/screen/area_query.c
@@ -28,8 +28,6 @@
#include "RNA_types.h"
-#include "WM_api.h"
-
#include "ED_screen.h"
#include "UI_interface.h"
diff --git a/source/blender/editors/screen/area_utils.c b/source/blender/editors/screen/area_utils.c
index 1a99210b73d..61fb9d5a3a8 100644
--- a/source/blender/editors/screen/area_utils.c
+++ b/source/blender/editors/screen/area_utils.c
@@ -28,7 +28,6 @@
#include "RNA_access.h"
#include "RNA_types.h"
-#include "WM_api.h"
#include "WM_message.h"
#include "ED_screen.h"
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index af1e0eeed79..dc435efd86b 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -24,8 +24,6 @@
#include <stdio.h>
#include <string.h>
-#include "MEM_guardedalloc.h"
-
#include "DNA_userdef_types.h"
#include "DNA_vec_types.h"
@@ -41,7 +39,10 @@
#include "GPU_immediate.h"
#include "GPU_matrix.h"
-#include "GPU_state.h"
+
+#ifdef __APPLE__
+# include "GPU_state.h"
+#endif
#include "UI_interface.h"
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 6f8b25f782b..f7742c5e50a 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -29,36 +29,28 @@
#include "DNA_object_types.h"
#include "DNA_armature_types.h"
-#include "DNA_brush_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_sequence_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
-#include "DNA_workspace_types.h"
#include "BLI_utildefines.h"
-#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_object.h"
#include "BKE_action.h"
#include "BKE_armature.h"
-#include "BKE_paint.h"
#include "BKE_gpencil.h"
#include "BKE_layer.h"
#include "BKE_sequencer.h"
-#include "BKE_workspace.h"
-
-#include "DEG_depsgraph.h"
#include "RNA_access.h"
#include "ED_armature.h"
#include "ED_gpencil.h"
#include "ED_anim_api.h"
-#include "ED_uvedit.h"
#include "WM_api.h"
#include "UI_interface.h"
diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c
index 1124070486f..316604156de 100644
--- a/source/blender/editors/screen/screen_draw.c
+++ b/source/blender/editors/screen/screen_draw.c
@@ -32,9 +32,7 @@
#include "BLI_rect.h"
#include "WM_api.h"
-#include "WM_types.h"
-#include "UI_interface.h"
#include "UI_resources.h"
#include "screen_intern.h"
@@ -273,8 +271,8 @@ static GPUBatch *batch_screen_edges_get(int *corner_len)
GPU_vertbuf_data_alloc(vbo, CORNER_RESOLUTION * 2 * 4 + 2);
uint vidx = 0;
- for (int corner = 0; corner < 4; ++corner) {
- for (int c = 0; c < CORNER_RESOLUTION; ++c) {
+ for (int corner = 0; corner < 4; corner++) {
+ for (int c = 0; c < CORNER_RESOLUTION; c++) {
do_vert_pair(vbo, pos, &vidx, corner, c);
}
}
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 326bbbd8770..c8008fe3cc7 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -41,20 +41,18 @@
#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
-#include "BKE_node.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
+#include "BKE_sound.h"
#include "BKE_workspace.h"
#include "WM_api.h"
#include "WM_types.h"
-#include "ED_object.h"
#include "ED_screen.h"
#include "ED_screen_types.h"
#include "ED_clip.h"
#include "ED_node.h"
-#include "ED_render.h"
#include "UI_interface.h"
@@ -292,33 +290,45 @@ void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new)
/* used with join operator */
int area_getorientation(ScrArea *sa, ScrArea *sb)
{
- ScrVert *sav1, *sav2, *sav3, *sav4;
- ScrVert *sbv1, *sbv2, *sbv3, *sbv4;
-
if (sa == NULL || sb == NULL) {
return -1;
}
- sav1 = sa->v1;
- sav2 = sa->v2;
- sav3 = sa->v3;
- sav4 = sa->v4;
- sbv1 = sb->v1;
- sbv2 = sb->v2;
- sbv3 = sb->v3;
- sbv4 = sb->v4;
+ ScrVert *saBL = sa->v1;
+ ScrVert *saTL = sa->v2;
+ ScrVert *saTR = sa->v3;
+ ScrVert *saBR = sa->v4;
- if (sav1 == sbv4 && sav2 == sbv3) { /* sa to right of sb = W */
- return 0;
+ ScrVert *sbBL = sb->v1;
+ ScrVert *sbTL = sb->v2;
+ ScrVert *sbTR = sb->v3;
+ ScrVert *sbBR = sb->v4;
+
+ int tolerance = U.pixelsize * 4;
+
+ if (saBL->vec.x == sbBR->vec.x && saTL->vec.x == sbTR->vec.x) { /* sa to right of sb = W */
+ if ((ABS(saBL->vec.y - sbBR->vec.y) <= tolerance) &&
+ (ABS(saTL->vec.y - sbTR->vec.y) <= tolerance)) {
+ return 0;
+ }
}
- else if (sav2 == sbv1 && sav3 == sbv4) { /* sa to bottom of sb = N */
- return 1;
+ else if (saTL->vec.y == sbBL->vec.y && saTR->vec.y == sbBR->vec.y) { /* sa to bottom of sb = N */
+ if ((ABS(saTL->vec.x - sbBL->vec.x) <= tolerance) &&
+ (ABS(saTR->vec.x - sbBR->vec.x) <= tolerance)) {
+ return 1;
+ }
}
- else if (sav3 == sbv2 && sav4 == sbv1) { /* sa to left of sb = E */
- return 2;
+ else if (saTR->vec.x == sbTL->vec.x && saBR->vec.x == sbBL->vec.x) { /* sa to left of sb = E */
+ if ((ABS(saTR->vec.y - sbTL->vec.y) <= tolerance) &&
+ (ABS(saBR->vec.y - sbBL->vec.y) <= tolerance)) {
+ return 2;
+ }
}
- else if (sav1 == sbv2 && sav4 == sbv3) { /* sa on top of sb = S*/
- return 3;
+ else if (saBL->vec.y == sbTL->vec.y && saBR->vec.y == sbTR->vec.y) { /* sa on top of sb = S*/
+ if ((ABS(saBL->vec.x - sbTL->vec.x) <= tolerance) &&
+ (ABS(saBR->vec.x - sbTR->vec.x) <= tolerance)) {
+ return 3;
+ }
}
return -1;
@@ -329,36 +339,50 @@ int area_getorientation(ScrArea *sa, ScrArea *sb)
*/
int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2)
{
- int dir;
-
- dir = area_getorientation(sa1, sa2);
- /*printf("dir is : %i\n", dir);*/
+ int dir = area_getorientation(sa1, sa2);
if (dir == -1) {
return 0;
}
- if (dir == 0) {
- sa1->v1 = sa2->v1;
- sa1->v2 = sa2->v2;
+ /* Align areas if they are not. Do sanity checking before getting here. */
+
+ if (dir == 0 || dir == 2) {
+ /* horizontal join, so vertically align source vert to target */
+ sa2->v1->vec.y = sa1->v1->vec.y; /* vertical align sa1 BL */
+ sa2->v2->vec.y = sa1->v2->vec.y; /* vertical align sa1 TL */
+ sa2->v3->vec.y = sa1->v3->vec.y; /* vertical align sa1 TR */
+ sa2->v4->vec.y = sa1->v4->vec.y; /* vertical align sa1 BR */
+ }
+ else {
+ /* vertical join, so horizontally align source verts to target */
+ sa2->v1->vec.x = sa1->v1->vec.x; /* vertical align sa1 BL */
+ sa2->v2->vec.x = sa1->v2->vec.x; /* vertical align sa1 TL */
+ sa2->v3->vec.x = sa1->v3->vec.x; /* vertical align sa1 TR */
+ sa2->v4->vec.x = sa1->v4->vec.x; /* vertical align sa1 BR */
+ }
+
+ if (dir == 0) { /* sa1 to right of sa2 = W */
+ sa1->v1 = sa2->v1; /* BL */
+ sa1->v2 = sa2->v2; /* TL */
screen_geom_edge_add(scr, sa1->v2, sa1->v3);
screen_geom_edge_add(scr, sa1->v1, sa1->v4);
}
- else if (dir == 1) {
- sa1->v2 = sa2->v2;
- sa1->v3 = sa2->v3;
+ else if (dir == 1) { /* sa1 to bottom of sa2 = N */
+ sa1->v2 = sa2->v2; /* TL */
+ sa1->v3 = sa2->v3; /* TR */
screen_geom_edge_add(scr, sa1->v1, sa1->v2);
screen_geom_edge_add(scr, sa1->v3, sa1->v4);
}
- else if (dir == 2) {
- sa1->v3 = sa2->v3;
- sa1->v4 = sa2->v4;
+ else if (dir == 2) { /* sa1 to left of sa2 = E */
+ sa1->v3 = sa2->v3; /* TR */
+ sa1->v4 = sa2->v4; /* BR */
screen_geom_edge_add(scr, sa1->v2, sa1->v3);
screen_geom_edge_add(scr, sa1->v1, sa1->v4);
}
- else if (dir == 3) {
- sa1->v1 = sa2->v1;
- sa1->v4 = sa2->v4;
+ else if (dir == 3) { /* sa1 on top of sa2 = S */
+ sa1->v1 = sa2->v1; /* BL */
+ sa1->v4 = sa2->v4; /* BR */
screen_geom_edge_add(scr, sa1->v1, sa1->v2);
screen_geom_edge_add(scr, sa1->v3, sa1->v4);
}
@@ -492,6 +516,17 @@ void ED_screen_ensure_updated(wmWindowManager *wm, wmWindow *win, bScreen *scree
}
}
+/**
+ * Utility to exit and free an area-region. Screen level regions (menus/popups) need to be treated
+ * slightly differently, see #ui_region_temp_remove().
+ */
+void ED_region_remove(bContext *C, ScrArea *sa, ARegion *ar)
+{
+ ED_region_exit(C, ar);
+ BKE_area_region_free(sa->type, ar);
+ BLI_freelinkN(&sa->regionbase, ar);
+}
+
/* *********** exit calls are for closing running stuff ******** */
void ED_region_exit(bContext *C, ARegion *ar)
@@ -557,6 +592,11 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
if (screen->animtimer) {
WM_event_remove_timer(wm, window, screen->animtimer);
+
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Scene *scene = WM_window_get_active_scene(prevwin);
+ Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id);
+ BKE_sound_stop_scene(scene_eval);
}
screen->animtimer = NULL;
screen->scrubbing = false;
@@ -604,14 +644,14 @@ static void screen_cursor_set(wmWindow *win, const int xy[2])
if (sa) {
if (az->type == AZONE_AREA) {
- WM_cursor_set(win, CURSOR_EDIT);
+ WM_cursor_set(win, WM_CURSOR_EDIT);
}
else if (az->type == AZONE_REGION) {
if (az->edge == AE_LEFT_TO_TOPRIGHT || az->edge == AE_RIGHT_TO_TOPLEFT) {
- WM_cursor_set(win, CURSOR_X_MOVE);
+ WM_cursor_set(win, WM_CURSOR_X_MOVE);
}
else {
- WM_cursor_set(win, CURSOR_Y_MOVE);
+ WM_cursor_set(win, WM_CURSOR_Y_MOVE);
}
}
}
@@ -620,14 +660,14 @@ static void screen_cursor_set(wmWindow *win, const int xy[2])
if (actedge) {
if (screen_geom_edge_is_horizontal(actedge)) {
- WM_cursor_set(win, CURSOR_Y_MOVE);
+ WM_cursor_set(win, WM_CURSOR_Y_MOVE);
}
else {
- WM_cursor_set(win, CURSOR_X_MOVE);
+ WM_cursor_set(win, WM_CURSOR_X_MOVE);
}
}
else {
- WM_cursor_set(win, CURSOR_STD);
+ WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
}
}
@@ -1320,6 +1360,53 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
return sc->areabase.first;
}
+/**
+ * Wrapper to open a temporary space either as fullscreen space, or as separate window, as defined
+ * by \a display_type.
+ *
+ * \param title: Title to set for the window, if a window is spawned.
+ * \param x, y: Position of the window, if a window is spawned.
+ * \param sizex, sizey: Dimensions of the window, if a window is spawned.
+ */
+ScrArea *ED_screen_temp_space_open(bContext *C,
+ const char *title,
+ int x,
+ int y,
+ int sizex,
+ int sizey,
+ eSpace_Type space_type,
+ int display_type)
+{
+ ScrArea *sa = NULL;
+
+ switch (display_type) {
+ case USER_TEMP_SPACE_DISPLAY_WINDOW:
+ if (WM_window_open_temp(C, title, x, y, sizex, sizey, (int)space_type)) {
+ sa = CTX_wm_area(C);
+ }
+ break;
+ case USER_TEMP_SPACE_DISPLAY_FULLSCREEN: {
+ ScrArea *ctx_sa = CTX_wm_area(C);
+
+ if (ctx_sa->full) {
+ sa = ctx_sa;
+ ED_area_newspace(C, ctx_sa, space_type, true);
+ /* we already had a fullscreen here -> mark new space as a stacked fullscreen */
+ sa->flag |= (AREA_FLAG_STACKED_FULLSCREEN | AREA_FLAG_TEMP_TYPE);
+ }
+ else if (ctx_sa->spacetype == space_type) {
+ sa = ED_screen_state_toggle(C, CTX_wm_window(C), ctx_sa, SCREENMAXIMIZED);
+ }
+ else {
+ sa = ED_screen_full_newspace(C, ctx_sa, (int)space_type);
+ }
+ break;
+ }
+ }
+
+ return sa;
+}
+
/* update frame rate info for viewport drawing */
void ED_refresh_viewport_fps(bContext *C)
{
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 417bdf84232..0b374617cce 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -38,7 +38,6 @@
#include "DNA_lattice_types.h"
#include "DNA_object_types.h"
#include "DNA_curve_types.h"
-#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
#include "DNA_meta_types.h"
#include "DNA_mesh_types.h"
@@ -48,7 +47,6 @@
#include "DNA_userdef_types.h"
#include "BKE_context.h"
-#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
@@ -1043,28 +1041,28 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, event->x, event->y) == sad->sa1) {
/* Same area, so possible split. */
WM_cursor_set(
- win, (ELEM(sad->gesture_dir, 'n', 's')) ? BC_V_SPLITCURSOR : BC_H_SPLITCURSOR);
+ win, (ELEM(sad->gesture_dir, 'n', 's')) ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT);
is_gesture = (delta_max > split_threshold);
}
else {
/* Different area, so possible join. */
if (sad->gesture_dir == 'n') {
- WM_cursor_set(win, BC_N_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_N_ARROW);
}
else if (sad->gesture_dir == 's') {
- WM_cursor_set(win, BC_S_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_S_ARROW);
}
else if (sad->gesture_dir == 'e') {
- WM_cursor_set(win, BC_E_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_E_ARROW);
}
else {
- WM_cursor_set(win, BC_W_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_W_ARROW);
}
is_gesture = (delta_max > join_threshold);
}
}
else {
- WM_cursor_set(CTX_wm_window(C), BC_CROSSCURSOR);
+ WM_cursor_set(CTX_wm_window(C), WM_CURSOR_CROSS);
is_gesture = false;
}
}
@@ -1229,7 +1227,7 @@ static int area_swap_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
/* add modal handler */
- WM_cursor_modal_set(CTX_wm_window(C), BC_SWAPAREA_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_SWAP_AREA);
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -2121,7 +2119,7 @@ static void area_split_preview_update_cursor(bContext *C, wmOperator *op)
{
wmWindow *win = CTX_wm_window(C);
int dir = RNA_enum_get(op->ptr, "direction");
- WM_cursor_set(win, (dir == 'n' || dir == 's') ? BC_V_SPLITCURSOR : BC_H_SPLITCURSOR);
+ WM_cursor_set(win, (dir == 'n' || dir == 's') ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT);
}
/* UI callback, adds new handler */
@@ -3363,7 +3361,9 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
sAreaJoinData *jd;
if (op->customdata == NULL) {
- area_join_init(C, op, NULL, NULL);
+ if (!area_join_init(C, op, NULL, NULL)) {
+ return OPERATOR_CANCELLED;
+ }
}
jd = (sAreaJoinData *)op->customdata;
@@ -3418,19 +3418,19 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (dir == 1) {
- WM_cursor_set(win, BC_N_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_N_ARROW);
}
else if (dir == 3) {
- WM_cursor_set(win, BC_S_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_S_ARROW);
}
else if (dir == 2) {
- WM_cursor_set(win, BC_E_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_E_ARROW);
}
else if (dir == 0) {
- WM_cursor_set(win, BC_W_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_W_ARROW);
}
else {
- WM_cursor_set(win, BC_STOPCURSOR);
+ WM_cursor_set(win, WM_CURSOR_STOP);
}
break;
@@ -3846,10 +3846,7 @@ static int region_quadview_exec(bContext *C, wmOperator *op)
for (ar = sa->regionbase.first; ar; ar = arn) {
arn = ar->next;
if (ar->alignment == RGN_ALIGN_QSPLIT) {
- ED_region_exit(C, ar);
- BKE_area_region_free(sa->type, ar);
- BLI_remlink(&sa->regionbase, ar);
- MEM_freeN(ar);
+ ED_region_remove(C, sa, ar);
}
}
ED_area_tag_redraw(sa);
@@ -3934,6 +3931,65 @@ static void SCREEN_OT_region_quadview(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Region Toggle Operator
+ * \{ */
+
+static int region_toggle_exec(bContext *C, wmOperator *op)
+{
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "region_type");
+ ARegion *region;
+
+ if (RNA_property_is_set(op->ptr, prop)) {
+ region = BKE_area_find_region_type(CTX_wm_area(C), RNA_property_enum_get(op->ptr, prop));
+ }
+ else {
+ region = CTX_wm_region(C);
+ }
+
+ if (region) {
+ ED_region_toggle_hidden(C, region);
+ }
+ ED_region_tag_redraw(region);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool region_toggle_poll(bContext *C)
+{
+ ScrArea *area = CTX_wm_area(C);
+
+ /* don't flip anything around in topbar */
+ if (area && area->spacetype == SPACE_TOPBAR) {
+ CTX_wm_operator_poll_msg_set(C, "Toggling regions in the Top-bar is not allowed");
+ return 0;
+ }
+
+ return ED_operator_areaactive(C);
+}
+
+static void SCREEN_OT_region_toggle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Toggle Region";
+ ot->idname = "SCREEN_OT_region_toggle";
+ ot->description = "Hide or unhide the region";
+
+ /* api callbacks */
+ ot->exec = region_toggle_exec;
+ ot->poll = region_toggle_poll;
+ ot->flag = 0;
+
+ RNA_def_enum(ot->srna,
+ "region_type",
+ rna_enum_region_type_items,
+ 0,
+ "Region Type",
+ "Type of the region to toggle");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Region Flip Operator
* \{ */
@@ -4298,7 +4354,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, false);
Scene *scene_eval = (depsgraph != NULL) ? DEG_get_evaluated_scene(depsgraph) : NULL;
wmTimer *wt = screen->animtimer;
ScreenAnimData *sad = wt->customdata;
@@ -4772,7 +4828,9 @@ static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *even
int sizey = 520 * UI_DPI_FAC;
/* changes context! */
- if (WM_window_open_temp(C, event->x, event->y, sizex, sizey, WM_WINDOW_USERPREFS) != NULL) {
+ if (WM_window_open_temp(
+ C, IFACE_("Blender Preferences"), event->x, event->y, sizex, sizey, SPACE_USERPREF) !=
+ NULL) {
/* The header only contains the editor switcher and looks empty.
* So hiding in the temp window makes sense. */
ScrArea *area = CTX_wm_area(C);
@@ -4821,7 +4879,11 @@ static int drivers_editor_show_invoke(bContext *C, wmOperator *op, const wmEvent
but = UI_context_active_but_prop_get(C, &ptr, &prop, &index);
/* changes context! */
- if (WM_window_open_temp(C, event->x, event->y, sizex, sizey, WM_WINDOW_DRIVERS) != NULL) {
+ if (WM_window_open_temp(
+ C, IFACE_("Blender Drivers Editor"), event->x, event->y, sizex, sizey, SPACE_GRAPH) !=
+ NULL) {
+ ED_drivers_editor_init(C, CTX_wm_area(C));
+
/* activate driver F-Curve for the property under the cursor */
if (but) {
FCurve *fcu;
@@ -4877,7 +4939,9 @@ static int info_log_show_invoke(bContext *C, wmOperator *op, const wmEvent *even
int shift_y = 480;
/* changes context! */
- if (WM_window_open_temp(C, event->x, event->y + shift_y, sizex, sizey, WM_WINDOW_INFO) != NULL) {
+ if (WM_window_open_temp(
+ C, IFACE_("Blender Info Log"), event->x, event->y + shift_y, sizex, sizey, SPACE_INFO) !=
+ NULL) {
return OPERATOR_FINISHED;
}
else {
@@ -5359,6 +5423,7 @@ void ED_operatortypes_screen(void)
WM_operatortype_append(SCREEN_OT_area_swap);
WM_operatortype_append(SCREEN_OT_region_quadview);
WM_operatortype_append(SCREEN_OT_region_scale);
+ WM_operatortype_append(SCREEN_OT_region_toggle);
WM_operatortype_append(SCREEN_OT_region_flip);
WM_operatortype_append(SCREEN_OT_header_toggle_menus);
WM_operatortype_append(SCREEN_OT_region_context_menu);
diff --git a/source/blender/editors/screen/screen_user_menu.c b/source/blender/editors/screen/screen_user_menu.c
index 26849edeb44..661c17f55d2 100644
--- a/source/blender/editors/screen/screen_user_menu.c
+++ b/source/blender/editors/screen/screen_user_menu.c
@@ -52,27 +52,43 @@
#include "RNA_access.h"
/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
+
+static const char *screen_menu_context_string(const bContext *C, const SpaceLink *sl)
+{
+ if (sl->spacetype == SPACE_NODE) {
+ const SpaceNode *snode = (const SpaceNode *)sl;
+ return snode->tree_idname;
+ }
+ return CTX_data_mode_string(C);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Menu Type
* \{ */
bUserMenu **ED_screen_user_menus_find(const bContext *C, uint *r_len)
{
SpaceLink *sl = CTX_wm_space_data(C);
- const char *context = CTX_data_mode_string(C);
if (sl == NULL) {
*r_len = 0;
return NULL;
}
+ const char *context_mode = CTX_data_mode_string(C);
+ const char *context = screen_menu_context_string(C, sl);
uint array_len = 3;
bUserMenu **um_array = MEM_calloc_arrayN(array_len, sizeof(*um_array), __func__);
um_array[0] = BKE_blender_user_menu_find(&U.user_menus, sl->spacetype, context);
um_array[1] = (sl->spacetype != SPACE_TOPBAR) ?
- BKE_blender_user_menu_find(&U.user_menus, SPACE_TOPBAR, context) :
+ BKE_blender_user_menu_find(&U.user_menus, SPACE_TOPBAR, context_mode) :
NULL;
um_array[2] = (sl->spacetype == SPACE_VIEW3D) ?
- BKE_blender_user_menu_find(&U.user_menus, SPACE_PROPERTIES, context) :
+ BKE_blender_user_menu_find(&U.user_menus, SPACE_PROPERTIES, context_mode) :
NULL;
*r_len = array_len;
@@ -82,7 +98,7 @@ bUserMenu **ED_screen_user_menus_find(const bContext *C, uint *r_len)
bUserMenu *ED_screen_user_menu_ensure(bContext *C)
{
SpaceLink *sl = CTX_wm_space_data(C);
- const char *context = CTX_data_mode_string(C);
+ const char *context = screen_menu_context_string(C, sl);
return BKE_blender_user_menu_ensure(&U.user_menus, sl->spacetype, context);
}
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
index 61b737589c8..bbb959c27ff 100644
--- a/source/blender/editors/screen/workspace_edit.c
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -29,18 +29,13 @@
#include "BKE_appdir.h"
#include "BKE_blendfile.h"
#include "BKE_context.h"
-#include "BKE_idcode.h"
-#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
-#include "BKE_report.h"
-#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_workspace.h"
#include "BLO_readfile.h"
-#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_workspace_types.h"
@@ -49,13 +44,9 @@
#include "ED_object.h"
#include "ED_screen.h"
-#include "MEM_guardedalloc.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
-#include "DEG_depsgraph.h"
-
#include "UI_interface.h"
#include "UI_resources.h"
@@ -63,7 +54,6 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "WM_toolsystem.h"
#include "screen_intern.h"
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 752a5c36010..a5cc262ddcd 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -31,6 +31,7 @@ set(INC
../../render/extern/include
../../windowmanager
../../../../intern/atomic
+ ../../../../intern/clog
../../../../intern/glew-mx
../../../../intern/guardedalloc
)
@@ -47,7 +48,6 @@ set(SRC
paint_image.c
paint_image_2d.c
paint_image_proj.c
- paint_image_undo.c
paint_mask.c
paint_ops.c
paint_stroke.c
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 65e10f98753..774d4ef09b1 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -45,13 +45,17 @@
#include "BKE_node.h"
#include "BKE_paint.h"
#include "BKE_colortools.h"
+#include "BKE_object.h"
#include "WM_api.h"
+#include "wm_cursors.h"
#include "IMB_imbuf_types.h"
#include "ED_view3d.h"
+#include "DEG_depsgraph.h"
+
#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
@@ -87,6 +91,7 @@ typedef struct CursorSnapshot {
GLuint overlay_texture;
int size;
int zoom;
+ int curve_preset;
} CursorSnapshot;
static TexSnapshot primary_snap = {0};
@@ -422,7 +427,8 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
int size;
const bool refresh = !cursor_snap.overlay_texture ||
- (overlay_flags & PAINT_OVERLAY_INVALID_CURVE) || cursor_snap.zoom != zoom;
+ (overlay_flags & PAINT_OVERLAY_INVALID_CURVE) || cursor_snap.zoom != zoom ||
+ cursor_snap.curve_preset != br->curve_preset;
init = (cursor_snap.overlay_texture != 0);
@@ -502,6 +508,7 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ cursor_snap.curve_preset = br->curve_preset;
BKE_paint_reset_overlay_invalid(PAINT_OVERLAY_INVALID_CURVE);
return 1;
@@ -602,7 +609,7 @@ static bool sculpt_get_brush_geometry(bContext *C,
/* Draw an overlay that shows what effect the brush's texture will
* have on brush strength */
-static void paint_draw_tex_overlay(UnifiedPaintSettings *ups,
+static bool paint_draw_tex_overlay(UnifiedPaintSettings *ups,
Brush *brush,
ViewContext *vc,
int x,
@@ -622,7 +629,7 @@ static void paint_draw_tex_overlay(UnifiedPaintSettings *ups,
if (!(mtex->tex) ||
!((mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) ||
(valid && ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_TILED)))) {
- return;
+ return false;
}
if (load_tex(brush, vc, zoom, col, primary)) {
@@ -728,18 +735,19 @@ static void paint_draw_tex_overlay(UnifiedPaintSettings *ups,
GPU_matrix_pop();
}
}
+ return true;
}
/* Draw an overlay that shows what effect the brush's texture will
* have on brush strength */
-static void paint_draw_cursor_overlay(
+static bool paint_draw_cursor_overlay(
UnifiedPaintSettings *ups, Brush *brush, ViewContext *vc, int x, int y, float zoom)
{
rctf quad;
/* check for overlay mode */
if (!(brush->overlay_flags & BRUSH_OVERLAY_CURSOR)) {
- return;
+ return false;
}
if (load_tex_cursor(brush, vc, zoom)) {
@@ -811,9 +819,10 @@ static void paint_draw_cursor_overlay(
GPU_matrix_pop();
}
}
+ return true;
}
-static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups,
+static bool paint_draw_alpha_overlay(UnifiedPaintSettings *ups,
Brush *brush,
ViewContext *vc,
int x,
@@ -824,6 +833,9 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups,
/* Color means that primary brush texture is colored and
* secondary is used for alpha/mask control. */
bool col = ELEM(mode, PAINT_MODE_TEXTURE_3D, PAINT_MODE_TEXTURE_2D, PAINT_MODE_VERTEX);
+
+ bool alpha_overlay_active = false;
+
eOverlayControlFlags flags = BKE_paint_get_overlay_flags();
gpuPushAttr(GPU_DEPTH_BUFFER_BIT | GPU_BLEND_BIT);
@@ -836,37 +848,43 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups,
/* Colored overlay should be drawn separately. */
if (col) {
if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY)) {
- paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, true, true);
+ alpha_overlay_active = paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, true, true);
}
if (!(flags & PAINT_OVERLAY_OVERRIDE_SECONDARY)) {
- paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, false);
+ alpha_overlay_active = paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, false);
}
if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR)) {
- paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
+ alpha_overlay_active = paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
}
}
else {
if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY) && (mode != PAINT_MODE_WEIGHT)) {
- paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, true);
+ alpha_overlay_active = paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, true);
}
if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR)) {
- paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
+ alpha_overlay_active = paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
}
}
GPU_matrix_pop();
gpuPopAttr();
+
+ return alpha_overlay_active;
}
-BLI_INLINE void draw_tri_point(
- unsigned int pos, float sel_col[4], float pivot_col[4], float *co, float width, bool selected)
+BLI_INLINE void draw_tri_point(unsigned int pos,
+ const float sel_col[4],
+ float pivot_col[4],
+ float *co,
+ float width,
+ bool selected)
{
immUniformColor4fv(selected ? sel_col : pivot_col);
GPU_line_width(3.0f);
float w = width / 2.0f;
- float tri[3][2] = {
+ const float tri[3][2] = {
{co[0], co[1] + w},
{co[0] - w, co[1] - w},
{co[0] + w, co[1] - w},
@@ -888,8 +906,12 @@ BLI_INLINE void draw_tri_point(
immEnd();
}
-BLI_INLINE void draw_rect_point(
- unsigned int pos, float sel_col[4], float handle_col[4], float *co, float width, bool selected)
+BLI_INLINE void draw_rect_point(unsigned int pos,
+ const float sel_col[4],
+ float handle_col[4],
+ float *co,
+ float width,
+ bool selected)
{
immUniformColor4fv(selected ? sel_col : handle_col);
@@ -1074,8 +1096,135 @@ static bool ommit_cursor_drawing(Paint *paint, ePaintMode mode, Brush *brush)
return true;
}
+static void cursor_draw_point_screen_space(
+ const uint gpuattr, const ARegion *ar, float true_location[3], float obmat[4][4], int size)
+{
+ float translation_vertex_cursor[3], location[3];
+ copy_v3_v3(location, true_location);
+ mul_m4_v3(obmat, location);
+ ED_view3d_project(ar, location, translation_vertex_cursor);
+ imm_draw_circle_fill_3d(
+ gpuattr, translation_vertex_cursor[0], translation_vertex_cursor[1], size, 10);
+}
+
+static void cursor_draw_tiling_preview(const uint gpuattr,
+ const ARegion *ar,
+ const float true_location[3],
+ Sculpt *sd,
+ Object *ob,
+ float radius)
+{
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ float orgLoc[3], location[3];
+ int dim, tile_pass = 0;
+ int start[3];
+ int end[3];
+ int cur[3];
+ const float *bbMin = bb->vec[0];
+ const float *bbMax = bb->vec[6];
+ const float *step = sd->paint.tile_offset;
+
+ copy_v3_v3(orgLoc, true_location);
+ for (dim = 0; dim < 3; dim++) {
+ if ((sd->paint.symmetry_flags & (PAINT_TILE_X << dim)) && step[dim] > 0) {
+ start[dim] = (bbMin[dim] - orgLoc[dim] - radius) / step[dim];
+ end[dim] = (bbMax[dim] - orgLoc[dim] + radius) / step[dim];
+ }
+ else {
+ start[dim] = end[dim] = 0;
+ }
+ }
+ copy_v3_v3_int(cur, start);
+ for (cur[0] = start[0]; cur[0] <= end[0]; cur[0]++) {
+ for (cur[1] = start[1]; cur[1] <= end[1]; cur[1]++) {
+ for (cur[2] = start[2]; cur[2] <= end[2]; cur[2]++) {
+ if (!cur[0] && !cur[1] && !cur[2]) {
+ /* skip tile at orgLoc, this was already handled before all others */
+ continue;
+ }
+ tile_pass++;
+ for (dim = 0; dim < 3; dim++) {
+ location[dim] = cur[dim] * step[dim] + orgLoc[dim];
+ }
+ cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3);
+ }
+ }
+ }
+}
+
+static void cursor_draw_point_with_symmetry(const uint gpuattr,
+ const ARegion *ar,
+ const float true_location[3],
+ Sculpt *sd,
+ Object *ob,
+ float radius)
+{
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ float location[3], symm_rot_mat[4][4];
+
+ for (int i = 0; i <= symm; i++) {
+ if (i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
+
+ /* Axis Symmetry */
+ flip_v3_v3(location, true_location, (char)i);
+ cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3);
+
+ /* Tiling */
+ cursor_draw_tiling_preview(gpuattr, ar, location, sd, ob, radius);
+
+ /* Radial Symmetry */
+ for (char raxis = 0; raxis < 3; raxis++) {
+ for (int r = 1; r < sd->radial_symm[raxis]; r++) {
+ float angle = 2 * M_PI * r / sd->radial_symm[(int)raxis];
+ flip_v3_v3(location, true_location, (char)i);
+ unit_m4(symm_rot_mat);
+ rotate_m4(symm_rot_mat, raxis + 'X', angle);
+ mul_m4_v3(symm_rot_mat, location);
+
+ cursor_draw_tiling_preview(gpuattr, ar, location, sd, ob, radius);
+ cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3);
+ }
+ }
+ }
+ }
+}
+
+static void sculpt_geometry_preview_lines_draw(const uint gpuattr, SculptSession *ss)
+{
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.6f);
+
+ /* Cursor normally draws on top, but for this part we need depth tests. */
+ const bool depth_test = GPU_depth_test_enabled();
+ if (!depth_test) {
+ GPU_depth_test(true);
+ }
+
+ GPU_line_width(1.0f);
+ if (ss->preview_vert_index_count > 0) {
+ immBegin(GPU_PRIM_LINES, ss->preview_vert_index_count);
+ for (int i = 0; i < ss->preview_vert_index_count; i++) {
+ immVertex3fv(gpuattr, sculpt_vertex_co_get(ss, ss->preview_vert_index_list[i]));
+ }
+ immEnd();
+ }
+
+ /* Restore depth test value. */
+ if (!depth_test) {
+ GPU_depth_test(false);
+ }
+}
+
+static bool paint_use_2d_cursor(ePaintMode mode)
+{
+ if (mode >= PAINT_MODE_TEXTURE_3D) {
+ return true;
+ }
+ return false;
+}
+
static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
@@ -1083,6 +1232,9 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
Brush *brush = BKE_paint_brush(paint);
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+ /* 2d or 3d painting? */
+ const bool use_2d_cursor = paint_use_2d_cursor(mode);
+
/* check that brush drawing is enabled */
if (ommit_cursor_drawing(paint, mode, brush)) {
return;
@@ -1091,7 +1243,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* can't use stroke vc here because this will be called during
* mouse over too, not just during a stroke */
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
if (vc.rv3d && (vc.rv3d->rflag & RV3D_NAVIGATING)) {
return;
@@ -1109,7 +1261,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* set various defaults */
const float *outline_col = brush->add_col;
- const float outline_alpha = 0.5f;
+ const float outline_alpha = 0.7f;
float translation[2] = {x, y};
float final_radius = (BKE_brush_size_get(scene, brush) * zoomx);
@@ -1121,34 +1273,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
}
/* draw overlay */
- paint_draw_alpha_overlay(ups, brush, &vc, x, y, zoomx, mode);
-
- /* TODO: as sculpt and other paint modes are unified, this
- * special mode of drawing will go away */
- if ((mode == PAINT_MODE_SCULPT) && vc.obact->sculpt) {
- float location[3];
- int pixel_radius;
-
- /* test if brush is over the mesh */
- bool hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location, ups);
-
- if (BKE_brush_use_locked_size(scene, brush)) {
- BKE_brush_size_set(scene, brush, pixel_radius);
- }
-
- /* check if brush is subtracting, use different color then */
- /* TODO: no way currently to know state of pen flip or
- * invert key modifier without starting a stroke */
- if (((ups->draw_inverted == 0) ^ ((brush->flag & BRUSH_DIR_IN) == 0)) &&
- BKE_brush_sculpt_has_secondary_color(brush)) {
- outline_col = brush->sub_col;
- }
-
- /* only do if brush is over the mesh */
- if (hit) {
- paint_cursor_on_hit(ups, brush, &vc, location);
- }
- }
+ bool alpha_overlay_active = paint_draw_alpha_overlay(ups, brush, &vc, x, y, zoomx, mode);
if (ups->draw_anchored) {
final_radius = ups->anchored_size;
@@ -1158,25 +1283,243 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
}
/* make lines pretty */
- GPU_line_width(1.0f);
+ GPU_line_width(2.0f);
GPU_blend(true); /* TODO: also set blend mode? */
GPU_line_smooth(true);
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ if (use_2d_cursor) {
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3fvAlpha(outline_col, outline_alpha);
+
+ /* draw brush outline */
+ if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) {
+ imm_draw_circle_wire_2d(
+ pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
+ /* outer at half alpha */
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
+ }
+
+ GPU_line_width(1.0f);
+ imm_draw_circle_wire_2d(pos, translation[0], translation[1], final_radius, 40);
+ }
+ else { /* 3d painting */
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ /* TODO: as sculpt and other paint modes are unified, this
+ * special mode of drawing will go away */
+ Object *obact = vc.obact;
+ SculptSession *ss = obact ? obact->sculpt : NULL;
+ if ((mode == PAINT_MODE_SCULPT) && ss) {
+ float location[3];
+ int pixel_radius;
+
+ /* test if brush is over the mesh */
+ bool hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location, ups);
+
+ if (BKE_brush_use_locked_size(scene, brush)) {
+ BKE_brush_size_set(scene, brush, pixel_radius);
+ }
+
+ /* check if brush is subtracting, use different color then */
+ /* TODO: no way currently to know state of pen flip or
+ * invert key modifier without starting a stroke */
+ if (((ups->draw_inverted == 0) ^ ((brush->flag & BRUSH_DIR_IN) == 0)) &&
+ BKE_brush_sculpt_has_secondary_color(brush)) {
+ outline_col = brush->sub_col;
+ }
+
+ /* only do if brush is over the mesh */
+ if (hit) {
+ paint_cursor_on_hit(ups, brush, &vc, location);
+ }
+ }
+
+ immUniformColor3fvAlpha(outline_col, outline_alpha);
+
+ if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) {
+ imm_draw_circle_wire_3d(
+ pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
+ /* outer at half alpha */
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
+ }
+
+ /* Only sculpt mode cursor for now */
+ /* Disable for PBVH_GRIDS */
+ bool is_multires = ss && ss->pbvh && BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS;
- /* set brush color */
- immUniformColor3fvAlpha(outline_col, outline_alpha);
+ SculptCursorGeometryInfo gi;
+ float mouse[2] = {x - ar->winrct.xmin, y - ar->winrct.ymin};
+ int prev_active_vertex_index = -1;
+ bool is_cursor_over_mesh = false;
- /* draw brush outline */
- if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) {
- /* inner at full alpha */
- imm_draw_circle_wire_2d(
- pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
- /* outer at half alpha */
- immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
+ /* Update the active vertex */
+ if ((mode == PAINT_MODE_SCULPT) && ss && !ups->stroke_active) {
+ prev_active_vertex_index = ss->active_vertex_index;
+ is_cursor_over_mesh = sculpt_cursor_geometry_info_update(
+ C, &gi, mouse, !(brush->falloff_shape & BRUSH_AIRBRUSH));
+ }
+ /* Use special paint crosshair cursor in all paint modes*/
+ wmWindow *win = CTX_wm_window(C);
+ WM_cursor_set(win, WM_CURSOR_PAINT);
+
+ if ((mode == PAINT_MODE_SCULPT) && ss && !(brush->falloff_shape & BRUSH_AIRBRUSH)) {
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+
+ if (!ups->stroke_active) {
+ bool update_previews = false;
+ if (is_cursor_over_mesh && !alpha_overlay_active) {
+
+ if (prev_active_vertex_index != ss->active_vertex_index) {
+ update_previews = true;
+ }
+
+ float rds;
+ if (!BKE_brush_use_locked_size(scene, brush)) {
+ rds = paint_calc_object_space_radius(
+ &vc, gi.location, BKE_brush_size_get(scene, brush));
+ }
+ else {
+ rds = BKE_brush_unprojected_radius_get(scene, brush);
+ }
+
+ wmViewport(&ar->winrct);
+
+ /* Draw 3D active vertex preview with symmetry*/
+ if (len_v3v3(gi.active_vertex_co, gi.location) < rds) {
+ cursor_draw_point_with_symmetry(pos, ar, gi.active_vertex_co, sd, vc.obact, rds);
+ }
+
+ /* Draw pose brush origin */
+ if (brush->sculpt_tool == SCULPT_TOOL_POSE && !is_multires) {
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
+ if (update_previews) {
+ BKE_sculpt_update_object_for_edit(depsgraph, vc.obact, true, false);
+ sculpt_pose_calc_pose_data(
+ sd, vc.obact, ss, gi.location, rds, brush->pose_offset, ss->pose_origin, NULL);
+ }
+ cursor_draw_point_screen_space(pos, ar, ss->pose_origin, vc.obact->obmat, 5);
+ }
+
+ /* Draw 3D brush cursor */
+ GPU_matrix_push_projection();
+ ED_view3d_draw_setup_view(CTX_wm_window(C),
+ CTX_data_depsgraph_pointer(C),
+ CTX_data_scene(C),
+ ar,
+ CTX_wm_view3d(C),
+ NULL,
+ NULL,
+ NULL);
+
+ float cursor_trans[4][4], cursor_rot[4][4];
+ float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
+ float quat[4];
+
+ copy_m4_m4(cursor_trans, vc.obact->obmat);
+ translate_m4(cursor_trans, gi.location[0], gi.location[1], gi.location[2]);
+ rotation_between_vecs_to_quat(quat, z_axis, gi.normal);
+ quat_to_mat4(cursor_rot, quat);
+
+ GPU_matrix_push();
+ GPU_matrix_mul(cursor_trans);
+ GPU_matrix_mul(cursor_rot);
+ immUniformColor3fvAlpha(outline_col, outline_alpha);
+ GPU_line_width(2.0f);
+ imm_draw_circle_wire_3d(pos, 0, 0, rds, 80);
+ GPU_line_width(1.0f);
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
+ imm_draw_circle_wire_3d(pos, 0, 0, rds * clamp_f(brush->alpha, 0.0f, 1.0f), 80);
+ GPU_matrix_pop();
+
+ /* Update and draw dynamic mesh preview lines */
+ GPU_matrix_push();
+ GPU_matrix_mul(vc.obact->obmat);
+ if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) &&
+ !is_multires) {
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->modifiers_active) {
+ sculpt_geometry_preview_lines_update(C, ss, rds);
+ sculpt_geometry_preview_lines_draw(pos, ss);
+ }
+ }
+
+ /* Draw pose brush line preview */
+ if (brush->sculpt_tool == SCULPT_TOOL_POSE && !is_multires) {
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
+ GPU_line_width(2.0f);
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(pos, ss->pose_origin);
+ immVertex3fv(pos, gi.location);
+ immEnd();
+ }
+
+ GPU_matrix_pop();
+
+ GPU_matrix_pop_projection();
+
+ wmWindowViewport(win);
+ }
+ else {
+ /* Draw default cursor when the mouse is not over the mesh or there are no supported
+ * overlays active */
+ GPU_line_width(1.0f);
+ /* Reduce alpha to increase the contrast when the cursor is over the mesh */
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.8);
+ imm_draw_circle_wire_3d(pos, translation[0], translation[1], final_radius, 80);
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.35f);
+ imm_draw_circle_wire_3d(pos,
+ translation[0],
+ translation[1],
+ final_radius * clamp_f(brush->alpha, 0.0f, 1.0f),
+ 80);
+ }
+ }
+ else {
+ if (vc.obact->sculpt->cache && !vc.obact->sculpt->cache->first_time) {
+ /* Draw cursor location preview when the stroke is active using the data from StrokeCache
+ */
+ float cursor_location[3];
+ wmViewport(&ar->winrct);
+ copy_v3_v3(cursor_location, ss->cache->true_location);
+ if (ss->cache->brush->sculpt_tool == SCULPT_TOOL_GRAB) {
+ add_v3_v3(cursor_location, ss->cache->grab_delta);
+ }
+ cursor_draw_point_with_symmetry(
+ pos, ar, cursor_location, sd, vc.obact, ss->cache->radius);
+
+ /* Draw cached dynamic mesh preview lines */
+ if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) &&
+ !is_multires) {
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->modifiers_active) {
+ GPU_matrix_push_projection();
+ ED_view3d_draw_setup_view(CTX_wm_window(C),
+ CTX_data_depsgraph_pointer(C),
+ CTX_data_scene(C),
+ ar,
+ CTX_wm_view3d(C),
+ NULL,
+ NULL,
+ NULL);
+ GPU_matrix_push();
+ GPU_matrix_mul(vc.obact->obmat);
+ sculpt_geometry_preview_lines_draw(pos, ss);
+ GPU_matrix_pop();
+ GPU_matrix_pop_projection();
+ }
+ }
+
+ wmWindowViewport(win);
+ }
+ }
+ }
+ else {
+ /* Draw default cursor in unsupported modes */
+ GPU_line_width(1.0f);
+ imm_draw_circle_wire_3d(pos, translation[0], translation[1], final_radius, 40);
+ }
}
- imm_draw_circle_wire_2d(pos, translation[0], translation[1], final_radius, 40);
immUnbindProgram();
diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c
index d9fd194e96f..62c31c91f8d 100644
--- a/source/blender/editors/sculpt_paint/paint_curve.c
+++ b/source/blender/editors/sculpt_paint/paint_curve.c
@@ -35,8 +35,6 @@
#include "BKE_main.h"
#include "BKE_paint.h"
-#include "DEG_depsgraph.h"
-
#include "ED_view3d.h"
#include "ED_paint.h"
diff --git a/source/blender/editors/sculpt_paint/paint_curve_undo.c b/source/blender/editors/sculpt_paint/paint_curve_undo.c
index bd62a59e73f..c14ccd27804 100644
--- a/source/blender/editors/sculpt_paint/paint_curve_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_curve_undo.c
@@ -35,7 +35,6 @@
#include "ED_undo.h"
#include "WM_api.h"
-#include "WM_types.h"
#include "paint_intern.h"
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index 5852012891d..026dc39c668 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -37,7 +37,6 @@
#include "BKE_ccg.h"
#include "BKE_context.h"
#include "BKE_mesh.h"
-#include "BKE_mesh_runtime.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BKE_subsurf.h"
@@ -135,7 +134,6 @@ static void partialvis_update_grids(Depsgraph *depsgraph,
float planes[4][4])
{
CCGElem **grids;
- CCGKey key;
BLI_bitmap **grid_hidden;
int *grid_indices, totgrid, i;
bool any_changed = false, any_visible = false;
@@ -143,7 +141,7 @@ static void partialvis_update_grids(Depsgraph *depsgraph,
/* get PBVH data */
BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, NULL, &grids);
grid_hidden = BKE_pbvh_grid_hidden(pbvh);
- BKE_pbvh_get_grid_key(pbvh, &key);
+ CCGKey key = *BKE_pbvh_get_grid_key(pbvh);
sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
@@ -299,15 +297,17 @@ static void rect_from_props(rcti *rect, PointerRNA *ptr)
rect->ymax = RNA_int_get(ptr, "ymax");
}
-static void clip_planes_from_rect(bContext *C, float clip_planes[4][4], const rcti *rect)
+static void clip_planes_from_rect(bContext *C,
+ Depsgraph *depsgraph,
+ float clip_planes[4][4],
+ const rcti *rect)
{
ViewContext vc;
BoundBox bb;
view3d_operator_needs_opengl(C);
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ED_view3d_clipping_calc(&bb, clip_planes, vc.ar, vc.obact, rect);
- negate_m4(clip_planes);
}
/* If mode is inside, get all PBVH nodes that lie at least partially
@@ -322,17 +322,18 @@ static void get_pbvh_nodes(
/* select search callback */
switch (mode) {
case PARTIALVIS_INSIDE:
- cb = BKE_pbvh_node_planes_contain_AABB;
+ cb = BKE_pbvh_node_frustum_contain_AABB;
break;
case PARTIALVIS_OUTSIDE:
- cb = BKE_pbvh_node_planes_exclude_AABB;
+ cb = BKE_pbvh_node_frustum_exclude_AABB;
break;
case PARTIALVIS_ALL:
case PARTIALVIS_MASKED:
break;
}
- BKE_pbvh_search_gather(pbvh, cb, clip_planes, nodes, totnode);
+ PBVHFrustumPlanes frustum = {.planes = clip_planes, .num_planes = 4};
+ BKE_pbvh_search_gather(pbvh, cb, &frustum, nodes, totnode);
}
static int hide_show_exec(bContext *C, wmOperator *op)
@@ -355,7 +356,7 @@ static int hide_show_exec(bContext *C, wmOperator *op)
area = RNA_enum_get(op->ptr, "area");
rect_from_props(&rect, op->ptr);
- clip_planes_from_rect(C, clip_planes, &rect);
+ clip_planes_from_rect(C, depsgraph, clip_planes, &rect);
pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob);
BLI_assert(ob->sculpt->pbvh == pbvh);
@@ -363,6 +364,8 @@ static int hide_show_exec(bContext *C, wmOperator *op)
get_pbvh_nodes(pbvh, &nodes, &totnode, clip_planes, area);
pbvh_type = BKE_pbvh_type(pbvh);
+ negate_m4(clip_planes);
+
/* start undo */
switch (action) {
case PARTIALVIS_HIDE:
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index f3a6cfa0d5c..24c2dfb6c6b 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -113,10 +113,10 @@ void imapaint_region_tiles(
IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
- *tw = ((x + w - 1) >> IMAPAINT_TILE_BITS);
- *th = ((y + h - 1) >> IMAPAINT_TILE_BITS);
- *tx = (x >> IMAPAINT_TILE_BITS);
- *ty = (y >> IMAPAINT_TILE_BITS);
+ *tw = ((x + w - 1) >> ED_IMAGE_UNDO_TILE_BITS);
+ *th = ((y + h - 1) >> ED_IMAGE_UNDO_TILE_BITS);
+ *tx = (x >> ED_IMAGE_UNDO_TILE_BITS);
+ *ty = (y >> ED_IMAGE_UNDO_TILE_BITS);
}
void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h, bool find_old)
@@ -147,11 +147,12 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int
imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh);
- ListBase *undo_tiles = ED_image_undo_get_tiles();
+ ListBase *undo_tiles = ED_image_paint_tile_list_get();
for (ty = tiley; ty <= tileh; ty++) {
for (tx = tilex; tx <= tilew; tx++) {
- image_undo_push_tile(undo_tiles, ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
+ ED_image_paint_tile_push(
+ undo_tiles, ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
}
}
@@ -467,12 +468,13 @@ static void gradient_draw_line(bContext *UNUSED(C), int x, int y, void *customda
static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const float mouse[2])
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *settings = scene->toolsettings;
PaintOperation *pop = MEM_callocN(sizeof(PaintOperation), "PaintOperation"); /* caller frees */
Brush *brush = BKE_paint_brush(&settings->imapaint.paint);
int mode = RNA_enum_get(op->ptr, "mode");
- ED_view3d_viewcontext_init(C, &pop->vc);
+ ED_view3d_viewcontext_init(C, &pop->vc, depsgraph);
copy_v2_v2(pop->prevmouse, mouse);
copy_v2_v2(pop->startmouse, mouse);
@@ -699,7 +701,7 @@ static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
event->type);
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
return OPERATOR_FINISHED;
}
/* add modal handler */
@@ -1022,7 +1024,7 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event
!RNA_boolean_get(op->ptr, "merged");
paint_sample_color(C, ar, event->mval[0], event->mval[1], use_sample_texture, false);
- WM_cursor_modal_set(win, BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER);
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 8f1156295a3..4f1ae10aa62 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -1197,23 +1197,24 @@ static void paint_2d_do_making_brush(ImagePaintState *s,
int tileh)
{
ImBuf tmpbuf;
- IMB_initImBuf(&tmpbuf, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0);
+ IMB_initImBuf(&tmpbuf, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE, 32, 0);
- ListBase *undo_tiles = ED_image_undo_get_tiles();
+ ListBase *undo_tiles = ED_image_paint_tile_list_get();
for (int ty = tiley; ty <= tileh; ty++) {
for (int tx = tilex; tx <= tilew; tx++) {
/* retrieve original pixels + mask from undo buffer */
unsigned short *mask;
- int origx = region->destx - tx * IMAPAINT_TILE_SIZE;
- int origy = region->desty - ty * IMAPAINT_TILE_SIZE;
+ int origx = region->destx - tx * ED_IMAGE_UNDO_TILE_SIZE;
+ int origy = region->desty - ty * ED_IMAGE_UNDO_TILE_SIZE;
if (s->canvas->rect_float) {
- tmpbuf.rect_float = image_undo_find_tile(
+ tmpbuf.rect_float = ED_image_paint_tile_find(
undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
}
else {
- tmpbuf.rect = image_undo_find_tile(undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
+ tmpbuf.rect = ED_image_paint_tile_find(
+ undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
}
IMB_rectblend(s->canvas,
@@ -1454,8 +1455,6 @@ static void paint_2d_canvas_free(ImagePaintState *s)
paint_delete_blur_kernel(s->blurkernel);
MEM_freeN(s->blurkernel);
}
-
- image_undo_remove_masks();
}
void paint_2d_stroke(void *ps,
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 397b2981ace..5e004c7d675 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -77,15 +77,11 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
-#include "BKE_texture.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
-#include "UI_interface.h"
-
#include "ED_object.h"
-#include "ED_mesh.h"
#include "ED_node.h"
#include "ED_paint.h"
#include "ED_screen.h"
@@ -105,7 +101,6 @@
#include "IMB_colormanagement.h"
-#include "bmesh.h"
//#include "bmesh_tools.h"
#include "paint_intern.h"
@@ -1812,31 +1807,31 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
}
if (generate_tile) {
- ListBase *undo_tiles = ED_image_undo_get_tiles();
+ ListBase *undo_tiles = ED_image_paint_tile_list_get();
volatile void *undorect;
if (tinf->masked) {
- undorect = image_undo_push_tile(undo_tiles,
- pjIma->ima,
- pjIma->ibuf,
- tinf->tmpibuf,
- tx,
- ty,
- &pjIma->maskRect[tile_index],
- &pjIma->valid[tile_index],
- true,
- false);
+ undorect = ED_image_paint_tile_push(undo_tiles,
+ pjIma->ima,
+ pjIma->ibuf,
+ tinf->tmpibuf,
+ tx,
+ ty,
+ &pjIma->maskRect[tile_index],
+ &pjIma->valid[tile_index],
+ true,
+ false);
}
else {
- undorect = image_undo_push_tile(undo_tiles,
- pjIma->ima,
- pjIma->ibuf,
- tinf->tmpibuf,
- tx,
- ty,
- NULL,
- &pjIma->valid[tile_index],
- true,
- false);
+ undorect = ED_image_paint_tile_push(undo_tiles,
+ pjIma->ima,
+ pjIma->ibuf,
+ tinf->tmpibuf,
+ tx,
+ ty,
+ NULL,
+ &pjIma->valid[tile_index],
+ true,
+ false);
}
BKE_image_mark_dirty(pjIma->ima, pjIma->ibuf);
@@ -1885,14 +1880,14 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
/* calculate the undo tile offset of the pixel, used to store the original
* pixel color and accumulated mask if any */
- x_tile = x_px >> IMAPAINT_TILE_BITS;
- y_tile = y_px >> IMAPAINT_TILE_BITS;
+ x_tile = x_px >> ED_IMAGE_UNDO_TILE_BITS;
+ y_tile = y_px >> ED_IMAGE_UNDO_TILE_BITS;
- x_round = x_tile * IMAPAINT_TILE_SIZE;
- y_round = y_tile * IMAPAINT_TILE_SIZE;
+ x_round = x_tile * ED_IMAGE_UNDO_TILE_SIZE;
+ y_round = y_tile * ED_IMAGE_UNDO_TILE_SIZE;
// memset(projPixel, 0, size);
- tile_offset = (x_px - x_round) + (y_px - y_round) * IMAPAINT_TILE_SIZE;
+ tile_offset = (x_px - x_round) + (y_px - y_round) * ED_IMAGE_UNDO_TILE_SIZE;
tile_index = project_paint_undo_subtiles(tinf, x_tile, y_tile);
/* other thread may be initializing the tile so wait here */
@@ -1900,8 +1895,9 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
/* pass */
}
- BLI_assert(tile_index < (IMAPAINT_TILE_NUMBER(ibuf->x) * IMAPAINT_TILE_NUMBER(ibuf->y)));
- BLI_assert(tile_offset < (IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE));
+ BLI_assert(tile_index <
+ (ED_IMAGE_UNDO_TILE_NUMBER(ibuf->x) * ED_IMAGE_UNDO_TILE_NUMBER(ibuf->y)));
+ BLI_assert(tile_offset < (ED_IMAGE_UNDO_TILE_SIZE * ED_IMAGE_UNDO_TILE_SIZE));
projPixel->valid = projima->valid[tile_index];
@@ -2979,7 +2975,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
TileInfo tinf = {
ps->tile_lock,
ps->do_masking,
- IMAPAINT_TILE_NUMBER(ibuf->x),
+ ED_IMAGE_UNDO_TILE_NUMBER(ibuf->x),
tmpibuf,
ps->projImages + image_index,
};
@@ -3931,7 +3927,7 @@ static void proj_paint_state_thread_init(ProjPaintState *ps, const bool reset_th
BLI_spin_init(ps->tile_lock);
}
- image_undo_init_locks();
+ ED_image_paint_tile_lock_init();
}
for (a = 0; a < ps->thread_tot; a++) {
@@ -4249,8 +4245,8 @@ static void project_paint_build_proj_ima(ProjPaintState *ps,
projIma->ima = node->link;
projIma->touch = 0;
projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL);
- size = sizeof(void **) * IMAPAINT_TILE_NUMBER(projIma->ibuf->x) *
- IMAPAINT_TILE_NUMBER(projIma->ibuf->y);
+ size = sizeof(void **) * ED_IMAGE_UNDO_TILE_NUMBER(projIma->ibuf->x) *
+ ED_IMAGE_UNDO_TILE_NUMBER(projIma->ibuf->y);
projIma->partRedrawRect = BLI_memarena_alloc(
arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
partial_redraw_array_init(projIma->partRedrawRect);
@@ -4540,8 +4536,6 @@ static void project_paint_end(ProjPaintState *ps)
{
int a;
- image_undo_remove_masks();
-
/* dereference used image buffers */
if (ps->is_shared_user == false) {
ProjPaintImage *projIma;
@@ -4583,7 +4577,7 @@ static void project_paint_end(ProjPaintState *ps)
MEM_freeN((void *)ps->tile_lock);
}
- image_undo_end_locks();
+ ED_image_paint_tile_lock_end();
#ifndef PROJ_DEBUG_NOSEAMBLEED
if (ps->seam_bleed_px > 0.0f) {
@@ -5212,8 +5206,10 @@ static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool),
float line_len_sq_inv, line_len;
float f;
float color_f[4];
- float p[2] = {projPixel->projCoSS[0] - lastpos[0],
- projPixel->projCoSS[1] - lastpos[1]};
+ const float p[2] = {
+ projPixel->projCoSS[0] - lastpos[0],
+ projPixel->projCoSS[1] - lastpos[1],
+ };
sub_v2_v2v2(tangent, pos, lastpos);
line_len = len_squared_v2(tangent);
diff --git a/source/blender/editors/sculpt_paint/paint_image_undo.c b/source/blender/editors/sculpt_paint/paint_image_undo.c
deleted file mode 100644
index 93dcd3ad0f6..00000000000
--- a/source/blender/editors/sculpt_paint/paint_image_undo.c
+++ /dev/null
@@ -1,625 +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.
- *
- * 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 edsculpt
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-#include "BLI_threads.h"
-
-#include "DNA_image_types.h"
-#include "DNA_windowmanager_types.h"
-#include "DNA_object_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_space_types.h"
-#include "DNA_workspace_types.h"
-
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-
-#include "BKE_context.h"
-#include "BKE_image.h"
-#include "BKE_paint.h"
-#include "BKE_undo_system.h"
-
-#include "DEG_depsgraph.h"
-
-#include "ED_paint.h"
-#include "ED_undo.h"
-#include "ED_util.h"
-#include "ED_object.h"
-
-#include "GPU_draw.h"
-
-#include "WM_api.h"
-
-#include "paint_intern.h"
-
-/* -------------------------------------------------------------------- */
-/** \name Undo Conversion
- * \{ */
-
-typedef struct UndoImageTile {
- struct UndoImageTile *next, *prev;
-
- char ibufname[IMB_FILENAME_SIZE];
-
- union {
- float *fp;
- unsigned int *uint;
- void *pt;
- } rect;
-
- unsigned short *mask;
-
- int x, y;
-
- /* TODO(campbell): avoid storing the ID per tile,
- * adds unnecessary overhead restoring undo steps when most tiles share the same image. */
- UndoRefID_Image image_ref;
-
- short source;
- bool use_float;
- char gen_type;
- bool valid;
-
- size_t undo_size;
-} UndoImageTile;
-
-/* this is a static resource for non-globality,
- * Maybe it should be exposed as part of the
- * paint operation, but for now just give a public interface */
-static SpinLock undolock;
-
-void image_undo_init_locks(void)
-{
- BLI_spin_init(&undolock);
-}
-
-void image_undo_end_locks(void)
-{
- BLI_spin_end(&undolock);
-}
-
-/* UNDO */
-typedef enum {
- COPY = 0,
- RESTORE = 1,
- RESTORE_COPY = 2,
-} CopyMode;
-
-static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, CopyMode mode)
-{
- if (mode == COPY) {
- /* copy or swap contents of tile->rect and region in ibuf->rect */
- IMB_rectcpy(tmpibuf,
- ibuf,
- 0,
- 0,
- tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE,
- IMAPAINT_TILE_SIZE,
- IMAPAINT_TILE_SIZE);
-
- if (ibuf->rect_float) {
- SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
- }
- else {
- SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
- }
- }
- else {
- if (mode == RESTORE_COPY) {
- IMB_rectcpy(tmpibuf,
- ibuf,
- 0,
- 0,
- tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE,
- IMAPAINT_TILE_SIZE,
- IMAPAINT_TILE_SIZE);
- }
- /* swap to the tmpbuf for easy copying */
- if (ibuf->rect_float) {
- SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
- }
- else {
- SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
- }
-
- IMB_rectcpy(ibuf,
- tmpibuf,
- tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE,
- 0,
- 0,
- IMAPAINT_TILE_SIZE,
- IMAPAINT_TILE_SIZE);
-
- if (mode == RESTORE) {
- if (ibuf->rect_float) {
- SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
- }
- else {
- SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
- }
- }
- }
-}
-
-void *image_undo_find_tile(ListBase *undo_tiles,
- Image *ima,
- ImBuf *ibuf,
- int x_tile,
- int y_tile,
- unsigned short **mask,
- bool validate)
-{
- UndoImageTile *tile;
- const bool use_float = (ibuf->rect_float != NULL);
-
- for (tile = undo_tiles->first; tile; tile = tile->next) {
- if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type &&
- ima->source == tile->source) {
- if (tile->use_float == use_float) {
- if (STREQ(tile->ibufname, ibuf->name)) {
- if (mask) {
- /* allocate mask if requested */
- if (!tile->mask) {
- tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE *
- IMAPAINT_TILE_SIZE,
- "UndoImageTile.mask");
- }
-
- *mask = tile->mask;
- }
- if (validate) {
- tile->valid = true;
- }
- return tile->rect.pt;
- }
- }
- }
- }
-
- return NULL;
-}
-
-void *image_undo_push_tile(ListBase *undo_tiles,
- Image *ima,
- ImBuf *ibuf,
- ImBuf **tmpibuf,
- int x_tile,
- int y_tile,
- unsigned short **mask,
- bool **valid,
- bool proj,
- bool find_prev)
-{
- UndoImageTile *tile;
- int allocsize;
- const bool use_float = (ibuf->rect_float != NULL);
- void *data;
-
- /* check if tile is already pushed */
-
- /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
- if (find_prev) {
- data = image_undo_find_tile(undo_tiles, ima, ibuf, x_tile, y_tile, mask, true);
- if (data) {
- return data;
- }
- }
-
- if (*tmpibuf == NULL) {
- *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
- }
-
- tile = MEM_callocN(sizeof(UndoImageTile), "UndoImageTile");
- tile->x = x_tile;
- tile->y = y_tile;
-
- /* add mask explicitly here */
- if (mask) {
- *mask = tile->mask = MEM_callocN(
- sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE, "UndoImageTile.mask");
- }
- allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
- allocsize *= (ibuf->rect_float) ? sizeof(float) : sizeof(char);
- tile->rect.pt = MEM_mapallocN(allocsize, "UndeImageTile.rect");
-
- BLI_strncpy(tile->ibufname, ibuf->name, sizeof(tile->ibufname));
-
- tile->gen_type = ima->gen_type;
- tile->source = ima->source;
- tile->use_float = use_float;
- tile->valid = true;
- tile->image_ref.ptr = ima;
-
- if (valid) {
- *valid = &tile->valid;
- }
- undo_copy_tile(tile, *tmpibuf, ibuf, COPY);
-
- if (proj) {
- BLI_spin_lock(&undolock);
- }
- BLI_addtail(undo_tiles, tile);
-
- if (proj) {
- BLI_spin_unlock(&undolock);
- }
- return tile->rect.pt;
-}
-
-void image_undo_remove_masks(void)
-{
- ListBase *undo_tiles = ED_image_undo_get_tiles();
- UndoImageTile *tile;
-
- for (tile = undo_tiles->first; tile; tile = tile->next) {
- if (tile->mask) {
- MEM_freeN(tile->mask);
- tile->mask = NULL;
- }
- }
-}
-
-static void image_undo_restore_runtime(ListBase *lb)
-{
- ImBuf *ibuf, *tmpibuf;
- UndoImageTile *tile;
-
- tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
-
- for (tile = lb->first; tile; tile = tile->next) {
- Image *ima = tile->image_ref.ptr;
- ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
-
- undo_copy_tile(tile, tmpibuf, ibuf, RESTORE);
-
- GPU_free_image(ima); /* force OpenGL reload (maybe partial update will operate better?) */
- if (ibuf->rect_float) {
- ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
- }
- if (ibuf->mipmap[0]) {
- ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
- }
- ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
-
- IMB_freeImBuf(tmpibuf);
-}
-
-static void image_undo_restore_list(ListBase *lb)
-{
- ImBuf *tmpibuf = IMB_allocImBuf(
- IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
-
- for (UndoImageTile *tile = lb->first; tile; tile = tile->next) {
-
- Image *ima = tile->image_ref.ptr;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
-
- if (ima && ibuf && !STREQ(tile->ibufname, ibuf->name)) {
- /* current ImBuf filename was changed, probably current frame
- * was changed when painting on image sequence, rather than storing
- * full image user (which isn't so obvious, btw) try to find ImBuf with
- * matched file name in list of already loaded images */
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
-
- ibuf = BKE_image_get_ibuf_with_name(ima, tile->ibufname);
- }
-
- if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- if (ima->gen_type != tile->gen_type || ima->source != tile->source) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- const bool use_float = (ibuf->rect_float != NULL);
-
- if (use_float != tile->use_float) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- undo_copy_tile(tile, tmpibuf, ibuf, RESTORE_COPY);
-
- BKE_image_mark_dirty(ima, ibuf);
- GPU_free_image(ima); /* force OpenGL reload */
-
- if (ibuf->rect_float) {
- ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
- }
- if (ibuf->mipmap[0]) {
- ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
- }
- ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
-
- DEG_id_tag_update(&ima->id, 0);
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
-
- IMB_freeImBuf(tmpibuf);
-}
-
-static void image_undo_free_list(ListBase *lb)
-{
- for (UndoImageTile *tile = lb->first, *tile_next; tile; tile = tile_next) {
- tile_next = tile->next;
- MEM_freeN(tile->rect.pt);
- MEM_freeN(tile);
- }
-}
-
-static void image_undo_invalidate(void)
-{
- UndoImageTile *tile;
- ListBase *lb = ED_image_undo_get_tiles();
-
- for (tile = lb->first; tile; tile = tile->next) {
- tile->valid = false;
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Implements ED Undo System
- * \{ */
-
-typedef struct ImageUndoStep {
- UndoStep step;
- ListBase tiles;
- bool is_encode_init;
- ePaintMode paint_mode;
-} ImageUndoStep;
-
-static bool image_undosys_poll(bContext *C)
-{
- Object *obact = CTX_data_active_object(C);
-
- ScrArea *sa = CTX_wm_area(C);
- if (sa && (sa->spacetype == SPACE_IMAGE)) {
- SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
- if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
- return true;
- }
- }
- else {
- if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) {
- return true;
- }
- }
- return false;
-}
-
-static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
-{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- /* dummy, memory is cleared anyway. */
- us->is_encode_init = true;
- BLI_listbase_clear(&us->tiles);
-}
-
-static bool image_undosys_step_encode(struct bContext *C,
- struct Main *UNUSED(bmain),
- UndoStep *us_p)
-{
- /* dummy, encoding is done along the way by adding tiles
- * to the current 'ImageUndoStep' added by encode_init. */
- ImageUndoStep *us = (ImageUndoStep *)us_p;
-
- BLI_assert(us->step.data_size == 0);
-
- int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
-
- if (us->is_encode_init) {
- /* first dispose of invalid tiles (may happen due to drag dot for instance) */
- for (UndoImageTile *tile = us->tiles.first; tile;) {
- if (!tile->valid) {
- UndoImageTile *tmp_tile = tile->next;
- MEM_freeN(tile->rect.pt);
- BLI_freelinkN(&us->tiles, tile);
- tile = tmp_tile;
- }
- else {
- us->step.data_size += allocsize * (tile->use_float ? sizeof(float) : sizeof(char));
- tile = tile->next;
- }
- }
- }
- else {
- /* Happens when switching modes. */
- ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C);
- BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
- us->paint_mode = paint_mode;
- }
-
- us_p->is_applied = true;
-
- return true;
-}
-
-static void image_undosys_step_decode_undo_impl(ImageUndoStep *us)
-{
- BLI_assert(us->step.is_applied == true);
- image_undo_restore_list(&us->tiles);
- us->step.is_applied = false;
-}
-
-static void image_undosys_step_decode_redo_impl(ImageUndoStep *us)
-{
- BLI_assert(us->step.is_applied == false);
- image_undo_restore_list(&us->tiles);
- us->step.is_applied = true;
-}
-
-static void image_undosys_step_decode_undo(ImageUndoStep *us, bool is_final)
-{
- 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) {
- break;
- }
- us_iter = (ImageUndoStep *)us_iter->step.next;
- }
- while (us_iter != us || (!is_final && us_iter == us)) {
- image_undosys_step_decode_undo_impl(us_iter);
- if (us_iter == us) {
- break;
- }
- us_iter = (ImageUndoStep *)us_iter->step.prev;
- }
-}
-
-static void image_undosys_step_decode_redo(ImageUndoStep *us)
-{
- ImageUndoStep *us_iter = us;
- while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) {
- if (us_iter->step.prev->is_applied == true) {
- break;
- }
- us_iter = (ImageUndoStep *)us_iter->step.prev;
- }
- while (us_iter && (us_iter->step.is_applied == false)) {
- image_undosys_step_decode_redo_impl(us_iter);
- if (us_iter == us) {
- break;
- }
- us_iter = (ImageUndoStep *)us_iter->step.next;
- }
-}
-
-static void image_undosys_step_decode(
- struct bContext *C, struct Main *bmain, UndoStep *us_p, int dir, bool is_final)
-{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- if (dir < 0) {
- image_undosys_step_decode_undo(us, is_final);
- }
- else {
- image_undosys_step_decode_redo(us);
- }
-
- if (us->paint_mode == PAINT_MODE_TEXTURE_3D) {
- ED_object_mode_set(C, OB_MODE_TEXTURE_PAINT);
- }
-
- /* Refresh texture slots. */
- ED_editors_init_for_undo(bmain);
-}
-
-static void image_undosys_step_free(UndoStep *us_p)
-{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- image_undo_free_list(&us->tiles);
-}
-
-static void image_undosys_foreach_ID_ref(UndoStep *us_p,
- UndoTypeForEachIDRefFn foreach_ID_ref_fn,
- void *user_data)
-{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- for (UndoImageTile *tile = us->tiles.first; tile; tile = tile->next) {
- foreach_ID_ref_fn(user_data, ((UndoRefID *)&tile->image_ref));
- }
-}
-
-/* Export for ED_undo_sys. */
-void ED_image_undosys_type(UndoType *ut)
-{
- ut->name = "Image";
- ut->poll = image_undosys_poll;
- ut->step_encode_init = image_undosys_step_encode_init;
- ut->step_encode = image_undosys_step_encode;
- ut->step_decode = image_undosys_step_decode;
- ut->step_free = image_undosys_step_free;
-
- ut->step_foreach_ID_ref = image_undosys_foreach_ID_ref;
-
- ut->use_context = true;
-
- ut->step_size = sizeof(ImageUndoStep);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Utilities
- * \{ */
-
-ListBase *ED_image_undosys_step_get_tiles(UndoStep *us_p)
-{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- return &us->tiles;
-}
-
-ListBase *ED_image_undo_get_tiles(void)
-{
- UndoStack *ustack = ED_undo_stack_get();
- UndoStep *us_prev = ustack->step_init;
- UndoStep *us_p = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_IMAGE);
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- /* We should always have an undo push started when accessing tiles,
- * not doing this means we won't have paint_mode correctly set. */
- BLI_assert(us_p == us_prev);
- if (us_p != us_prev) {
- /* Fallback value until we can be sure this never happens. */
- us->paint_mode = PAINT_MODE_TEXTURE_2D;
- }
- return ED_image_undosys_step_get_tiles(us_p);
-}
-
-/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/
-void ED_image_undo_restore(UndoStep *us)
-{
- ListBase *lb = ED_image_undosys_step_get_tiles(us);
- image_undo_restore_runtime(lb);
- image_undo_invalidate();
-}
-
-void ED_image_undo_push_begin(const char *name, int paint_mode)
-{
- UndoStack *ustack = ED_undo_stack_get();
- bContext *C = NULL; /* special case, we never read from this. */
- UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE);
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
- us->paint_mode = paint_mode;
-}
-
-void ED_image_undo_push_end(void)
-{
- UndoStack *ustack = ED_undo_stack_get();
- BKE_undosys_step_push(ustack, NULL, NULL);
- WM_file_tag_modified();
-}
-
-/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 5efedf69fe4..69eed84fe2b 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -70,7 +70,7 @@ struct PaintStroke *paint_stroke_new(struct bContext *C,
StrokeRedraw redraw,
StrokeDone done,
int event_type);
-void paint_stroke_data_free(struct wmOperator *op);
+void paint_stroke_free(struct bContext *C, struct wmOperator *op);
bool paint_space_stroke_enabled(struct Brush *br, enum ePaintMode mode);
bool paint_supports_dynamic_size(struct Brush *br, enum ePaintMode mode);
@@ -184,10 +184,6 @@ typedef struct ImagePaintPartialRedraw {
int enabled;
} ImagePaintPartialRedraw;
-#define IMAPAINT_TILE_BITS 6
-#define IMAPAINT_TILE_SIZE (1 << IMAPAINT_TILE_BITS)
-#define IMAPAINT_TILE_NUMBER(size) (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS)
-
bool image_texture_paint_poll(struct bContext *C);
void imapaint_image_update(struct SpaceImage *sima,
struct Image *image,
@@ -252,31 +248,6 @@ void PAINT_OT_add_texture_paint_slot(struct wmOperatorType *ot);
void PAINT_OT_image_paint(struct wmOperatorType *ot);
void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot);
-/* paint_image_undo.c */
-void *image_undo_find_tile(ListBase *undo_tiles,
- struct Image *ima,
- struct ImBuf *ibuf,
- int x_tile,
- int y_tile,
- unsigned short **mask,
- bool validate);
-void *image_undo_push_tile(ListBase *undo_tiles,
- struct Image *ima,
- struct ImBuf *ibuf,
- struct ImBuf **tmpibuf,
- int x_tile,
- int y_tile,
- unsigned short **,
- bool **valid,
- bool proj,
- bool find_prev);
-void image_undo_remove_masks(void);
-void image_undo_init_locks(void);
-void image_undo_end_locks(void);
-
-struct ListBase *ED_image_undosys_step_get_tiles(struct UndoStep *us_p);
-struct ListBase *ED_image_undo_get_tiles(void);
-
/* sculpt_uv.c */
void SCULPT_OT_uv_sculpt_stroke(struct wmOperatorType *ot);
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 74212058fc7..a93e55685d2 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -109,6 +109,7 @@ static void mask_flood_fill_task_cb(void *__restrict userdata,
const PaintMaskFloodMode mode = data->mode;
const float value = data->value;
+ bool redraw = false;
PBVHVertexIter vi;
@@ -116,13 +117,19 @@ static void mask_flood_fill_task_cb(void *__restrict userdata,
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) {
+ redraw = true;
+ }
}
BKE_pbvh_vertex_iter_end;
- BKE_pbvh_node_mark_redraw(node);
- if (data->multires) {
- BKE_pbvh_node_mark_normals_update(node);
+ if (redraw) {
+ BKE_pbvh_node_mark_update_mask(node);
+ if (data->multires) {
+ BKE_pbvh_node_mark_normals_update(node);
+ }
}
}
@@ -160,16 +167,15 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
-
- 0, totnode, &data, mask_flood_fill_task_cb, &settings);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BLI_task_parallel_range(0, totnode, &data, mask_flood_fill_task_cb, &settings);
if (multires) {
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
}
+ BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask);
+
sculpt_undo_push_end();
if (nodes) {
@@ -255,24 +261,32 @@ static void mask_box_select_task_cb(void *__restrict userdata,
PBVHVertexIter vi;
bool any_masked = false;
+ bool redraw = false;
BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE)
{
if (is_effected(clip_planes_final, vi.co)) {
+ float prevmask = *vi.mask;
if (!any_masked) {
any_masked = true;
sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_MASK);
- BKE_pbvh_node_mark_redraw(node);
if (data->multires) {
BKE_pbvh_node_mark_normals_update(node);
}
}
mask_flood_fill_set_elem(vi.mask, mode, value);
+ if (prevmask != *vi.mask) {
+ redraw = true;
+ }
}
}
BKE_pbvh_vertex_iter_end;
+
+ if (redraw) {
+ BKE_pbvh_node_mark_update_mask(node);
+ }
}
bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *rect, bool select)
@@ -297,7 +311,6 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
/* transform the clip planes in object space */
ED_view3d_clipping_calc(&bb, clip_planes, vc->ar, vc->obact, rect);
- negate_m4(clip_planes);
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true);
pbvh = ob->sculpt->pbvh;
@@ -305,7 +318,7 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
sculpt_undo_push_begin("Mask box fill");
- for (symmpass = 0; symmpass <= symm; ++symmpass) {
+ for (symmpass = 0; symmpass <= symm; symmpass++) {
if (symmpass == 0 || (symm & symmpass && (symm != 5 || symmpass != 3) &&
(symm != 6 || (symmpass != 3 && symmpass != 5)))) {
int j = 0;
@@ -315,8 +328,10 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
flip_plane(clip_planes_final[j], clip_planes[j], symmpass);
}
- BKE_pbvh_search_gather(
- pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode);
+ PBVHFrustumPlanes frustum = {.planes = clip_planes_final, .num_planes = 4};
+ BKE_pbvh_search_gather(pbvh, BKE_pbvh_node_frustum_contain_AABB, &frustum, &nodes, &totnode);
+
+ negate_m4(clip_planes_final);
MaskTaskData data = {
.ob = ob,
@@ -329,9 +344,7 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
- totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings);
if (nodes) {
@@ -344,6 +357,8 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
}
+ BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask);
+
sculpt_undo_push_end();
ED_region_tag_redraw(ar);
@@ -462,7 +477,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
/* Calculations of individual vertices are done in 2D screen space to diminish the amount of
* calculations done. Bounding box PBVH collision is not computed against enclosing rectangle
* of lasso */
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
/* lasso data calculations */
data.vc = &vc;
@@ -483,7 +498,6 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
&data);
ED_view3d_clipping_calc(&bb, clip_planes, vc.ar, vc.obact, &data.rect);
- negate_m4(clip_planes);
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true);
pbvh = ob->sculpt->pbvh;
@@ -491,7 +505,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
sculpt_undo_push_begin("Mask lasso fill");
- for (symmpass = 0; symmpass <= symm; ++symmpass) {
+ for (symmpass = 0; symmpass <= symm; symmpass++) {
if ((symmpass == 0) || (symm & symmpass && (symm != 5 || symmpass != 3) &&
(symm != 6 || (symmpass != 3 && symmpass != 5)))) {
int j = 0;
@@ -505,8 +519,11 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
/* gather nodes inside lasso's enclosing rectangle
* (should greatly help with bigger meshes) */
+ PBVHFrustumPlanes frustum = {.planes = clip_planes_final, .num_planes = 4};
BKE_pbvh_search_gather(
- pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode);
+ pbvh, BKE_pbvh_node_frustum_contain_AABB, &frustum, &nodes, &totnode);
+
+ negate_m4(clip_planes_final);
data.task_data.ob = ob;
data.task_data.pbvh = pbvh;
@@ -516,9 +533,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
data.task_data.value = value;
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
- (totnode > SCULPT_THREADED_LIMIT));
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings);
if (nodes) {
@@ -531,6 +546,8 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
}
+ BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask);
+
sculpt_undo_push_end();
ED_region_tag_redraw(vc.ar);
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index f58afcdadc1..97455d479dc 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -29,32 +29,22 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
-#include "DNA_gpencil_types.h"
#include "BKE_brush.h"
#include "BKE_context.h"
-#include "BKE_gpencil.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_paint.h"
-#include "BKE_report.h"
-
-#include "DEG_depsgraph.h"
#include "ED_paint.h"
#include "ED_screen.h"
-#include "ED_select_utils.h"
#include "ED_image.h"
-#include "ED_gpencil.h"
-#include "UI_resources.h"
#include "WM_api.h"
#include "WM_types.h"
-#include "WM_toolsystem.h"
#include "RNA_access.h"
#include "RNA_define.h"
-#include "RNA_enum_types.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 694dae49d30..d8be345cc84 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -43,7 +43,6 @@
#include "BKE_curve.h"
#include "BKE_colortools.h"
#include "BKE_image.h"
-#include "BKE_mesh.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -57,6 +56,7 @@
#include "IMB_imbuf_types.h"
#include "paint_intern.h"
+#include "sculpt_intern.h"
#include <float.h>
#include <math.h>
@@ -93,6 +93,8 @@ typedef struct PaintStroke {
int cur_sample;
float last_mouse_position[2];
+ float last_world_space_position[3];
+ bool stroke_over_mesh;
/* space distance covered so far */
float stroke_distance;
@@ -218,6 +220,8 @@ static bool paint_tool_require_location(Brush *brush, ePaintMode mode)
case PAINT_MODE_SCULPT:
if (ELEM(brush->sculpt_tool,
SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ELASTIC_DEFORM,
+ SCULPT_TOOL_POSE,
SCULPT_TOOL_ROTATE,
SCULPT_TOOL_SNAKE_HOOK,
SCULPT_TOOL_THUMB)) {
@@ -233,11 +237,27 @@ static bool paint_tool_require_location(Brush *brush, ePaintMode mode)
return true;
}
+static bool paint_stroke_use_scene_spacing(Brush *brush, ePaintMode mode)
+{
+ switch (mode) {
+ case PAINT_MODE_SCULPT:
+ return brush->flag & BRUSH_SCENE_SPACING;
+ default:
+ break;
+ }
+ return false;
+}
+
static bool paint_tool_require_inbetween_mouse_events(Brush *brush, ePaintMode mode)
{
switch (mode) {
case PAINT_MODE_SCULPT:
- if (ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB)) {
+ if (ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_ELASTIC_DEFORM,
+ SCULPT_TOOL_POSE)) {
return false;
}
else {
@@ -523,6 +543,11 @@ static void paint_brush_stroke_add_step(bContext *C,
copy_v2_v2(stroke->last_mouse_position, mouse_in);
stroke->last_pressure = pressure;
+ if (paint_stroke_use_scene_spacing(brush, mode)) {
+ sculpt_stroke_get_location(C, stroke->last_world_space_position, stroke->last_mouse_position);
+ mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position);
+ }
+
if (paint_stroke_use_jitter(mode, brush, stroke->stroke_mode == BRUSH_STROKE_INVERT)) {
float delta[2];
float factor = stroke->zoom_2d;
@@ -600,14 +625,34 @@ static bool paint_smooth_stroke(PaintStroke *stroke,
return true;
}
-static float paint_space_stroke_spacing(const Scene *scene,
+static float paint_space_stroke_spacing(bContext *C,
+ const Scene *scene,
PaintStroke *stroke,
float size_pressure,
float spacing_pressure)
{
- /* brushes can have a minimum size of 1.0 but with pressure it can be smaller then a pixel
- * causing very high step sizes, hanging blender [#32381] */
- const float size_clamp = max_ff(1.0f, BKE_brush_size_get(scene, stroke->brush) * size_pressure);
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+ Brush *brush = BKE_paint_brush(paint);
+ float size_clamp = 0.0f;
+ float size = BKE_brush_size_get(scene, stroke->brush) * size_pressure;
+ if (paint_stroke_use_scene_spacing(brush, mode)) {
+ if (!BKE_brush_use_locked_size(scene, brush)) {
+ float last_object_space_position[3];
+ mul_v3_m4v3(
+ last_object_space_position, stroke->vc.obact->imat, stroke->last_world_space_position);
+ size_clamp = paint_calc_object_space_radius(&stroke->vc, last_object_space_position, size);
+ }
+ else {
+ size_clamp = BKE_brush_unprojected_radius_get(scene, brush) * size_pressure;
+ }
+ }
+ else {
+ /* brushes can have a minimum size of 1.0 but with pressure it can be smaller then a pixel
+ * causing very high step sizes, hanging blender [#32381] */
+ size_clamp = max_ff(1.0f, size);
+ }
+
float spacing = stroke->brush->spacing;
/* apply spacing pressure */
@@ -619,7 +664,12 @@ static float paint_space_stroke_spacing(const Scene *scene,
* the fact that brush can be scaled there. */
spacing *= stroke->zoom_2d;
- return max_ff(1.0, size_clamp * spacing / 50.0f);
+ if (paint_stroke_use_scene_spacing(brush, mode)) {
+ return max_ff(0.001f, size_clamp * spacing / 50.f);
+ }
+ else {
+ return max_ff(1.0, size_clamp * spacing / 50.0f);
+ }
}
static float paint_stroke_overlapped_curve(Brush *br, float x, float spacing)
@@ -677,14 +727,18 @@ static float paint_stroke_integrate_overlap(Brush *br, float factor)
}
}
-static float paint_space_stroke_spacing_variable(
- const Scene *scene, PaintStroke *stroke, float pressure, float dpressure, float length)
+static float paint_space_stroke_spacing_variable(bContext *C,
+ const Scene *scene,
+ PaintStroke *stroke,
+ float pressure,
+ float dpressure,
+ float length)
{
if (BKE_brush_use_size_pressure(scene, stroke->brush)) {
/* use pressure to modify size. set spacing so that at 100%, the circles
* are aligned nicely with no overlap. for this the spacing needs to be
* the average of the previous and next size. */
- float s = paint_space_stroke_spacing(scene, stroke, 1.0f, pressure);
+ float s = paint_space_stroke_spacing(C, scene, stroke, 1.0f, pressure);
float q = s * dpressure / (2.0f * length);
float pressure_fac = (1.0f + q) / (1.0f - q);
@@ -692,14 +746,15 @@ static float paint_space_stroke_spacing_variable(
float new_size_pressure = stroke->last_pressure * pressure_fac;
/* average spacing */
- float last_spacing = paint_space_stroke_spacing(scene, stroke, last_size_pressure, pressure);
- float new_spacing = paint_space_stroke_spacing(scene, stroke, new_size_pressure, pressure);
+ float last_spacing = paint_space_stroke_spacing(
+ C, scene, stroke, last_size_pressure, pressure);
+ float new_spacing = paint_space_stroke_spacing(C, scene, stroke, new_size_pressure, pressure);
return 0.5f * (last_spacing + new_spacing);
}
else {
/* no size pressure */
- return paint_space_stroke_spacing(scene, stroke, 1.0f, pressure);
+ return paint_space_stroke_spacing(C, scene, stroke, 1.0f, pressure);
}
}
@@ -711,29 +766,63 @@ static int paint_space_stroke(bContext *C,
float final_pressure)
{
const Scene *scene = CTX_data_scene(C);
+ ARegion *ar = CTX_wm_region(C);
PaintStroke *stroke = op->customdata;
UnifiedPaintSettings *ups = stroke->ups;
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+ Brush *brush = BKE_paint_brush(paint);
int cnt = 0;
- float pressure, dpressure;
- float mouse[2], dmouse[2];
- float length;
- float no_pressure_spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f);
-
- sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position);
+ const bool use_scene_spacing = paint_stroke_use_scene_spacing(brush, mode);
+ float d_world_space_position[3] = {0.0f};
- pressure = stroke->last_pressure;
- dpressure = final_pressure - stroke->last_pressure;
+ float no_pressure_spacing = paint_space_stroke_spacing(C, scene, stroke, 1.0f, 1.0f);
+ float pressure = stroke->last_pressure;
+ float dpressure = final_pressure - stroke->last_pressure;
- length = normalize_v2(dmouse);
+ float dmouse[2];
+ sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position);
+ float length = normalize_v2(dmouse);
+
+ if (use_scene_spacing) {
+ float world_space_position[3];
+ bool hit = sculpt_stroke_get_location(C, world_space_position, final_mouse);
+ mul_m4_v3(stroke->vc.obact->obmat, world_space_position);
+ if (hit && stroke->stroke_over_mesh) {
+ sub_v3_v3v3(d_world_space_position, world_space_position, stroke->last_world_space_position);
+ length = len_v3(d_world_space_position);
+ stroke->stroke_over_mesh = true;
+ }
+ else {
+ length = 0.0f;
+ zero_v3(d_world_space_position);
+ stroke->stroke_over_mesh = hit;
+ if (stroke->stroke_over_mesh) {
+ copy_v3_v3(stroke->last_world_space_position, world_space_position);
+ }
+ }
+ }
while (length > 0.0f) {
float spacing = paint_space_stroke_spacing_variable(
- scene, stroke, pressure, dpressure, length);
+ C, scene, stroke, pressure, dpressure, length);
+ float mouse[3];
if (length >= spacing) {
- mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing;
- mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing;
+ if (use_scene_spacing) {
+ float final_world_space_position[3];
+ normalize_v3(d_world_space_position);
+ mul_v3_v3fl(final_world_space_position, d_world_space_position, spacing);
+ add_v3_v3v3(final_world_space_position,
+ stroke->last_world_space_position,
+ final_world_space_position);
+ ED_view3d_project(ar, final_world_space_position, mouse);
+ }
+ else {
+ mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing;
+ mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing;
+ }
pressure = stroke->last_pressure + (spacing / length) * dpressure;
ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush,
@@ -767,14 +856,16 @@ PaintStroke *paint_stroke_new(bContext *C,
StrokeDone done,
int event_type)
{
+ struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke");
ToolSettings *toolsettings = CTX_data_tool_settings(C);
UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings;
Paint *p = BKE_paint_get_active_from_context(C);
Brush *br = stroke->brush = BKE_paint_brush(p);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
float zoomx, zoomy;
- ED_view3d_viewcontext_init(C, &stroke->vc);
+ ED_view3d_viewcontext_init(C, &stroke->vc, depsgraph);
stroke->get_location = get_location;
stroke->test_start = test_start;
@@ -797,6 +888,10 @@ PaintStroke *paint_stroke_new(bContext *C,
ups->overlap_factor = 1.0;
ups->stroke_active = true;
+ if (rv3d) {
+ rv3d->rflag |= RV3D_PAINTING;
+ }
+
zero_v3(ups->average_stroke_accum);
ups->average_stroke_counter = 0;
@@ -811,20 +906,42 @@ PaintStroke *paint_stroke_new(bContext *C,
return stroke;
}
-void paint_stroke_data_free(struct wmOperator *op)
+void paint_stroke_free(bContext *C, wmOperator *op)
{
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ PaintStroke *stroke = op->customdata;
+ UnifiedPaintSettings *ups = stroke->ups;
+
+ ups->draw_anchored = false;
+ ups->stroke_active = false;
+
+ if (rv3d) {
+ rv3d->rflag &= ~RV3D_PAINTING;
+ }
+
+ if (stroke->timer) {
+ WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), stroke->timer);
+ }
+
+ if (stroke->rng) {
+ BLI_rng_free(stroke->rng);
+ }
+
+ if (stroke->stroke_cursor) {
+ WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor);
+ }
+
+ BLI_freelistN(&stroke->line);
+
BKE_paint_set_overlay_override(0);
MEM_SAFE_FREE(op->customdata);
}
-static void stroke_done(struct bContext *C, struct wmOperator *op)
+static void stroke_done(bContext *C, wmOperator *op)
{
- struct PaintStroke *stroke = op->customdata;
+ PaintStroke *stroke = op->customdata;
UnifiedPaintSettings *ups = stroke->ups;
- ups->draw_anchored = false;
- ups->stroke_active = false;
-
/* reset rotation here to avoid doing so in cursor display */
if (!(stroke->brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
ups->brush_rotation = 0.0f;
@@ -844,21 +961,7 @@ static void stroke_done(struct bContext *C, struct wmOperator *op)
}
}
- if (stroke->timer) {
- WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), stroke->timer);
- }
-
- if (stroke->rng) {
- BLI_rng_free(stroke->rng);
- }
-
- if (stroke->stroke_cursor) {
- WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor);
- }
-
- BLI_freelistN(&stroke->line);
-
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
}
/* Returns zero if the stroke dots should not be spaced, non-zero otherwise */
@@ -871,6 +974,8 @@ static bool sculpt_is_grab_tool(Brush *br)
{
return ELEM(br->sculpt_tool,
SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ELASTIC_DEFORM,
+ SCULPT_TOOL_POSE,
SCULPT_TOOL_THUMB,
SCULPT_TOOL_ROTATE,
SCULPT_TOOL_SNAKE_HOOK);
@@ -1079,7 +1184,7 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
if (br->flag & BRUSH_CURVE) {
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
const Scene *scene = CTX_data_scene(C);
- const float spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f);
+ const float spacing = paint_space_stroke_spacing(C, scene, stroke, 1.0f, 1.0f);
PaintCurve *pc = br->paint_curve;
PaintCurvePoint *pcp;
float length_residue = 0.0f;
@@ -1250,6 +1355,11 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (!stroke->stroke_started) {
stroke->last_pressure = sample_average.pressure;
copy_v2_v2(stroke->last_mouse_position, sample_average.mouse);
+ if (paint_stroke_use_scene_spacing(br, mode)) {
+ stroke->stroke_over_mesh = sculpt_stroke_get_location(
+ C, stroke->last_world_space_position, sample_average.mouse);
+ mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position);
+ }
stroke->stroke_started = stroke->test_start(C, op, sample_average.mouse);
BLI_assert((stroke->stroke_started & ~1) == 0); /* 0/1 */
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 4b9d9a2cc01..a014fe7fdff 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -46,7 +46,6 @@
#include "BKE_image.h"
#include "BKE_material.h"
#include "BKE_mesh_runtime.h"
-#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_report.h"
@@ -101,9 +100,9 @@ bool paint_convert_bb_to_rect(rcti *rect,
ED_view3d_ob_project_mat_get(rv3d, ob, projection_mat);
- for (i = 0; i < 2; ++i) {
- for (j = 0; j < 2; ++j) {
- for (k = 0; k < 2; ++k) {
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 2; j++) {
+ for (k = 0; k < 2; k++) {
float vec[3], proj[2];
int proj_i[2];
vec[0] = i ? bb_min[0] : bb_max[0];
@@ -145,7 +144,6 @@ void paint_calc_redraw_planes(float planes[4][4],
rect.ymax += 2;
ED_view3d_clipping_calc(&bb, planes, ar, ob, &rect);
- negate_m4(planes);
}
float paint_calc_object_space_radius(ViewContext *vc, const float center[3], float pixel_radius)
@@ -251,7 +249,7 @@ static void imapaint_project(float matrix[4][4], const float co[3], float pco[4]
}
static void imapaint_tri_weights(float matrix[4][4],
- GLint view[4],
+ const GLint view[4],
const float v1[3],
const float v2[3],
const float v3[3],
@@ -506,7 +504,7 @@ void paint_sample_color(
unsigned int totpoly = me->totpoly;
if (CustomData_has_layer(&me_eval->ldata, CD_MLOOPUV)) {
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
view3d_operator_needs_opengl(C);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 12da8790b91..3554a6cc546 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -34,7 +34,6 @@
#include "BLI_array_utils.h"
#include "BLI_task.h"
-#include "DNA_armature_types.h"
#include "DNA_mesh_types.h"
#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
@@ -42,7 +41,6 @@
#include "DNA_object_types.h"
#include "RNA_access.h"
-#include "RNA_define.h"
#include "BKE_brush.h"
#include "BKE_context.h"
@@ -195,17 +193,12 @@ static bool vertex_paint_use_fast_update_check(Object *ob)
return false;
}
-static void paint_last_stroke_update(Scene *scene, ARegion *ar, const float mval[2])
+static void paint_last_stroke_update(Scene *scene, const float location[3])
{
- const int mval_i[2] = {mval[0], mval[1]};
- float world[3];
-
- if (ED_view3d_autodist_simple(ar, mval_i, world, 0, NULL)) {
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- ups->average_stroke_counter++;
- add_v3_v3(ups->average_stroke_accum, world);
- ups->last_stroke_valid = true;
- }
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ ups->average_stroke_counter++;
+ add_v3_v3(ups->average_stroke_accum, location);
+ ups->last_stroke_valid = true;
}
/* polling - retrieve whether cursor should be set or operator should be done */
@@ -260,7 +253,7 @@ static bool weight_paint_poll_ex(bContext *C, bool check_tool)
(BKE_paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != NULL) &&
(sa = CTX_wm_area(C)) && (sa->spacetype == SPACE_VIEW3D)) {
ARegion *ar = CTX_wm_region(C);
- if (ar->regiontype == RGN_TYPE_WINDOW) {
+ if (ELEM(ar->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_HUD)) {
if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
return 1;
}
@@ -1610,7 +1603,7 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
/* make mode data storage */
wpd = MEM_callocN(sizeof(struct WPaintData), "WPaintData");
paint_stroke_set_mode_data(stroke, wpd);
- ED_view3d_viewcontext_init(C, &wpd->vc);
+ ED_view3d_viewcontext_init(C, &wpd->vc, depsgraph);
view_angle_limits_init(&wpd->normal_angle_precalc,
vp->paint.brush->falloff_angle,
(vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
@@ -2080,9 +2073,7 @@ static void calculate_average_weight(SculptThreadedTaskData *data,
data->custom_data = accum;
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((data->sd->flags & SCULPT_USE_OPENMP) &&
- totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (data->sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings);
uint accum_len = 0;
@@ -2128,10 +2119,9 @@ static void wpaint_paint_leaves(bContext *C,
/* Use this so average can modify its weight without touching the brush. */
data.strength = BKE_brush_weight_get(scene, brush);
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
/* NOTE: current mirroring code cannot be run in parallel */
- settings.use_threading = !(me->editflag & ME_EDIT_MIRROR_X);
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, !(me->editflag & ME_EDIT_MIRROR_X), totnode);
switch ((eBrushWeightPaintTool)brush->weightpaint_tool) {
case WPAINT_TOOL_AVERAGE:
@@ -2351,7 +2341,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* calculate pivot for rotation around seletion if needed */
/* also needed for "View Selected" on last stroke */
- paint_last_stroke_update(scene, vc->ar, ss->cache->mouse);
+ paint_last_stroke_update(scene, ss->cache->location);
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
@@ -2446,7 +2436,7 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
event->type);
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
return OPERATOR_FINISHED;
}
/* add modal handler */
@@ -2655,7 +2645,7 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
/* make mode data storage */
vpd = MEM_callocN(sizeof(*vpd), "VPaintData");
paint_stroke_set_mode_data(stroke, vpd);
- ED_view3d_viewcontext_init(C, &vpd->vc);
+ ED_view3d_viewcontext_init(C, &vpd->vc, depsgraph);
view_angle_limits_init(&vpd->normal_angle_precalc,
vp->paint.brush->falloff_angle,
(vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
@@ -3142,7 +3132,7 @@ static void calculate_average_color(SculptThreadedTaskData *data,
data->custom_data = accum;
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings);
uint accum_len = 0;
@@ -3188,7 +3178,7 @@ static void vpaint_paint_leaves(bContext *C,
.me = me,
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
switch ((eBrushVertexPaintTool)brush->vertexpaint_tool) {
case VPAINT_TOOL_AVERAGE:
calculate_average_color(&data, nodes, totnode);
@@ -3331,7 +3321,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* calculate pivot for rotation around seletion if needed */
/* also needed for "View Selected" on last stroke */
- paint_last_stroke_update(scene, vc->ar, ss->cache->mouse);
+ paint_last_stroke_update(scene, ss->cache->location);
ED_region_tag_redraw(vc->ar);
@@ -3388,7 +3378,7 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
event->type);
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
index 9a6251e2f98..266c130d12a 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
@@ -272,7 +272,6 @@ static bool vertex_color_smooth(Object *ob)
{
Mesh *me;
const MPoly *mp;
-
int i, j;
bool *mlooptag;
@@ -282,6 +281,7 @@ static bool vertex_color_smooth(Object *ob)
}
const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
mlooptag = MEM_callocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
@@ -289,15 +289,19 @@ static bool vertex_color_smooth(Object *ob)
mp = me->mpoly;
for (i = 0; i < me->totpoly; i++, mp++) {
const MLoop *ml = me->mloop + mp->loopstart;
- int ml_index = mp->loopstart;
if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
continue;
}
- for (j = 0; j < mp->totloop; j++, ml_index++, ml++) {
- mlooptag[ml_index] = true;
- }
+ j = 0;
+ do {
+ if (!(use_vert_sel && !(me->mvert[ml->v].flag & SELECT))) {
+ mlooptag[mp->loopstart + j] = true;
+ }
+ ml++;
+ j++;
+ } while (j < mp->totloop);
}
/* remove stale me->mcol, will be added later */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
index 6511c90f5e1..71865d0de73 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
@@ -20,13 +20,9 @@
* Intended for use by `paint_vertex.c` & `paint_vertex_color_ops.c`.
*/
-#include "MEM_guardedalloc.h"
-
-#include "DNA_brush_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
#include "BLI_math_base.h"
#include "BLI_math_color.h"
@@ -54,29 +50,37 @@ bool ED_vpaint_color_transform(struct Object *ob,
{
Mesh *me;
const MPoly *mp;
+ int i, j;
if (((me = BKE_mesh_from_object(ob)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) {
return false;
}
const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- mp = me->mpoly;
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
- for (int i = 0; i < me->totpoly; i++, mp++) {
- MLoopCol *lcol = &me->mloopcol[mp->loopstart];
+ mp = me->mpoly;
+ for (i = 0; i < me->totpoly; i++, mp++) {
+ MLoopCol *lcol = me->mloopcol + mp->loopstart;
if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
continue;
}
- for (int j = 0; j < mp->totloop; j++, lcol++) {
- float col_mix[3];
- rgb_uchar_to_float(col_mix, &lcol->r);
+ j = 0;
+ do {
+ uint vidx = me->mloop[mp->loopstart + j].v;
+ if (!(use_vert_sel && !(me->mvert[vidx].flag & SELECT))) {
+ float col_mix[3];
+ rgb_uchar_to_float(col_mix, &lcol->r);
- vpaint_tx_fn(col_mix, user_data, col_mix);
+ vpaint_tx_fn(col_mix, user_data, col_mix);
- rgb_float_to_uchar(&lcol->r, col_mix);
- }
+ rgb_float_to_uchar(&lcol->r, col_mix);
+ }
+ lcol++;
+ j++;
+ } while (j < mp->totloop);
}
/* remove stale me->mcol, will be added later */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
index 4aa9dc8a295..f0fe2d4ebdc 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -24,13 +24,8 @@
#include "BLI_math.h"
#include "BLI_bitmap.h"
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-#include "IMB_colormanagement.h"
-
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "DNA_particle_types.h"
#include "DNA_brush_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -44,7 +39,6 @@
#include "BKE_deform.h"
#include "BKE_mesh.h"
#include "BKE_mesh_iterators.h"
-#include "BKE_mesh_mapping.h"
#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object_deform.h"
@@ -178,11 +172,12 @@ void PAINT_OT_weight_from_bones(wmOperatorType *ot)
/* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */
static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
Mesh *me;
bool changed = false;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
me = BKE_mesh_from_object(vc.obact);
if (me && me->dvert && vc.v3d && vc.rv3d && (vc.obact->actdef != 0)) {
@@ -308,10 +303,11 @@ static const EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C,
if (C) {
wmWindow *win = CTX_wm_window(C);
if (win && win->eventstate) {
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
ViewContext vc;
Mesh *me;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
me = BKE_mesh_from_object(vc.obact);
if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) {
@@ -379,8 +375,9 @@ static const EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C,
static int weight_sample_group_exec(bContext *C, wmOperator *op)
{
int type = RNA_enum_get(op->ptr, "group");
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
BLI_assert(type + 1 >= 0);
vc.obact->actdef = type + 1;
@@ -885,7 +882,7 @@ void PAINT_OT_weight_gradient(wmOperatorType *ot)
prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
+ WM_operator_properties_gesture_straightline(ot, WM_CURSOR_EDIT);
}
/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
index c71315872f6..28699b45add 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
@@ -20,16 +20,12 @@
* Intended for use by `paint_vertex.c` & `paint_vertex_weight_ops.c`.
*/
-#include "MEM_guardedalloc.h"
-
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string_utils.h"
#include "DNA_armature_types.h"
#include "DNA_mesh_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_brush_types.h"
#include "DNA_object_types.h"
#include "BKE_action.h"
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 08febfcc470..b9d621fc1fb 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -27,9 +27,11 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_dial_2d.h"
+#include "BLI_gsqueue.h"
+#include "BLI_ghash.h"
+#include "BLI_hash.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
#include "BLT_translation.h"
@@ -65,7 +67,6 @@
#include "BKE_subsurf.h"
#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -92,22 +93,18 @@
#include <stdlib.h>
#include <string.h>
-/* Sculpt PBVH abstraction API */
-
-/* Do not use these functions while working with PBVH_GRIDS data in SculptSession */
-
-/* TODO: why is this kept, should it be removed? */
-#if 0 /* UNUSED */
+/* Sculpt PBVH abstraction API
+ *
+ * This is read-only, for writing use PBVH vertex iterators. There vd.index matches
+ * the indices used here.
+ *
+ * For multires, the same vertex in multiple grids is counted multiple times, with
+ * different index for each grid. */
-static int sculpt_active_vertex_get(SculptSession *ss)
+static void sculpt_vertex_random_access_init(SculptSession *ss)
{
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- return ss->active_vertex_index;
- case PBVH_BMESH:
- return ss->active_vertex_index;
- default:
- return 0;
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ BM_mesh_elem_index_ensure(ss->bm, BM_VERT);
}
}
@@ -118,65 +115,48 @@ static int sculpt_vertex_count_get(SculptSession *ss)
return ss->totvert;
case PBVH_BMESH:
return BM_mesh_elem_count(BKE_pbvh_get_bmesh(ss->pbvh), BM_VERT);
- default:
- return 0;
+ case PBVH_GRIDS:
+ return BKE_pbvh_get_grid_num_vertices(ss->pbvh);
}
-}
-static void sculpt_vertex_normal_get(SculptSession *ss, int index, float no[3])
-{
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- normal_short_to_float_v3(no, ss->mvert[index].no);
- return;
- case PBVH_BMESH:
- copy_v3_v3(no, BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->no);
- default:
- return;
- }
+ return 0;
}
-static float *sculpt_vertex_co_get(SculptSession *ss, int index)
+const float *sculpt_vertex_co_get(SculptSession *ss, int index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
return ss->mvert[index].co;
case PBVH_BMESH:
return BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->co;
- default:
- return NULL;
- }
-}
-
-static void sculpt_vertex_co_set(SculptSession *ss, int index, float co[3])
-{
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- copy_v3_v3(ss->mvert[index].co, co);
- return;
- case PBVH_BMESH:
- copy_v3_v3(BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->co, co);
- return;
- default:
- return;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int vertex_index = index - grid_index * key->grid_area;
+ CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index];
+ return CCG_elem_co(key, CCG_elem_offset(key, elem, vertex_index));
+ }
}
+ return NULL;
}
-static void sculpt_vertex_mask_set(SculptSession *ss, int index, float mask)
+static void sculpt_vertex_normal_get(SculptSession *ss, int index, float no[3])
{
- BMVert *v;
- float *mask_p;
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- ss->vmask[index] = mask;
+ normal_short_to_float_v3(no, ss->mvert[index].no);
return;
case PBVH_BMESH:
- v = BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index);
- mask_p = BM_ELEM_CD_GET_VOID_P(v, CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK));
- *(mask_p) = mask;
- return;
- default:
- return;
+ copy_v3_v3(no, BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->no);
+ break;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int vertex_index = index - grid_index * key->grid_area;
+ CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index];
+ copy_v3_v3(no, CCG_elem_no(key, CCG_elem_offset(key, elem, vertex_index)));
+ break;
+ }
}
}
@@ -191,25 +171,44 @@ static float sculpt_vertex_mask_get(SculptSession *ss, int index)
v = BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index);
mask = BM_ELEM_CD_GET_VOID_P(v, CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK));
return *mask;
- default:
- return 0;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int vertex_index = index - grid_index * key->grid_area;
+ CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index];
+ return *CCG_elem_mask(key, CCG_elem_offset(key, elem, vertex_index));
+ }
}
+
+ return 0.0f;
}
-static void sculpt_vertex_tag_update(SculptSession *ss, int index)
+static int sculpt_active_vertex_get(SculptSession *ss)
{
+ BLI_assert(BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS);
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- ss->mvert[index].flag |= ME_VERT_PBVH_UPDATE;
- return;
+ return ss->active_vertex_index;
case PBVH_BMESH:
- return;
- default:
- return;
+ return ss->active_vertex_index;
+ case PBVH_GRIDS:
+ return ss->active_vertex_index;
}
+
+ return 0;
}
-# define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256
+static const float *sculpt_active_vertex_co_get(SculptSession *ss)
+{
+ return sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss));
+}
+
+static void sculpt_active_vertex_normal_get(SculptSession *ss, float normal[3])
+{
+ sculpt_vertex_normal_get(ss, sculpt_active_vertex_get(ss), normal);
+}
+
+#define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256
typedef struct SculptVertexNeighborIter {
int *neighbors;
@@ -286,16 +285,26 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
if (poly_get_adj_loops_from_vert(p, ss->mloop, (int)index, f_adj_v) != -1) {
int j;
for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
- if (vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2) {
- if (f_adj_v[j] != (int)index) {
- sculpt_vertex_neighbor_add(iter, f_adj_v[j]);
- }
+ if (f_adj_v[j] != (int)index) {
+ sculpt_vertex_neighbor_add(iter, f_adj_v[j]);
}
}
}
}
}
+static void sculpt_vertex_neighbors_get_grids(SculptSession *UNUSED(ss),
+ int UNUSED(index),
+ SculptVertexNeighborIter *iter)
+{
+ /* TODO: implement this for multires. It might also be worth changing this
+ * iterator to provide a coordinate and mask pointer directly for effiency,
+ * rather than converting back and forth between CCGElem and global index. */
+ iter->size = 0;
+ iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
+ iter->neighbors = iter->neighbors_fixed;
+}
+
static void sculpt_vertex_neighbors_get(SculptSession *ss,
int index,
SculptVertexNeighborIter *iter)
@@ -307,24 +316,247 @@ static void sculpt_vertex_neighbors_get(SculptSession *ss,
case PBVH_BMESH:
sculpt_vertex_neighbors_get_bmesh(ss, index, iter);
return;
- default:
- break;
+ case PBVH_GRIDS:
+ sculpt_vertex_neighbors_get_grids(ss, index, iter);
+ return;
+ }
+}
+
+#define sculpt_vertex_neighbors_iter_begin(ss, v_index, neighbor_iterator) \
+ sculpt_vertex_neighbors_get(ss, v_index, &neighbor_iterator); \
+ for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \
+ neighbor_iterator.i++) { \
+ neighbor_iterator.index = ni.neighbors[ni.i];
+
+#define sculpt_vertex_neighbors_iter_end(neighbor_iterator) \
+ } \
+ if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \
+ MEM_freeN(neighbor_iterator.neighbors); \
+ } \
+ ((void)0)
+
+/* Utils */
+static bool check_vertex_pivot_symmetry(const float vco[3], const float pco[3], const char symm)
+{
+ bool is_in_symmetry_area = true;
+ for (int i = 0; i < 3; i++) {
+ char symm_it = 1 << i;
+ if (symm & symm_it) {
+ if (pco[i] == 0.0f) {
+ if (vco[i] > 0.0f) {
+ is_in_symmetry_area = false;
+ }
+ }
+ if (vco[i] * pco[i] < 0.0f) {
+ is_in_symmetry_area = false;
+ }
+ }
}
+ return is_in_symmetry_area;
}
-# define sculpt_vertex_neighbors_iter_begin(ss, v_index, neighbor_iterator) \
- sculpt_vertex_neighbors_get(ss, v_index, &neighbor_iterator); \
- for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \
- neighbor_iterator.i++) { \
- neighbor_iterator.index = ni.neighbors[ni.i];
+typedef struct NearestVertexTLSData {
+ int nearest_vertex_index;
+ float nearest_vertex_distance_squared;
+} NearestVertexTLSData;
+
+static void do_nearest_vertex_get_task_cb(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ NearestVertexTLSData *nvtd = tls->userdata_chunk;
+ PBVHVertexIter vd;
-# define sculpt_vertex_neighbors_iter_end(neighbor_iterator) \
- } \
- if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \
- MEM_freeN(neighbor_iterator.neighbors); \
+ 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) {
+ nvtd->nearest_vertex_index = vd.index;
+ nvtd->nearest_vertex_distance_squared = distance_squared;
}
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void nearest_vertex_get_finalize(void *__restrict userdata, void *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ NearestVertexTLSData *nvtd = tls;
+ if (data->nearest_vertex_index == -1) {
+ data->nearest_vertex_index = nvtd->nearest_vertex_index;
+ }
+ else if (nvtd->nearest_vertex_distance_squared < data->nearest_vertex_distance_squared) {
+ data->nearest_vertex_index = nvtd->nearest_vertex_index;
+ data->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared;
+ }
+}
+
+static int sculpt_nearest_vertex_get(
+ Sculpt *sd, Object *ob, float co[3], float max_distance, bool use_original)
+{
+ SculptSession *ss = ob->sculpt;
+ PBVHNode **nodes = NULL;
+ int totnode;
+ SculptSearchSphereData data = {
+ .ss = ss,
+ .sd = sd,
+ .radius_squared = max_distance * max_distance,
+ .original = use_original,
+ .center = co,
+ };
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
+ if (totnode == 0) {
+ return -1;
+ }
+
+ SculptThreadedTaskData task_data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .max_distance_squared = max_distance * max_distance,
+ .nearest_vertex_index = -1,
+ };
-#endif /* UNUSED */
+ copy_v3_v3(task_data.nearest_vertex_search_co, co);
+ task_data.nearest_vertex_distance_squared = FLT_MAX;
+ NearestVertexTLSData nvtd;
+ nvtd.nearest_vertex_index = -1;
+ nvtd.nearest_vertex_distance_squared = FLT_MAX;
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ settings.func_finalize = nearest_vertex_get_finalize;
+ settings.userdata_chunk = &nvtd;
+ settings.userdata_chunk_size = sizeof(NearestVertexTLSData);
+ BLI_task_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings);
+
+ MEM_SAFE_FREE(nodes);
+
+ return task_data.nearest_vertex_index;
+}
+
+static bool is_symmetry_iteration_valid(char i, char symm)
+{
+ return i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)));
+}
+
+/* Checks if a vertex is inside the brush radius from any of its mirrored axis */
+static bool sculpt_is_vertex_inside_brush_radius_symm(const float vertex[3],
+ const float br_co[3],
+ float radius,
+ char symm)
+{
+ for (char i = 0; i <= symm; ++i) {
+ if (is_symmetry_iteration_valid(i, symm)) {
+ float location[3];
+ flip_v3_v3(location, br_co, (char)i);
+ if (len_squared_v3v3(location, vertex) < radius * radius) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/* Sculpt Flood Fill API
+ *
+ * Iterate over connected vertices, starting from one or more initial vertices. */
+
+typedef struct SculptFloodFill {
+ GSQueue *queue;
+ char *visited_vertices;
+} SculptFloodFill;
+
+typedef struct SculptFloodFillIterator {
+ int v;
+ int it;
+ float edge_factor;
+} SculptFloodFillIterator;
+
+static void sculpt_floodfill_init(SculptSession *ss, SculptFloodFill *flood)
+{
+ int vertex_count = sculpt_vertex_count_get(ss);
+ sculpt_vertex_random_access_init(ss);
+
+ flood->queue = BLI_gsqueue_new(sizeof(SculptFloodFillIterator));
+ flood->visited_vertices = MEM_callocN(vertex_count * sizeof(char), "visited vertices");
+}
+
+static void sculpt_floodfill_add_initial(SculptFloodFill *flood, int index)
+{
+ SculptFloodFillIterator mevit;
+ mevit.v = index;
+ mevit.it = 0;
+ mevit.edge_factor = 1.0f;
+ BLI_gsqueue_push(flood->queue, &mevit);
+}
+
+static void sculpt_floodfill_add_active(
+ Sculpt *sd, Object *ob, SculptSession *ss, SculptFloodFill *flood, float radius)
+{
+ /* Add active vertex and symmetric vertices to the queue. */
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ for (char i = 0; i <= symm; ++i) {
+ if (is_symmetry_iteration_valid(i, symm)) {
+ int v = -1;
+ if (i == 0) {
+ v = sculpt_active_vertex_get(ss);
+ }
+ else if (radius > 0.0f) {
+ float radius_squared = (radius == FLT_MAX) ? FLT_MAX : radius * radius;
+ float location[3];
+ flip_v3_v3(location, sculpt_active_vertex_co_get(ss), i);
+ v = sculpt_nearest_vertex_get(sd, ob, location, radius_squared, false);
+ }
+ if (v != -1) {
+ sculpt_floodfill_add_initial(flood, v);
+ }
+ }
+ }
+}
+
+static void sculpt_floodfill_execute(SculptSession *ss,
+ SculptFloodFill *flood,
+ bool (*func)(SculptSession *ss,
+ const SculptFloodFillIterator *from,
+ SculptFloodFillIterator *to,
+ void *userdata),
+ void *userdata)
+{
+ /* TODO: multires support, taking into account duplicate vertices and
+ * correctly handling them in the pose, automask and mask expand callbacks. */
+ while (!BLI_gsqueue_is_empty(flood->queue)) {
+ SculptFloodFillIterator from;
+ BLI_gsqueue_pop(flood->queue, &from);
+ SculptVertexNeighborIter ni;
+ sculpt_vertex_neighbors_iter_begin(ss, from.v, ni)
+ {
+ if (flood->visited_vertices[ni.index] == 0) {
+ flood->visited_vertices[ni.index] = 1;
+
+ SculptFloodFillIterator to;
+ to.v = ni.index;
+ to.it = from.it + 1;
+ to.edge_factor = 0.0f;
+
+ if (func(ss, &from, &to, userdata)) {
+ BLI_gsqueue_push(flood->queue, &to);
+ }
+ }
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+ }
+}
+
+static void sculpt_floodfill_free(SculptFloodFill *flood)
+{
+ MEM_SAFE_FREE(flood->visited_vertices);
+ BLI_gsqueue_free(flood->queue);
+ flood->queue = NULL;
+}
/** \name Tool Capabilities
*
@@ -354,13 +586,19 @@ static bool sculpt_has_active_modifiers(Scene *scene, Object *ob)
static bool sculpt_tool_needs_original(const char sculpt_tool)
{
- return ELEM(
- sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB, SCULPT_TOOL_LAYER);
+ return ELEM(sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_LAYER,
+ SCULPT_TOOL_DRAW_SHARP,
+ SCULPT_TOOL_ELASTIC_DEFORM,
+ SCULPT_TOOL_POSE);
}
static bool sculpt_tool_is_proxy_used(const char sculpt_tool)
{
- return ELEM(sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER);
+ return ELEM(sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER, SCULPT_TOOL_POSE);
}
static bool sculpt_brush_use_topology_rake(const SculptSession *ss, const Brush *brush)
@@ -381,9 +619,11 @@ static int sculpt_brush_needs_normal(const SculptSession *ss, const Brush *brush
SCULPT_TOOL_BLOB,
SCULPT_TOOL_CREASE,
SCULPT_TOOL_DRAW,
+ SCULPT_TOOL_DRAW_SHARP,
SCULPT_TOOL_LAYER,
SCULPT_TOOL_NUDGE,
SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_ELASTIC_DEFORM,
SCULPT_TOOL_THUMB) ||
(brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)) ||
@@ -673,14 +913,10 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm &&
- totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP) && !ss->bm, totnode);
BLI_task_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings);
- if (nodes) {
- MEM_freeN(nodes);
- }
+ MEM_SAFE_FREE(nodes);
}
/*** BVH Tree ***/
@@ -748,17 +984,26 @@ void ED_sculpt_redraw_planes_get(float planes[4][4], ARegion *ar, Object *ob)
void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
{
- RegionView3D *rv3d = ss->cache->vc->rv3d;
+ RegionView3D *rv3d = ss->cache ? ss->cache->vc->rv3d : ss->rv3d;
+
+ test->radius_squared = ss->cache ? ss->cache->radius_squared :
+ ss->cursor_radius * ss->cursor_radius;
+ if (ss->cache) {
+ copy_v3_v3(test->location, ss->cache->location);
+ test->mirror_symmetry_pass = ss->cache->mirror_symmetry_pass;
+ }
+ else {
+ copy_v3_v3(test->location, ss->cursor_location);
+ test->mirror_symmetry_pass = 0;
+ }
- test->radius_squared = ss->cache->radius_squared;
- copy_v3_v3(test->location, ss->cache->location);
test->dist = 0.0f; /* just for initialize */
/* Only for 2D projection. */
zero_v4(test->plane_view);
zero_v4(test->plane_tool);
- test->mirror_symmetry_pass = ss->cache->mirror_symmetry_pass;
+ test->mirror_symmetry_pass = ss->cache ? ss->cache->mirror_symmetry_pass : 0;
if (rv3d->rflag & RV3D_CLIPPING) {
test->clip_rv3d = rv3d;
@@ -945,6 +1190,123 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test,
#endif
+/* Automasking */
+
+static bool sculpt_automasking_enabled(SculptSession *ss, const Brush *br)
+{
+ // REMOVE WITH PBVH_GRIDS
+ if (ss->pbvh && BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ return false;
+ }
+
+ if (sculpt_stroke_is_dynamic_topology(ss, br)) {
+ return false;
+ }
+ if (br->automasking_flags & BRUSH_AUTOMASKING_TOPOLOGY) {
+ return true;
+ }
+ return false;
+}
+
+static float sculpt_automasking_factor_get(SculptSession *ss, int vert)
+{
+ if (ss->cache->automask) {
+ return ss->cache->automask[vert];
+ }
+ else {
+ return 1.0f;
+ }
+}
+
+static void sculpt_automasking_end(Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ if (ss->cache && ss->cache->automask) {
+ MEM_freeN(ss->cache->automask);
+ }
+}
+
+static bool sculpt_automasking_is_constrained_by_radius(Brush *br)
+{
+ /* 2D falloff is not constrained by radius */
+ if (br->falloff_shape & BRUSH_AIRBRUSH) {
+ return false;
+ }
+
+ if (ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB)) {
+ return true;
+ }
+ return false;
+}
+
+typedef struct AutomaskFloodFillData {
+ float *automask_factor;
+ float radius;
+ bool use_radius;
+ float location[3];
+ char symm;
+} AutomaskFloodFillData;
+
+static bool automask_floodfill_cb(SculptSession *ss,
+ const SculptFloodFillIterator *UNUSED(from),
+ SculptFloodFillIterator *to,
+ void *userdata)
+{
+ AutomaskFloodFillData *data = userdata;
+
+ data->automask_factor[to->v] = 1.0f;
+ return (!data->use_radius ||
+ sculpt_is_vertex_inside_brush_radius_symm(
+ sculpt_vertex_co_get(ss, to->v), data->location, data->radius, data->symm));
+}
+
+static float *sculpt_topology_automasking_init(Sculpt *sd, Object *ob, float *automask_factor)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ if (!sculpt_automasking_enabled(ss, brush)) {
+ return NULL;
+ }
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
+ BLI_assert(!"Topology masking: pmap missing");
+ return NULL;
+ }
+
+ /* Flood fill automask to connected vertices. Limited to vertices inside
+ * the brush radius if the tool requires it */
+ SculptFloodFill flood;
+ sculpt_floodfill_init(ss, &flood);
+ sculpt_floodfill_add_active(sd, ob, ss, &flood, ss->cache->radius);
+
+ AutomaskFloodFillData fdata = {
+ .automask_factor = automask_factor,
+ .radius = ss->cache->radius,
+ .use_radius = sculpt_automasking_is_constrained_by_radius(brush),
+ .symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL,
+ };
+ copy_v3_v3(fdata.location, sculpt_active_vertex_co_get(ss));
+ sculpt_floodfill_execute(ss, &flood, automask_floodfill_cb, &fdata);
+ sculpt_floodfill_free(&flood);
+
+ return automask_factor;
+}
+
+static void sculpt_automasking_init(Sculpt *sd, Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ ss->cache->automask = MEM_callocN(sizeof(float) * sculpt_vertex_count_get(ss),
+ "automask_factor");
+
+ if (brush->automasking_flags & BRUSH_AUTOMASKING_TOPOLOGY) {
+ sculpt_vertex_random_access_init(ss);
+ sculpt_topology_automasking_init(sd, ob, ss->cache->automask);
+ }
+}
+
/* ===== Sculpting =====
*/
static void flip_v3(float v[3], const char symm)
@@ -986,7 +1348,7 @@ static float calc_radial_symmetry_feather(Sculpt *sd,
float overlap;
overlap = 0;
- for (i = 1; i < sd->radial_symm[axis - 'X']; ++i) {
+ for (i = 1; i < sd->radial_symm[axis - 'X']; i++) {
const float angle = 2 * M_PI * i / sd->radial_symm[axis - 'X'];
overlap += calc_overlap(cache, symm, axis, angle);
}
@@ -1033,24 +1395,28 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
* \note These are all _very_ similar, when changing one, check others.
* \{ */
+typedef struct AreaNormalCenterTLSData {
+ float private_co[2][3];
+ float private_no[2][3];
+ int private_count[2];
+} AreaNormalCenterTLSData;
+
static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
+ const TaskParallelTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
+ AreaNormalCenterTLSData *anctd = tls->userdata_chunk;
float(*area_nos)[3] = data->area_nos;
float(*area_cos)[3] = data->area_cos;
PBVHVertexIter vd;
SculptUndoNode *unode = NULL;
- float private_co[2][3] = {{0.0f}};
- float private_no[2][3] = {{0.0f}};
- int private_count[2] = {0};
bool use_original = false;
- if (ss->cache->original) {
+ if (ss->cache && ss->cache->original) {
unode = sculpt_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
use_original = (unode->co || unode->bm_entry);
}
@@ -1059,6 +1425,13 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ /* Update the test radius to sample the normal using the normal radius of the brush */
+ if (data->brush->ob_mode == OB_MODE_SCULPT) {
+ float test_radius = sqrtf(test.radius_squared);
+ test_radius *= data->brush->normal_radius_factor;
+ test.radius_squared = test_radius * test_radius;
+ }
+
/* when the mesh is edited we can't rely on original coords
* (original mesh may not even have verts in brush radius) */
if (use_original && data->has_bm_orco) {
@@ -1087,12 +1460,12 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
if (area_cos) {
- add_v3_v3(private_co[flip_index], co);
+ add_v3_v3(anctd->private_co[flip_index], co);
}
if (area_nos) {
- add_v3_v3(private_no[flip_index], no);
+ add_v3_v3(anctd->private_no[flip_index], no);
}
- private_count[flip_index] += 1;
+ anctd->private_count[flip_index] += 1;
}
}
}
@@ -1120,6 +1493,8 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
const float *no;
int flip_index;
+ data->any_vertex_sampled = true;
+
if (use_original) {
normal_short_to_float_v3(no_buf, no_s);
no = no_buf;
@@ -1134,38 +1509,42 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
}
}
- flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ flip_index = (dot_v3v3(ss->cache ? ss->cache->view_normal : ss->cursor_view_normal, no) <=
+ 0.0f);
if (area_cos) {
- add_v3_v3(private_co[flip_index], co);
+ add_v3_v3(anctd->private_co[flip_index], co);
}
if (area_nos) {
- add_v3_v3(private_no[flip_index], no);
+ add_v3_v3(anctd->private_no[flip_index], no);
}
- private_count[flip_index] += 1;
+ anctd->private_count[flip_index] += 1;
}
}
BKE_pbvh_vertex_iter_end;
}
+}
- BLI_mutex_lock(&data->mutex);
-
+static void calc_area_normal_and_center_finalize(void *__restrict userdata, void *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ AreaNormalCenterTLSData *anctd = tls;
+ float(*area_nos)[3] = data->area_nos;
+ float(*area_cos)[3] = data->area_cos;
/* for flatten center */
if (area_cos) {
- add_v3_v3(area_cos[0], private_co[0]);
- add_v3_v3(area_cos[1], private_co[1]);
+ add_v3_v3(area_cos[0], anctd->private_co[0]);
+ add_v3_v3(area_cos[1], anctd->private_co[1]);
}
/* for area normal */
if (area_nos) {
- add_v3_v3(area_nos[0], private_no[0]);
- add_v3_v3(area_nos[1], private_no[1]);
+ add_v3_v3(area_nos[0], anctd->private_no[0]);
+ add_v3_v3(area_nos[1], anctd->private_no[1]);
}
/* weights */
- data->count[0] += private_count[0];
- data->count[1] += private_count[1];
-
- BLI_mutex_unlock(&data->mutex);
+ data->count[0] += anctd->private_count[0];
+ data->count[1] += anctd->private_count[1];
}
static void calc_area_center(
@@ -1193,15 +1572,16 @@ static void calc_area_center(
.area_nos = NULL,
.count = count,
};
- BLI_mutex_init(&data.mutex);
+
+ AreaNormalCenterTLSData anctd = {{{0}}};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ settings.func_finalize = calc_area_normal_and_center_finalize;
+ settings.userdata_chunk = &anctd;
+ settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData);
BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
- BLI_mutex_end(&data.mutex);
-
/* for flatten center */
for (n = 0; n < ARRAY_SIZE(area_cos); n++) {
if (count[n] != 0) {
@@ -1218,12 +1598,12 @@ static void calc_area_normal(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3])
{
const Brush *brush = BKE_paint_brush(&sd->paint);
- bool use_threading = (sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT;
+ bool use_threading = (sd->flags & SCULPT_USE_OPENMP);
sculpt_pbvh_calc_area_normal(brush, ob, nodes, totnode, use_threading, r_area_no);
}
/* expose 'calc_area_normal' externally. */
-void sculpt_pbvh_calc_area_normal(const Brush *brush,
+bool sculpt_pbvh_calc_area_normal(const Brush *brush,
Object *ob,
PBVHNode **nodes,
int totnode,
@@ -1249,22 +1629,26 @@ void sculpt_pbvh_calc_area_normal(const Brush *brush,
.area_cos = NULL,
.area_nos = area_nos,
.count = count,
+ .any_vertex_sampled = false,
};
- BLI_mutex_init(&data.mutex);
+
+ AreaNormalCenterTLSData anctd = {{{0}}};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = use_threading;
+ BKE_pbvh_parallel_range_settings(&settings, use_threading, totnode);
+ settings.func_finalize = calc_area_normal_and_center_finalize;
+ settings.userdata_chunk = &anctd;
+ settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData);
BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
- BLI_mutex_end(&data.mutex);
-
/* for area normal */
for (int i = 0; i < ARRAY_SIZE(area_nos); i++) {
if (normalize_v3_v3(r_area_no, area_nos[i]) != 0.0f) {
break;
}
}
+
+ return data.any_vertex_sampled;
}
/* this calculates flatten center and area normal together,
@@ -1295,15 +1679,16 @@ static void calc_area_normal_and_center(
.area_nos = area_nos,
.count = count,
};
- BLI_mutex_init(&data.mutex);
+
+ AreaNormalCenterTLSData anctd = {{{0}}};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ settings.func_finalize = calc_area_normal_and_center_finalize;
+ settings.userdata_chunk = &anctd;
+ settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData);
BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
- BLI_mutex_end(&data.mutex);
-
/* for flatten center */
for (n = 0; n < ARRAY_SIZE(area_cos); n++) {
if (count[n] != 0) {
@@ -1353,6 +1738,7 @@ static float brush_strength(const Sculpt *sd,
case SCULPT_TOOL_CLAY:
case SCULPT_TOOL_CLAY_STRIPS:
case SCULPT_TOOL_DRAW:
+ case SCULPT_TOOL_DRAW_SHARP:
case SCULPT_TOOL_LAYER:
return alpha * flip * pressure * overlap * feather;
@@ -1418,6 +1804,10 @@ static float brush_strength(const Sculpt *sd,
case SCULPT_TOOL_ROTATE:
return alpha * pressure * feather;
+ case SCULPT_TOOL_ELASTIC_DEFORM:
+ case SCULPT_TOOL_POSE:
+ return root_alpha * feather;
+
default:
return 0;
}
@@ -1431,6 +1821,7 @@ float tex_strength(SculptSession *ss,
const short vno[3],
const float fno[3],
const float mask,
+ const int vertex_index,
const int thread_id)
{
StrokeCache *cache = ss->cache;
@@ -1501,6 +1892,9 @@ float tex_strength(SculptSession *ss,
/* Paint mask */
avg *= 1.0f - mask;
+ /* Automasking */
+ avg *= sculpt_automasking_factor_get(ss, vertex_index);
+
return avg;
}
@@ -1508,10 +1902,22 @@ float tex_strength(SculptSession *ss,
bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v)
{
SculptSearchSphereData *data = data_v;
- float *center = data->ss->cache->location, nearest[3];
+ float *center, nearest[3];
+ if (data->center) {
+ center = data->center;
+ }
+ else {
+ center = data->ss->cache ? data->ss->cache->location : data->ss->cursor_location;
+ }
float t[3], bb_min[3], bb_max[3];
int i;
+ if (data->ignore_fully_masked) {
+ if (BKE_pbvh_node_fully_masked_get(node)) {
+ return false;
+ }
+ }
+
if (data->original) {
BKE_pbvh_node_get_original_BB(node, bb_min, bb_max);
}
@@ -1519,7 +1925,7 @@ bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v)
BKE_pbvh_node_get_BB(node, bb_min, bb_max);
}
- for (i = 0; i < 3; ++i) {
+ for (i = 0; i < 3; i++) {
if (bb_min[i] > center[i]) {
nearest[i] = bb_min[i];
}
@@ -1542,6 +1948,12 @@ bool sculpt_search_circle_cb(PBVHNode *node, void *data_v)
SculptSearchCircleData *data = data_v;
float bb_min[3], bb_max[3];
+ if (data->ignore_fully_masked) {
+ if (BKE_pbvh_node_fully_masked_get(node)) {
+ return false;
+ }
+ }
+
if (data->original) {
BKE_pbvh_node_get_original_BB(node, bb_min, bb_max);
}
@@ -1561,7 +1973,7 @@ static void sculpt_clip(Sculpt *sd, SculptSession *ss, float co[3], const float
{
int i;
- for (i = 0; i < 3; ++i) {
+ for (i = 0; i < 3; i++) {
if (sd->flags & (SCULPT_LOCK_X << i)) {
continue;
}
@@ -1575,6 +1987,25 @@ static void sculpt_clip(Sculpt *sd, SculptSession *ss, float co[3], const float
}
}
+static PBVHNode **sculpt_pbvh_gather_cursor_update(Object *ob,
+ Sculpt *sd,
+ bool use_original,
+ int *r_totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ PBVHNode **nodes = NULL;
+ SculptSearchSphereData data = {
+ .ss = ss,
+ .sd = sd,
+ .radius_squared = ss->cursor_radius,
+ .original = use_original,
+ .ignore_fully_masked = false,
+ .center = NULL,
+ };
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, r_totnode);
+ return nodes;
+}
+
static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
Sculpt *sd,
const Brush *brush,
@@ -1585,13 +2016,16 @@ static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
SculptSession *ss = ob->sculpt;
PBVHNode **nodes = NULL;
- /* Build a list of all nodes that are potentially within the brush's area of influence */
+ /* Build a list of all nodes that are potentially within the cursor or brush's area of influence
+ */
if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
SculptSearchSphereData data = {
.ss = ss,
.sd = sd,
.radius_squared = SQUARE(ss->cache->radius * radius_scale),
.original = use_original,
+ .ignore_fully_masked = brush->sculpt_tool != SCULPT_TOOL_MASK,
+ .center = NULL,
};
BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, r_totnode);
}
@@ -1602,9 +2036,10 @@ static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
SculptSearchCircleData data = {
.ss = ss,
.sd = sd,
- .radius_squared = SQUARE(ss->cache->radius * radius_scale),
+ .radius_squared = ss->cache ? SQUARE(ss->cache->radius * radius_scale) : ss->cursor_radius,
.original = use_original,
.dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc,
+ .ignore_fully_masked = brush->sculpt_tool != SCULPT_TOOL_MASK,
};
BKE_pbvh_search_gather(ss->pbvh, sculpt_search_circle_cb, &data, &nodes, r_totnode);
}
@@ -1839,92 +2274,51 @@ static void bmesh_neighbor_average(float avg[3], BMVert *v)
copy_v3_v3(avg, v->co);
}
-/* For bmesh: average only the four most aligned (parallel and perpendicular) edges
- * relative to a direction. Naturally converges to a quad-like tessellation. */
+/* For bmesh: Average surrounding verts based on an orthogonality measure.
+ * Naturally converges to a quad-like structure. */
static void bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert *v)
{
- /* Logic for 3 or more is identical. */
- const int vfcount = BM_vert_face_count_at_most(v, 3);
-
- /* Don't modify corner vertices. */
- if (vfcount < 2) {
- copy_v3_v3(avg, v->co);
- return;
- }
-
- /* Project the direction to the vertex normal and create an additional
- * parallel vector. */
- float dir_a[3], dir_b[3];
- cross_v3_v3v3(dir_a, direction, v->no);
- cross_v3_v3v3(dir_b, dir_a, v->no);
-
- /* The four vectors which will be used for smoothing.
- * Occasionally less than 4 verts match the requirements in that case
- * use 'v' as fallback. */
- BMVert *pos_a = v;
- BMVert *neg_a = v;
- BMVert *pos_b = v;
- BMVert *neg_b = v;
-
- float pos_score_a = 0.0f;
- float neg_score_a = 0.0f;
- float pos_score_b = 0.0f;
- float neg_score_b = 0.0f;
-
- BMIter liter;
- BMLoop *l;
-
- BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- BMVert *adj_v[2] = {l->prev->v, l->next->v};
- for (int i = 0; i < ARRAY_SIZE(adj_v); i++) {
- BMVert *v_other = adj_v[i];
+ float avg_co[3] = {0, 0, 0};
+ float tot_co = 0;
- if (vfcount != 2 || BM_vert_face_count_at_most(v_other, 2) <= 2) {
- float vec[3];
- sub_v3_v3v3(vec, v_other->co, v->co);
- normalize_v3(vec);
+ BMIter eiter;
+ BMEdge *e;
- /* The score is a measure of how orthogonal the edge is. */
- float score = dot_v3v3(vec, dir_a);
-
- if (score >= pos_score_a) {
- pos_a = v_other;
- pos_score_a = score;
- }
- else if (score < neg_score_a) {
- neg_a = v_other;
- neg_score_a = score;
- }
- /* The same scoring but for the perpendicular direction. */
- score = dot_v3v3(vec, dir_b);
-
- if (score >= pos_score_b) {
- pos_b = v_other;
- pos_score_b = score;
- }
- else if (score < neg_score_b) {
- neg_b = v_other;
- neg_score_b = score;
- }
- }
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ if (BM_edge_is_boundary(e)) {
+ copy_v3_v3(avg, v->co);
+ return;
}
+ BMVert *v_other = (e->v1 == v) ? e->v2 : e->v1;
+ float vec[3];
+ sub_v3_v3v3(vec, v_other->co, v->co);
+ madd_v3_v3fl(vec, v->no, -dot_v3v3(vec, v->no));
+ normalize_v3(vec);
+
+ /* fac is a measure of how orthogonal or parallel the edge is
+ * relative to the direction */
+ float fac = dot_v3v3(vec, direction);
+ fac = fac * fac - 0.5f;
+ fac *= fac;
+ madd_v3_v3fl(avg_co, v_other->co, fac);
+ tot_co += fac;
}
- /* Average everything together. */
- zero_v3(avg);
- add_v3_v3(avg, pos_a->co);
- add_v3_v3(avg, neg_a->co);
- add_v3_v3(avg, pos_b->co);
- add_v3_v3(avg, neg_b->co);
- mul_v3_fl(avg, 0.25f);
+ /* In case vert has no Edge s */
+ if (tot_co > 0) {
+ mul_v3_v3fl(avg, avg_co, 1.0f / tot_co);
- /* Preserve volume. */
- float vec[3];
- sub_v3_v3(avg, v->co);
- mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no));
- sub_v3_v3(avg, vec);
- add_v3_v3(avg, v->co);
+ /* Preserve volume. */
+ float vec[3];
+ sub_v3_v3(avg, v->co);
+ mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no));
+ sub_v3_v3(avg, vec);
+ add_v3_v3(avg, v->co);
+ }
+ else {
+ zero_v3(avg);
+ }
}
/* Same logic as neighbor_average_mask(), but for bmesh rather than mesh */
@@ -1956,6 +2350,48 @@ static float bmesh_neighbor_average_mask(BMVert *v, const int cd_vert_mask_offse
}
}
+static void grids_neighbor_average(SculptSession *ss, float result[3], int index)
+{
+ float avg[3] = {0.0f, 0.0f, 0.0f};
+ int total = 0;
+
+ SculptVertexNeighborIter ni;
+ sculpt_vertex_neighbors_iter_begin(ss, index, ni)
+ {
+ add_v3_v3(avg, sculpt_vertex_co_get(ss, ni.index));
+ total++;
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+
+ if (total > 0) {
+ mul_v3_v3fl(result, avg, 1.0f / (float)total);
+ }
+ else {
+ copy_v3_v3(result, sculpt_vertex_co_get(ss, index));
+ }
+}
+
+static float grids_neighbor_average_mask(SculptSession *ss, int index)
+{
+ float avg = 0.0f;
+ int total = 0;
+
+ SculptVertexNeighborIter ni;
+ sculpt_vertex_neighbors_iter_begin(ss, index, ni)
+ {
+ avg += sculpt_vertex_mask_get(ss, ni.index);
+ total++;
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+
+ if (total > 0) {
+ return avg / (float)total;
+ }
+ else {
+ return sculpt_vertex_mask_get(ss, index);
+ }
+}
+
/* Note: uses after-struct allocated mem to store actual cache... */
typedef struct SculptDoBrushSmoothGridDataChunk {
size_t tmpgrid_size;
@@ -1964,10 +2400,14 @@ typedef struct SculptDoBrushSmoothGridDataChunk {
typedef struct {
SculptSession *ss;
const float *ray_start;
+ const float *ray_normal;
bool hit;
float depth;
bool original;
+ int active_vertex_index;
+ float *face_normal;
+
struct IsectRayPrecalc isect_precalc;
} SculptRaycastData;
@@ -2018,6 +2458,7 @@ static void do_smooth_brush_mesh_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
+ vd.index,
tls->thread_id);
if (smooth_mask) {
float val = neighbor_average_mask(ss, vd.vert_indices[vd.i]) - *vd.mask;
@@ -2073,6 +2514,7 @@ static void do_smooth_brush_bmesh_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
smooth_mask ? 0.0f : *vd.mask,
+ vd.index,
tls->thread_id);
if (smooth_mask) {
float val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask;
@@ -2115,6 +2557,7 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
mul_v3_v3fl(
tmp, ss->cache->sculpt_normal_symm, dot_v3v3(ss->cache->sculpt_normal_symm, direction));
sub_v3_v3(direction, tmp);
+ normalize_v3(direction);
/* Cancel if there's no grab data. */
if (is_zero_v3(direction)) {
@@ -2132,11 +2575,17 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade =
- bstrength *
- tex_strength(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, tls->thread_id) *
- ss->cache->pressure;
+ const float fade = bstrength *
+ tex_strength(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ *vd.mask,
+ vd.index,
+ tls->thread_id) *
+ ss->cache->pressure;
float avg[3], val[3];
@@ -2169,7 +2618,6 @@ static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata,
float bstrength = data->strength;
CCGElem **griddata, *gddata;
- CCGKey key;
float(*tmpgrid_co)[3] = NULL;
float tmprow_co[2][3];
@@ -2188,7 +2636,7 @@ static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata,
BKE_pbvh_node_get_grids(
ss->pbvh, data->nodes[n], &grid_indices, &totgrid, NULL, &gridsize, &griddata);
- BKE_pbvh_get_grid_key(ss->pbvh, &key);
+ CCGKey key = *BKE_pbvh_get_grid_key(ss->pbvh);
grid_hidden = BKE_pbvh_grid_hidden(ss->pbvh);
@@ -2280,7 +2728,7 @@ static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata,
const float fade =
bstrength *
tex_strength(
- ss, brush, co, sqrtf(test.dist), NULL, fno, strength_mask, tls->thread_id);
+ ss, brush, co, sqrtf(test.dist), NULL, fno, strength_mask, 0, tls->thread_id);
float f = 1.0f / 16.0f;
if (x == 0 || x == gridsize - 1) {
@@ -2336,7 +2784,7 @@ static void smooth(Sculpt *sd,
return;
}
- for (iteration = 0; iteration <= count; ++iteration) {
+ for (iteration = 0; iteration <= count; iteration++) {
const float strength = (iteration != count) ? 1.0f : last;
SculptThreadedTaskData data = {
@@ -2349,8 +2797,7 @@ static void smooth(Sculpt *sd,
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
switch (type) {
case PBVH_GRIDS: {
@@ -2399,7 +2846,7 @@ static void bmesh_topology_rake(
const int count = iterations * bstrength + 1;
const float factor = iterations * bstrength / count;
- for (iteration = 0; iteration <= count; ++iteration) {
+ for (iteration = 0; iteration <= count; iteration++) {
SculptThreadedTaskData data = {
.sd = sd,
@@ -2409,8 +2856,7 @@ static void bmesh_topology_rake(
.strength = factor,
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
}
@@ -2441,7 +2887,7 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
{
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = tex_strength(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, tls->thread_id);
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, tls->thread_id);
(*vd.mask) += fade * bstrength;
CLAMP(*vd.mask, 0, 1);
@@ -2467,8 +2913,7 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings);
}
@@ -2516,6 +2961,7 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -2554,11 +3000,86 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings);
}
+static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *offset = data->offset;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+
+ 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)) {
+ /* offset vertex */
+ const float fade = tex_strength(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ tls->thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], offset, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float offset[3];
+ const float bstrength = ss->cache->bstrength;
+
+ /* offset with as much as possible factored in already */
+ mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
+ mul_v3_v3(offset, ss->cache->scale);
+ mul_v3_fl(offset, bstrength);
+
+ /* XXX - this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
+ * initialize before threads so they can do curve mapping */
+ BKE_curvemapping_initialize(brush->curve);
+
+ /* threaded loop over nodes */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .offset = offset,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
+}
+
/**
* Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB'
*/
@@ -2593,6 +3114,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
float val1[3];
float val2[3];
@@ -2670,8 +3192,7 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings);
}
@@ -2703,6 +3224,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
float val[3];
@@ -2732,8 +3254,7 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings);
}
@@ -2771,6 +3292,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
orig_data.no,
NULL,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -2804,11 +3326,613 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
}
+/* Regularized Kelvinlets: Sculpting Brushes based on Fundamental Solutions of Elasticity
+ * Pixar Technical Memo #17-03 */
+
+typedef struct KelvinletParams {
+ float f;
+ float a;
+ float b;
+ float c;
+ float radius_scaled;
+} KelvinletParams;
+
+static int sculpt_kelvinlet_get_scale_iteration_count(eBrushElasticDeformType type)
+{
+ if (type == BRUSH_ELASTIC_DEFORM_GRAB) {
+ return 1;
+ }
+ if (type == BRUSH_ELASTIC_DEFORM_GRAB_BISCALE) {
+ return 2;
+ }
+ if (type == BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE) {
+ return 3;
+ }
+ return 0;
+}
+
+static void sculpt_kelvinet_integrate(void (*kelvinlet)(float disp[3],
+ const float vertex_co[3],
+ const float location[3],
+ float normal[3],
+ KelvinletParams *p),
+ float r_disp[3],
+ const float vertex_co[3],
+ const float location[3],
+ float normal[3],
+ KelvinletParams *p)
+{
+ float k[4][3], k_it[4][3];
+ kelvinlet(k[0], vertex_co, location, normal, p);
+ copy_v3_v3(k_it[0], k[0]);
+ mul_v3_fl(k_it[0], 0.5f);
+ add_v3_v3v3(k_it[0], vertex_co, k_it[0]);
+ kelvinlet(k[1], k_it[0], location, normal, p);
+ copy_v3_v3(k_it[1], k[1]);
+ mul_v3_fl(k_it[1], 0.5f);
+ add_v3_v3v3(k_it[1], vertex_co, k_it[1]);
+ kelvinlet(k[2], k_it[1], location, normal, p);
+ copy_v3_v3(k_it[2], k[2]);
+ add_v3_v3v3(k_it[2], vertex_co, k_it[2]);
+ sub_v3_v3v3(k_it[2], k_it[2], location);
+ kelvinlet(k[3], k_it[2], location, normal, p);
+ copy_v3_v3(r_disp, k[0]);
+ madd_v3_v3fl(r_disp, k[1], 2);
+ madd_v3_v3fl(r_disp, k[2], 2);
+ add_v3_v3(r_disp, k[3]);
+ mul_v3_fl(r_disp, 1.0f / 6.0f);
+}
+
+/* Regularized Kelvinlets: Formula (16) */
+static void sculpt_kelvinlet_scale(float disp[3],
+ const float vertex_co[3],
+ const float location[3],
+ float UNUSED(normal[3]),
+ KelvinletParams *p)
+{
+ float r_v[3];
+ sub_v3_v3v3(r_v, vertex_co, location);
+ float r = len_v3(r_v);
+ float r_e = sqrtf(r * r + p->radius_scaled * p->radius_scaled);
+ float u = (2.0f * p->b - p->a) * ((1.0f / (r_e * r_e * r_e))) +
+ ((3.0f * p->radius_scaled * p->radius_scaled) / (2.0f * r_e * r_e * r_e * r_e * r_e));
+ float fade = u * p->c;
+ mul_v3_v3fl(disp, r_v, fade * p->f);
+}
+
+/* Regularized Kelvinlets: Formula (15) */
+static void sculpt_kelvinlet_twist(float disp[3],
+ const float vertex_co[3],
+ const float location[3],
+ float normal[3],
+ KelvinletParams *p)
+{
+ float r_v[3], q_r[3];
+ sub_v3_v3v3(r_v, vertex_co, location);
+ float r = len_v3(r_v);
+ float r_e = sqrtf(r * r + p->radius_scaled * p->radius_scaled);
+ float u = -p->a * ((1.0f / (r_e * r_e * r_e))) +
+ ((3.0f * p->radius_scaled * p->radius_scaled) / (2.0f * r_e * r_e * r_e * r_e * r_e));
+ float fade = u * p->c;
+ cross_v3_v3v3(q_r, normal, r_v);
+ mul_v3_v3fl(disp, q_r, fade * p->f);
+}
+
+static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *grab_delta = data->grab_delta;
+ const float *location = ss->cache->location;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+
+ const float bstrength = ss->cache->bstrength;
+
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ /* Maybe this can be exposed to the user */
+ float radius_e[3] = {1.0f, 2.0f, 2.0f};
+ float r_e[3];
+ float kvl[3];
+ float radius_scaled[3];
+
+ radius_scaled[0] = ss->cache->radius * radius_e[0];
+ radius_scaled[1] = radius_scaled[0] * radius_e[1];
+ radius_scaled[2] = radius_scaled[1] * radius_e[2];
+
+ float shear_modulus = 1.0f;
+ float poisson_ratio = brush->elastic_deform_volume_preservation;
+
+ float a = 1.0f / (4.0f * (float)M_PI * shear_modulus);
+ float b = a / (4.0f * (1.0f - poisson_ratio));
+ float c = 2 * (3.0f * a - 2.0f * b);
+
+ float dir;
+ if (ss->cache->mouse[0] > ss->cache->initial_mouse[0]) {
+ dir = 1.0f;
+ }
+ else {
+ dir = -1.0f;
+ }
+
+ if (brush->elastic_deform_type == BRUSH_ELASTIC_DEFORM_TWIST) {
+ int symm = ss->cache->mirror_symmetry_pass;
+ if (symm == 1 || symm == 2 || symm == 4 || symm == 7) {
+ dir = -dir;
+ }
+ }
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+ float fade, final_disp[3], weights[3];
+ float r = len_v3v3(location, orig_data.co);
+ KelvinletParams params;
+ params.a = a;
+ params.b = b;
+ params.c = c;
+ params.radius_scaled = radius_scaled[0];
+
+ int multi_scale_it = sculpt_kelvinlet_get_scale_iteration_count(brush->elastic_deform_type);
+ for (int it = 0; it < max_ii(1, multi_scale_it); it++) {
+ r_e[it] = sqrtf(r * r + radius_scaled[it] * radius_scaled[it]);
+ }
+
+ /* Regularized Kelvinlets: Formula (6) */
+ for (int s_it = 0; s_it < multi_scale_it; s_it++) {
+ kvl[s_it] = ((a - b) / r_e[s_it]) + ((b * r * r) / (r_e[s_it] * r_e[s_it] * r_e[s_it])) +
+ ((a * radius_scaled[s_it] * radius_scaled[s_it]) /
+ (2.0f * r_e[s_it] * r_e[s_it] * r_e[s_it]));
+ }
+
+ switch (brush->elastic_deform_type) {
+ /* Regularized Kelvinlets: Multi-scale extrapolation. Formula (11) */
+ case BRUSH_ELASTIC_DEFORM_GRAB:
+ fade = kvl[0] * c;
+ mul_v3_v3fl(final_disp, grab_delta, fade * bstrength * 20.f);
+ break;
+ case BRUSH_ELASTIC_DEFORM_GRAB_BISCALE: {
+ const float u = kvl[0] - kvl[1];
+ fade = u * c / ((1.0f / radius_scaled[0]) - (1.0f / radius_scaled[1]));
+ mul_v3_v3fl(final_disp, grab_delta, fade * bstrength * 20.0f);
+ break;
+ }
+ case BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE: {
+ weights[0] = 1.0f;
+ weights[1] = -(
+ (radius_scaled[2] * radius_scaled[2] - radius_scaled[0] * radius_scaled[0]) /
+ (radius_scaled[2] * radius_scaled[2] - radius_scaled[1] * radius_scaled[1]));
+ weights[2] = ((radius_scaled[1] * radius_scaled[1] - radius_scaled[0] * radius_scaled[0]) /
+ (radius_scaled[2] * radius_scaled[2] - radius_scaled[1] * radius_scaled[1]));
+
+ const float u = weights[0] * kvl[0] + weights[1] * kvl[1] + weights[2] * kvl[2];
+ fade = u * c /
+ (weights[0] / radius_scaled[0] + weights[1] / radius_scaled[1] +
+ weights[2] / radius_scaled[2]);
+ mul_v3_v3fl(final_disp, grab_delta, fade * bstrength * 20.0f);
+ break;
+ }
+ case BRUSH_ELASTIC_DEFORM_SCALE:
+ params.f = len_v3(grab_delta) * dir * bstrength;
+ sculpt_kelvinet_integrate(sculpt_kelvinlet_scale,
+ final_disp,
+ orig_data.co,
+ location,
+ ss->cache->sculpt_normal_symm,
+ &params);
+ break;
+ case BRUSH_ELASTIC_DEFORM_TWIST:
+ params.f = len_v3(grab_delta) * dir * bstrength;
+ sculpt_kelvinet_integrate(sculpt_kelvinlet_twist,
+ final_disp,
+ orig_data.co,
+ location,
+ ss->cache->sculpt_normal_symm,
+ &params);
+ break;
+ }
+
+ if (vd.mask) {
+ mul_v3_fl(final_disp, 1.0f - *vd.mask);
+ }
+
+ mul_v3_fl(final_disp, sculpt_automasking_factor_get(ss, vd.index));
+
+ copy_v3_v3(proxy[vd.i], final_disp);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .grab_delta = grab_delta,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
+}
+
+static void do_pose_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+
+ PBVHVertexIter vd;
+ float disp[3], val[3];
+ float final_pos[3];
+
+ 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)
+ {
+
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+ if (check_vertex_pivot_symmetry(
+ orig_data.co, data->pose_initial_co, ss->cache->mirror_symmetry_pass)) {
+ copy_v3_v3(val, orig_data.co);
+ mul_m4_v3(data->transform_trans_inv, val);
+ mul_m4_v3(data->transform_rot, val);
+ mul_m4_v3(data->transform_trans, val);
+ sub_v3_v3v3(disp, val, orig_data.co);
+
+ mul_v3_fl(disp, ss->cache->pose_factor[vd.index]);
+ float mask = vd.mask ? *vd.mask : 0.0f;
+ mul_v3_fl(disp, 1.0f - mask);
+ add_v3_v3v3(final_pos, orig_data.co, disp);
+ copy_v3_v3(vd.co, final_pos);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3], rot_quat[4], initial_v[3], current_v[3], temp[3];
+ float pose_origin[3];
+ float pose_initial_co[3];
+ float transform_rot[4][4], transform_trans[4][4], transform_trans_inv[4][4];
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ return;
+ }
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ copy_v3_v3(pose_origin, ss->cache->pose_origin);
+ flip_v3(pose_origin, (char)ss->cache->mirror_symmetry_pass);
+
+ copy_v3_v3(pose_initial_co, ss->cache->pose_initial_co);
+ flip_v3(pose_initial_co, (char)ss->cache->mirror_symmetry_pass);
+
+ sub_v3_v3v3(initial_v, pose_initial_co, pose_origin);
+ normalize_v3(initial_v);
+
+ add_v3_v3v3(temp, pose_initial_co, grab_delta);
+ sub_v3_v3v3(current_v, temp, pose_origin);
+ normalize_v3(current_v);
+
+ rotation_between_vecs_to_quat(rot_quat, initial_v, current_v);
+ unit_m4(transform_rot);
+ unit_m4(transform_trans);
+ quat_to_mat4(transform_rot, rot_quat);
+ translate_m4(transform_trans, pose_origin[0], pose_origin[1], pose_origin[2]);
+ invert_m4_m4(transform_trans_inv, transform_trans);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .grab_delta = grab_delta,
+ .pose_origin = pose_origin,
+ .pose_initial_co = pose_initial_co,
+ .transform_rot = transform_rot,
+ .transform_trans = transform_trans,
+ .transform_trans_inv = transform_trans_inv,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings);
+}
+
+typedef struct PoseGrowFactorTLSData {
+ float pos_avg[3];
+ int tot_pos_avg;
+} PoseGrowFactorTLSData;
+
+static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ PoseGrowFactorTLSData *gftd = tls->userdata_chunk;
+ SculptSession *ss = data->ob->sculpt;
+ const char symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ const float *active_co = sculpt_active_vertex_co_get(ss);
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ SculptVertexNeighborIter ni;
+ float max = 0.0f;
+ sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
+ {
+ float vmask_f = data->prev_mask[ni.index];
+ if (vmask_f > max) {
+ max = vmask_f;
+ }
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+ if (max != data->prev_mask[vd.index]) {
+ data->pose_factor[vd.index] = max;
+ if (check_vertex_pivot_symmetry(vd.co, active_co, symm)) {
+ add_v3_v3(gftd->pos_avg, vd.co);
+ gftd->tot_pos_avg++;
+ }
+ }
+ }
+
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void pose_brush_grow_factor_finalize(void *__restrict userdata, void *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ PoseGrowFactorTLSData *gftd = tls;
+ add_v3_v3(data->tot_pos_avg, gftd->pos_avg);
+ data->tot_pos_count += gftd->tot_pos_avg;
+}
+
+/* Grow the factor until its boundary is near to the offset pose origin */
+static void sculpt_pose_grow_pose_factor(
+ Sculpt *sd, Object *ob, SculptSession *ss, float pose_origin[3], float *pose_factor)
+{
+ PBVHNode **nodes;
+ PBVH *pbvh = ob->sculpt->pbvh;
+ int totnode;
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .totnode = totnode,
+ .pose_factor = pose_factor,
+ };
+ TaskParallelSettings settings;
+ PoseGrowFactorTLSData gftd;
+ gftd.tot_pos_avg = 0;
+ zero_v3(gftd.pos_avg);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ settings.func_finalize = pose_brush_grow_factor_finalize;
+ settings.userdata_chunk = &gftd;
+ settings.userdata_chunk_size = sizeof(PoseGrowFactorTLSData);
+
+ bool grow_next_iteration = true;
+ float prev_len = FLT_MAX;
+ data.prev_mask = MEM_mallocN(sculpt_vertex_count_get(ss) * sizeof(float), "prev mask");
+ while (grow_next_iteration) {
+ zero_v3(data.tot_pos_avg);
+ data.tot_pos_count = 0;
+ zero_v3(gftd.pos_avg);
+ gftd.tot_pos_avg = 0;
+ memcpy(data.prev_mask, pose_factor, sculpt_vertex_count_get(ss) * sizeof(float));
+ BLI_task_parallel_range(0, totnode, &data, pose_brush_grow_factor_task_cb_ex, &settings);
+ if (data.tot_pos_count != 0) {
+ mul_v3_fl(data.tot_pos_avg, 1.0f / (float)data.tot_pos_count);
+ float len = len_v3v3(data.tot_pos_avg, pose_origin);
+ if (len < prev_len) {
+ prev_len = len;
+ grow_next_iteration = true;
+ }
+ else {
+ grow_next_iteration = false;
+ memcpy(pose_factor, data.prev_mask, sculpt_vertex_count_get(ss) * sizeof(float));
+ }
+ }
+ else {
+ grow_next_iteration = false;
+ }
+ }
+ MEM_freeN(data.prev_mask);
+
+ MEM_SAFE_FREE(nodes);
+}
+
+static bool sculpt_pose_brush_is_vertex_inside_brush_radius(const float vertex[3],
+ const float br_co[3],
+ float radius,
+ char symm)
+{
+ for (char i = 0; i <= symm; ++i) {
+ if (is_symmetry_iteration_valid(i, symm)) {
+ float location[3];
+ flip_v3_v3(location, br_co, (char)i);
+ if (len_v3v3(location, vertex) < radius) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/* Calculate the pose origin and (Optionaly the pose factor) that is used when using the pose brush
+ *
+ * r_pose_origin must be a valid pointer. the r_pose_factor is optional. When set to NULL it won't
+ * be calculated. */
+typedef struct PoseFloodFillData {
+ float pose_initial_co[3];
+ float radius;
+ int symm;
+
+ float *pose_factor;
+ float pose_origin[3];
+ int tot_co;
+} PoseFloodFillData;
+
+static bool pose_floodfill_cb(SculptSession *ss,
+ const SculptFloodFillIterator *UNUSED(from),
+ SculptFloodFillIterator *to,
+ void *userdata)
+{
+ PoseFloodFillData *data = userdata;
+
+ if (data->pose_factor) {
+ data->pose_factor[to->v] = 1.0f;
+ }
+
+ const float *co = sculpt_vertex_co_get(ss, to->v);
+ if (sculpt_pose_brush_is_vertex_inside_brush_radius(
+ co, data->pose_initial_co, data->radius, data->symm)) {
+ return true;
+ }
+ else if (check_vertex_pivot_symmetry(co, data->pose_initial_co, data->symm)) {
+ add_v3_v3(data->pose_origin, co);
+ data->tot_co++;
+ }
+
+ return false;
+}
+
+void sculpt_pose_calc_pose_data(Sculpt *sd,
+ Object *ob,
+ SculptSession *ss,
+ float initial_location[3],
+ float radius,
+ float pose_offset,
+ float *r_pose_origin,
+ float *r_pose_factor)
+{
+ sculpt_vertex_random_access_init(ss);
+
+ /* Calculate the pose rotation point based on the boundaries of the brush factor. */
+ SculptFloodFill flood;
+ sculpt_floodfill_init(ss, &flood);
+ sculpt_floodfill_add_active(sd, ob, ss, &flood, (r_pose_factor) ? radius : 0.0f);
+
+ PoseFloodFillData fdata = {
+ .radius = radius,
+ .symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL,
+ .pose_factor = r_pose_factor,
+ .tot_co = 0,
+ };
+ zero_v3(fdata.pose_origin);
+ copy_v3_v3(fdata.pose_initial_co, initial_location);
+ sculpt_floodfill_execute(ss, &flood, pose_floodfill_cb, &fdata);
+ sculpt_floodfill_free(&flood);
+
+ if (fdata.tot_co > 0) {
+ mul_v3_fl(fdata.pose_origin, 1.0f / (float)fdata.tot_co);
+ }
+
+ /* Offset the pose origin */
+ float pose_d[3];
+ sub_v3_v3v3(pose_d, fdata.pose_origin, fdata.pose_initial_co);
+ normalize_v3(pose_d);
+ madd_v3_v3fl(fdata.pose_origin, pose_d, radius * pose_offset);
+ copy_v3_v3(r_pose_origin, fdata.pose_origin);
+
+ if (pose_offset != 0.0f && r_pose_factor) {
+ sculpt_pose_grow_pose_factor(sd, ob, ss, fdata.pose_origin, r_pose_factor);
+ }
+}
+
+static void pose_brush_init_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ SculptVertexNeighborIter ni;
+ float avg = 0;
+ int total = 0;
+ sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
+ {
+ avg += ss->cache->pose_factor[ni.index];
+ total++;
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+
+ if (total > 0) {
+ ss->cache->pose_factor[vd.index] = avg / (float)total;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void sculpt_pose_brush_init(
+ Sculpt *sd, Object *ob, SculptSession *ss, Brush *br, float initial_location[3], float radius)
+{
+ float *pose_factor = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(float), "Pose factor");
+
+ sculpt_pose_calc_pose_data(
+ sd, ob, ss, initial_location, radius, br->pose_offset, ss->cache->pose_origin, pose_factor);
+
+ copy_v3_v3(ss->cache->pose_initial_co, initial_location);
+ ss->cache->pose_factor = pose_factor;
+
+ PBVHNode **nodes;
+ PBVH *pbvh = ob->sculpt->pbvh;
+ int totnode;
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = br,
+ .nodes = nodes,
+ };
+
+ /* Smooth the pose brush factor for cleaner deformation */
+ for (int i = 0; i < 4; i++) {
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BLI_task_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings);
+ }
+
+ MEM_SAFE_FREE(nodes);
+}
+
static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
@@ -2838,6 +3962,7 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -2871,8 +3996,7 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings);
}
@@ -2911,6 +4035,7 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -2992,8 +4117,7 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings);
}
@@ -3031,6 +4155,7 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
orig_data.no,
NULL,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -3064,8 +4189,7 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings);
}
@@ -3104,6 +4228,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
orig_data.no,
NULL,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
@@ -3137,8 +4262,7 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings);
}
@@ -3183,6 +4307,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
float *disp = &layer_disp[vd.i];
float val[3];
@@ -3234,8 +4359,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
BLI_mutex_init(&data.mutex);
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
BLI_mutex_end(&data.mutex);
@@ -3269,6 +4393,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
float val[3];
@@ -3302,8 +4427,7 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings);
}
@@ -3315,7 +4439,8 @@ static void calc_sculpt_plane(
if (ss->cache->mirror_symmetry_pass == 0 && ss->cache->radial_symmetry_pass == 0 &&
ss->cache->tile_pass == 0 &&
- (ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) {
+ (ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_PLANE) ||
+ !(brush->flag & BRUSH_ORIGINAL_NORMAL))) {
switch (brush->sculpt_plane) {
case SCULPT_DISP_DIR_VIEW:
copy_v3_v3(r_area_no, ss->cache->true_view_normal);
@@ -3352,10 +4477,20 @@ static void calc_sculpt_plane(
}
/* for area normal */
- copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
+ if ((!ss->cache->first_time) && (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
+ copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
+ }
+ else {
+ copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
+ }
/* for flatten center */
- copy_v3_v3(ss->cache->last_center, r_area_co);
+ if ((!ss->cache->first_time) && (brush->flag & BRUSH_ORIGINAL_PLANE)) {
+ copy_v3_v3(r_area_co, ss->cache->last_center);
+ }
+ else {
+ copy_v3_v3(ss->cache->last_center, r_area_co);
+ }
}
else {
/* for area normal */
@@ -3455,6 +4590,7 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -3500,8 +4636,7 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
}
@@ -3549,6 +4684,7 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -3598,8 +4734,7 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
}
@@ -3646,6 +4781,7 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -3728,8 +4864,7 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings);
}
@@ -3774,6 +4909,7 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -3821,8 +4957,7 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings);
}
@@ -3866,6 +5001,7 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -3913,8 +5049,7 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
}
@@ -3946,6 +5081,7 @@ static void do_gravity_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
+ vd.index,
tls->thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -3982,8 +5118,7 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings);
}
@@ -4085,7 +5220,7 @@ static void sculpt_topology_update(Sculpt *sd,
(brush->falloff_shape != PAINT_FALLOFF_SHAPE_SPHERE));
}
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
/* update average stroke position */
copy_v3_v3(location, ss->cache->true_location);
@@ -4103,20 +5238,42 @@ static void do_brush_action_task_cb(void *__restrict userdata,
data->nodes[n],
data->brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK :
SCULPT_UNDO_COORDS);
- BKE_pbvh_node_mark_update(data->nodes[n]);
+ if (data->brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ BKE_pbvh_node_mark_update_mask(data->nodes[n]);
+ }
+ else {
+ BKE_pbvh_node_mark_update(data->nodes[n]);
+ }
}
static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups)
{
SculptSession *ss = ob->sculpt;
int totnode;
+ PBVHNode **nodes;
/* Build a list of all nodes that are potentially within the brush's area of influence */
- const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
- ss->cache->original;
- const float radius_scale = 1.0f;
- PBVHNode **nodes = sculpt_pbvh_gather_generic(
- ob, sd, brush, use_original, radius_scale, &totnode);
+
+ /* These brushes need to update all nodes as they are not constrained by the brush radius */
+ if (brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) {
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+ }
+ else if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
+ float final_radius = ss->cache->radius * (1 + brush->pose_offset);
+ SculptSearchSphereData data = {
+ .ss = ss,
+ .sd = sd,
+ .radius_squared = final_radius * final_radius,
+ .original = true,
+ };
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
+ }
+ else {
+ const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
+ ss->cache->original;
+ const float radius_scale = 1.0f;
+ nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale, &totnode);
+ }
/* Only act if some verts are inside the brush area */
if (totnode) {
@@ -4130,8 +5287,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings);
if (sculpt_brush_needs_normal(ss, brush)) {
@@ -4142,6 +5298,19 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
update_brush_local_mat(sd, ob);
}
+ if (ss->cache->first_time && ss->cache->mirror_symmetry_pass == 0) {
+ if (sculpt_automasking_enabled(ss, brush)) {
+ sculpt_automasking_init(sd, ob);
+ }
+ }
+
+ if (brush->sculpt_tool == SCULPT_TOOL_POSE && ss->cache->first_time &&
+ ss->cache->mirror_symmetry_pass == 0) {
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS) {
+ sculpt_pose_brush_init(sd, ob, ss, brush, ss->cache->location, ss->cache->radius);
+ }
+ }
+
/* Apply one type of brush action */
switch (brush->sculpt_tool) {
case SCULPT_TOOL_DRAW:
@@ -4198,6 +5367,15 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
case SCULPT_TOOL_MASK:
do_mask_brush(sd, ob, nodes, totnode);
break;
+ case SCULPT_TOOL_POSE:
+ do_pose_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_DRAW_SHARP:
+ do_draw_sharp_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_ELASTIC_DEFORM:
+ do_elastic_deform_brush(sd, ob, nodes, totnode);
+ break;
}
if (!ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_MASK) &&
@@ -4219,7 +5397,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
do_gravity(sd, ob, nodes, totnode, sd->gravity_factor);
}
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
/* update average stroke position */
copy_v3_v3(location, ss->cache->true_location);
@@ -4262,8 +5440,12 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata,
Object *ob = data->ob;
/* these brushes start from original coordinates */
- const bool use_orco = ELEM(
- data->brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB);
+ const bool use_orco = ELEM(data->brush->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_ELASTIC_DEFORM,
+ SCULPT_TOOL_POSE);
PBVHVertexIter vd;
PBVHProxyNode *proxies;
@@ -4327,14 +5509,11 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings);
}
- if (nodes) {
- MEM_freeN(nodes);
- }
+ MEM_SAFE_FREE(nodes);
}
/* copy the modified vertices from bvh to the active key */
@@ -4385,12 +5564,12 @@ static void sculpt_flush_stroke_deform_task_cb(void *__restrict userdata,
}
/* flush displacement from deformed PBVH to original layer */
-static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
+static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- if (sculpt_tool_is_proxy_used(brush->sculpt_tool)) {
+ if (is_proxy_used) {
/* this brushes aren't using proxies, so sculpt_combine_proxies() wouldn't
* propagate needed deformation to original base */
@@ -4420,8 +5599,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
};
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(0, totnode, &data, sculpt_flush_stroke_deform_task_cb, &settings);
if (vertCos) {
@@ -4429,7 +5607,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
MEM_freeN(vertCos);
}
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
/* Modifiers could depend on mesh normals, so we should update them/
* Note, then if sculpting happens on locked key, normals should be re-calculated
@@ -4513,7 +5691,7 @@ static void do_tiled(
float orgLoc[3]; /* position of the "prototype" stroke for tiling */
copy_v3_v3(orgLoc, cache->location);
- for (dim = 0; dim < 3; ++dim) {
+ for (dim = 0; dim < 3; dim++) {
if ((sd->paint.symmetry_flags & (PAINT_TILE_X << dim)) && step[dim] > 0) {
start[dim] = (bbMin[dim] - orgLoc[dim] - radius) / step[dim];
end[dim] = (bbMax[dim] - orgLoc[dim] + radius) / step[dim];
@@ -4529,16 +5707,16 @@ static void do_tiled(
/* now do it for all the tiles */
copy_v3_v3_int(cur, start);
- for (cur[0] = start[0]; cur[0] <= end[0]; ++cur[0]) {
- for (cur[1] = start[1]; cur[1] <= end[1]; ++cur[1]) {
- for (cur[2] = start[2]; cur[2] <= end[2]; ++cur[2]) {
+ for (cur[0] = start[0]; cur[0] <= end[0]; cur[0]++) {
+ for (cur[1] = start[1]; cur[1] <= end[1]; cur[1]++) {
+ for (cur[2] = start[2]; cur[2] <= end[2]; cur[2]++) {
if (!cur[0] && !cur[1] && !cur[2]) {
continue; /* skip tile at orgLoc, this was already handled before all others */
}
++cache->tile_pass;
- for (dim = 0; dim < 3; ++dim) {
+ for (dim = 0; dim < 3; dim++) {
cache->location[dim] = cur[dim] * step[dim] + orgLoc[dim];
cache->plane_offset[dim] = cur[dim] * step[dim];
}
@@ -4560,7 +5738,7 @@ static void do_radial_symmetry(Sculpt *sd,
SculptSession *ss = ob->sculpt;
int i;
- for (i = 1; i < sd->radial_symm[axis - 'X']; ++i) {
+ for (i = 1; i < sd->radial_symm[axis - 'X']; i++) {
const float angle = 2 * M_PI * i / sd->radial_symm[axis - 'X'];
ss->cache->radial_symmetry_pass = i;
sculpt_cache_calc_brushdata_symm(ss->cache, symm, axis, angle);
@@ -4600,7 +5778,7 @@ static void do_symmetrical_brush_actions(Sculpt *sd,
/* symm is a bit combination of XYZ -
* 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
- for (i = 0; i <= symm; ++i) {
+ for (i = 0; i <= symm; i++) {
if (i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
cache->mirror_symmetry_pass = i;
cache->radial_symmetry_pass = 0;
@@ -4703,6 +5881,12 @@ static const char *sculpt_tool_name(Sculpt *sd)
return "Mask Brush";
case SCULPT_TOOL_SIMPLIFY:
return "Simplify Brush";
+ case SCULPT_TOOL_DRAW_SHARP:
+ return "Draw Sharp Brush";
+ case SCULPT_TOOL_ELASTIC_DEFORM:
+ return "Elastic Deform Brush";
+ case SCULPT_TOOL_POSE:
+ return "Pose Brush";
}
return "Sculpting";
@@ -4717,6 +5901,9 @@ void sculpt_cache_free(StrokeCache *cache)
if (cache->dial) {
MEM_freeN(cache->dial);
}
+ if (cache->pose_factor) {
+ MEM_freeN(cache->pose_factor);
+ }
MEM_freeN(cache);
}
@@ -4732,7 +5919,7 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss)
if (mmd->flag & MOD_MIR_CLIPPING) {
/* check each axis for mirroring */
- for (i = 0; i < 3; ++i) {
+ for (i = 0; i < 3; i++) {
if (mmd->flag & (MOD_MIR_AXIS_X << i)) {
/* enable sculpt clipping */
ss->cache->flag |= CLIP_X << i;
@@ -4894,7 +6081,7 @@ static void sculpt_update_cache_invariants(
memcpy(ss->layer_co, ss->deform_cos, ss->totvert);
}
else {
- for (i = 0; i < ss->totvert; ++i) {
+ for (i = 0; i < ss->totvert; i++) {
copy_v3_v3(ss->layer_co[i], ss->mvert[i].co);
}
}
@@ -4910,12 +6097,21 @@ static void sculpt_update_cache_invariants(
/* Make copies of the mesh vertex locations and normals for some tools */
if (brush->flag & BRUSH_ANCHORED) {
- cache->original = 1;
+ cache->original = true;
+ }
+
+ /* Draw sharp does not need the original coordinates to produce the accumulate effect, so it
+ * should work the opposite way. */
+ if (brush->sculpt_tool == SCULPT_TOOL_DRAW_SHARP) {
+ cache->original = true;
}
if (SCULPT_TOOL_HAS_ACCUMULATE(brush->sculpt_tool)) {
if (!(brush->flag & BRUSH_ACCUMULATE)) {
- cache->original = 1;
+ cache->original = true;
+ if (brush->sculpt_tool == SCULPT_TOOL_DRAW_SHARP) {
+ cache->original = false;
+ }
}
}
@@ -4941,15 +6137,22 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
if (ELEM(tool,
SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ELASTIC_DEFORM,
SCULPT_TOOL_NUDGE,
SCULPT_TOOL_CLAY_STRIPS,
SCULPT_TOOL_SNAKE_HOOK,
+ SCULPT_TOOL_POSE,
SCULPT_TOOL_THUMB) ||
sculpt_brush_use_topology_rake(ss, brush)) {
float grab_location[3], imat[4][4], delta[3], loc[3];
if (cache->first_time) {
- copy_v3_v3(cache->orig_grab_location, cache->true_location);
+ if (tool == SCULPT_TOOL_GRAB && brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) {
+ copy_v3_v3(cache->orig_grab_location, sculpt_active_vertex_co_get(ss));
+ }
+ else {
+ copy_v3_v3(cache->orig_grab_location, cache->true_location);
+ }
}
else if (tool == SCULPT_TOOL_SNAKE_HOOK) {
add_v3_v3(cache->true_location, cache->grab_delta);
@@ -4963,7 +6166,9 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
if (!cache->first_time) {
switch (tool) {
case SCULPT_TOOL_GRAB:
+ case SCULPT_TOOL_POSE:
case SCULPT_TOOL_THUMB:
+ case SCULPT_TOOL_ELASTIC_DEFORM:
sub_v3_v3v3(delta, grab_location, cache->old_grab_location);
invert_m4_m4(imat, ob->obmat);
mul_mat3_m4_v3(imat, delta);
@@ -5000,13 +6205,25 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
copy_v3_v3(cache->old_grab_location, grab_location);
if (tool == SCULPT_TOOL_GRAB) {
+ if (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) {
+ copy_v3_v3(cache->anchored_location, cache->orig_grab_location);
+ }
+ else {
+ copy_v3_v3(cache->anchored_location, cache->true_location);
+ }
+ }
+ else if (tool == SCULPT_TOOL_ELASTIC_DEFORM) {
copy_v3_v3(cache->anchored_location, cache->true_location);
}
else if (tool == SCULPT_TOOL_THUMB) {
copy_v3_v3(cache->anchored_location, cache->orig_grab_location);
}
- if (ELEM(tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB)) {
+ if (ELEM(tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_ELASTIC_DEFORM,
+ SCULPT_TOOL_POSE)) {
/* location stays the same for finding vertices in brush radius */
copy_v3_v3(cache->true_location, cache->orig_grab_location);
@@ -5144,20 +6361,25 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
/* Returns true if any of the smoothing modes are active (currently
* one of smooth brush, autosmooth, mask smooth, or shift-key
* smooth) */
-static bool sculpt_any_smooth_mode(const Brush *brush, StrokeCache *cache, int stroke_mode)
+static bool sculpt_needs_conectivity_info(const Brush *brush, SculptSession *ss, int stroke_mode)
{
- return ((stroke_mode == BRUSH_STROKE_SMOOTH) || (cache && cache->alt_smooth) ||
+ if (ss && sculpt_automasking_enabled(ss, brush)) {
+ return true;
+ }
+ return ((stroke_mode == BRUSH_STROKE_SMOOTH) || (ss && ss->cache && ss->cache->alt_smooth) ||
(brush->sculpt_tool == SCULPT_TOOL_SMOOTH) || (brush->autosmooth_factor > 0) ||
- ((brush->sculpt_tool == SCULPT_TOOL_MASK) && (brush->mask_tool == BRUSH_MASK_SMOOTH)));
+ ((brush->sculpt_tool == SCULPT_TOOL_MASK) && (brush->mask_tool == BRUSH_MASK_SMOOTH)) ||
+ (brush->sculpt_tool == SCULPT_TOOL_POSE));
}
static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush)
{
SculptSession *ss = ob->sculpt;
+ View3D *v3d = CTX_wm_view3d(C);
- if (ss->kb || ss->modifiers_active) {
+ bool need_pmap = sculpt_needs_conectivity_info(brush, ss, 0);
+ if (ss->kb || ss->modifiers_active || (!BKE_sculptsession_use_pbvh_draw(ob, v3d) && need_pmap)) {
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- bool need_pmap = sculpt_any_smooth_mode(brush, ss->cache, 0);
BKE_sculpt_update_object_for_edit(depsgraph, ob, need_pmap, false);
}
}
@@ -5186,8 +6408,11 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
origco,
use_origco,
srd->ray_start,
+ srd->ray_normal,
&srd->isect_precalc,
- &srd->depth)) {
+ &srd->depth,
+ &srd->active_vertex_index,
+ srd->face_normal)) {
srd->hit = 1;
*tmin = srd->depth;
}
@@ -5275,26 +6500,147 @@ static float sculpt_raycast_init(ViewContext *vc,
return dist;
}
+/* Gets the normal, location and active vertex location of the geometry under the cursor. This also
+ * updates
+ * the active vertex and cursor related data of the SculptSession using the mouse position */
+bool sculpt_cursor_geometry_info_update(bContext *C,
+ SculptCursorGeometryInfo *out,
+ const float mouse[2],
+ bool use_sampled_normal)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Scene *scene = CTX_data_scene(C);
+ Sculpt *sd = scene->toolsettings->sculpt;
+ Object *ob;
+ SculptSession *ss;
+ ViewContext vc;
+ const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
+ float ray_start[3], ray_end[3], ray_normal[3], depth, face_normal[3], sampled_normal[3],
+ mat[3][3];
+ float viewDir[3] = {0.0f, 0.0f, 1.0f};
+ int totnode;
+ bool original = false, hit = false;
+
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
+
+ ob = vc.obact;
+ ss = ob->sculpt;
+
+ if (!ss->pbvh) {
+ zero_v3(out->location);
+ zero_v3(out->normal);
+ zero_v3(out->active_vertex_co);
+ return false;
+ }
+
+ /* PBVH raycast to get active vertex and face normal */
+ depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
+ sculpt_stroke_modifiers_check(C, ob, brush);
+
+ SculptRaycastData srd = {
+ .original = original,
+ .ss = ob->sculpt,
+ .hit = 0,
+ .ray_start = ray_start,
+ .ray_normal = ray_normal,
+ .depth = depth,
+ .face_normal = face_normal,
+ };
+ isect_ray_tri_watertight_v3_precalc(&srd.isect_precalc, ray_normal);
+ BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd, ray_start, ray_normal, srd.original);
+
+ /* Cursor is not over the mesh, return default values */
+ if (!srd.hit) {
+ zero_v3(out->location);
+ zero_v3(out->normal);
+ zero_v3(out->active_vertex_co);
+ return false;
+ }
+
+ /* Update the active vertex of the SculptSession */
+ ss->active_vertex_index = srd.active_vertex_index;
+
+ if (!ss->multires) {
+ copy_v3_v3(out->active_vertex_co, sculpt_active_vertex_co_get(ss));
+ }
+ else {
+ zero_v3(out->active_vertex_co);
+ }
+
+ copy_v3_v3(out->location, ray_normal);
+ mul_v3_fl(out->location, srd.depth);
+ add_v3_v3(out->location, ray_start);
+
+ /* Option to return the face normal directly for performance o accuracy reasons */
+ if (!use_sampled_normal) {
+ copy_v3_v3(out->normal, srd.face_normal);
+ return hit;
+ }
+
+ /* Sampled normal calculation */
+ float radius;
+
+ /* Update cursor data in SculptSession */
+ invert_m4_m4(ob->imat, ob->obmat);
+ copy_m3_m4(mat, vc.rv3d->viewinv);
+ mul_m3_v3(mat, viewDir);
+ copy_m3_m4(mat, ob->imat);
+ mul_m3_v3(mat, viewDir);
+ normalize_v3_v3(ss->cursor_view_normal, viewDir);
+ copy_v3_v3(ss->cursor_normal, srd.face_normal);
+ copy_v3_v3(ss->cursor_location, out->location);
+ ss->rv3d = vc.rv3d;
+
+ if (!BKE_brush_use_locked_size(scene, brush)) {
+ radius = paint_calc_object_space_radius(&vc, out->location, BKE_brush_size_get(scene, brush));
+ }
+ else {
+ radius = BKE_brush_unprojected_radius_get(scene, brush);
+ }
+ ss->cursor_radius = radius;
+
+ PBVHNode **nodes = sculpt_pbvh_gather_cursor_update(ob, sd, original, &totnode);
+
+ /* In case there are no nodes under the cursor, return the face normal */
+ if (!totnode) {
+ MEM_SAFE_FREE(nodes);
+ copy_v3_v3(out->normal, srd.face_normal);
+ return true;
+ }
+
+ /* Calculate the sampled normal */
+ if (sculpt_pbvh_calc_area_normal(brush, ob, nodes, totnode, true, sampled_normal)) {
+ copy_v3_v3(out->normal, sampled_normal);
+ }
+ else {
+ /* Use face normal when there are no vertices to sample inside the cursor radius */
+ copy_v3_v3(out->normal, srd.face_normal);
+ }
+ MEM_SAFE_FREE(nodes);
+ return true;
+}
+
/* Do a raycast in the tree to find the 3d brush location
* (This allows us to ignore the GL depth buffer)
* Returns 0 if the ray doesn't hit the mesh, non-zero otherwise
*/
bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob;
SculptSession *ss;
StrokeCache *cache;
- float ray_start[3], ray_end[3], ray_normal[3], depth;
+ float ray_start[3], ray_end[3], ray_normal[3], depth, face_normal[3];
bool original;
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ob = vc.obact;
ss = ob->sculpt;
cache = ss->cache;
- original = (cache) ? cache->original : 0;
+ original = (cache) ? cache->original : false;
const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
@@ -5302,14 +6648,21 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ BM_mesh_elem_table_ensure(ss->bm, BM_VERT);
+ BM_mesh_elem_index_ensure(ss->bm, BM_VERT);
+ }
+
bool hit = false;
{
SculptRaycastData srd;
srd.ss = ob->sculpt;
srd.ray_start = ray_start;
+ srd.ray_normal = ray_normal;
srd.hit = 0;
srd.depth = depth;
srd.original = original;
+ srd.face_normal = face_normal;
isect_ray_tri_watertight_v3_precalc(&srd.isect_precalc, ray_normal);
BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd, ray_start, ray_normal, srd.original);
@@ -5343,10 +6696,6 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
}
}
- if (cache && hit) {
- copy_v3_v3(cache->true_location, out);
- }
-
return hit;
}
@@ -5386,7 +6735,7 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op)
view3d_operator_needs_opengl(C);
sculpt_brush_init_tex(scene, sd, ss);
- is_smooth = sculpt_any_smooth_mode(brush, NULL, mode);
+ is_smooth = sculpt_needs_conectivity_info(brush, ss, mode);
BKE_sculpt_update_object_for_edit(depsgraph, ob, is_smooth, need_mask);
}
@@ -5397,7 +6746,8 @@ static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
/* Restore the mesh before continuing with anchored stroke */
if ((brush->flag & BRUSH_ANCHORED) ||
- (brush->sculpt_tool == SCULPT_TOOL_GRAB &&
+ ((brush->sculpt_tool == SCULPT_TOOL_GRAB ||
+ brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) &&
BKE_brush_use_size_pressure(ss->cache->vc->scene, brush)) ||
(brush->flag & BRUSH_DRAG_DOT)) {
paint_mesh_restore_co(sd, ob);
@@ -5415,7 +6765,7 @@ void sculpt_update_object_bounding_box(Object *ob)
}
}
-static void sculpt_flush_update_step(bContext *C)
+static void sculpt_flush_update_step(bContext *C, SculptUpdateType update_flags)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob = CTX_data_active_object(C);
@@ -5423,6 +6773,12 @@ static void sculpt_flush_update_step(bContext *C)
ARegion *ar = CTX_wm_region(C);
MultiresModifierData *mmd = ss->multires;
View3D *v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+
+ if (rv3d) {
+ /* Mark for faster 3D viewport redraws. */
+ rv3d->rflag |= RV3D_PAINTING;
+ }
if (mmd != NULL) {
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
@@ -5443,11 +6799,13 @@ static void sculpt_flush_update_step(bContext *C)
* only the part of the 3D viewport where changes happened. */
rcti r;
- BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB);
- /* Update the object's bounding box too so that the object
- * doesn't get incorrectly clipped during drawing in
- * draw_mesh_object(). [#33790] */
- sculpt_update_object_bounding_box(ob);
+ if (update_flags & SCULPT_UPDATE_COORDS) {
+ BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB);
+ /* Update the object's bounding box too so that the object
+ * doesn't get incorrectly clipped during drawing in
+ * draw_mesh_object(). [#33790] */
+ sculpt_update_object_bounding_box(ob);
+ }
if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) {
if (ss->cache) {
@@ -5467,16 +6825,21 @@ static void sculpt_flush_update_step(bContext *C)
}
}
-static void sculpt_flush_update_done(const bContext *C, Object *ob)
+static void sculpt_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags)
{
/* After we are done drawing the stroke, check if we need to do a more
* expensive depsgraph tag to update geometry. */
wmWindowManager *wm = CTX_wm_manager(C);
View3D *current_v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
SculptSession *ss = ob->sculpt;
Mesh *mesh = ob->data;
bool need_tag = (mesh->id.us > 1); /* Always needed for linked duplicates. */
+ if (rv3d) {
+ rv3d->rflag &= ~RV3D_PAINTING;
+ }
+
for (wmWindow *win = wm->windows.first; win; win = win->next) {
bScreen *screen = WM_window_get_active_screen(win);
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
@@ -5486,11 +6849,26 @@ static void sculpt_flush_update_done(const bContext *C, Object *ob)
if (v3d != current_v3d) {
need_tag |= !BKE_sculptsession_use_pbvh_draw(ob, v3d);
}
+
+ /* Tag all 3D viewports for redraw now that we are done. Others
+ * viewports did not get a full redraw, and anti-aliasing for the
+ * current viewport was deactivated. */
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ ED_region_tag_redraw(ar);
+ }
+ }
}
}
}
- BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateOriginalBB);
+ if (update_flags & SCULPT_UPDATE_COORDS) {
+ BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateOriginalBB);
+ }
+
+ if (update_flags & SCULPT_UPDATE_MASK) {
+ BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask);
+ }
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
BKE_pbvh_bmesh_after_stroke(ss->pbvh);
@@ -5577,7 +6955,6 @@ static void sculpt_stroke_update_step(bContext *C,
}
do_symmetrical_brush_actions(sd, ob, do_brush_action, ups);
-
sculpt_combine_proxies(sd, ob);
/* hack to fix noise texture tearing mesh */
@@ -5594,7 +6971,7 @@ static void sculpt_stroke_update_step(bContext *C,
* sculpt_flush_update_step().
*/
if (ss->modifiers_active) {
- sculpt_flush_stroke_deform(sd, ob);
+ sculpt_flush_stroke_deform(sd, ob, sculpt_tool_is_proxy_used(brush->sculpt_tool));
}
else if (ss->kb) {
sculpt_update_keyblock(ob);
@@ -5603,7 +6980,12 @@ static void sculpt_stroke_update_step(bContext *C,
ss->cache->first_time = false;
/* Cleanup */
- sculpt_flush_update_step(C);
+ if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
+ }
+ else {
+ sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS);
+ }
}
static void sculpt_brush_exit_tex(Sculpt *sd)
@@ -5647,12 +7029,21 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
}
}
+ if (sculpt_automasking_enabled(ss, brush)) {
+ sculpt_automasking_end(ob);
+ }
+
sculpt_cache_free(ss->cache);
ss->cache = NULL;
sculpt_undo_push_end();
- sculpt_flush_update_done(C, ob);
+ if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
+ }
+ else {
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
+ }
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
}
@@ -5683,12 +7074,12 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent
ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click");
if (ignore_background_click && !over_mesh(C, op, event->x, event->y)) {
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
return OPERATOR_PASS_THROUGH;
}
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
return OPERATOR_FINISHED;
}
/* add modal handler */
@@ -5817,8 +7208,19 @@ void sculpt_pbvh_clear(Object *ob)
/* Clear out any existing DM and PBVH */
if (ss->pbvh) {
BKE_pbvh_free(ss->pbvh);
+ ss->pbvh = NULL;
+ }
+
+ if (ss->pmap) {
+ MEM_freeN(ss->pmap);
+ ss->pmap = NULL;
}
- ss->pbvh = NULL;
+
+ if (ss->pmap_mem) {
+ MEM_freeN(ss->pmap_mem);
+ ss->pmap_mem = NULL;
+ }
+
BKE_object_free_derived_caches(ob);
/* Tag to rebuild PBVH in depsgraph. */
@@ -6388,13 +7790,11 @@ void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scen
const int mode_flag = OB_MODE_SCULPT;
Mesh *me = BKE_mesh_from_object(ob);
- MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
- if (mmd) {
- multires_force_update(ob);
- }
+ multires_flush_sculpt_updates(ob);
/* Not needed for now. */
#if 0
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
#endif
@@ -6539,7 +7939,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
sculpt_undo_push_end();
/* force rebuild of pbvh for better BB placement */
@@ -6580,8 +7980,9 @@ static void sample_detail(bContext *C, int mx, int my)
CTX_wm_area_set(C, sa);
CTX_wm_region_set(C, ar);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
/* Pick sample detail. */
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -6624,7 +8025,7 @@ static int sculpt_sample_detail_size_exec(bContext *C, wmOperator *op)
static int sculpt_sample_detail_size_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e))
{
ED_workspace_status_text(C, TIP_("Click on the mesh to set the detail"));
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
@@ -6740,6 +8141,1630 @@ static void SCULPT_OT_set_detail_size(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static void filter_cache_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;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ if (!vd.mask || (vd.mask && *vd.mask < 1.0f)) {
+ data->node_mask[i] = 1;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ if (data->node_mask[i] == 1) {
+ sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
+ }
+}
+
+static void sculpt_filter_cache_init(Object *ob, Sculpt *sd)
+{
+ SculptSession *ss = ob->sculpt;
+ PBVH *pbvh = ob->sculpt->pbvh;
+ PBVHNode **nodes;
+ int totnode;
+
+ ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache");
+
+ ss->filter_cache->random_seed = rand();
+
+ SculptSearchSphereData search_data = {
+ .original = true,
+ };
+ BKE_pbvh_search_gather(pbvh, NULL, &search_data, &nodes, &totnode);
+
+ int *node_mask = MEM_callocN((unsigned int)totnode * sizeof(int), "node mask");
+
+ for (int i = 0; i < totnode; i++) {
+ BKE_pbvh_node_mark_normals_update(nodes[i]);
+ }
+
+ /* mesh->runtime.subdiv_ccg is not available. Updating of the normals is done during drawing.
+ * Filters can't use normals in multires. */
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS) {
+ BKE_pbvh_update_normals(ss->pbvh, NULL);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .node_mask = node_mask,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BLI_task_parallel_range(0, totnode, &data, filter_cache_init_task_cb, &settings);
+
+ int tot_active_nodes = 0;
+ int active_node_index = 0;
+ PBVHNode **active_nodes;
+
+ /* Count number of PBVH nodes that are not fully masked */
+ for (int i = 0; i < totnode; i++) {
+ if (node_mask[i] == 1) {
+ tot_active_nodes++;
+ }
+ }
+
+ /* Create the final list of nodes that is going to be processed in the filter */
+ active_nodes = MEM_callocN(tot_active_nodes * sizeof(PBVHNode *), "active nodes");
+
+ for (int i = 0; i < totnode; i++) {
+ if (node_mask[i] == 1) {
+ active_nodes[active_node_index] = nodes[i];
+ active_node_index++;
+ }
+ }
+
+ ss->filter_cache->nodes = active_nodes;
+ ss->filter_cache->totnode = tot_active_nodes;
+
+ MEM_SAFE_FREE(nodes);
+ MEM_SAFE_FREE(node_mask);
+}
+
+static void sculpt_filter_cache_free(SculptSession *ss)
+{
+ if (ss->filter_cache->nodes) {
+ MEM_freeN(ss->filter_cache->nodes);
+ }
+ if (ss->filter_cache->mask_update_it) {
+ MEM_freeN(ss->filter_cache->mask_update_it);
+ }
+ if (ss->filter_cache->prev_mask) {
+ MEM_freeN(ss->filter_cache->prev_mask);
+ }
+ if (ss->filter_cache->normal_factor) {
+ MEM_freeN(ss->filter_cache->normal_factor);
+ }
+ MEM_freeN(ss->filter_cache);
+ ss->filter_cache = NULL;
+}
+
+typedef enum eSculptMeshFilterTypes {
+ MESH_FILTER_SMOOTH = 0,
+ MESH_FILTER_SCALE = 1,
+ MESH_FILTER_INFLATE = 2,
+ MESH_FILTER_SPHERE = 3,
+ MESH_FILTER_RANDOM = 4,
+} eSculptMeshFilterTypes;
+
+static EnumPropertyItem prop_mesh_filter_types[] = {
+ {MESH_FILTER_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth mesh"},
+ {MESH_FILTER_SCALE, "SCALE", 0, "Scale", "Scale mesh"},
+ {MESH_FILTER_INFLATE, "INFLATE", 0, "Inflate", "Inflate mesh"},
+ {MESH_FILTER_SPHERE, "SPHERE", 0, "Sphere", "Morph into sphere"},
+ {MESH_FILTER_RANDOM, "RANDOM", 0, "Random", "Randomize vertex positions"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+typedef enum eMeshFilterDeformAxis {
+ MESH_FILTER_DEFORM_X = 1 << 0,
+ MESH_FILTER_DEFORM_Y = 1 << 1,
+ MESH_FILTER_DEFORM_Z = 1 << 2,
+} eMeshFilterDeformAxis;
+
+static EnumPropertyItem prop_mesh_filter_deform_axis_items[] = {
+ {MESH_FILTER_DEFORM_X, "X", 0, "X", "Deform in the X axis"},
+ {MESH_FILTER_DEFORM_Y, "Y", 0, "Y", "Deform in the Y axis"},
+ {MESH_FILTER_DEFORM_Z, "Z", 0, "Z", "Deform in the Z axis"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static void mesh_filter_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];
+
+ const int filter_type = data->filter_type;
+
+ SculptOrigVertData orig_data;
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
+
+ PBVHVertexIter vd;
+ 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;
+ fade = 1 - fade;
+ fade *= data->filter_strength;
+ copy_v3_v3(orig_co, orig_data.co);
+ switch (filter_type) {
+ case MESH_FILTER_SMOOTH:
+ CLAMP(fade, -1.0f, 1.0f);
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES:
+ neighbor_average(ss, avg, vd.index);
+ break;
+ case PBVH_BMESH:
+ bmesh_neighbor_average(avg, vd.bm_vert);
+ break;
+ case PBVH_GRIDS:
+ grids_neighbor_average(ss, avg, vd.index);
+ break;
+ }
+ sub_v3_v3v3(val, avg, orig_co);
+ madd_v3_v3v3fl(val, orig_co, val, fade);
+ sub_v3_v3v3(disp, val, orig_co);
+ break;
+ case MESH_FILTER_INFLATE:
+ normal_short_to_float_v3(normal, orig_data.no);
+ mul_v3_v3fl(disp, normal, fade);
+ break;
+ case MESH_FILTER_SCALE:
+ unit_m3(transform);
+ scale_m3_fl(transform, 1 + fade);
+ copy_v3_v3(val, orig_co);
+ mul_m3_v3(transform, val);
+ sub_v3_v3v3(disp, val, orig_co);
+ break;
+ case MESH_FILTER_SPHERE:
+ normalize_v3_v3(disp, orig_co);
+ if (fade > 0) {
+ mul_v3_v3fl(disp, disp, fade);
+ }
+ else {
+ mul_v3_v3fl(disp, disp, -fade);
+ }
+
+ unit_m3(transform);
+ if (fade > 0) {
+ scale_m3_fl(transform, 1 - fade);
+ }
+ else {
+ scale_m3_fl(transform, 1 + fade);
+ }
+ copy_v3_v3(val, orig_co);
+ mul_m3_v3(transform, val);
+ sub_v3_v3v3(disp2, val, orig_co);
+
+ mid_v3_v3v3(disp, disp, disp2);
+ break;
+ case MESH_FILTER_RANDOM: {
+ normal_short_to_float_v3(normal, orig_data.no);
+ /* Index is not unique for multires, so hash by vertex coordinates. */
+ const uint *hash_co = (const uint *)orig_co;
+ const uint hash = BLI_hash_int_2d(hash_co[0], hash_co[1]) ^
+ BLI_hash_int_2d(hash_co[2], ss->filter_cache->random_seed);
+ mul_v3_fl(normal, hash * (1.0f / (float)0xFFFFFFFF) - 0.5f);
+ mul_v3_v3fl(disp, normal, fade);
+ break;
+ }
+ }
+
+ for (int it = 0; it < 3; it++) {
+ if (!ss->filter_cache->enabled_axis[it]) {
+ disp[it] = 0.0f;
+ }
+ }
+
+ add_v3_v3v3(final_pos, orig_co, disp);
+ copy_v3_v3(vd.co, final_pos);
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ BKE_pbvh_node_mark_redraw(node);
+ BKE_pbvh_node_mark_normals_update(node);
+}
+
+static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ int filter_type = RNA_enum_get(op->ptr, "type");
+ float filter_strength = RNA_float_get(op->ptr, "strength");
+
+ if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
+ sculpt_filter_cache_free(ss);
+ sculpt_undo_push_end();
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
+ return OPERATOR_FINISHED;
+ }
+
+ if (event->type != MOUSEMOVE) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ float len = event->prevclickx - event->mval[0];
+ filter_strength = filter_strength * -len * 0.001f * UI_DPI_FAC;
+
+ sculpt_vertex_random_access_init(ss);
+
+ bool needs_pmap = (filter_type == MESH_FILTER_SMOOTH);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .filter_type = filter_type,
+ .filter_strength = filter_strength,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings);
+
+ if (ss->modifiers_active || ss->kb) {
+ sculpt_flush_stroke_deform(sd, ob, true);
+ }
+
+ sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ int filter_type = RNA_enum_get(op->ptr, "type");
+ SculptSession *ss = ob->sculpt;
+ PBVH *pbvh = ob->sculpt->pbvh;
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ return OPERATOR_CANCELLED;
+ }
+
+ int deform_axis = RNA_enum_get(op->ptr, "deform_axis");
+ if (deform_axis == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ sculpt_vertex_random_access_init(ss);
+
+ bool needs_pmap = (filter_type == MESH_FILTER_SMOOTH);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false);
+
+ if (BKE_pbvh_type(pbvh) == PBVH_FACES && needs_pmap && !ob->sculpt->pmap) {
+ return OPERATOR_CANCELLED;
+ }
+
+ sculpt_undo_push_begin("Mesh filter");
+
+ sculpt_filter_cache_init(ob, sd);
+
+ ss->filter_cache->enabled_axis[0] = deform_axis & MESH_FILTER_DEFORM_X;
+ ss->filter_cache->enabled_axis[1] = deform_axis & MESH_FILTER_DEFORM_Y;
+ ss->filter_cache->enabled_axis[2] = deform_axis & MESH_FILTER_DEFORM_Z;
+
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void SCULPT_OT_mesh_filter(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Filter mesh";
+ ot->idname = "SCULPT_OT_mesh_filter";
+ ot->description = "Applies a filter to modify the current mesh";
+
+ /* api callbacks */
+ ot->invoke = sculpt_mesh_filter_invoke;
+ ot->modal = sculpt_mesh_filter_modal;
+ ot->poll = sculpt_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* rna */
+ RNA_def_enum(ot->srna,
+ "type",
+ prop_mesh_filter_types,
+ MESH_FILTER_INFLATE,
+ "Filter type",
+ "Operation that is going to be applied to the mesh");
+ RNA_def_float(
+ ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter Strength", -10.0f, 10.0f);
+ RNA_def_enum_flag(ot->srna,
+ "deform_axis",
+ prop_mesh_filter_deform_axis_items,
+ MESH_FILTER_DEFORM_X | MESH_FILTER_DEFORM_Y | MESH_FILTER_DEFORM_Z,
+ "Deform axis",
+ "Apply the deformation in the selected axis");
+}
+
+typedef enum eSculptMaskFilterTypes {
+ MASK_FILTER_SMOOTH = 0,
+ MASK_FILTER_SHARPEN = 1,
+ MASK_FILTER_GROW = 2,
+ MASK_FILTER_SHRINK = 3,
+ MASK_FILTER_CONTRAST_INCREASE = 5,
+ MASK_FILTER_CONTRAST_DECREASE = 6,
+} eSculptMaskFilterTypes;
+
+static EnumPropertyItem prop_mask_filter_types[] = {
+ {MASK_FILTER_SMOOTH, "SMOOTH", 0, "Smooth Mask", "Smooth mask"},
+ {MASK_FILTER_SHARPEN, "SHARPEN", 0, "Sharpen Mask", "Sharpen mask"},
+ {MASK_FILTER_GROW, "GROW", 0, "Grow Mask", "Grow mask"},
+ {MASK_FILTER_SHRINK, "SHRINK", 0, "Shrink Mask", "Shrink mask"},
+ {MASK_FILTER_CONTRAST_INCREASE,
+ "CONTRAST_INCREASE",
+ 0,
+ "Increase contrast",
+ "Increase the contrast of the paint mask"},
+ {MASK_FILTER_CONTRAST_DECREASE,
+ "CONTRAST_DECREASE",
+ 0,
+ "Decrease contrast",
+ "Decrease the contrast of the paint mask"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static void mask_filter_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];
+ bool update = false;
+
+ const int mode = data->filter_type;
+ float contrast = 0.0f;
+
+ PBVHVertexIter vd;
+
+ if (mode == MASK_FILTER_CONTRAST_INCREASE) {
+ contrast = 0.1f;
+ }
+
+ if (mode == MASK_FILTER_CONTRAST_DECREASE) {
+ contrast = -0.1f;
+ }
+
+ 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;
+ switch (mode) {
+ case MASK_FILTER_SMOOTH:
+ case MASK_FILTER_SHARPEN: {
+ float val = 0.0f;
+
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES:
+ val = neighbor_average_mask(ss, vd.index);
+ break;
+ case PBVH_BMESH:
+ val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset);
+ break;
+ case PBVH_GRIDS:
+ val = grids_neighbor_average_mask(ss, vd.index);
+ break;
+ }
+
+ val -= *vd.mask;
+
+ if (mode == MASK_FILTER_SMOOTH) {
+ *vd.mask += val;
+ }
+ else if (mode == MASK_FILTER_SHARPEN) {
+ if (*vd.mask > 0.5f) {
+ *vd.mask += 0.05f;
+ }
+ else {
+ *vd.mask -= 0.05f;
+ }
+ *vd.mask += val / 2;
+ }
+ break;
+ }
+ case MASK_FILTER_GROW:
+ max = 0.0f;
+ sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
+ {
+ float vmask_f = data->prev_mask[ni.index];
+ if (vmask_f > max) {
+ max = vmask_f;
+ }
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+ *vd.mask = max;
+ break;
+ case MASK_FILTER_SHRINK:
+ min = 1.0f;
+ sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
+ {
+ float vmask_f = data->prev_mask[ni.index];
+ if (vmask_f < min) {
+ min = vmask_f;
+ }
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+ *vd.mask = min;
+ break;
+ case MASK_FILTER_CONTRAST_INCREASE:
+ case MASK_FILTER_CONTRAST_DECREASE:
+ delta = contrast / 2.0f;
+ gain = 1.0f - delta * 2.0f;
+ if (contrast > 0) {
+ gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON);
+ offset = gain * (-delta);
+ }
+ else {
+ delta *= -1;
+ offset = gain * (delta);
+ }
+ *vd.mask = gain * (*vd.mask) + offset;
+ break;
+ }
+ CLAMP(*vd.mask, 0.0f, 1.0f);
+ if (*vd.mask != prev_val) {
+ update = true;
+ }
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ if (update) {
+ BKE_pbvh_node_mark_update_mask(node);
+ }
+}
+
+static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
+{
+ ARegion *ar = CTX_wm_region(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ PBVH *pbvh = ob->sculpt->pbvh;
+ PBVHNode **nodes;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ int totnode;
+ int filter_type = RNA_enum_get(op->ptr, "filter_type");
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ sculpt_vertex_random_access_init(ss);
+
+ if (!ob->sculpt->pmap) {
+ return OPERATOR_CANCELLED;
+ }
+
+ int num_verts = sculpt_vertex_count_get(ss);
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+ sculpt_undo_push_begin("Mask filter");
+
+ for (int i = 0; i < totnode; i++) {
+ sculpt_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
+ }
+
+ float *prev_mask = NULL;
+ int iterations = RNA_int_get(op->ptr, "iterations");
+
+ /* Auto iteration count calculates the number of iteration based on the vertices of the mesh to
+ * avoid adding an unnecessary amount of undo steps when using the operator from a shortcut.
+ * One iteration per 50000 vertices in the mesh should be fine in most cases.
+ * Maybe we want this to be configurable. */
+ if (RNA_boolean_get(op->ptr, "auto_iteration_count")) {
+ iterations = (int)(num_verts / 50000.0f) + 1;
+ }
+
+ for (int i = 0; i < iterations; i++) {
+ if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) {
+ prev_mask = MEM_mallocN(num_verts * sizeof(float), "prevmask");
+ for (int j = 0; j < num_verts; j++) {
+ prev_mask[j] = sculpt_vertex_mask_get(ss, j);
+ }
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .filter_type = filter_type,
+ .prev_mask = prev_mask,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BLI_task_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings);
+
+ if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) {
+ MEM_freeN(prev_mask);
+ }
+ }
+
+ MEM_SAFE_FREE(nodes);
+
+ sculpt_undo_push_end();
+
+ ED_region_tag_redraw(ar);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_mask_filter(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Mask Filter";
+ ot->idname = "SCULPT_OT_mask_filter";
+ ot->description = "Applies a filter to modify the current mask";
+
+ /* api callbacks */
+ ot->exec = sculpt_mask_filter_exec;
+ ot->poll = sculpt_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER;
+
+ /* rna */
+ RNA_def_enum(ot->srna,
+ "filter_type",
+ prop_mask_filter_types,
+ MASK_FILTER_SMOOTH,
+ "Type",
+ "Filter that is going to be applied to the mask");
+ RNA_def_int(ot->srna,
+ "iterations",
+ 1,
+ 1,
+ 100,
+ "Iterations",
+ "Number of times that the filter is going to be applied",
+ 1,
+ 100);
+ RNA_def_boolean(
+ ot->srna,
+ "auto_iteration_count",
+ false,
+ "Auto Iteration Count",
+ "Use a automatic number of iterations based on the number of vertices of the sculpt");
+}
+
+static float neighbor_dirty_mask(SculptSession *ss, PBVHVertexIter *vd)
+{
+ int total = 0;
+ float avg[3];
+ zero_v3(avg);
+
+ SculptVertexNeighborIter ni;
+ sculpt_vertex_neighbors_iter_begin(ss, vd->index, ni)
+ {
+ float normalized[3];
+ sub_v3_v3v3(normalized, sculpt_vertex_co_get(ss, ni.index), vd->co);
+ normalize_v3(normalized);
+ add_v3_v3(avg, normalized);
+ total++;
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ float normal[3];
+ if (vd->no) {
+ normal_short_to_float_v3(normal, vd->no);
+ }
+ else {
+ copy_v3_v3(normal, vd->fno);
+ }
+ float dot = dot_v3v3(avg, normal);
+ float angle = max_ff(saacosf(dot), 0.0f);
+ return angle;
+ }
+ return 0;
+}
+
+typedef struct DirtyMaskRangeData {
+ float min, max;
+} DirtyMaskRangeData;
+
+static void dirty_mask_compute_range_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+ DirtyMaskRangeData *range = tls->userdata_chunk;
+ PBVHVertexIter vd;
+
+ 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);
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void dirty_mask_compute_range_finalize(void *__restrict userdata, void *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ DirtyMaskRangeData *range = tls;
+
+ data->dirty_mask_min = min_ff(range->min, data->dirty_mask_min);
+ data->dirty_mask_max = max_ff(range->max, data->dirty_mask_max);
+}
+
+static void dirty_mask_apply_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 bool dirty_only = data->dirty_mask_dirty_only;
+ const float min = data->dirty_mask_min;
+ const float max = data->dirty_mask_max;
+
+ float range = max - min;
+ if (range < 0.0001f) {
+ range = 0;
+ }
+ else {
+ range = 1.0f / range;
+ }
+
+ 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 - ((dirty_mask - min) * range));
+ if (dirty_only) {
+ mask = fminf(mask, 0.5f) * 2.0f;
+ }
+ *vd.mask = CLAMPIS(mask, 0.0f, 1.0f);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ BKE_pbvh_node_mark_update_mask(node);
+}
+
+static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op)
+{
+ ARegion *ar = CTX_wm_region(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ PBVH *pbvh = ob->sculpt->pbvh;
+ PBVHNode **nodes;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ int totnode;
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ sculpt_vertex_random_access_init(ss);
+
+ if (!ob->sculpt->pmap) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+ sculpt_undo_push_begin("Dirty Mask");
+
+ for (int i = 0; i < totnode; i++) {
+ sculpt_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .dirty_mask_min = FLT_MAX,
+ .dirty_mask_max = -FLT_MAX,
+ .dirty_mask_dirty_only = RNA_boolean_get(op->ptr, "dirty_only"),
+ };
+ DirtyMaskRangeData range = {
+ .min = FLT_MAX,
+ .max = -FLT_MAX,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+
+ settings.func_finalize = dirty_mask_compute_range_finalize;
+ settings.userdata_chunk = &range;
+ settings.userdata_chunk_size = sizeof(DirtyMaskRangeData);
+
+ BLI_task_parallel_range(0, totnode, &data, dirty_mask_compute_range_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, dirty_mask_apply_task_cb, &settings);
+
+ MEM_SAFE_FREE(nodes);
+
+ BKE_pbvh_update_vertex_data(pbvh, SCULPT_UPDATE_MASK);
+
+ sculpt_undo_push_end();
+
+ ED_region_tag_redraw(ar);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_dirty_mask(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Dirty Mask";
+ ot->idname = "SCULPT_OT_dirty_mask";
+ ot->description = "Generates a mask based on the geometry cavity and pointiness";
+
+ /* api callbacks */
+ ot->exec = sculpt_dirty_mask_exec;
+ ot->poll = sculpt_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER;
+
+ /* rna */
+ RNA_def_boolean(
+ ot->srna, "dirty_only", false, "Dirty Only", "Don't calculate cleans for convex areas");
+}
+
+static void sculpt_mask_expand_cancel(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ MEM_freeN(op->customdata);
+
+ for (int n = 0; n < ss->filter_cache->totnode; n++) {
+ PBVHNode *node = ss->filter_cache->nodes[n];
+ PBVHVertexIter vd;
+ 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;
+
+ BKE_pbvh_node_mark_redraw(node);
+ }
+
+ sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
+ sculpt_filter_cache_free(ss);
+ sculpt_undo_push_end();
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
+ ED_workspace_status_text(C, NULL);
+}
+
+static void sculpt_expand_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;
+ int update_it = data->mask_expand_update_it;
+
+ 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) {
+ if (ss->filter_cache->normal_factor[sculpt_active_vertex_get(ss)] <
+ ss->filter_cache->normal_factor[vd.index]) {
+ final_mask = 1.0f;
+ }
+ else {
+ final_mask = 0.0f;
+ }
+ }
+ else {
+ if (ss->filter_cache->mask_update_it[vi] <= update_it &&
+ ss->filter_cache->mask_update_it[vi] != 0) {
+ final_mask = 1.0f;
+ }
+ else {
+ final_mask = 0.0f;
+ }
+ }
+
+ if (data->mask_expand_keep_prev_mask) {
+ final_mask = MAX2(ss->filter_cache->prev_mask[vd.index], final_mask);
+ }
+
+ if (data->mask_expand_invert_mask) {
+ final_mask = 1.0f - final_mask;
+ }
+
+ if (*vd.mask != final_mask) {
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ *vd.mask = final_mask;
+ BKE_pbvh_node_mark_update_mask(node);
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ float prevclick_f[2];
+ copy_v2_v2(prevclick_f, op->customdata);
+ int prevclick[2] = {(int)prevclick_f[0], (int)prevclick_f[1]};
+ int len = (int)len_v2v2_int(prevclick, event->mval);
+ len = ABS(len);
+ int mask_speed = RNA_int_get(op->ptr, "mask_speed");
+ int mask_expand_update_it = len / mask_speed;
+ mask_expand_update_it = mask_expand_update_it + 1;
+
+ if (RNA_boolean_get(op->ptr, "use_cursor")) {
+ SculptCursorGeometryInfo sgi;
+ float mouse[2];
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+ sculpt_cursor_geometry_info_update(C, &sgi, mouse, false);
+ mask_expand_update_it = ss->filter_cache->mask_update_it[(int)sculpt_active_vertex_get(ss)];
+ }
+
+ if ((event->type == ESCKEY && event->val == KM_PRESS) ||
+ (event->type == RIGHTMOUSE && event->val == KM_PRESS)) {
+ /* Returning OPERATOR_CANCELLED will leak memory due to not finishing
+ * undo. Better solution could be to make paint_mesh_restore_co work
+ * for this case. */
+ sculpt_mask_expand_cancel(C, op);
+ return OPERATOR_FINISHED;
+ }
+
+ if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) ||
+ (event->type == RETKEY && event->val == KM_PRESS) ||
+ (event->type == PADENTER && event->val == KM_PRESS)) {
+
+ /* Smooth iterations */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .filter_type = MASK_FILTER_SMOOTH,
+ };
+
+ int smooth_iterations = RNA_int_get(op->ptr, "smooth_iterations");
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false);
+ for (int i = 0; i < smooth_iterations; i++) {
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mask_filter_task_cb, &settings);
+ }
+
+ /* Pivot position */
+ if (RNA_boolean_get(op->ptr, "update_pivot")) {
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ const float threshold = 0.2f;
+ float avg[3];
+ int total = 0;
+ zero_v3(avg);
+
+ 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)
+ {
+ const float mask = (vd.mask) ? *vd.mask : 0.0f;
+ if (mask < (0.5f + threshold) && mask > (0.5f - threshold)) {
+ if (check_vertex_pivot_symmetry(
+ vd.co, ss->filter_cache->mask_expand_initial_co, symm)) {
+ add_v3_v3(avg, vd.co);
+ total++;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ copy_v3_v3(ss->pivot_pos, avg);
+ }
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
+ }
+
+ MEM_freeN(op->customdata);
+
+ for (int i = 0; i < ss->filter_cache->totnode; i++) {
+ BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
+ }
+
+ sculpt_filter_cache_free(ss);
+
+ sculpt_undo_push_end();
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
+ ED_workspace_status_text(C, NULL);
+ return OPERATOR_FINISHED;
+ }
+
+ if (event->type != MOUSEMOVE) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ if (mask_expand_update_it == ss->filter_cache->mask_update_current_it) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ if (mask_expand_update_it < ss->filter_cache->mask_update_last_it) {
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .mask_expand_update_it = mask_expand_update_it,
+ .mask_expand_use_normals = RNA_boolean_get(op->ptr, "use_normals"),
+ .mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"),
+ .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"),
+ };
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
+ ss->filter_cache->mask_update_current_it = mask_expand_update_it;
+ }
+
+ sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+typedef struct MaskExpandFloodFillData {
+ float original_normal[3];
+ float edge_sensitivity;
+ bool use_normals;
+} MaskExpandFloodFillData;
+
+static bool mask_expand_floodfill_cb(SculptSession *ss,
+ const SculptFloodFillIterator *from,
+ SculptFloodFillIterator *to,
+ void *userdata)
+{
+ MaskExpandFloodFillData *data = userdata;
+
+ ss->filter_cache->mask_update_it[to->v] = to->it;
+ if (to->it > ss->filter_cache->mask_update_last_it) {
+ ss->filter_cache->mask_update_last_it = to->it;
+ }
+
+ if (data->use_normals) {
+ float current_normal[3], prev_normal[3];
+ sculpt_vertex_normal_get(ss, to->v, current_normal);
+ sculpt_vertex_normal_get(ss, from->v, prev_normal);
+ to->edge_factor = dot_v3v3(current_normal, prev_normal) * from->edge_factor;
+ ss->filter_cache->normal_factor[to->v] = dot_v3v3(data->original_normal, current_normal) *
+ powf(from->edge_factor, data->edge_sensitivity);
+ CLAMP(ss->filter_cache->normal_factor[to->v], 0.0f, 1.0f);
+ }
+
+ return true;
+}
+
+static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ PBVH *pbvh = ob->sculpt->pbvh;
+
+ bool use_normals = RNA_boolean_get(op->ptr, "use_normals");
+
+ SculptCursorGeometryInfo sgi;
+ float mouse[2];
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ return OPERATOR_CANCELLED;
+ }
+
+ sculpt_vertex_random_access_init(ss);
+
+ op->customdata = MEM_mallocN(2 * sizeof(float), "initial mouse position");
+ copy_v2_v2(op->customdata, mouse);
+
+ sculpt_cursor_geometry_info_update(C, &sgi, mouse, false);
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ int vertex_count = sculpt_vertex_count_get(ss);
+
+ ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache");
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &ss->filter_cache->nodes, &ss->filter_cache->totnode);
+
+ sculpt_undo_push_begin("Mask Expand");
+
+ for (int i = 0; i < ss->filter_cache->totnode; i++) {
+ sculpt_undo_push_node(ob, ss->filter_cache->nodes[i], SCULPT_UNDO_MASK);
+ BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
+ }
+
+ ss->filter_cache->mask_update_it = MEM_callocN(sizeof(int) * vertex_count,
+ "mask update iteration");
+ if (use_normals) {
+ ss->filter_cache->normal_factor = MEM_callocN(sizeof(float) * vertex_count,
+ "mask update normal factor");
+ }
+
+ ss->filter_cache->prev_mask = MEM_callocN(sizeof(float) * vertex_count, "prev mask");
+ for (int i = 0; i < vertex_count; i++) {
+ ss->filter_cache->prev_mask[i] = sculpt_vertex_mask_get(ss, i);
+ }
+
+ ss->filter_cache->mask_update_last_it = 1;
+ ss->filter_cache->mask_update_current_it = 1;
+ ss->filter_cache->mask_update_it[sculpt_active_vertex_get(ss)] = 1;
+
+ copy_v3_v3(ss->filter_cache->mask_expand_initial_co, sculpt_active_vertex_co_get(ss));
+
+ SculptFloodFill flood;
+ sculpt_floodfill_init(ss, &flood);
+ sculpt_floodfill_add_active(sd, ob, ss, &flood, FLT_MAX);
+
+ MaskExpandFloodFillData fdata = {
+ .use_normals = use_normals,
+ .edge_sensitivity = RNA_int_get(op->ptr, "edge_sensitivity"),
+ };
+ sculpt_active_vertex_normal_get(ss, fdata.original_normal);
+ sculpt_floodfill_execute(ss, &flood, mask_expand_floodfill_cb, &fdata);
+ sculpt_floodfill_free(&flood);
+
+ if (use_normals) {
+ for (int repeat = 0; repeat < 2; repeat++) {
+ for (int i = 0; i < vertex_count; i++) {
+ float avg = 0;
+ SculptVertexNeighborIter ni;
+ sculpt_vertex_neighbors_iter_begin(ss, i, ni)
+ {
+ avg += ss->filter_cache->normal_factor[ni.index];
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+ ss->filter_cache->normal_factor[i] = avg / ni.size;
+ }
+ }
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .mask_expand_update_it = 0,
+ .mask_expand_use_normals = RNA_boolean_get(op->ptr, "use_normals"),
+ .mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"),
+ .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"),
+ };
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
+
+ const char *status_str = TIP_(
+ "Move the mouse to expand the mask from the active vertex. LBM: confirm mask, ESC/RMB: "
+ "cancel");
+ ED_workspace_status_text(C, status_str);
+
+ sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void SCULPT_OT_mask_expand(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Mask Expand";
+ ot->idname = "SCULPT_OT_mask_expand";
+ ot->description = "Expands a mask from the initial active vertex under the cursor";
+
+ /* api callbacks */
+ ot->invoke = sculpt_mask_expand_invoke;
+ ot->modal = sculpt_mask_expand_modal;
+ ot->cancel = sculpt_mask_expand_cancel;
+ ot->poll = sculpt_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->prop = RNA_def_boolean(ot->srna, "invert", true, "Invert", "Invert the new mask");
+ ot->prop = RNA_def_boolean(
+ ot->srna, "use_cursor", true, "Use Cursor", "Expand the mask to the cursor position");
+ ot->prop = RNA_def_boolean(ot->srna,
+ "update_pivot",
+ true,
+ "Update Pivot Position",
+ "Set the pivot position to the mask border after creating the mask");
+ ot->prop = RNA_def_int(ot->srna, "smooth_iterations", 2, 0, 10, "Smooth iterations", "", 0, 10);
+ ot->prop = RNA_def_int(ot->srna, "mask_speed", 5, 1, 10, "Mask speed", "", 1, 10);
+
+ ot->prop = RNA_def_boolean(ot->srna,
+ "use_normals",
+ true,
+ "Use Normals",
+ "Generate the mask using the normals and curvature of the model");
+ ot->prop = RNA_def_boolean(ot->srna,
+ "keep_previous_mask",
+ false,
+ "Keep Previous Mask",
+ "Generate the new mask on top of the current one");
+ ot->prop = RNA_def_int(ot->srna,
+ "edge_sensitivity",
+ 300,
+ 0,
+ 2000,
+ "Edge Detection Sensitivity",
+ "Sensitivity for expanding the mask across sculpted sharp edges when "
+ "using normals to generate the mask",
+ 0,
+ 2000);
+}
+
+void sculpt_geometry_preview_lines_update(bContext *C, SculptSession *ss, float radius)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+
+ ss->preview_vert_index_count = 0;
+ int totpoints = 0;
+
+ /* This function is called from the cursor drawing code, so the PBVH may not be build yet */
+ if (!ss->pbvh) {
+ return;
+ }
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ if (!ss->pmap) {
+ return;
+ }
+
+ float brush_co[3];
+ copy_v3_v3(brush_co, sculpt_active_vertex_co_get(ss));
+
+ char *visited_vertices = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(char),
+ "visited vertices");
+
+ /* Assuming an average of 6 edges per vertex in a triangulated mesh */
+ const int max_preview_vertices = sculpt_vertex_count_get(ss) * 3 * 2;
+
+ if (ss->preview_vert_index_list == NULL) {
+ ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines");
+ }
+
+ GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int));
+ int active_v = sculpt_active_vertex_get(ss);
+ BLI_gsqueue_push(not_visited_vertices, &active_v);
+
+ while (!BLI_gsqueue_is_empty(not_visited_vertices)) {
+ int from_v;
+ BLI_gsqueue_pop(not_visited_vertices, &from_v);
+ SculptVertexNeighborIter ni;
+ sculpt_vertex_neighbors_iter_begin(ss, from_v, ni)
+ {
+ if (totpoints + (ni.size * 2) < max_preview_vertices) {
+ int to_v = ni.index;
+ ss->preview_vert_index_list[totpoints] = from_v;
+ totpoints++;
+ ss->preview_vert_index_list[totpoints] = to_v;
+ totpoints++;
+ if (visited_vertices[to_v] == 0) {
+ visited_vertices[to_v] = 1;
+ const float *co = sculpt_vertex_co_get(ss, to_v);
+ if (len_squared_v3v3(brush_co, co) < radius * radius) {
+ BLI_gsqueue_push(not_visited_vertices, &to_v);
+ }
+ }
+ }
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+ }
+
+ BLI_gsqueue_free(not_visited_vertices);
+
+ MEM_freeN(visited_vertices);
+
+ ss->preview_vert_index_count = totpoints;
+}
+void ED_sculpt_init_transform(struct bContext *C)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+
+ copy_v3_v3(ss->init_pivot_pos, ss->pivot_pos);
+ copy_v4_v4(ss->init_pivot_rot, ss->pivot_rot);
+
+ sculpt_undo_push_begin("Transform");
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false);
+
+ ss->pivot_rot[3] = 1.0f;
+
+ sculpt_vertex_random_access_init(ss);
+ sculpt_filter_cache_init(ob, sd);
+}
+
+typedef enum PaintSymmetryAreas {
+ AREA_SYMM_X = (1 << 0),
+ AREA_SYMM_Y = (1 << 1),
+ AREA_SYMM_Z = (1 << 2),
+} PaintSymmetryAreas;
+
+static char sculpt_get_vertex_symm_area(float co[3])
+{
+ float vco[3];
+ char symm_area = 0;
+ copy_v3_v3(vco, co);
+ if (vco[0] < 0) {
+ symm_area |= AREA_SYMM_X;
+ }
+ if (vco[1] < 0) {
+ symm_area |= AREA_SYMM_Y;
+ }
+ if (vco[2] < 0) {
+ symm_area |= AREA_SYMM_Z;
+ }
+ return symm_area;
+}
+
+static void flip_qt(float qt[4], char symm)
+{
+ float euler[3];
+ if (symm & PAINT_SYMM_X) {
+ quat_to_eul(euler, qt);
+ euler[1] = -euler[1];
+ euler[2] = -euler[2];
+ eul_to_quat(qt, euler);
+ }
+ if (symm & PAINT_SYMM_Y) {
+ quat_to_eul(euler, qt);
+ euler[0] = -euler[0];
+ euler[2] = -euler[2];
+ eul_to_quat(qt, euler);
+ }
+ if (symm & PAINT_SYMM_Z) {
+ quat_to_eul(euler, qt);
+ euler[0] = -euler[0];
+ euler[1] = -euler[1];
+ eul_to_quat(qt, euler);
+ }
+}
+
+static void sculpt_flip_transform_by_symm_area(
+ float disp[3], float rot[4], char symm, char symmarea, float pivot[3])
+{
+
+ for (char i = 0; i < 3; i++) {
+ char symm_it = 1 << i;
+ if (symm & symm_it) {
+ if (symmarea & symm_it) {
+ if (disp) {
+ flip_v3(disp, symm_it);
+ }
+ if (rot) {
+ flip_qt(rot, symm_it);
+ }
+ }
+ if (pivot[0] < 0) {
+ if (disp) {
+ flip_v3(disp, symm_it);
+ }
+ if (rot) {
+ flip_qt(rot, symm_it);
+ }
+ }
+ }
+ }
+}
+
+static void sculpt_transform_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];
+
+ SculptOrigVertData orig_data;
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
+
+ PBVHVertexIter vd;
+
+ sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+ float transformed_co[3], orig_co[3], disp[3];
+ float fade = vd.mask ? *vd.mask : 0.0f;
+ copy_v3_v3(orig_co, orig_data.co);
+ char symm_area = sculpt_get_vertex_symm_area(orig_co);
+
+ copy_v3_v3(transformed_co, orig_co);
+ mul_m4_v3(data->transform_mats[(int)symm_area], transformed_co);
+ sub_v3_v3v3(disp, transformed_co, orig_co);
+ mul_v3_fl(disp, 1.0f - fade);
+
+ add_v3_v3v3(vd.co, orig_co, disp);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ BKE_pbvh_node_mark_redraw(node);
+ BKE_pbvh_node_mark_normals_update(node);
+}
+
+void ED_sculpt_update_modal_transform(struct bContext *C)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+
+ sculpt_vertex_random_access_init(ss);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ };
+
+ float final_pivot_pos[3], d_t[3], d_r[4];
+ float t_mat[4][4], r_mat[4][4], s_mat[4][4], pivot_mat[4][4], pivot_imat[4][4],
+ transform_mat[4][4];
+
+ copy_v3_v3(final_pivot_pos, ss->pivot_pos);
+ for (int i = 0; i < 8; i++) {
+ copy_v3_v3(final_pivot_pos, ss->pivot_pos);
+
+ unit_m4(pivot_mat);
+
+ unit_m4(t_mat);
+ unit_m4(r_mat);
+ unit_m4(s_mat);
+
+ /* Translation matrix */
+ sub_v3_v3v3(d_t, ss->pivot_pos, ss->init_pivot_pos);
+ sculpt_flip_transform_by_symm_area(d_t, NULL, symm, (char)i, ss->init_pivot_pos);
+ translate_m4(t_mat, d_t[0], d_t[1], d_t[2]);
+
+ /* Rotation matrix */
+ sub_qt_qtqt(d_r, ss->pivot_rot, ss->init_pivot_rot);
+ normalize_qt(d_r);
+ sculpt_flip_transform_by_symm_area(NULL, d_r, symm, (char)i, ss->init_pivot_pos);
+ quat_to_mat4(r_mat, d_r);
+
+ /* Scale matrix */
+ size_to_mat4(s_mat, ss->pivot_scale);
+
+ /* Pivot matrix */
+ sculpt_flip_transform_by_symm_area(final_pivot_pos, NULL, symm, (char)i, ss->init_pivot_pos);
+ translate_m4(pivot_mat, final_pivot_pos[0], final_pivot_pos[1], final_pivot_pos[2]);
+ invert_m4_m4(pivot_imat, pivot_mat);
+
+ /* Final transform matrix */
+ mul_m4_m4m4(transform_mat, r_mat, t_mat);
+ mul_m4_m4m4(transform_mat, transform_mat, s_mat);
+ mul_m4_m4m4(data.transform_mats[i], transform_mat, pivot_imat);
+ mul_m4_m4m4(data.transform_mats[i], pivot_mat, data.transform_mats[i]);
+ }
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(
+ 0, ss->filter_cache->totnode, &data, sculpt_transform_task_cb, &settings);
+
+ if (ss->modifiers_active || ss->kb) {
+ sculpt_flush_stroke_deform(sd, ob, true);
+ }
+
+ sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS);
+}
+
+void ED_sculpt_end_transform(struct bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ if (ss->filter_cache) {
+ sculpt_filter_cache_free(ss);
+ }
+ sculpt_undo_push_end();
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
+}
+
+typedef enum eSculptPivotPositionModes {
+ SCULPT_PIVOT_POSITION_ORIGIN = 0,
+ SCULPT_PIVOT_POSITION_UNMASKED = 1,
+ SCULPT_PIVOT_POSITION_MASK_BORDER = 2,
+ SCULPT_PIVOT_POSITION_ACTIVE_VERTEX = 3,
+ SCULPT_PIVOT_POSITION_CURSOR_SURFACE = 4,
+} eSculptPivotPositionModes;
+
+static EnumPropertyItem prop_sculpt_pivot_position_types[] = {
+ {SCULPT_PIVOT_POSITION_ORIGIN,
+ "ORIGIN",
+ 0,
+ "Origin",
+ "Sets the pivot to the origin of the sculpt"},
+ {SCULPT_PIVOT_POSITION_UNMASKED,
+ "UNMASKED",
+ 0,
+ "Unmasked",
+ "Sets the pivot position to the average position of the unmasked vertices"},
+ {SCULPT_PIVOT_POSITION_MASK_BORDER,
+ "BORDER",
+ 0,
+ "Mask border",
+ "Sets the pivot position to the center of the border of the mask"},
+ {SCULPT_PIVOT_POSITION_ACTIVE_VERTEX,
+ "ACTIVE",
+ 0,
+ "Active vertex",
+ "Sets the pivot position to the active vertex position"},
+ {SCULPT_PIVOT_POSITION_CURSOR_SURFACE,
+ "SURFACE",
+ 0,
+ "Surface",
+ "Sets the pivot position to the surface under the cursor"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static int sculpt_set_pivot_position_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ ARegion *ar = CTX_wm_region(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+
+ int mode = RNA_enum_get(op->ptr, "mode");
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true);
+
+ /* Pivot to center */
+ if (mode == SCULPT_PIVOT_POSITION_ORIGIN) {
+ zero_v3(ss->pivot_pos);
+ }
+ /* Pivot to active vertex */
+ else if (mode == SCULPT_PIVOT_POSITION_ACTIVE_VERTEX) {
+ copy_v3_v3(ss->pivot_pos, sculpt_active_vertex_co_get(ss));
+ }
+ /* Pivot to raycast surface */
+ else if (mode == SCULPT_PIVOT_POSITION_CURSOR_SURFACE) {
+ float stroke_location[3];
+ float mouse[2];
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+ if (sculpt_stroke_get_location(C, stroke_location, mouse)) {
+ copy_v3_v3(ss->pivot_pos, stroke_location);
+ }
+ }
+ else {
+ PBVHNode **nodes;
+ int totnode;
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+
+ float avg[3];
+ int total = 0;
+ zero_v3(avg);
+
+ /* Pivot to unmasked */
+ 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)
+ {
+ const float mask = (vd.mask) ? *vd.mask : 0.0f;
+ if (mask < 1.0f) {
+ if (check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) {
+ add_v3_v3(avg, vd.co);
+ total++;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+ }
+ /* Pivot to mask border */
+ else if (mode == SCULPT_PIVOT_POSITION_MASK_BORDER) {
+ const float threshold = 0.2f;
+
+ for (int n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ 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 (check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) {
+ add_v3_v3(avg, vd.co);
+ total++;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+ }
+
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ copy_v3_v3(ss->pivot_pos, avg);
+ }
+
+ MEM_SAFE_FREE(nodes);
+ }
+
+ ED_region_tag_redraw(ar);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_set_pivot_position(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Pivot Position";
+ ot->idname = "SCULPT_OT_set_pivot_position";
+ ot->description = "Sets the sculpt transform pivot position";
+
+ /* api callbacks */
+ ot->invoke = sculpt_set_pivot_position_invoke;
+ ot->poll = sculpt_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ RNA_def_enum(ot->srna,
+ "mode",
+ prop_sculpt_pivot_position_types,
+ SCULPT_PIVOT_POSITION_UNMASKED,
+ "Mode",
+ "");
+}
void ED_operatortypes_sculpt(void)
{
@@ -6752,4 +9777,9 @@ void ED_operatortypes_sculpt(void)
WM_operatortype_append(SCULPT_OT_detail_flood_fill);
WM_operatortype_append(SCULPT_OT_sample_detail_size);
WM_operatortype_append(SCULPT_OT_set_detail_size);
+ WM_operatortype_append(SCULPT_OT_mesh_filter);
+ WM_operatortype_append(SCULPT_OT_mask_filter);
+ WM_operatortype_append(SCULPT_OT_dirty_mask);
+ WM_operatortype_append(SCULPT_OT_mask_expand);
+ WM_operatortype_append(SCULPT_OT_set_pivot_position);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index bc9a4c1d85b..e9af49a0b5a 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -44,8 +44,38 @@ bool sculpt_mode_poll_view3d(struct bContext *C);
bool sculpt_poll(struct bContext *C);
bool sculpt_poll_view3d(struct bContext *C);
+/* Updates */
+
+typedef enum SculptUpdateType {
+ SCULPT_UPDATE_COORDS = 1 << 0,
+ SCULPT_UPDATE_MASK = 1 << 1,
+} SculptUpdateType;
+
/* Stroke */
+
+typedef struct SculptCursorGeometryInfo {
+ float location[3];
+ float normal[3];
+ float active_vertex_co[3];
+} SculptCursorGeometryInfo;
+
bool sculpt_stroke_get_location(struct bContext *C, float out[3], const float mouse[2]);
+bool sculpt_cursor_geometry_info_update(bContext *C,
+ SculptCursorGeometryInfo *out,
+ const float mouse[2],
+ bool use_sampled_normal);
+void sculpt_geometry_preview_lines_update(bContext *C, struct SculptSession *ss, float radius);
+void sculpt_pose_calc_pose_data(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ float initial_location[3],
+ float radius,
+ float pose_offset,
+ float *r_pose_origin,
+ float *r_pose_factor);
+
+/* Sculpt PBVH abstraction API */
+const float *sculpt_vertex_co_get(struct SculptSession *ss, int index);
/* Dynamic topology */
void sculpt_pbvh_clear(Object *ob);
@@ -107,6 +137,10 @@ typedef struct SculptUndoNode {
int geom_totloop;
int geom_totpoly;
+ /* pivot */
+ float pivot_pos[3];
+ float pivot_rot[4];
+
size_t undo_size;
} SculptUndoNode;
@@ -158,10 +192,41 @@ typedef struct SculptThreadedTaskData {
float (*mat)[4];
float (*vertCos)[3];
+ int filter_type;
+ float filter_strength;
+ int *node_mask;
+
/* 0=towards view, 1=flipped */
float (*area_cos)[3];
float (*area_nos)[3];
int *count;
+ bool any_vertex_sampled;
+
+ float *prev_mask;
+
+ float *pose_origin;
+ float *pose_initial_co;
+ float *pose_factor;
+ float (*transform_rot)[4], (*transform_trans)[4], (*transform_trans_inv)[4];
+
+ float tot_pos_avg[3];
+ int tot_pos_count;
+
+ float max_distance_squared;
+ float nearest_vertex_search_co[3];
+ int nearest_vertex_index;
+ float nearest_vertex_distance_squared;
+
+ int mask_expand_update_it;
+ bool mask_expand_invert_mask;
+ bool mask_expand_use_normals;
+ bool mask_expand_keep_prev_mask;
+
+ float transform_mats[8][4][4];
+
+ float dirty_mask_min;
+ float dirty_mask_max;
+ bool dirty_mask_dirty_only;
ThreadMutex mutex;
@@ -190,7 +255,9 @@ typedef struct {
struct Sculpt *sd;
struct SculptSession *ss;
float radius_squared;
+ float *center;
bool original;
+ bool ignore_fully_masked;
} SculptSearchSphereData;
typedef struct {
@@ -198,6 +265,7 @@ typedef struct {
struct SculptSession *ss;
float radius_squared;
bool original;
+ bool ignore_fully_masked;
struct DistRayAABB_Precalc *dist_ray_to_aabb_precalc;
} SculptSearchCircleData;
@@ -223,10 +291,11 @@ float tex_strength(struct SculptSession *ss,
const short vno[3],
const float fno[3],
const float mask,
+ const int vertex_index,
const int thread_id);
/* just for vertex paint. */
-void sculpt_pbvh_calc_area_normal(const struct Brush *brush,
+bool sculpt_pbvh_calc_area_normal(const struct Brush *brush,
Object *ob,
PBVHNode **nodes,
int totnode,
@@ -310,6 +379,11 @@ typedef struct StrokeCache {
bool original;
float anchored_location[3];
+ /* Pose brush */
+ float *pose_factor;
+ float pose_initial_co[3];
+ float pose_origin[3];
+
float vertex_rotation; /* amount to rotate the vertices when using rotate brush */
struct Dial *dial;
@@ -324,11 +398,30 @@ typedef struct StrokeCache {
float true_gravity_direction[3];
float gravity_direction[3];
+ float *automask;
+
rcti previous_r; /* previous redraw rectangle */
rcti current_r; /* current redraw rectangle */
} StrokeCache;
+typedef struct FilterCache {
+ bool enabled_axis[3];
+ int random_seed;
+
+ /* unmasked nodes */
+ PBVHNode **nodes;
+ int totnode;
+
+ /* mask expand iteration caches */
+ int mask_update_current_it;
+ int mask_update_last_it;
+ int *mask_update_it;
+ float *normal_factor;
+ float *prev_mask;
+ float mask_expand_initial_co[3];
+} FilterCache;
+
void sculpt_cache_calc_brushdata_symm(StrokeCache *cache,
const char symm,
const char axis,
@@ -346,6 +439,4 @@ void sculpt_update_object_bounding_box(struct Object *ob);
bool sculpt_get_redraw_rect(struct ARegion *ar, struct RegionView3D *rv3d, Object *ob, rcti *rect);
-#define SCULPT_THREADED_LIMIT 4
-
#endif
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index cb8afd5d7fa..788d07f6e78 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -39,8 +39,6 @@
#include "DNA_scene_types.h"
#include "DNA_mesh_types.h"
#include "DNA_screen_types.h"
-#include "DNA_space_types.h"
-#include "DNA_workspace_types.h"
#include "BKE_ccg.h"
#include "BKE_context.h"
@@ -49,7 +47,6 @@
#include "BKE_paint.h"
#include "BKE_key.h"
#include "BKE_mesh.h"
-#include "BKE_mesh_runtime.h"
#include "BKE_scene.h"
#include "BKE_subsurf.h"
#include "BKE_subdiv_ccg.h"
@@ -62,13 +59,11 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "ED_paint.h"
#include "ED_object.h"
#include "ED_sculpt.h"
#include "ED_undo.h"
#include "bmesh.h"
-#include "paint_intern.h"
#include "sculpt_intern.h"
typedef struct UndoSculpt {
@@ -352,8 +347,7 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C,
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
BLI_task_parallel_range(
0, totnode, nodes, sculpt_undo_bmesh_restore_generic_task_cb, &settings);
@@ -494,6 +488,9 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
bool partial_update = true;
for (unode = lb->first; unode; unode = unode->next) {
+ /* restore pivot */
+ copy_v3_v3(ss->pivot_pos, unode->pivot_pos);
+ copy_v3_v3(ss->pivot_rot, unode->pivot_rot);
if (STREQ(unode->idname, ob->id.name)) {
if (unode->type == SCULPT_UNDO_MASK) {
/* is possible that we can't do the mask undo (below)
@@ -1055,6 +1052,10 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
break;
}
+ /* store sculpt pivot */
+ copy_v3_v3(unode->pivot_pos, ss->pivot_pos);
+ copy_v3_v3(unode->pivot_rot, ss->pivot_rot);
+
/* store active shape key */
if (ss->kb) {
BLI_strncpy(unode->shapeName, ss->kb->name, sizeof(ss->kb->name));
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index 91ed9057667..8fbaf3396bd 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -38,7 +38,6 @@
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
-#include "BKE_main.h"
#include "BKE_mesh_mapping.h"
#include "BKE_paint.h"
@@ -48,10 +47,6 @@
#include "ED_image.h"
#include "ED_mesh.h"
-#include "GPU_immediate.h"
-#include "GPU_immediate_util.h"
-#include "GPU_state.h"
-
#include "WM_api.h"
#include "WM_types.h"
@@ -151,7 +146,7 @@ typedef struct Temp_UvData {
static void HC_relaxation_iteration_uv(BMEditMesh *em,
UvSculptData *sculptdata,
- float mouse_coord[2],
+ const float mouse_coord[2],
float alpha,
float radius,
float aspectRatio)
@@ -239,7 +234,7 @@ static void HC_relaxation_iteration_uv(BMEditMesh *em,
static void laplacian_relaxation_iteration_uv(BMEditMesh *em,
UvSculptData *sculptdata,
- float mouse_coord[2],
+ const float mouse_coord[2],
float alpha,
float radius,
float aspectRatio)
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index 51231ccf634..4e710d31cbb 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -710,7 +710,7 @@ static void SOUND_OT_mixdown(wmOperatorType *ot)
FILE_TYPE_FOLDER | FILE_TYPE_SOUND,
FILE_SPECIAL,
FILE_SAVE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
#ifdef WITH_AUDASPACE
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 944a0c74f4c..242acfd0261 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -1663,7 +1663,7 @@ static const EnumPropertyItem prop_actkeys_snap_types[] = {
{ACTKEYS_SNAP_CFRA,
"CFRA",
0,
- "Current frame",
+ "Current Frame",
"Snap selected keyframes to the current frame"},
{ACTKEYS_SNAP_NEAREST_FRAME,
"NEAREST_FRAME",
@@ -1789,17 +1789,17 @@ static const EnumPropertyItem prop_actkeys_mirror_types[] = {
{ACTKEYS_MIRROR_CFRA,
"CFRA",
0,
- "By Times over Current frame",
+ "By Times Over Current Frame",
"Flip times of selected keyframes using the current frame as the mirror line"},
{ACTKEYS_MIRROR_XAXIS,
"XAXIS",
0,
- "By Values over Value=0",
+ "By Values Over Value=0",
"Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"},
{ACTKEYS_MIRROR_MARKER,
"MARKER",
0,
- "By Times over First Selected Marker",
+ "By Times Over First Selected Marker",
"Flip times of selected keyframes using the first selected marker as the reference point"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 9e2634b183a..4a4ff5f5605 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -339,7 +339,9 @@ static int actkeys_deselectall_exec(bContext *C, wmOperator *op)
/* set notifier that keyframe selection have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -572,7 +574,9 @@ static int actkeys_box_select_exec(bContext *C, wmOperator *op)
/* set notifier that keyframe selection have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -805,7 +809,9 @@ static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -871,7 +877,9 @@ static int action_circle_select_exec(bContext *C, wmOperator *op)
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1099,7 +1107,9 @@ static int actkeys_columnselect_exec(bContext *C, wmOperator *op)
/* set notifier that keyframe selection have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1159,7 +1169,9 @@ static int actkeys_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
/* set notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1243,7 +1255,9 @@ static int actkeys_select_more_exec(bContext *C, wmOperator *UNUSED(op))
/* set notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1278,7 +1292,9 @@ static int actkeys_select_less_exec(bContext *C, wmOperator *UNUSED(op))
/* set notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1717,22 +1733,26 @@ static void mouse_action_keys(bAnimContext *ac,
/* Highlight GPencil Layer */
if (ale != NULL && ale->data != NULL && ale->type == ANIMTYPE_GPLAYER) {
+ bGPdata *gpd = (bGPdata *)ale->id;
bGPDlayer *gpl = ale->data;
gpl->flag |= GP_LAYER_SELECT;
- // gpencil_layer_setactive(gpd, gpl);
+ /* Update other layer status. */
+ if (BKE_gpencil_layer_getactive(gpd) != gpl) {
+ BKE_gpencil_layer_setactive(gpd, gpl);
+ BKE_gpencil_layer_autolock_set(gpd, false);
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
}
}
else if (ac->datatype == ANIMCONT_MASK) {
/* deselect all other channels first */
ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
- /* Highlight GPencil Layer */
if (ale != NULL && ale->data != NULL && ale->type == ANIMTYPE_MASKLAYER) {
MaskLayer *masklay = ale->data;
masklay->flag |= MASK_LAYERFLAG_SELECT;
- // gpencil_layer_setactive(gpd, gpl);
}
}
}
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 23c224f5ae0..b26c3113fbd 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -364,6 +364,7 @@ static void buttons_area_listener(wmWindow *UNUSED(win),
switch (wmn->data) {
case ND_RENDER_OPTIONS:
buttons_area_redraw(sa, BCONTEXT_RENDER);
+ buttons_area_redraw(sa, BCONTEXT_OUTPUT);
buttons_area_redraw(sa, BCONTEXT_VIEW_LAYER);
break;
case ND_WORLD:
diff --git a/source/blender/editors/space_clip/clip_dopesheet_draw.c b/source/blender/editors/space_clip/clip_dopesheet_draw.c
index 3c2d3eb1d97..e64f21f9307 100644
--- a/source/blender/editors/space_clip/clip_dopesheet_draw.c
+++ b/source/blender/editors/space_clip/clip_dopesheet_draw.c
@@ -44,7 +44,6 @@
#include "RNA_access.h"
-#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_state.h"
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index e3fa8edd714..80b58954c8f 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -161,7 +161,7 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc
/* cache background */
ED_region_cache_draw_background(ar);
- /* cached segments -- could be usefu lto debug caching strategies */
+ /* cached segments -- could be useful to debug caching strategies */
BKE_movieclip_get_cache_segments(clip, &sc->user, &totseg, &points);
ED_region_cache_draw_cached_segments(ar, totseg, points, sfra, efra);
@@ -404,177 +404,185 @@ static void draw_stabilization_border(
}
}
-static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackingTrack *track)
-{
-#define MAX_STATIC_PATH 64
- int count = sc->path_length;
- int i, a, b, curindex = -1;
- float path_static[(MAX_STATIC_PATH + 1) * 2][2];
- float(*path)[2];
- int tiny = sc->flag & SC_SHOW_TINY_MARKER, framenr, start_frame;
- MovieTrackingMarker *marker;
+enum {
+ PATH_POINT_FLAG_KEYFRAME = (1 << 0),
+};
- if (count == 0) {
- return;
- }
+typedef struct TrachPathPoint {
+ float co[2];
+ uchar flag;
+} TrackPathPoint;
- start_frame = framenr = ED_space_clip_get_clip_frame_number(sc);
-
- marker = BKE_tracking_marker_get(track, framenr);
- if (marker->framenr != framenr || marker->flag & MARKER_DISABLED) {
- return;
- }
-
- if (count < MAX_STATIC_PATH) {
- path = path_static;
- }
- else {
- path = MEM_mallocN(sizeof(*path) * (count + 1) * 2, "path");
+static void marker_to_path_point(SpaceClip *sc,
+ const MovieTrackingTrack *track,
+ const MovieTrackingMarker *marker,
+ TrackPathPoint *point)
+{
+ add_v2_v2v2(point->co, marker->pos, track->offset);
+ ED_clip_point_undistorted_pos(sc, point->co, point->co);
+ point->flag = 0;
+ if ((marker->flag & MARKER_TRACKED) == 0) {
+ point->flag |= PATH_POINT_FLAG_KEYFRAME;
}
+}
- a = count;
- i = framenr - 1;
- while (i >= framenr - count) {
- marker = BKE_tracking_marker_get(track, i);
-
- if (!marker || marker->flag & MARKER_DISABLED) {
+static int track_to_path_segment(SpaceClip *sc,
+ MovieTrackingTrack *track,
+ int direction,
+ TrackPathPoint *path)
+{
+ const int count = sc->path_length;
+ int current_frame = ED_space_clip_get_clip_frame_number(sc);
+ const MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, current_frame);
+ /* Check whether there is marker at exact current frame.
+ * If not, we don't have anything to be put to path. */
+ if (marker == NULL || (marker->flag & MARKER_DISABLED)) {
+ return 0;
+ }
+ /* Index inside of path array where we write data to. */
+ int point_index = count;
+ int path_length = 0;
+ for (int i = 0; i < count; ++i) {
+ marker_to_path_point(sc, track, marker, &path[point_index]);
+ /* Move to the next marker along the path segment. */
+ path_length++;
+ point_index += direction;
+ current_frame += direction;
+ marker = BKE_tracking_marker_get_exact(track, current_frame);
+ if (marker == NULL || (marker->flag & MARKER_DISABLED)) {
+ /* Reached end of tracked segment. */
break;
}
+ }
+ return path_length;
+}
- if (marker->framenr == i) {
- add_v2_v2v2(path[--a], marker->pos, track->offset);
- ED_clip_point_undistorted_pos(sc, path[a], path[a]);
+static void draw_track_path_points(const TrackPathPoint *path,
+ uint position_attribute,
+ const int start_point,
+ const int num_points)
+{
+ if (num_points == 0) {
+ return;
+ }
+ immBegin(GPU_PRIM_POINTS, num_points);
+ for (int i = 0; i < num_points; i++) {
+ const TrackPathPoint *point = &path[i + start_point];
+ immVertex2fv(position_attribute, point->co);
+ }
+ immEnd();
+}
- if (marker->framenr == start_frame) {
- curindex = a;
- }
- }
- else {
- break;
+static void draw_track_path_keyframe_points(const TrackPathPoint *path,
+ uint position_attribute,
+ const int start_point,
+ const int num_points)
+{
+ immBeginAtMost(GPU_PRIM_POINTS, num_points);
+ for (int i = 0; i < num_points; i++) {
+ const TrackPathPoint *point = &path[i + start_point];
+ if (point->flag & PATH_POINT_FLAG_KEYFRAME) {
+ immVertex2fv(position_attribute, point->co);
}
+ }
+ immEnd();
+}
- i--;
+static void draw_track_path_lines(const TrackPathPoint *path,
+ uint position_attribute,
+ const int start_point,
+ const int num_points)
+{
+ if (num_points < 2) {
+ return;
+ }
+ immBegin(GPU_PRIM_LINE_STRIP, num_points);
+ for (int i = 0; i < num_points; i++) {
+ const TrackPathPoint *point = &path[i + start_point];
+ immVertex2fv(position_attribute, point->co);
}
+ immEnd();
+}
- b = count;
- i = framenr;
- while (i <= framenr + count) {
- marker = BKE_tracking_marker_get(track, i);
+static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackingTrack *track)
+{
+#define MAX_STATIC_PATH 64
- if (!marker || marker->flag & MARKER_DISABLED) {
- break;
- }
+ const int count = sc->path_length;
+ TrackPathPoint path_static[(MAX_STATIC_PATH + 1) * 2];
+ TrackPathPoint *path;
+ const bool tiny = (sc->flag & SC_SHOW_TINY_MARKER) != 0;
- if (marker->framenr == i) {
- if (marker->framenr == start_frame) {
- curindex = b;
- }
+ if (count == 0) {
+ /* Early output, nothing to bother about here. */
+ return;
+ }
- add_v2_v2v2(path[b++], marker->pos, track->offset);
- ED_clip_point_undistorted_pos(sc, path[b - 1], path[b - 1]);
- }
- else {
- break;
- }
+ /* Try to use stack allocated memory when possibly, only use heap allocation
+ * for really long paths. */
+ path = (count < MAX_STATIC_PATH) ? path_static :
+ MEM_mallocN(sizeof(*path) * (count + 1) * 2, "path");
+ /* Collect path information. */
+ const int num_points_before = track_to_path_segment(sc, track, -1, path);
+ const int num_points_after = track_to_path_segment(sc, track, 1, path);
+ if (num_points_before == 0 && num_points_after == 0) {
+ return;
+ }
- i++;
+ int num_all_points = num_points_before + num_points_after;
+ /* If both leading and trailing parts of the path are there the center point is counted twice. */
+ if (num_points_before != 0 && num_points_after != 0) {
+ num_all_points -= 1;
}
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ const int path_start_index = count - num_points_before + 1;
+ const int path_center_index = count;
+ const uint position_attribute = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ /* Draw path outline. */
if (!tiny) {
immUniformThemeColor(TH_MARKER_OUTLINE);
-
if (TRACK_VIEW_SELECTED(sc, track)) {
- if ((b - a - 1) >= 1) {
- GPU_point_size(5.0f);
-
- immBegin(GPU_PRIM_POINTS, b - a - 1);
-
- for (i = a; i < b; i++) {
- if (i != curindex) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
- }
-
- immEnd();
- }
- }
-
- if ((b - a) >= 2) {
- GPU_line_width(3.0f);
-
- immBegin(GPU_PRIM_LINE_STRIP, b - a);
-
- for (i = a; i < b; i++) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
-
- immEnd();
+ GPU_point_size(5.0f);
+ draw_track_path_points(path, position_attribute, path_start_index, num_all_points);
+ GPU_point_size(7.0f);
+ draw_track_path_keyframe_points(path, position_attribute, path_start_index, num_all_points);
}
+ /* Draw darker outline for actual path, all line segments at once. */
+ GPU_line_width(3.0f);
+ draw_track_path_lines(path, position_attribute, path_start_index, num_all_points);
}
- if (TRACK_VIEW_SELECTED(sc, track)) {
- GPU_point_size(3.0f);
-
- if ((curindex - a) >= 1) {
- immUniformThemeColor(TH_PATH_BEFORE);
-
- immBegin(GPU_PRIM_POINTS, curindex - a);
-
- for (i = a; i < curindex; i++) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
-
- immEnd();
- }
-
- if ((b - curindex - 1) >= 1) {
- immUniformThemeColor(TH_PATH_AFTER);
-
- immBegin(GPU_PRIM_POINTS, b - curindex - 1);
-
- for (i = curindex + 1; i < b; i++) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
-
- immEnd();
- }
- }
+ /* Draw all points. */
+ GPU_point_size(3.0f);
+ immUniformThemeColor(TH_PATH_BEFORE);
+ draw_track_path_points(path, position_attribute, path_start_index, num_points_before);
+ immUniformThemeColor(TH_PATH_AFTER);
+ draw_track_path_points(path, position_attribute, path_center_index, num_points_after);
+ /* Connect points with color coded segments. */
GPU_line_width(1);
+ immUniformThemeColor(TH_PATH_BEFORE);
+ draw_track_path_lines(path, position_attribute, path_start_index, num_points_before);
+ immUniformThemeColor(TH_PATH_AFTER);
+ draw_track_path_lines(path, position_attribute, path_center_index, num_points_after);
+
+ /* Draw all bigger points corresponding to keyframes. */
+ GPU_point_size(5.0f);
+ immUniformThemeColor(TH_PATH_KEYFRAME_BEFORE);
+ draw_track_path_keyframe_points(path, position_attribute, path_start_index, num_points_before);
+ immUniformThemeColor(TH_PATH_KEYFRAME_AFTER);
+ draw_track_path_keyframe_points(path, position_attribute, path_center_index, num_points_after);
- if ((curindex - a + 1) >= 2) {
- immUniformThemeColor(TH_PATH_BEFORE);
-
- immBegin(GPU_PRIM_LINE_STRIP, curindex - a + 1);
-
- for (i = a; i <= curindex; i++) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
-
- immEnd();
- }
-
- if ((b - curindex) >= 2) {
- immUniformThemeColor(TH_PATH_AFTER);
-
- immBegin(GPU_PRIM_LINE_STRIP, b - curindex);
-
- for (i = curindex; i < b; i++) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
-
- immEnd();
+ if (path != path_static) {
+ MEM_freeN(path);
}
immUnbindProgram();
- if (path != path_static) {
- MEM_freeN(path);
- }
#undef MAX_STATIC_PATH
}
@@ -887,7 +895,7 @@ static float get_shortest_pattern_side(MovieTrackingMarker *marker)
}
static void draw_marker_slide_square(
- float x, float y, float dx, float dy, int outline, float px[2], unsigned int pos)
+ float x, float y, float dx, float dy, int outline, const float px[2], unsigned int pos)
{
float tdx, tdy;
@@ -903,7 +911,7 @@ static void draw_marker_slide_square(
}
static void draw_marker_slide_triangle(
- float x, float y, float dx, float dy, int outline, float px[2], unsigned int pos)
+ float x, float y, float dx, float dy, int outline, const float px[2], unsigned int pos)
{
float tdx, tdy;
diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h
index 8599de9f16f..bd54d4f0016 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -94,6 +94,7 @@ void CLIP_OT_view_zoom_out(struct wmOperatorType *ot);
void CLIP_OT_view_zoom_ratio(struct wmOperatorType *ot);
void CLIP_OT_view_all(struct wmOperatorType *ot);
void CLIP_OT_view_selected(struct wmOperatorType *ot);
+void CLIP_OT_view_center_cursor(struct wmOperatorType *ot);
void CLIP_OT_change_frame(wmOperatorType *ot);
void CLIP_OT_rebuild_proxy(struct wmOperatorType *ot);
void CLIP_OT_mode_set(struct wmOperatorType *ot);
@@ -108,6 +109,8 @@ void CLIP_OT_set_scene_frames(wmOperatorType *ot);
void CLIP_OT_cursor_set(struct wmOperatorType *ot);
+void CLIP_OT_lock_selection_toggle(struct wmOperatorType *ot);
+
/* clip_toolbar.c */
struct ARegion *ED_clip_has_properties_region(struct ScrArea *sa);
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index cf899773822..192449a219d 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -78,7 +78,9 @@
#include "clip_intern.h" // own include
-/******************** view navigation utilities *********************/
+/* -------------------------------------------------------------------- */
+/** \name View Navigation Utilities
+ * \{ */
static void sclip_zoom_set(const bContext *C,
float zoom,
@@ -162,7 +164,11 @@ static void sclip_zoom_set_factor_exec(bContext *C, const wmEvent *event, float
ED_region_tag_redraw(ar);
}
-/******************** open clip operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Open Clip Operator
+ * \{ */
static void clip_filesel(bContext *C, wmOperator *op, const char *path)
{
@@ -326,7 +332,11 @@ void CLIP_OT_open(wmOperatorType *ot)
FILE_SORT_ALPHA);
}
-/******************* reload clip operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reload Clip Operator
+ * \{ */
static int reload_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -355,7 +365,11 @@ void CLIP_OT_reload(wmOperatorType *ot)
ot->exec = reload_exec;
}
-/********************** view pan operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Pan Operator
+ * \{ */
typedef struct ViewPanData {
float x, y;
@@ -376,7 +390,7 @@ static void view_pan_init(bContext *C, wmOperator *op, const wmEvent *event)
/* Grab will be set when running from gizmo. */
vpd->own_cursor = (win->grabcursor == 0);
if (vpd->own_cursor) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
vpd->x = event->x;
@@ -510,7 +524,7 @@ void CLIP_OT_view_pan(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY | OPTYPE_LOCK_BYPASS;
/* properties */
RNA_def_float_vector(ot->srna,
@@ -525,7 +539,11 @@ void CLIP_OT_view_pan(wmOperatorType *ot)
FLT_MAX);
}
-/********************** view zoom operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom Operator
+ * \{ */
typedef struct ViewZoomData {
float x, y;
@@ -549,7 +567,7 @@ static void view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event)
/* Grab will be set when running from gizmo. */
vpd->own_cursor = (win->grabcursor == 0);
if (vpd->own_cursor) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
if (U.viewzoom == USER_ZOOM_CONT) {
@@ -712,7 +730,7 @@ void CLIP_OT_view_zoom(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY | OPTYPE_LOCK_BYPASS;
/* properties */
prop = RNA_def_float(ot->srna,
@@ -729,7 +747,11 @@ void CLIP_OT_view_zoom(wmOperatorType *ot)
WM_operator_properties_use_cursor_init(ot);
}
-/********************** view zoom in/out operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom In/Out Operator
+ * \{ */
static int view_zoom_in_exec(bContext *C, wmOperator *op)
{
@@ -771,6 +793,9 @@ void CLIP_OT_view_zoom_in(wmOperatorType *ot)
ot->invoke = view_zoom_in_invoke;
ot->poll = ED_space_clip_view_clip_poll;
+ /* flags */
+ ot->flag |= OPTYPE_LOCK_BYPASS;
+
/* properties */
prop = RNA_def_float_vector(ot->srna,
"location",
@@ -825,6 +850,9 @@ void CLIP_OT_view_zoom_out(wmOperatorType *ot)
ot->invoke = view_zoom_out_invoke;
ot->poll = ED_space_clip_view_clip_poll;
+ /* flags */
+ ot->flag |= OPTYPE_LOCK_BYPASS;
+
/* properties */
prop = RNA_def_float_vector(ot->srna,
"location",
@@ -839,7 +867,11 @@ void CLIP_OT_view_zoom_out(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
-/********************** view zoom ratio operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom Ratio Operator
+ * \{ */
static int view_zoom_ratio_exec(bContext *C, wmOperator *op)
{
@@ -867,6 +899,9 @@ void CLIP_OT_view_zoom_ratio(wmOperatorType *ot)
ot->exec = view_zoom_ratio_exec;
ot->poll = ED_space_clip_view_clip_poll;
+ /* flags */
+ ot->flag |= OPTYPE_LOCK_BYPASS;
+
/* properties */
RNA_def_float(ot->srna,
"ratio",
@@ -878,8 +913,11 @@ void CLIP_OT_view_zoom_ratio(wmOperatorType *ot)
-FLT_MAX,
FLT_MAX);
}
+/** \} */
-/********************** view all operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name View All Operator
+ * \{ */
static int view_all_exec(bContext *C, wmOperator *op)
{
@@ -945,12 +983,48 @@ void CLIP_OT_view_all(wmOperatorType *ot)
ot->exec = view_all_exec;
ot->poll = ED_space_clip_view_clip_poll;
+ /* flags */
+ ot->flag = OPTYPE_LOCK_BYPASS;
+
/* properties */
prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Center View To Cursor Operator
+ * \{ */
+
+static int view_center_cursor_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ clip_view_center_to_point(sc, sc->cursor[0], sc->cursor[1]);
+
+ ED_region_tag_redraw(ar);
+
+ return OPERATOR_FINISHED;
+}
-/********************** view selected operator *********************/
+void CLIP_OT_view_center_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Center View to Cursor";
+ ot->description = "Center the view so that the cursor is in the middle of the view";
+ ot->idname = "CLIP_OT_view_center_cursor";
+
+ /* api callbacks */
+ ot->exec = view_center_cursor_exec;
+ ot->poll = ED_space_clip_maskedit_poll;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Selected Operator
+ * \{ */
static int view_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -976,9 +1050,15 @@ void CLIP_OT_view_selected(wmOperatorType *ot)
/* api callbacks */
ot->exec = view_selected_exec;
ot->poll = ED_space_clip_view_clip_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_LOCK_BYPASS;
}
+/** \} */
-/********************** change frame operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name Change Frame Operator
+ * \{ */
static bool change_frame_poll(bContext *C)
{
@@ -1094,8 +1174,11 @@ void CLIP_OT_change_frame(wmOperatorType *ot)
/* rna */
RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
}
+/** \} */
-/********************** rebuild proxies operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name Rebuild Proxies Operator
+ * \{ */
typedef struct ProxyBuildJob {
Scene *scene;
@@ -1116,7 +1199,7 @@ static void proxy_freejob(void *pjv)
static int proxy_bitflag_to_array(int size_flag, int build_sizes[4], int undistort)
{
int build_count = 0;
- int size_flags[2][4] = {
+ const int size_flags[2][4] = {
{MCLIP_PROXY_SIZE_25, MCLIP_PROXY_SIZE_50, MCLIP_PROXY_SIZE_75, MCLIP_PROXY_SIZE_100},
{MCLIP_PROXY_UNDISTORTED_SIZE_25,
MCLIP_PROXY_UNDISTORTED_SIZE_50,
@@ -1506,8 +1589,11 @@ void CLIP_OT_rebuild_proxy(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER;
}
+/** \} */
-/********************** mode set operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name Mode Set Operator
+ * \{ */
static int mode_set_exec(bContext *C, wmOperator *op)
{
@@ -1543,7 +1629,12 @@ void CLIP_OT_mode_set(wmOperatorType *ot)
}
#ifdef WITH_INPUT_NDOF
-/********************** NDOF operator *********************/
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NDOF Operator
+ * \{ */
/* Combined pan/zoom from a 3D mouse device.
* Z zooms, XY pans
@@ -1589,10 +1680,18 @@ void CLIP_OT_view_ndof(wmOperatorType *ot)
/* api callbacks */
ot->invoke = clip_view_ndof_invoke;
ot->poll = ED_space_clip_view_clip_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_LOCK_BYPASS;
}
+
+/** \} */
+
#endif /* WITH_INPUT_NDOF */
-/********************** Prefetch operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name Prefetch Operator
+ * \{ */
static int clip_prefetch_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
@@ -1632,8 +1731,11 @@ void CLIP_OT_prefetch(wmOperatorType *ot)
ot->invoke = clip_prefetch_invoke;
ot->modal = clip_prefetch_modal;
}
+/** \} */
-/********************** Set scene frames *********************/
+/* -------------------------------------------------------------------- */
+/** \name Set Scene Frames Operator
+ * \{ */
static int clip_set_scene_frames_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -1668,8 +1770,11 @@ void CLIP_OT_set_scene_frames(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
ot->exec = clip_set_scene_frames_exec;
}
+/** \} */
-/******************** set 3d cursor operator ********************/
+/* -------------------------------------------------------------------- */
+/** \name Set 3d Cursor Operator
+ * \{ */
static int clip_set_2d_cursor_exec(bContext *C, wmOperator *op)
{
@@ -1730,7 +1835,40 @@ void CLIP_OT_cursor_set(wmOperatorType *ot)
10.0f);
}
-/********************** macros *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Lock To Selection Operator
+ * \{ */
+
+static int lock_selection_togglee_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+ space_clip->flag ^= SC_LOCK_SELECTION;
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CLIP, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_lock_selection_toggle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Toggle Lock Selection";
+ ot->description = "Toggle Lock Selection option of the current clip editor";
+ ot->idname = "CLIP_OT_lock_selection_toggle";
+
+ /* api callbacks */
+ ot->poll = ED_space_clip_poll;
+ ot->exec = lock_selection_togglee_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_LOCK_BYPASS;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Macros
+ * \{ */
void ED_operatormacros_clip(void)
{
@@ -1754,3 +1892,5 @@ void ED_operatormacros_clip(void)
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_boolean_set(otmacro->ptr, "release_confirm", true);
}
+
+/** \} */
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index 48f788e2e3a..902229c0bba 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -38,7 +38,6 @@
#include "DEG_depsgraph_build.h"
#include "GPU_immediate.h"
-#include "GPU_matrix.h"
#include "GPU_state.h"
#include "WM_api.h"
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index c1cb975447f..16305a9b17b 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -443,6 +443,7 @@ static void clip_operatortypes(void)
WM_operatortype_append(CLIP_OT_view_zoom_ratio);
WM_operatortype_append(CLIP_OT_view_all);
WM_operatortype_append(CLIP_OT_view_selected);
+ WM_operatortype_append(CLIP_OT_view_center_cursor);
WM_operatortype_append(CLIP_OT_change_frame);
WM_operatortype_append(CLIP_OT_rebuild_proxy);
WM_operatortype_append(CLIP_OT_mode_set);
@@ -452,6 +453,7 @@ static void clip_operatortypes(void)
WM_operatortype_append(CLIP_OT_prefetch);
WM_operatortype_append(CLIP_OT_set_scene_frames);
WM_operatortype_append(CLIP_OT_cursor_set);
+ WM_operatortype_append(CLIP_OT_lock_selection_toggle);
/* ** tracking_ops.c ** */
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index 1375b99bdaa..f1bce00ea0b 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -448,8 +448,8 @@ static float mouse_to_slide_zone_distance_squared(const float co[2],
int width,
int height)
{
- float pixel_co[2] = {co[0] * width, co[1] * height},
- pixel_slide_zone[2] = {slide_zone[0] * width, slide_zone[1] * height};
+ const float pixel_co[2] = {co[0] * width, co[1] * height},
+ pixel_slide_zone[2] = {slide_zone[0] * width, slide_zone[1] * height};
return SQUARE(pixel_co[0] - pixel_slide_zone[0]) + SQUARE(pixel_co[1] - pixel_slide_zone[1]);
}
@@ -2090,7 +2090,7 @@ static int keyframe_insert_exec(bContext *C, wmOperator *UNUSED(op))
void CLIP_OT_keyframe_insert(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Insert keyframe";
+ ot->name = "Insert Keyframe";
ot->description = "Insert a keyframe to selected tracks at current frame";
ot->idname = "CLIP_OT_keyframe_insert";
@@ -2113,7 +2113,7 @@ static int keyframe_delete_exec(bContext *C, wmOperator *UNUSED(op))
void CLIP_OT_keyframe_delete(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Delete keyframe";
+ ot->name = "Delete Keyframe";
ot->description = "Delete a keyframe from selected tracks at current frame";
ot->idname = "CLIP_OT_keyframe_delete";
diff --git a/source/blender/editors/space_clip/tracking_ops_plane.c b/source/blender/editors/space_clip/tracking_ops_plane.c
index b1bf88634bc..7d2324d3f48 100644
--- a/source/blender/editors/space_clip/tracking_ops_plane.c
+++ b/source/blender/editors/space_clip/tracking_ops_plane.c
@@ -115,8 +115,8 @@ static float mouse_to_plane_slide_zone_distance_squared(const float co[2],
int width,
int height)
{
- float pixel_co[2] = {co[0] * width, co[1] * height},
- pixel_slide_zone[2] = {slide_zone[0] * width, slide_zone[1] * height};
+ const float pixel_co[2] = {co[0] * width, co[1] * height},
+ pixel_slide_zone[2] = {slide_zone[0] * width, slide_zone[1] * height};
return SQUARE(pixel_co[0] - pixel_slide_zone[0]) + SQUARE(pixel_co[1] - pixel_slide_zone[1]);
}
diff --git a/source/blender/editors/space_clip/tracking_ops_solve.c b/source/blender/editors/space_clip/tracking_ops_solve.c
index 96b00ec5463..1d2fc239a89 100644
--- a/source/blender/editors/space_clip/tracking_ops_solve.c
+++ b/source/blender/editors/space_clip/tracking_ops_solve.c
@@ -50,6 +50,7 @@
/********************** solve camera operator *********************/
typedef struct {
+ struct wmWindowManager *wm;
Scene *scene;
MovieClip *clip;
MovieClipUser user;
@@ -78,6 +79,7 @@ static bool solve_camera_initjob(
/* Could fail if footage uses images with different sizes. */
BKE_movieclip_get_size(clip, &sc->user, &width, &height);
+ scj->wm = CTX_wm_manager(C);
scj->clip = clip;
scj->scene = scene;
scj->reports = op->reports;
@@ -88,6 +90,8 @@ static bool solve_camera_initjob(
tracking->stats = MEM_callocN(sizeof(MovieTrackingStats), "solve camera stats");
+ WM_set_locked_interface(scj->wm, true);
+
return true;
}
@@ -114,6 +118,8 @@ static void solve_camera_freejob(void *scv)
MovieClip *clip = scj->clip;
int solved;
+ WM_set_locked_interface(scj->wm, false);
+
if (!scj->context) {
/* job weren't fully initialized due to some error */
MEM_freeN(scj);
diff --git a/source/blender/editors/space_clip/tracking_ops_track.c b/source/blender/editors/space_clip/tracking_ops_track.c
index 9536c64c415..adbb3e30850 100644
--- a/source/blender/editors/space_clip/tracking_ops_track.c
+++ b/source/blender/editors/space_clip/tracking_ops_track.c
@@ -59,6 +59,7 @@ typedef struct TrackMarkersJob {
float delay; /* Delay in milliseconds to allow
* tracking at fixed FPS */
+ struct wmWindowManager *wm;
struct Main *main;
struct Scene *scene;
struct bScreen *screen;
@@ -127,7 +128,7 @@ static bool track_markers_check_direction(int backwards, int curfra, int efra)
return true;
}
-static int track_markers_initjob(bContext *C, TrackMarkersJob *tmj, bool backwards, bool sequence)
+static bool track_markers_initjob(bContext *C, TrackMarkersJob *tmj, bool backwards, bool sequence)
{
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -202,7 +203,15 @@ static int track_markers_initjob(bContext *C, TrackMarkersJob *tmj, bool backwar
tmj->main = CTX_data_main(C);
tmj->screen = CTX_wm_screen(C);
- return track_markers_check_direction(backwards, tmj->sfra, tmj->efra);
+ tmj->wm = CTX_wm_manager(C);
+
+ if (!track_markers_check_direction(backwards, tmj->sfra, tmj->efra)) {
+ return false;
+ }
+
+ WM_set_locked_interface(tmj->wm, true);
+
+ return true;
}
static void track_markers_startjob(void *tmv, short *stop, short *do_update, float *progress)
@@ -281,6 +290,7 @@ static void track_markers_freejob(void *tmv)
{
TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
tmj->clip->tracking_context = NULL;
+ WM_set_locked_interface(tmj->wm, false);
BKE_autotrack_context_free(tmj->context);
MEM_freeN(tmj);
}
diff --git a/source/blender/editors/space_clip/tracking_ops_utils.c b/source/blender/editors/space_clip/tracking_ops_utils.c
index 3970f1381bf..7579c9a49c6 100644
--- a/source/blender/editors/space_clip/tracking_ops_utils.c
+++ b/source/blender/editors/space_clip/tracking_ops_utils.c
@@ -57,11 +57,11 @@ void clip_tracking_clear_invisible_track_selection(SpaceClip *sc, MovieClip *cli
void clip_tracking_hide_cursor(bContext *C)
{
wmWindow *win = CTX_wm_window(C);
- WM_cursor_set(win, CURSOR_NONE);
+ WM_cursor_set(win, WM_CURSOR_NONE);
}
void clip_tracking_show_cursor(bContext *C)
{
wmWindow *win = CTX_wm_window(C);
- WM_cursor_set(win, CURSOR_STD);
+ WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index 4532b61f291..f6063b49005 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -57,7 +57,7 @@ static float dist_to_crns(float co[2], float pos[2], float crns[4][2]);
/********************** mouse select operator *********************/
static int mouse_on_side(
- float co[2], float x1, float y1, float x2, float y2, float epsx, float epsy)
+ const float co[2], float x1, float y1, float x2, float y2, float epsx, float epsy)
{
if (x1 > x2) {
SWAP(float, x1, x2);
@@ -71,7 +71,7 @@ static int mouse_on_side(
}
static int mouse_on_rect(
- float co[2], float pos[2], float min[2], float max[2], float epsx, float epsy)
+ const float co[2], float pos[2], float min[2], float max[2], float epsx, float epsy)
{
return mouse_on_side(
co, pos[0] + min[0], pos[1] + min[1], pos[0] + max[0], pos[1] + min[1], epsx, epsy) ||
diff --git a/source/blender/editors/space_console/console_ops.c b/source/blender/editors/space_console/console_ops.c
index faf613482a3..bc18a6cfb56 100644
--- a/source/blender/editors/space_console/console_ops.c
+++ b/source/blender/editors/space_console/console_ops.c
@@ -1082,7 +1082,7 @@ typedef struct SetConsoleCursor {
// TODO, cursor placement without selection
static void console_cursor_set_to_pos(
- SpaceConsole *sc, ARegion *ar, SetConsoleCursor *scu, int mval[2], int UNUSED(sel))
+ SpaceConsole *sc, ARegion *ar, SetConsoleCursor *scu, const int mval[2], int UNUSED(sel))
{
int pos;
pos = console_char_pick(sc, ar, mval);
diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c
index 999255aef88..5cc2f00413a 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -26,6 +26,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BKE_global.h"
#include "BKE_context.h"
#include "BKE_screen.h"
@@ -148,11 +149,11 @@ static void console_main_region_init(wmWindowManager *wm, ARegion *ar)
static void console_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
{
SpaceText *st = sa->spacedata.first;
- int wmcursor = BC_TEXTEDITCURSOR;
+ int wmcursor = WM_CURSOR_TEXT_EDIT;
if (st->text &&
BLI_rcti_isect_pt(&st->txtbar, win->eventstate->x - ar->winrct.xmin, st->txtbar.ymin)) {
- wmcursor = CURSOR_STD;
+ wmcursor = WM_CURSOR_DEFAULT;
}
WM_cursor_set(win, wmcursor);
@@ -173,7 +174,7 @@ static void id_drop_copy(wmDrag *drag, wmDropBox *drop)
ID *id = WM_drag_ID(drag, 0);
/* copy drag path to properties */
- char *text = RNA_path_full_ID_py(id);
+ char *text = RNA_path_full_ID_py(G_MAIN, id);
RNA_string_set(drop->ptr, "text", text);
MEM_freeN(text);
}
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 3a6d59c1dbf..0aec6d5e6a0 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -26,6 +26,7 @@
#include <errno.h>
#include "BLI_blenlib.h"
+#include "BLI_fileops_types.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
@@ -70,239 +71,57 @@
#include "file_intern.h" // own include
-/* Dummy helper - we need dynamic tooltips here. */
-static char *file_draw_tooltip_func(bContext *UNUSED(C), void *argN, const char *UNUSED(tip))
+void ED_file_path_button(bScreen *screen,
+ const SpaceFile *sfile,
+ FileSelectParams *params,
+ uiBlock *block)
{
- char *dyn_tooltip = argN;
- return BLI_strdup(dyn_tooltip);
-}
-
-/* Note: This function uses pixelspace (0, 0, winx, winy), not view2d.
- * The controls are laid out as follows:
- *
- * -------------------------------------------
- * | Directory input | execute |
- * -------------------------------------------
- * | Filename input | + | - | cancel |
- * -------------------------------------------
- *
- * The input widgets will stretch to fill any excess space.
- * When there isn't enough space for all controls to be shown, they are
- * hidden in this order: x/-, execute/cancel, input widgets.
- */
-void file_draw_buttons(const bContext *C, ARegion *ar)
-{
- /* Button layout. */
- const int max_x = ar->winx - 10;
- const int line1_y = ar->winy - (IMASEL_BUTTONS_HEIGHT / 2 + IMASEL_BUTTONS_MARGIN);
- const int line2_y = line1_y - (IMASEL_BUTTONS_HEIGHT / 2 + IMASEL_BUTTONS_MARGIN);
- const int input_minw = 20;
- const int btn_h = UI_UNIT_Y;
- const int btn_fn_w = UI_UNIT_X;
- const int btn_minw = 80;
- const int btn_margin = 20;
- const int separator = 4;
-
- /* Additional locals. */
- char uiblockstr[32];
- int loadbutton;
- int fnumbuttons;
- int min_x = 10;
- int chan_offs = 0;
- int available_w = max_x - min_x;
- int line1_w = available_w;
- int line2_w = available_w;
-
+ PointerRNA params_rna_ptr;
uiBut *but;
- uiBlock *block;
- SpaceFile *sfile = CTX_wm_space_file(C);
- FileSelectParams *params = ED_fileselect_get_params(sfile);
- ARegion *artmp;
- const bool is_browse_only = (sfile->op == NULL);
-
- /* Initialize UI block. */
- BLI_snprintf(uiblockstr, sizeof(uiblockstr), "win %p", (void *)ar);
- block = UI_block_begin(C, ar, uiblockstr, UI_EMBOSS);
-
- /* exception to make space for collapsed region icon */
- for (artmp = CTX_wm_area(C)->regionbase.first; artmp; artmp = artmp->next) {
- if (artmp->regiontype == RGN_TYPE_TOOLS && artmp->flag & RGN_FLAG_HIDDEN) {
- chan_offs = 16;
- min_x += chan_offs;
- available_w -= chan_offs;
- }
- }
-
- /* Is there enough space for the execute / cancel buttons? */
- if (is_browse_only) {
- loadbutton = 0;
- }
- else {
- const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
- loadbutton = UI_fontstyle_string_width(fstyle, params->title) + btn_margin;
- CLAMP_MIN(loadbutton, btn_minw);
- if (available_w <= loadbutton + separator + input_minw) {
- loadbutton = 0;
- }
+ RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, &params_rna_ptr);
+
+ /* callbacks for operator check functions */
+ UI_block_func_set(block, file_draw_check_cb, NULL, NULL);
+
+ but = uiDefButR(block,
+ UI_BTYPE_TEXT,
+ -1,
+ "",
+ 0,
+ 0,
+ UI_UNIT_X * 10,
+ UI_UNIT_Y,
+ &params_rna_ptr,
+ "directory",
+ 0,
+ 0.0f,
+ (float)FILE_MAX,
+ 0.0f,
+ 0.0f,
+ TIP_("File path"));
+
+ BLI_assert(!UI_but_flag_is_set(but, UI_BUT_UNDO));
+ BLI_assert(!UI_but_is_utf8(but));
+
+ UI_but_func_complete_set(but, autocomplete_directory, NULL);
+ UI_but_funcN_set(but, file_directory_enter_handle, NULL, but);
+
+ /* TODO, directory editing is non-functional while a library is loaded
+ * until this is properly supported just disable it. */
+ if (sfile && sfile->files && filelist_lib(sfile->files)) {
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
}
- if (loadbutton) {
- line1_w -= (loadbutton + separator);
- line2_w = line1_w;
- }
-
- /* Is there enough space for file number increment/decrement buttons? */
- fnumbuttons = 2 * btn_fn_w;
- if (!loadbutton || line2_w <= fnumbuttons + separator + input_minw) {
- fnumbuttons = 0;
- }
- else {
- line2_w -= (fnumbuttons + separator);
- }
-
- /* Text input fields for directory and file. */
- if (available_w > 0) {
- const struct FileDirEntry *file = sfile->files ?
- filelist_file(sfile->files, params->active_file) :
- NULL;
- int overwrite_alert = file_draw_check_exists(sfile);
- const bool is_active_dir = file && (file->typeflag & FILE_TYPE_FOLDER);
-
- /* callbacks for operator check functions */
- UI_block_func_set(block, file_draw_check_cb, NULL, NULL);
-
- but = uiDefBut(block,
- UI_BTYPE_TEXT,
- -1,
- "",
- min_x,
- line1_y,
- line1_w - chan_offs,
- btn_h,
- params->dir,
- 0.0,
- (float)FILE_MAX,
- 0,
- 0,
- TIP_("File path"));
- UI_but_func_complete_set(but, autocomplete_directory, NULL);
- UI_but_flag_enable(but, UI_BUT_NO_UTF8);
- UI_but_flag_disable(but, UI_BUT_UNDO);
- UI_but_funcN_set(but, file_directory_enter_handle, NULL, but);
-
- /* TODO, directory editing is non-functional while a library is loaded
- * until this is properly supported just disable it. */
- if (sfile->files && filelist_lib(sfile->files)) {
- UI_but_flag_enable(but, UI_BUT_DISABLED);
- }
-
- if ((params->flag & FILE_DIRSEL_ONLY) == 0) {
- but = uiDefBut(
- block,
- UI_BTYPE_TEXT,
- -1,
- "",
- min_x,
- line2_y,
- line2_w - chan_offs,
- btn_h,
- is_active_dir ? (char *)"" : params->file,
- 0.0,
- (float)FILE_MAXFILE,
- 0,
- 0,
- TIP_(overwrite_alert ? N_("File name, overwrite existing") : N_("File name")));
- UI_but_func_complete_set(but, autocomplete_file, NULL);
- UI_but_flag_enable(but, UI_BUT_NO_UTF8);
- UI_but_flag_disable(but, UI_BUT_UNDO);
- /* silly workaround calling NFunc to ensure this does not get called
- * immediate ui_apply_but_func but only after button deactivates */
- UI_but_funcN_set(but, file_filename_enter_handle, NULL, but);
-
- /* check if this overrides a file and if the operator option is used */
- if (overwrite_alert) {
- UI_but_flag_enable(but, UI_BUT_REDALERT);
- }
- }
-
- /* clear func */
- UI_block_func_set(block, NULL, NULL, NULL);
- }
-
- /* Filename number increment / decrement buttons. */
- if (fnumbuttons && (params->flag & FILE_DIRSEL_ONLY) == 0) {
- UI_block_align_begin(block);
- but = uiDefIconButO(block,
- UI_BTYPE_BUT,
- "FILE_OT_filenum",
- 0,
- ICON_REMOVE,
- min_x + line2_w + separator - chan_offs,
- line2_y,
- btn_fn_w,
- btn_h,
- TIP_("Decrement the filename number"));
- RNA_int_set(UI_but_operator_ptr_get(but), "increment", -1);
-
- but = uiDefIconButO(block,
- UI_BTYPE_BUT,
- "FILE_OT_filenum",
- 0,
- ICON_ADD,
- min_x + line2_w + separator + btn_fn_w - chan_offs,
- line2_y,
- btn_fn_w,
- btn_h,
- TIP_("Increment the filename number"));
- RNA_int_set(UI_but_operator_ptr_get(but), "increment", 1);
- UI_block_align_end(block);
- }
-
- /* Execute / cancel buttons. */
- if (loadbutton) {
- const struct FileDirEntry *file = sfile->files ?
- filelist_file(sfile->files, params->active_file) :
- NULL;
- char const *str_exec;
-
- if (file && FILENAME_IS_PARENT(file->relpath)) {
- str_exec = IFACE_("Parent Directory");
- }
- else if (file && file->typeflag & FILE_TYPE_DIR) {
- str_exec = IFACE_("Open Directory");
- }
- else {
- str_exec = params->title; /* params->title is already translated! */
- }
-
- but = uiDefButO(block,
- UI_BTYPE_BUT,
- "FILE_OT_execute",
- WM_OP_EXEC_REGION_WIN,
- str_exec,
- max_x - loadbutton,
- line1_y,
- loadbutton,
- btn_h,
- "");
- /* Just a display hint. */
- UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT);
-
- uiDefButO(block,
- UI_BTYPE_BUT,
- "FILE_OT_cancel",
- WM_OP_EXEC_REGION_WIN,
- IFACE_("Cancel"),
- max_x - loadbutton,
- line2_y,
- loadbutton,
- btn_h,
- "");
- }
+ /* clear func */
+ UI_block_func_set(block, NULL, NULL, NULL);
+}
- UI_block_end(C, block);
- UI_block_draw(C, block);
+/* Dummy helper - we need dynamic tooltips here. */
+static char *file_draw_tooltip_func(bContext *UNUSED(C), void *argN, const char *UNUSED(tip))
+{
+ char *dyn_tooltip = argN;
+ return BLI_strdup(dyn_tooltip);
}
static void draw_tile(int sx, int sy, int width, int height, int colorid, int shade)
@@ -319,13 +138,10 @@ static void file_draw_icon(
{
uiBut *but;
int x, y;
- // float alpha = 1.0f;
x = sx;
y = sy - height;
- /*if (icon == ICON_FILE_BLANK) alpha = 0.375f;*/
-
but = uiDefIconBut(
block, UI_BTYPE_LABEL, 0, icon, x, y, width, height, NULL, 0.0f, 0.0f, 0.0f, 0.0f, NULL);
UI_but_func_tooltip_set(but, file_draw_tooltip_func, BLI_strdup(path));
@@ -349,7 +165,7 @@ static void file_draw_string(int sx,
rcti rect;
char fname[FILE_MAXFILE];
- if (string[0] == '\0') {
+ if (string[0] == '\0' || width < 1) {
return;
}
@@ -362,7 +178,7 @@ static void file_draw_string(int sx,
/* no text clipping needed, UI_fontstyle_draw does it but is a bit too strict
* (for buttons it works) */
rect.xmin = sx;
- rect.xmax = (int)(sx + ceil(width + 5.0f / UI_DPI_FAC));
+ rect.xmax = sx + round_fl_to_int(width);
rect.ymin = sy - height;
rect.ymax = sy;
@@ -404,8 +220,8 @@ static void file_draw_preview(uiBlock *block,
float scaledx, scaledy;
float scale;
int ex, ey;
- bool use_dropshadow = !is_icon && (typeflags & FILE_TYPE_IMAGE);
- float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ bool show_outline = !is_icon &&
+ (typeflags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_BLENDER));
BLI_assert(imb != NULL);
@@ -440,15 +256,20 @@ static void file_draw_preview(uiBlock *block,
xco = sx + (int)dx;
yco = sy - layout->prv_h + (int)dy;
- /* shadow */
- if (use_dropshadow) {
- UI_draw_box_shadow(220, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey));
- }
-
GPU_blend(true);
- /* the image */
- if (!is_icon && typeflags & FILE_TYPE_FTFONT) {
+ /* the large image */
+
+ float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ if (is_icon) {
+ if (typeflags & FILE_TYPE_DIR) {
+ UI_GetThemeColor4fv(TH_ICON_FOLDER, col);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_TEXT, col);
+ }
+ }
+ else if (typeflags & FILE_TYPE_FTFONT) {
UI_GetThemeColor4fv(TH_TEXT, col);
}
@@ -477,30 +298,58 @@ static void file_draw_preview(uiBlock *block,
GPU_blend_set_func_separate(
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- if (icon) {
- UI_icon_draw_ex((float)xco + (7 * UI_DPI_FAC),
- (float)yco + (7 * UI_DPI_FAC),
- icon,
- icon_aspect,
- 1.0f,
- 0.0f,
- NULL,
- false);
+ if (icon && (icon != ICON_FILE_FONT)) {
+ /* size of center icon is scaled to fit container and UI scale */
+ float icon_x, icon_y;
+
+ if (is_icon) {
+ const float icon_size = 16.0f / icon_aspect * U.dpi_fac;
+ float icon_opacity = 0.3f;
+ uchar icon_color[4] = {0, 0, 0, 255};
+ float bgcolor[4];
+ UI_GetThemeColor4fv(TH_ICON_FOLDER, bgcolor);
+ if (rgb_to_grayscale(bgcolor) < 0.5f) {
+ icon_color[0] = 255;
+ icon_color[1] = 255;
+ icon_color[2] = 255;
+ }
+ icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f);
+ icon_y = yco + (ey / 2.0f) - (icon_size * ((typeflags & FILE_TYPE_DIR) ? 0.78f : 0.75f));
+ UI_icon_draw_ex(
+ icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false);
+ }
+ else {
+ const uchar dark[4] = {0, 0, 0, 255};
+ const uchar light[4] = {255, 255, 255, 255};
+
+ /* Smaller, fainter icon for preview image thumbnail. */
+ icon_x = xco + (2.0f * UI_DPI_FAC);
+ icon_y = yco + (2.0f * UI_DPI_FAC);
+
+ UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false);
+ UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
+ }
}
- /* border */
- if (use_dropshadow) {
+ /* Contrasting outline around some preview types. */
+ if (show_outline) {
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
+ float border_color[4] = {1.0f, 1.0f, 1.0f, 0.4f};
+ float bgcolor[4];
+ UI_GetThemeColor4fv(TH_BACK, bgcolor);
+ if (rgb_to_grayscale(bgcolor) > 0.5f) {
+ border_color[0] = 0.0f;
+ border_color[1] = 0.0f;
+ border_color[2] = 0.0f;
+ }
+ immUniformColor4fv(border_color);
imm_draw_box_wire_2d(pos, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey));
immUnbindProgram();
}
but = uiDefBut(block, UI_BTYPE_LABEL, 0, "", xco, yco, ex, ey, NULL, 0.0, 0.0, 0, 0, NULL);
- UI_but_func_tooltip_set(but, file_draw_tooltip_func, BLI_strdup(path));
/* dragregion */
if (drag) {
@@ -557,6 +406,7 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
static void draw_background(FileLayout *layout, View2D *v2d)
{
+ const int item_height = layout->tile_h + (2 * layout->tile_border_y);
int i;
int sy;
@@ -565,9 +415,11 @@ static void draw_background(FileLayout *layout, View2D *v2d)
immUniformThemeColorShade(TH_BACK, -7);
/* alternating flat shade background */
- for (i = 0; (i <= layout->rows); i += 2) {
- sy = (int)v2d->cur.ymax - i * (layout->tile_h + 2 * layout->tile_border_y) -
- layout->tile_border_y;
+ for (i = 2; (i <= layout->rows + 1); i += 2) {
+ sy = (int)v2d->cur.ymax - layout->offset_top - i * item_height - layout->tile_border_y;
+
+ /* Offsett pattern slightly to add scroll effect. */
+ sy += round_fl_to_int(item_height * (v2d->tot.ymax - v2d->cur.ymax) / item_height);
immRectf(pos,
v2d->cur.xmin,
@@ -632,6 +484,176 @@ static void draw_dividers(FileLayout *layout, View2D *v2d)
}
}
+static void draw_columnheader_background(const FileLayout *layout, const View2D *v2d)
+{
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShade(TH_BACK, 11);
+
+ immRectf(pos,
+ v2d->cur.xmin,
+ v2d->cur.ymax - layout->attribute_column_header_h,
+ v2d->cur.xmax,
+ v2d->cur.ymax);
+
+ immUnbindProgram();
+}
+
+static void draw_columnheader_columns(const FileSelectParams *params,
+ FileLayout *layout,
+ const View2D *v2d,
+ const uchar text_col[4])
+{
+ const float divider_pad = 0.2 * layout->attribute_column_header_h;
+ int sx = v2d->cur.xmin, sy = v2d->cur.ymax;
+
+ for (FileAttributeColumnType column_type = 0; column_type < ATTRIBUTE_COLUMN_MAX;
+ column_type++) {
+ if (!file_attribute_column_type_enabled(params, column_type)) {
+ continue;
+ }
+ const FileAttributeColumn *column = &layout->attribute_columns[column_type];
+
+ /* Active sort type triangle */
+ if (params->sort == column->sort_type) {
+ float tri_color[4];
+
+ rgba_uchar_to_float(tri_color, text_col);
+ UI_draw_icon_tri(sx + column->width - (0.3f * U.widget_unit) -
+ ATTRIBUTE_COLUMN_PADDING / 2.0f,
+ sy + (0.1f * U.widget_unit) - (layout->attribute_column_header_h / 2),
+ (params->flag & FILE_SORT_INVERT) ? 't' : 'v',
+ tri_color);
+ }
+
+ file_draw_string(sx + ATTRIBUTE_COLUMN_PADDING,
+ sy - layout->tile_border_y,
+ IFACE_(column->name),
+ column->width - 2 * ATTRIBUTE_COLUMN_PADDING,
+ layout->attribute_column_header_h - layout->tile_border_y,
+ UI_STYLE_TEXT_LEFT,
+ text_col);
+
+ /* Separator line */
+ if (column_type != COLUMN_NAME) {
+ uint pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShade(TH_BACK, -10);
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, sx - 1, sy - divider_pad);
+ immVertex2f(pos, sx - 1, sy - layout->attribute_column_header_h + divider_pad);
+ immEnd();
+ immUnbindProgram();
+ }
+
+ sx += column->width;
+ }
+
+ /* Vertical separator lines line */
+ {
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShade(TH_BACK, -10);
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex2f(pos, v2d->cur.xmin, sy);
+ immVertex2f(pos, v2d->cur.xmax, sy);
+ immVertex2f(pos, v2d->cur.xmin, sy - layout->attribute_column_header_h);
+ immVertex2f(pos, v2d->cur.xmax, sy - layout->attribute_column_header_h);
+ immEnd();
+ immUnbindProgram();
+ }
+}
+
+/**
+ * Updates the stat string stored in file->entry if necessary.
+ */
+static const char *filelist_get_details_column_string(FileAttributeColumnType column,
+ const FileDirEntry *file,
+ const bool small_size,
+ const bool update_stat_strings)
+{
+ switch (column) {
+ case COLUMN_DATETIME:
+ if (!(file->typeflag & FILE_TYPE_BLENDERLIB) && !FILENAME_IS_CURRPAR(file->relpath)) {
+ if ((file->entry->datetime_str[0] == '\0') || update_stat_strings) {
+ char date[FILELIST_DIRENTRY_DATE_LEN], time[FILELIST_DIRENTRY_TIME_LEN];
+ bool is_today, is_yesterday;
+
+ BLI_filelist_entry_datetime_to_string(
+ NULL, file->entry->time, small_size, time, date, &is_today, &is_yesterday);
+
+ if (is_today || is_yesterday) {
+ BLI_strncpy(date, is_today ? N_("Today") : N_("Yesterday"), sizeof(date));
+ }
+ BLI_snprintf(
+ file->entry->datetime_str, sizeof(file->entry->datetime_str), "%s %s", date, time);
+ }
+
+ return file->entry->datetime_str;
+ }
+ break;
+ case COLUMN_SIZE:
+ if ((file->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) ||
+ !(file->typeflag & (FILE_TYPE_DIR | FILE_TYPE_BLENDERLIB))) {
+ if ((file->entry->size_str[0] == '\0') || update_stat_strings) {
+ BLI_filelist_entry_size_to_string(
+ NULL, file->entry->size, small_size, file->entry->size_str);
+ }
+
+ return file->entry->size_str;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static void draw_details_columns(const FileSelectParams *params,
+ const FileLayout *layout,
+ const FileDirEntry *file,
+ const int pos_x,
+ const int pos_y,
+ const uchar text_col[4])
+{
+ const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size);
+ const bool update_stat_strings = small_size != SMALL_SIZE_CHECK(layout->curr_size);
+ int sx = pos_x - layout->tile_border_x - (UI_UNIT_X * 0.1f), sy = pos_y;
+
+ for (FileAttributeColumnType column_type = 0; column_type < ATTRIBUTE_COLUMN_MAX;
+ column_type++) {
+ const FileAttributeColumn *column = &layout->attribute_columns[column_type];
+
+ /* Name column is not a detail column (should already be drawn), always skip here. */
+ if (column_type == COLUMN_NAME) {
+ sx += column->width;
+ continue;
+ }
+ if (!file_attribute_column_type_enabled(params, column_type)) {
+ continue;
+ }
+
+ const char *str = filelist_get_details_column_string(
+ column_type, file, small_size, update_stat_strings);
+
+ if (str) {
+ file_draw_string(sx + ATTRIBUTE_COLUMN_PADDING,
+ sy - layout->tile_border_y,
+ IFACE_(str),
+ column->width - 2 * ATTRIBUTE_COLUMN_PADDING,
+ layout->tile_h,
+ column->text_align,
+ text_col);
+ }
+
+ sx += column->width;
+ }
+}
+
void file_draw_list(const bContext *C, ARegion *ar)
{
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -652,18 +674,14 @@ void file_draw_list(const bContext *C, ARegion *ar)
bool is_icon;
eFontStyle_Align align;
bool do_drag;
- int column_space = 0.6f * UI_UNIT_X;
unsigned char text_col[4];
- const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size);
- const bool update_stat_strings = small_size != SMALL_SIZE_CHECK(layout->curr_size);
- const float thumb_icon_aspect = sqrtf(64.0f / (float)(params->thumbnail_size));
+ const bool draw_columnheader = (params->display == FILE_VERTICALDISPLAY);
+ const float thumb_icon_aspect = MIN2(64.0f / (float)(params->thumbnail_size), 1.0f);
numfiles = filelist_files_ensure(files);
if (params->display != FILE_IMGDISPLAY) {
-
draw_background(layout, v2d);
-
draw_dividers(layout, v2d);
}
@@ -679,13 +697,14 @@ void file_draw_list(const bContext *C, ARegion *ar)
numfiles_layout += layout->rows;
}
else {
- numfiles_layout += layout->columns;
+ numfiles_layout += layout->flow_columns;
}
filelist_file_cache_slidingwindow_set(files, numfiles_layout);
- textwidth = (FILE_IMGDISPLAY == params->display) ? layout->tile_w :
- (int)layout->column_widths[COLUMN_NAME];
+ textwidth = (FILE_IMGDISPLAY == params->display) ?
+ layout->tile_w :
+ round_fl_to_int(layout->attribute_columns[COLUMN_NAME].width);
textheight = (int)(layout->textheight * 3.0 / 2.0 + 0.5);
align = (FILE_IMGDISPLAY == params->display) ? UI_STYLE_TEXT_CENTER : UI_STYLE_TEXT_LEFT;
@@ -719,11 +738,16 @@ void file_draw_list(const bContext *C, ARegion *ar)
BLF_batch_draw_begin();
+ UI_GetThemeColor4ubv(TH_TEXT, text_col);
+
for (i = offset; (i < numfiles) && (i < offset + numfiles_layout); i++) {
unsigned int file_selflag;
char path[FILE_MAX_LIBEXTRA];
+ int padx = 0.1f * UI_UNIT_X;
+ int icon_ofs = 0;
+
ED_fileselect_layout_tilepos(layout, i, &sx, &sy);
- sx += (int)(v2d->tot.xmin + 0.1f * UI_UNIT_X);
+ sx += (int)(v2d->tot.xmin + padx);
sy = (int)(v2d->tot.ymax - sy);
file = filelist_file(files, i);
@@ -737,15 +761,14 @@ void file_draw_list(const bContext *C, ARegion *ar)
int colorid = (file_selflag & FILE_SEL_SELECTED) ? TH_HILITE : TH_BACK;
int shade = (params->highlight_file == i) || (file_selflag & FILE_SEL_HIGHLIGHTED) ? 35 :
0;
+ const short width = ELEM(params->display, FILE_VERTICALDISPLAY, FILE_HORIZONTALDISPLAY) ?
+ layout->tile_w - (2 * padx) :
+ layout->tile_w;
BLI_assert(i == 0 || !FILENAME_IS_CURRPAR(file->relpath));
- draw_tile(sx,
- sy - 1,
- layout->tile_w + 4,
- sfile->layout->tile_h + layout->tile_border_y,
- colorid,
- shade);
+ draw_tile(
+ sx, sy - 1, width, sfile->layout->tile_h + layout->tile_border_y, colorid, shade);
}
}
UI_draw_roundbox_corner_set(UI_CNR_NONE);
@@ -778,38 +801,28 @@ void file_draw_list(const bContext *C, ARegion *ar)
file_draw_icon(block,
path,
sx,
- sy - (UI_UNIT_Y / 6),
+ sy - layout->tile_border_y,
filelist_geticon(files, i, true),
ICON_DEFAULT_WIDTH_SCALE,
ICON_DEFAULT_HEIGHT_SCALE,
do_drag);
- sx += ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X;
+ icon_ofs += ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X;
}
- UI_GetThemeColor4ubv(TH_TEXT, text_col);
-
if (file_selflag & FILE_SEL_EDITING) {
uiBut *but;
- short width;
-
- if (params->display == FILE_SHORTDISPLAY) {
- width = layout->tile_w - (ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X);
- }
- else if (params->display == FILE_LONGDISPLAY) {
- width = layout->column_widths[COLUMN_NAME] + (column_space * 3.5f);
- }
- else {
- BLI_assert(params->display == FILE_IMGDISPLAY);
- width = textwidth;
- }
+ const short width = (params->display == FILE_IMGDISPLAY) ?
+ textwidth :
+ layout->attribute_columns[COLUMN_NAME].width -
+ ATTRIBUTE_COLUMN_PADDING;
but = uiDefBut(block,
UI_BTYPE_TEXT,
1,
"",
- sx,
+ sx + icon_ofs,
sy - layout->tile_h - 0.15f * UI_UNIT_X,
- width,
+ width - icon_ofs,
textheight,
sfile->params->renamefile,
1.0f,
@@ -825,74 +838,19 @@ void file_draw_list(const bContext *C, ARegion *ar)
sfile->files, file, FILE_SEL_REMOVE, FILE_SEL_EDITING, CHECK_ALL);
}
}
-
- if (!(file_selflag & FILE_SEL_EDITING)) {
- int tpos = (FILE_IMGDISPLAY == params->display) ? sy - layout->tile_h + layout->textheight :
- sy;
- file_draw_string(sx + 1, tpos, file->name, (float)textwidth, textheight, align, text_col);
- }
-
- sx += (int)layout->column_widths[COLUMN_NAME] + column_space;
- if (params->display == FILE_SHORTDISPLAY) {
- if ((file->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) ||
- !(file->typeflag & (FILE_TYPE_DIR | FILE_TYPE_BLENDERLIB))) {
- if ((file->entry->size_str[0] == '\0') || update_stat_strings) {
- BLI_filelist_entry_size_to_string(
- NULL, file->entry->size, small_size, file->entry->size_str);
- }
- file_draw_string(sx,
- sy,
- file->entry->size_str,
- layout->column_widths[COLUMN_SIZE],
- layout->tile_h,
- align,
- text_col);
- }
- sx += (int)layout->column_widths[COLUMN_SIZE] + column_space;
+ else {
+ const int txpos = (params->display == FILE_IMGDISPLAY) ? sx : sx + 1 + icon_ofs;
+ const int typos = (params->display == FILE_IMGDISPLAY) ?
+ sy - layout->tile_h + layout->textheight :
+ sy - layout->tile_border_y;
+ const int twidth = (params->display == FILE_IMGDISPLAY) ?
+ textwidth :
+ textwidth - 1 - icon_ofs - padx - layout->tile_border_x;
+ file_draw_string(txpos, typos, file->name, (float)twidth, textheight, align, text_col);
}
- else if (params->display == FILE_LONGDISPLAY) {
- if (!(file->typeflag & FILE_TYPE_BLENDERLIB) && !FILENAME_IS_CURRPAR(file->relpath)) {
- if ((file->entry->date_str[0] == '\0') || update_stat_strings) {
- BLI_filelist_entry_datetime_to_string(
- NULL, file->entry->time, small_size, file->entry->time_str, file->entry->date_str);
- }
- file_draw_string(sx,
- sy,
- file->entry->date_str,
- layout->column_widths[COLUMN_DATE],
- layout->tile_h,
- align,
- text_col);
- sx += (int)layout->column_widths[COLUMN_DATE] + column_space;
- file_draw_string(sx,
- sy,
- file->entry->time_str,
- layout->column_widths[COLUMN_TIME],
- layout->tile_h,
- align,
- text_col);
- sx += (int)layout->column_widths[COLUMN_TIME] + column_space;
- }
- else {
- sx += (int)layout->column_widths[COLUMN_DATE] + column_space;
- sx += (int)layout->column_widths[COLUMN_TIME] + column_space;
- }
- if ((file->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) ||
- !(file->typeflag & (FILE_TYPE_DIR | FILE_TYPE_BLENDERLIB))) {
- if ((file->entry->size_str[0] == '\0') || update_stat_strings) {
- BLI_filelist_entry_size_to_string(
- NULL, file->entry->size, small_size, file->entry->size_str);
- }
- file_draw_string(sx,
- sy,
- file->entry->size_str,
- layout->column_widths[COLUMN_SIZE],
- layout->tile_h,
- align,
- text_col);
- }
- sx += (int)layout->column_widths[COLUMN_SIZE] + column_space;
+ if (params->display != FILE_IMGDISPLAY) {
+ draw_details_columns(params, layout, file, sx, sy, text_col);
}
}
@@ -901,5 +859,11 @@ void file_draw_list(const bContext *C, ARegion *ar)
UI_block_end(C, block);
UI_block_draw(C, block);
+ /* Draw last, on top of file list. */
+ if (draw_columnheader) {
+ draw_columnheader_background(layout, v2d);
+ draw_columnheader_columns(params, layout, v2d, text_col);
+ }
+
layout->curr_size = params->thumbnail_size;
}
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index bad25511dd5..b0ff67844d8 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -30,9 +30,7 @@ struct ARegion;
struct ARegionType;
struct FileSelectParams;
struct SpaceFile;
-
-/* file_ops.c */
-struct ARegion *file_tools_region(struct ScrArea *sa);
+struct View2D;
/* file_draw.c */
#define TILE_BORDER_X (UI_UNIT_X / 4)
@@ -42,9 +40,10 @@ struct ARegion *file_tools_region(struct ScrArea *sa);
#define IMASEL_BUTTONS_HEIGHT (UI_UNIT_Y * 2)
#define IMASEL_BUTTONS_MARGIN (UI_UNIT_Y / 6)
+#define ATTRIBUTE_COLUMN_PADDING (0.5f * UI_UNIT_X)
+
#define SMALL_SIZE_CHECK(_size) ((_size) < 64) /* Related to FileSelectParams.thumbnail_size. */
-void file_draw_buttons(const bContext *C, ARegion *ar);
void file_calc_previews(const bContext *C, ARegion *ar);
void file_draw_list(const bContext *C, ARegion *ar);
@@ -64,6 +63,7 @@ typedef enum WalkSelectDirection {
} WalkSelectDirections;
void FILE_OT_highlight(struct wmOperatorType *ot);
+void FILE_OT_sort_column_ui_context(struct wmOperatorType *ot);
void FILE_OT_select(struct wmOperatorType *ot);
void FILE_OT_select_walk(struct wmOperatorType *ot);
void FILE_OT_select_all(struct wmOperatorType *ot);
@@ -82,7 +82,6 @@ void FILE_OT_directory_new(struct wmOperatorType *ot);
void FILE_OT_previous(struct wmOperatorType *ot);
void FILE_OT_next(struct wmOperatorType *ot);
void FILE_OT_refresh(struct wmOperatorType *ot);
-void FILE_OT_bookmark_toggle(struct wmOperatorType *ot);
void FILE_OT_filenum(struct wmOperatorType *ot);
void FILE_OT_delete(struct wmOperatorType *ot);
void FILE_OT_rename(struct wmOperatorType *ot);
@@ -108,10 +107,21 @@ void file_sfile_to_operator_ex(bContext *C,
struct SpaceFile *sfile,
char *filepath);
void file_sfile_to_operator(bContext *C, struct wmOperator *op, struct SpaceFile *sfile);
+
void file_operator_to_sfile(bContext *C, struct SpaceFile *sfile, struct wmOperator *op);
/* filesel.c */
void fileselect_file_set(SpaceFile *sfile, const int index);
+bool file_attribute_column_type_enabled(const FileSelectParams *params,
+ FileAttributeColumnType column);
+bool file_attribute_column_header_is_inside(const struct View2D *v2d,
+ const FileLayout *layout,
+ int x,
+ int y);
+FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d,
+ const FileSelectParams *params,
+ FileLayout *layout,
+ int x);
float file_string_width(const char *str);
float file_font_pointsize(void);
@@ -122,7 +132,8 @@ int autocomplete_file(struct bContext *C, char *str, void *arg_v);
void file_params_renamefile_activate(struct SpaceFile *sfile, struct FileSelectParams *params);
/* file_panels.c */
-void file_panels_register(struct ARegionType *art);
+void file_tool_props_region_panels_register(struct ARegionType *art);
+void file_execute_region_panels_register(struct ARegionType *art);
/* file_utils.c */
void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds);
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index eb5f02b6e13..b4b51de302d 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -78,7 +78,12 @@ static FileSelection find_file_mouse_rect(SpaceFile *sfile, ARegion *ar, const r
BLI_rctf_rcti_copy(&rect_region_fl, rect_region);
+ /* Okay, manipulating v2d rects here is hacky... */
+ v2d->mask.ymax -= sfile->layout->offset_top;
+ v2d->cur.ymax -= sfile->layout->offset_top;
UI_view2d_region_to_view_rctf(v2d, &rect_region_fl, &rect_view_fl);
+ v2d->mask.ymax += sfile->layout->offset_top;
+ v2d->cur.ymax += sfile->layout->offset_top;
BLI_rcti_init(&rect_view,
(int)(v2d->tot.xmin + rect_view_fl.xmin),
@@ -190,7 +195,6 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
const bool is_parent_dir = FILENAME_IS_PARENT(file->relpath);
if (do_diropen == false) {
- params->file[0] = '\0';
retval = FILE_SELECT_DIR;
}
/* the path is too long and we are not going up! */
@@ -235,7 +239,7 @@ static bool file_is_any_selected(struct FileList *files)
int i;
/* Is any file selected ? */
- for (i = 0; i < numfiles; ++i) {
+ for (i = 0; i < numfiles; i++) {
if (filelist_entry_select_index_get(files, i, CHECK_ALL)) {
return true;
}
@@ -262,8 +266,8 @@ static void file_ensure_inside_viewbounds(ARegion *ar, SpaceFile *sfile, const i
cur->ymax = cur->ymin + ar->winy;
}
/* up */
- else if (cur->ymax < rect.ymax) {
- cur->ymax = rect.ymax + layout->tile_border_y;
+ else if ((cur->ymax - layout->offset_top) < rect.ymax) {
+ cur->ymax = rect.ymax + layout->tile_border_y + layout->offset_top;
cur->ymin = cur->ymax - ar->winy;
}
/* left - also use if tile is wider than viewbounds so view is aligned to file name */
@@ -278,7 +282,7 @@ static void file_ensure_inside_viewbounds(ARegion *ar, SpaceFile *sfile, const i
}
else {
BLI_assert(cur->xmin <= rect.xmin && cur->xmax >= rect.xmax && cur->ymin <= rect.ymin &&
- cur->ymax >= rect.ymax);
+ (cur->ymax - layout->offset_top) >= rect.ymax);
changed = false;
}
@@ -384,7 +388,7 @@ static int file_box_select_modal(bContext *C, wmOperator *op, const wmEvent *eve
if (result == OPERATOR_RUNNING_MODAL) {
WM_operator_properties_border_to_rcti(op, &rect);
- BLI_rcti_isect(&(ar->v2d.mask), &rect, &rect);
+ ED_fileselect_layout_isect_rect(sfile->layout, &ar->v2d, &rect, &rect);
sel = file_selection_get(C, &rect, 0);
if ((sel.first != params->sel_first) || (sel.last != params->sel_last)) {
@@ -440,13 +444,13 @@ static int file_box_select_exec(bContext *C, wmOperator *op)
file_deselect_all(sfile, FILE_SEL_SELECTED);
}
- BLI_rcti_isect(&(ar->v2d.mask), &rect, &rect);
+ ED_fileselect_layout_isect_rect(sfile->layout, &ar->v2d, &rect, &rect);
ret = file_select(C, &rect, select ? FILE_SEL_ADD : FILE_SEL_REMOVE, false, false);
/* unselect '..' parent entry - it's not supposed to be selected if more than
* one file is selected */
- filelist_entry_select_index_set(sfile->files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
+ filelist_entry_parent_select_set(sfile->files, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
if (FILE_SELECT_DIR == ret) {
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -485,6 +489,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const bool extend = RNA_boolean_get(op->ptr, "extend");
const bool fill = RNA_boolean_get(op->ptr, "fill");
const bool do_diropen = RNA_boolean_get(op->ptr, "open");
+ const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
if (ar->regiontype != RGN_TYPE_WINDOW) {
return OPERATOR_CANCELLED;
@@ -493,7 +498,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
rect.xmin = rect.xmax = event->mval[0];
rect.ymin = rect.ymax = event->mval[1];
- if (!BLI_rcti_isect_pt(&ar->v2d.mask, rect.xmin, rect.ymin)) {
+ if (!ED_fileselect_layout_is_inside_pt(sfile->layout, &ar->v2d, rect.xmin, rect.ymin)) {
return OPERATOR_CANCELLED;
}
@@ -514,14 +519,18 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (extend) {
/* unselect '..' parent entry - it's not supposed to be selected if more
* than one file is selected */
- filelist_entry_select_index_set(
- sfile->files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
+ filelist_entry_parent_select_set(sfile->files, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
}
- if (FILE_SELECT_DIR == ret) {
+ if (ret == FILE_SELECT_NOTHING) {
+ if (deselect_all) {
+ file_deselect_all(sfile, FILE_SEL_SELECTED);
+ }
+ }
+ else if (ret == FILE_SELECT_DIR) {
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
- else if (FILE_SELECT_FILE == ret) {
+ else if (ret == FILE_SELECT_FILE) {
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
}
@@ -537,8 +546,8 @@ void FILE_OT_select(wmOperatorType *ot)
/* identifiers */
ot->name = "Select";
- ot->description = "Activate/select file";
ot->idname = "FILE_OT_select";
+ ot->description = "Handle mouse clicks to select and activate items";
/* api callbacks */
ot->invoke = file_select_invoke;
@@ -556,6 +565,12 @@ void FILE_OT_select(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "open", true, "Open", "Open a directory when selecting it");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna,
+ "deselect_all",
+ false,
+ "Deselect On Nothing",
+ "Deselect all when nothing under the cursor");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/**
@@ -580,6 +595,11 @@ static bool file_walk_select_selection_set(bContext *C,
BLI_assert(params);
+ if (numfiles == 0) {
+ /* No files visible, nothing to do. */
+ return false;
+ }
+
if (has_selection) {
if (extend && filelist_entry_select_index_get(files, active_old, CHECK_ALL) &&
filelist_entry_select_index_get(files, active_new, CHECK_ALL)) {
@@ -609,7 +629,7 @@ static bool file_walk_select_selection_set(bContext *C,
}
/* select first file */
else if (ELEM(direction, FILE_SELECT_WALK_DOWN, FILE_SELECT_WALK_RIGHT)) {
- params->active_file = active = extend ? 1 : 0;
+ params->active_file = active = 0;
}
else {
BLI_assert(0);
@@ -626,7 +646,7 @@ static bool file_walk_select_selection_set(bContext *C,
/* unselect '..' parent entry - it's not supposed to be selected if more
* than one file is selected */
- filelist_entry_select_index_set(files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
+ filelist_entry_parent_select_set(files, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
}
else {
/* deselect all first */
@@ -641,11 +661,6 @@ static bool file_walk_select_selection_set(bContext *C,
if (fill) {
FileSelection sel = {MIN2(active, last_sel), MAX2(active, last_sel)};
- /* clamping selection to not include '..' parent entry */
- if (sel.first == 0) {
- sel.first = 1;
- }
-
/* fill selection between last and first selected file */
filelist_entries_select_index_range_set(
files, &sel, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
@@ -653,6 +668,12 @@ static bool file_walk_select_selection_set(bContext *C,
if (deselect) {
filelist_entry_select_index_set(files, active, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
}
+
+ /* unselect '..' parent entry - it's not supposed to be selected if more
+ * than one file is selected */
+ if ((sel.last - sel.first) > 1) {
+ filelist_entry_parent_select_set(files, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
+ }
}
else {
filelist_entry_select_index_set(
@@ -688,10 +709,15 @@ static bool file_walk_select_do(bContext *C,
/* *** get all needed files for handling selection *** */
+ if (numfiles == 0) {
+ /* No files visible, nothing to do. */
+ return false;
+ }
+
if (has_selection) {
ARegion *ar = CTX_wm_region(C);
FileLayout *layout = ED_fileselect_get_layout(sfile, ar);
- const int idx_shift = (layout->flag & FILE_LAYOUT_HOR) ? layout->rows : layout->columns;
+ const int idx_shift = (layout->flag & FILE_LAYOUT_HOR) ? layout->rows : layout->flow_columns;
if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_UP) ||
(layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_LEFT)) {
@@ -718,7 +744,7 @@ static bool file_walk_select_do(bContext *C,
BLI_assert(0);
}
- if (!IN_RANGE(active_new, 0, numfiles)) {
+ if (!IN_RANGE(active_new, -1, numfiles)) {
if (extend) {
/* extend to invalid file -> abort */
return false;
@@ -1185,7 +1211,7 @@ int file_highlight_set(SpaceFile *sfile, ARegion *ar, int mx, int my)
mx -= ar->winrct.xmin;
my -= ar->winrct.ymin;
- if (BLI_rcti_isect_pt(&ar->v2d.mask, mx, my)) {
+ if (ED_fileselect_layout_is_inside_pt(sfile->layout, v2d, mx, my)) {
float fx, fy;
int highlight_file;
@@ -1234,6 +1260,53 @@ void FILE_OT_highlight(struct wmOperatorType *ot)
ot->poll = ED_operator_file_active;
}
+static int file_column_sort_ui_context_invoke(bContext *C,
+ wmOperator *UNUSED(op),
+ const wmEvent *event)
+{
+ const ARegion *ar = CTX_wm_region(C);
+ SpaceFile *sfile = CTX_wm_space_file(C);
+
+ if (file_attribute_column_header_is_inside(
+ &ar->v2d, sfile->layout, event->mval[0], event->mval[1])) {
+ const FileAttributeColumnType column_type = file_attribute_column_type_find_isect(
+ &ar->v2d, sfile->params, sfile->layout, event->mval[0]);
+
+ if (column_type != COLUMN_NONE) {
+ const FileAttributeColumn *column = &sfile->layout->attribute_columns[column_type];
+
+ if (column->sort_type != FILE_SORT_NONE) {
+ if (sfile->params->sort == column->sort_type) {
+ /* Already sorting by selected column -> toggle sort invert (three state logic). */
+ sfile->params->flag ^= FILE_SORT_INVERT;
+ }
+ else {
+ sfile->params->sort = column->sort_type;
+ sfile->params->flag &= ~FILE_SORT_INVERT;
+ }
+
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+ }
+ }
+ }
+
+ return OPERATOR_PASS_THROUGH;
+}
+
+void FILE_OT_sort_column_ui_context(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Sort from Column";
+ ot->description = "Change sorting to use column under cursor";
+ ot->idname = "FILE_OT_sort_column_ui_context";
+
+ /* api callbacks */
+ ot->invoke = file_column_sort_ui_context_invoke;
+ ot->poll = ED_operator_file_active;
+
+ ot->flag = OPTYPE_INTERNAL;
+}
+
int file_cancel_exec(bContext *C, wmOperator *UNUSED(unused))
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -1433,14 +1506,11 @@ void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
bool file_draw_check_exists(SpaceFile *sfile)
{
if (sfile->op) { /* fails on reload */
- PropertyRNA *prop;
- if ((prop = RNA_struct_find_property(sfile->op->ptr, "check_existing"))) {
- if (RNA_property_boolean_get(sfile->op->ptr, prop)) {
- char filepath[FILE_MAX];
- BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file);
- if (BLI_is_file(filepath)) {
- return true;
- }
+ if (sfile->params && (sfile->params->flag & FILE_CHECK_EXISTING)) {
+ char filepath[FILE_MAX];
+ BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file);
+ if (BLI_is_file(filepath)) {
+ return true;
}
}
}
@@ -1683,7 +1753,7 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w
/* check if we are editing a name */
int edit_idx = -1;
- for (i = 0; i < numfiles; ++i) {
+ for (i = 0; i < numfiles; i++) {
if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL) &
(FILE_SEL_EDITING | FILE_SEL_HIGHLIGHTED)) {
edit_idx = i;
@@ -1713,7 +1783,7 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w
/* Number of items in a block (i.e. lines in a column in horizontal layout, or columns in a line
* in vertical layout).
*/
- const int items_block_size = is_horizontal ? sfile->layout->rows : sfile->layout->columns;
+ const int items_block_size = is_horizontal ? sfile->layout->rows : sfile->layout->flow_columns;
/* Scroll offset is the first file in the row/column we are editing in. */
if (sfile->scroll_offset == 0) {
@@ -1915,6 +1985,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
ScrArea *sa = CTX_wm_area(C);
+ const bool do_diropen = RNA_boolean_get(op->ptr, "open");
if (!sfile->params) {
BKE_report(op->reports, RPT_WARNING, "No parent directory given");
@@ -1963,9 +2034,11 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* now remember file to jump into editing */
- BLI_strncpy(sfile->params->renamefile, name, FILE_MAXFILE);
- sfile->params->rename_flag = FILE_PARAMS_RENAME_PENDING;
+ /* If we don't enter the directory directly, remember file to jump into editing. */
+ if (do_diropen == false) {
+ BLI_strncpy(sfile->params->renamefile, name, FILE_MAXFILE);
+ sfile->params->rename_flag = FILE_PARAMS_RENAME_PENDING;
+ }
/* set timer to smoothly view newly generated file */
/* max 30 frs/sec */
@@ -1978,7 +2051,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
/* reload dir to make sure we're seeing what's in the directory */
ED_fileselect_clear(wm, sa, sfile);
- if (RNA_boolean_get(op->ptr, "open")) {
+ if (do_diropen) {
BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir));
ED_file_change_dir(C);
}
@@ -1998,7 +2071,7 @@ void FILE_OT_directory_new(struct wmOperatorType *ot)
ot->idname = "FILE_OT_directory_new";
/* api callbacks */
- ot->invoke = WM_operator_confirm;
+ ot->invoke = WM_operator_confirm_or_exec;
ot->exec = file_directory_new_exec;
ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
@@ -2007,6 +2080,7 @@ void FILE_OT_directory_new(struct wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "open", false, "Open", "Open new directory");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ WM_operator_properties_confirm_or_exec(ot);
}
/* TODO This should go to BLI_path_utils. */
@@ -2075,6 +2149,10 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile->params) {
+ char old_dir[sizeof(sfile->params->dir)];
+
+ BLI_strncpy(old_dir, sfile->params->dir, sizeof(old_dir));
+
file_expand_directory(C);
/* special case, user may have pasted a filepath into the directory */
@@ -2108,8 +2186,10 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
BLI_cleanup_dir(BKE_main_blendfile_path(bmain), sfile->params->dir);
if (filelist_is_dir(sfile->files, sfile->params->dir)) {
- /* if directory exists, enter it immediately */
- ED_file_change_dir(C);
+ if (!STREQ(sfile->params->dir, old_dir)) { /* Avoids flickering when nothing's changed. */
+ /* if directory exists, enter it immediately */
+ ED_file_change_dir(C);
+ }
/* don't do for now because it selects entire text instead of
* placing cursor at the end */
@@ -2138,6 +2218,8 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
WM_operator_properties_create_ptr(&ptr, ot);
RNA_string_set(&ptr, "directory", sfile->params->dir);
RNA_boolean_set(&ptr, "open", true);
+ /* Enable confirmation prompt, else it's too easy to accidentaly create new directories. */
+ RNA_boolean_set(&ptr, "confirm", true);
if (lastdir) {
BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir));
@@ -2239,57 +2321,15 @@ void FILE_OT_hidedot(struct wmOperatorType *ot)
ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
}
-ARegion *file_tools_region(ScrArea *sa)
+static bool file_filenum_poll(bContext *C)
{
- ARegion *ar, *arnew;
-
- if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS)) != NULL) {
- return ar;
- }
-
- /* add subdiv level; after header */
- ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
-
- /* is error! */
- if (ar == NULL) {
- return NULL;
- }
-
- arnew = MEM_callocN(sizeof(ARegion), "tools for file");
- BLI_insertlinkafter(&sa->regionbase, ar, arnew);
- arnew->regiontype = RGN_TYPE_TOOLS;
- arnew->alignment = RGN_ALIGN_LEFT;
-
- ar = MEM_callocN(sizeof(ARegion), "tool props for file");
- BLI_insertlinkafter(&sa->regionbase, arnew, ar);
- ar->regiontype = RGN_TYPE_TOOL_PROPS;
- ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
-
- return arnew;
-}
-
-static int file_bookmark_toggle_exec(bContext *C, wmOperator *UNUSED(unused))
-{
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = file_tools_region(sa);
+ SpaceFile *sfile = CTX_wm_space_file(C);
- if (ar) {
- ED_region_toggle_hidden(C, ar);
+ if (!ED_operator_file_active(C)) {
+ return false;
}
- return OPERATOR_FINISHED;
-}
-
-void FILE_OT_bookmark_toggle(struct wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Toggle Bookmarks";
- ot->description = "Toggle bookmarks display";
- ot->idname = "FILE_OT_bookmark_toggle";
-
- /* api callbacks */
- ot->exec = file_bookmark_toggle_exec;
- ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
+ return sfile->params && (sfile->params->flag & FILE_CHECK_EXISTING);
}
/**
@@ -2349,7 +2389,7 @@ void FILE_OT_filenum(struct wmOperatorType *ot)
/* api callbacks */
ot->exec = file_filenum_exec;
- ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
+ ot->poll = file_filenum_poll;
/* props */
RNA_def_int(ot->srna, "increment", 1, -100, 100, "Increment", "", -100, 100);
diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c
index d9a6e70121f..9ba098fcf45 100644
--- a/source/blender/editors/space_file/file_panels.c
+++ b/source/blender/editors/space_file/file_panels.c
@@ -95,7 +95,7 @@ static void file_panel_operator(const bContext *C, Panel *pa)
UI_block_func_set(uiLayoutGetBlock(pa->layout), NULL, NULL, NULL);
}
-void file_panels_register(ARegionType *art)
+void file_tool_props_region_panels_register(ARegionType *art)
{
PanelType *pt;
@@ -103,8 +103,122 @@ void file_panels_register(ARegionType *art)
strcpy(pt->idname, "FILE_PT_operator");
strcpy(pt->label, N_("Operator"));
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ pt->flag = PNL_NO_HEADER;
pt->poll = file_panel_operator_poll;
pt->draw_header = file_panel_operator_header;
pt->draw = file_panel_operator;
BLI_addtail(&art->paneltypes, pt);
}
+
+static void file_panel_execution_cancel_button(uiLayout *layout)
+{
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiLayoutSetScaleX(row, 0.8f);
+ uiLayoutSetFixedSize(row, true);
+ uiItemO(row, IFACE_("Cancel"), ICON_NONE, "FILE_OT_cancel");
+}
+
+static void file_panel_execution_execute_button(uiLayout *layout, const char *title)
+{
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiLayoutSetScaleX(row, 0.8f);
+ uiLayoutSetFixedSize(row, true);
+ /* Just a display hint. */
+ uiLayoutSetActiveDefault(row, true);
+ uiItemO(row, title, ICON_NONE, "FILE_OT_execute");
+}
+
+static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa)
+{
+ bScreen *screen = CTX_wm_screen(C);
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ FileSelectParams *params = ED_fileselect_get_params(sfile);
+ uiBlock *block = uiLayoutGetBlock(pa->layout);
+ uiBut *but;
+ uiLayout *row;
+ PointerRNA params_rna_ptr, *but_extra_rna_ptr;
+
+ const bool overwrite_alert = file_draw_check_exists(sfile);
+ const bool windows_layout =
+#ifdef _WIN32
+ true;
+#else
+ false;
+#endif
+
+ RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, &params_rna_ptr);
+
+ row = uiLayoutRow(pa->layout, false);
+ uiLayoutSetScaleY(row, 1.3f);
+
+ /* callbacks for operator check functions */
+ UI_block_func_set(block, file_draw_check_cb, NULL, NULL);
+
+ but = uiDefButR(block,
+ UI_BTYPE_TEXT,
+ -1,
+ "",
+ 0,
+ 0,
+ UI_UNIT_X * 5,
+ UI_UNIT_Y,
+ &params_rna_ptr,
+ "filename",
+ 0,
+ 0.0f,
+ (float)FILE_MAXFILE,
+ 0,
+ 0,
+ TIP_(overwrite_alert ? N_("File name, overwrite existing") : N_("File name")));
+
+ BLI_assert(!UI_but_flag_is_set(but, UI_BUT_UNDO));
+ BLI_assert(!UI_but_is_utf8(but));
+
+ UI_but_func_complete_set(but, autocomplete_file, NULL);
+ /* silly workaround calling NFunc to ensure this does not get called
+ * immediate ui_apply_but_func but only after button deactivates */
+ UI_but_funcN_set(but, file_filename_enter_handle, NULL, but);
+
+ if (params->flag & FILE_CHECK_EXISTING) {
+ but_extra_rna_ptr = UI_but_extra_operator_icon_add(
+ but, "FILE_OT_filenum", WM_OP_EXEC_REGION_WIN, ICON_ADD);
+ RNA_int_set(but_extra_rna_ptr, "increment", 1);
+ but_extra_rna_ptr = UI_but_extra_operator_icon_add(
+ but, "FILE_OT_filenum", WM_OP_EXEC_REGION_WIN, ICON_REMOVE);
+ RNA_int_set(but_extra_rna_ptr, "increment", -1);
+ }
+
+ /* check if this overrides a file and if the operator option is used */
+ if (overwrite_alert) {
+ UI_but_flag_enable(but, UI_BUT_REDALERT);
+ }
+ UI_block_func_set(block, NULL, NULL, NULL);
+
+ {
+ uiLayout *sub = uiLayoutRow(row, false);
+ uiLayoutSetOperatorContext(sub, WM_OP_EXEC_REGION_WIN);
+
+ if (windows_layout) {
+ file_panel_execution_execute_button(sub, params->title);
+ file_panel_execution_cancel_button(sub);
+ }
+ else {
+ file_panel_execution_cancel_button(sub);
+ file_panel_execution_execute_button(sub, params->title);
+ }
+ }
+}
+
+void file_execute_region_panels_register(ARegionType *art)
+{
+ PanelType *pt;
+
+ pt = MEM_callocN(sizeof(PanelType), "spacetype file execution buttons");
+ strcpy(pt->idname, "FILE_PT_execution_buttons");
+ strcpy(pt->label, N_("Execute Buttons"));
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ pt->flag = PNL_NO_HEADER;
+ pt->poll = file_panel_operator_poll;
+ pt->draw = file_panel_execution_buttons_draw;
+ BLI_addtail(&art->paneltypes, pt);
+}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index f7dda1defe8..27cccf6bab1 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -329,25 +329,21 @@ enum {
FL_IS_PENDING = 1 << 2,
FL_NEED_SORTING = 1 << 3,
FL_NEED_FILTERING = 1 << 4,
+ FL_SORT_INVERT = 1 << 5,
};
-#define SPECIAL_IMG_SIZE 48
-#define SPECIAL_IMG_ROWS 4
-#define SPECIAL_IMG_COLS 4
+#define SPECIAL_IMG_SIZE 256
+#define SPECIAL_IMG_ROWS 1
+#define SPECIAL_IMG_COLS 7
enum {
- SPECIAL_IMG_FOLDER = 0,
- SPECIAL_IMG_PARENT = 1,
- SPECIAL_IMG_REFRESH = 2,
- SPECIAL_IMG_BLENDFILE = 3,
- SPECIAL_IMG_SOUNDFILE = 4,
- SPECIAL_IMG_MOVIEFILE = 5,
- SPECIAL_IMG_PYTHONFILE = 6,
- SPECIAL_IMG_TEXTFILE = 7,
- SPECIAL_IMG_FONTFILE = 8,
- SPECIAL_IMG_UNKNOWNFILE = 9,
- SPECIAL_IMG_LOADING = 10,
- SPECIAL_IMG_BACKUP = 11,
+ SPECIAL_IMG_DOCUMENT = 0,
+ SPECIAL_IMG_UNSUPORTED = 1,
+ SPECIAL_IMG_FOLDER = 2,
+ SPECIAL_IMG_PARENT = 3,
+ SPECIAL_IMG_DRIVE_FIXED = 4,
+ SPECIAL_IMG_DRIVE_ATTACHED = 5,
+ SPECIAL_IMG_DRIVE_REMOTE = 6,
SPECIAL_IMG_MAX,
};
@@ -369,6 +365,19 @@ static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size);
/* ********** Sort helpers ********** */
+struct FileSortData {
+ bool inverted;
+};
+
+static int compare_apply_inverted(int val, const struct FileSortData *sort_data)
+{
+ return sort_data->inverted ? -val : val;
+}
+
+/**
+ * Handles inverted sorting itself (currently there's nothing to invert), so if this returns non-0,
+ * it should be used as-is and not inverted.
+ */
static int compare_direntry_generic(const FileListInternEntry *entry1,
const FileListInternEntry *entry2)
{
@@ -420,10 +429,11 @@ static int compare_direntry_generic(const FileListInternEntry *entry1,
return 0;
}
-static int compare_name(void *UNUSED(user_data), const void *a1, const void *a2)
+static int compare_name(void *user_data, const void *a1, const void *a2)
{
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
+ const struct FileSortData *sort_data = user_data;
char *name1, *name2;
int ret;
@@ -434,13 +444,14 @@ static int compare_name(void *UNUSED(user_data), const void *a1, const void *a2)
name1 = entry1->name;
name2 = entry2->name;
- return BLI_natstrcmp(name1, name2);
+ return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
}
-static int compare_date(void *UNUSED(user_data), const void *a1, const void *a2)
+static int compare_date(void *user_data, const void *a1, const void *a2)
{
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
+ const struct FileSortData *sort_data = user_data;
char *name1, *name2;
int64_t time1, time2;
int ret;
@@ -452,22 +463,23 @@ static int compare_date(void *UNUSED(user_data), const void *a1, const void *a2)
time1 = (int64_t)entry1->st.st_mtime;
time2 = (int64_t)entry2->st.st_mtime;
if (time1 < time2) {
- return 1;
+ return compare_apply_inverted(1, sort_data);
}
if (time1 > time2) {
- return -1;
+ return compare_apply_inverted(-1, sort_data);
}
name1 = entry1->name;
name2 = entry2->name;
- return BLI_natstrcmp(name1, name2);
+ return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
}
-static int compare_size(void *UNUSED(user_data), const void *a1, const void *a2)
+static int compare_size(void *user_data, const void *a1, const void *a2)
{
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
+ const struct FileSortData *sort_data = user_data;
char *name1, *name2;
uint64_t size1, size2;
int ret;
@@ -479,22 +491,23 @@ static int compare_size(void *UNUSED(user_data), const void *a1, const void *a2)
size1 = entry1->st.st_size;
size2 = entry2->st.st_size;
if (size1 < size2) {
- return 1;
+ return compare_apply_inverted(1, sort_data);
}
if (size1 > size2) {
- return -1;
+ return compare_apply_inverted(-1, sort_data);
}
name1 = entry1->name;
name2 = entry2->name;
- return BLI_natstrcmp(name1, name2);
+ return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
}
-static int compare_extension(void *UNUSED(user_data), const void *a1, const void *a2)
+static int compare_extension(void *user_data, const void *a1, const void *a2)
{
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
+ const struct FileSortData *sort_data = user_data;
char *name1, *name2;
int ret;
@@ -516,10 +529,10 @@ static int compare_extension(void *UNUSED(user_data), const void *a1, const void
return -1;
}
if (entry1->blentype < entry2->blentype) {
- return -1;
+ return compare_apply_inverted(-1, sort_data);
}
if (entry1->blentype > entry2->blentype) {
- return 1;
+ return compare_apply_inverted(1, sort_data);
}
}
else {
@@ -539,48 +552,58 @@ static int compare_extension(void *UNUSED(user_data), const void *a1, const void
}
if ((ret = BLI_strcasecmp(sufix1, sufix2))) {
- return ret;
+ return compare_apply_inverted(ret, sort_data);
}
}
name1 = entry1->name;
name2 = entry2->name;
- return BLI_natstrcmp(name1, name2);
+ return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
}
void filelist_sort(struct FileList *filelist)
{
if ((filelist->flags & FL_NEED_SORTING) && (filelist->sort != FILE_SORT_NONE)) {
+ void *sort_cb = NULL;
+
switch (filelist->sort) {
case FILE_SORT_ALPHA:
- BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_name, NULL);
+ sort_cb = compare_name;
break;
case FILE_SORT_TIME:
- BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_date, NULL);
+ sort_cb = compare_date;
break;
case FILE_SORT_SIZE:
- BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_size, NULL);
+ sort_cb = compare_size;
break;
case FILE_SORT_EXTENSION:
- BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_extension, NULL);
+ sort_cb = compare_extension;
break;
case FILE_SORT_NONE: /* Should never reach this point! */
default:
BLI_assert(0);
break;
}
+ BLI_listbase_sort_r(
+ &filelist->filelist_intern.entries,
+ sort_cb,
+ &(struct FileSortData){.inverted = (filelist->flags & FL_SORT_INVERT) != 0});
filelist_filter_clear(filelist);
filelist->flags &= ~FL_NEED_SORTING;
}
}
-void filelist_setsorting(struct FileList *filelist, const short sort)
+void filelist_setsorting(struct FileList *filelist, const short sort, bool invert_sort)
{
- if (filelist->sort != sort) {
+ const bool was_invert_sort = filelist->flags & FL_SORT_INVERT;
+
+ if ((filelist->sort != sort) || (was_invert_sort != invert_sort)) {
filelist->sort = sort;
filelist->flags |= FL_NEED_SORTING;
+ filelist->flags = invert_sort ? (filelist->flags | FL_SORT_INVERT) :
+ (filelist->flags & ~FL_SORT_INVERT);
}
}
@@ -635,9 +658,9 @@ static bool is_filtered_file(FileListInternEntry *file,
{
bool is_filtered = !is_hidden_file(file->relpath, filter);
- if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) {
+ if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) {
/* We only check for types if some type are enabled in filtering. */
- if (filter->filter) {
+ if (filter->filter && (filter->flags & FLF_DO_FILTER)) {
if (file->typeflag & FILE_TYPE_DIR) {
if (file->typeflag &
(FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
@@ -657,6 +680,7 @@ static bool is_filtered_file(FileListInternEntry *file,
}
}
}
+ /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
if (is_filtered && (filter->filter_search[0] != '\0')) {
if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) {
is_filtered = false;
@@ -676,9 +700,9 @@ static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileLis
if (BLO_library_path_explode(path, dir, &group, &name)) {
is_filtered = !is_hidden_file(file->relpath, filter);
- if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) {
+ if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) {
/* We only check for types if some type are enabled in filtering. */
- if (filter->filter || filter->filter_id) {
+ if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) {
if (file->typeflag & FILE_TYPE_DIR) {
if (file->typeflag &
(FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
@@ -704,6 +728,7 @@ static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileLis
}
}
}
+ /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
if (is_filtered && (filter->filter_search[0] != '\0')) {
if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) {
is_filtered = false;
@@ -870,7 +895,7 @@ void filelist_free_icons(void)
BLI_assert(G.background == false);
- for (i = 0; i < SPECIAL_IMG_MAX; ++i) {
+ for (i = 0; i < SPECIAL_IMG_MAX; i++) {
IMB_freeImBuf(gSpecialFileImages[i]);
gSpecialFileImages[i] = NULL;
}
@@ -904,42 +929,12 @@ static ImBuf *filelist_geticon_image_ex(const unsigned int typeflag, const char
if (FILENAME_IS_PARENT(relpath)) {
ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT];
}
- else if (FILENAME_IS_CURRENT(relpath)) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH];
- }
else {
ibuf = gSpecialFileImages[SPECIAL_IMG_FOLDER];
}
}
- else if (typeflag & FILE_TYPE_BLENDER) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE];
- }
- else if (typeflag & FILE_TYPE_BLENDERLIB) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE];
- }
- else if (typeflag & (FILE_TYPE_MOVIE)) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE];
- }
- else if (typeflag & FILE_TYPE_SOUND) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE];
- }
- else if (typeflag & FILE_TYPE_PYSCRIPT) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE];
- }
- else if (typeflag & FILE_TYPE_FTFONT) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE];
- }
- else if (typeflag & FILE_TYPE_TEXT) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE];
- }
- else if (typeflag & FILE_TYPE_IMAGE) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING];
- }
- else if (typeflag & FILE_TYPE_BLENDER_BACKUP) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_BACKUP];
- }
else {
- ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE];
+ ibuf = gSpecialFileImages[SPECIAL_IMG_DOCUMENT];
}
return ibuf;
@@ -1001,14 +996,20 @@ static int filelist_geticon_ex(const int typeflag,
return ICON_FILE_BLANK;
}
else if (typeflag & FILE_TYPE_COLLADA) {
- return ICON_FILE_BLANK;
+ return ICON_FILE_3D;
}
else if (typeflag & FILE_TYPE_ALEMBIC) {
- return ICON_FILE_BLANK;
+ return ICON_FILE_3D;
+ }
+ else if (typeflag & FILE_TYPE_OBJECT_IO) {
+ return ICON_FILE_3D;
}
else if (typeflag & FILE_TYPE_TEXT) {
return ICON_FILE_TEXT;
}
+ else if (typeflag & FILE_TYPE_ARCHIVE) {
+ return ICON_FILE_ARCHIVE;
+ }
else if (typeflag & FILE_TYPE_BLENDERLIB) {
const int ret = UI_idcode_icon_get(blentype);
if (ret != ICON_NONE) {
@@ -1243,7 +1244,8 @@ static void filelist_cache_previews_clear(FileListEntryCache *cache)
BLI_task_pool_cancel(cache->previews_pool);
while ((preview = BLI_thread_queue_pop_timeout(cache->previews_done, 0))) {
- // printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
+ // printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path,
+ // preview->img);
if (preview->img) {
IMB_freeImBuf(preview->img);
}
@@ -2128,6 +2130,12 @@ int ED_path_extension_type(const char *path)
else if (BLI_path_extension_check(path, ".abc")) {
return FILE_TYPE_ALEMBIC;
}
+ else if (BLI_path_extension_check(path, ".zip")) {
+ return FILE_TYPE_ARCHIVE;
+ }
+ else if (BLI_path_extension_check_n(path, ".obj", ".3ds", ".fbx", ".glb", ".gltf", NULL)) {
+ return FILE_TYPE_OBJECT_IO;
+ }
else if (BLI_path_extension_check_array(path, imb_ext_image)) {
return FILE_TYPE_IMAGE;
}
@@ -2177,11 +2185,13 @@ int ED_file_extension_icon(const char *path)
case FILE_TYPE_BTX:
return ICON_FILE_BLANK;
case FILE_TYPE_COLLADA:
- return ICON_FILE_BLANK;
case FILE_TYPE_ALEMBIC:
- return ICON_FILE_BLANK;
+ case FILE_TYPE_OBJECT_IO:
+ return ICON_FILE_3D;
case FILE_TYPE_TEXT:
return ICON_FILE_TEXT;
+ case FILE_TYPE_ARCHIVE:
+ return ICON_FILE_ARCHIVE;
default:
return ICON_FILE_BLANK;
}
@@ -2298,6 +2308,19 @@ unsigned int filelist_entry_select_index_get(FileList *filelist,
return 0;
}
+/**
+ * Set selection of the '..' parent entry, but only if it's actually visible.
+ */
+void filelist_entry_parent_select_set(FileList *filelist,
+ FileSelType select,
+ unsigned int flag,
+ FileCheckType check)
+{
+ if ((filelist->filter_data.flags & FLF_HIDE_PARENT) == 0) {
+ filelist_entry_select_index_set(filelist, 0, select, flag, check);
+ }
+}
+
/* WARNING! dir must be FILE_MAX_LIBEXTRA long! */
bool filelist_islibrary(struct FileList *filelist, char *dir, char **group)
{
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index caf77246797..9b1107294ff 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -55,7 +55,7 @@ void folderlist_pushdir(struct ListBase *folderlist, const char *dir);
const char *folderlist_peeklastdir(struct ListBase *folderdist);
int folderlist_clear_next(struct SpaceFile *sfile);
-void filelist_setsorting(struct FileList *filelist, const short sort);
+void filelist_setsorting(struct FileList *filelist, const short sort, bool invert_sort);
void filelist_sort(struct FileList *filelist);
void filelist_setfilter_options(struct FileList *filelist,
@@ -117,6 +117,10 @@ unsigned int filelist_entry_select_get(struct FileList *filelist,
unsigned int filelist_entry_select_index_get(struct FileList *filelist,
const int index,
FileCheckType check);
+void filelist_entry_parent_select_set(struct FileList *filelist,
+ FileSelType select,
+ unsigned int flag,
+ FileCheckType check);
void filelist_setrecursion(struct FileList *filelist, const int recursion_level);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index db42d007b8e..e2c9bb8d6e5 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -49,6 +49,10 @@
#include "BLI_utildefines.h"
#include "BLI_fnmatch.h"
+#include "BLO_readfile.h"
+
+#include "BLT_translation.h"
+
#include "BKE_appdir.h"
#include "BKE_context.h"
#include "BKE_main.h"
@@ -69,6 +73,8 @@
#include "file_intern.h"
#include "filelist.h"
+#define VERTLIST_MAJORCOLUMN_WIDTH (25 * UI_UNIT_X)
+
FileSelectParams *ED_fileselect_get_params(struct SpaceFile *sfile)
{
if (!sfile->params) {
@@ -98,7 +104,9 @@ short ED_fileselect_set_params(SpaceFile *sfile)
sizeof(sfile->params->file));
sfile->params->filter_glob[0] = '\0';
/* set the default thumbnails size */
- sfile->params->thumbnail_size = 128;
+ sfile->params->thumbnail_size = U_default.file_space_data.thumbnail_size;
+ /* Show size column by default. */
+ sfile->params->details_flags = U_default.file_space_data.details_flags;
}
params = sfile->params;
@@ -161,6 +169,13 @@ short ED_fileselect_set_params(SpaceFile *sfile)
params->flag &= ~FILE_DIRSEL_ONLY;
}
+ if ((prop = RNA_struct_find_property(op->ptr, "check_existing"))) {
+ params->flag |= RNA_property_boolean_get(op->ptr, prop) ? FILE_CHECK_EXISTING : 0;
+ }
+ if ((prop = RNA_struct_find_property(op->ptr, "hide_props_region"))) {
+ params->flag |= RNA_property_boolean_get(op->ptr, prop) ? FILE_HIDE_TOOL_PROPS : 0;
+ }
+
params->filter = 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_blender"))) {
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BLENDER : 0;
@@ -189,6 +204,9 @@ short ED_fileselect_set_params(SpaceFile *sfile)
if ((prop = RNA_struct_find_property(op->ptr, "filter_text"))) {
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_TEXT : 0;
}
+ if ((prop = RNA_struct_find_property(op->ptr, "filter_archive"))) {
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_ARCHIVE : 0;
+ }
if ((prop = RNA_struct_find_property(op->ptr, "filter_folder"))) {
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_FOLDER : 0;
}
@@ -258,26 +276,11 @@ short ED_fileselect_set_params(SpaceFile *sfile)
params->sort = RNA_property_enum_get(op->ptr, prop);
}
else {
- params->sort = FILE_SORT_ALPHA;
+ params->sort = U_default.file_space_data.sort_type;
}
if (params->display == FILE_DEFAULTDISPLAY) {
- if (params->display_previous == FILE_DEFAULTDISPLAY) {
- if (U.uiflag & USER_SHOW_THUMBNAILS) {
- if (params->filter & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT)) {
- params->display = FILE_IMGDISPLAY;
- }
- else {
- params->display = FILE_SHORTDISPLAY;
- }
- }
- else {
- params->display = FILE_SHORTDISPLAY;
- }
- }
- else {
- params->display = params->display_previous;
- }
+ params->display = U_default.file_space_data.display_type;
}
if (is_relative_path) {
@@ -291,10 +294,9 @@ short ED_fileselect_set_params(SpaceFile *sfile)
else {
/* default values, if no operator */
params->type = FILE_UNIX;
- params->flag |= FILE_HIDE_DOT;
+ params->flag |= U_default.file_space_data.flag;
params->flag &= ~FILE_DIRSEL_ONLY;
- params->display = FILE_SHORTDISPLAY;
- params->display_previous = FILE_DEFAULTDISPLAY;
+ params->display = FILE_VERTICALDISPLAY;
params->sort = FILE_SORT_ALPHA;
params->filter = 0;
params->filter_glob[0] = '\0';
@@ -330,6 +332,63 @@ short ED_fileselect_set_params(SpaceFile *sfile)
return 1;
}
+/* The subset of FileSelectParams.flag items we store into preferences. */
+#define PARAMS_FLAGS_REMEMBERED (FILE_HIDE_DOT | FILE_SORT_INVERT)
+
+void ED_fileselect_set_params_from_userdef(SpaceFile *sfile)
+{
+ wmOperator *op = sfile->op;
+ UserDef_FileSpaceData *sfile_udata = &U.file_space_data;
+
+ ED_fileselect_set_params(sfile);
+
+ if (!op) {
+ return;
+ }
+
+ if (!RNA_struct_property_is_set(op->ptr, "display_type")) {
+ sfile->params->display = sfile_udata->display_type;
+ }
+ if (!RNA_struct_property_is_set(op->ptr, "sort_method")) {
+ sfile->params->sort = sfile_udata->sort_type;
+ }
+ sfile->params->thumbnail_size = sfile_udata->thumbnail_size;
+ sfile->params->details_flags = sfile_udata->details_flags;
+
+ /* Combine flags we take from params with the flags we take from userdef. */
+ sfile->params->flag = (sfile->params->flag & ~PARAMS_FLAGS_REMEMBERED) |
+ (sfile_udata->flag & PARAMS_FLAGS_REMEMBERED);
+}
+
+/**
+ * Update the user-preference data for the file space. In fact, this also contains some
+ * non-FileSelectParams data, but it's neglectable.
+ *
+ * \param temp_win_size: If the browser was opened in a temporary window, pass its size here so we
+ * can store that in the preferences. Otherwise NULL.
+ */
+void ED_fileselect_params_to_userdef(SpaceFile *sfile, int temp_win_size[2])
+{
+ UserDef_FileSpaceData *sfile_udata_new = &U.file_space_data;
+ UserDef_FileSpaceData sfile_udata_old = U.file_space_data;
+
+ sfile_udata_new->display_type = sfile->params->display;
+ sfile_udata_new->thumbnail_size = sfile->params->thumbnail_size;
+ sfile_udata_new->sort_type = sfile->params->sort;
+ sfile_udata_new->details_flags = sfile->params->details_flags;
+ sfile_udata_new->flag = sfile->params->flag & PARAMS_FLAGS_REMEMBERED;
+
+ if (temp_win_size) {
+ sfile_udata_new->temp_win_sizex = temp_win_size[0];
+ sfile_udata_new->temp_win_sizey = temp_win_size[1];
+ }
+
+ /* Tag prefs as dirty if something has changed. */
+ if (memcmp(sfile_udata_new, &sfile_udata_old, sizeof(sfile_udata_old)) != 0) {
+ U.runtime.is_dirty = true;
+ }
+}
+
void ED_fileselect_reset_params(SpaceFile *sfile)
{
sfile->params->type = FILE_UNIX;
@@ -344,7 +403,7 @@ void ED_fileselect_reset_params(SpaceFile *sfile)
void fileselect_file_set(SpaceFile *sfile, const int index)
{
const struct FileDirEntry *file = filelist_file(sfile->files, index);
- if (file && file->relpath && file->relpath[0] && !(file->typeflag & FILE_TYPE_FOLDER)) {
+ if (file && file->relpath && file->relpath[0] && !(file->typeflag & FILE_TYPE_DIR)) {
BLI_strncpy(sfile->params->file, file->relpath, FILE_MAXFILE);
}
}
@@ -372,10 +431,10 @@ int ED_fileselect_layout_numfiles(FileLayout *layout, ARegion *ar)
}
else {
const int y_item = layout->tile_h + (2 * layout->tile_border_y);
- const int y_view = (int)(BLI_rctf_size_y(&ar->v2d.cur));
+ const int y_view = (int)(BLI_rctf_size_y(&ar->v2d.cur)) - layout->offset_top;
const int y_over = y_item - (y_view % y_item);
numfiles = (int)((float)(y_view + y_over) / (float)(y_item));
- return numfiles * layout->columns;
+ return numfiles * layout->flow_columns;
}
}
@@ -395,19 +454,19 @@ FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const rcti *r
}
colmin = (rect->xmin) / (layout->tile_w + 2 * layout->tile_border_x);
- rowmin = (rect->ymin) / (layout->tile_h + 2 * layout->tile_border_y);
+ rowmin = (rect->ymin - layout->offset_top) / (layout->tile_h + 2 * layout->tile_border_y);
colmax = (rect->xmax) / (layout->tile_w + 2 * layout->tile_border_x);
- rowmax = (rect->ymax) / (layout->tile_h + 2 * layout->tile_border_y);
+ rowmax = (rect->ymax - layout->offset_top) / (layout->tile_h + 2 * layout->tile_border_y);
- if (is_inside(colmin, rowmin, layout->columns, layout->rows) ||
- is_inside(colmax, rowmax, layout->columns, layout->rows)) {
- CLAMP(colmin, 0, layout->columns - 1);
+ if (is_inside(colmin, rowmin, layout->flow_columns, layout->rows) ||
+ is_inside(colmax, rowmax, layout->flow_columns, layout->rows)) {
+ CLAMP(colmin, 0, layout->flow_columns - 1);
CLAMP(rowmin, 0, layout->rows - 1);
- CLAMP(colmax, 0, layout->columns - 1);
+ CLAMP(colmax, 0, layout->flow_columns - 1);
CLAMP(rowmax, 0, layout->rows - 1);
}
- if ((colmin > layout->columns - 1) || (rowmin > layout->rows - 1)) {
+ if ((colmin > layout->flow_columns - 1) || (rowmin > layout->rows - 1)) {
sel.first = -1;
}
else {
@@ -415,10 +474,10 @@ FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const rcti *r
sel.first = layout->rows * colmin + rowmin;
}
else {
- sel.first = colmin + layout->columns * rowmin;
+ sel.first = colmin + layout->flow_columns * rowmin;
}
}
- if ((colmax > layout->columns - 1) || (rowmax > layout->rows - 1)) {
+ if ((colmax > layout->flow_columns - 1) || (rowmax > layout->rows - 1)) {
sel.last = -1;
}
else {
@@ -426,7 +485,7 @@ FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const rcti *r
sel.last = layout->rows * colmax + rowmax;
}
else {
- sel.last = colmax + layout->columns * rowmax;
+ sel.last = colmax + layout->flow_columns * rowmax;
}
}
@@ -443,9 +502,9 @@ int ED_fileselect_layout_offset(FileLayout *layout, int x, int y)
}
offsetx = (x) / (layout->tile_w + 2 * layout->tile_border_x);
- offsety = (y) / (layout->tile_h + 2 * layout->tile_border_y);
+ offsety = (y - layout->offset_top) / (layout->tile_h + 2 * layout->tile_border_y);
- if (offsetx > layout->columns - 1) {
+ if (offsetx > layout->flow_columns - 1) {
return -1;
}
if (offsety > layout->rows - 1) {
@@ -456,27 +515,123 @@ int ED_fileselect_layout_offset(FileLayout *layout, int x, int y)
active_file = layout->rows * offsetx + offsety;
}
else {
- active_file = offsetx + layout->columns * offsety;
+ active_file = offsetx + layout->flow_columns * offsety;
}
return active_file;
}
+/**
+ * Get the currently visible bounds of the layout in screen space. Matches View2D.mask minus the
+ * top column-header row.
+ */
+void ED_fileselect_layout_maskrect(const FileLayout *layout, const View2D *v2d, rcti *r_rect)
+{
+ *r_rect = v2d->mask;
+ r_rect->ymax -= layout->offset_top;
+}
+
+bool ED_fileselect_layout_is_inside_pt(const FileLayout *layout, const View2D *v2d, int x, int y)
+{
+ rcti maskrect;
+ ED_fileselect_layout_maskrect(layout, v2d, &maskrect);
+ return BLI_rcti_isect_pt(&maskrect, x, y);
+}
+
+bool ED_fileselect_layout_isect_rect(const FileLayout *layout,
+ const View2D *v2d,
+ const rcti *rect,
+ rcti *r_dst)
+{
+ rcti maskrect;
+ ED_fileselect_layout_maskrect(layout, v2d, &maskrect);
+ return BLI_rcti_isect(&maskrect, rect, r_dst);
+}
+
void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y)
{
if (layout->flag == FILE_LAYOUT_HOR) {
*x = layout->tile_border_x +
(tile / layout->rows) * (layout->tile_w + 2 * layout->tile_border_x);
- *y = layout->tile_border_y +
+ *y = layout->offset_top + layout->tile_border_y +
(tile % layout->rows) * (layout->tile_h + 2 * layout->tile_border_y);
}
else {
*x = layout->tile_border_x +
- ((tile) % layout->columns) * (layout->tile_w + 2 * layout->tile_border_x);
- *y = layout->tile_border_y +
- ((tile) / layout->columns) * (layout->tile_h + 2 * layout->tile_border_y);
+ ((tile) % layout->flow_columns) * (layout->tile_w + 2 * layout->tile_border_x);
+ *y = layout->offset_top + layout->tile_border_y +
+ ((tile) / layout->flow_columns) * (layout->tile_h + 2 * layout->tile_border_y);
}
}
+/**
+ * Check if the region coordinate defined by \a x and \a y are inside the column header.
+ */
+bool file_attribute_column_header_is_inside(const View2D *v2d,
+ const FileLayout *layout,
+ int x,
+ int y)
+{
+ rcti header_rect = v2d->mask;
+ header_rect.ymin = header_rect.ymax - layout->attribute_column_header_h;
+ return BLI_rcti_isect_pt(&header_rect, x, y);
+}
+
+bool file_attribute_column_type_enabled(const FileSelectParams *params,
+ FileAttributeColumnType column)
+{
+ switch (column) {
+ case COLUMN_NAME:
+ /* Always enabled */
+ return true;
+ case COLUMN_DATETIME:
+ return (params->details_flags & FILE_DETAILS_DATETIME) != 0;
+ case COLUMN_SIZE:
+ return (params->details_flags & FILE_DETAILS_SIZE) != 0;
+ default:
+ return false;
+ }
+}
+
+/**
+ * Find the column type at region coordinate given by \a x (y doesn't matter for this).
+ */
+FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d,
+ const FileSelectParams *params,
+ FileLayout *layout,
+ int x)
+{
+ float mx, my;
+ int offset_tile;
+
+ UI_view2d_region_to_view(v2d, x, v2d->mask.ymax - layout->offset_top - 1, &mx, &my);
+ offset_tile = ED_fileselect_layout_offset(
+ layout, (int)(v2d->tot.xmin + mx), (int)(v2d->tot.ymax - my));
+ if (offset_tile > -1) {
+ int tile_x, tile_y;
+ int pos_x = 0;
+ int rel_x; /* x relative to the hovered tile */
+
+ ED_fileselect_layout_tilepos(layout, offset_tile, &tile_x, &tile_y);
+ /* Column header drawing doesn't use left tile border, so subtract it. */
+ rel_x = mx - (tile_x - layout->tile_border_x);
+
+ for (FileAttributeColumnType column = 0; column < ATTRIBUTE_COLUMN_MAX; column++) {
+ if (!file_attribute_column_type_enabled(params, column)) {
+ continue;
+ }
+ const int width = layout->attribute_columns[column].width;
+
+ if (IN_RANGE(rel_x, pos_x, pos_x + width)) {
+ return column;
+ }
+
+ pos_x += width;
+ }
+ }
+
+ return COLUMN_NONE;
+}
+
float file_string_width(const char *str)
{
uiStyle *style = UI_style_get();
@@ -512,20 +667,52 @@ float file_font_pointsize(void)
#endif
}
-static void column_widths(FileSelectParams *params, struct FileLayout *layout)
+static void file_attribute_columns_widths(const FileSelectParams *params, FileLayout *layout)
{
- int i;
+ FileAttributeColumn *columns = layout->attribute_columns;
const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size);
+ const int pad = small_size ? 0 : ATTRIBUTE_COLUMN_PADDING * 2;
- for (i = 0; i < MAX_FILE_COLUMN; ++i) {
- layout->column_widths[i] = 0;
+ for (int i = 0; i < ATTRIBUTE_COLUMN_MAX; i++) {
+ layout->attribute_columns[i].width = 0;
}
- layout->column_widths[COLUMN_NAME] = ((float)params->thumbnail_size / 8.0f) * UI_UNIT_X;
/* Biggest possible reasonable values... */
- layout->column_widths[COLUMN_DATE] = file_string_width(small_size ? "23/08/89" : "23-Dec-89");
- layout->column_widths[COLUMN_TIME] = file_string_width("23:59");
- layout->column_widths[COLUMN_SIZE] = file_string_width(small_size ? "98.7 M" : "98.7 MiB");
+ columns[COLUMN_DATETIME].width = file_string_width(small_size ? "23/08/89" :
+ "23 Dec 6789, 23:59") +
+ pad;
+ columns[COLUMN_SIZE].width = file_string_width(small_size ? "98.7 M" : "098.7 MiB") + pad;
+ if (params->display == FILE_IMGDISPLAY) {
+ columns[COLUMN_NAME].width = ((float)params->thumbnail_size / 8.0f) * UI_UNIT_X;
+ }
+ /* Name column uses remaining width */
+ else {
+ int remwidth = layout->tile_w;
+ for (FileAttributeColumnType column_type = ATTRIBUTE_COLUMN_MAX - 1; column_type >= 0;
+ column_type--) {
+ if ((column_type == COLUMN_NAME) ||
+ !file_attribute_column_type_enabled(params, column_type)) {
+ continue;
+ }
+ remwidth -= columns[column_type].width;
+ }
+ columns[COLUMN_NAME].width = remwidth;
+ }
+}
+
+static void file_attribute_columns_init(const FileSelectParams *params, FileLayout *layout)
+{
+ file_attribute_columns_widths(params, layout);
+
+ layout->attribute_columns[COLUMN_NAME].name = N_("Name");
+ layout->attribute_columns[COLUMN_NAME].sort_type = FILE_SORT_ALPHA;
+ layout->attribute_columns[COLUMN_NAME].text_align = UI_STYLE_TEXT_LEFT;
+ layout->attribute_columns[COLUMN_DATETIME].name = N_("Date Modified");
+ layout->attribute_columns[COLUMN_DATETIME].sort_type = FILE_SORT_TIME;
+ layout->attribute_columns[COLUMN_DATETIME].text_align = UI_STYLE_TEXT_LEFT;
+ layout->attribute_columns[COLUMN_SIZE].name = N_("Size");
+ layout->attribute_columns[COLUMN_SIZE].sort_type = FILE_SORT_SIZE;
+ layout->attribute_columns[COLUMN_SIZE].text_align = UI_STYLE_TEXT_RIGHT;
}
void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
@@ -533,7 +720,6 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
FileSelectParams *params = ED_fileselect_get_params(sfile);
FileLayout *layout = NULL;
View2D *v2d = &ar->v2d;
- int maxlen = 0;
int numfiles;
int textheight;
@@ -560,61 +746,69 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
layout->tile_w = layout->prv_w + 2 * layout->prv_border_x;
layout->tile_h = layout->prv_h + 2 * layout->prv_border_y + textheight;
layout->width = (int)(BLI_rctf_size_x(&v2d->cur) - 2 * layout->tile_border_x);
- layout->columns = layout->width / (layout->tile_w + 2 * layout->tile_border_x);
- if (layout->columns > 0) {
- layout->rows = numfiles / layout->columns + 1; // XXX dirty, modulo is zero
+ layout->flow_columns = layout->width / (layout->tile_w + 2 * layout->tile_border_x);
+ layout->attribute_column_header_h = 0;
+ layout->offset_top = 0;
+ if (layout->flow_columns > 0) {
+ layout->rows = numfiles / layout->flow_columns + 1; // XXX dirty, modulo is zero
}
else {
- layout->columns = 1;
+ layout->flow_columns = 1;
layout->rows = numfiles + 1; // XXX dirty, modulo is zero
}
layout->height = sfile->layout->rows * (layout->tile_h + 2 * layout->tile_border_y) +
- layout->tile_border_y * 2;
+ layout->tile_border_y * 2 - layout->offset_top;
layout->flag = FILE_LAYOUT_VER;
}
- else {
- int column_space = 0.6f * UI_UNIT_X;
- int column_icon_space = 0.2f * UI_UNIT_X;
+ else if (params->display == FILE_VERTICALDISPLAY) {
+ int rowcount;
- layout->prv_w = 0;
- layout->prv_h = 0;
+ layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X;
+ layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y;
+ layout->tile_border_x = 0.4f * UI_UNIT_X;
+ layout->tile_border_y = 0.1f * UI_UNIT_Y;
+ layout->tile_h = textheight * 3 / 2;
+ layout->width = (int)(BLI_rctf_size_x(&v2d->cur) - 2 * layout->tile_border_x);
+ layout->tile_w = layout->width;
+ layout->flow_columns = 1;
+ layout->attribute_column_header_h = layout->tile_h * 1.2f + 2 * layout->tile_border_y;
+ layout->offset_top = layout->attribute_column_header_h;
+ rowcount = (int)(BLI_rctf_size_y(&v2d->cur) - layout->offset_top - 2 * layout->tile_border_y) /
+ (layout->tile_h + 2 * layout->tile_border_y);
+ file_attribute_columns_init(params, layout);
+
+ layout->rows = MAX2(rowcount, numfiles);
+ BLI_assert(layout->rows != 0);
+ layout->height = sfile->layout->rows * (layout->tile_h + 2 * layout->tile_border_y) +
+ layout->tile_border_y * 2 + layout->offset_top;
+ layout->flag = FILE_LAYOUT_VER;
+ }
+ else if (params->display == FILE_HORIZONTALDISPLAY) {
+ layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X;
+ layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y;
layout->tile_border_x = 0.4f * UI_UNIT_X;
layout->tile_border_y = 0.1f * UI_UNIT_Y;
- layout->prv_border_x = 0;
- layout->prv_border_y = 0;
layout->tile_h = textheight * 3 / 2;
+ layout->attribute_column_header_h = 0;
+ layout->offset_top = layout->attribute_column_header_h;
layout->height = (int)(BLI_rctf_size_y(&v2d->cur) - 2 * layout->tile_border_y);
/* Padding by full scrollbar H is too much, can overlap tile border Y. */
layout->rows = (layout->height - V2D_SCROLL_HEIGHT + layout->tile_border_y) /
(layout->tile_h + 2 * layout->tile_border_y);
+ layout->tile_w = VERTLIST_MAJORCOLUMN_WIDTH;
+ file_attribute_columns_init(params, layout);
- column_widths(params, layout);
-
- if (params->display == FILE_SHORTDISPLAY) {
- maxlen = ICON_DEFAULT_WIDTH_SCALE + column_icon_space +
- (int)layout->column_widths[COLUMN_NAME] + column_space +
- (int)layout->column_widths[COLUMN_SIZE] + column_space;
- }
- else {
- maxlen = ICON_DEFAULT_WIDTH_SCALE + column_icon_space +
- (int)layout->column_widths[COLUMN_NAME] + column_space +
- (int)layout->column_widths[COLUMN_DATE] + column_space +
- (int)layout->column_widths[COLUMN_TIME] + column_space +
- (int)layout->column_widths[COLUMN_SIZE] + column_space;
- }
- layout->tile_w = maxlen;
if (layout->rows > 0) {
- layout->columns = numfiles / layout->rows + 1; // XXX dirty, modulo is zero
+ layout->flow_columns = numfiles / layout->rows + 1; // XXX dirty, modulo is zero
}
else {
layout->rows = 1;
- layout->columns = numfiles + 1; // XXX dirty, modulo is zero
+ layout->flow_columns = numfiles + 1; // XXX dirty, modulo is zero
}
- layout->width = sfile->layout->columns * (layout->tile_w + 2 * layout->tile_border_x) +
+ layout->width = sfile->layout->flow_columns * (layout->tile_w + 2 * layout->tile_border_x) +
layout->tile_border_x * 2;
layout->flag = FILE_LAYOUT_HOR;
}
- params->display_previous = params->display;
layout->dirty = false;
}
@@ -742,7 +936,7 @@ int autocomplete_file(struct bContext *C, char *str, void *UNUSED(arg_v))
int nentries = filelist_files_ensure(sfile->files);
int i;
- for (i = 0; i < nentries; ++i) {
+ for (i = 0; i < nentries; i++) {
FileDirEntry *file = filelist_file(sfile->files, i);
UI_autocomplete_update_name(autocpl, file->relpath);
}
@@ -771,6 +965,17 @@ void ED_fileselect_exit(wmWindowManager *wm, ScrArea *sa, SpaceFile *sfile)
return;
}
if (sfile->op) {
+ wmWindow *temp_win = WM_window_is_temp_screen(wm->winactive) ? wm->winactive : NULL;
+ int win_size[2];
+
+ if (temp_win) {
+ /* Get DPI/pixelsize independent size to be stored in preferences. */
+ WM_window_set_dpi(temp_win); /* Ensure the DPI is taken from the right window. */
+ win_size[0] = WM_window_pixels_x(temp_win) / UI_DPI_FAC;
+ win_size[1] = WM_window_pixels_y(temp_win) / UI_DPI_FAC;
+ }
+ ED_fileselect_params_to_userdef(sfile, temp_win ? win_size : NULL);
+
WM_event_fileselect_event(wm, sfile->op, EVT_FILESELECT_EXTERNAL_CANCEL);
sfile->op = NULL;
}
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index b50c37baae6..7faa2b883f2 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -404,7 +404,7 @@ void fsmenu_write_file(struct FSMenu *fsmenu, const char *filename)
fprintf(fp, "[Recent]\n");
for (fsm_iter = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_RECENT);
fsm_iter && (nwritten < FSMENU_RECENT_MAX);
- fsm_iter = fsm_iter->next, ++nwritten) {
+ fsm_iter = fsm_iter->next, nwritten++) {
if (fsm_iter->path && fsm_iter->save) {
fsmenu_entry_generate_name(fsm_iter, fsm_name, sizeof(fsm_name));
if (fsm_iter->name[0] && !STREQ(fsm_iter->name, fsm_name)) {
@@ -492,20 +492,17 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
/* Flee from horrible win querying hover floppy drives! */
if (i > 1) {
- /* Try to get volume label as well... */
+ /* Try to get a friendly drive description. */
+ SHFILEINFOW shFile = {0};
BLI_strncpy_wchar_from_utf8(wline, tmps, 4);
- if (GetVolumeInformationW(
- wline, wline + 4, FILE_MAXDIR - 4, NULL, NULL, NULL, NULL, 0)) {
- size_t label_len;
-
- BLI_strncpy_wchar_as_utf8(line, wline + 4, FILE_MAXDIR - 4);
-
- label_len = MIN2(strlen(line), FILE_MAXDIR - 6);
- BLI_snprintf(line + label_len, 6, " (%.2s)", tmps);
-
+ if (SHGetFileInfoW(wline, 0, &shFile, sizeof(SHFILEINFOW), SHGFI_DISPLAYNAME)) {
+ BLI_strncpy_wchar_as_utf8(line, shFile.szDisplayName, FILE_MAXDIR);
name = line;
}
}
+ if (name == NULL) {
+ name = tmps;
+ }
fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, tmps, name, FS_INSERT_SORTED);
}
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 1fd878e4662..d63fcf402de 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -55,6 +55,40 @@
#include "filelist.h"
#include "GPU_framebuffer.h"
+static ARegion *file_execute_region_ensure(ScrArea *sa, ARegion *ar_prev)
+{
+ ARegion *ar;
+
+ if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE)) != NULL) {
+ return ar;
+ }
+
+ ar = MEM_callocN(sizeof(ARegion), "execute region for file");
+ BLI_insertlinkafter(&sa->regionbase, ar_prev, ar);
+ ar->regiontype = RGN_TYPE_EXECUTE;
+ ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->flag = RGN_FLAG_DYNAMIC_SIZE;
+
+ return ar;
+}
+
+static ARegion *file_tool_props_region_ensure(ScrArea *sa, ARegion *ar_prev)
+{
+ ARegion *ar;
+
+ if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS)) != NULL) {
+ return ar;
+ }
+
+ /* add subdiv level; after execute region */
+ ar = MEM_callocN(sizeof(ARegion), "tool props for file");
+ BLI_insertlinkafter(&sa->regionbase, ar_prev, ar);
+ ar->regiontype = RGN_TYPE_TOOL_PROPS;
+ ar->alignment = RGN_ALIGN_RIGHT;
+
+ return ar;
+}
+
/* ******************** default callbacks for file space ***************** */
static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
@@ -78,17 +112,14 @@ static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scen
ar->regiontype = RGN_TYPE_TOOLS;
ar->alignment = RGN_ALIGN_LEFT;
- /* Tool props (aka operator) region */
- ar = MEM_callocN(sizeof(ARegion), "tool props region for file");
- BLI_addtail(&sfile->regionbase, ar);
- ar->regiontype = RGN_TYPE_TOOL_PROPS;
- ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
-
/* ui list region */
ar = MEM_callocN(sizeof(ARegion), "ui region for file");
BLI_addtail(&sfile->regionbase, ar);
ar->regiontype = RGN_TYPE_UI;
ar->alignment = RGN_ALIGN_TOP;
+ ar->flag |= RGN_FLAG_DYNAMIC_SIZE;
+
+ /* Tool props and execute region are added as needed, see file_refresh(). */
/* main region */
ar = MEM_callocN(sizeof(ARegion), "main region for file");
@@ -201,9 +232,50 @@ static SpaceLink *file_duplicate(SpaceLink *sl)
return (SpaceLink *)sfilen;
}
+static void file_ensure_valid_region_state(bContext *C,
+ wmWindowManager *wm,
+ wmWindow *win,
+ ScrArea *sa,
+ SpaceFile *sfile,
+ FileSelectParams *params)
+{
+ ARegion *ar_ui = BKE_area_find_region_type(sa, RGN_TYPE_UI);
+ ARegion *ar_props = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS);
+ ARegion *ar_execute = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE);
+ bool needs_init = false; /* To avoid multiple ED_area_initialize() calls. */
+
+ /* If there's an file-operation, ensure we have the option and execute region */
+ if (sfile->op && (ar_props == NULL)) {
+ ar_execute = file_execute_region_ensure(sa, ar_ui);
+ ar_props = file_tool_props_region_ensure(sa, ar_execute);
+
+ if (params->flag & FILE_HIDE_TOOL_PROPS) {
+ ar_props->flag |= RGN_FLAG_HIDDEN;
+ }
+ else {
+ ar_props->flag &= ~RGN_FLAG_HIDDEN;
+ }
+
+ needs_init = true;
+ }
+ /* If there's _no_ file-operation, ensure we _don't_ have the option and execute region */
+ else if ((sfile->op == NULL) && (ar_props != NULL)) {
+ BLI_assert(ar_execute != NULL);
+
+ ED_region_remove(C, sa, ar_props);
+ ED_region_remove(C, sa, ar_execute);
+ needs_init = true;
+ }
+
+ if (needs_init) {
+ ED_area_initialize(wm, win, sa);
+ }
+}
+
static void file_refresh(const bContext *C, ScrArea *sa)
{
wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelectParams *params = ED_fileselect_get_params(sfile);
struct FSMenu *fsmenu = ED_fsmenu_get();
@@ -217,15 +289,16 @@ static void file_refresh(const bContext *C, ScrArea *sa)
}
filelist_setdir(sfile->files, params->dir);
filelist_setrecursion(sfile->files, params->recursion_level);
- filelist_setsorting(sfile->files, params->sort);
- filelist_setfilter_options(sfile->files,
- (params->flag & FILE_FILTER) != 0,
- (params->flag & FILE_HIDE_DOT) != 0,
- false, /* TODO hide_parent, should be controllable? */
- params->filter,
- params->filter_id,
- params->filter_glob,
- params->filter_search);
+ filelist_setsorting(sfile->files, params->sort, params->flag & FILE_SORT_INVERT);
+ filelist_setfilter_options(
+ sfile->files,
+ (params->flag & FILE_FILTER) != 0,
+ (params->flag & FILE_HIDE_DOT) != 0,
+ true, /* Just always hide parent, prefer to not add an extra user option for this. */
+ params->filter,
+ params->filter_id,
+ params->filter_glob,
+ params->filter_search);
/* Update the active indices of bookmarks & co. */
sfile->systemnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_SYSTEM, params->dir);
@@ -254,7 +327,7 @@ static void file_refresh(const bContext *C, ScrArea *sa)
else {
filelist_cache_previews_set(sfile->files, false);
if (sfile->previews_timer) {
- WM_event_remove_timer_notifier(wm, CTX_wm_window(C), sfile->previews_timer);
+ WM_event_remove_timer_notifier(wm, win, sfile->previews_timer);
sfile->previews_timer = NULL;
}
}
@@ -268,11 +341,8 @@ static void file_refresh(const bContext *C, ScrArea *sa)
}
/* Might be called with NULL sa, see file_main_region_draw() below. */
- if (sa && BKE_area_find_region_type(sa, RGN_TYPE_TOOLS) == NULL) {
- /* Create TOOLS/TOOL_PROPS regions. */
- file_tools_region(sa);
-
- ED_area_initialize(wm, CTX_wm_window(C), sa);
+ if (sa) {
+ file_ensure_valid_region_state((bContext *)C, wm, win, sa, sfile, params);
}
ED_area_tag_redraw(sa);
@@ -406,6 +476,11 @@ static void file_main_region_draw(const bContext *C, ARegion *ar)
v2d->keepofs &= ~V2D_LOCKOFS_Y;
v2d->keepofs |= V2D_LOCKOFS_X;
}
+ else if (params->display == FILE_VERTICALDISPLAY) {
+ v2d->scroll = V2D_SCROLL_RIGHT;
+ v2d->keepofs &= ~V2D_LOCKOFS_Y;
+ v2d->keepofs |= V2D_LOCKOFS_X;
+ }
else {
v2d->scroll = V2D_SCROLL_BOTTOM;
v2d->keepofs &= ~V2D_LOCKOFS_X;
@@ -439,7 +514,9 @@ static void file_main_region_draw(const bContext *C, ARegion *ar)
UI_view2d_view_restore(C);
/* scrollers */
- scrollers = UI_view2d_scrollers_calc(v2d, NULL);
+ rcti view_rect;
+ ED_fileselect_layout_maskrect(sfile->layout, v2d, &view_rect);
+ scrollers = UI_view2d_scrollers_calc(v2d, &view_rect);
UI_view2d_scrollers_draw(v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
}
@@ -452,13 +529,13 @@ static void file_operatortypes(void)
WM_operatortype_append(FILE_OT_select_box);
WM_operatortype_append(FILE_OT_select_bookmark);
WM_operatortype_append(FILE_OT_highlight);
+ WM_operatortype_append(FILE_OT_sort_column_ui_context);
WM_operatortype_append(FILE_OT_execute);
WM_operatortype_append(FILE_OT_cancel);
WM_operatortype_append(FILE_OT_parent);
WM_operatortype_append(FILE_OT_previous);
WM_operatortype_append(FILE_OT_next);
WM_operatortype_append(FILE_OT_refresh);
- WM_operatortype_append(FILE_OT_bookmark_toggle);
WM_operatortype_append(FILE_OT_bookmark_add);
WM_operatortype_append(FILE_OT_bookmark_delete);
WM_operatortype_append(FILE_OT_bookmark_cleanup);
@@ -538,7 +615,8 @@ static void file_ui_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
- UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy);
+ ED_region_panels_init(wm, ar);
+ ar->v2d.keepzoom |= V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y;
/* own keymap */
keymap = WM_keymap_ensure(wm->defaultconf, "File Browser", SPACE_FILE, 0);
@@ -550,22 +628,24 @@ static void file_ui_region_init(wmWindowManager *wm, ARegion *ar)
static void file_ui_region_draw(const bContext *C, ARegion *ar)
{
- float col[3];
- /* clear */
- UI_GetThemeColor3fv(TH_BACK, col);
- GPU_clear_color(col[0], col[1], col[2], 0.0);
- GPU_clear(GPU_COLOR_BIT);
+ ED_region_panels(C, ar);
+}
- /* scrolling here is just annoying, disable it */
- ar->v2d.cur.ymax = BLI_rctf_size_y(&ar->v2d.cur);
- ar->v2d.cur.ymin = 0;
+static void file_execution_region_init(wmWindowManager *wm, ARegion *ar)
+{
+ wmKeyMap *keymap;
- /* set view2d view matrix for scrolling (without scrollers) */
- UI_view2d_view_ortho(&ar->v2d);
+ ED_region_panels_init(wm, ar);
+ ar->v2d.keepzoom |= V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y;
- file_draw_buttons(C, ar);
+ /* own keymap */
+ keymap = WM_keymap_ensure(wm->defaultconf, "File Browser", SPACE_FILE, 0);
+ WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap);
+}
- UI_view2d_view_restore(C);
+static void file_execution_region_draw(const bContext *C, ARegion *ar)
+{
+ ED_region_panels(C, ar);
}
static void file_ui_region_listener(wmWindow *UNUSED(win),
@@ -656,13 +736,22 @@ void ED_spacetype_file(void)
/* regions: ui */
art = MEM_callocN(sizeof(ARegionType), "spacetype file region");
art->regionid = RGN_TYPE_UI;
- art->prefsizey = 60;
art->keymapflag = ED_KEYMAP_UI;
art->listener = file_ui_region_listener;
art->init = file_ui_region_init;
art->draw = file_ui_region_draw;
BLI_addhead(&st->regiontypes, art);
+ /* regions: execution */
+ art = MEM_callocN(sizeof(ARegionType), "spacetype file region");
+ art->regionid = RGN_TYPE_EXECUTE;
+ art->keymapflag = ED_KEYMAP_UI;
+ art->listener = file_ui_region_listener;
+ art->init = file_execution_region_init;
+ art->draw = file_execution_region_draw;
+ BLI_addhead(&st->regiontypes, art);
+ file_execute_region_panels_register(art);
+
/* regions: channels (directories) */
art = MEM_callocN(sizeof(ARegionType), "spacetype file region");
art->regionid = RGN_TYPE_TOOLS;
@@ -677,14 +766,14 @@ void ED_spacetype_file(void)
/* regions: tool properties */
art = MEM_callocN(sizeof(ARegionType), "spacetype file operator region");
art->regionid = RGN_TYPE_TOOL_PROPS;
- art->prefsizex = 0;
- art->prefsizey = 360;
+ art->prefsizex = 240;
+ art->prefsizey = 60;
art->keymapflag = ED_KEYMAP_UI;
art->listener = file_tools_region_listener;
art->init = file_tools_region_init;
art->draw = file_tools_region_draw;
BLI_addhead(&st->regiontypes, art);
- file_panels_register(art);
+ file_tool_props_region_panels_register(art);
BKE_spacetype_register(st);
}
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index b264a5cb260..33cb1cb0075 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -861,6 +861,15 @@ static void graph_panel_driverVar__transChan(uiLayout *layout, ID *id, DriverVar
sub = uiLayoutColumn(layout, true);
uiItemR(sub, &dtar_ptr, "transform_type", 0, NULL, ICON_NONE);
+
+ if (ELEM(dtar->transChan,
+ DTAR_TRANSCHAN_ROTX,
+ DTAR_TRANSCHAN_ROTY,
+ DTAR_TRANSCHAN_ROTZ,
+ DTAR_TRANSCHAN_ROTW)) {
+ uiItemR(sub, &dtar_ptr, "rotation_mode", 0, IFACE_("Mode"), ICON_NONE);
+ }
+
uiItemR(sub, &dtar_ptr, "transform_space", 0, IFACE_("Space"), ICON_NONE);
}
@@ -1147,8 +1156,12 @@ static void graph_draw_driver_settings_panel(uiLayout *layout,
if ((dvar->type == DVAR_TYPE_ROT_DIFF) ||
(dvar->type == DVAR_TYPE_TRANSFORM_CHAN &&
- dvar->targets[0].transChan >= DTAR_TRANSCHAN_ROTX &&
- dvar->targets[0].transChan < DTAR_TRANSCHAN_SCALEX)) {
+ ELEM(dvar->targets[0].transChan,
+ DTAR_TRANSCHAN_ROTX,
+ DTAR_TRANSCHAN_ROTY,
+ DTAR_TRANSCHAN_ROTZ,
+ DTAR_TRANSCHAN_ROTW) &&
+ dvar->targets[0].rotation_mode != DTAR_ROTMODE_QUATERNION)) {
BLI_snprintf(
valBuf, sizeof(valBuf), "%.3f (%4.1f°)", dvar->curval, RAD2DEGF(dvar->curval));
}
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index e7ba498fc11..42a1566629a 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -39,7 +39,6 @@
#include "BKE_curve.h"
#include "BKE_fcurve.h"
-#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
#include "GPU_state.h"
@@ -205,7 +204,7 @@ static void draw_fcurve_keyframe_vertices(FCurve *fcu, View2D *v2d, bool edit, u
{
immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
- immUniform1f("size", UI_GetThemeValuef(TH_VERTEX_SIZE) * U.pixelsize);
+ immUniform1f("size", UI_GetThemeValuef(TH_VERTEX_SIZE) * U.dpi_fac);
draw_fcurve_selected_keyframe_vertices(fcu, v2d, edit, false, pos);
draw_fcurve_selected_keyframe_vertices(fcu, v2d, edit, true, pos);
@@ -269,8 +268,8 @@ static void draw_fcurve_handle_vertices(FCurve *fcu,
immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
/* set handle size */
- immUniform1f("size", (1.4f * UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE)) * U.pixelsize);
- immUniform1f("outlineWidth", 1.5f * U.pixelsize);
+ immUniform1f("size", (1.4f * UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE)) * U.dpi_fac);
+ immUniform1f("outlineWidth", 1.5f * U.dpi_fac);
draw_fcurve_selected_handle_vertices(fcu, v2d, false, sel_handle_only, pos);
draw_fcurve_selected_handle_vertices(fcu, v2d, true, sel_handle_only, pos);
@@ -880,10 +879,6 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
float offset;
float unitfac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset);
- /* for now, only show when debugging driver... */
- // if ((driver->flag & DRIVER_FLAG_SHOWDEBUG) == 0)
- // return;
-
const uint shdr_pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index b624e21937f..59cf5f63de3 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -1538,7 +1538,7 @@ void GRAPH_OT_sound_bake(wmOperatorType *ot)
FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE,
FILE_SPECIAL,
FILE_OPENFILE,
- WM_FILESEL_FILEPATH,
+ WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
RNA_def_float(ot->srna,
@@ -2506,28 +2506,28 @@ static const EnumPropertyItem prop_graphkeys_mirror_types[] = {
{GRAPHKEYS_MIRROR_CFRA,
"CFRA",
0,
- "By Times over Current Frame",
+ "By Times Over Current Frame",
"Flip times of selected keyframes using the current frame as the mirror line"},
{GRAPHKEYS_MIRROR_VALUE,
"VALUE",
0,
- "By Values over Cursor Value",
+ "By Values Over Cursor Value",
"Flip values of selected keyframes using the cursor value (Y/Horizontal component) as the "
"mirror line"},
{GRAPHKEYS_MIRROR_YAXIS,
"YAXIS",
0,
- "By Times over Time=0",
+ "By Times Over Time=0",
"Flip times of selected keyframes, effectively reversing the order they appear in"},
{GRAPHKEYS_MIRROR_XAXIS,
"XAXIS",
0,
- "By Values over Value=0",
+ "By Values Over Value=0",
"Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"},
{GRAPHKEYS_MIRROR_MARKER,
"MARKER",
0,
- "By Times over First Selected Marker",
+ "By Times Over First Selected Marker",
"Flip times of selected keyframes using the first selected marker as the reference point"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt
index 61e6b065cba..5abcff436f1 100644
--- a/source/blender/editors/space_image/CMakeLists.txt
+++ b/source/blender/editors/space_image/CMakeLists.txt
@@ -29,6 +29,7 @@ set(INC
../../makesrna
../../render/extern/include
../../windowmanager
+ ../../../../intern/clog
../../../../intern/glew-mx
../../../../intern/guardedalloc
)
@@ -42,6 +43,7 @@ set(SRC
image_draw.c
image_edit.c
image_ops.c
+ image_undo.c
space_image.c
image_intern.h
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index ccd0a2bfd79..ec2b1cc7fbe 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -301,6 +301,18 @@ void ED_image_mouse_pos(SpaceImage *sima, ARegion *ar, const int mval[2], float
co[1] = ((mval[1] - sy) / zoomy) / height;
}
+void ED_image_view_center_to_point(SpaceImage *sima, float x, float y)
+{
+ int width, height;
+ float aspx, aspy;
+
+ ED_space_image_get_size(sima, &width, &height);
+ ED_space_image_get_aspect(sima, &aspx, &aspy);
+
+ sima->xof = (x - 0.5f) * width * aspx;
+ sima->yof = (y - 0.5f) * height * aspy;
+}
+
void ED_image_point_pos(SpaceImage *sima, ARegion *ar, float x, float y, float *xr, float *yr)
{
int sx, sy, width, height;
@@ -476,3 +488,9 @@ bool ED_space_image_maskedit_mask_poll(bContext *C)
return false;
}
+
+bool ED_space_image_cursor_poll(bContext *C)
+{
+ return ED_operator_uvedit_space_image(C) || ED_space_image_maskedit_poll(C) ||
+ ED_space_image_paint_curve(C);
+}
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index 1abb6715fdb..f8ce065d46c 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -44,10 +44,12 @@ void draw_image_sample_line(struct SpaceImage *sima);
/* image_ops.c */
bool space_image_main_region_poll(struct bContext *C);
+bool space_image_view_center_cursor_poll(struct bContext *C);
void IMAGE_OT_view_all(struct wmOperatorType *ot);
void IMAGE_OT_view_pan(struct wmOperatorType *ot);
void IMAGE_OT_view_selected(struct wmOperatorType *ot);
+void IMAGE_OT_view_center_cursor(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom_in(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom_out(struct wmOperatorType *ot);
@@ -70,6 +72,7 @@ void IMAGE_OT_pack(struct wmOperatorType *ot);
void IMAGE_OT_unpack(struct wmOperatorType *ot);
void IMAGE_OT_invert(struct wmOperatorType *ot);
+void IMAGE_OT_resize(struct wmOperatorType *ot);
void IMAGE_OT_cycle_render_slot(struct wmOperatorType *ot);
void IMAGE_OT_clear_render_slot(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 7ea693f2fd2..39f7bf001f3 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -103,7 +103,9 @@
#include "image_intern.h"
-/******************** view navigation utilities *********************/
+/* -------------------------------------------------------------------- */
+/** \name View Navigation Utilities
+ * \{ */
static void sima_zoom_set(
SpaceImage *sima, ARegion *ar, float zoom, const float location[2], const bool zoom_to_pos)
@@ -211,7 +213,7 @@ static ImageUser *image_user_from_context(const bContext *C)
}
}
-static bool image_buffer_exists_from_context(bContext *C)
+static bool image_from_context_has_data_poll(bContext *C)
{
Image *ima = image_from_context(C);
ImageUser *iuser = image_user_from_context(C);
@@ -227,6 +229,16 @@ static bool image_buffer_exists_from_context(bContext *C)
return has_buffer;
}
+/**
+ * Use this when the image buffer is accessed without the image user.
+ */
+static bool image_from_contect_has_data_poll_no_image_user(bContext *C)
+{
+ Image *ima = image_from_context(C);
+
+ return BKE_image_has_ibuf(ima, NULL);
+}
+
static bool image_not_packed_poll(bContext *C)
{
/* Do not run 'replace' on packed images, it does not give user expected results at all. */
@@ -280,7 +292,12 @@ static bool image_sample_poll(bContext *C)
return true;
}
-/********************** view pan operator *********************/
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Pan Operator
+ * \{ */
typedef struct ViewPanData {
float x, y;
@@ -300,7 +317,7 @@ static void image_view_pan_init(bContext *C, wmOperator *op, const wmEvent *even
/* Grab will be set when running from gizmo. */
vpd->own_cursor = (win->grabcursor == 0);
if (vpd->own_cursor) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
vpd->x = event->x;
@@ -423,7 +440,11 @@ void IMAGE_OT_view_pan(wmOperatorType *ot)
FLT_MAX);
}
-/********************** view zoom operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom Operator
+ * \{ */
typedef struct ViewZoomData {
float origx, origy;
@@ -453,7 +474,7 @@ static void image_view_zoom_init(bContext *C, wmOperator *op, const wmEvent *eve
/* Grab will be set when running from gizmo. */
vpd->own_cursor = (win->grabcursor == 0);
if (vpd->own_cursor) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
vpd->origx = event->x;
@@ -671,7 +692,12 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot)
}
#ifdef WITH_INPUT_NDOF
-/********************** NDOF operator *********************/
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NDOF Operator
+ * \{ */
/* Combined pan/zoom from a 3D mouse device.
* Z zooms, XY pans
@@ -721,9 +747,14 @@ void IMAGE_OT_view_ndof(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_LOCK_BYPASS;
}
+
+/** \} */
+
#endif /* WITH_INPUT_NDOF */
-/********************** view all operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name View All Operator
+ * \{ */
/* Updates the fields of the View2D member of the SpaceImage struct.
* Default behavior is to reset the position of the image and set the zoom to 1
@@ -800,7 +831,41 @@ void IMAGE_OT_view_all(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/********************** view selected operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Center View To Cursor Operator
+ * \{ */
+
+static int view_center_cursor_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ ED_image_view_center_to_point(sima, sima->cursor[0], sima->cursor[1]);
+
+ ED_region_tag_redraw(ar);
+
+ return OPERATOR_FINISHED;
+}
+
+void IMAGE_OT_view_center_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Center View to Cursor";
+ ot->description = "Center the view so that the cursor is in the middle of the view";
+ ot->idname = "IMAGE_OT_view_center_cursor";
+
+ /* api callbacks */
+ ot->exec = view_center_cursor_exec;
+ ot->poll = ED_space_image_cursor_poll;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Selected Operator
+ * \{ */
static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -866,7 +931,11 @@ void IMAGE_OT_view_selected(wmOperatorType *ot)
ot->poll = image_view_selected_poll;
}
-/********************** view zoom in/out operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom In/Out Operator
+ * \{ */
static int image_view_zoom_in_exec(bContext *C, wmOperator *op)
{
@@ -984,7 +1053,11 @@ void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
-/********************** view zoom ratio operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom Ratio Operator
+ * \{ */
static int image_view_zoom_ratio_exec(bContext *C, wmOperator *op)
{
@@ -1028,7 +1101,11 @@ void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot)
FLT_MAX);
}
-/********************** view border-zoom operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Border-Zoom Operator
+ * \{ */
static int image_view_zoom_border_exec(bContext *C, wmOperator *op)
{
@@ -1084,14 +1161,18 @@ void IMAGE_OT_view_zoom_border(wmOperatorType *ot)
WM_operator_properties_gesture_box_zoom(ot);
}
-/**************** load/replace/save callbacks ******************/
+/* load/replace/save callbacks */
static void image_filesel(bContext *C, wmOperator *op, const char *path)
{
RNA_string_set(op->ptr, "filepath", path);
WM_event_add_fileselect(C, op);
}
-/******************** open image operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Open Image Operator
+ * \{ */
typedef struct ImageOpenData {
PropertyPointerRNA pprop;
@@ -1525,7 +1606,12 @@ void IMAGE_OT_open(wmOperatorType *ot)
"Automatically detect animated sequences in selected images (based on file names)");
}
-/******************** Match movie length operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Match Movie Length Operator
+ * \{ */
+
static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -1571,7 +1657,11 @@ void IMAGE_OT_match_movie_length(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL /* | OPTYPE_UNDO */;
}
-/******************** replace image operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Replace Image Operator
+ * \{ */
static int image_replace_exec(bContext *C, wmOperator *op)
{
@@ -1656,7 +1746,11 @@ void IMAGE_OT_replace(wmOperatorType *ot)
FILE_SORT_ALPHA);
}
-/******************** save image as operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Save Image As Operator
+ * \{ */
static char imtype_best_depth(ImBuf *ibuf, const char imtype)
{
@@ -1773,6 +1867,7 @@ static int image_save_options_init(Main *bmain,
}
else {
BLI_snprintf(opts->filepath, sizeof(opts->filepath), "//%s", ima->id.name + 2);
+ BLI_path_make_safe(opts->filepath);
BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain));
}
}
@@ -1969,7 +2064,7 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
static bool image_save_as_poll(bContext *C)
{
- if (!image_buffer_exists_from_context(C)) {
+ if (!image_from_context_has_data_poll(C)) {
return false;
}
@@ -2020,12 +2115,16 @@ void IMAGE_OT_save_as(wmOperatorType *ot)
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
FILE_SPECIAL,
FILE_SAVE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
}
-/******************** save image operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Save Image Operator
+ * \{ */
static bool image_file_path_saveable(bContext *C, Image *ima, ImageUser *iuser)
{
@@ -2066,7 +2165,7 @@ static bool image_file_path_saveable(bContext *C, Image *ima, ImageUser *iuser)
static bool image_save_poll(bContext *C)
{
/* Can't save if there are no pixels. */
- if (image_buffer_exists_from_context(C) == false) {
+ if (image_from_context_has_data_poll(C) == false) {
return false;
}
@@ -2146,7 +2245,11 @@ void IMAGE_OT_save(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/******************* save sequence operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Save Sequence Operator
+ * \{ */
static int image_save_sequence_exec(bContext *C, wmOperator *op)
{
@@ -2195,7 +2298,12 @@ static int image_save_sequence_exec(bContext *C, wmOperator *op)
/* get a filename for menu */
BLI_split_dir_part(first_ibuf->name, di, sizeof(di));
- BKE_reportf(op->reports, RPT_INFO, "%d image(s) will be saved in %s", tot, di);
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ tot == 1 ? "%d image will be saved in %s" :
+ "%d images will be saved in %s",
+ tot,
+ di);
iter = IMB_moviecacheIter_new(image->cache);
while (!IMB_moviecacheIter_done(iter)) {
@@ -2232,13 +2340,17 @@ void IMAGE_OT_save_sequence(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_save_sequence_exec;
- ot->poll = image_buffer_exists_from_context;
+ ot->poll = image_from_context_has_data_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** save all operator **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Save All Operator
+ * \{ */
static bool image_should_be_saved_when_modified(Image *ima)
{
@@ -2388,7 +2500,11 @@ void IMAGE_OT_save_all_modified(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/******************** reload image operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reload Image Operator
+ * \{ */
static int image_reload_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -2425,7 +2541,12 @@ void IMAGE_OT_reload(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER; /* no undo, image buffer is not handled by undo */
}
-/********************** new image operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name New Image Operator
+ * \{ */
+
#define IMA_DEF_NAME N_("Untitled")
enum {
@@ -2641,22 +2762,18 @@ void IMAGE_OT_new(wmOperatorType *ot)
#undef IMA_DEF_NAME
-/********************* invert operators *********************/
-
-static bool image_invert_poll(bContext *C)
-{
- Image *ima = image_from_context(C);
+/** \} */
- return BKE_image_has_ibuf(ima, NULL);
-}
+/* -------------------------------------------------------------------- */
+/** \name Invert Operators
+ * \{ */
static int image_invert_exec(bContext *C, wmOperator *op)
{
Image *ima = image_from_context(C);
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
SpaceImage *sima = CTX_wm_space_image(C);
- /* undo is supported only on image paint mode currently */
- bool support_undo = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
+ const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
/* flags indicate if this channel should be inverted */
const bool r = RNA_boolean_get(op->ptr, "invert_r");
@@ -2671,14 +2788,12 @@ static int image_invert_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (support_undo) {
- ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
- /* not strictly needed, because we only imapaint_dirty_region to invalidate all tiles
- * but better do this right in case someone copies this for a tool that uses partial
- * redraw better */
+ ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf);
+
+ if (is_paint) {
ED_imapaint_clear_partial_redraw();
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
}
+
/* TODO: make this into an IMB_invert_channels(ibuf,r,g,b,a) method!? */
if (ibuf->rect_float) {
@@ -2732,9 +2847,7 @@ static int image_invert_exec(bContext *C, wmOperator *op)
ibuf->userflags |= IB_MIPMAP_INVALID;
}
- if (support_undo) {
- ED_image_undo_push_end();
- }
+ ED_image_undo_push_end();
/* force GPU reupload, all image is invalid */
GPU_free_image(ima);
@@ -2757,7 +2870,7 @@ void IMAGE_OT_invert(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_invert_exec;
- ot->poll = image_invert_poll;
+ ot->poll = image_from_contect_has_data_poll_no_image_user;
/* properties */
prop = RNA_def_boolean(ot->srna, "invert_r", 0, "Red", "Invert Red Channel");
@@ -2770,10 +2883,96 @@ void IMAGE_OT_invert(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Scale Operator
+ * \{ */
+
+static int image_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Image *ima = image_from_context(C);
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ const int size[2] = {ibuf->x, ibuf->y};
+ RNA_property_int_set_array(op->ptr, prop, size);
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
+ return WM_operator_props_dialog_popup(C, op, 200, 200);
+}
+
+static int image_scale_exec(bContext *C, wmOperator *op)
+{
+ Image *ima = image_from_context(C);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
+
+ if (ibuf == NULL) {
+ /* TODO: this should actually never happen, but does for render-results -> cleanup */
+ return OPERATOR_CANCELLED;
+ }
+
+ if (is_paint) {
+ ED_imapaint_clear_partial_redraw();
+ }
+
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
+ int size[2];
+ if (RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_int_get_array(op->ptr, prop, size);
+ }
+ else {
+ size[0] = ibuf->x;
+ size[1] = ibuf->y;
+ RNA_property_int_set_array(op->ptr, prop, size);
+ }
+
+ ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf);
+
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+ IMB_scaleImBuf(ibuf, size[0], size[1]);
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+
+ ED_image_undo_push_end();
+
+ /* force GPU reupload, all image is invalid */
+ GPU_free_image(ima);
+
+ DEG_id_tag_update(&ima->id, 0);
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
+
+ return OPERATOR_FINISHED;
}
-/********************* pack operator *********************/
+void IMAGE_OT_resize(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Resize Image";
+ ot->idname = "IMAGE_OT_resize";
+ ot->description = "Resize the image";
+
+ /* api callbacks */
+ ot->invoke = image_scale_invoke;
+ ot->exec = image_scale_exec;
+ ot->poll = image_from_contect_has_data_poll_no_image_user;
+
+ /* properties */
+ RNA_def_int_vector(ot->srna, "size", 2, NULL, 1, INT_MAX, "Size", "", 1, SHRT_MAX);
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pack Operator
+ * \{ */
static bool image_pack_test(bContext *C, wmOperator *op)
{
@@ -2826,7 +3025,11 @@ void IMAGE_OT_pack(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************* unpack operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Unpack Operator
+ * \{ */
static int image_unpack_exec(bContext *C, wmOperator *op)
{
@@ -2925,7 +3128,11 @@ void IMAGE_OT_unpack(wmOperatorType *ot)
ot->srna, "id", NULL, MAX_ID_NAME - 2, "Image Name", "Image data-block name to unpack");
}
-/******************** sample image operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sample Image Operator
+ * \{ */
typedef struct ImageSampleInfo {
ARegionType *art;
@@ -3338,7 +3545,12 @@ void IMAGE_OT_sample(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/******************** sample line operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sample Line Operator
+ * \{ */
+
static int image_sample_line_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -3420,10 +3632,14 @@ void IMAGE_OT_sample_line(wmOperatorType *ot)
/* flags */
ot->flag = 0; /* no undo/register since this operates on the space */
- WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
+ WM_operator_properties_gesture_straightline(ot, WM_CURSOR_EDIT);
}
-/******************** set curve point operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Curve Point Operator
+ * \{ */
void IMAGE_OT_curves_point_set(wmOperatorType *ot)
{
@@ -3457,7 +3673,11 @@ void IMAGE_OT_curves_point_set(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/********************* cycle render slot operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cycle Render Slot Operator
+ * \{ */
static bool image_cycle_render_slot_poll(bContext *C)
{
@@ -3503,7 +3723,11 @@ void IMAGE_OT_cycle_render_slot(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "reverse", 0, "Cycle in Reverse", "");
}
-/********************* clear render slot operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clear Render Slot Operator
+ * \{ */
static int image_clear_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3534,7 +3758,11 @@ void IMAGE_OT_clear_render_slot(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
}
-/********************* add render slot operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Render Slot Operator
+ * \{ */
static int image_add_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3563,7 +3791,11 @@ void IMAGE_OT_add_render_slot(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
}
-/********************* remove render slot operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Remove Render Slot Operator
+ * \{ */
static int image_remove_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3594,7 +3826,11 @@ void IMAGE_OT_remove_render_slot(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
}
-/********************** change frame operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Change Frame Operator
+ * \{ */
static bool change_frame_poll(bContext *C)
{
@@ -3745,7 +3981,11 @@ void IMAGE_OT_read_viewlayers(wmOperatorType *ot)
ot->flag = 0;
}
-/* ********************* Render border operator ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Render Border Operator
+ * \{ */
static int render_border_exec(bContext *C, wmOperator *op)
{
@@ -3814,7 +4054,11 @@ void IMAGE_OT_render_border(wmOperatorType *ot)
WM_operator_properties_border(ot);
}
-/* ********************* Clear render border operator ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clear Render Border Operator
+ * \{ */
static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3839,3 +4083,5 @@ void IMAGE_OT_clear_render_border(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/** \} */
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
new file mode 100644
index 00000000000..c450d5122eb
--- /dev/null
+++ b/source/blender/editors/space_image/image_undo.c
@@ -0,0 +1,1032 @@
+/*
+ * 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.
+ *
+ * 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 spimage
+ *
+ * Overview
+ * ========
+ *
+ * - Each undo step is a #ImageUndoStep
+ * - Each #ImageUndoStep stores a list of #UndoImageHandle
+ * - Each #UndoImageHandle stores a list of #UndoImageBuf
+ * (this is the undo systems equivalent of an #ImBuf).
+ * - Each #UndoImageBuf stores an array of #UndoImageTile
+ * The tiles are shared between #UndoImageBuf's to avoid duplication.
+ *
+ * When the undo system manages an image, there will always be a full copy (as a #UndoImageBuf)
+ * each new undo step only stores modified tiles.
+ */
+
+#include "CLG_log.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_threads.h"
+
+#include "DNA_image_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BKE_context.h"
+#include "BKE_image.h"
+#include "BKE_paint.h"
+#include "BKE_undo_system.h"
+
+#include "DEG_depsgraph.h"
+
+#include "ED_paint.h"
+#include "ED_undo.h"
+#include "ED_util.h"
+#include "ED_object.h"
+
+#include "GPU_draw.h"
+
+#include "WM_api.h"
+
+static CLG_LogRef LOG = {"ed.image.undo"};
+
+/* -------------------------------------------------------------------- */
+/** \name Thread Locking
+ * \{ */
+
+/* this is a static resource for non-globality,
+ * Maybe it should be exposed as part of the
+ * paint operation, but for now just give a public interface */
+static SpinLock paint_tiles_lock;
+
+void ED_image_paint_tile_lock_init(void)
+{
+ BLI_spin_init(&paint_tiles_lock);
+}
+
+void ED_image_paint_tile_lock_end(void)
+{
+ BLI_spin_end(&paint_tiles_lock);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Paint Tiles
+ *
+ * Created on demand while painting,
+ * use to access the previous state for some paint operations.
+ *
+ * These buffers are also used for undo when available.
+ *
+ * \{ */
+
+static ImBuf *imbuf_alloc_temp_tile(void)
+{
+ return IMB_allocImBuf(
+ ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE, 32, IB_rectfloat | IB_rect);
+}
+
+typedef struct PaintTile {
+ struct PaintTile *next, *prev;
+ Image *image;
+ ImBuf *ibuf;
+ union {
+ float *fp;
+ uint *uint;
+ void *pt;
+ } rect;
+ ushort *mask;
+ bool valid;
+ bool use_float;
+ int x, y;
+} PaintTile;
+
+static void ptile_free(PaintTile *ptile)
+{
+ if (ptile->rect.pt) {
+ MEM_freeN(ptile->rect.pt);
+ }
+ if (ptile->mask) {
+ MEM_freeN(ptile->mask);
+ }
+ MEM_freeN(ptile);
+}
+
+static void ptile_free_list(ListBase *paint_tiles)
+{
+ for (PaintTile *ptile = paint_tiles->first, *ptile_next; ptile; ptile = ptile_next) {
+ ptile_next = ptile->next;
+ ptile_free(ptile);
+ }
+ BLI_listbase_clear(paint_tiles);
+}
+
+static void ptile_invalidate_list(ListBase *paint_tiles)
+{
+ for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
+ ptile->valid = false;
+ }
+}
+
+void *ED_image_paint_tile_find(ListBase *paint_tiles,
+ Image *image,
+ ImBuf *ibuf,
+ int x_tile,
+ int y_tile,
+ ushort **r_mask,
+ bool validate)
+{
+ for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
+ if (ptile->x == x_tile && ptile->y == y_tile) {
+ if (ptile->image == image && ptile->ibuf == ibuf) {
+ if (r_mask) {
+ /* allocate mask if requested. */
+ if (!ptile->mask) {
+ ptile->mask = MEM_callocN(sizeof(ushort) * SQUARE(ED_IMAGE_UNDO_TILE_SIZE),
+ "UndoImageTile.mask");
+ }
+ *r_mask = ptile->mask;
+ }
+ if (validate) {
+ ptile->valid = true;
+ }
+ return ptile->rect.pt;
+ }
+ }
+ }
+ return NULL;
+}
+
+void *ED_image_paint_tile_push(ListBase *paint_tiles,
+ Image *image,
+ ImBuf *ibuf,
+ ImBuf **tmpibuf,
+ int x_tile,
+ int y_tile,
+ ushort **r_mask,
+ bool **r_valid,
+ bool use_thread_lock,
+ bool find_prev)
+{
+ const bool has_float = (ibuf->rect_float != NULL);
+
+ /* check if tile is already pushed */
+
+ /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
+ if (find_prev) {
+ void *data = ED_image_paint_tile_find(paint_tiles, image, ibuf, x_tile, y_tile, r_mask, true);
+ if (data) {
+ return data;
+ }
+ }
+
+ if (*tmpibuf == NULL) {
+ *tmpibuf = imbuf_alloc_temp_tile();
+ }
+
+ PaintTile *ptile = MEM_callocN(sizeof(PaintTile), "PaintTile");
+
+ ptile->image = image;
+ ptile->ibuf = ibuf;
+
+ ptile->x = x_tile;
+ ptile->y = y_tile;
+
+ /* add mask explicitly here */
+ if (r_mask) {
+ *r_mask = ptile->mask = MEM_callocN(sizeof(ushort) * SQUARE(ED_IMAGE_UNDO_TILE_SIZE),
+ "PaintTile.mask");
+ }
+
+ ptile->rect.pt = MEM_mapallocN((ibuf->rect_float ? sizeof(float[4]) : sizeof(char[4])) *
+ SQUARE(ED_IMAGE_UNDO_TILE_SIZE),
+ "PaintTile.rect");
+
+ ptile->use_float = has_float;
+ ptile->valid = true;
+
+ if (r_valid) {
+ *r_valid = &ptile->valid;
+ }
+
+ IMB_rectcpy(*tmpibuf,
+ ibuf,
+ 0,
+ 0,
+ x_tile * ED_IMAGE_UNDO_TILE_SIZE,
+ y_tile * ED_IMAGE_UNDO_TILE_SIZE,
+ ED_IMAGE_UNDO_TILE_SIZE,
+ ED_IMAGE_UNDO_TILE_SIZE);
+
+ if (has_float) {
+ SWAP(float *, ptile->rect.fp, (*tmpibuf)->rect_float);
+ }
+ else {
+ SWAP(uint *, ptile->rect.uint, (*tmpibuf)->rect);
+ }
+
+ if (use_thread_lock) {
+ BLI_spin_lock(&paint_tiles_lock);
+ }
+ BLI_addtail(paint_tiles, ptile);
+
+ if (use_thread_lock) {
+ BLI_spin_unlock(&paint_tiles_lock);
+ }
+ return ptile->rect.pt;
+}
+
+static void ptile_restore_runtime_list(ListBase *paint_tiles)
+{
+ ImBuf *tmpibuf = imbuf_alloc_temp_tile();
+
+ for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
+ Image *image = ptile->image;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
+ const bool has_float = (ibuf->rect_float != NULL);
+
+ if (has_float) {
+ SWAP(float *, ptile->rect.fp, tmpibuf->rect_float);
+ }
+ else {
+ SWAP(uint *, ptile->rect.uint, tmpibuf->rect);
+ }
+
+ IMB_rectcpy(
+ ibuf, tmpibuf, ptile->x, ptile->y, 0, 0, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE);
+
+ if (has_float) {
+ SWAP(float *, ptile->rect.fp, tmpibuf->rect_float);
+ }
+ else {
+ SWAP(uint *, ptile->rect.uint, tmpibuf->rect);
+ }
+
+ GPU_free_image(image); /* force OpenGL reload (maybe partial update will operate better?) */
+ if (ibuf->rect_float) {
+ ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
+ }
+ if (ibuf->mipmap[0]) {
+ ibuf->userflags |= IB_MIPMAP_INVALID; /* force mip-map recreation. */
+ }
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+
+ IMB_freeImBuf(tmpibuf);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Undo Tile
+ * \{ */
+
+static uint index_from_xy(uint tile_x, uint tile_y, const uint tiles_dims[2])
+{
+ BLI_assert(tile_x < tiles_dims[0] && tile_y < tiles_dims[1]);
+ return (tile_y * tiles_dims[0]) + tile_x;
+}
+
+typedef struct UndoImageTile {
+ union {
+ float *fp;
+ uint *uint;
+ void *pt;
+ } rect;
+ int users;
+} UndoImageTile;
+
+static UndoImageTile *utile_alloc(bool has_float)
+{
+ UndoImageTile *utile = MEM_callocN(sizeof(*utile), "ImageUndoTile");
+ if (has_float) {
+ utile->rect.fp = MEM_mallocN(sizeof(float[4]) * SQUARE(ED_IMAGE_UNDO_TILE_SIZE), __func__);
+ }
+ else {
+ utile->rect.uint = MEM_mallocN(sizeof(uint) * SQUARE(ED_IMAGE_UNDO_TILE_SIZE), __func__);
+ }
+ return utile;
+}
+
+static void utile_init_from_imbuf(
+ UndoImageTile *utile, const uint x, const uint y, const ImBuf *ibuf, ImBuf *tmpibuf)
+{
+ const bool has_float = ibuf->rect_float;
+
+ if (has_float) {
+ SWAP(float *, utile->rect.fp, tmpibuf->rect_float);
+ }
+ else {
+ SWAP(uint *, utile->rect.uint, tmpibuf->rect);
+ }
+
+ IMB_rectcpy(tmpibuf, ibuf, 0, 0, x, y, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE);
+
+ if (has_float) {
+ SWAP(float *, utile->rect.fp, tmpibuf->rect_float);
+ }
+ else {
+ SWAP(uint *, utile->rect.uint, tmpibuf->rect);
+ }
+}
+
+static void utile_restore(
+ const UndoImageTile *utile, const uint x, const uint y, ImBuf *ibuf, ImBuf *tmpibuf)
+{
+ const bool has_float = ibuf->rect_float;
+ float *prev_rect_float = tmpibuf->rect_float;
+ uint *prev_rect = tmpibuf->rect;
+
+ if (has_float) {
+ tmpibuf->rect_float = utile->rect.fp;
+ }
+ else {
+ tmpibuf->rect = utile->rect.uint;
+ }
+
+ IMB_rectcpy(ibuf, tmpibuf, x, y, 0, 0, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE);
+
+ tmpibuf->rect_float = prev_rect_float;
+ tmpibuf->rect = prev_rect;
+}
+
+static void utile_decref(UndoImageTile *utile)
+{
+ utile->users -= 1;
+ BLI_assert(utile->users >= 0);
+ if (utile->users == 0) {
+ MEM_freeN(utile->rect.pt);
+ MEM_freeN(utile);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Undo Buffer
+ * \{ */
+
+typedef struct UndoImageBuf {
+ struct UndoImageBuf *next, *prev;
+
+ /**
+ * The buffer after the undo step has executed.
+ */
+ struct UndoImageBuf *post;
+
+ char ibuf_name[IMB_FILENAME_SIZE];
+
+ UndoImageTile **tiles;
+
+ /** Can calculate these from dims, just for convenience. */
+ uint tiles_len;
+ uint tiles_dims[2];
+
+ uint image_dims[2];
+
+ /** Store variables from the image. */
+ struct {
+ short source;
+ bool use_float;
+ char gen_type;
+ } image_state;
+
+} UndoImageBuf;
+
+static UndoImageBuf *ubuf_from_image_no_tiles(Image *image, const ImBuf *ibuf)
+{
+ UndoImageBuf *ubuf = MEM_callocN(sizeof(*ubuf), __func__);
+
+ ubuf->image_dims[0] = ibuf->x;
+ ubuf->image_dims[1] = ibuf->y;
+
+ ubuf->tiles_dims[0] = ED_IMAGE_UNDO_TILE_NUMBER(ubuf->image_dims[0]);
+ ubuf->tiles_dims[1] = ED_IMAGE_UNDO_TILE_NUMBER(ubuf->image_dims[1]);
+
+ ubuf->tiles_len = ubuf->tiles_dims[0] * ubuf->tiles_dims[1];
+ ubuf->tiles = MEM_callocN(sizeof(*ubuf->tiles) * ubuf->tiles_len, __func__);
+
+ BLI_strncpy(ubuf->ibuf_name, ibuf->name, sizeof(ubuf->ibuf_name));
+ ubuf->image_state.gen_type = image->gen_type;
+ ubuf->image_state.source = image->source;
+ ubuf->image_state.use_float = ibuf->rect_float != NULL;
+
+ return ubuf;
+}
+
+static void ubuf_from_image_all_tiles(UndoImageBuf *ubuf, const ImBuf *ibuf)
+{
+ ImBuf *tmpibuf = imbuf_alloc_temp_tile();
+
+ const bool has_float = ibuf->rect_float;
+ int i = 0;
+ for (uint y_tile = 0; y_tile < ubuf->tiles_dims[1]; y_tile += 1) {
+ uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS;
+ for (uint x_tile = 0; x_tile < ubuf->tiles_dims[0]; x_tile += 1) {
+ uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS;
+
+ BLI_assert(ubuf->tiles[i] == NULL);
+ UndoImageTile *utile = utile_alloc(has_float);
+ utile->users = 1;
+ utile_init_from_imbuf(utile, x, y, ibuf, tmpibuf);
+ ubuf->tiles[i] = utile;
+
+ i += 1;
+ }
+ }
+
+ IMB_freeImBuf(tmpibuf);
+}
+
+static void ubuf_free(UndoImageBuf *ubuf)
+{
+ UndoImageBuf *ubuf_post = ubuf->post;
+ for (uint i = 0; i < ubuf->tiles_len; i++) {
+ UndoImageTile *utile = ubuf->tiles[i];
+ utile_decref(utile);
+ }
+ MEM_freeN(ubuf->tiles);
+ MEM_freeN(ubuf);
+ if (ubuf_post) {
+ ubuf_free(ubuf_post);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Undo Handle
+ * \{ */
+
+typedef struct UndoImageHandle {
+ struct UndoImageHandle *next, *prev;
+
+ /** Each undo handle refers to a single image which may have multiple buffers. */
+ UndoRefID_Image image_ref;
+
+ /**
+ * List of #UndoImageBuf's to support multiple buffers per image.
+ *
+ * \note To properly support multiple buffers per image
+ * we would need to store an #ImageUser for each #UndoImageBuf.
+ * since when restoring the image we use:
+ * `BKE_image_acquire_ibuf(image, NULL, NULL)`.
+ */
+ ListBase buffers;
+
+} UndoImageHandle;
+
+static void uhandle_restore_list(ListBase *undo_handles, bool use_init)
+{
+ ImBuf *tmpibuf = imbuf_alloc_temp_tile();
+
+ for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) {
+ /* Tiles only added to second set of tiles. */
+ Image *image = uh->image_ref.ptr;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
+ if (UNLIKELY(ibuf == NULL)) {
+ CLOG_ERROR(&LOG, "Unable to get buffer for image '%s'", image->id.name + 2);
+ continue;
+ }
+ bool changed = false;
+ for (UndoImageBuf *ubuf_iter = uh->buffers.first; ubuf_iter; ubuf_iter = ubuf_iter->next) {
+ UndoImageBuf *ubuf = use_init ? ubuf_iter : ubuf_iter->post;
+ IMB_rect_size_set(ibuf, ubuf->image_dims);
+ int i = 0;
+ for (uint y_tile = 0; y_tile < ubuf->tiles_dims[1]; y_tile += 1) {
+ uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS;
+ for (uint x_tile = 0; x_tile < ubuf->tiles_dims[0]; x_tile += 1) {
+ uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS;
+ utile_restore(ubuf->tiles[i], x, y, ibuf, tmpibuf);
+ changed = true;
+ i += 1;
+ }
+ }
+ }
+
+ if (changed) {
+ BKE_image_mark_dirty(image, ibuf);
+ GPU_free_image(image); /* force OpenGL reload */
+
+ if (ibuf->rect_float) {
+ ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
+ }
+ if (ibuf->mipmap[0]) {
+ ibuf->userflags |= IB_MIPMAP_INVALID; /* force mip-map recreation. */
+ }
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+
+ DEG_id_tag_update(&image->id, 0);
+ }
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+
+ IMB_freeImBuf(tmpibuf);
+}
+
+static void uhandle_free_list(ListBase *undo_handles)
+{
+ LISTBASE_FOREACH_MUTABLE (UndoImageHandle *, uh, undo_handles) {
+ LISTBASE_FOREACH_MUTABLE (UndoImageBuf *, ubuf, &uh->buffers) {
+ ubuf_free(ubuf);
+ }
+ MEM_freeN(uh);
+ }
+ BLI_listbase_clear(undo_handles);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Undo Internal Utilities
+ * \{ */
+
+/** #UndoImageHandle utilities */
+
+static UndoImageBuf *uhandle_lookup_ubuf(UndoImageHandle *uh,
+ const Image *UNUSED(image),
+ const char *ibuf_name)
+{
+ for (UndoImageBuf *ubuf = uh->buffers.first; ubuf; ubuf = ubuf->next) {
+ if (STREQ(ubuf->ibuf_name, ibuf_name)) {
+ return ubuf;
+ }
+ }
+ return NULL;
+}
+
+static UndoImageBuf *uhandle_add_ubuf(UndoImageHandle *uh, Image *image, ImBuf *ibuf)
+{
+ BLI_assert(uhandle_lookup_ubuf(uh, image, ibuf->name) == NULL);
+ UndoImageBuf *ubuf = ubuf_from_image_no_tiles(image, ibuf);
+ BLI_addtail(&uh->buffers, ubuf);
+
+ ubuf->post = NULL;
+
+ return ubuf;
+}
+
+static UndoImageBuf *uhandle_ensure_ubuf(UndoImageHandle *uh, Image *image, ImBuf *ibuf)
+{
+ UndoImageBuf *ubuf = uhandle_lookup_ubuf(uh, image, ibuf->name);
+ if (ubuf == NULL) {
+ ubuf = uhandle_add_ubuf(uh, image, ibuf);
+ }
+ return ubuf;
+}
+
+static UndoImageHandle *uhandle_lookup_by_name(ListBase *undo_handles, const Image *image)
+{
+ for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) {
+ if (STREQ(image->id.name + 2, uh->image_ref.name + 2)) {
+ return uh;
+ }
+ }
+ return NULL;
+}
+
+static UndoImageHandle *uhandle_lookup(ListBase *undo_handles, const Image *image)
+{
+ for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) {
+ if (image == uh->image_ref.ptr) {
+ return uh;
+ }
+ }
+ return NULL;
+}
+
+static UndoImageHandle *uhandle_add(ListBase *undo_handles, Image *image)
+{
+ BLI_assert(uhandle_lookup(undo_handles, image) == NULL);
+ UndoImageHandle *uh = MEM_callocN(sizeof(*uh), __func__);
+ uh->image_ref.ptr = image;
+ BLI_addtail(undo_handles, uh);
+ return uh;
+}
+
+static UndoImageHandle *uhandle_ensure(ListBase *undo_handles, Image *image)
+{
+ UndoImageHandle *uh = uhandle_lookup(undo_handles, image);
+ if (uh == NULL) {
+ uh = uhandle_add(undo_handles, image);
+ }
+ return uh;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
+
+typedef struct ImageUndoStep {
+ UndoStep step;
+
+ /** #UndoImageHandle */
+ ListBase handles;
+
+ /**
+ * #PaintTile
+ * Run-time only data (active during a paint stroke).
+ */
+ ListBase paint_tiles;
+
+ bool is_encode_init;
+ ePaintMode paint_mode;
+
+} ImageUndoStep;
+
+/**
+ * Find the previous undo buffer from this one.
+ * \note We could look into undo steps even further back.
+ */
+static UndoImageBuf *ubuf_lookup_from_reference(ImageUndoStep *us_prev,
+ const Image *image,
+ const UndoImageBuf *ubuf)
+{
+ /* Use name lookup because because the pointer is cleared for previous steps. */
+ UndoImageHandle *uh_prev = uhandle_lookup_by_name(&us_prev->handles, image);
+ if (uh_prev != NULL) {
+ UndoImageBuf *ubuf_reference = uhandle_lookup_ubuf(uh_prev, image, ubuf->ibuf_name);
+ if (ubuf_reference) {
+ ubuf_reference = ubuf_reference->post;
+ if ((ubuf_reference->image_dims[0] == ubuf->image_dims[0]) &&
+ (ubuf_reference->image_dims[1] == ubuf->image_dims[1])) {
+ return ubuf_reference;
+ }
+ }
+ }
+ return NULL;
+}
+
+static bool image_undosys_poll(bContext *C)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && (sa->spacetype == SPACE_IMAGE)) {
+ SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
+ if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
+ return true;
+ }
+ }
+ else {
+ if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ /* dummy, memory is cleared anyway. */
+ us->is_encode_init = true;
+ BLI_listbase_clear(&us->handles);
+ BLI_listbase_clear(&us->paint_tiles);
+}
+
+static bool image_undosys_step_encode(struct bContext *C,
+ struct Main *UNUSED(bmain),
+ UndoStep *us_p)
+{
+ /* Encoding is done along the way by adding tiles
+ * to the current 'ImageUndoStep' added by encode_init.
+ *
+ * This function ensures there are previous and current states of the image in the undo buffer.
+ */
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+
+ BLI_assert(us->step.data_size == 0);
+
+ if (us->is_encode_init) {
+
+ ImBuf *tmpibuf = imbuf_alloc_temp_tile();
+
+ ImageUndoStep *us_reference = (ImageUndoStep *)ED_undo_stack_get()->step_active;
+ while (us_reference && us_reference->step.type != BKE_UNDOSYS_TYPE_IMAGE) {
+ us_reference = (ImageUndoStep *)us_reference->step.prev;
+ }
+
+ /* Initialize undo tiles from ptiles (if they exist). */
+ for (PaintTile *ptile = us->paint_tiles.first, *ptile_next; ptile; ptile = ptile_next) {
+ if (ptile->valid) {
+ UndoImageHandle *uh = uhandle_ensure(&us->handles, ptile->image);
+ UndoImageBuf *ubuf_pre = uhandle_ensure_ubuf(uh, ptile->image, ptile->ibuf);
+
+ UndoImageTile *utile = MEM_callocN(sizeof(*utile), "UndoImageTile");
+ utile->users = 1;
+ utile->rect.pt = ptile->rect.pt;
+ ptile->rect.pt = NULL;
+ const uint tile_index = index_from_xy(ptile->x, ptile->y, ubuf_pre->tiles_dims);
+
+ BLI_assert(ubuf_pre->tiles[tile_index] == NULL);
+ ubuf_pre->tiles[tile_index] = utile;
+ }
+ ptile_next = ptile->next;
+ ptile_free(ptile);
+ }
+ BLI_listbase_clear(&us->paint_tiles);
+
+ for (UndoImageHandle *uh = us->handles.first; uh; uh = uh->next) {
+ for (UndoImageBuf *ubuf_pre = uh->buffers.first; ubuf_pre; ubuf_pre = ubuf_pre->next) {
+
+ ImBuf *ibuf = BKE_image_acquire_ibuf(uh->image_ref.ptr, NULL, NULL);
+
+ const bool has_float = ibuf->rect_float;
+
+ BLI_assert(ubuf_pre->post == NULL);
+ ubuf_pre->post = ubuf_from_image_no_tiles(uh->image_ref.ptr, ibuf);
+ UndoImageBuf *ubuf_post = ubuf_pre->post;
+
+ if (ubuf_pre->image_dims[0] != ubuf_post->image_dims[0] ||
+ ubuf_pre->image_dims[1] != ubuf_post->image_dims[1]) {
+ ubuf_from_image_all_tiles(ubuf_post, ibuf);
+ }
+ else {
+ /* Search for the previous buffer. */
+ UndoImageBuf *ubuf_reference = (us_reference ?
+ ubuf_lookup_from_reference(
+ us_reference, uh->image_ref.ptr, ubuf_post) :
+ NULL);
+
+ int i = 0;
+ for (uint y_tile = 0; y_tile < ubuf_pre->tiles_dims[1]; y_tile += 1) {
+ uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS;
+ for (uint x_tile = 0; x_tile < ubuf_pre->tiles_dims[0]; x_tile += 1) {
+ uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS;
+
+ if ((ubuf_reference != NULL) && ((ubuf_pre->tiles[i] == NULL) ||
+ /* In this case the paint stroke as has added a tile
+ * which we have a duplicate reference available. */
+ (ubuf_pre->tiles[i]->users == 1))) {
+ if (ubuf_pre->tiles[i] != NULL) {
+ /* If we have a reference, re-use this single use tile for the post state. */
+ BLI_assert(ubuf_pre->tiles[i]->users == 1);
+ ubuf_post->tiles[i] = ubuf_pre->tiles[i];
+ ubuf_pre->tiles[i] = NULL;
+ utile_init_from_imbuf(ubuf_post->tiles[i], x, y, ibuf, tmpibuf);
+ }
+ else {
+ BLI_assert(ubuf_post->tiles[i] == NULL);
+ ubuf_post->tiles[i] = ubuf_reference->tiles[i];
+ ubuf_post->tiles[i]->users += 1;
+ }
+ BLI_assert(ubuf_pre->tiles[i] == NULL);
+ ubuf_pre->tiles[i] = ubuf_reference->tiles[i];
+ ubuf_pre->tiles[i]->users += 1;
+
+ BLI_assert(ubuf_pre->tiles[i] != NULL);
+ BLI_assert(ubuf_post->tiles[i] != NULL);
+ }
+ else {
+ UndoImageTile *utile = utile_alloc(has_float);
+ utile_init_from_imbuf(utile, x, y, ibuf, tmpibuf);
+
+ if (ubuf_pre->tiles[i] != NULL) {
+ ubuf_post->tiles[i] = utile;
+ utile->users = 1;
+ }
+ else {
+ ubuf_pre->tiles[i] = utile;
+ ubuf_post->tiles[i] = utile;
+ utile->users = 2;
+ }
+ }
+ BLI_assert(ubuf_pre->tiles[i] != NULL);
+ BLI_assert(ubuf_post->tiles[i] != NULL);
+ i += 1;
+ }
+ }
+ }
+ BKE_image_release_ibuf(uh->image_ref.ptr, ibuf, NULL);
+ }
+ }
+
+ IMB_freeImBuf(tmpibuf);
+
+ /* Useful to debug tiles are stored correctly. */
+ if (false) {
+ uhandle_restore_list(&us->handles, false);
+ }
+ }
+ else {
+ /* Happens when switching modes. */
+ ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C);
+ BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
+ us->paint_mode = paint_mode;
+ }
+
+ us_p->is_applied = true;
+
+ return true;
+}
+
+static void image_undosys_step_decode_undo_impl(ImageUndoStep *us, bool is_final)
+{
+ BLI_assert(us->step.is_applied == true);
+ uhandle_restore_list(&us->handles, !is_final);
+ us->step.is_applied = false;
+}
+
+static void image_undosys_step_decode_redo_impl(ImageUndoStep *us)
+{
+ BLI_assert(us->step.is_applied == false);
+ uhandle_restore_list(&us->handles, false);
+ us->step.is_applied = true;
+}
+
+static void image_undosys_step_decode_undo(ImageUndoStep *us, bool is_final)
+{
+ 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) {
+ break;
+ }
+ us_iter = (ImageUndoStep *)us_iter->step.next;
+ }
+ while (us_iter != us || (!is_final && us_iter == us)) {
+
+ image_undosys_step_decode_undo_impl(us_iter, is_final);
+ if (us_iter == us) {
+ break;
+ }
+ us_iter = (ImageUndoStep *)us_iter->step.prev;
+ }
+}
+
+static void image_undosys_step_decode_redo(ImageUndoStep *us)
+{
+ ImageUndoStep *us_iter = us;
+ while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) {
+ if (us_iter->step.prev->is_applied == true) {
+ break;
+ }
+ us_iter = (ImageUndoStep *)us_iter->step.prev;
+ }
+ while (us_iter && (us_iter->step.is_applied == false)) {
+ image_undosys_step_decode_redo_impl(us_iter);
+ if (us_iter == us) {
+ break;
+ }
+ us_iter = (ImageUndoStep *)us_iter->step.next;
+ }
+}
+
+static void image_undosys_step_decode(
+ struct bContext *C, struct Main *bmain, UndoStep *us_p, int dir, bool is_final)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ if (dir < 0) {
+ image_undosys_step_decode_undo(us, is_final);
+ }
+ else {
+ image_undosys_step_decode_redo(us);
+ }
+
+ if (us->paint_mode == PAINT_MODE_TEXTURE_3D) {
+ ED_object_mode_set(C, OB_MODE_TEXTURE_PAINT);
+ }
+
+ /* Refresh texture slots. */
+ ED_editors_init_for_undo(bmain);
+}
+
+static void image_undosys_step_free(UndoStep *us_p)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ uhandle_free_list(&us->handles);
+
+ /* Typically this list will have been cleared. */
+ ptile_free_list(&us->paint_tiles);
+}
+
+static void image_undosys_foreach_ID_ref(UndoStep *us_p,
+ UndoTypeForEachIDRefFn foreach_ID_ref_fn,
+ void *user_data)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ for (UndoImageHandle *uh = us->handles.first; uh; uh = uh->next) {
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&uh->image_ref));
+ }
+}
+
+/* Export for ED_undo_sys. */
+void ED_image_undosys_type(UndoType *ut)
+{
+ ut->name = "Image";
+ ut->poll = image_undosys_poll;
+ ut->step_encode_init = image_undosys_step_encode_init;
+ ut->step_encode = image_undosys_step_encode;
+ ut->step_decode = image_undosys_step_decode;
+ ut->step_free = image_undosys_step_free;
+
+ ut->step_foreach_ID_ref = image_undosys_foreach_ID_ref;
+
+ ut->use_context = true;
+
+ ut->step_size = sizeof(ImageUndoStep);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+ListBase *ED_image_paint_tile_list_get(void)
+{
+ UndoStack *ustack = ED_undo_stack_get();
+ UndoStep *us_prev = ustack->step_init;
+ UndoStep *us_p = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_IMAGE);
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ /* We should always have an undo push started when accessing tiles,
+ * not doing this means we won't have paint_mode correctly set. */
+ BLI_assert(us_p == us_prev);
+ if (us_p != us_prev) {
+ /* Fallback value until we can be sure this never happens. */
+ us->paint_mode = PAINT_MODE_TEXTURE_2D;
+ }
+ return &us->paint_tiles;
+}
+
+/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/
+void ED_image_undo_restore(UndoStep *us)
+{
+ ListBase *paint_tiles = &((ImageUndoStep *)us)->paint_tiles;
+ ptile_restore_runtime_list(paint_tiles);
+ ptile_invalidate_list(paint_tiles);
+}
+
+static ImageUndoStep *image_undo_push_begin(const char *name, int paint_mode)
+{
+ UndoStack *ustack = ED_undo_stack_get();
+ bContext *C = NULL; /* special case, we never read from this. */
+ UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE);
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
+ us->paint_mode = paint_mode;
+ return us;
+}
+
+void ED_image_undo_push_begin(const char *name, int paint_mode)
+{
+ image_undo_push_begin(name, paint_mode);
+}
+
+void ED_image_undo_push_begin_with_image(const char *name, Image *image, ImBuf *ibuf)
+{
+ ImageUndoStep *us = image_undo_push_begin(name, PAINT_MODE_TEXTURE_2D);
+
+ UndoImageHandle *uh = uhandle_ensure(&us->handles, image);
+ UndoImageBuf *ubuf_pre = uhandle_ensure_ubuf(uh, image, ibuf);
+ BLI_assert(ubuf_pre->post == NULL);
+
+ ImageUndoStep *us_reference = (ImageUndoStep *)ED_undo_stack_get()->step_active;
+ while (us_reference && us_reference->step.type != BKE_UNDOSYS_TYPE_IMAGE) {
+ us_reference = (ImageUndoStep *)us_reference->step.prev;
+ }
+ UndoImageBuf *ubuf_reference = (us_reference ?
+ ubuf_lookup_from_reference(us_reference, image, ubuf_pre) :
+ NULL);
+
+ if (ubuf_reference) {
+ memcpy(ubuf_pre->tiles, ubuf_reference->tiles, sizeof(*ubuf_pre->tiles) * ubuf_pre->tiles_len);
+ for (uint i = 0; i < ubuf_pre->tiles_len; i++) {
+ UndoImageTile *utile = ubuf_pre->tiles[i];
+ utile->users += 1;
+ }
+ }
+ else {
+ ubuf_from_image_all_tiles(ubuf_pre, ibuf);
+ }
+}
+
+void ED_image_undo_push_end(void)
+{
+ UndoStack *ustack = ED_undo_stack_get();
+ BKE_undosys_step_push(ustack, NULL, NULL);
+ WM_file_tag_modified();
+}
+
+/** \} */
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 5fa4fe3e077..a88ecc91868 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -207,6 +207,7 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_view_all);
WM_operatortype_append(IMAGE_OT_view_pan);
WM_operatortype_append(IMAGE_OT_view_selected);
+ WM_operatortype_append(IMAGE_OT_view_center_cursor);
WM_operatortype_append(IMAGE_OT_view_zoom);
WM_operatortype_append(IMAGE_OT_view_zoom_in);
WM_operatortype_append(IMAGE_OT_view_zoom_out);
@@ -229,6 +230,7 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_unpack);
WM_operatortype_append(IMAGE_OT_invert);
+ WM_operatortype_append(IMAGE_OT_resize);
WM_operatortype_append(IMAGE_OT_cycle_render_slot);
WM_operatortype_append(IMAGE_OT_clear_render_slot);
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index 106edc290d5..b51aec90e4f 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -441,11 +441,11 @@ static void stats_string(ViewLayer *view_layer)
#undef SCENE_STATS_FMT_INT
/* get memory statistics */
- BLI_str_format_byte_unit(formatted_mem, mem_in_use - mmap_in_use, true);
+ BLI_str_format_byte_unit(formatted_mem, mem_in_use - mmap_in_use, false);
ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, TIP_(" | Mem: %s"), formatted_mem);
if (mmap_in_use) {
- BLI_str_format_byte_unit(formatted_mem, mmap_in_use, true);
+ BLI_str_format_byte_unit(formatted_mem, mmap_in_use, false);
BLI_snprintf(memstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_(" (%s)"), formatted_mem);
}
@@ -454,11 +454,11 @@ static void stats_string(ViewLayer *view_layer)
GPU_mem_stats_get(&gpu_tot_memory, &gpu_free_mem);
- BLI_str_format_byte_unit(formatted_mem, gpu_free_mem, true);
+ BLI_str_format_byte_unit(formatted_mem, gpu_free_mem, false);
ofs = BLI_snprintf(gpumemstr, MAX_INFO_MEM_LEN, TIP_(" | Free GPU Mem: %s"), formatted_mem);
if (gpu_tot_memory) {
- BLI_str_format_byte_unit(formatted_mem, gpu_tot_memory, true);
+ BLI_str_format_byte_unit(formatted_mem, gpu_tot_memory, false);
BLI_snprintf(gpumemstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_("/%s"), formatted_mem);
}
}
@@ -581,7 +581,7 @@ const char *ED_info_stats_string(Main *bmain, Scene *scene, ViewLayer *view_laye
if (wm->is_interface_locked) {
return "";
}
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
if (!view_layer->stats) {
stats_update(depsgraph, view_layer);
}
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index 9d6ccd6fe35..913d2a06d46 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -47,7 +47,6 @@
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
-#include "GPU_draw.h"
#include "GPU_state.h"
#include "WM_types.h"
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index a69eb254621..3beb12fbb2a 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -24,6 +24,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_system.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
@@ -44,9 +45,9 @@
#include "BIF_glutil.h"
-#include "GPU_draw.h"
#include "GPU_batch.h"
#include "GPU_batch_presets.h"
+#include "GPU_extensions.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
#include "GPU_state.h"
@@ -730,37 +731,7 @@ static void node_buts_image_user(uiLayout *layout,
static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiLayout *row, *col, *sub;
-
- uiItemR(layout, ptr, "vector_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
-
- col = uiLayoutColumn(row, true);
- uiItemL(col, IFACE_("Location:"), ICON_NONE);
- uiItemR(col, ptr, "translation", 0, "", ICON_NONE);
-
- col = uiLayoutColumn(row, true);
- uiItemL(col, IFACE_("Rotation:"), ICON_NONE);
- uiItemR(col, ptr, "rotation", 0, "", ICON_NONE);
-
- col = uiLayoutColumn(row, true);
- uiItemL(col, IFACE_("Scale:"), ICON_NONE);
- uiItemR(col, ptr, "scale", 0, "", ICON_NONE);
-
- row = uiLayoutRow(layout, false);
-
- col = uiLayoutColumn(row, true);
- uiItemR(col, ptr, "use_min", 0, IFACE_("Min"), ICON_NONE);
- sub = uiLayoutColumn(col, true);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min"));
- uiItemR(sub, ptr, "min", 0, "", ICON_NONE);
-
- col = uiLayoutColumn(row, true);
- uiItemR(col, ptr, "use_max", 0, IFACE_("Max"), ICON_NONE);
- sub = uiLayoutColumn(col, true);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max"));
- uiItemR(sub, ptr, "max", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "vector_type", 0, NULL, ICON_NONE);
}
static void node_shader_buts_vect_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -937,14 +908,24 @@ static void node_shader_buts_tex_wave(uiLayout *layout, bContext *UNUSED(C), Poi
static void node_shader_buts_tex_musgrave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "musgrave_dimensions", 0, "", ICON_NONE);
uiItemR(layout, ptr, "musgrave_type", 0, "", ICON_NONE);
}
static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "coloring", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "distance", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "voronoi_dimensions", 0, "", ICON_NONE);
uiItemR(layout, ptr, "feature", 0, "", ICON_NONE);
+ int feature = RNA_enum_get(ptr, "feature");
+ if (!ELEM(feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS) &&
+ RNA_enum_get(ptr, "voronoi_dimensions") != 1) {
+ uiItemR(layout, ptr, "distance", 0, "", ICON_NONE);
+ }
+}
+
+static void node_shader_buts_tex_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "noise_dimensions", 0, "", ICON_NONE);
}
static void node_shader_buts_tex_pointdensity(uiLayout *layout,
@@ -1017,6 +998,18 @@ static void node_shader_buts_uvmap(uiLayout *layout, bContext *C, PointerRNA *pt
}
}
+static void node_shader_buts_vertex_color(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
+ if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
+ PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
+ uiItemPointerR(layout, ptr, "layer_name", &dataptr, "vertex_colors", "", ICON_GROUP_VCOL);
+ }
+ else {
+ uiItemL(layout, "No mesh in active object.", ICON_ERROR);
+ }
+}
+
static void node_shader_buts_uvalongstroke(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "use_tips", 0, NULL, 0);
@@ -1188,7 +1181,7 @@ static void node_shader_buts_ambient_occlusion(uiLayout *layout,
static void node_shader_buts_white_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "dimensions", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "noise_dimensions", 0, "", ICON_NONE);
}
/* only once called */
@@ -1266,6 +1259,9 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_TEX_VORONOI:
ntype->draw_buttons = node_shader_buts_tex_voronoi;
break;
+ case SH_NODE_TEX_NOISE:
+ ntype->draw_buttons = node_shader_buts_tex_noise;
+ break;
case SH_NODE_TEX_POINTDENSITY:
ntype->draw_buttons = node_shader_buts_tex_pointdensity;
break;
@@ -1315,6 +1311,9 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_UVMAP:
ntype->draw_buttons = node_shader_buts_uvmap;
break;
+ case SH_NODE_VERTEX_COLOR:
+ ntype->draw_buttons = node_shader_buts_vertex_color;
+ break;
case SH_NODE_UVALONGSTROKE:
ntype->draw_buttons = node_shader_buts_uvalongstroke;
break;
@@ -2703,6 +2702,10 @@ static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), Po
{
#ifndef WITH_OPENIMAGEDENOISE
uiItemL(layout, IFACE_("Disabled, built without OpenImageDenoise"), ICON_ERROR);
+#else
+ if (!BLI_cpu_support_sse41()) {
+ uiItemL(layout, IFACE_("Disabled, CPU with SSE4.1 is required"), ICON_ERROR);
+ }
#endif
uiItemR(layout, ptr, "use_hdr", 0, NULL, ICON_NONE);
@@ -3143,12 +3146,12 @@ static void node_template_properties_update(bNodeType *ntype)
bNodeSocketTemplate *stemp;
if (ntype->inputs) {
- for (stemp = ntype->inputs; stemp->type >= 0; ++stemp) {
+ for (stemp = ntype->inputs; stemp->type >= 0; stemp++) {
node_socket_template_properties_update(ntype, stemp);
}
}
if (ntype->outputs) {
- for (stemp = ntype->outputs; stemp->type >= 0; ++stemp) {
+ for (stemp = ntype->outputs; stemp->type >= 0; stemp++) {
node_socket_template_properties_update(ntype, stemp);
}
}
@@ -3769,7 +3772,7 @@ static void nodelink_batch_init(void)
GPU_vertbuf_data_alloc(vbo, vcount);
int v = 0;
- for (int k = 0; k < 2; ++k) {
+ for (int k = 0; k < 2; k++) {
unsigned char uv[2] = {0, 0};
float pos[2] = {0.0f, 0.0f};
float exp[2] = {0.0f, 1.0f};
@@ -3780,7 +3783,7 @@ static void nodelink_batch_init(void)
}
/* curve strip */
- for (int i = 0; i < LINK_RESOL; ++i) {
+ for (int i = 0; i < LINK_RESOL; i++) {
uv[0] = 255 * (i / (float)(LINK_RESOL - 1));
uv[1] = 0;
set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
@@ -3796,7 +3799,7 @@ static void nodelink_batch_init(void)
copy_v2_v2(exp, arrow_expand_axis[0]);
set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
/* arrow */
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
uv[1] = 0;
copy_v2_v2(pos, arrow_verts[i]);
copy_v2_v2(exp, arrow_expand_axis[i]);
@@ -3887,7 +3890,9 @@ static void nodelink_batch_draw(SpaceNode *snode)
void nodelink_batch_start(SpaceNode *UNUSED(snode))
{
- g_batch_link.enabled = true;
+ /* TODO: partial workaround for NVIDIA driver bug on recent GTX/RTX cards,
+ * that breaks instancing when using indirect draw-call (see T70011). */
+ g_batch_link.enabled = !GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY);
}
void nodelink_batch_end(SpaceNode *snode)
diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c
index 01a30f677a3..664349b3c3b 100644
--- a/source/blender/editors/space_node/node_add.c
+++ b/source/blender/editors/space_node/node_add.c
@@ -309,7 +309,7 @@ void NODE_OT_add_reroute(wmOperatorType *ot)
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", BC_CROSSCURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
+ RNA_def_int(ot->srna, "cursor", WM_CURSOR_CROSS, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
}
/* ****************** Add File Node Operator ******************* */
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index 6dc2182b684..2081c69a1a4 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -47,7 +47,6 @@
#include "BIF_glutil.h"
-#include "GPU_draw.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
@@ -261,7 +260,7 @@ void ED_node_sort(bNodeTree *ntree)
do {
/* setup first_b pointer */
- for (b = 0; b < k && first_b; ++b) {
+ for (b = 0; b < k && first_b; b++) {
first_b = first_b->next;
}
/* all batches merged? */
@@ -289,7 +288,7 @@ void ED_node_sort(bNodeTree *ntree)
/* setup first pointers for next batch */
first_b = node_b;
- for (; b < k; ++b) {
+ for (; b < k; b++) {
/* all nodes sorted? */
if (first_b == NULL) {
break;
@@ -970,7 +969,7 @@ void node_draw_sockets(View2D *v2d,
continue;
}
if (select_all || (sock->flag & SELECT)) {
- ++selected_input_len;
+ selected_input_len++;
continue;
}
@@ -995,7 +994,7 @@ void node_draw_sockets(View2D *v2d,
continue;
}
if (select_all || (sock->flag & SELECT)) {
- ++selected_output_len;
+ selected_output_len++;
continue;
}
@@ -1457,16 +1456,16 @@ static void node_draw_hidden(const bContext *C,
int node_get_resize_cursor(int directions)
{
if (directions == 0) {
- return CURSOR_STD;
+ return WM_CURSOR_DEFAULT;
}
else if ((directions & ~(NODE_RESIZE_TOP | NODE_RESIZE_BOTTOM)) == 0) {
- return CURSOR_Y_MOVE;
+ return WM_CURSOR_Y_MOVE;
}
else if ((directions & ~(NODE_RESIZE_RIGHT | NODE_RESIZE_LEFT)) == 0) {
- return CURSOR_X_MOVE;
+ return WM_CURSOR_X_MOVE;
}
else {
- return CURSOR_EDIT;
+ return WM_CURSOR_EDIT;
}
}
@@ -1475,7 +1474,7 @@ void node_set_cursor(wmWindow *win, SpaceNode *snode, float cursor[2])
bNodeTree *ntree = snode->edittree;
bNode *node;
bNodeSocket *sock;
- int wmcursor = CURSOR_STD;
+ int wmcursor = WM_CURSOR_DEFAULT;
if (ntree) {
if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN | SOCK_OUT)) {
@@ -1732,11 +1731,11 @@ void drawnodespace(const bContext *C, ARegion *ar)
depth = 0;
while (path->prev && depth < max_depth) {
path = path->prev;
- ++depth;
+ depth++;
}
/* parent node trees in the background */
- for (curdepth = depth; curdepth > 0; path = path->next, --curdepth) {
+ for (curdepth = depth; curdepth > 0; path = path->next, curdepth--) {
ntree = path->nodetree;
if (ntree) {
snode_setup_v2d(snode, ar, path->view_center);
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index dcf901216f5..8811918b552 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -204,14 +204,13 @@ static void compo_initjob(void *cjv)
Scene *scene = cj->scene;
ViewLayer *view_layer = cj->view_layer;
- cj->compositor_depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
+ cj->compositor_depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
DEG_graph_build_for_compositor_preview(
cj->compositor_depsgraph, bmain, scene, view_layer, cj->ntree);
/* NOTE: Don't update animation to preserve unkeyed changes, this means can not use
* evaluate_on_framechange. */
- DEG_graph_flush_update(bmain, cj->compositor_depsgraph);
- DEG_evaluate_on_refresh(cj->compositor_depsgraph);
+ DEG_evaluate_on_refresh(bmain, cj->compositor_depsgraph);
bNodeTree *ntree_eval = (bNodeTree *)DEG_get_evaluated_id(cj->compositor_depsgraph,
&cj->ntree->id);
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index 3fd03bac874..08ac84cbb2f 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -298,7 +298,7 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
tlink->fromsock,
link->tonode->new_node,
link->tosock->new_sock);
- ++num_external_links;
+ num_external_links++;
}
}
@@ -331,7 +331,7 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
tlink->fromsock->new_sock,
link->tonode,
link->tosock);
- ++num_internal_links;
+ num_internal_links++;
}
}
}
@@ -695,7 +695,7 @@ static int node_get_selected_minmax(bNodeTree *ntree, bNode *gnode, float *min,
if (node_group_make_use_node(node, gnode)) {
nodeToView(node, 0.0f, 0.0f, &loc[0], &loc[1]);
minmax_v2v2_v2(min, max, loc);
- ++totselect;
+ totselect++;
}
}
@@ -717,7 +717,7 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
ListBase anim_basepaths = {NULL, NULL};
float min[2], max[2], center[2];
int totselect;
- bool expose_all = false;
+ bool expose_visible = false;
bNode *input_node, *output_node;
/* XXX rough guess, not nice but we don't have access to UI constants here ... */
@@ -735,7 +735,7 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
/* auto-add interface for "solo" nodes */
if (totselect == 1) {
- expose_all = true;
+ expose_visible = true;
}
/* move nodes over */
@@ -879,8 +879,8 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
}
}
- /* expose all unlinked sockets too */
- if (expose_all) {
+ /* expose all unlinked sockets too but only the visible ones*/
+ if (expose_visible) {
for (node = ngroup->nodes.first; node; node = node->next) {
if (node_group_make_use_node(node, gnode)) {
for (sock = node->inputs.first; sock; sock = sock->next) {
@@ -892,6 +892,9 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
break;
}
}
+ if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) {
+ skip = true;
+ }
if (skip) {
continue;
}
@@ -913,6 +916,9 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
skip = true;
}
}
+ if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) {
+ skip = true;
+ }
if (skip) {
continue;
}
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index cf52ca8489f..357ef31c51f 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -572,10 +572,10 @@ static int node_count_links(bNodeTree *ntree, bNodeSocket *sock)
int count = 0;
for (link = ntree->links.first; link; link = link->next) {
if (link->fromsock == sock) {
- ++count;
+ count++;
}
if (link->tosock == sock) {
- ++count;
+ count++;
}
}
return count;
@@ -599,7 +599,7 @@ static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link)
if (from_count > from->limit) {
nodeRemLink(ntree, tlink);
tlink = NULL;
- --from_count;
+ from_count--;
}
}
@@ -607,7 +607,7 @@ static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link)
if (to_count > to->limit) {
nodeRemLink(ntree, tlink);
tlink = NULL;
- --to_count;
+ to_count--;
}
}
}
@@ -1103,7 +1103,7 @@ void NODE_OT_links_cut(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
/* internal */
- RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
+ RNA_def_int(ot->srna, "cursor", WM_CURSOR_KNIFE, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
}
/* ********************** Detach links operator ***************** */
@@ -1567,7 +1567,7 @@ static bNodeSocket *socket_best_match(ListBase *sockets)
}
/* try all types, starting from 'highest' (i.e. colors, vectors, values) */
- for (type = maxtype; type >= 0; --type) {
+ for (type = maxtype; type >= 0; type--) {
for (sock = sockets->first; sock; sock = sock->next) {
if (!nodeSocketIsHidden(sock) && type == sock->type) {
return sock;
@@ -1576,7 +1576,7 @@ static bNodeSocket *socket_best_match(ListBase *sockets)
}
/* no visible sockets, unhide first of highest type */
- for (type = maxtype; type >= 0; --type) {
+ for (type = maxtype; type >= 0; type--) {
for (sock = sockets->first; sock; sock = sock->next) {
if (type == sock->type) {
sock->flag &= ~SOCK_HIDDEN;
diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c
index 78f36719880..b66cd0d3069 100644
--- a/source/blender/editors/space_node/node_select.c
+++ b/source/blender/editors/space_node/node_select.c
@@ -430,11 +430,9 @@ void node_select_single(bContext *C, bNode *node)
}
static int node_mouse_select(bContext *C,
+ wmOperator *op,
const int mval[2],
- const bool extend,
- const bool socket_select,
- const bool deselect_all,
- const bool wait_to_deselect_others)
+ bool wait_to_deselect_others)
{
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
@@ -445,8 +443,15 @@ static int node_mouse_select(bContext *C,
float cursor[2];
int ret_value = OPERATOR_CANCELLED;
- /* Waiting to deselect others is only allowed for basic selection. */
- BLI_assert(!(extend || socket_select) || !wait_to_deselect_others);
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+ /* always do socket_select when extending selection. */
+ const bool socket_select = extend || RNA_boolean_get(op->ptr, "socket_select");
+ const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
+
+ /* These cases are never modal. */
+ if (extend || socket_select) {
+ wait_to_deselect_others = false;
+ }
/* get mouse coordinates in view2d space */
UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &cursor[0], &cursor[1]);
@@ -552,19 +557,13 @@ static int node_mouse_select(bContext *C,
static int node_select_exec(bContext *C, wmOperator *op)
{
- int mval[2];
-
/* get settings from RNA properties for operator */
+ int mval[2];
mval[0] = RNA_int_get(op->ptr, "mouse_x");
mval[1] = RNA_int_get(op->ptr, "mouse_y");
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- /* always do socket_select when extending selection. */
- const bool socket_select = extend || RNA_boolean_get(op->ptr, "socket_select");
- const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
-
/* perform the select */
- const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, false);
+ const int ret_value = node_mouse_select(C, op, mval, false);
/* allow tweak event to work too */
return ret_value | OPERATOR_PASS_THROUGH;
@@ -579,19 +578,9 @@ static int node_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
mval[0] = RNA_int_get(op->ptr, "mouse_x");
mval[1] = RNA_int_get(op->ptr, "mouse_y");
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- /* always do socket_select when extending selection. */
- const bool socket_select = extend || RNA_boolean_get(op->ptr, "socket_select");
- const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
-
- /* These cases are never modal. */
- if (extend || socket_select) {
- return node_select_exec(C, op);
- }
-
if (init_event_type == 0) {
if (event->val == KM_PRESS) {
- const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, true);
+ const int ret_value = node_mouse_select(C, op, mval, true);
op->customdata = POINTER_FROM_INT((int)event->type);
if (ret_value & OPERATOR_RUNNING_MODAL) {
@@ -603,11 +592,12 @@ static int node_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* If we are in init phase, and cannot validate init of modal operations,
* just fall back to basic exec.
*/
- return node_select_exec(C, op);
+ const int ret_value = node_mouse_select(C, op, mval, false);
+ return ret_value | OPERATOR_PASS_THROUGH;
}
}
else if (event->type == init_event_type && event->val == KM_RELEASE) {
- const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, false);
+ const int ret_value = node_mouse_select(C, op, mval, false);
return ret_value | OPERATOR_PASS_THROUGH;
}
else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
@@ -1234,8 +1224,18 @@ static uiBlock *node_find_menu(bContext *C, ARegion *ar, void *arg_op)
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
- but = uiDefSearchBut(
- block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, 9 * UI_UNIT_X, UI_UNIT_Y, 0, 0, "");
+ but = uiDefSearchBut(block,
+ search,
+ 0,
+ ICON_VIEWZOOM,
+ sizeof(search),
+ 10,
+ 10,
+ UI_searchbox_size_x(),
+ UI_UNIT_Y,
+ 0,
+ 0,
+ "");
UI_but_func_search_set(but, NULL, node_find_cb, op->type, false, node_find_call_cb, NULL);
UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
@@ -1256,7 +1256,7 @@ static uiBlock *node_find_menu(bContext *C, ARegion *ar, void *arg_op)
NULL);
/* Move it downwards, mouse over button. */
- UI_block_bounds_set_popup(block, 6, (const int[2]){0, -UI_UNIT_Y});
+ UI_block_bounds_set_popup(block, 0.3f * U.widget_unit, (const int[2]){0, -UI_UNIT_Y});
return block;
}
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index 8cc57a82fe0..c6994dab72d 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -342,7 +342,7 @@ static void ui_node_link_items(NodeLinkArg *arg,
ListBase *lb = (in_out == SOCK_IN ? &ngroup->inputs : &ngroup->outputs);
bNodeSocket *stemp;
int index;
- for (stemp = lb->first, index = 0; stemp; stemp = stemp->next, ++index, ++i) {
+ for (stemp = lb->first, index = 0; stemp; stemp = stemp->next, index++, i++) {
NodeLinkItem *item = &items[i];
item->socket_index = index;
@@ -363,15 +363,15 @@ static void ui_node_link_items(NodeLinkArg *arg,
bNodeSocketTemplate *stemp;
int i;
- for (stemp = socket_templates; stemp && stemp->type != -1; ++stemp) {
- ++totitems;
+ for (stemp = socket_templates; stemp && stemp->type != -1; stemp++) {
+ totitems++;
}
if (totitems > 0) {
items = MEM_callocN(sizeof(NodeLinkItem) * totitems, "ui node link items");
i = 0;
- for (stemp = socket_templates; stemp && stemp->type != -1; ++stemp, ++i) {
+ for (stemp = socket_templates; stemp && stemp->type != -1; stemp++, i++) {
NodeLinkItem *item = &items[i];
item->socket_index = i;
@@ -441,7 +441,7 @@ static int ui_node_item_name_compare(const void *a, const void *b)
{
const bNodeType *type_a = *(const bNodeType **)a;
const bNodeType *type_b = *(const bNodeType **)b;
- return BLI_natstrcmp(type_a->ui_name, type_b->ui_name);
+ return BLI_strcasecmp_natural(type_a->ui_name, type_b->ui_name);
}
static bool ui_node_item_special_poll(const bNodeTree *UNUSED(ntree), const bNodeType *ntype)
@@ -506,13 +506,13 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
ui_node_link_items(arg, SOCK_OUT, &items, &totitems);
- for (i = 0; i < totitems; ++i) {
+ for (i = 0; i < totitems; i++) {
if (ui_compatible_sockets(items[i].socket_type, sock->type)) {
num++;
}
}
- for (i = 0; i < totitems; ++i) {
+ for (i = 0; i < totitems; i++) {
if (!ui_compatible_sockets(items[i].socket_type, sock->type)) {
continue;
}
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index 7183512a5bc..e114c3dbc05 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -158,7 +158,7 @@ bNodeTree *ED_node_tree_get(SpaceNode *snode, int level)
{
bNodeTreePath *path;
int i;
- for (path = snode->treepath.last, i = 0; path; path = path->prev, ++i) {
+ for (path = snode->treepath.last, i = 0; path; path = path->prev, i++) {
if (i == level) {
return path->nodetree;
}
@@ -171,7 +171,7 @@ int ED_node_tree_path_length(SpaceNode *snode)
bNodeTreePath *path;
int length = 0;
int i;
- for (path = snode->treepath.first, i = 0; path; path = path->next, ++i) {
+ for (path = snode->treepath.first, i = 0; path; path = path->next, i++) {
length += strlen(path->node_name);
if (i > 0) {
length += 1; /* for separator char */
@@ -186,7 +186,7 @@ void ED_node_tree_path_get(SpaceNode *snode, char *value)
int i;
value[0] = '\0';
- for (path = snode->treepath.first, i = 0; path; path = path->next, ++i) {
+ for (path = snode->treepath.first, i = 0; path; path = path->next, i++) {
if (i == 0) {
strcpy(value, path->node_name);
value += strlen(path->node_name);
@@ -204,7 +204,7 @@ void ED_node_tree_path_get_fixedbuf(SpaceNode *snode, char *value, int max_lengt
int size, i;
value[0] = '\0';
- for (path = snode->treepath.first, i = 0; path; path = path->next, ++i) {
+ for (path = snode->treepath.first, i = 0; path; path = path->next, i++) {
if (i == 0) {
size = BLI_strncpy_rlen(value, path->node_name, max_length);
}
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c
index 4740c412083..309446db83b 100644
--- a/source/blender/editors/space_outliner/outliner_collections.c
+++ b/source/blender/editors/space_outliner/outliner_collections.c
@@ -89,7 +89,7 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te)
}
else if (ELEM(tselem->type, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
Scene *scene = (Scene *)tselem->id;
- return BKE_collection_master(scene);
+ return scene->master_collection;
}
else if (tselem->type == 0 && te->idcode == ID_GR) {
return (Collection *)tselem->id;
@@ -199,7 +199,7 @@ static int collection_new_exec(bContext *C, wmOperator *op)
}
if (data.collection == NULL || ID_IS_LINKED(data.collection)) {
- data.collection = BKE_collection_master(scene);
+ data.collection = scene->master_collection;
}
if (ID_IS_LINKED(scene)) {
@@ -514,14 +514,14 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op)
* This can happen when a whole scene is linked e.g. */
if (parent != NULL && ID_IS_LINKED(parent)) {
Scene *scene = CTX_data_scene(C);
- parent = ID_IS_LINKED(scene) ? NULL : BKE_collection_master(scene);
+ parent = ID_IS_LINKED(scene) ? NULL : scene->master_collection;
}
else if (parent != NULL && (parent->flag & COLLECTION_IS_MASTER) != 0) {
Scene *scene = BKE_collection_master_scene_search(bmain, parent);
BLI_assert(scene != NULL);
if (ID_IS_LINKED(scene)) {
scene = CTX_data_scene(C);
- parent = ID_IS_LINKED(scene) ? NULL : BKE_collection_master(scene);
+ parent = ID_IS_LINKED(scene) ? NULL : scene->master_collection;
}
}
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c
index 6031ba5cffc..602031a6854 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.c
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.c
@@ -56,8 +56,6 @@
#include "UI_resources.h"
#include "UI_view2d.h"
-#include "GPU_state.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -537,7 +535,7 @@ static int scene_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent
Collection *collection;
if (scene != CTX_data_scene(C)) {
/* when linking to an inactive scene link to the master collection */
- collection = BKE_collection_master(scene);
+ collection = scene->master_collection;
}
else {
collection = CTX_data_collection(C);
@@ -967,7 +965,7 @@ static int outliner_item_drag_drop_invoke(bContext *C,
}
else {
Scene *scene = CTX_data_scene(C);
- parent = BKE_collection_master(scene);
+ parent = scene->master_collection;
}
WM_drag_add_ID(drag, id, &parent->id);
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 943993cb810..c81d292a859 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -674,7 +674,7 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Outliner ID data Remap";
+ ot->name = "Outliner ID Data Remap";
ot->idname = "OUTLINER_OT_id_remap";
/* callbacks */
@@ -770,7 +770,11 @@ static int outliner_id_copy_exec(bContext *C, wmOperator *op)
BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend");
BKE_copybuffer_save(bmain, str, op->reports);
- BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-blocks", num_ids);
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ num_ids == 1 ? "Copied %d selected data-block" :
+ "Copied %d selected data-blocks",
+ num_ids);
return OPERATOR_FINISHED;
}
@@ -804,7 +808,11 @@ static int outliner_id_paste_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_WINDOW, NULL);
- BKE_reportf(op->reports, RPT_INFO, "%d data-blocks pasted", num_pasted);
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ num_pasted == 1 ? "%d data-block pasted" :
+ "%d data-blocks pasted",
+ num_pasted);
return OPERATOR_FINISHED;
}
@@ -2257,7 +2265,11 @@ static int outliner_orphans_purge_exec(bContext *C, wmOperator *op)
BKE_id_multi_tagged_delete(bmain);
- BKE_reportf(op->reports, RPT_INFO, "Deleted %d data-blocks", num_tagged[INDEX_ID_NULL]);
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ num_tagged[INDEX_ID_NULL] == 1 ? "Deleted %d data-block" :
+ "Deleted %d data-blocks",
+ num_tagged[INDEX_ID_NULL]);
/* XXX: tree management normally happens from draw_outliner(), but when
* you're clicking to fast on Delete object from context menu in
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index 4b57d4ad771..9d7efc7fe46 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -27,9 +27,6 @@
#include "BLT_translation.h"
-#include "GPU_immediate.h"
-#include "GPU_state.h"
-
#include "RNA_access.h"
#include "UI_interface.h"
diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.c
index cf734526958..29c820bce92 100644
--- a/source/blender/editors/space_outliner/outliner_sync.c
+++ b/source/blender/editors/space_outliner/outliner_sync.c
@@ -134,7 +134,7 @@ static void outliner_sync_select_from_outliner_set_types(bContext *C,
const bool sequence_view = soops->outlinevis == SO_SEQUENCE;
- sync_types->object = !sequence_view && (obact && obact->mode == OB_MODE_OBJECT);
+ sync_types->object = !sequence_view;
sync_types->edit_bone = !sequence_view && (obedit && obedit->type == OB_ARMATURE);
sync_types->pose_bone = !sequence_view && (obact && obact->mode == OB_MODE_POSE);
sync_types->sequence = sequence_view;
@@ -143,8 +143,9 @@ static void outliner_sync_select_from_outliner_set_types(bContext *C,
/**
* Current dirty flags and outliner display mode determine which type of syncing should occur.
* This is to ensure sync flag data is not lost on sync in the wrong display mode.
+ * Returns true if a sync is needed.
*/
-static void outliner_sync_select_to_outliner_set_types(const bContext *C,
+static bool outliner_sync_select_to_outliner_set_types(const bContext *C,
SpaceOutliner *soops,
SyncSelectTypes *sync_types)
{
@@ -153,7 +154,7 @@ static void outliner_sync_select_to_outliner_set_types(const bContext *C,
const bool sequence_view = soops->outlinevis == SO_SEQUENCE;
- sync_types->object = !sequence_view && (obact && obact->mode == OB_MODE_OBJECT) &&
+ sync_types->object = !sequence_view &&
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_OBJECT);
sync_types->edit_bone = !sequence_view && (obedit && obedit->type == OB_ARMATURE) &&
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE);
@@ -161,6 +162,9 @@ static void outliner_sync_select_to_outliner_set_types(const bContext *C,
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_POSE_BONE);
sync_types->sequence = sequence_view &&
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_SEQUENCE);
+
+ return sync_types->object || sync_types->edit_bone || sync_types->pose_bone ||
+ sync_types->sequence;
}
/**
@@ -366,17 +370,22 @@ void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *soops)
selected_items_free(&selected_items);
- /* Tag for updates */
+ /* Tag for updates and clear dirty flag toprevent a sync to the outliner on draw */
if (sync_types.object) {
+ soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_OBJECT;
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
+ else if (sync_types.edit_bone) {
+ soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE;
+ }
+ else if (sync_types.pose_bone) {
+ soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_POSE_BONE;
+ }
if (sync_types.sequence) {
+ soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_SEQUENCE;
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
}
-
- /* Clear outliner sync select dirty flag to prevent a sync to the outliner on draw */
- soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_ALL;
}
static void outliner_select_sync_from_object(ViewLayer *view_layer,
@@ -393,6 +402,9 @@ static void outliner_select_sync_from_object(ViewLayer *view_layer,
if (base && (ob == obact)) {
outliner_element_activate(soops, tselem);
}
+ else {
+ tselem->flag &= ~TSE_ACTIVE;
+ }
if (is_selected) {
tselem->flag |= TSE_SELECTED;
@@ -412,6 +424,9 @@ static void outliner_select_sync_from_edit_bone(SpaceOutliner *soops,
if (ebone == ebone_active) {
outliner_element_activate(soops, tselem);
}
+ else {
+ tselem->flag &= ~TSE_ACTIVE;
+ }
if (ebone->flag & BONE_SELECTED) {
tselem->flag |= TSE_SELECTED;
@@ -432,6 +447,9 @@ static void outliner_select_sync_from_pose_bone(SpaceOutliner *soops,
if (pchan == pchan_active) {
outliner_element_activate(soops, tselem);
}
+ else {
+ tselem->flag &= ~TSE_ACTIVE;
+ }
if (bone->flag & BONE_SELECTED) {
tselem->flag |= TSE_SELECTED;
@@ -450,6 +468,9 @@ static void outliner_select_sync_from_sequence(SpaceOutliner *soops,
if (seq == sequence_active) {
outliner_element_activate(soops, tselem);
}
+ else {
+ tselem->flag &= ~TSE_ACTIVE;
+ }
if (seq->flag & SELECT) {
tselem->flag |= TSE_SELECTED;
@@ -523,12 +544,12 @@ static void get_sync_select_active_data(const bContext *C, SyncSelectActiveData
/* If outliner is dirty sync selection from view layer and sequwncer */
void outliner_sync_selection(const bContext *C, SpaceOutliner *soops)
{
- if (soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_ALL) {
- ViewLayer *view_layer = CTX_data_view_layer(C);
+ /* Set which types of data to sync from sync dirty flag and outliner display mode */
+ SyncSelectTypes sync_types;
+ const bool sync_required = outliner_sync_select_to_outliner_set_types(C, soops, &sync_types);
- /* Set which types of data to sync from sync dirty flag and outliner display mode */
- SyncSelectTypes sync_types;
- outliner_sync_select_to_outliner_set_types(C, soops, &sync_types);
+ if (sync_required) {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
/* Store active object, bones, and sequence */
SyncSelectActiveData active_data;
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 2c4a648da65..219943d08a6 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -299,7 +299,7 @@ static void unlink_collection_cb(bContext *C,
}
else if (GS(tsep->id->name) == ID_SCE) {
Scene *scene = (Scene *)tsep->id;
- Collection *parent = BKE_collection_master(scene);
+ Collection *parent = scene->master_collection;
id_fake_user_set(&collection->id);
BKE_collection_child_remove(bmain, parent, collection);
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
@@ -338,7 +338,7 @@ static void unlink_object_cb(bContext *C,
}
else if (GS(tsep->id->name) == ID_SCE) {
Scene *scene = (Scene *)tsep->id;
- Collection *parent = BKE_collection_master(scene);
+ Collection *parent = scene->master_collection;
BKE_collection_object_remove(bmain, parent, ob, true);
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
@@ -680,12 +680,7 @@ static void object_delete_cb(bContext *C,
if (ob == CTX_data_edit_object(C)) {
ED_object_editmode_exit(C, EM_FREEDATA);
}
- ED_object_base_free_and_unlink(CTX_data_main(C), scene, ob);
- /* leave for ED_outliner_id_unref to handle */
-#if 0
- te->directdata = NULL;
- tselem->id = NULL;
-#endif
+ BKE_id_delete(bmain, ob);
}
}
@@ -718,12 +713,15 @@ static void id_override_library_cb(bContext *C,
TreeStoreElem *tselem,
void *UNUSED(user_data))
{
- if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) {
+ if (ID_IS_OVERRIDABLE_LIBRARY(tselem->id)) {
Main *bmain = CTX_data_main(C);
- ID *override_id = BKE_override_library_create_from_id(bmain, tselem->id);
+ /* For now, remapp all local usages of linked ID to local override one here. */
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, true);
+ ID *override_id = BKE_override_library_create_from_id(bmain, tselem->id, true);
if (override_id != NULL) {
BKE_main_id_clear_newpoins(bmain);
}
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
}
}
@@ -1204,11 +1202,6 @@ static void object_delete_hierarchy_cb(bContext *C,
}
outline_delete_hierarchy(C, reports, scene, base);
- /* leave for ED_outliner_id_unref to handle */
-#if 0
- te->directdata = NULL;
- tselem->id = NULL;
-#endif
}
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
@@ -1292,11 +1285,6 @@ static void object_batch_delete_hierarchy_cb(bContext *C,
}
outline_batch_delete_hierarchy(reports, CTX_data_main(C), view_layer, scene, base);
- /* leave for ED_outliner_id_unref to handle */
-#if 0
- te->directdata = NULL;
- tselem->id = NULL;
-#endif
}
}
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index c3168a7a532..fd6a052b84d 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -1601,7 +1601,7 @@ typedef struct tTreeSort {
short idcode;
} tTreeSort;
-/* alphabetical comparator, tryping to put objects first */
+/* alphabetical comparator, trying to put objects first */
static int treesort_alpha_ob(const void *v1, const void *v2)
{
const tTreeSort *x1 = v1, *x2 = v2;
@@ -1627,7 +1627,7 @@ static int treesort_alpha_ob(const void *v1, const void *v2)
return (x1->te->flag & TE_CHILD_NOT_IN_COLLECTION) ? 1 : -1;
}
- comp = strcmp(x1->name, x2->name);
+ comp = BLI_strcasecmp_natural(x1->name, x2->name);
if (comp > 0) {
return 1;
@@ -1659,7 +1659,7 @@ static int treesort_alpha(const void *v1, const void *v2)
const tTreeSort *x1 = v1, *x2 = v2;
int comp;
- comp = strcmp(x1->name, x2->name);
+ comp = BLI_strcasecmp_natural(x1->name, x2->name);
if (comp > 0) {
return 1;
@@ -1697,7 +1697,7 @@ static int treesort_obtype_alpha(const void *v1, const void *v2)
}
}
else {
- int comp = strcmp(x1->name, x2->name);
+ int comp = BLI_strcasecmp_natural(x1->name, x2->name);
if (comp > 0) {
return 1;
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index 79880c68120..68eea4f278b 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -229,6 +229,11 @@ static void outliner_main_region_listener(wmWindow *UNUSED(win),
ED_region_tag_redraw(ar);
}
break;
+ case NC_TEXT:
+ if (ELEM(wmn->action, NA_ADDED, NA_REMOVED)) {
+ ED_region_tag_redraw(ar);
+ }
+ break;
}
}
diff --git a/source/blender/editors/space_script/script_edit.c b/source/blender/editors/space_script/script_edit.c
index 48248fe1dd2..2be05785d2b 100644
--- a/source/blender/editors/space_script/script_edit.c
+++ b/source/blender/editors/space_script/script_edit.c
@@ -106,6 +106,7 @@ static bool script_test_modal_operators(bContext *C)
static int script_reload_exec(bContext *C, wmOperator *op)
{
+
#ifdef WITH_PYTHON
/* clear running operators */
@@ -114,6 +115,8 @@ static int script_reload_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ WM_script_tag_reload();
+
/* TODO, this crashes on netrender and keying sets, need to look into why
* disable for now unless running in debug mode */
WM_cursor_wait(1);
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index b24f8e8d00f..8a15c05dd4a 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -336,7 +336,7 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
}
seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_SCENE);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+ seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
seq->scene = sce_seq;
@@ -420,7 +420,7 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op)
}
seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MOVIECLIP);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+ seq->blend_mode = SEQ_TYPE_CROSS;
seq->clip = clip;
id_us_ensure_real(&seq->clip->id);
@@ -504,7 +504,7 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op)
}
seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MASK);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+ seq->blend_mode = SEQ_TYPE_CROSS;
seq->mask = mask;
id_us_ensure_real(&seq->mask->id);
@@ -1091,8 +1091,14 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
if (seq->type == SEQ_TYPE_COLOR) {
SolidColorVars *colvars = (SolidColorVars *)seq->effectdata;
RNA_float_get_array(op->ptr, "color", colvars->col);
+ seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
+ }
+ else if (seq->type == SEQ_TYPE_ADJUSTMENT) {
+ seq->blend_mode = SEQ_TYPE_CROSS;
+ }
+ else if (seq->type == SEQ_TYPE_TEXT) {
+ seq->blend_mode = SEQ_TYPE_ALPHAOVER;
}
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
/* an unset channel is a special case where we automatically go above
* the other strips. */
@@ -1169,7 +1175,7 @@ void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot)
RNA_def_enum(ot->srna,
"type",
sequencer_prop_effect_types,
- SEQ_TYPE_ALPHAOVER,
+ SEQ_TYPE_CROSS,
"Type",
"Sequencer effect type");
RNA_def_float_vector(ot->srna,
diff --git a/source/blender/editors/space_sequencer/sequencer_buttons.c b/source/blender/editors/space_sequencer/sequencer_buttons.c
index 6740c2baad2..7bec913900d 100644
--- a/source/blender/editors/space_sequencer/sequencer_buttons.c
+++ b/source/blender/editors/space_sequencer/sequencer_buttons.c
@@ -117,5 +117,6 @@ void sequencer_buttons_register(ARegionType *art)
pt->poll = metadata_panel_context_poll;
pt->draw = metadata_panel_context_draw;
pt->flag |= PNL_DEFAULT_CLOSED;
+ pt->order = 10;
BLI_addtail(&art->paneltypes, pt);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index b15acb12d00..1a788237e6e 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -72,6 +72,7 @@
#include "UI_view2d.h"
#include "WM_api.h"
+#include "WM_types.h"
#include "MEM_guardedalloc.h"
@@ -333,7 +334,7 @@ static void drawseqwave(View2D *v2d,
value2 = (1.0f - f) * value2 + f * waveform->data[p * 3 + 4];
}
- if (fcu) {
+ if (fcu && !BKE_fcurve_is_empty(fcu)) {
float evaltime = x1_offset + (i * stepsize);
volume = evaluate_fcurve(fcu, evaltime);
}
@@ -1223,6 +1224,14 @@ void sequencer_draw_maskedit(const bContext *C, Scene *scene, ARegion *ar, Space
}
#endif
+/* Force redraw, when prefetching and using cache view. */
+static void seq_prefetch_wm_notify(const bContext *C, Scene *scene)
+{
+ if (BKE_sequencer_prefetch_need_redraw(CTX_data_main(C), scene)) {
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, NULL);
+ }
+}
+
static void *sequencer_OCIO_transform_ibuf(
const bContext *C, ImBuf *ibuf, bool *glsl_used, int *format, int *type)
{
@@ -1612,6 +1621,7 @@ void sequencer_draw_preview(const bContext *C,
}
UI_view2d_view_restore(C);
+ seq_prefetch_wm_notify(C, scene);
}
#if 0
@@ -2004,6 +2014,8 @@ void draw_timeline_seq(const bContext *C, ARegion *ar)
short cfra_flag = 0;
float col[3];
+ seq_prefetch_wm_notify(C, scene);
+
/* clear and setup matrix */
UI_GetThemeColor3fv(TH_BACK, col);
if (ed && ed->metastack.first) {
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 22b73c32bfe..9d7163cd6d9 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -3894,7 +3894,7 @@ void SEQUENCER_OT_change_effect_type(struct wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna,
"type",
sequencer_prop_effect_types,
- SEQ_TYPE_ALPHAOVER,
+ SEQ_TYPE_CROSS,
"Type",
"Sequencer effect type");
}
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index c1a3c79b0d8..088f06e9da8 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -29,6 +29,7 @@
#include "BLI_blenlib.h"
+#include "BKE_global.h"
#include "BKE_context.h"
#include "BKE_library.h"
#include "BKE_screen.h"
@@ -310,11 +311,11 @@ static void text_main_region_draw(const bContext *C, ARegion *ar)
static void text_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
{
SpaceText *st = sa->spacedata.first;
- int wmcursor = BC_TEXTEDITCURSOR;
+ int wmcursor = WM_CURSOR_TEXT_EDIT;
if (st->text &&
BLI_rcti_isect_pt(&st->txtbar, win->eventstate->x - ar->winrct.xmin, st->txtbar.ymin)) {
- wmcursor = CURSOR_STD;
+ wmcursor = WM_CURSOR_DEFAULT;
}
WM_cursor_set(win, wmcursor);
@@ -356,7 +357,7 @@ static void text_drop_paste(wmDrag *drag, wmDropBox *drop)
ID *id = WM_drag_ID(drag, 0);
/* copy drag path to properties */
- text = RNA_path_full_ID_py(id);
+ text = RNA_path_full_ID_py(G_MAIN, id);
RNA_string_set(drop->ptr, "text", text);
MEM_freeN(text);
}
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index e1550deb659..f9557225b6b 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -142,7 +142,7 @@ static char *buf_tabs_to_spaces(const char *in_buf, const int tab_size)
BLI_INLINE int text_pixel_x_to_column(SpaceText *st, const int x)
{
- /* add half the char width so mouse cursor selection is inbetween letters */
+ /* Add half the char width so mouse cursor selection is in between letters. */
return (x + (st->cwidth / 2)) / st->cwidth;
}
@@ -443,6 +443,8 @@ static int text_reload_exec(bContext *C, wmOperator *op)
text_drawcache_tag_update(CTX_wm_space_text(C), 1);
WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text);
+ text->flags &= ~TXT_ISDIRTY;
+
/* return to scroll position */
st->top = orig_top;
txt_screen_clamp(st, ar);
@@ -3482,7 +3484,7 @@ static int text_find_and_replace(bContext *C, wmOperator *op, short mode)
}
else {
if (!found) {
- BKE_reportf(op->reports, RPT_ERROR, "Text not found: %s", st->findstr);
+ BKE_reportf(op->reports, RPT_WARNING, "Text not found: %s", st->findstr);
}
}
diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c
index 4c6f2231cc1..a42ab048907 100644
--- a/source/blender/editors/space_userpref/space_userpref.c
+++ b/source/blender/editors/space_userpref/space_userpref.c
@@ -121,7 +121,7 @@ static void userpref_main_region_init(wmWindowManager *wm, ARegion *ar)
static void userpref_main_region_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels_ex(C, ar, NULL, U.userpref, true);
+ ED_region_panels_ex(C, ar, NULL, U.space_data.section_active, true);
}
static void userpref_operatortypes(void)
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index dc375958eb4..7c75f0ea907 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -33,6 +33,9 @@ set(INC
../../../../intern/glew-mx
../../../../intern/guardedalloc
../../../../intern/smoke/extern
+
+ # dna_type_offsets.h
+ ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern
)
set(INC_SYS
@@ -96,3 +99,6 @@ if(WITH_MOD_SMOKE)
endif()
blender_add_lib(bf_editor_space_view3d "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+# Needed so we can use dna_type_offsets.h for defaults initialization.
+add_dependencies(bf_editor_space_view3d bf_dna)
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index b412a72cce1..2cdfd8039c1 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -35,11 +35,9 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
-#include "GPU_draw.h"
#include "GPU_shader.h"
#include "GPU_immediate.h"
#include "GPU_batch.h"
-#include "GPU_matrix.h"
#include "GPU_state.h"
#include "ED_mesh.h"
@@ -96,7 +94,7 @@ void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], un
circball_array_fill(verts, cent, rad, tmat);
immBegin(GPU_PRIM_LINE_LOOP, CIRCLE_RESOL);
- for (int i = 0; i < CIRCLE_RESOL; ++i) {
+ for (int i = 0; i < CIRCLE_RESOL; i++) {
immVertex3fv(pos, verts[i]);
}
immEnd();
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 5974100b534..fbb6dfb8f8f 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -29,6 +29,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_defaults.h"
#include "MEM_guardedalloc.h"
@@ -39,6 +40,7 @@
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_icons.h"
+#include "BKE_idprop.h"
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_mball.h"
@@ -52,9 +54,6 @@
#include "ED_screen.h"
#include "ED_transform.h"
-#include "GPU_framebuffer.h"
-#include "GPU_material.h"
-#include "GPU_viewport.h"
#include "GPU_matrix.h"
#include "DRW_engine.h"
@@ -246,56 +245,11 @@ static SpaceLink *view3d_new(const ScrArea *UNUSED(sa), const Scene *scene)
View3D *v3d;
RegionView3D *rv3d;
- v3d = MEM_callocN(sizeof(View3D), "initview3d");
- v3d->spacetype = SPACE_VIEW3D;
+ v3d = DNA_struct_default_alloc(View3D);
+
if (scene) {
v3d->camera = scene->camera;
}
- v3d->scenelock = true;
- v3d->grid = 1.0f;
- v3d->gridlines = 16;
- v3d->gridsubdiv = 10;
- BKE_screen_view3d_shading_init(&v3d->shading);
-
- v3d->overlay.wireframe_threshold = 1.0f;
- v3d->overlay.xray_alpha_bone = 0.5f;
- v3d->overlay.texture_paint_mode_opacity = 1.0f;
- v3d->overlay.weight_paint_mode_opacity = 1.0f;
- v3d->overlay.vertex_paint_mode_opacity = 1.0f;
- /* Intentionally different to vertex/paint mode,
- * we typically want to see shading too. */
- v3d->overlay.sculpt_mode_mask_opacity = 0.75f;
-
- v3d->overlay.edit_flag = V3D_OVERLAY_EDIT_FACES | V3D_OVERLAY_EDIT_SEAMS |
- V3D_OVERLAY_EDIT_SHARP | V3D_OVERLAY_EDIT_FREESTYLE_EDGE |
- V3D_OVERLAY_EDIT_FREESTYLE_FACE | V3D_OVERLAY_EDIT_EDGES |
- V3D_OVERLAY_EDIT_CREASES | V3D_OVERLAY_EDIT_BWEIGHTS |
- V3D_OVERLAY_EDIT_CU_HANDLES | V3D_OVERLAY_EDIT_CU_NORMALS;
-
- v3d->gridflag = V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_FLOOR | V3D_SHOW_ORTHO_GRID;
-
- v3d->flag = V3D_SELECT_OUTLINE;
- v3d->flag2 = V3D_SHOW_RECONSTRUCTION | V3D_SHOW_ANNOTATION;
-
- v3d->lens = 50.0f;
- v3d->clip_start = 0.01f;
- v3d->clip_end = 1000.0f;
-
- v3d->overlay.gpencil_paper_opacity = 0.5f;
- v3d->overlay.gpencil_grid_opacity = 0.9f;
-
- v3d->bundle_size = 0.2f;
- v3d->bundle_drawtype = OB_PLAINAXES;
-
- /* stereo */
- v3d->stereo3d_camera = STEREO_3D_ID;
- v3d->stereo3d_flag |= V3D_S3D_DISPPLANE;
- v3d->stereo3d_convergence_alpha = 0.15f;
- v3d->stereo3d_volume_alpha = 0.05f;
-
- /* grease pencil settings */
- v3d->vertex_opacity = 1.0f;
- v3d->gp_flag |= V3D_GP_SHOW_EDIT_LINES;
/* tool header */
ar = MEM_callocN(sizeof(ARegion), "tool header for view3d");
@@ -363,6 +317,11 @@ static void view3d_free(SpaceLink *sl)
if (vd->fx_settings.dof) {
MEM_freeN(vd->fx_settings.dof);
}
+
+ if (vd->shading.prop) {
+ IDP_FreeProperty(vd->shading.prop);
+ vd->shading.prop = NULL;
+ }
}
/* spacetype; init callback */
@@ -386,6 +345,10 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl)
v3dn->shading.type = OB_SOLID;
}
+ if (v3dn->shading.prop) {
+ v3dn->shading.prop = IDP_CopyProperty(v3do->shading.prop);
+ }
+
/* copy or clear inside new stuff */
v3dn->runtime.properties_storage = NULL;
@@ -618,7 +581,7 @@ static void view3d_lightcache_update(bContext *C)
Scene *scene = CTX_data_scene(C);
- if (strcmp(scene->r.engine, RE_engine_id_BLENDER_EEVEE) != 0) {
+ if (!BKE_scene_uses_blender_eevee(scene)) {
/* Only do auto bake if eevee is the active engine */
return;
}
@@ -1079,10 +1042,10 @@ static void view3d_main_region_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
if (obedit) {
- WM_cursor_set(win, CURSOR_EDIT);
+ WM_cursor_set(win, WM_CURSOR_EDIT);
}
else {
- WM_cursor_set(win, CURSOR_STD);
+ WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index 3d3c73ad27c..9ab56dba72d 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -106,7 +106,9 @@ typedef union {
/* temporary struct for storing transform properties */
typedef struct {
+ float ob_obmat_orig[4][4];
float ob_dims_orig[3];
+ float ob_scale_orig[3];
float ob_dims[3];
/* Floats only (treated as an array). */
TransformMedian ve_median, median;
@@ -1050,6 +1052,8 @@ static void v3d_object_dimension_buts(bContext *C, uiLayout *layout, View3D *v3d
BKE_object_dimensions_get(ob, tfp->ob_dims);
copy_v3_v3(tfp->ob_dims_orig, tfp->ob_dims);
+ copy_v3_v3(tfp->ob_scale_orig, ob->scale);
+ copy_m4_m4(tfp->ob_obmat_orig, ob->obmat);
uiDefBut(block,
UI_BTYPE_LABEL,
@@ -1095,7 +1099,8 @@ static void v3d_object_dimension_buts(bContext *C, uiLayout *layout, View3D *v3d
axis_mask |= (1 << i);
}
}
- BKE_object_dimensions_set(ob, tfp->ob_dims, axis_mask);
+ BKE_object_dimensions_set_ex(
+ ob, tfp->ob_dims, axis_mask, tfp->ob_scale_orig, tfp->ob_obmat_orig);
PointerRNA obptr;
RNA_id_pointer_create(&ob->id, &obptr);
@@ -1461,6 +1466,7 @@ static void v3d_editarmature_buts(uiLayout *layout, Object *ob)
uiItemR(col, &eboneptr, "tail_radius", 0, IFACE_("Radius"), ICON_NONE);
uiItemR(col, &eboneptr, "roll", 0, NULL, ICON_NONE);
+ uiItemR(col, &eboneptr, "length", 0, NULL, ICON_NONE);
uiItemR(col, &eboneptr, "envelope_distance", 0, IFACE_("Envelope"), ICON_NONE);
}
diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c
index f8f97848d14..260546738f4 100644
--- a/source/blender/editors/space_view3d/view3d_camera_control.c
+++ b/source/blender/editors/space_view3d/view3d_camera_control.c
@@ -208,8 +208,8 @@ void ED_view3d_cameracontrol_update(View3DCameraControl *vctrl,
const bool do_rotate,
const bool do_translate)
{
- /* we are in camera view so apply the view ofs and quat to the view matrix and set the camera
- * to the view */
+ /* We are in camera view so apply the view offset and rotation to the view matrix
+ * and set the camera to the view. */
Scene *scene = vctrl->ctx_scene;
View3D *v3d = vctrl->ctx_v3d;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index f6afa112f08..aafd36a5bb8 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -39,6 +39,7 @@
#include "BKE_scene.h"
#include "BKE_object.h"
#include "BKE_paint.h"
+#include "BKE_studiolight.h"
#include "BKE_unit.h"
#include "BLF_api.h"
@@ -1088,7 +1089,7 @@ static void draw_rotation_guide(const RegionView3D *rv3d)
color[3] = 63; /* somewhat faint */
immAttr4ubv(col, color);
float angle = 0.0f;
- for (int i = 0; i < ROT_AXIS_DETAIL; ++i, angle += step) {
+ for (int i = 0; i < ROT_AXIS_DETAIL; i++, angle += step) {
float p[3] = {s * cosf(angle), s * sinf(angle), 0.0f};
if (!upright) {
@@ -1860,6 +1861,9 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph,
if (drawtype == OB_MATERIAL) {
v3d.shading.flag = V3D_SHADING_SCENE_WORLD | V3D_SHADING_SCENE_LIGHTS;
}
+ else if (drawtype == OB_RENDER) {
+ v3d.shading.flag = V3D_SHADING_SCENE_WORLD_RENDER | V3D_SHADING_SCENE_LIGHTS_RENDER;
+ }
v3d.flag2 = V3D_HIDE_OVERLAYS;
diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c
index d5772e5052a..acc46935eb5 100644
--- a/source/blender/editors/space_view3d/view3d_draw_legacy.c
+++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c
@@ -88,14 +88,8 @@
#include "UI_interface_icons.h"
#include "UI_resources.h"
-#include "GPU_draw.h"
#include "GPU_framebuffer.h"
-#include "GPU_material.h"
-#include "GPU_extensions.h"
#include "GPU_immediate.h"
-#include "GPU_immediate_util.h"
-#include "GPU_select.h"
-#include "GPU_matrix.h"
#include "GPU_state.h"
#include "GPU_viewport.h"
@@ -389,6 +383,14 @@ void ED_view3d_datamask(const bContext *C,
r_cddata_masks->lmask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
r_cddata_masks->vmask |= CD_MASK_ORCO;
}
+ else if (v3d->shading.type == OB_SOLID) {
+ if (v3d->shading.color_type == V3D_SHADING_TEXTURE_COLOR) {
+ r_cddata_masks->lmask |= CD_MASK_MLOOPUV;
+ }
+ if (v3d->shading.color_type == V3D_SHADING_VERTEX_COLOR) {
+ r_cddata_masks->lmask |= CD_MASK_MLOOPCOL;
+ }
+ }
if ((CTX_data_mode_enum(C) == CTX_MODE_EDIT_MESH) &&
(v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_WEIGHT)) {
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index e76ef2b0458..3ad194a5d2b 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -2997,7 +2997,7 @@ static int viewselected_exec(bContext *C, wmOperator *op)
ok = paintface_minmax(ob_eval, min, max);
}
else if (ob_eval && (ob_eval->mode & OB_MODE_PARTICLE_EDIT)) {
- ok = PE_minmax(scene, view_layer_eval, min, max);
+ ok = PE_minmax(depsgraph, scene, CTX_data_view_layer(C), min, max);
}
else if (ob_eval && (ob_eval->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT |
OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) {
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
index 3c911e266a9..53a5609d437 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
@@ -213,7 +213,7 @@ static void WIDGETGROUP_navigate_setup(const bContext *C, wmGizmoGroup *gzgroup)
{
wmGizmo *gz = navgroup->gz_array[GZ_INDEX_ROTATE];
gz->scale_basis = GIZMO_SIZE / 2;
- char mapping[6] = {
+ const char mapping[6] = {
RV3D_VIEW_LEFT,
RV3D_VIEW_RIGHT,
RV3D_VIEW_FRONT,
@@ -274,7 +274,7 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
float icon_offset_from_axis = 0.0f;
switch ((eUserpref_MiniAxisType)U.mini_axis_type) {
case USER_MINI_AXIS_TYPE_GIZMO:
- icon_offset_from_axis = icon_offset * 2.0f;
+ icon_offset_from_axis = icon_offset * 2.1f;
break;
case USER_MINI_AXIS_TYPE_MINIMAL:
icon_offset_from_axis = (UI_UNIT_X * 2.5) + ((U.rvisize * U.pixelsize * 2.0f));
@@ -285,8 +285,8 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
}
const float co[2] = {
- rect_visible->xmax - icon_offset_from_axis,
- rect_visible->ymax - icon_offset_mini * 0.75f,
+ rect_visible->xmax - icon_offset_mini * 0.75f,
+ rect_visible->ymax - icon_offset_from_axis,
};
wmGizmo *gz;
@@ -307,25 +307,25 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
if (show_navigate) {
int icon_mini_slot = 0;
gz = navgroup->gz_array[GZ_INDEX_ZOOM];
- gz->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++);
- gz->matrix_basis[3][1] = co[1];
+ gz->matrix_basis[3][0] = co[0];
+ gz->matrix_basis[3][1] = co[1] - (icon_offset_mini * icon_mini_slot++);
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
gz = navgroup->gz_array[GZ_INDEX_MOVE];
- gz->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++);
- gz->matrix_basis[3][1] = co[1];
+ gz->matrix_basis[3][0] = co[0];
+ gz->matrix_basis[3][1] = co[1] - (icon_offset_mini * icon_mini_slot++);
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
gz = navgroup->gz_array[GZ_INDEX_CAMERA];
- gz->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++);
- gz->matrix_basis[3][1] = co[1];
+ gz->matrix_basis[3][0] = co[0];
+ gz->matrix_basis[3][1] = co[1] - (icon_offset_mini * icon_mini_slot++);
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
if (navgroup->state.rv3d.is_camera == false) {
gz = navgroup->gz_array[rv3d->is_persp ? GZ_INDEX_PERSP : GZ_INDEX_ORTHO];
- gz->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++);
- gz->matrix_basis[3][1] = co[1];
+ gz->matrix_basis[3][0] = co[0];
+ gz->matrix_basis[3][1] = co[1] - (icon_offset_mini * icon_mini_slot++);
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
index 539b5d93bdf..d6d3a3dc563 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
@@ -479,7 +479,7 @@ static int gizmo_axis_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mv
float i_best_len_sq = FLT_MAX;
for (int i = 0; i < 3; i++) {
for (int is_pos = 0; is_pos < 2; is_pos++) {
- float co[2] = {
+ const float co[2] = {
gz->matrix_offset[i][0] * (is_pos ? 1 : -1),
gz->matrix_offset[i][1] * (is_pos ? 1 : -1),
};
@@ -518,9 +518,9 @@ static int gizmo_axis_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mv
static int gizmo_axis_cursor_get(wmGizmo *gz)
{
if (gz->highlight_part > 0) {
- return CURSOR_EDIT;
+ return WM_CURSOR_EDIT;
}
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
void VIEW3D_GT_navigate_rotate(wmGizmoType *gzt)
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c
index a984e339305..68159e2d684 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c
@@ -77,7 +77,20 @@ static void gizmo_preselect_elem_draw(const bContext *UNUSED(C), wmGizmo *gz)
static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int mval[2])
{
+ wmEvent *event = CTX_wm_window(C)->eventstate;
MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz;
+
+ /* Hack: Switch action mode based on key input */
+ const bool is_ctrl_pressed = WM_event_modifier_flag(event) & KM_CTRL;
+ const bool is_shift_pressed = WM_event_modifier_flag(event) & KM_SHIFT;
+ EDBM_preselect_action_set(gz_ele->psel, PRESELECT_ACTION_TRANSFORM);
+ if (is_ctrl_pressed && !is_shift_pressed) {
+ EDBM_preselect_action_set(gz_ele->psel, PRESELECT_ACTION_CREATE);
+ }
+ if (!is_ctrl_pressed && is_shift_pressed) {
+ EDBM_preselect_action_set(gz_ele->psel, PRESELECT_ACTION_DELETE);
+ }
+
struct {
Object *ob;
BMElem *ele;
@@ -87,18 +100,6 @@ static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int
.dist = ED_view3d_select_dist_px(),
};
- struct {
- int base_index;
- int vert_index;
- int edge_index;
- int face_index;
- } prev = {
- .base_index = gz_ele->base_index,
- .vert_index = gz_ele->vert_index,
- .edge_index = gz_ele->edge_index,
- .face_index = gz_ele->face_index,
- };
-
{
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -115,32 +116,66 @@ static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int
{
/* TODO: support faces. */
- int base_index = -1;
+ int base_index_vert = -1;
+ int base_index_edge = -1;
+ int base_index_face = -1;
BMVert *eve_test;
BMEdge *eed_test;
+ BMFace *efa_test;
if (EDBM_unified_findnearest_from_raycast(&vc,
gz_ele->bases,
gz_ele->bases_len,
+ false,
true,
- &base_index,
+ &base_index_vert,
+ &base_index_edge,
+ &base_index_face,
&eve_test,
&eed_test,
- NULL)) {
- Base *base = gz_ele->bases[base_index];
- best.ob = base->object;
- if (eve_test) {
- best.ele = (BMElem *)eve_test;
- }
- else if (eed_test) {
- best.ele = (BMElem *)eed_test;
+ &efa_test)) {
+ if (EDBM_preselect_action_get(gz_ele->psel) == PRESELECT_ACTION_DELETE) {
+ /* Delete action */
+ if (efa_test) {
+ best.ele = (BMElem *)efa_test;
+ best.base_index = base_index_face;
+ }
}
+
else {
- BLI_assert(0);
+ /* Transform and create action */
+ if (eed_test) {
+ best.ele = (BMElem *)eed_test;
+ best.base_index = base_index_edge;
+ }
+ }
+
+ /* All actions use same vertex pre-selection. */
+ /* Re-topology should always prioritize edge pre-selection.
+ * Only pre-select a vertex when the cursor is really close to it. */
+ if (eve_test) {
+ BMVert *vert = (BMVert *)eve_test;
+ float vert_p_co[3], vert_co[3];
+ float mval_f[2] = {UNPACK2(vc.mval)};
+ mul_v3_m4v3(vert_co, gz_ele->bases[base_index_vert]->object->obmat, vert->co);
+ ED_view3d_project(vc.ar, vert_co, vert_p_co);
+ float len = len_v2v2(vert_p_co, mval_f);
+ if (len < 35) {
+ best.ele = (BMElem *)eve_test;
+ best.base_index = base_index_vert;
+ }
+ if (!BM_vert_is_boundary(vert) &&
+ EDBM_preselect_action_get(gz_ele->psel) != PRESELECT_ACTION_DELETE) {
+ best.ele = (BMElem *)eve_test;
+ best.base_index = base_index_vert;
+ }
}
- best.base_index = base_index;
+
/* Check above should never fail, if it does it's an internal error. */
BLI_assert(best.base_index != -1);
+
+ Base *base = gz_ele->bases[best.base_index];
+ best.ob = base->object;
}
}
@@ -167,32 +202,30 @@ static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int
}
}
- if ((prev.base_index == gz_ele->base_index) && (prev.vert_index == gz_ele->vert_index) &&
- (prev.edge_index == gz_ele->edge_index) && (prev.face_index == gz_ele->face_index)) {
- /* pass (only recalculate on change) */
- }
- else {
- if (best.ele) {
- const float(*coords)[3] = NULL;
- {
- Object *ob = gz_ele->bases[gz_ele->base_index]->object;
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, ob->data);
- if (me_eval->runtime.edit_data) {
- coords = me_eval->runtime.edit_data->vertexCos;
- }
+ if (best.ele) {
+ const float(*coords)[3] = NULL;
+ {
+ Object *ob = gz_ele->bases[gz_ele->base_index]->object;
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, ob->data);
+ if (me_eval->runtime.edit_data) {
+ coords = me_eval->runtime.edit_data->vertexCos;
}
- EDBM_preselect_elem_update_from_single(gz_ele->psel, bm, best.ele, coords);
- }
- else {
- EDBM_preselect_elem_clear(gz_ele->psel);
}
+ EDBM_preselect_elem_update_from_single(gz_ele->psel, bm, best.ele, coords);
+ EDBM_preselect_elem_update_preview(gz_ele->psel, &vc, bm, best.ele, mval);
+ }
+ else {
+ EDBM_preselect_elem_clear(gz_ele->psel);
+ EDBM_preselect_preview_clear(gz_ele->psel);
+ }
- RNA_int_set(gz->ptr, "object_index", gz_ele->base_index);
- RNA_int_set(gz->ptr, "vert_index", gz_ele->vert_index);
- RNA_int_set(gz->ptr, "edge_index", gz_ele->edge_index);
- RNA_int_set(gz->ptr, "face_index", gz_ele->face_index);
+ RNA_int_set(gz->ptr, "object_index", gz_ele->base_index);
+ RNA_int_set(gz->ptr, "vert_index", gz_ele->vert_index);
+ RNA_int_set(gz->ptr, "edge_index", gz_ele->edge_index);
+ RNA_int_set(gz->ptr, "face_index", gz_ele->face_index);
+ if (best.ele) {
ARegion *ar = CTX_wm_region(C);
ED_region_tag_redraw(ar);
}
@@ -471,5 +504,4 @@ void ED_view3d_gizmo_mesh_preselect_get_active(bContext *C,
}
}
}
-
/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
index f4e3dc85447..5625333d837 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
@@ -61,7 +61,6 @@
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
-#include "GPU_select.h"
#include "GPU_state.h"
#include "BLF_api.h"
@@ -1014,9 +1013,9 @@ static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel)
static int gizmo_ruler_cursor_get(wmGizmo *gz)
{
if (gz->highlight_part == PART_LINE) {
- return BC_CROSSCURSOR;
+ return WM_CURSOR_CROSS;
}
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
void VIEW3D_GT_ruler_item(wmGizmoType *gzt)
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 6984562337c..200cc12a6c1 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -109,17 +109,17 @@ static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event)
switch (event) {
case B_SEL_VERT:
- if (EDBM_selectmode_toggle(C, SCE_SELECT_VERTEX, -1, shift, ctrl)) {
+ if (EDBM_selectmode_toggle_multi(C, SCE_SELECT_VERTEX, -1, shift, ctrl)) {
ED_undo_push(C, "Selectmode Set: Vertex");
}
break;
case B_SEL_EDGE:
- if (EDBM_selectmode_toggle(C, SCE_SELECT_EDGE, -1, shift, ctrl)) {
+ if (EDBM_selectmode_toggle_multi(C, SCE_SELECT_EDGE, -1, shift, ctrl)) {
ED_undo_push(C, "Selectmode Set: Edge");
}
break;
case B_SEL_FACE:
- if (EDBM_selectmode_toggle(C, SCE_SELECT_FACE, -1, shift, ctrl)) {
+ if (EDBM_selectmode_toggle_multi(C, SCE_SELECT_FACE, -1, shift, ctrl)) {
ED_undo_push(C, "Selectmode Set: Face");
}
break;
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index e5a145b0411..37eea6b03d7 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -79,7 +79,11 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op)
BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend");
BKE_copybuffer_save(bmain, str, op->reports);
- BKE_reportf(op->reports, RPT_INFO, "Copied %d selected objects", num_copied);
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ num_copied == 1 ? "Copied %d selected object" :
+ "Copied %d selected objects",
+ num_copied);
return OPERATOR_FINISHED;
}
@@ -118,7 +122,11 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_WINDOW, NULL);
- BKE_reportf(op->reports, RPT_INFO, "%d objects pasted", num_pasted);
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ num_pasted == 1 ? "%d object pasted" :
+ "%d objects pasted",
+ num_pasted);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index b81b7e0109e..56c8b4bcbe9 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -116,7 +116,7 @@ eV3DProjStatus ED_view3d_project_base(const struct ARegion *ar, struct Base *bas
* - 'rv3d->persmatob', is_local == true
*/
static eV3DProjStatus ed_view3d_project__internal(const ARegion *ar,
- float perspmat[4][4],
+ const float perspmat[4][4],
const bool is_local, /* normally hidden */
const float co[3],
float r_co[2],
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 1c9ce142165..198b5d05540 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -97,7 +97,6 @@
#include "UI_interface.h"
-#include "GPU_draw.h"
#include "GPU_glew.h"
#include "GPU_matrix.h"
@@ -121,13 +120,13 @@ float ED_view3d_select_dist_px(void)
}
/* TODO: should return whether there is valid context to continue */
-void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc)
+void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc, Depsgraph *depsgraph)
{
memset(vc, 0, sizeof(ViewContext));
vc->C = C;
vc->ar = CTX_wm_region(C);
vc->bmain = CTX_data_main(C);
- vc->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ vc->depsgraph = depsgraph;
vc->scene = CTX_data_scene(C);
vc->view_layer = CTX_data_view_layer(C);
vc->v3d = CTX_wm_view3d(C);
@@ -1345,11 +1344,12 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
if (mcords) {
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
view3d_operator_needs_opengl(C);
BKE_object_update_select_id(CTX_data_main(C));
/* setup view context for argument to callbacks */
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
bool changed_multi = view3d_lasso_select(C, &vc, mcords, mcords_tot, sel_op);
@@ -1890,6 +1890,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
/* mval comes from event->mval, only use within region handlers */
Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
Base *basact = NULL;
uint buffer[MAXPICKBUF];
@@ -1898,7 +1899,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
view3d_operator_needs_opengl(C);
BKE_object_update_select_id(CTX_data_main(C));
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
const bool do_nearest = !XRAY_ACTIVE(vc.v3d);
const int hits = mixed_bones_object_selectbuffer(
@@ -1956,9 +1957,10 @@ static bool ed_object_select_pick(bContext *C,
bool enumerate,
bool object)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
/* setup view context for argument to callbacks */
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
@@ -3204,6 +3206,7 @@ static bool do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const e
static int view3d_box_select_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
rcti rect;
bool changed_multi = false;
@@ -3215,7 +3218,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
BKE_object_update_select_id(CTX_data_main(C));
/* setup view context for argument to callbacks */
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
WM_operator_properties_border_to_rcti(op, &rect);
@@ -4005,6 +4008,7 @@ static bool object_circle_select(ViewContext *vc,
/* not a real operator, only for circle test */
static int view3d_circle_select_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
const int radius = RNA_int_get(op->ptr, "radius");
const int mval[2] = {RNA_int_get(op->ptr, "x"), RNA_int_get(op->ptr, "y")};
@@ -4017,7 +4021,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"),
WM_gesture_is_modal_first(gesture));
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
Object *obact = vc.obact;
Object *obedit = vc.obedit;
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 2515ee6e482..dd8e2e07271 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -27,6 +27,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_utildefines.h"
@@ -195,8 +196,8 @@ void ED_view3d_smooth_view_ex(
sms.to_camera = true; /* restore view3d values in end */
}
- /* skip smooth viewing for render engine draw */
- if (smooth_viewtx && v3d->shading.type != OB_RENDER) {
+ /* skip smooth viewing for external render engine draw */
+ if (smooth_viewtx && !(v3d->shading.type == OB_RENDER && rv3d->render_engine)) {
bool changed = false; /* zero means no difference */
if (sview->camera_old != sview->camera) {
@@ -507,7 +508,7 @@ static bool view3d_camera_to_view_poll(bContext *C)
void VIEW3D_OT_camera_to_view(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Align Camera To View";
+ ot->name = "Align Camera to View";
ot->description = "Set camera view to active view";
ot->idname = "VIEW3D_OT_camera_to_view";
@@ -1187,7 +1188,7 @@ finally:
/** \name Local View Operators
* \{ */
-static uint free_localbit(Main *bmain)
+static uint free_localview_bit(Main *bmain)
{
ScrArea *sa;
bScreen *sc;
@@ -1242,7 +1243,7 @@ static bool view3d_localview_init(const Depsgraph *depsgraph,
INIT_MINMAX(min, max);
- local_view_bit = free_localbit(bmain);
+ local_view_bit = free_localview_bit(bmain);
if (local_view_bit == 0) {
/* TODO(dfelinto): We can kick one of the other 3D views out of local view
@@ -1534,3 +1535,134 @@ void VIEW3D_OT_localview_remove_from(wmOperatorType *ot)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Local Collections
+ * \{ */
+
+static uint free_localcollection_bit(Main *bmain,
+ unsigned short local_collections_uuid,
+ bool *reset)
+{
+ ScrArea *sa;
+ bScreen *sc;
+
+ ushort local_view_bits = 0;
+
+ /* Check all areas: which localviews are in use? */
+ for (sc = bmain->screens.first; sc; sc = sc->id.next) {
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ SpaceLink *sl = sa->spacedata.first;
+ for (; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ if (v3d->flag & V3D_LOCAL_COLLECTIONS) {
+ local_view_bits |= v3d->local_collections_uuid;
+ }
+ }
+ }
+ }
+ }
+
+ /* First try to keep the old uuid. */
+ if (local_collections_uuid && ((local_collections_uuid & local_view_bits) == 0)) {
+ return local_collections_uuid;
+ }
+
+ /* Otherwise get the first free available. */
+ for (int i = 0; i < 16; i++) {
+ if ((local_view_bits & (1 << i)) == 0) {
+ *reset = true;
+ return (1 << i);
+ }
+ }
+
+ return 0;
+}
+
+static void local_collections_reset_uuid(LayerCollection *layer_collection,
+ const unsigned short local_view_bit)
+{
+ layer_collection->local_collections_bits |= local_view_bit;
+ LISTBASE_FOREACH (LayerCollection *, child, &layer_collection->layer_collections) {
+ local_collections_reset_uuid(child, local_view_bit);
+ }
+}
+
+static void view3d_local_collections_reset(Main *bmain, const uint local_view_bit)
+{
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ LISTBASE_FOREACH (LayerCollection *, layer_collection, &view_layer->layer_collections) {
+ local_collections_reset_uuid(layer_collection, local_view_bit);
+ }
+ }
+ }
+}
+
+/**
+ * See if current uuid is valid, otherwise set a valid uuid to v3d,
+ * Try to keep the same uuid previously used to allow users to
+ * quickly toggle back and forth.
+ */
+bool ED_view3d_local_collections_set(Main *bmain, struct View3D *v3d)
+{
+ if ((v3d->flag & V3D_LOCAL_COLLECTIONS) == 0) {
+ return true;
+ }
+
+ bool reset = false;
+ v3d->flag &= ~V3D_LOCAL_COLLECTIONS;
+ uint local_view_bit = free_localcollection_bit(bmain, v3d->local_collections_uuid, &reset);
+
+ if (local_view_bit == 0) {
+ return false;
+ }
+
+ v3d->local_collections_uuid = local_view_bit;
+ v3d->flag |= V3D_LOCAL_COLLECTIONS;
+
+ if (reset) {
+ view3d_local_collections_reset(bmain, local_view_bit);
+ }
+
+ return true;
+}
+
+void ED_view3d_local_collections_reset(struct bContext *C, const bool reset_all)
+{
+ Main *bmain = CTX_data_main(C);
+ uint local_view_bit = ~(0);
+ bool do_reset = false;
+
+ /* Reset only the ones that are not in use. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ if (v3d->local_collections_uuid) {
+ if (v3d->flag & V3D_LOCAL_COLLECTIONS) {
+ local_view_bit &= ~v3d->local_collections_uuid;
+ }
+ else {
+ do_reset = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (do_reset) {
+ view3d_local_collections_reset(bmain, local_view_bit);
+ }
+ else if (reset_all && (do_reset || (local_view_bit != ~(0)))) {
+ view3d_local_collections_reset(bmain, ~(0));
+ View3D v3d = {.local_collections_uuid = ~(0)};
+ BKE_layer_collection_local_sync(CTX_data_view_layer(C), &v3d);
+ DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_BASE_FLAGS);
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 91c05f5cac6..ac9ad30d719 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -577,7 +577,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->ar->winrct.ymin + walk->center_mval[1]);
/* remove the mouse cursor temporarily */
- WM_cursor_modal_set(win, CURSOR_NONE);
+ WM_cursor_modal_set(win, WM_CURSOR_NONE);
return 1;
}
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index 9696f0fb315..e3ff8b92081 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -40,7 +40,25 @@ set(INC_SYS
set(SRC
transform.c
transform_constraints.c
- transform_conversions.c
+ transform_convert.c
+ transform_convert_action.c
+ transform_convert_armature.c
+ transform_convert_cursor.c
+ transform_convert_curve.c
+ transform_convert_gpencil.c
+ transform_convert_graph.c
+ transform_convert_lattice.c
+ transform_convert_mask.c
+ transform_convert_mball.c
+ transform_convert_mesh.c
+ transform_convert_nla.c
+ transform_convert_node.c
+ transform_convert_object.c
+ transform_convert_paintcurve.c
+ transform_convert_particle.c
+ transform_convert_sculpt.c
+ transform_convert_sequencer.c
+ transform_convert_tracking.c
transform_generics.c
transform_gizmo_2d.c
transform_gizmo_3d.c
@@ -52,6 +70,7 @@ set(SRC
transform_snap_object.c
transform.h
+ transform_convert.h
)
set(LIB
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 6478928a6b6..67ea0f255fc 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -65,7 +65,6 @@
#include "DEG_depsgraph.h"
#include "GPU_immediate.h"
-#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
#include "GPU_state.h"
@@ -79,6 +78,7 @@
#include "ED_clip.h"
#include "ED_node.h"
#include "ED_gpencil.h"
+#include "ED_sculpt.h"
#include "WM_types.h"
#include "WM_api.h"
@@ -95,6 +95,7 @@
#include "BLT_translation.h"
#include "transform.h"
+#include "transform_convert.h"
/* Disabling, since when you type you know what you are doing,
* and being able to set it to zero is handy. */
@@ -1793,7 +1794,7 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
if (t->helpline != HLP_NONE) {
float cent[2];
- float mval[3] = {
+ const float mval[3] = {
x,
y,
0.0f,
@@ -2298,16 +2299,14 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
}
+ if ((t->options & CTX_SCULPT) && !(t->options & CTX_PAINT_CURVE)) {
+ ED_sculpt_end_transform(C);
+ }
+
if ((prop = RNA_struct_find_property(op->ptr, "correct_uv"))) {
RNA_property_boolean_set(
op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) != 0);
}
-
- if (t->mode == TFM_SHEAR) {
- prop = RNA_struct_find_property(op->ptr, "shear_axis");
- t->custom.mode.data = POINTER_FROM_INT(RNA_property_enum_get(op->ptr, prop));
- RNA_property_enum_set(op->ptr, prop, POINTER_AS_INT(t->custom.mode.data));
- }
}
/**
@@ -2347,6 +2346,11 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
+ Object *ob = CTX_data_active_object(C);
+ if (ob && ob->mode == OB_MODE_SCULPT && ob->sculpt) {
+ options |= CTX_SCULPT;
+ }
+
t->options = options;
t->mode = mode;
@@ -2409,6 +2413,10 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
createTransData(C, t); // make TransData structs from selection
+ if (t->options & CTX_SCULPT) {
+ ED_sculpt_init_transform(C);
+ }
+
if (t->data_len_all == 0) {
postTrans(C, t);
return 0;
@@ -2517,8 +2525,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
initToSphere(t);
break;
case TFM_SHEAR:
- prop = RNA_struct_find_property(op->ptr, "shear_axis");
- t->custom.mode.data = POINTER_FROM_INT(RNA_property_enum_get(op->ptr, prop));
initShear(t);
break;
case TFM_BEND:
@@ -3515,13 +3521,7 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
static void initShear_mouseInputMode(TransInfo *t)
{
float dir[3];
-
- if (t->custom.mode.data == NULL) {
- copy_v3_v3(dir, t->orient_matrix[t->orient_axis_ortho]);
- }
- else {
- cross_v3_v3v3(dir, t->orient_matrix[t->orient_axis_ortho], t->orient_matrix[t->orient_axis]);
- }
+ copy_v3_v3(dir, t->orient_matrix[t->orient_axis_ortho]);
/* Without this, half the gizmo handles move in the opposite direction. */
if ((t->orient_axis_ortho + 1) % 3 != t->orient_axis) {
@@ -3569,24 +3569,22 @@ static eRedrawFlag handleEventShear(TransInfo *t, const wmEvent *event)
if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) {
/* Use custom.mode.data pointer to signal Shear direction */
- if (t->custom.mode.data == NULL) {
- t->custom.mode.data = (void *)1;
- }
- else {
- t->custom.mode.data = NULL;
- }
+ do {
+ t->orient_axis_ortho = (t->orient_axis_ortho + 1) % 3;
+ } while (t->orient_axis_ortho == t->orient_axis);
+
initShear_mouseInputMode(t);
status = TREDRAW_HARD;
}
else if (event->type == XKEY && event->val == KM_PRESS) {
- t->custom.mode.data = NULL;
+ t->orient_axis_ortho = (t->orient_axis + 1) % 3;
initShear_mouseInputMode(t);
status = TREDRAW_HARD;
}
else if (event->type == YKEY && event->val == KM_PRESS) {
- t->custom.mode.data = (void *)1;
+ t->orient_axis_ortho = (t->orient_axis + 2) % 3;
initShear_mouseInputMode(t);
status = TREDRAW_HARD;
@@ -3630,14 +3628,7 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
}
unit_m3(smat);
-
- // Custom data signals shear direction
- if (t->custom.mode.data == NULL) {
- smat[1][0] = value;
- }
- else {
- smat[0][1] = value;
- }
+ smat[1][0] = value;
copy_v3_v3(axismat_inv[0], t->orient_matrix[t->orient_axis_ortho]);
copy_v3_v3(axismat_inv[2], t->orient_matrix[t->orient_axis]);
@@ -3878,7 +3869,7 @@ static void ElementResize(TransInfo *t, TransDataContainer *tc, TransData *td, f
if (td->ext && td->ext->size) {
float fsize[3];
- if (t->flag & (T_OBJECT | T_TEXTURE | T_POSE)) {
+ if ((t->options & CTX_SCULPT) || t->flag & (T_OBJECT | T_TEXTURE | T_POSE)) {
float obsizemat[3][3];
/* Reorient the size mat to fit the oriented object. */
mul_m3_m3m3(obsizemat, tmat, td->axismtx);
@@ -4331,8 +4322,11 @@ static void headerRotation(TransInfo *t, char str[UI_MAX_DRAW_STR], float final)
*
* Protected axis and other transform settings are taken into account.
*/
-static void ElementRotation_ex(
- TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const float *center)
+static void ElementRotation_ex(TransInfo *t,
+ TransDataContainer *tc,
+ TransData *td,
+ const float mat[3][3],
+ const float *center)
{
float vec[3], totmat[3][3], smat[3][3];
float eul[3], fmat[3][3], quat[4];
@@ -4736,7 +4730,7 @@ static void initTrackball(TransInfo *t)
static void applyTrackballValue(TransInfo *t,
const float axis1[3],
const float axis2[3],
- float angles[2])
+ const float angles[2])
{
float mat[3][3];
float axis[3];
@@ -6398,367 +6392,6 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
/** \} */
/* -------------------------------------------------------------------- */
-/* Original Data Store */
-
-/** \name Orig-Data Store Utility Functions
- * \{ */
-
-static void slide_origdata_init_flag(TransInfo *t, TransDataContainer *tc, SlideOrigData *sod)
-{
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- BMesh *bm = em->bm;
- const bool has_layer_math = CustomData_has_math(&bm->ldata);
- const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
-
- if ((t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) &&
- /* don't do this at all for non-basis shape keys, too easy to
- * accidentally break uv maps or vertex colors then */
- (bm->shapenr <= 1) && (has_layer_math || (cd_loop_mdisp_offset != -1))) {
- sod->use_origfaces = true;
- sod->cd_loop_mdisp_offset = cd_loop_mdisp_offset;
- }
- else {
- sod->use_origfaces = false;
- sod->cd_loop_mdisp_offset = -1;
- }
-}
-
-static void slide_origdata_init_data(TransDataContainer *tc, SlideOrigData *sod)
-{
- if (sod->use_origfaces) {
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- BMesh *bm = em->bm;
-
- sod->origfaces = BLI_ghash_ptr_new(__func__);
- sod->bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default,
- &((struct BMeshCreateParams){
- .use_toolflags = false,
- }));
- /* we need to have matching customdata */
- BM_mesh_copy_init_customdata(sod->bm_origfaces, bm, NULL);
- }
-}
-
-static void slide_origdata_create_data_vert(BMesh *bm,
- SlideOrigData *sod,
- TransDataGenericSlideVert *sv)
-{
- BMIter liter;
- int j, l_num;
- float *loop_weights;
-
- /* copy face data */
- // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) {
- BM_iter_init(&liter, bm, BM_LOOPS_OF_VERT, sv->v);
- l_num = liter.count;
- loop_weights = BLI_array_alloca(loop_weights, l_num);
- for (j = 0; j < l_num; j++) {
- BMLoop *l = BM_iter_step(&liter);
- BMLoop *l_prev, *l_next;
- void **val_p;
- if (!BLI_ghash_ensure_p(sod->origfaces, l->f, &val_p)) {
- BMFace *f_copy = BM_face_copy(sod->bm_origfaces, bm, l->f, true, true);
- *val_p = f_copy;
- }
-
- if ((l_prev = BM_loop_find_prev_nodouble(l, l->next, FLT_EPSILON)) &&
- (l_next = BM_loop_find_next_nodouble(l, l_prev, FLT_EPSILON))) {
- loop_weights[j] = angle_v3v3v3(l_prev->v->co, l->v->co, l_next->v->co);
- }
- else {
- loop_weights[j] = 0.0f;
- }
- }
-
- /* store cd_loop_groups */
- if (sod->layer_math_map_num && (l_num != 0)) {
- sv->cd_loop_groups = BLI_memarena_alloc(sod->arena, sod->layer_math_map_num * sizeof(void *));
- for (j = 0; j < sod->layer_math_map_num; j++) {
- const int layer_nr = sod->layer_math_map[j];
- sv->cd_loop_groups[j] = BM_vert_loop_groups_data_layer_create(
- bm, sv->v, layer_nr, loop_weights, sod->arena);
- }
- }
- else {
- sv->cd_loop_groups = NULL;
- }
-
- BLI_ghash_insert(sod->origverts, sv->v, sv);
-}
-
-static void slide_origdata_create_data(TransDataContainer *tc,
- SlideOrigData *sod,
- TransDataGenericSlideVert *sv_array,
- unsigned int v_stride,
- unsigned int v_num)
-{
- if (sod->use_origfaces) {
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- BMesh *bm = em->bm;
- unsigned int i;
- TransDataGenericSlideVert *sv;
-
- int layer_index_dst;
- int j;
-
- layer_index_dst = 0;
-
- /* TODO: We don't need `sod->layer_math_map` when there are no loops linked
- * to one of the sliding vertices. */
- if (CustomData_has_math(&bm->ldata)) {
- /* over alloc, only 'math' layers are indexed */
- sod->layer_math_map = MEM_mallocN(bm->ldata.totlayer * sizeof(int), __func__);
- for (j = 0; j < bm->ldata.totlayer; j++) {
- if (CustomData_layer_has_math(&bm->ldata, j)) {
- sod->layer_math_map[layer_index_dst++] = j;
- }
- }
- BLI_assert(layer_index_dst != 0);
- }
-
- sod->layer_math_map_num = layer_index_dst;
-
- sod->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
-
- sod->origverts = BLI_ghash_ptr_new_ex(__func__, v_num);
-
- for (i = 0, sv = sv_array; i < v_num; i++, sv = POINTER_OFFSET(sv, v_stride)) {
- slide_origdata_create_data_vert(bm, sod, sv);
- }
-
- if (tc->mirror.axis_flag) {
- TransData *td = tc->data;
- TransDataGenericSlideVert *sv_mirror;
-
- sod->sv_mirror = MEM_callocN(sizeof(*sv_mirror) * tc->data_len, __func__);
- sod->totsv_mirror = tc->data_len;
-
- sv_mirror = sod->sv_mirror;
-
- for (i = 0; i < tc->data_len; i++, td++) {
- BMVert *eve = td->extra;
- /* Check the vertex has been used since both sides
- * of the mirror may be selected & sliding. */
- if (eve && !BLI_ghash_haskey(sod->origverts, eve)) {
- sv_mirror->v = eve;
- copy_v3_v3(sv_mirror->co_orig_3d, eve->co);
-
- slide_origdata_create_data_vert(bm, sod, sv_mirror);
- sv_mirror++;
- }
- else {
- sod->totsv_mirror--;
- }
- }
-
- if (sod->totsv_mirror == 0) {
- MEM_freeN(sod->sv_mirror);
- sod->sv_mirror = NULL;
- }
- }
- }
-}
-
-/**
- * If we're sliding the vert, return its original location, if not, the current location is good.
- */
-static const float *slide_origdata_orig_vert_co(SlideOrigData *sod, BMVert *v)
-{
- TransDataGenericSlideVert *sv = BLI_ghash_lookup(sod->origverts, v);
- return sv ? sv->co_orig_3d : v->co;
-}
-
-static void slide_origdata_interp_data_vert(SlideOrigData *sod,
- BMesh *bm,
- bool is_final,
- TransDataGenericSlideVert *sv)
-{
- BMIter liter;
- int j, l_num;
- float *loop_weights;
- const bool is_moved = (len_squared_v3v3(sv->v->co, sv->co_orig_3d) > FLT_EPSILON);
- const bool do_loop_weight = sod->layer_math_map_num && is_moved;
- const bool do_loop_mdisps = is_final && is_moved && (sod->cd_loop_mdisp_offset != -1);
- const float *v_proj_axis = sv->v->no;
- /* original (l->prev, l, l->next) projections for each loop ('l' remains unchanged) */
- float v_proj[3][3];
-
- if (do_loop_weight || do_loop_mdisps) {
- project_plane_normalized_v3_v3v3(v_proj[1], sv->co_orig_3d, v_proj_axis);
- }
-
- // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT)
- BM_iter_init(&liter, bm, BM_LOOPS_OF_VERT, sv->v);
- l_num = liter.count;
- loop_weights = do_loop_weight ? BLI_array_alloca(loop_weights, l_num) : NULL;
- for (j = 0; j < l_num; j++) {
- BMFace *f_copy; /* the copy of 'f' */
- BMLoop *l = BM_iter_step(&liter);
-
- f_copy = BLI_ghash_lookup(sod->origfaces, l->f);
-
- /* only loop data, no vertex data since that contains shape keys,
- * and we do not want to mess up other shape keys */
- BM_loop_interp_from_face(bm, l, f_copy, false, false);
-
- /* make sure face-attributes are correct (e.g. #MLoopUV, #MLoopCol) */
- BM_elem_attrs_copy_ex(sod->bm_origfaces, bm, f_copy, l->f, 0x0, CD_MASK_NORMAL);
-
- /* weight the loop */
- if (do_loop_weight) {
- const float eps = 1.0e-8f;
- const BMLoop *l_prev = l->prev;
- const BMLoop *l_next = l->next;
- const float *co_prev = slide_origdata_orig_vert_co(sod, l_prev->v);
- const float *co_next = slide_origdata_orig_vert_co(sod, l_next->v);
- bool co_prev_ok;
- bool co_next_ok;
-
- /* In the unlikely case that we're next to a zero length edge -
- * walk around the to the next.
- *
- * Since we only need to check if the vertex is in this corner,
- * its not important _which_ loop - as long as its not overlapping
- * 'sv->co_orig_3d', see: T45096. */
- project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
- while (UNLIKELY(((co_prev_ok = (len_squared_v3v3(v_proj[1], v_proj[0]) > eps)) == false) &&
- ((l_prev = l_prev->prev) != l->next))) {
- co_prev = slide_origdata_orig_vert_co(sod, l_prev->v);
- project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
- }
- project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis);
- while (UNLIKELY(((co_next_ok = (len_squared_v3v3(v_proj[1], v_proj[2]) > eps)) == false) &&
- ((l_next = l_next->next) != l->prev))) {
- co_next = slide_origdata_orig_vert_co(sod, l_next->v);
- project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis);
- }
-
- if (co_prev_ok && co_next_ok) {
- const float dist = dist_signed_squared_to_corner_v3v3v3(
- sv->v->co, UNPACK3(v_proj), v_proj_axis);
-
- loop_weights[j] = (dist >= 0.0f) ? 1.0f : ((dist <= -eps) ? 0.0f : (1.0f + (dist / eps)));
- if (UNLIKELY(!isfinite(loop_weights[j]))) {
- loop_weights[j] = 0.0f;
- }
- }
- else {
- loop_weights[j] = 0.0f;
- }
- }
- }
-
- if (sod->layer_math_map_num && sv->cd_loop_groups) {
- if (do_loop_weight) {
- for (j = 0; j < sod->layer_math_map_num; j++) {
- BM_vert_loop_groups_data_layer_merge_weights(
- bm, sv->cd_loop_groups[j], sod->layer_math_map[j], loop_weights);
- }
- }
- else {
- for (j = 0; j < sod->layer_math_map_num; j++) {
- BM_vert_loop_groups_data_layer_merge(bm, sv->cd_loop_groups[j], sod->layer_math_map[j]);
- }
- }
- }
-
- /* Special handling for multires
- *
- * Interpolate from every other loop (not ideal)
- * However values will only be taken from loops which overlap other mdisps.
- * */
- if (do_loop_mdisps) {
- float(*faces_center)[3] = BLI_array_alloca(faces_center, l_num);
- BMLoop *l;
-
- BM_ITER_ELEM_INDEX (l, &liter, sv->v, BM_LOOPS_OF_VERT, j) {
- BM_face_calc_center_median(l->f, faces_center[j]);
- }
-
- BM_ITER_ELEM_INDEX (l, &liter, sv->v, BM_LOOPS_OF_VERT, j) {
- BMFace *f_copy = BLI_ghash_lookup(sod->origfaces, l->f);
- float f_copy_center[3];
- BMIter liter_other;
- BMLoop *l_other;
- int j_other;
-
- BM_face_calc_center_median(f_copy, f_copy_center);
-
- BM_ITER_ELEM_INDEX (l_other, &liter_other, sv->v, BM_LOOPS_OF_VERT, j_other) {
- BM_face_interp_multires_ex(bm,
- l_other->f,
- f_copy,
- faces_center[j_other],
- f_copy_center,
- sod->cd_loop_mdisp_offset);
- }
- }
- }
-}
-
-static void slide_origdata_interp_data(Object *obedit,
- SlideOrigData *sod,
- TransDataGenericSlideVert *sv,
- unsigned int v_stride,
- unsigned int v_num,
- bool is_final)
-{
- if (sod->use_origfaces) {
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- unsigned int i;
- const bool has_mdisps = (sod->cd_loop_mdisp_offset != -1);
-
- for (i = 0; i < v_num; i++, sv = POINTER_OFFSET(sv, v_stride)) {
-
- if (sv->cd_loop_groups || has_mdisps) {
- slide_origdata_interp_data_vert(sod, bm, is_final, sv);
- }
- }
-
- if (sod->sv_mirror) {
- sv = sod->sv_mirror;
- for (i = 0; i < v_num; i++, sv++) {
- if (sv->cd_loop_groups || has_mdisps) {
- slide_origdata_interp_data_vert(sod, bm, is_final, sv);
- }
- }
- }
- }
-}
-
-static void slide_origdata_free_date(SlideOrigData *sod)
-{
- if (sod->use_origfaces) {
- if (sod->bm_origfaces) {
- BM_mesh_free(sod->bm_origfaces);
- sod->bm_origfaces = NULL;
- }
-
- if (sod->origfaces) {
- BLI_ghash_free(sod->origfaces, NULL, NULL);
- sod->origfaces = NULL;
- }
-
- if (sod->origverts) {
- BLI_ghash_free(sod->origverts, NULL, NULL);
- sod->origverts = NULL;
- }
-
- if (sod->arena) {
- BLI_memarena_free(sod->arena);
- sod->arena = NULL;
- }
-
- MEM_SAFE_FREE(sod->layer_math_map);
-
- MEM_SAFE_FREE(sod->sv_mirror);
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/* Transform (Edge Slide) */
/** \name Transform Edge Slide
@@ -7209,8 +6842,6 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, TransDataContainer *t
View3D *v3d = NULL;
RegionView3D *rv3d = NULL;
- slide_origdata_init_flag(t, tc, &sld->orig_data);
-
sld->curr_sv_index = 0;
/*ensure valid selection*/
@@ -7541,18 +7172,10 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, TransDataContainer *t
calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, true);
- /* create copies of faces for customdata projection */
- bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
- slide_origdata_init_data(tc, &sld->orig_data);
- slide_origdata_create_data(
- tc, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
-
if (rv3d) {
calcEdgeSlide_even(t, tc, sld, mval);
}
- sld->em = em;
-
tc->custom.mode.data = sld;
MEM_freeN(sv_table);
@@ -7586,8 +7209,6 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, TransDataContainer *t
rv3d = t->ar ? t->ar->regiondata : NULL;
}
- slide_origdata_init_flag(t, tc, &sld->orig_data);
-
sld->curr_sv_index = 0;
/* ensure valid selection */
{
@@ -7736,18 +7357,10 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, TransDataContainer *t
calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, false);
- /* create copies of faces for customdata projection */
- bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
- slide_origdata_init_data(tc, &sld->orig_data);
- slide_origdata_create_data(
- tc, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
-
if (rv3d) {
calcEdgeSlide_even(t, tc, sld, mval);
}
- sld->em = em;
-
tc->custom.mode.data = sld;
MEM_freeN(sv_table);
@@ -7764,25 +7377,10 @@ void projectEdgeSlideData(TransInfo *t, bool is_final)
continue;
}
- SlideOrigData *sod = &sld->orig_data;
- if (sod->use_origfaces == false) {
- continue;
- }
-
- slide_origdata_interp_data(tc->obedit,
- sod,
- (TransDataGenericSlideVert *)sld->sv,
- sizeof(*sld->sv),
- sld->totsv,
- is_final);
+ trans_mesh_customdata_correction_apply(tc, is_final);
}
}
-void freeEdgeSlideTempFaces(EdgeSlideData *sld)
-{
- slide_origdata_free_date(&sld->orig_data);
-}
-
void freeEdgeSlideVerts(TransInfo *UNUSED(t),
TransDataContainer *UNUSED(tc),
TransCustomData *custom_data)
@@ -7793,10 +7391,6 @@ void freeEdgeSlideVerts(TransInfo *UNUSED(t),
return;
}
- freeEdgeSlideTempFaces(sld);
-
- bmesh_edit_end(sld->em->bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
-
MEM_freeN(sld->sv);
MEM_freeN(sld);
@@ -7855,6 +7449,8 @@ static void initEdgeSlide_ex(
tc->custom.mode.free_cb = freeEdgeSlideVerts;
}
+ trans_mesh_customdata_correction_init(t);
+
/* set custom point first if you want value to be initialized by init */
calcEdgeSlideCustomPoints(t);
initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO_FLIP);
@@ -8330,8 +7926,6 @@ static bool createVertSlideVerts(TransInfo *t, TransDataContainer *tc)
VertSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
int j;
- slide_origdata_init_flag(t, tc, &sld->orig_data);
-
sld->curr_sv_index = 0;
j = 0;
@@ -8395,13 +7989,6 @@ static bool createVertSlideVerts(TransInfo *t, TransDataContainer *tc)
sld->sv = sv_array;
sld->totsv = j;
- bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
- slide_origdata_init_data(tc, &sld->orig_data);
- slide_origdata_create_data(
- tc, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
-
- sld->em = em;
-
tc->custom.mode.data = sld;
/* most likely will be set below */
@@ -8430,24 +8017,10 @@ static bool createVertSlideVerts(TransInfo *t, TransDataContainer *tc)
void projectVertSlideData(TransInfo *t, bool is_final)
{
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- VertSlideData *sld = tc->custom.mode.data;
- SlideOrigData *sod = &sld->orig_data;
- if (sod->use_origfaces == true) {
- slide_origdata_interp_data(tc->obedit,
- sod,
- (TransDataGenericSlideVert *)sld->sv,
- sizeof(*sld->sv),
- sld->totsv,
- is_final);
- }
+ trans_mesh_customdata_correction_apply(tc, is_final);
}
}
-void freeVertSlideTempFaces(VertSlideData *sld)
-{
- slide_origdata_free_date(&sld->orig_data);
-}
-
void freeVertSlideVerts(TransInfo *UNUSED(t),
TransDataContainer *UNUSED(tc),
TransCustomData *custom_data)
@@ -8458,10 +8031,6 @@ void freeVertSlideVerts(TransInfo *UNUSED(t),
return;
}
- freeVertSlideTempFaces(sld);
-
- bmesh_edit_end(sld->em->bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
-
if (sld->totsv > 0) {
TransDataVertSlideVert *sv = sld->sv;
int i = 0;
@@ -8511,6 +8080,8 @@ static void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use
return;
}
+ trans_mesh_customdata_correction_init(t);
+
/* set custom point first if you want value to be initialized by init */
calcVertSlideCustomPoints(t);
initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO);
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 358e4825278..ff2afbc0cd7 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -267,7 +267,6 @@ typedef struct TransDataNla {
int handle;
} TransDataNla;
-struct GHash;
struct LinkNode;
/* header of TransDataEdgeSlideVert, TransDataEdgeSlideEdge */
@@ -294,38 +293,11 @@ typedef struct TransDataEdgeSlideVert {
int loop_nr;
} TransDataEdgeSlideVert;
-/* store original data so we can correct UV's and similar when sliding */
-typedef struct SlideOrigData {
- /** Set when #origfaces is initialized. */
- bool use_origfaces;
- int cd_loop_mdisp_offset;
-
- /** map {BMVert: TransDataGenericSlideVert} */
- struct GHash *origverts;
- struct GHash *origfaces;
- struct BMesh *bm_origfaces;
-
- struct MemArena *arena;
- /** Number of math BMLoop layers. */
- int layer_math_map_num;
- /** Array size of 'layer_math_map_num'
- * maps TransDataVertSlideVert.cd_group index to absolute CustomData layer index */
- int *layer_math_map;
-
- /** Array of slide vert data especially for mirror verts. */
- TransDataGenericSlideVert *sv_mirror;
- int totsv_mirror;
-} SlideOrigData;
-
typedef struct EdgeSlideData {
TransDataEdgeSlideVert *sv;
int totsv;
int mval_start[2], mval_end[2];
- struct BMEditMesh *em;
-
- SlideOrigData orig_data;
-
int curr_sv_index;
/** when un-clamped - use this index: #TransDataEdgeSlideVert.dir_side */
@@ -354,11 +326,6 @@ typedef struct TransDataVertSlideVert {
typedef struct VertSlideData {
TransDataVertSlideVert *sv;
int totsv;
-
- struct BMEditMesh *em;
-
- SlideOrigData orig_data;
-
int curr_sv_index;
/* result of ED_view3d_ob_project_mat_get */
@@ -449,6 +416,18 @@ typedef struct TransData {
short protectflag;
} TransData;
+typedef struct TransDataMirror {
+ /** location of mirrored reference data. */
+ const float *loc_src;
+ /** Location of the data to transform. */
+ float *loc_dst;
+ void *extra;
+ /* `sign` can be -2, -1, 0 or 1. */
+ int sign_x : 2;
+ int sign_y : 2;
+ int sign_z : 2;
+} TransDataMirror;
+
typedef struct MouseInput {
void (*apply)(struct TransInfo *t, struct MouseInput *mi, const double mval[2], float output[3]);
void (*post)(struct TransInfo *t, float values[3]);
@@ -549,10 +528,18 @@ typedef struct TransDataContainer {
* Mirror option
*/
struct {
- /* Currently for mesh X mirror only. */
- int axis_flag;
- /** Set to -1.0f or 1.0 when use_mirror is set. */
- float sign;
+ union {
+ struct {
+ uint axis_x : 1;
+ uint axis_y : 1;
+ uint axis_z : 1;
+ };
+ /* For easy checking. */
+ char use_mirror_any;
+ };
+ /** Mirror data array. */
+ TransDataMirror *data;
+ int data_len;
} mirror;
TransCustomDataContainer custom;
@@ -721,16 +708,6 @@ typedef struct TransInfo {
/** Typically for mode settings. */
TransCustomDataContainer custom;
-
- /**
- * Object to object data transform table.
- * Don't add these to transform data because we may want to include child objects
- * which aren't being transformed.
- * - The key is object data #ID.
- * - The value is #XFormObjectData_Extra.
- */
- struct GHash *obdata_in_obmode_map;
-
} TransInfo;
/* ******************** Macros & Prototypes *********************** */
@@ -802,10 +779,6 @@ enum {
T_MODAL_CURSOR_SET = 1 << 26,
T_CLNOR_REBUILD = 1 << 27,
-
- /** When transforming object's, adjust the object data so it stays in the same place. */
- T_OBJECT_DATA_IN_OBJECT_MODE = 1 << 28,
-
};
/** #TransInfo.modifiers */
@@ -874,16 +847,18 @@ enum {
/** For Graph Editor - curves that can only have int-values
* need their keyframes tagged with this. */
TD_INTVALUES = 1 << 15,
- /** For editmode mirror, clamp to x = 0 */
- TD_MIRROR_EDGE = 1 << 16,
+ /** For editmode mirror, clamp axis to 0 */
+ TD_MIRROR_EDGE_X = 1 << 16,
+ TD_MIRROR_EDGE_Y = 1 << 17,
+ TD_MIRROR_EDGE_Z = 1 << 18,
/** For fcurve handles, move them along with their keyframes */
- TD_MOVEHANDLE1 = 1 << 17,
- TD_MOVEHANDLE2 = 1 << 18,
+ TD_MOVEHANDLE1 = 1 << 19,
+ TD_MOVEHANDLE2 = 1 << 20,
/** Exceptional case with pose bone rotating when a parent bone has 'Local Location'
* option enabled and rotating also transforms it. */
- TD_PBONE_LOCAL_MTX_P = 1 << 19,
+ TD_PBONE_LOCAL_MTX_P = 1 << 21,
/** Same as above but for a child bone. */
- TD_PBONE_LOCAL_MTX_C = 1 << 20,
+ TD_PBONE_LOCAL_MTX_C = 1 << 22,
};
/** #TransSnap.status */
@@ -923,23 +898,6 @@ void drawPropCircle(const struct bContext *C, TransInfo *t);
struct wmKeyMap *transform_modal_keymap(struct wmKeyConfig *keyconf);
-/*********************** transform_conversions.c ********** */
-
-void flushTransIntFrameActionData(TransInfo *t);
-void flushTransGraphData(TransInfo *t);
-void remake_graph_transdata(TransInfo *t, struct ListBase *anim_data);
-void flushTransUVs(TransInfo *t);
-void flushTransParticles(TransInfo *t);
-bool clipUVTransform(TransInfo *t, float vec[2], const bool resize);
-void clipUVData(TransInfo *t);
-void flushTransNodes(TransInfo *t);
-void flushTransSeq(TransInfo *t);
-void flushTransTracking(TransInfo *t);
-void flushTransMasking(TransInfo *t);
-void flushTransPaintCurve(TransInfo *t);
-void restoreMirrorPoseBones(TransDataContainer *tc);
-void restoreBones(TransDataContainer *tc);
-
/*********************** transform_gizmo.c ********** */
#define GIZMO_AXIS_LINE_WIDTH 2.0f
@@ -949,32 +907,8 @@ bool gimbal_axis(struct Object *ob, float gmat[3][3]);
void drawDial3d(const TransInfo *t);
/*********************** TransData Creation and General Handling *********** */
-void createTransData(struct bContext *C, TransInfo *t);
-void sort_trans_data_dist(TransInfo *t);
-void special_aftertrans_update(struct bContext *C, TransInfo *t);
-int special_transform_moving(TransInfo *t);
-
-void transform_autoik_update(TransInfo *t, short mode);
bool transdata_check_local_islands(TransInfo *t, short around);
-int count_set_pose_transflags(struct Object *ob,
- const int mode,
- const short around,
- bool has_translate_rotate[2]);
-
-/* Auto-keyframe applied after transform, returns true if motion paths need to be updated. */
-void autokeyframe_object(struct bContext *C,
- struct Scene *scene,
- struct ViewLayer *view_layer,
- struct Object *ob,
- int tmode);
-void autokeyframe_pose(
- struct bContext *C, struct Scene *scene, struct Object *ob, int tmode, short targetless_ik);
-
-/* Test if we need to update motion paths for a given object. */
-bool motionpath_need_update_object(struct Scene *scene, struct Object *ob);
-bool motionpath_need_update_pose(struct Scene *scene, struct Object *ob);
-
/*********************** Constraints *****************************/
void drawConstraint(TransInfo *t);
@@ -1146,11 +1080,9 @@ int getTransformOrientation(const struct bContext *C, float normal[3], float pla
void freeCustomNormalArray(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data);
-void freeEdgeSlideTempFaces(EdgeSlideData *sld);
void freeEdgeSlideVerts(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data);
void projectEdgeSlideData(TransInfo *t, bool is_final);
-void freeVertSlideTempFaces(VertSlideData *sld);
void freeVertSlideVerts(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data);
void projectVertSlideData(TransInfo *t, bool is_final);
@@ -1179,7 +1111,4 @@ bool checkUseAxisMatrix(TransInfo *t);
th != tc_end; \
th++, i++)
-void trans_obdata_in_obmode_free_all(struct TransInfo *t);
-void trans_obdata_in_obmode_update_all(struct TransInfo *t);
-
#endif
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
deleted file mode 100644
index dc072d74be6..00000000000
--- a/source/blender/editors/transform/transform_conversions.c
+++ /dev/null
@@ -1,9925 +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) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup edtransform
- */
-
-#include <string.h>
-#include <math.h>
-#include <limits.h>
-
-#include "DNA_anim_types.h"
-#include "DNA_brush_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_lattice_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meta_types.h"
-#include "DNA_node_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_space_types.h"
-#include "DNA_sequence_types.h"
-#include "DNA_view3d_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_gpencil_types.h"
-#include "DNA_movieclip_types.h"
-#include "DNA_mask_types.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-#include "BLI_listbase.h"
-#include "BLI_linklist_stack.h"
-#include "BLI_string.h"
-#include "BLI_bitmap.h"
-#include "BLI_rect.h"
-#include "BLI_kdtree.h"
-
-#include "BKE_action.h"
-#include "BKE_animsys.h"
-#include "BKE_armature.h"
-#include "BKE_constraint.h"
-#include "BKE_context.h"
-#include "BKE_crazyspace.h"
-#include "BKE_curve.h"
-#include "BKE_fcurve.h"
-#include "BKE_global.h"
-#include "BKE_gpencil.h"
-#include "BKE_layer.h"
-#include "BKE_key.h"
-#include "BKE_main.h"
-#include "BKE_mesh.h"
-#include "BKE_mesh_mapping.h"
-#include "BKE_modifier.h"
-#include "BKE_movieclip.h"
-#include "BKE_nla.h"
-#include "BKE_node.h"
-#include "BKE_object.h"
-#include "BKE_particle.h"
-#include "BKE_paint.h"
-#include "BKE_pointcache.h"
-#include "BKE_report.h"
-#include "BKE_rigidbody.h"
-#include "BKE_scene.h"
-#include "BKE_sequencer.h"
-#include "BKE_editmesh.h"
-#include "BKE_tracking.h"
-#include "BKE_mask.h"
-#include "BKE_colortools.h"
-
-#include "BIK_api.h"
-
-#include "ED_anim_api.h"
-#include "ED_armature.h"
-#include "ED_particle.h"
-#include "ED_image.h"
-#include "ED_keyframing.h"
-#include "ED_keyframes_edit.h"
-#include "ED_object.h"
-#include "ED_markers.h"
-#include "ED_mesh.h"
-#include "ED_node.h"
-#include "ED_uvedit.h"
-#include "ED_clip.h"
-#include "ED_mask.h"
-#include "ED_gpencil.h"
-
-#include "WM_api.h" /* for WM_event_add_notifier to deal with stabilization nodes */
-#include "WM_types.h"
-
-#include "UI_view2d.h"
-#include "UI_interface.h"
-
-#include "RNA_access.h"
-
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_build.h"
-#include "DEG_depsgraph_query.h"
-
-#include "transform.h"
-#include "bmesh.h"
-
-/**
- * Transforming around ourselves is no use, fallback to individual origins,
- * useful for curve/armatures.
- */
-static void transform_around_single_fallback(TransInfo *t)
-{
- if ((t->data_len_all == 1) &&
- (ELEM(t->around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEDIAN, V3D_AROUND_ACTIVE)) &&
- (ELEM(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL))) {
- t->around = V3D_AROUND_LOCAL_ORIGINS;
- }
-}
-
-/* when transforming islands */
-struct TransIslandData {
- float co[3];
- float axismtx[3][3];
-};
-
-/* local function prototype - for Object/Bone Constraints */
-static bool constraints_list_needinv(TransInfo *t, ListBase *list);
-
-/* ************************** Functions *************************** */
-
-static int trans_data_compare_dist(const void *a, const void *b)
-{
- const TransData *td_a = (const TransData *)a;
- const TransData *td_b = (const TransData *)b;
-
- if (td_a->dist < td_b->dist) {
- return -1;
- }
- else if (td_a->dist > td_b->dist) {
- return 1;
- }
- else {
- return 0;
- }
-}
-
-static int trans_data_compare_rdist(const void *a, const void *b)
-{
- const TransData *td_a = (const TransData *)a;
- const TransData *td_b = (const TransData *)b;
-
- if (td_a->rdist < td_b->rdist) {
- return -1;
- }
- else if (td_a->rdist > td_b->rdist) {
- return 1;
- }
- else {
- return 0;
- }
-}
-
-static void sort_trans_data_dist_container(const TransInfo *t, TransDataContainer *tc)
-{
- TransData *start = tc->data;
- int i;
-
- for (i = 0; i < tc->data_len && start->flag & TD_SELECTED; i++) {
- start++;
- }
-
- if (i < tc->data_len) {
- if (t->flag & T_PROP_CONNECTED) {
- qsort(start, tc->data_len - i, sizeof(TransData), trans_data_compare_dist);
- }
- else {
- qsort(start, tc->data_len - i, sizeof(TransData), trans_data_compare_rdist);
- }
- }
-}
-void sort_trans_data_dist(TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- sort_trans_data_dist_container(t, tc);
- }
-}
-
-/**
- * Make #TD_SELECTED first in the array.
- */
-static void sort_trans_data_selected_first_container(TransDataContainer *tc)
-{
- TransData *sel, *unsel;
- TransData temp;
- unsel = tc->data;
- sel = tc->data;
- sel += tc->data_len - 1;
- while (sel > unsel) {
- while (unsel->flag & TD_SELECTED) {
- unsel++;
- if (unsel == sel) {
- return;
- }
- }
- while (!(sel->flag & TD_SELECTED)) {
- sel--;
- if (unsel == sel) {
- return;
- }
- }
- temp = *unsel;
- *unsel = *sel;
- *sel = temp;
- sel--;
- unsel++;
- }
-}
-static void sort_trans_data_selected_first(TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- sort_trans_data_selected_first_container(tc);
- }
-}
-
-/**
- * Distance calculated from not-selected vertex to nearest selected vertex.
- */
-static void set_prop_dist(TransInfo *t, const bool with_dist)
-{
- int a;
-
- float _proj_vec[3];
- const float *proj_vec = NULL;
-
- /* support for face-islands */
- const bool use_island = transdata_check_local_islands(t, t->around);
-
- if (t->flag & T_PROP_PROJECTED) {
- if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) {
- RegionView3D *rv3d = t->ar->regiondata;
- normalize_v3_v3(_proj_vec, rv3d->viewinv[2]);
- proj_vec = _proj_vec;
- }
- }
-
- /* Count number of selected. */
- int td_table_len = 0;
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (a = 0; a < tc->data_len; a++, td++) {
- if (td->flag & TD_SELECTED) {
- td_table_len++;
- }
- else {
- /* By definition transform-data has selected items in beginning. */
- break;
- }
- }
- }
-
- /* Pointers to selected's #TransData.
- * Used to find #TransData from the index returned by #BLI_kdtree_find_nearest. */
- TransData **td_table = MEM_mallocN(sizeof(*td_table) * td_table_len, __func__);
-
- /* Create and fill kd-tree of selected's positions - in global or proj_vec space. */
- KDTree_3d *td_tree = BLI_kdtree_3d_new(td_table_len);
-
- int td_table_index = 0;
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (a = 0; a < tc->data_len; a++, td++) {
- if (td->flag & TD_SELECTED) {
- /* Initialize, it was mallocced. */
- float vec[3];
- td->rdist = 0.0f;
-
- if (use_island) {
- if (tc->use_local_mat) {
- mul_v3_m4v3(vec, tc->mat, td->iloc);
- }
- else {
- mul_v3_m3v3(vec, td->mtx, td->iloc);
- }
- }
- else {
- if (tc->use_local_mat) {
- mul_v3_m4v3(vec, tc->mat, td->center);
- }
- else {
- mul_v3_m3v3(vec, td->mtx, td->center);
- }
- }
-
- if (proj_vec) {
- float vec_p[3];
- project_v3_v3v3(vec_p, vec, proj_vec);
- sub_v3_v3(vec, vec_p);
- }
-
- BLI_kdtree_3d_insert(td_tree, td_table_index, vec);
- td_table[td_table_index++] = td;
- }
- else {
- /* By definition transform-data has selected items in beginning. */
- break;
- }
- }
- }
- BLI_assert(td_table_index == td_table_len);
-
- BLI_kdtree_3d_balance(td_tree);
-
- /* For each non-selected vertex, find distance to the nearest selected vertex. */
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (a = 0; a < tc->data_len; a++, td++) {
- if ((td->flag & TD_SELECTED) == 0) {
- float vec[3];
-
- if (use_island) {
- if (tc->use_local_mat) {
- mul_v3_m4v3(vec, tc->mat, td->iloc);
- }
- else {
- mul_v3_m3v3(vec, td->mtx, td->iloc);
- }
- }
- else {
- if (tc->use_local_mat) {
- mul_v3_m4v3(vec, tc->mat, td->center);
- }
- else {
- mul_v3_m3v3(vec, td->mtx, td->center);
- }
- }
-
- if (proj_vec) {
- float vec_p[3];
- project_v3_v3v3(vec_p, vec, proj_vec);
- sub_v3_v3(vec, vec_p);
- }
-
- KDTreeNearest_3d nearest;
- const int td_index = BLI_kdtree_3d_find_nearest(td_tree, vec, &nearest);
-
- td->rdist = -1.0f;
- if (td_index != -1) {
- td->rdist = nearest.dist;
- if (use_island) {
- copy_v3_v3(td->center, td_table[td_index]->center);
- copy_m3_m3(td->axismtx, td_table[td_index]->axismtx);
- }
- }
-
- if (with_dist) {
- td->dist = td->rdist;
- }
- }
- }
- }
-
- BLI_kdtree_3d_free(td_tree);
- MEM_freeN(td_table);
-}
-
-/* ************************** CONVERSIONS ************************* */
-
-/* ********************* texture space ********* */
-
-static void createTransTexspace(TransInfo *t)
-{
- ViewLayer *view_layer = t->view_layer;
- TransData *td;
- Object *ob;
- ID *id;
- short *texflag;
-
- ob = OBACT(view_layer);
-
- if (ob == NULL) { // Shouldn't logically happen, but still...
- return;
- }
-
- id = ob->data;
- if (id == NULL || !ELEM(GS(id->name), ID_ME, ID_CU, ID_MB)) {
- BKE_report(t->reports, RPT_ERROR, "Unsupported object type for text-space transform");
- return;
- }
-
- if (BKE_object_obdata_is_libdata(ob)) {
- BKE_report(t->reports, RPT_ERROR, "Linked data can't text-space transform");
- return;
- }
-
- {
- BLI_assert(t->data_container_len == 1);
- TransDataContainer *tc = t->data_container;
- tc->data_len = 1;
- td = tc->data = MEM_callocN(sizeof(TransData), "TransTexspace");
- td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
- }
-
- td->flag = TD_SELECTED;
- copy_v3_v3(td->center, ob->obmat[3]);
- td->ob = ob;
-
- copy_m3_m4(td->mtx, ob->obmat);
- copy_m3_m4(td->axismtx, ob->obmat);
- normalize_m3(td->axismtx);
- pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
-
- if (BKE_object_obdata_texspace_get(ob, &texflag, &td->loc, &td->ext->size, &td->ext->rot)) {
- ob->dtx |= OB_TEXSPACE;
- *texflag &= ~ME_AUTOSPACE;
- }
-
- copy_v3_v3(td->iloc, td->loc);
- copy_v3_v3(td->ext->irot, td->ext->rot);
- copy_v3_v3(td->ext->isize, td->ext->size);
-}
-
-/* -------------------------------------------------------------------- */
-/** \name Cursor Transform Creation
- *
- * Instead of transforming the selection, move the 2D/3D cursor.
- *
- * \{ */
-
-static void createTransCursor_image(TransInfo *t)
-{
- TransData *td;
- SpaceImage *sima = t->sa->spacedata.first;
- float *cursor_location = sima->cursor;
-
- {
- BLI_assert(t->data_container_len == 1);
- TransDataContainer *tc = t->data_container;
- tc->data_len = 1;
- td = tc->data = MEM_callocN(sizeof(TransData), "TransTexspace");
- td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
- }
-
- td->flag = TD_SELECTED;
- copy_v3_v3(td->center, cursor_location);
- td->ob = NULL;
-
- unit_m3(td->mtx);
- unit_m3(td->axismtx);
- pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
-
- td->loc = cursor_location;
- copy_v3_v3(td->iloc, cursor_location);
-}
-
-static void createTransCursor_view3d(TransInfo *t)
-{
- TransData *td;
-
- Scene *scene = t->scene;
- if (ID_IS_LINKED(scene)) {
- BKE_report(t->reports, RPT_ERROR, "Linked data can't text-space transform");
- return;
- }
-
- View3DCursor *cursor = &scene->cursor;
- {
- BLI_assert(t->data_container_len == 1);
- TransDataContainer *tc = t->data_container;
- tc->data_len = 1;
- td = tc->data = MEM_callocN(sizeof(TransData), "TransTexspace");
- td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
- }
-
- td->flag = TD_SELECTED;
- copy_v3_v3(td->center, cursor->location);
- td->ob = NULL;
-
- unit_m3(td->mtx);
- BKE_scene_cursor_rot_to_mat3(cursor, td->axismtx);
- normalize_m3(td->axismtx);
- pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
-
- td->loc = cursor->location;
- copy_v3_v3(td->iloc, cursor->location);
-
- if (cursor->rotation_mode > 0) {
- td->ext->rot = cursor->rotation_euler;
- td->ext->rotAxis = NULL;
- td->ext->rotAngle = NULL;
- td->ext->quat = NULL;
-
- copy_v3_v3(td->ext->irot, cursor->rotation_euler);
- }
- else if (cursor->rotation_mode == ROT_MODE_AXISANGLE) {
- td->ext->rot = NULL;
- td->ext->rotAxis = cursor->rotation_axis;
- td->ext->rotAngle = &cursor->rotation_angle;
- td->ext->quat = NULL;
-
- td->ext->irotAngle = cursor->rotation_angle;
- copy_v3_v3(td->ext->irotAxis, cursor->rotation_axis);
- }
- else {
- td->ext->rot = NULL;
- td->ext->rotAxis = NULL;
- td->ext->rotAngle = NULL;
- td->ext->quat = cursor->rotation_quaternion;
-
- copy_qt_qt(td->ext->iquat, cursor->rotation_quaternion);
- }
- td->ext->rotOrder = cursor->rotation_mode;
-}
-
-/** \} */
-
-/* ********************* edge (for crease) ***** */
-
-static void createTransEdge(TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
-
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- TransData *td = NULL;
- BMEdge *eed;
- BMIter iter;
- float mtx[3][3], smtx[3][3];
- int count = 0, countsel = 0;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
- int cd_edge_float_offset;
-
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- countsel++;
- }
- if (is_prop_edit) {
- count++;
- }
- }
- }
-
- if (countsel == 0) {
- tc->data_len = 0;
- continue;
- }
-
- if (is_prop_edit) {
- tc->data_len = count;
- }
- else {
- tc->data_len = countsel;
- }
-
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransCrease");
-
- copy_m3_m4(mtx, tc->obedit->obmat);
- pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
-
- /* create data we need */
- if (t->mode == TFM_BWEIGHT) {
- BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_BWEIGHT);
- cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
- }
- else { // if (t->mode == TFM_CREASE) {
- BLI_assert(t->mode == TFM_CREASE);
- BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_CREASE);
- cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
- }
-
- BLI_assert(cd_edge_float_offset != -1);
-
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) &&
- (BM_elem_flag_test(eed, BM_ELEM_SELECT) || is_prop_edit)) {
- float *fl_ptr;
- /* need to set center for center calculations */
- mid_v3_v3v3(td->center, eed->v1->co, eed->v2->co);
-
- td->loc = NULL;
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- td->flag = TD_SELECTED;
- }
- else {
- td->flag = 0;
- }
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
-
- td->ext = NULL;
-
- fl_ptr = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_float_offset);
- td->val = fl_ptr;
- td->ival = *fl_ptr;
-
- td++;
- }
- }
- }
-}
-
-/* ********************* pose mode ************* */
-
-static bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan)
-{
- bConstraint *con = pchan->constraints.first;
-
- for (; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce != 0.0f)) {
- bKinematicConstraint *data = con->data;
-
- if (data->tar == NULL) {
- return data;
- }
- if (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0) {
- return data;
- }
- }
- }
- return NULL;
-}
-
-static short apply_targetless_ik(Object *ob)
-{
- bPoseChannel *pchan, *parchan, *chanlist[256];
- bKinematicConstraint *data;
- int segcount, apply = 0;
-
- /* now we got a difficult situation... we have to find the
- * target-less IK pchans, and apply transformation to the all
- * pchans that were in the chain */
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- data = has_targetless_ik(pchan);
- if (data && (data->flag & CONSTRAINT_IK_AUTO)) {
-
- /* fill the array with the bones of the chain (armature.c does same, keep it synced) */
- segcount = 0;
-
- /* exclude tip from chain? */
- if (!(data->flag & CONSTRAINT_IK_TIP)) {
- parchan = pchan->parent;
- }
- else {
- parchan = pchan;
- }
-
- /* Find the chain's root & count the segments needed */
- for (; parchan; parchan = parchan->parent) {
- chanlist[segcount] = parchan;
- segcount++;
-
- if (segcount == data->rootbone || segcount > 255) {
- break; // 255 is weak
- }
- }
- for (; segcount; segcount--) {
- Bone *bone;
- float rmat[4][4] /*, tmat[4][4], imat[4][4]*/;
-
- /* pose_mat(b) = pose_mat(b-1) * offs_bone * channel * constraint * IK */
- /* we put in channel the entire result of rmat = (channel * constraint * IK) */
- /* pose_mat(b) = pose_mat(b-1) * offs_bone * rmat */
- /* rmat = pose_mat(b) * inv(pose_mat(b-1) * offs_bone ) */
-
- parchan = chanlist[segcount - 1];
- bone = parchan->bone;
- bone->flag |= BONE_TRANSFORM; /* ensures it gets an auto key inserted */
-
- BKE_armature_mat_pose_to_bone(parchan, parchan->pose_mat, rmat);
-
- /* apply and decompose, doesn't work for constraints or non-uniform scale well */
- {
- float rmat3[3][3], qrmat[3][3], imat3[3][3], smat[3][3];
- copy_m3_m4(rmat3, rmat);
-
- /* rotation */
- /* [#22409] is partially caused by this, as slight numeric error introduced during
- * the solving process leads to locked-axis values changing. However, we cannot modify
- * the values here, or else there are huge discrepancies between IK-solver (interactive)
- * and applied poses. */
- BKE_pchan_mat3_to_rot(parchan, rmat3, false);
-
- /* for size, remove rotation */
- /* causes problems with some constraints (so apply only if needed) */
- if (data->flag & CONSTRAINT_IK_STRETCH) {
- BKE_pchan_rot_to_mat3(parchan, qrmat);
- invert_m3_m3(imat3, qrmat);
- mul_m3_m3m3(smat, rmat3, imat3);
- mat3_to_size(parchan->size, smat);
- }
-
- /* causes problems with some constraints (e.g. childof), so disable this */
- /* as it is IK shouldn't affect location directly */
- /* copy_v3_v3(parchan->loc, rmat[3]); */
- }
- }
-
- apply = 1;
- data->flag &= ~CONSTRAINT_IK_AUTO;
- }
- }
-
- return apply;
-}
-
-static void add_pose_transdata(
- TransInfo *t, bPoseChannel *pchan, Object *ob, TransDataContainer *tc, TransData *td)
-{
- Bone *bone = pchan->bone;
- float pmat[3][3], omat[3][3];
- float cmat[3][3], tmat[3][3];
- float vec[3];
-
- copy_v3_v3(vec, pchan->pose_mat[3]);
- copy_v3_v3(td->center, vec);
-
- td->ob = ob;
- td->flag = TD_SELECTED;
- if (bone->flag & BONE_HINGE_CHILD_TRANSFORM) {
- td->flag |= TD_NOCENTER;
- }
-
- if (bone->flag & BONE_TRANSFORM_CHILD) {
- td->flag |= TD_NOCENTER;
- td->flag |= TD_NO_LOC;
- }
-
- td->protectflag = pchan->protectflag;
-
- td->loc = pchan->loc;
- copy_v3_v3(td->iloc, pchan->loc);
-
- td->ext->size = pchan->size;
- copy_v3_v3(td->ext->isize, pchan->size);
-
- if (pchan->rotmode > 0) {
- td->ext->rot = pchan->eul;
- td->ext->rotAxis = NULL;
- td->ext->rotAngle = NULL;
- td->ext->quat = NULL;
-
- copy_v3_v3(td->ext->irot, pchan->eul);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- td->ext->rot = NULL;
- td->ext->rotAxis = pchan->rotAxis;
- td->ext->rotAngle = &pchan->rotAngle;
- td->ext->quat = NULL;
-
- td->ext->irotAngle = pchan->rotAngle;
- copy_v3_v3(td->ext->irotAxis, pchan->rotAxis);
- }
- else {
- td->ext->rot = NULL;
- td->ext->rotAxis = NULL;
- td->ext->rotAngle = NULL;
- td->ext->quat = pchan->quat;
-
- copy_qt_qt(td->ext->iquat, pchan->quat);
- }
- td->ext->rotOrder = pchan->rotmode;
-
- /* proper way to get parent transform + own transform + constraints transform */
- copy_m3_m4(omat, ob->obmat);
-
- /* New code, using "generic" BKE_bone_parent_transform_calc_from_pchan(). */
- {
- BoneParentTransform bpt;
- float rpmat[3][3];
-
- BKE_bone_parent_transform_calc_from_pchan(pchan, &bpt);
- if (t->mode == TFM_TRANSLATION) {
- copy_m3_m4(pmat, bpt.loc_mat);
- }
- else {
- copy_m3_m4(pmat, bpt.rotscale_mat);
- }
-
- /* Grrr! Exceptional case: When translating pose bones that are either Hinge or NoLocal,
- * and want align snapping, we just need both loc_mat and rotscale_mat.
- * So simply always store rotscale mat in td->ext, and always use it to apply rotations...
- * Ugly to need such hacks! :/ */
- copy_m3_m4(rpmat, bpt.rotscale_mat);
-
- if (constraints_list_needinv(t, &pchan->constraints)) {
- copy_m3_m4(tmat, pchan->constinv);
- invert_m3_m3(cmat, tmat);
- mul_m3_series(td->mtx, cmat, omat, pmat);
- mul_m3_series(td->ext->r_mtx, cmat, omat, rpmat);
- }
- else {
- mul_m3_series(td->mtx, omat, pmat);
- mul_m3_series(td->ext->r_mtx, omat, rpmat);
- }
- invert_m3_m3(td->ext->r_smtx, td->ext->r_mtx);
- }
-
- pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
-
- /* exceptional case: rotate the pose bone which also applies transformation
- * when a parentless bone has BONE_NO_LOCAL_LOCATION [] */
- if (!ELEM(t->mode, TFM_TRANSLATION, TFM_RESIZE) &&
- (pchan->bone->flag & BONE_NO_LOCAL_LOCATION)) {
- if (pchan->parent) {
- /* same as td->smtx but without pchan->bone->bone_mat */
- td->flag |= TD_PBONE_LOCAL_MTX_C;
- mul_m3_m3m3(td->ext->l_smtx, pchan->bone->bone_mat, td->smtx);
- }
- else {
- td->flag |= TD_PBONE_LOCAL_MTX_P;
- }
- }
-
- /* for axismat we use bone's own transform */
- copy_m3_m4(pmat, pchan->pose_mat);
- mul_m3_m3m3(td->axismtx, omat, pmat);
- normalize_m3(td->axismtx);
-
- if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
- bArmature *arm = tc->poseobj->data;
-
- if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
- td->loc = NULL;
- td->val = &bone->dist;
- td->ival = bone->dist;
- }
- else {
- // abusive storage of scale in the loc pointer :)
- td->loc = &bone->xwidth;
- copy_v3_v3(td->iloc, td->loc);
- td->val = NULL;
- }
- }
-
- /* in this case we can do target-less IK grabbing */
- if (t->mode == TFM_TRANSLATION) {
- bKinematicConstraint *data = has_targetless_ik(pchan);
- if (data) {
- if (data->flag & CONSTRAINT_IK_TIP) {
- copy_v3_v3(data->grabtarget, pchan->pose_tail);
- }
- else {
- copy_v3_v3(data->grabtarget, pchan->pose_head);
- }
- td->loc = data->grabtarget;
- copy_v3_v3(td->iloc, td->loc);
- data->flag |= CONSTRAINT_IK_AUTO;
-
- /* only object matrix correction */
- copy_m3_m3(td->mtx, omat);
- pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
- }
- }
-
- /* store reference to first constraint */
- td->con = pchan->constraints.first;
-}
-
-static void bone_children_clear_transflag(int mode, short around, ListBase *lb)
-{
- Bone *bone = lb->first;
-
- for (; bone; bone = bone->next) {
- if ((bone->flag & BONE_HINGE) && (bone->flag & BONE_CONNECTED)) {
- bone->flag |= BONE_HINGE_CHILD_TRANSFORM;
- }
- else if ((bone->flag & BONE_TRANSFORM) && (mode == TFM_ROTATION || mode == TFM_TRACKBALL) &&
- (around == V3D_AROUND_LOCAL_ORIGINS)) {
- bone->flag |= BONE_TRANSFORM_CHILD;
- }
- else {
- bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
- }
-
- bone_children_clear_transflag(mode, around, &bone->childbase);
- }
-}
-
-/* sets transform flags in the bones
- * returns total number of bones with BONE_TRANSFORM */
-int count_set_pose_transflags(Object *ob,
- const int mode,
- const short around,
- bool has_translate_rotate[2])
-{
- bArmature *arm = ob->data;
- bPoseChannel *pchan;
- Bone *bone;
- int total = 0;
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- bone = pchan->bone;
- if (PBONE_VISIBLE(arm, bone)) {
- if ((bone->flag & BONE_SELECTED)) {
- bone->flag |= BONE_TRANSFORM;
- }
- else {
- bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
- }
-
- bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM;
- bone->flag &= ~BONE_TRANSFORM_CHILD;
- }
- else {
- bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
- }
- }
-
- /* make sure no bone can be transformed when a parent is transformed */
- /* since pchans are depsgraph sorted, the parents are in beginning of list */
- if (!ELEM(mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- bone = pchan->bone;
- if (bone->flag & BONE_TRANSFORM) {
- bone_children_clear_transflag(mode, around, &bone->childbase);
- }
- }
- }
- /* now count, and check if we have autoIK or have to switch from translate to rotate */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- bone = pchan->bone;
- if (bone->flag & BONE_TRANSFORM) {
- total++;
-
- if (has_translate_rotate != NULL) {
- if (has_targetless_ik(pchan) == NULL) {
- if (pchan->parent && (pchan->bone->flag & BONE_CONNECTED)) {
- if (pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM) {
- has_translate_rotate[0] = true;
- }
- }
- else {
- if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC) {
- has_translate_rotate[0] = true;
- }
- }
- if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT) {
- has_translate_rotate[1] = true;
- }
- }
- else {
- has_translate_rotate[0] = true;
- }
- }
- }
- }
-
- return total;
-}
-
-/* -------- Auto-IK ---------- */
-
-/* adjust pose-channel's auto-ik chainlen */
-static bool pchan_autoik_adjust(bPoseChannel *pchan, short chainlen)
-{
- bConstraint *con;
- bool changed = false;
-
- /* don't bother to search if no valid constraints */
- if ((pchan->constflag & (PCHAN_HAS_IK | PCHAN_HAS_TARGET)) == 0) {
- return changed;
- }
-
- /* check if pchan has ik-constraint */
- for (con = pchan->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce != 0.0f)) {
- bKinematicConstraint *data = con->data;
-
- /* only accept if a temporary one (for auto-ik) */
- if (data->flag & CONSTRAINT_IK_TEMP) {
- /* chainlen is new chainlen, but is limited by maximum chainlen */
- const int old_rootbone = data->rootbone;
- if ((chainlen == 0) || (chainlen > data->max_rootbone)) {
- data->rootbone = data->max_rootbone;
- }
- else {
- data->rootbone = chainlen;
- }
- changed |= (data->rootbone != old_rootbone);
- }
- }
- }
-
- return changed;
-}
-
-/* change the chain-length of auto-ik */
-void transform_autoik_update(TransInfo *t, short mode)
-{
- Main *bmain = CTX_data_main(t->context);
-
- short *chainlen = &t->settings->autoik_chainlen;
- bPoseChannel *pchan;
-
- /* mode determines what change to apply to chainlen */
- if (mode == 1) {
- /* mode=1 is from WHEELMOUSEDOWN... increases len */
- (*chainlen)++;
- }
- else if (mode == -1) {
- /* mode==-1 is from WHEELMOUSEUP... decreases len */
- if (*chainlen > 0) {
- (*chainlen)--;
- }
- else {
- /* IK length did not change, skip updates. */
- return;
- }
- }
-
- /* apply to all pose-channels */
- bool changed = false;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
-
- /* sanity checks (don't assume t->poseobj is set, or that it is an armature) */
- if (ELEM(NULL, tc->poseobj, tc->poseobj->pose)) {
- continue;
- }
-
- for (pchan = tc->poseobj->pose->chanbase.first; pchan; pchan = pchan->next) {
- changed |= pchan_autoik_adjust(pchan, *chainlen);
- }
- }
-
- if (changed) {
- /* TODO(sergey): Consider doing partial update only. */
- DEG_relations_tag_update(bmain);
- }
-}
-
-/* frees temporal IKs */
-static void pose_grab_with_ik_clear(Main *bmain, Object *ob)
-{
- bKinematicConstraint *data;
- bPoseChannel *pchan;
- bConstraint *con, *next;
- bool relations_changed = false;
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- /* clear all temporary lock flags */
- pchan->ikflag &= ~(BONE_IK_NO_XDOF_TEMP | BONE_IK_NO_YDOF_TEMP | BONE_IK_NO_ZDOF_TEMP);
-
- pchan->constflag &= ~(PCHAN_HAS_IK | PCHAN_HAS_TARGET);
-
- /* remove all temporary IK-constraints added */
- for (con = pchan->constraints.first; con; con = next) {
- next = con->next;
- if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
- data = con->data;
- if (data->flag & CONSTRAINT_IK_TEMP) {
- relations_changed = true;
-
- /* iTaSC needs clear for removed constraints */
- BIK_clear_data(ob->pose);
-
- BLI_remlink(&pchan->constraints, con);
- MEM_freeN(con->data);
- MEM_freeN(con);
- continue;
- }
- pchan->constflag |= PCHAN_HAS_IK;
- if (data->tar == NULL || (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0)) {
- pchan->constflag |= PCHAN_HAS_TARGET;
- }
- }
- }
- }
-
- if (relations_changed) {
- /* TODO(sergey): Consider doing partial update only. */
- DEG_relations_tag_update(bmain);
- }
-}
-
-/* adds the IK to pchan - returns if added */
-static short pose_grab_with_ik_add(bPoseChannel *pchan)
-{
- bKinematicConstraint *targetless = NULL;
- bKinematicConstraint *data;
- bConstraint *con;
-
- /* Sanity check */
- if (pchan == NULL) {
- return 0;
- }
-
- /* Rule: not if there's already an IK on this channel */
- for (con = pchan->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
- data = con->data;
-
- if (data->tar == NULL || (data->tar->type == OB_ARMATURE && data->subtarget[0] == '\0')) {
- /* make reference to constraint to base things off later
- * (if it's the last targetless constraint encountered) */
- targetless = (bKinematicConstraint *)con->data;
-
- /* but, if this is a targetless IK, we make it auto anyway (for the children loop) */
- if (con->enforce != 0.0f) {
- data->flag |= CONSTRAINT_IK_AUTO;
-
- /* if no chain length has been specified,
- * just make things obey standard rotation locks too */
- if (data->rootbone == 0) {
- for (; pchan; pchan = pchan->parent) {
- /* here, we set ik-settings for bone from pchan->protectflag */
- // XXX: careful with quats/axis-angle rotations where we're locking 4d components
- if (pchan->protectflag & OB_LOCK_ROTX) {
- pchan->ikflag |= BONE_IK_NO_XDOF_TEMP;
- }
- if (pchan->protectflag & OB_LOCK_ROTY) {
- pchan->ikflag |= BONE_IK_NO_YDOF_TEMP;
- }
- if (pchan->protectflag & OB_LOCK_ROTZ) {
- pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP;
- }
- }
- }
-
- return 0;
- }
- }
-
- if ((con->flag & CONSTRAINT_DISABLE) == 0 && (con->enforce != 0.0f)) {
- return 0;
- }
- }
- }
-
- con = BKE_constraint_add_for_pose(NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC);
-
- /* for draw, but also for detecting while pose solving */
- pchan->constflag |= (PCHAN_HAS_IK | PCHAN_HAS_TARGET);
-
- data = con->data;
- if (targetless) {
- /* if exists, use values from last targetless (but disabled) IK-constraint as base */
- *data = *targetless;
- }
- else {
- data->flag = CONSTRAINT_IK_TIP;
- }
- data->flag |= CONSTRAINT_IK_TEMP | CONSTRAINT_IK_AUTO | CONSTRAINT_IK_POS;
- copy_v3_v3(data->grabtarget, pchan->pose_tail);
-
- /* watch-it! has to be 0 here, since we're still on the
- * same bone for the first time through the loop T25885. */
- data->rootbone = 0;
-
- /* we only include bones that are part of a continual connected chain */
- do {
- /* here, we set ik-settings for bone from pchan->protectflag */
- // XXX: careful with quats/axis-angle rotations where we're locking 4d components
- if (pchan->protectflag & OB_LOCK_ROTX) {
- pchan->ikflag |= BONE_IK_NO_XDOF_TEMP;
- }
- if (pchan->protectflag & OB_LOCK_ROTY) {
- pchan->ikflag |= BONE_IK_NO_YDOF_TEMP;
- }
- if (pchan->protectflag & OB_LOCK_ROTZ) {
- pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP;
- }
-
- /* now we count this pchan as being included */
- data->rootbone++;
-
- /* continue to parent, but only if we're connected to it */
- if (pchan->bone->flag & BONE_CONNECTED) {
- pchan = pchan->parent;
- }
- else {
- pchan = NULL;
- }
- } while (pchan);
-
- /* make a copy of maximum chain-length */
- data->max_rootbone = data->rootbone;
-
- return 1;
-}
-
-/* bone is a candidate to get IK, but we don't do it if it has children connected */
-static short pose_grab_with_ik_children(bPose *pose, Bone *bone)
-{
- Bone *bonec;
- short wentdeeper = 0, added = 0;
-
- /* go deeper if children & children are connected */
- for (bonec = bone->childbase.first; bonec; bonec = bonec->next) {
- if (bonec->flag & BONE_CONNECTED) {
- wentdeeper = 1;
- added += pose_grab_with_ik_children(pose, bonec);
- }
- }
- if (wentdeeper == 0) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(pose, bone->name);
- if (pchan) {
- added += pose_grab_with_ik_add(pchan);
- }
- }
-
- return added;
-}
-
-/* main call which adds temporal IK chains */
-static short pose_grab_with_ik(Main *bmain, Object *ob)
-{
- bArmature *arm;
- bPoseChannel *pchan, *parent;
- Bone *bonec;
- short tot_ik = 0;
-
- if ((ob == NULL) || (ob->pose == NULL) || (ob->mode & OB_MODE_POSE) == 0) {
- return 0;
- }
-
- arm = ob->data;
-
- /* Rule: allow multiple Bones
- * (but they must be selected, and only one ik-solver per chain should get added) */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->layer & arm->layer) {
- if (pchan->bone->flag & BONE_SELECTED) {
- /* Rule: no IK for solitatry (unconnected) bones */
- for (bonec = pchan->bone->childbase.first; bonec; bonec = bonec->next) {
- if (bonec->flag & BONE_CONNECTED) {
- break;
- }
- }
- if ((pchan->bone->flag & BONE_CONNECTED) == 0 && (bonec == NULL)) {
- continue;
- }
-
- /* rule: if selected Bone is not a root bone, it gets a temporal IK */
- if (pchan->parent) {
- /* only adds if there's no IK yet (and no parent bone was selected) */
- for (parent = pchan->parent; parent; parent = parent->parent) {
- if (parent->bone->flag & BONE_SELECTED) {
- break;
- }
- }
- if (parent == NULL) {
- tot_ik += pose_grab_with_ik_add(pchan);
- }
- }
- else {
- /* rule: go over the children and add IK to the tips */
- tot_ik += pose_grab_with_ik_children(ob->pose, pchan->bone);
- }
- }
- }
- }
-
- /* iTaSC needs clear for new IK constraints */
- if (tot_ik) {
- BIK_clear_data(ob->pose);
- /* TODO(sergey): Consider doing partial update only. */
- DEG_relations_tag_update(bmain);
- }
-
- return (tot_ik) ? 1 : 0;
-}
-
-static void pose_mirror_info_init(PoseInitData_Mirror *pid,
- bPoseChannel *pchan,
- bPoseChannel *pchan_orig,
- bool is_mirror_relative)
-{
- pid->pchan = pchan;
- copy_v3_v3(pid->orig.loc, pchan->loc);
- copy_v3_v3(pid->orig.size, pchan->size);
- pid->orig.curve_in_x = pchan->curve_in_x;
- pid->orig.curve_out_x = pchan->curve_out_x;
- pid->orig.roll1 = pchan->roll1;
- pid->orig.roll2 = pchan->roll2;
-
- if (pchan->rotmode > 0) {
- copy_v3_v3(pid->orig.eul, pchan->eul);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- copy_v3_v3(pid->orig.axis_angle, pchan->rotAxis);
- pid->orig.axis_angle[3] = pchan->rotAngle;
- }
- else {
- copy_qt_qt(pid->orig.quat, pchan->quat);
- }
-
- if (is_mirror_relative) {
- float pchan_mtx[4][4];
- float pchan_mtx_mirror[4][4];
-
- float flip_mtx[4][4];
- unit_m4(flip_mtx);
- flip_mtx[0][0] = -1;
-
- BKE_pchan_to_mat4(pchan_orig, pchan_mtx_mirror);
- BKE_pchan_to_mat4(pchan, pchan_mtx);
-
- mul_m4_m4m4(pchan_mtx_mirror, pchan_mtx_mirror, flip_mtx);
- mul_m4_m4m4(pchan_mtx_mirror, flip_mtx, pchan_mtx_mirror);
-
- invert_m4(pchan_mtx_mirror);
- mul_m4_m4m4(pid->offset_mtx, pchan_mtx, pchan_mtx_mirror);
- }
- else {
- unit_m4(pid->offset_mtx);
- }
-}
-
-static void pose_mirror_info_restore(const PoseInitData_Mirror *pid)
-{
- bPoseChannel *pchan = pid->pchan;
- copy_v3_v3(pchan->loc, pid->orig.loc);
- copy_v3_v3(pchan->size, pid->orig.size);
- pchan->curve_in_x = pid->orig.curve_in_x;
- pchan->curve_out_x = pid->orig.curve_out_x;
- pchan->roll1 = pid->orig.roll1;
- pchan->roll2 = pid->orig.roll2;
-
- if (pchan->rotmode > 0) {
- copy_v3_v3(pchan->eul, pid->orig.eul);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- copy_v3_v3(pchan->rotAxis, pid->orig.axis_angle);
- pchan->rotAngle = pid->orig.axis_angle[3];
- }
- else {
- copy_qt_qt(pchan->quat, pid->orig.quat);
- }
-}
-
-/**
- * When objects array is NULL, use 't->data_container' as is.
- */
-static void createTransPose(TransInfo *t)
-{
- Main *bmain = CTX_data_main(t->context);
-
- t->data_len_all = 0;
-
- bool has_translate_rotate_buf[2] = {false, false};
- bool *has_translate_rotate = (t->mode == TFM_TRANSLATION) ? has_translate_rotate_buf : NULL;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- Object *ob = tc->poseobj;
- bPose *pose = ob->pose;
-
- bArmature *arm;
-
- /* check validity of state */
- arm = BKE_armature_from_object(tc->poseobj);
- if ((arm == NULL) || (pose == NULL)) {
- continue;
- }
-
- const bool mirror = ((pose->flag & POSE_MIRROR_EDIT) != 0);
-
- /* set flags and count total */
- tc->data_len = count_set_pose_transflags(ob, t->mode, t->around, has_translate_rotate);
- if (tc->data_len == 0) {
- continue;
- }
-
- if (arm->flag & ARM_RESTPOS) {
- if (ELEM(t->mode, TFM_DUMMY, TFM_BONESIZE) == 0) {
- BKE_report(t->reports, RPT_ERROR, "Cannot change Pose when 'Rest Position' is enabled");
- tc->data_len = 0;
- continue;
- }
- }
-
- /* do we need to add temporal IK chains? */
- if ((pose->flag & POSE_AUTO_IK) && t->mode == TFM_TRANSLATION) {
- if (pose_grab_with_ik(bmain, ob)) {
- t->flag |= T_AUTOIK;
- has_translate_rotate[0] = true;
- }
- }
-
- if (mirror) {
- int total_mirrored = 0;
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if ((pchan->bone->flag & BONE_TRANSFORM) &&
- BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) {
- total_mirrored++;
- }
- }
-
- PoseInitData_Mirror *pid = MEM_mallocN((total_mirrored + 1) * sizeof(PoseInitData_Mirror),
- "PoseInitData_Mirror");
-
- /* Trick to terminate iteration. */
- pid[total_mirrored].pchan = NULL;
-
- tc->custom.type.data = pid;
- tc->custom.type.use_free = true;
- }
- }
-
- /* if there are no translatable bones, do rotation */
- if ((t->mode == TFM_TRANSLATION) && !has_translate_rotate[0]) {
- if (has_translate_rotate[1]) {
- t->mode = TFM_ROTATION;
- }
- else {
- t->mode = TFM_RESIZE;
- }
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- if (tc->data_len == 0) {
- continue;
- }
- Object *ob = tc->poseobj;
- TransData *td;
- TransDataExtension *tdx;
- int i;
-
- PoseInitData_Mirror *pid = tc->custom.type.data;
- int pid_index = 0;
- bPose *pose = ob->pose;
-
- if (pose == NULL) {
- continue;
- }
-
- const bool mirror = ((pose->flag & POSE_MIRROR_EDIT) != 0);
- const bool is_mirror_relative = ((pose->flag & POSE_MIRROR_RELATIVE) != 0);
-
- tc->poseobj = ob; /* we also allow non-active objects to be transformed, in weightpaint */
-
- /* init trans data */
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransPoseBone");
- tdx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension),
- "TransPoseBoneExt");
- for (i = 0; i < tc->data_len; i++, td++, tdx++) {
- td->ext = tdx;
- td->val = NULL;
- }
-
- /* use pose channels to fill trans data */
- td = tc->data;
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->flag & BONE_TRANSFORM) {
- add_pose_transdata(t, pchan, ob, tc, td);
-
- if (mirror) {
- bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name);
- if (pchan_mirror) {
- pose_mirror_info_init(&pid[pid_index], pchan_mirror, pchan, is_mirror_relative);
- pid_index++;
- }
- }
-
- td++;
- }
- }
-
- if (td != (tc->data + tc->data_len)) {
- BKE_report(t->reports, RPT_DEBUG, "Bone selection count error");
- }
-
- /* initialize initial auto=ik chainlen's? */
- if (t->flag & T_AUTOIK) {
- transform_autoik_update(t, 0);
- }
- }
-
- t->flag |= T_POSE;
- /* disable PET, its not usable in pose mode yet [#32444] */
- t->flag &= ~T_PROP_EDIT_ALL;
-}
-
-void restoreMirrorPoseBones(TransDataContainer *tc)
-{
- bPose *pose = tc->poseobj->pose;
-
- if (!(pose->flag & POSE_MIRROR_EDIT)) {
- return;
- }
-
- for (PoseInitData_Mirror *pid = tc->custom.type.data; pid->pchan; pid++) {
- pose_mirror_info_restore(pid);
- }
-}
-
-void restoreBones(TransDataContainer *tc)
-{
- bArmature *arm;
- BoneInitData *bid = tc->custom.type.data;
- EditBone *ebo;
-
- if (tc->obedit) {
- arm = tc->obedit->data;
- }
- else {
- BLI_assert(tc->poseobj != NULL);
- arm = tc->poseobj->data;
- }
-
- while (bid->bone) {
- ebo = bid->bone;
-
- ebo->dist = bid->dist;
- ebo->rad_head = bid->rad_head;
- ebo->rad_tail = bid->rad_tail;
- ebo->roll = bid->roll;
- ebo->xwidth = bid->xwidth;
- ebo->zwidth = bid->zwidth;
- copy_v3_v3(ebo->head, bid->head);
- copy_v3_v3(ebo->tail, bid->tail);
-
- if (arm->flag & ARM_MIRROR_EDIT) {
- EditBone *ebo_child;
-
- /* Also move connected ebo_child, in case ebo_child's name aren't mirrored properly */
- for (ebo_child = arm->edbo->first; ebo_child; ebo_child = ebo_child->next) {
- if ((ebo_child->flag & BONE_CONNECTED) && (ebo_child->parent == ebo)) {
- copy_v3_v3(ebo_child->head, ebo->tail);
- ebo_child->rad_head = ebo->rad_tail;
- }
- }
-
- /* Also move connected parent, in case parent's name isn't mirrored properly */
- if ((ebo->flag & BONE_CONNECTED) && ebo->parent) {
- EditBone *parent = ebo->parent;
- copy_v3_v3(parent->tail, ebo->head);
- parent->rad_tail = ebo->rad_head;
- }
- }
-
- bid++;
- }
-}
-
-/* ********************* armature ************** */
-static void createTransArmatureVerts(TransInfo *t)
-{
- t->data_len_all = 0;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- EditBone *ebo, *eboflip;
- bArmature *arm = tc->obedit->data;
- ListBase *edbo = arm->edbo;
- bool mirror = ((arm->flag & ARM_MIRROR_EDIT) != 0);
- int total_mirrored = 0;
-
- tc->data_len = 0;
- for (ebo = edbo->first; ebo; ebo = ebo->next) {
- const int data_len_prev = tc->data_len;
-
- if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
- if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
- if (ebo->flag & BONE_SELECTED) {
- tc->data_len++;
- }
- }
- else if (t->mode == TFM_BONE_ROLL) {
- if (ebo->flag & BONE_SELECTED) {
- tc->data_len++;
- }
- }
- else {
- if (ebo->flag & BONE_TIPSEL) {
- tc->data_len++;
- }
- if (ebo->flag & BONE_ROOTSEL) {
- tc->data_len++;
- }
- }
- }
-
- if (mirror && (data_len_prev < tc->data_len)) {
- eboflip = ED_armature_ebone_get_mirrored(arm->edbo, ebo);
- if (eboflip) {
- total_mirrored++;
- }
- }
- }
- if (!tc->data_len) {
- continue;
- }
-
- if (mirror) {
- BoneInitData *bid = MEM_mallocN((total_mirrored + 1) * sizeof(BoneInitData), "BoneInitData");
-
- /* trick to terminate iteration */
- bid[total_mirrored].bone = NULL;
-
- tc->custom.type.data = bid;
- tc->custom.type.use_free = true;
- }
- t->data_len_all += tc->data_len;
- }
-
- transform_around_single_fallback(t);
- t->data_len_all = -1;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- if (!tc->data_len) {
- continue;
- }
-
- EditBone *ebo, *eboflip;
- bArmature *arm = tc->obedit->data;
- ListBase *edbo = arm->edbo;
- TransData *td, *td_old;
- float mtx[3][3], smtx[3][3], bonemat[3][3];
- bool mirror = ((arm->flag & ARM_MIRROR_EDIT) != 0);
- BoneInitData *bid = tc->custom.type.data;
-
- copy_m3_m4(mtx, tc->obedit->obmat);
- pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
-
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransEditBone");
- int i = 0;
-
- for (ebo = edbo->first; ebo; ebo = ebo->next) {
- td_old = td;
- ebo->oldlength =
- ebo->length; // length==0.0 on extrude, used for scaling radius of bone points
-
- if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
- if (t->mode == TFM_BONE_ENVELOPE) {
- if (ebo->flag & BONE_ROOTSEL) {
- td->val = &ebo->rad_head;
- td->ival = *td->val;
-
- copy_v3_v3(td->center, ebo->head);
- td->flag = TD_SELECTED;
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
-
- td->loc = NULL;
- td->ext = NULL;
- td->ob = tc->obedit;
-
- td++;
- }
- if (ebo->flag & BONE_TIPSEL) {
- td->val = &ebo->rad_tail;
- td->ival = *td->val;
- copy_v3_v3(td->center, ebo->tail);
- td->flag = TD_SELECTED;
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
-
- td->loc = NULL;
- td->ext = NULL;
- td->ob = tc->obedit;
-
- td++;
- }
- }
- else if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
- if (ebo->flag & BONE_SELECTED) {
- if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
- td->loc = NULL;
- td->val = &ebo->dist;
- td->ival = ebo->dist;
- }
- else {
- // abusive storage of scale in the loc pointer :)
- td->loc = &ebo->xwidth;
- copy_v3_v3(td->iloc, td->loc);
- td->val = NULL;
- }
- copy_v3_v3(td->center, ebo->head);
- td->flag = TD_SELECTED;
-
- /* use local bone matrix */
- ED_armature_ebone_to_mat3(ebo, bonemat);
- mul_m3_m3m3(td->mtx, mtx, bonemat);
- invert_m3_m3(td->smtx, td->mtx);
-
- copy_m3_m3(td->axismtx, td->mtx);
- normalize_m3(td->axismtx);
-
- td->ext = NULL;
- td->ob = tc->obedit;
-
- td++;
- }
- }
- else if (t->mode == TFM_BONE_ROLL) {
- if (ebo->flag & BONE_SELECTED) {
- td->loc = NULL;
- td->val = &(ebo->roll);
- td->ival = ebo->roll;
-
- copy_v3_v3(td->center, ebo->head);
- td->flag = TD_SELECTED;
-
- td->ext = NULL;
- td->ob = tc->obedit;
-
- td++;
- }
- }
- else {
- if (ebo->flag & BONE_TIPSEL) {
- copy_v3_v3(td->iloc, ebo->tail);
-
- /* Don't allow single selected tips to have a modified center,
- * causes problem with snapping (see T45974).
- * However, in rotation mode, we want to keep that 'rotate bone around root with
- * only its tip selected' behavior (see T46325). */
- if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
- ((t->mode == TFM_ROTATION) || (ebo->flag & BONE_ROOTSEL))) {
- copy_v3_v3(td->center, ebo->head);
- }
- else {
- copy_v3_v3(td->center, td->iloc);
- }
-
- td->loc = ebo->tail;
- td->flag = TD_SELECTED;
- if (ebo->flag & BONE_EDITMODE_LOCKED) {
- td->protectflag = OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE;
- }
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
-
- ED_armature_ebone_to_mat3(ebo, td->axismtx);
-
- if ((ebo->flag & BONE_ROOTSEL) == 0) {
- td->extra = ebo;
- td->ival = ebo->roll;
- }
-
- td->ext = NULL;
- td->val = NULL;
- td->ob = tc->obedit;
-
- td++;
- }
- if (ebo->flag & BONE_ROOTSEL) {
- copy_v3_v3(td->iloc, ebo->head);
- copy_v3_v3(td->center, td->iloc);
- td->loc = ebo->head;
- td->flag = TD_SELECTED;
- if (ebo->flag & BONE_EDITMODE_LOCKED) {
- td->protectflag = OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE;
- }
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
-
- ED_armature_ebone_to_mat3(ebo, td->axismtx);
-
- td->extra = ebo; /* to fix roll */
- td->ival = ebo->roll;
-
- td->ext = NULL;
- td->val = NULL;
- td->ob = tc->obedit;
-
- td++;
- }
- }
- }
-
- if (mirror && (td_old != td)) {
- eboflip = ED_armature_ebone_get_mirrored(arm->edbo, ebo);
- if (eboflip) {
- bid[i].bone = eboflip;
- bid[i].dist = eboflip->dist;
- bid[i].rad_head = eboflip->rad_head;
- bid[i].rad_tail = eboflip->rad_tail;
- bid[i].roll = eboflip->roll;
- bid[i].xwidth = eboflip->xwidth;
- bid[i].zwidth = eboflip->zwidth;
- copy_v3_v3(bid[i].head, eboflip->head);
- copy_v3_v3(bid[i].tail, eboflip->tail);
- i++;
- }
- }
- }
-
- if (mirror) {
- /* trick to terminate iteration */
- BLI_assert(i + 1 == (MEM_allocN_len(bid) / sizeof(*bid)));
- bid[i].bone = NULL;
- }
- }
-}
-
-/* ********************* meta elements ********* */
-
-static void createTransMBallVerts(TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- MetaBall *mb = (MetaBall *)tc->obedit->data;
- MetaElem *ml;
- TransData *td;
- TransDataExtension *tx;
- float mtx[3][3], smtx[3][3];
- int count = 0, countsel = 0;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
-
- /* count totals */
- for (ml = mb->editelems->first; ml; ml = ml->next) {
- if (ml->flag & SELECT) {
- countsel++;
- }
- if (is_prop_edit) {
- count++;
- }
- }
-
- /* note: in prop mode we need at least 1 selected */
- if (countsel == 0) {
- continue;
- }
-
- if (is_prop_edit) {
- tc->data_len = count;
- }
- else {
- tc->data_len = countsel;
- }
-
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(MBall EditMode)");
- tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension),
- "MetaElement_TransExtension");
-
- copy_m3_m4(mtx, tc->obedit->obmat);
- pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
-
- for (ml = mb->editelems->first; ml; ml = ml->next) {
- if (is_prop_edit || (ml->flag & SELECT)) {
- td->loc = &ml->x;
- copy_v3_v3(td->iloc, td->loc);
- copy_v3_v3(td->center, td->loc);
-
- quat_to_mat3(td->axismtx, ml->quat);
-
- if (ml->flag & SELECT) {
- td->flag = TD_SELECTED | TD_USEQUAT | TD_SINGLESIZE;
- }
- else {
- td->flag = TD_USEQUAT;
- }
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
-
- td->ext = tx;
-
- /* Radius of MetaElem (mass of MetaElem influence) */
- if (ml->flag & MB_SCALE_RAD) {
- td->val = &ml->rad;
- td->ival = ml->rad;
- }
- else {
- td->val = &ml->s;
- td->ival = ml->s;
- }
-
- /* expx/expy/expz determine "shape" of some MetaElem types */
- tx->size = &ml->expx;
- tx->isize[0] = ml->expx;
- tx->isize[1] = ml->expy;
- tx->isize[2] = ml->expz;
-
- /* quat is used for rotation of MetaElem */
- tx->quat = ml->quat;
- copy_qt_qt(tx->iquat, ml->quat);
-
- tx->rot = NULL;
-
- td++;
- tx++;
- }
- }
- }
-}
-
-/* ********************* curve/surface ********* */
-
-static void calc_distanceCurveVerts(TransData *head, TransData *tail)
-{
- TransData *td, *td_near = NULL;
- for (td = head; td <= tail; td++) {
- if (td->flag & TD_SELECTED) {
- td_near = td;
- td->dist = 0.0f;
- }
- else if (td_near) {
- float dist;
- float vec[3];
-
- sub_v3_v3v3(vec, td_near->center, td->center);
- mul_m3_v3(head->mtx, vec);
- dist = len_v3(vec);
-
- if (dist < (td - 1)->dist) {
- td->dist = (td - 1)->dist;
- }
- else {
- td->dist = dist;
- }
- }
- else {
- td->dist = FLT_MAX;
- td->flag |= TD_NOTCONNECTED;
- }
- }
- td_near = NULL;
- for (td = tail; td >= head; td--) {
- if (td->flag & TD_SELECTED) {
- td_near = td;
- td->dist = 0.0f;
- }
- else if (td_near) {
- float dist;
- float vec[3];
-
- sub_v3_v3v3(vec, td_near->center, td->center);
- mul_m3_v3(head->mtx, vec);
- dist = len_v3(vec);
-
- if (td->flag & TD_NOTCONNECTED || dist < td->dist || (td + 1)->dist < td->dist) {
- td->flag &= ~TD_NOTCONNECTED;
- if (dist < (td + 1)->dist) {
- td->dist = (td + 1)->dist;
- }
- else {
- td->dist = dist;
- }
- }
- }
- }
-}
-
-/* Utility function for getting the handle data from bezier's */
-static TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt)
-{
- TransDataCurveHandleFlags *hdata;
- td->flag |= TD_BEZTRIPLE;
- hdata = td->hdata = MEM_mallocN(sizeof(TransDataCurveHandleFlags), "CuHandle Data");
- hdata->ih1 = bezt->h1;
- hdata->h1 = &bezt->h1;
- hdata->ih2 = bezt->h2; /* in case the second is not selected */
- hdata->h2 = &bezt->h2;
- return hdata;
-}
-
-/**
- * For the purpose of transform code we need to behave as if handles are selected,
- * even when they aren't (see special case below).
- */
-static int bezt_select_to_transform_triple_flag(const BezTriple *bezt, const bool hide_handles)
-{
- int flag = 0;
-
- if (hide_handles) {
- if (bezt->f2 & SELECT) {
- flag = (1 << 0) | (1 << 1) | (1 << 2);
- }
- }
- else {
- flag = (((bezt->f1 & SELECT) ? (1 << 0) : 0) | ((bezt->f2 & SELECT) ? (1 << 1) : 0) |
- ((bezt->f3 & SELECT) ? (1 << 2) : 0));
- }
-
- /* Special case for auto & aligned handles:
- * When a center point is being moved without the handles,
- * leaving the handles stationary makes no sense and only causes strange behavior,
- * where one handle is arbitrarily anchored, the other one is aligned and lengthened
- * based on where the center point is moved. Also a bug when cancelling, see: T52007.
- *
- * A more 'correct' solution could be to store handle locations in 'TransDataCurveHandleFlags'.
- * However that doesn't resolve odd behavior, so best transform the handles in this case.
- */
- if ((flag != ((1 << 0) | (1 << 1) | (1 << 2))) && (flag & (1 << 1))) {
- if (ELEM(bezt->h1, HD_AUTO, HD_ALIGN) && ELEM(bezt->h2, HD_AUTO, HD_ALIGN)) {
- flag = (1 << 0) | (1 << 1) | (1 << 2);
- }
- }
-
- return flag;
-}
-
-static void createTransCurveVerts(TransInfo *t)
-{
-
-#define SEL_F1 (1 << 0)
-#define SEL_F2 (1 << 1)
-#define SEL_F3 (1 << 2)
-
- t->data_len_all = 0;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- Curve *cu = tc->obedit->data;
- BLI_assert(cu->editnurb != NULL);
- BezTriple *bezt;
- BPoint *bp;
- int a;
- int count = 0, countsel = 0;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
- View3D *v3d = t->view;
- short hide_handles = (v3d != NULL) ?
- ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) :
- false;
-
- /* count total of vertices, check identical as in 2nd loop for making transdata! */
- ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- for (Nurb *nu = nurbs->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
- if (bezt->hide == 0) {
- const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
- if (bezt_tx & SEL_F1) {
- countsel++;
- }
- if (bezt_tx & SEL_F2) {
- countsel++;
- }
- if (bezt_tx & SEL_F3) {
- countsel++;
- }
- if (is_prop_edit) {
- count += 3;
- }
- }
- }
- }
- else {
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
- if (bp->hide == 0) {
- if (is_prop_edit) {
- count++;
- }
- if (bp->f1 & SELECT) {
- countsel++;
- }
- }
- }
- }
- }
- /* note: in prop mode we need at least 1 selected */
- if (countsel == 0) {
- tc->data_len = 0;
- continue;
- }
-
- if (is_prop_edit) {
- tc->data_len = count;
- }
- else {
- tc->data_len = countsel;
- }
- tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Curve EditMode)");
-
- t->data_len_all += tc->data_len;
- }
-
- transform_around_single_fallback(t);
- t->data_len_all = -1;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- if (tc->data_len == 0) {
- continue;
- }
-
- Curve *cu = tc->obedit->data;
- BezTriple *bezt;
- BPoint *bp;
- int a;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
- View3D *v3d = t->view;
- short hide_handles = (v3d != NULL) ?
- ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) :
- false;
-
- float mtx[3][3], smtx[3][3];
-
- copy_m3_m4(mtx, tc->obedit->obmat);
- pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
-
- TransData *td = tc->data;
- ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- for (Nurb *nu = nurbs->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- TransData *head, *tail;
- head = tail = td;
- for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
- if (bezt->hide == 0) {
- TransDataCurveHandleFlags *hdata = NULL;
- float axismtx[3][3];
-
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- float normal[3], plane[3];
-
- BKE_nurb_bezt_calc_normal(nu, bezt, normal);
- BKE_nurb_bezt_calc_plane(nu, bezt, plane);
-
- if (createSpaceNormalTangent(axismtx, normal, plane)) {
- /* pass */
- }
- else {
- normalize_v3(normal);
- axis_dominant_v3_to_m3(axismtx, normal);
- invert_m3(axismtx);
- }
- }
-
- /* Elements that will be transform (not always a match to selection). */
- const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
-
- if (is_prop_edit || bezt_tx & SEL_F1) {
- copy_v3_v3(td->iloc, bezt->vec[0]);
- td->loc = bezt->vec[0];
- copy_v3_v3(td->center,
- bezt->vec[(hide_handles || (t->around == V3D_AROUND_LOCAL_ORIGINS) ||
- (bezt->f2 & SELECT)) ?
- 1 :
- 0]);
- if (hide_handles) {
- if (bezt->f2 & SELECT) {
- td->flag = TD_SELECTED;
- }
- else {
- td->flag = 0;
- }
- }
- else {
- if (bezt->f1 & SELECT) {
- td->flag = TD_SELECTED;
- }
- else {
- td->flag = 0;
- }
- }
- td->ext = NULL;
- td->val = NULL;
-
- hdata = initTransDataCurveHandles(td, bezt);
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- copy_m3_m3(td->axismtx, axismtx);
- }
-
- td++;
- tail++;
- }
-
- /* This is the Curve Point, the other two are handles */
- if (is_prop_edit || bezt_tx & SEL_F2) {
- copy_v3_v3(td->iloc, bezt->vec[1]);
- td->loc = bezt->vec[1];
- copy_v3_v3(td->center, td->loc);
- if (bezt->f2 & SELECT) {
- td->flag = TD_SELECTED;
- }
- else {
- td->flag = 0;
- }
- td->ext = NULL;
-
- /* TODO - make points scale */
- if (t->mode == TFM_CURVE_SHRINKFATTEN) { /* || t->mode==TFM_RESIZE) {*/
- td->val = &(bezt->radius);
- td->ival = bezt->radius;
- }
- else if (t->mode == TFM_TILT) {
- td->val = &(bezt->tilt);
- td->ival = bezt->tilt;
- }
- else {
- td->val = NULL;
- }
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- copy_m3_m3(td->axismtx, axismtx);
- }
-
- if ((bezt_tx & SEL_F1) == 0 && (bezt_tx & SEL_F3) == 0) {
- /* If the middle is selected but the sides arnt, this is needed */
- if (hdata == NULL) {
- /* if the handle was not saved by the previous handle */
- hdata = initTransDataCurveHandles(td, bezt);
- }
- }
-
- td++;
- tail++;
- }
- if (is_prop_edit || bezt_tx & SEL_F3) {
- copy_v3_v3(td->iloc, bezt->vec[2]);
- td->loc = bezt->vec[2];
- copy_v3_v3(td->center,
- bezt->vec[(hide_handles || (t->around == V3D_AROUND_LOCAL_ORIGINS) ||
- (bezt->f2 & SELECT)) ?
- 1 :
- 2]);
- if (hide_handles) {
- if (bezt->f2 & SELECT) {
- td->flag = TD_SELECTED;
- }
- else {
- td->flag = 0;
- }
- }
- else {
- if (bezt->f3 & SELECT) {
- td->flag = TD_SELECTED;
- }
- else {
- td->flag = 0;
- }
- }
- td->ext = NULL;
- td->val = NULL;
-
- if (hdata == NULL) {
- /* if the handle was not saved by the previous handle */
- hdata = initTransDataCurveHandles(td, bezt);
- }
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- copy_m3_m3(td->axismtx, axismtx);
- }
-
- td++;
- tail++;
- }
-
- (void)hdata; /* quiet warning */
- }
- else if (is_prop_edit && head != tail) {
- calc_distanceCurveVerts(head, tail - 1);
- head = tail;
- }
- }
- if (is_prop_edit && head != tail) {
- calc_distanceCurveVerts(head, tail - 1);
- }
-
- /* TODO - in the case of tilt and radius we can also avoid allocating the
- * initTransDataCurveHandles but for now just don't change handle types */
- if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT, TFM_DUMMY) == 0) {
- /* sets the handles based on their selection,
- * do this after the data is copied to the TransData */
- BKE_nurb_handles_test(nu, !hide_handles);
- }
- }
- else {
- TransData *head, *tail;
- head = tail = td;
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
- if (bp->hide == 0) {
- if (is_prop_edit || (bp->f1 & SELECT)) {
- float axismtx[3][3];
-
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- if (nu->pntsv == 1) {
- float normal[3], plane[3];
-
- BKE_nurb_bpoint_calc_normal(nu, bp, normal);
- BKE_nurb_bpoint_calc_plane(nu, bp, plane);
-
- if (createSpaceNormalTangent(axismtx, normal, plane)) {
- /* pass */
- }
- else {
- normalize_v3(normal);
- axis_dominant_v3_to_m3(axismtx, normal);
- invert_m3(axismtx);
- }
- }
- }
-
- copy_v3_v3(td->iloc, bp->vec);
- td->loc = bp->vec;
- copy_v3_v3(td->center, td->loc);
- if (bp->f1 & SELECT) {
- td->flag = TD_SELECTED;
- }
- else {
- td->flag = 0;
- }
- td->ext = NULL;
-
- if (t->mode == TFM_CURVE_SHRINKFATTEN || t->mode == TFM_RESIZE) {
- td->val = &(bp->radius);
- td->ival = bp->radius;
- }
- else {
- td->val = &(bp->tilt);
- td->ival = bp->tilt;
- }
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- if (nu->pntsv == 1) {
- copy_m3_m3(td->axismtx, axismtx);
- }
- }
-
- td++;
- tail++;
- }
- }
- else if (is_prop_edit && head != tail) {
- calc_distanceCurveVerts(head, tail - 1);
- head = tail;
- }
- }
- if (is_prop_edit && head != tail) {
- calc_distanceCurveVerts(head, tail - 1);
- }
- }
- }
- }
-#undef SEL_F1
-#undef SEL_F2
-#undef SEL_F3
-}
-
-/* ********************* lattice *************** */
-
-static void createTransLatticeVerts(TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
-
- Lattice *latt = ((Lattice *)tc->obedit->data)->editlatt->latt;
- TransData *td = NULL;
- BPoint *bp;
- float mtx[3][3], smtx[3][3];
- int a;
- int count = 0, countsel = 0;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
-
- bp = latt->def;
- a = latt->pntsu * latt->pntsv * latt->pntsw;
- while (a--) {
- if (bp->hide == 0) {
- if (bp->f1 & SELECT) {
- countsel++;
- }
- if (is_prop_edit) {
- count++;
- }
- }
- bp++;
- }
-
- /* note: in prop mode we need at least 1 selected */
- if (countsel == 0) {
- return;
- }
-
- if (is_prop_edit) {
- tc->data_len = count;
- }
- else {
- tc->data_len = countsel;
- }
- tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Lattice EditMode)");
-
- copy_m3_m4(mtx, tc->obedit->obmat);
- pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
-
- td = tc->data;
- bp = latt->def;
- a = latt->pntsu * latt->pntsv * latt->pntsw;
- while (a--) {
- if (is_prop_edit || (bp->f1 & SELECT)) {
- if (bp->hide == 0) {
- copy_v3_v3(td->iloc, bp->vec);
- td->loc = bp->vec;
- copy_v3_v3(td->center, td->loc);
- if (bp->f1 & SELECT) {
- td->flag = TD_SELECTED;
- }
- else {
- td->flag = 0;
- }
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
-
- td->ext = NULL;
- td->val = NULL;
-
- td++;
- }
- }
- bp++;
- }
- }
-}
-
-/* ******************* particle edit **************** */
-static void createTransParticleVerts(bContext *C, TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
-
- TransData *td = NULL;
- TransDataExtension *tx;
- Object *ob = CTX_data_active_object(C);
- ParticleEditSettings *pset = PE_settings(t->scene);
- PTCacheEdit *edit = PE_get_current(t->scene, ob);
- ParticleSystem *psys = NULL;
- PTCacheEditPoint *point;
- PTCacheEditKey *key;
- float mat[4][4];
- int i, k, transformparticle;
- int count = 0, hasselected = 0;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
-
- if (edit == NULL || t->settings->particle.selectmode == SCE_SELECT_PATH) {
- return;
- }
-
- psys = edit->psys;
-
- for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) {
- point->flag &= ~PEP_TRANSFORM;
- transformparticle = 0;
-
- if ((point->flag & PEP_HIDE) == 0) {
- for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
- if ((key->flag & PEK_HIDE) == 0) {
- if (key->flag & PEK_SELECT) {
- hasselected = 1;
- transformparticle = 1;
- }
- else if (is_prop_edit) {
- transformparticle = 1;
- }
- }
- }
- }
-
- if (transformparticle) {
- count += point->totkey;
- point->flag |= PEP_TRANSFORM;
- }
- }
-
- /* note: in prop mode we need at least 1 selected */
- if (hasselected == 0) {
- return;
- }
-
- tc->data_len = count;
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Particle Mode)");
-
- if (t->mode == TFM_BAKE_TIME) {
- tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension),
- "Particle_TransExtension");
- }
- else {
- tx = tc->data_ext = NULL;
- }
-
- unit_m4(mat);
-
- invert_m4_m4(ob->imat, ob->obmat);
-
- for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) {
- TransData *head, *tail;
- head = tail = td;
-
- if (!(point->flag & PEP_TRANSFORM)) {
- continue;
- }
-
- if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
- ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
- psys_mat_hair_to_global(
- ob, psmd_eval->mesh_final, psys->part->from, psys->particles + i, mat);
- }
-
- for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
- if (key->flag & PEK_USE_WCO) {
- copy_v3_v3(key->world_co, key->co);
- mul_m4_v3(mat, key->world_co);
- td->loc = key->world_co;
- }
- else {
- td->loc = key->co;
- }
-
- copy_v3_v3(td->iloc, td->loc);
- copy_v3_v3(td->center, td->loc);
-
- if (key->flag & PEK_SELECT) {
- td->flag |= TD_SELECTED;
- }
- else if (!is_prop_edit) {
- td->flag |= TD_SKIP;
- }
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-
- /* don't allow moving roots */
- if (k == 0 && pset->flag & PE_LOCK_FIRST && (!psys || !(psys->flag & PSYS_GLOBAL_HAIR))) {
- td->protectflag |= OB_LOCK_LOC;
- }
-
- td->ob = ob;
- td->ext = tx;
- if (t->mode == TFM_BAKE_TIME) {
- td->val = key->time;
- td->ival = *(key->time);
- /* abuse size and quat for min/max values */
- td->flag |= TD_NO_EXT;
- if (k == 0) {
- tx->size = NULL;
- }
- else {
- tx->size = (key - 1)->time;
- }
-
- if (k == point->totkey - 1) {
- tx->quat = NULL;
- }
- else {
- tx->quat = (key + 1)->time;
- }
- }
-
- td++;
- if (tx) {
- tx++;
- }
- tail++;
- }
- if (is_prop_edit && head != tail) {
- calc_distanceCurveVerts(head, tail - 1);
- }
- }
- }
-}
-
-void flushTransParticles(TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- Scene *scene = t->scene;
- ViewLayer *view_layer = t->view_layer;
- Object *ob = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(scene, ob);
- ParticleSystem *psys = edit->psys;
- PTCacheEditPoint *point;
- PTCacheEditKey *key;
- TransData *td;
- float mat[4][4], imat[4][4], co[3];
- int i, k;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
-
- /* we do transform in world space, so flush world space position
- * back to particle local space (only for hair particles) */
- td = tc->data;
- for (i = 0, point = edit->points; i < edit->totpoint; i++, point++, td++) {
- if (!(point->flag & PEP_TRANSFORM)) {
- continue;
- }
-
- if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
- ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
- psys_mat_hair_to_global(
- ob, psmd_eval->mesh_final, psys->part->from, psys->particles + i, mat);
- invert_m4_m4(imat, mat);
-
- for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
- copy_v3_v3(co, key->world_co);
- mul_m4_v3(imat, co);
-
- /* optimization for proportional edit */
- if (!is_prop_edit || !compare_v3v3(key->co, co, 0.0001f)) {
- copy_v3_v3(key->co, co);
- point->flag |= PEP_EDIT_RECALC;
- }
- }
- }
- else {
- point->flag |= PEP_EDIT_RECALC;
- }
- }
-
- PE_update_object(t->depsgraph, scene, OBACT(view_layer), 1);
- BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
- DEG_id_tag_update(&ob->id, ID_RECALC_PSYS_REDO);
- }
-}
-
-/* ********************* mesh ****************** */
-
-static bool bmesh_test_dist_add(BMVert *v,
- BMVert *v_other,
- float *dists,
- const float *dists_prev,
- /* optionally track original index */
- int *index,
- const int *index_prev,
- float mtx[3][3])
-{
- if ((BM_elem_flag_test(v_other, BM_ELEM_SELECT) == 0) &&
- (BM_elem_flag_test(v_other, BM_ELEM_HIDDEN) == 0)) {
- const int i = BM_elem_index_get(v);
- const int i_other = BM_elem_index_get(v_other);
- float vec[3];
- float dist_other;
- sub_v3_v3v3(vec, v->co, v_other->co);
- mul_m3_v3(mtx, vec);
-
- dist_other = dists_prev[i] + len_v3(vec);
- if (dist_other < dists[i_other]) {
- dists[i_other] = dist_other;
- if (index != NULL) {
- index[i_other] = index_prev[i];
- }
- return true;
- }
- }
-
- return false;
-}
-
-/**
- * \param mtx: Measure distance in this space.
- * \param dists: Store the closest connected distance to selected vertices.
- * \param index: Optionally store the original index we're measuring the distance to (can be NULL).
- */
-static void editmesh_set_connectivity_distance(BMesh *bm,
- float mtx[3][3],
- float *dists,
- int *index)
-{
- BLI_LINKSTACK_DECLARE(queue, BMVert *);
-
- /* any BM_ELEM_TAG'd vertex is in 'queue_next', so we don't add in twice */
- BLI_LINKSTACK_DECLARE(queue_next, BMVert *);
-
- BLI_LINKSTACK_INIT(queue);
- BLI_LINKSTACK_INIT(queue_next);
-
- {
- BMIter viter;
- BMVert *v;
- int i;
-
- BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
- float dist;
- BM_elem_index_set(v, i); /* set_inline */
- BM_elem_flag_disable(v, BM_ELEM_TAG);
-
- if (BM_elem_flag_test(v, BM_ELEM_SELECT) == 0 || BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
- dist = FLT_MAX;
- if (index != NULL) {
- index[i] = i;
- }
- }
- else {
- BLI_LINKSTACK_PUSH(queue, v);
- dist = 0.0f;
- if (index != NULL) {
- index[i] = i;
- }
- }
-
- dists[i] = dist;
- }
- bm->elem_index_dirty &= ~BM_VERT;
- }
-
- /* need to be very careful of feedback loops here, store previous dist's to avoid feedback */
- float *dists_prev = MEM_dupallocN(dists);
- int *index_prev = MEM_dupallocN(index); /* may be NULL */
-
- do {
- BMVert *v;
- LinkNode *lnk;
-
- /* this is correct but slow to do each iteration,
- * instead sync the dist's while clearing BM_ELEM_TAG (below) */
-#if 0
- memcpy(dists_prev, dists, sizeof(float) * bm->totvert);
-#endif
-
- while ((v = BLI_LINKSTACK_POP(queue))) {
- BLI_assert(dists[BM_elem_index_get(v)] != FLT_MAX);
-
- /* connected edge-verts */
- if (v->e != NULL) {
- BMEdge *e_iter, *e_first;
-
- e_iter = e_first = v->e;
-
- /* would normally use BM_EDGES_OF_VERT, but this runs so often,
- * its faster to iterate on the data directly */
- do {
-
- if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == 0) {
-
- /* edge distance */
- {
- BMVert *v_other = BM_edge_other_vert(e_iter, v);
- if (bmesh_test_dist_add(v, v_other, dists, dists_prev, index, index_prev, mtx)) {
- if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
- BM_elem_flag_enable(v_other, BM_ELEM_TAG);
- BLI_LINKSTACK_PUSH(queue_next, v_other);
- }
- }
- }
-
- /* face distance */
- if (e_iter->l) {
- BMLoop *l_iter_radial, *l_first_radial;
- /**
- * imaginary edge diagonally across quad,
- * \note, this takes advantage of the rules of winding that we
- * know 2 or more of a verts edges wont reference the same face twice.
- * Also, if the edge is hidden, the face will be hidden too.
- */
- l_iter_radial = l_first_radial = e_iter->l;
-
- do {
- if ((l_iter_radial->v == v) && (l_iter_radial->f->len == 4) &&
- (BM_elem_flag_test(l_iter_radial->f, BM_ELEM_HIDDEN) == 0)) {
- BMVert *v_other = l_iter_radial->next->next->v;
- if (bmesh_test_dist_add(v, v_other, dists, dists_prev, index, index_prev, mtx)) {
- if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
- BM_elem_flag_enable(v_other, BM_ELEM_TAG);
- BLI_LINKSTACK_PUSH(queue_next, v_other);
- }
- }
- }
- } while ((l_iter_radial = l_iter_radial->radial_next) != l_first_radial);
- }
- }
- } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
- }
- }
-
- /* clear for the next loop */
- for (lnk = queue_next; lnk; lnk = lnk->next) {
- BMVert *v_link = lnk->link;
- const int i = BM_elem_index_get(v_link);
-
- BM_elem_flag_disable(v_link, BM_ELEM_TAG);
-
- /* keep in sync, avoid having to do full memcpy each iteration */
- dists_prev[i] = dists[i];
- if (index != NULL) {
- index_prev[i] = index[i];
- }
- }
-
- BLI_LINKSTACK_SWAP(queue, queue_next);
-
- /* none should be tagged now since 'queue_next' is empty */
- BLI_assert(BM_iter_mesh_count_flag(BM_VERTS_OF_MESH, bm, BM_ELEM_TAG, true) == 0);
-
- } while (BLI_LINKSTACK_SIZE(queue));
-
- BLI_LINKSTACK_FREE(queue);
- BLI_LINKSTACK_FREE(queue_next);
-
- MEM_freeN(dists_prev);
- if (index_prev != NULL) {
- MEM_freeN(index_prev);
- }
-}
-
-static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
- int *r_island_tot,
- int **r_island_vert_map,
- bool calc_single_islands)
-{
- BMesh *bm = em->bm;
- struct TransIslandData *trans_islands;
- char htype;
- char itype;
- int i;
-
- /* group vars */
- int *groups_array;
- int(*group_index)[2];
- int group_tot;
- void **ele_array;
-
- int *vert_map;
-
- if (em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
- groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totedgesel, __func__);
- group_tot = BM_mesh_calc_edge_groups(
- bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT);
-
- htype = BM_EDGE;
- itype = BM_VERTS_OF_EDGE;
- }
- else { /* (bm->selectmode & SCE_SELECT_FACE) */
- groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__);
- group_tot = BM_mesh_calc_face_groups(
- bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT, BM_VERT);
-
- htype = BM_FACE;
- itype = BM_VERTS_OF_FACE;
- }
-
- trans_islands = MEM_mallocN(sizeof(*trans_islands) * group_tot, __func__);
-
- vert_map = MEM_mallocN(sizeof(*vert_map) * bm->totvert, __func__);
- /* we shouldn't need this, but with incorrect selection flushing
- * its possible we have a selected vertex that's not in a face,
- * for now best not crash in that case. */
- copy_vn_i(vert_map, bm->totvert, -1);
-
- BM_mesh_elem_table_ensure(bm, htype);
- ele_array = (htype == BM_FACE) ? (void **)bm->ftable : (void **)bm->etable;
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- /* may be an edge OR a face array */
- for (i = 0; i < group_tot; i++) {
- BMEditSelection ese = {NULL};
-
- const int fg_sta = group_index[i][0];
- const int fg_len = group_index[i][1];
- float co[3], no[3], tangent[3];
- int j;
-
- zero_v3(co);
- zero_v3(no);
- zero_v3(tangent);
-
- ese.htype = htype;
-
- /* loop on each face in this group:
- * - assign r_vert_map
- * - calculate (co, no)
- */
- for (j = 0; j < fg_len; j++) {
- float tmp_co[3], tmp_no[3], tmp_tangent[3];
-
- ese.ele = ele_array[groups_array[fg_sta + j]];
-
- BM_editselection_center(&ese, tmp_co);
- BM_editselection_normal(&ese, tmp_no);
- BM_editselection_plane(&ese, tmp_tangent);
-
- add_v3_v3(co, tmp_co);
- add_v3_v3(no, tmp_no);
- add_v3_v3(tangent, tmp_tangent);
-
- {
- /* setup vertex map */
- BMIter iter;
- BMVert *v;
-
- /* connected edge-verts */
- BM_ITER_ELEM (v, &iter, ese.ele, itype) {
- vert_map[BM_elem_index_get(v)] = i;
- }
- }
- }
-
- mul_v3_v3fl(trans_islands[i].co, co, 1.0f / (float)fg_len);
-
- if (createSpaceNormalTangent(trans_islands[i].axismtx, no, tangent)) {
- /* pass */
- }
- else {
- if (normalize_v3(no) != 0.0f) {
- axis_dominant_v3_to_m3(trans_islands[i].axismtx, no);
- invert_m3(trans_islands[i].axismtx);
- }
- else {
- unit_m3(trans_islands[i].axismtx);
- }
- }
- }
-
- MEM_freeN(groups_array);
- MEM_freeN(group_index);
-
- /* for PET we need islands of 1 so connected vertices can use it with V3D_AROUND_LOCAL_ORIGINS */
- if (calc_single_islands) {
- BMIter viter;
- BMVert *v;
- int group_tot_single = 0;
-
- BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
- if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) {
- group_tot_single += 1;
- }
- }
-
- if (group_tot_single != 0) {
- trans_islands = MEM_reallocN(trans_islands,
- sizeof(*trans_islands) * (group_tot + group_tot_single));
-
- BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
- if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) {
- struct TransIslandData *v_island = &trans_islands[group_tot];
- vert_map[i] = group_tot;
-
- copy_v3_v3(v_island->co, v->co);
-
- if (is_zero_v3(v->no) != 0.0f) {
- axis_dominant_v3_to_m3(v_island->axismtx, v->no);
- invert_m3(v_island->axismtx);
- }
- else {
- unit_m3(v_island->axismtx);
- }
-
- group_tot += 1;
- }
- }
- }
- }
-
- *r_island_tot = group_tot;
- *r_island_vert_map = vert_map;
-
- return trans_islands;
-}
-
-/* way to overwrite what data is edited with transform */
-static void VertsToTransData(TransInfo *t,
- TransData *td,
- TransDataExtension *tx,
- BMEditMesh *em,
- BMVert *eve,
- float *bweight,
- struct TransIslandData *v_island,
- const bool no_island_center)
-{
- float *no, _no[3];
- BLI_assert(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) == 0);
-
- td->flag = 0;
- // if (key)
- // td->loc = key->co;
- // else
- td->loc = eve->co;
- copy_v3_v3(td->iloc, td->loc);
-
- if ((t->mode == TFM_SHRINKFATTEN) && (em->selectmode & SCE_SELECT_FACE) &&
- BM_elem_flag_test(eve, BM_ELEM_SELECT) &&
- (BM_vert_calc_normal_ex(eve, BM_ELEM_SELECT, _no))) {
- no = _no;
- }
- else {
- no = eve->no;
- }
-
- if (v_island) {
- if (no_island_center) {
- copy_v3_v3(td->center, td->loc);
- }
- else {
- copy_v3_v3(td->center, v_island->co);
- }
- copy_m3_m3(td->axismtx, v_island->axismtx);
- }
- else if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- copy_v3_v3(td->center, td->loc);
- createSpaceNormal(td->axismtx, no);
- }
- else {
- copy_v3_v3(td->center, td->loc);
-
- /* Setting normals */
- copy_v3_v3(td->axismtx[2], no);
- td->axismtx[0][0] = td->axismtx[0][1] = td->axismtx[0][2] = td->axismtx[1][0] =
- td->axismtx[1][1] = td->axismtx[1][2] = 0.0f;
- }
-
- td->ext = NULL;
- td->val = NULL;
- td->extra = NULL;
- if (t->mode == TFM_BWEIGHT) {
- td->val = bweight;
- td->ival = *bweight;
- }
- else if (t->mode == TFM_SKIN_RESIZE) {
- MVertSkin *vs = CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MVERT_SKIN);
- if (vs) {
- /* skin node size */
- td->ext = tx;
- copy_v3_v3(tx->isize, vs->radius);
- tx->size = vs->radius;
- td->val = vs->radius;
- }
- else {
- td->flag |= TD_SKIP;
- }
- }
- else if (t->mode == TFM_SHRINKFATTEN) {
- td->ext = tx;
- tx->isize[0] = BM_vert_calc_shell_factor_ex(eve, no, BM_ELEM_SELECT);
- }
-}
-
-static void createTransEditVerts(TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *tob = NULL;
- TransDataExtension *tx = NULL;
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- Mesh *me = tc->obedit->data;
- BMesh *bm = em->bm;
- BMVert *eve;
- BMIter iter;
- float(*mappedcos)[3] = NULL, (*quats)[4] = NULL;
- float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL;
- float *dists = NULL;
- int a;
- const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
- int mirror = 0;
- int cd_vert_bweight_offset = -1;
- bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
-
- struct TransIslandData *island_info = NULL;
- int island_info_tot;
- int *island_vert_map = NULL;
-
- /* Snap rotation along normal needs a common axis for whole islands,
- * otherwise one get random crazy results, see T59104.
- * However, we do not want to use the island center for the pivot/translation reference. */
- const bool is_snap_rotate = ((t->mode == TFM_TRANSLATION) &&
- /* There is not guarantee that snapping
- * is initialized yet at this point... */
- (usingSnappingNormal(t) ||
- (t->settings->snap_flag & SCE_SNAP_ROTATE) != 0) &&
- (t->around != V3D_AROUND_LOCAL_ORIGINS));
- /* Even for translation this is needed because of island-orientation, see: T51651. */
- const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS) || is_snap_rotate;
- /* Original index of our connected vertex when connected distances are calculated.
- * Optional, allocate if needed. */
- int *dists_index = NULL;
-
- if (tc->mirror.axis_flag) {
- EDBM_verts_mirror_cache_begin(em, 0, false, (t->flag & T_PROP_EDIT) == 0, use_topology);
- mirror = 1;
- }
-
- /**
- * Quick check if we can transform.
- *
- * \note ignore modes here, even in edge/face modes,
- * transform data is created by selected vertices.
- * \note in prop mode we need at least 1 selected.
- */
- if (bm->totvertsel == 0) {
- goto cleanup;
- }
-
- if (t->mode == TFM_BWEIGHT) {
- BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT);
- cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
- }
-
- if (prop_mode) {
- unsigned int count = 0;
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- count++;
- }
- }
-
- tc->data_len = count;
-
- /* allocating scratch arrays */
- if (prop_mode & T_PROP_CONNECTED) {
- dists = MEM_mallocN(em->bm->totvert * sizeof(float), __func__);
- if (is_island_center) {
- dists_index = MEM_mallocN(em->bm->totvert * sizeof(int), __func__);
- }
- }
- }
- else {
- tc->data_len = bm->totvertsel;
- }
-
- tob = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Mesh EditMode)");
- if (ELEM(t->mode, TFM_SKIN_RESIZE, TFM_SHRINKFATTEN)) {
- /* warning, this is overkill, we only need 2 extra floats,
- * but this stores loads of extra stuff, for TFM_SHRINKFATTEN its even more overkill
- * since we may not use the 'alt' transform mode to maintain shell thickness,
- * but with generic transform code its hard to lazy init vars */
- tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension),
- "TransObData ext");
- }
-
- copy_m3_m4(mtx, tc->obedit->obmat);
- /* we use a pseudo-inverse so that when one of the axes is scaled to 0,
- * matrix inversion still works and we can still moving along the other */
- pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
-
- if (prop_mode & T_PROP_CONNECTED) {
- editmesh_set_connectivity_distance(em->bm, mtx, dists, dists_index);
- }
-
- if (is_island_center) {
- /* In this specific case, near-by vertices will need to know
- * the island of the nearest connected vertex. */
- const bool calc_single_islands = ((prop_mode & T_PROP_CONNECTED) &&
- (t->around == V3D_AROUND_LOCAL_ORIGINS) &&
- (em->selectmode & SCE_SELECT_VERTEX));
-
- island_info = editmesh_islands_info_calc(
- em, &island_info_tot, &island_vert_map, calc_single_islands);
- }
-
- /* detect CrazySpace [tm] */
- if (modifiers_getCageIndex(t->scene, tc->obedit, NULL, 1) != -1) {
- int totleft = -1;
- if (modifiers_isCorrectableDeformed(t->scene, tc->obedit)) {
- BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context));
-
- /* Use evaluated state because we need b-bone cache. */
- Scene *scene_eval = (Scene *)DEG_get_evaluated_id(t->depsgraph, &t->scene->id);
- Object *obedit_eval = (Object *)DEG_get_evaluated_id(t->depsgraph, &tc->obedit->id);
- BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval);
- /* check if we can use deform matrices for modifier from the
- * start up to stack, they are more accurate than quats */
- totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh(
- t->depsgraph, scene_eval, obedit_eval, em_eval, &defmats, &defcos);
- }
-
- /* if we still have more modifiers, also do crazyspace
- * correction with quats, relative to the coordinates after
- * the modifiers that support deform matrices (defcos) */
-
-#if 0 /* TODO, fix crazyspace+extrude so it can be enabled for general use - campbell */
- if ((totleft > 0) || (totleft == -1))
-#else
- if (totleft > 0)
-#endif
- {
- mappedcos = BKE_crazyspace_get_mapped_editverts(t->depsgraph, tc->obedit);
- quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats");
- BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode);
- if (mappedcos) {
- MEM_freeN(mappedcos);
- }
- }
-
- if (defcos) {
- MEM_freeN(defcos);
- }
- }
-
- /* find out which half we do */
- if (mirror) {
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && eve->co[0] != 0.0f) {
- if (eve->co[0] < 0.0f) {
- tc->mirror.sign = -1.0f;
- mirror = -1;
- }
- break;
- }
- }
- }
-
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- struct TransIslandData *v_island = NULL;
- float *bweight = (cd_vert_bweight_offset != -1) ?
- BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) :
- NULL;
-
- if (island_info) {
- const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a;
- v_island = (island_vert_map[connected_index] != -1) ?
- &island_info[island_vert_map[connected_index]] :
- NULL;
- }
-
- /* Do not use the island center in case we are using islands
- * only to get axis for snap/rotate to normal... */
- VertsToTransData(t, tob, tx, em, eve, bweight, v_island, is_snap_rotate);
- if (tx) {
- tx++;
- }
-
- /* selected */
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- tob->flag |= TD_SELECTED;
- }
-
- if (prop_mode) {
- if (prop_mode & T_PROP_CONNECTED) {
- tob->dist = dists[a];
- }
- else {
- tob->flag |= TD_NOTCONNECTED;
- tob->dist = FLT_MAX;
- }
- }
-
- /* CrazySpace */
- const bool use_quats = quats && BM_elem_flag_test(eve, BM_ELEM_TAG);
- if (use_quats || defmats) {
- float mat[3][3], qmat[3][3], imat[3][3];
-
- /* Use both or either quat and defmat correction. */
- if (use_quats) {
- quat_to_mat3(qmat, quats[BM_elem_index_get(eve)]);
-
- if (defmats) {
- mul_m3_series(mat, defmats[a], qmat, mtx);
- }
- else {
- mul_m3_m3m3(mat, mtx, qmat);
- }
- }
- else {
- mul_m3_m3m3(mat, mtx, defmats[a]);
- }
-
- invert_m3_m3(imat, mat);
-
- copy_m3_m3(tob->smtx, imat);
- copy_m3_m3(tob->mtx, mat);
- }
- else {
- copy_m3_m3(tob->smtx, smtx);
- copy_m3_m3(tob->mtx, mtx);
- }
-
- /* Mirror? */
- if ((mirror > 0 && tob->iloc[0] > 0.0f) || (mirror < 0 && tob->iloc[0] < 0.0f)) {
- BMVert *vmir = EDBM_verts_mirror_get(em, eve); // t->obedit, em, eve, tob->iloc, a);
- if (vmir && vmir != eve) {
- tob->extra = vmir;
- }
- }
- tob++;
- }
- }
- }
-
- if (island_info) {
- MEM_freeN(island_info);
- MEM_freeN(island_vert_map);
- }
-
- if (mirror != 0) {
- tob = tc->data;
- for (a = 0; a < tc->data_len; a++, tob++) {
- if (ABS(tob->loc[0]) <= 0.00001f) {
- tob->flag |= TD_MIRROR_EDGE;
- }
- }
- }
-
- cleanup:
- /* crazy space free */
- if (quats) {
- MEM_freeN(quats);
- }
- if (defmats) {
- MEM_freeN(defmats);
- }
- if (dists) {
- MEM_freeN(dists);
- }
- if (dists_index) {
- MEM_freeN(dists_index);
- }
-
- if (tc->mirror.axis_flag) {
- EDBM_verts_mirror_cache_end(em);
- }
- }
-}
-
-/* *** NODE EDITOR *** */
-void flushTransNodes(TransInfo *t)
-{
- const float dpi_fac = UI_DPI_FAC;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- int a;
- TransData *td;
- TransData2D *td2d;
-
- applyGridAbsolute(t);
-
- /* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
- bNode *node = td->extra;
- float locx, locy;
-
- /* weirdo - but the node system is a mix of free 2d elements and dpi sensitive UI */
-#ifdef USE_NODE_CENTER
- locx = (td2d->loc[0] - (BLI_rctf_size_x(&node->totr)) * +0.5f) / dpi_fac;
- locy = (td2d->loc[1] - (BLI_rctf_size_y(&node->totr)) * -0.5f) / dpi_fac;
-#else
- locx = td2d->loc[0] / dpi_fac;
- locy = td2d->loc[1] / dpi_fac;
-#endif
-
- /* account for parents (nested nodes) */
- if (node->parent) {
- nodeFromView(node->parent, locx, locy, &node->locx, &node->locy);
- }
- else {
- node->locx = locx;
- node->locy = locy;
- }
- }
-
- /* handle intersection with noodles */
- if (tc->data_len == 1) {
- ED_node_link_intersect_test(t->sa, 1);
- }
- }
-}
-
-/* *** SEQUENCE EDITOR *** */
-
-/* commented _only_ because the meta may have animation data which
- * needs moving too [#28158] */
-
-#define SEQ_TX_NESTED_METAS
-
-BLI_INLINE void trans_update_seq(Scene *sce, Sequence *seq, int old_start, int sel_flag)
-{
- if (seq->depth == 0) {
- /* Calculate this strip and all nested strips.
- * Children are ALWAYS transformed first so we don't need to do this in another loop.
- */
- BKE_sequence_calc(sce, seq);
- }
- else {
- BKE_sequence_calc_disp(sce, seq);
- }
-
- if (sel_flag == SELECT) {
- BKE_sequencer_offset_animdata(sce, seq, seq->start - old_start);
- }
-}
-
-void flushTransSeq(TransInfo *t)
-{
- /* Editing null check already done */
- ListBase *seqbasep = BKE_sequencer_editing_get(t->scene, false)->seqbasep;
-
- int a, new_frame;
- TransData *td = NULL;
- TransData2D *td2d = NULL;
- TransDataSeq *tdsq = NULL;
- Sequence *seq;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* prevent updating the same seq twice
- * if the transdata order is changed this will mess up
- * but so will TransDataSeq */
- Sequence *seq_prev = NULL;
- int old_start_prev = 0, sel_flag_prev = 0;
-
- /* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
- int old_start;
- tdsq = (TransDataSeq *)td->extra;
- seq = tdsq->seq;
- old_start = seq->start;
- new_frame = round_fl_to_int(td2d->loc[0]);
-
- switch (tdsq->sel_flag) {
- case SELECT:
-#ifdef SEQ_TX_NESTED_METAS
- if ((seq->depth != 0 || BKE_sequence_tx_test(seq))) {
- /* for meta's, their children move */
- seq->start = new_frame - tdsq->start_offset;
- }
-#else
- if (seq->type != SEQ_TYPE_META && (seq->depth != 0 || seq_tx_test(seq))) {
- /* for meta's, their children move */
- seq->start = new_frame - tdsq->start_offset;
- }
-#endif
- if (seq->depth == 0) {
- seq->machine = round_fl_to_int(td2d->loc[1]);
- CLAMP(seq->machine, 1, MAXSEQ);
- }
- break;
- case SEQ_LEFTSEL: /* no vertical transform */
- BKE_sequence_tx_set_final_left(seq, new_frame);
- BKE_sequence_tx_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL);
-
- /* todo - move this into aftertrans update? - old seq tx needed it anyway */
- BKE_sequence_single_fix(seq);
- break;
- case SEQ_RIGHTSEL: /* no vertical transform */
- BKE_sequence_tx_set_final_right(seq, new_frame);
- BKE_sequence_tx_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL);
-
- /* todo - move this into aftertrans update? - old seq tx needed it anyway */
- BKE_sequence_single_fix(seq);
- break;
- }
-
- /* Update *previous* seq! Else, we would update a seq after its first transform,
- * and if it has more than one (like e.g. SEQ_LEFTSEL and SEQ_RIGHTSEL),
- * the others are not updated! See T38469.
- */
- if (seq != seq_prev) {
- if (seq_prev) {
- trans_update_seq(t->scene, seq_prev, old_start_prev, sel_flag_prev);
- }
-
- seq_prev = seq;
- old_start_prev = old_start;
- sel_flag_prev = tdsq->sel_flag;
- }
- else {
- /* We want to accumulate *all* sel_flags for this seq! */
- sel_flag_prev |= tdsq->sel_flag;
- }
- }
-
- /* Don't forget to update the last seq! */
- if (seq_prev) {
- trans_update_seq(t->scene, seq_prev, old_start_prev, sel_flag_prev);
- }
-
- /* originally TFM_TIME_EXTEND, transform changes */
- if (ELEM(t->mode, TFM_SEQ_SLIDE, TFM_TIME_TRANSLATE)) {
- /* Special annoying case here, need to calc metas with TFM_TIME_EXTEND only */
-
- /* calc all meta's then effects [#27953] */
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->type == SEQ_TYPE_META && seq->flag & SELECT) {
- BKE_sequence_calc(t->scene, seq);
- }
- }
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->seq1 || seq->seq2 || seq->seq3) {
- BKE_sequence_calc(t->scene, seq);
- }
- }
-
- /* update effects inside meta's */
- for (a = 0, seq_prev = NULL, td = tc->data, td2d = tc->data_2d; a < tc->data_len;
- a++, td++, td2d++, seq_prev = seq) {
- tdsq = (TransDataSeq *)td->extra;
- seq = tdsq->seq;
- if ((seq != seq_prev) && (seq->depth != 0)) {
- if (seq->seq1 || seq->seq2 || seq->seq3) {
- BKE_sequence_calc(t->scene, seq);
- }
- }
- }
- }
-
- /* need to do the overlap check in a new loop otherwise adjacent strips
- * will not be updated and we'll get false positives */
- seq_prev = NULL;
- for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
-
- tdsq = (TransDataSeq *)td->extra;
- seq = tdsq->seq;
-
- if (seq != seq_prev) {
- if (seq->depth == 0) {
- /* test overlap, displays red outline */
- seq->flag &= ~SEQ_OVERLAP;
- if (BKE_sequence_test_overlap(seqbasep, seq)) {
- seq->flag |= SEQ_OVERLAP;
- }
- }
- }
- seq_prev = seq;
- }
-}
-
-/* ********************* UV ****************** */
-
-static void UVsToTransData(const float aspect[2],
- TransData *td,
- TransData2D *td2d,
- float *uv,
- const float *center,
- bool selected)
-{
- /* uv coords are scaled by aspects. this is needed for rotations and
- * proportional editing to be consistent with the stretched uv coords
- * that are displayed. this also means that for display and numinput,
- * and when the uv coords are flushed, these are converted each time */
- td2d->loc[0] = uv[0] * aspect[0];
- td2d->loc[1] = uv[1] * aspect[1];
- td2d->loc[2] = 0.0f;
- td2d->loc2d = uv;
-
- td->flag = 0;
- td->loc = td2d->loc;
- copy_v2_v2(td->center, center ? center : td->loc);
- td->center[2] = 0.0f;
- copy_v3_v3(td->iloc, td->loc);
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
-
- if (selected) {
- td->flag |= TD_SELECTED;
- td->dist = 0.0;
- }
- else {
- td->dist = FLT_MAX;
- }
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-}
-
-static void createTransUVs(bContext *C, TransInfo *t)
-{
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
- Scene *scene = t->scene;
- ToolSettings *ts = CTX_data_tool_settings(C);
-
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
- const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0;
- const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS);
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
-
- TransData *td = NULL;
- TransData2D *td2d = NULL;
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- BMFace *efa;
- BMIter iter, liter;
- UvElementMap *elementmap = NULL;
- BLI_bitmap *island_enabled = NULL;
- struct {
- float co[2];
- int co_num;
- } *island_center = NULL;
- int count = 0, countsel = 0, count_rejected = 0;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if (!ED_space_image_show_uvedit(sima, tc->obedit)) {
- continue;
- }
-
- /* count */
- if (is_prop_connected || is_island_center) {
- /* create element map with island information */
- const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0;
- elementmap = BM_uv_element_map_create(em->bm, use_facesel, false, true);
- if (elementmap == NULL) {
- return;
- }
-
- if (is_prop_connected) {
- island_enabled = BLI_BITMAP_NEW(elementmap->totalIslands, "TransIslandData(UV Editing)");
- }
-
- if (is_island_center) {
- island_center = MEM_callocN(sizeof(*island_center) * elementmap->totalIslands, __func__);
- }
- }
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BMLoop *l;
-
- if (!uvedit_face_visible_test(scene, tc->obedit, ima, efa)) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- continue;
- }
-
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- countsel++;
-
- if (is_prop_connected || island_center) {
- UvElement *element = BM_uv_element_get(elementmap, efa, l);
-
- if (is_prop_connected) {
- BLI_BITMAP_ENABLE(island_enabled, element->island);
- }
-
- if (is_island_center) {
- if (element->flag == false) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- add_v2_v2(island_center[element->island].co, luv->uv);
- island_center[element->island].co_num++;
- element->flag = true;
- }
- }
- }
- }
-
- if (is_prop_edit) {
- count++;
- }
- }
- }
-
- /* note: in prop mode we need at least 1 selected */
- if (countsel == 0) {
- goto finally;
- }
-
- if (is_island_center) {
- int i;
-
- for (i = 0; i < elementmap->totalIslands; i++) {
- mul_v2_fl(island_center[i].co, 1.0f / island_center[i].co_num);
- mul_v2_v2(island_center[i].co, t->aspect);
- }
- }
-
- tc->data_len = (is_prop_edit) ? count : countsel;
- tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(UV Editing)");
- /* for each 2d uv coord a 3d vector is allocated, so that they can be
- * treated just as if they were 3d verts */
- tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransObData2D(UV Editing)");
-
- if (sima->flag & SI_CLIP_UV) {
- t->flag |= T_CLIP_UV;
- }
-
- td = tc->data;
- td2d = tc->data_2d;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BMLoop *l;
-
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- const bool selected = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
- MLoopUV *luv;
- const float *center = NULL;
-
- if (!is_prop_edit && !selected) {
- continue;
- }
-
- if (is_prop_connected || is_island_center) {
- UvElement *element = BM_uv_element_get(elementmap, efa, l);
-
- if (is_prop_connected) {
- if (!BLI_BITMAP_TEST(island_enabled, element->island)) {
- count_rejected++;
- continue;
- }
- }
-
- if (is_island_center) {
- center = island_center[element->island].co;
- }
- }
-
- BM_elem_flag_enable(l, BM_ELEM_TAG);
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- UVsToTransData(t->aspect, td++, td2d++, luv->uv, center, selected);
- }
- }
-
- if (is_prop_connected) {
- tc->data_len -= count_rejected;
- }
-
- if (sima->flag & SI_LIVE_UNWRAP) {
- ED_uvedit_live_unwrap_begin(t->scene, tc->obedit);
- }
-
- finally:
- if (is_prop_connected || is_island_center) {
- BM_uv_element_map_free(elementmap);
-
- if (is_prop_connected) {
- MEM_freeN(island_enabled);
- }
-
- if (island_center) {
- MEM_freeN(island_center);
- }
- }
- }
-}
-
-void flushTransUVs(TransInfo *t)
-{
- SpaceImage *sima = t->sa->spacedata.first;
- const bool use_pixel_snap = ((sima->pixel_snap_mode != SI_PIXEL_SNAP_DISABLED) &&
- (t->state != TRANS_CANCEL));
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData2D *td;
- int a;
- float aspect_inv[2], size[2];
-
- aspect_inv[0] = 1.0f / t->aspect[0];
- aspect_inv[1] = 1.0f / t->aspect[1];
-
- if (use_pixel_snap) {
- int size_i[2];
- ED_space_image_get_size(sima, &size_i[0], &size_i[1]);
- size[0] = size_i[0];
- size[1] = size_i[1];
- }
-
- /* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = tc->data_2d; a < tc->data_len; a++, td++) {
- td->loc2d[0] = td->loc[0] * aspect_inv[0];
- td->loc2d[1] = td->loc[1] * aspect_inv[1];
-
- if (use_pixel_snap) {
- td->loc2d[0] *= size[0];
- td->loc2d[1] *= size[1];
-
- switch (sima->pixel_snap_mode) {
- case SI_PIXEL_SNAP_CENTER:
- td->loc2d[0] = roundf(td->loc2d[0] - 0.5f) + 0.5f;
- td->loc2d[1] = roundf(td->loc2d[1] - 0.5f) + 0.5f;
- break;
- case SI_PIXEL_SNAP_CORNER:
- td->loc2d[0] = roundf(td->loc2d[0]);
- td->loc2d[1] = roundf(td->loc2d[1]);
- break;
- }
-
- td->loc2d[0] /= size[0];
- td->loc2d[1] /= size[1];
- }
- }
- }
-}
-
-bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
-{
- bool clipx = true, clipy = true;
- float min[2], max[2];
-
- min[0] = min[1] = 0.0f;
- max[0] = t->aspect[0];
- max[1] = t->aspect[1];
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
-
- TransData *td;
- int a;
-
- for (a = 0, td = tc->data; a < tc->data_len; a++, td++) {
- minmax_v2v2_v2(min, max, td->loc);
- }
- }
-
- if (resize) {
- if (min[0] < 0.0f && t->center_global[0] > 0.0f && t->center_global[0] < t->aspect[0] * 0.5f) {
- vec[0] *= t->center_global[0] / (t->center_global[0] - min[0]);
- }
- else if (max[0] > t->aspect[0] && t->center_global[0] < t->aspect[0]) {
- vec[0] *= (t->center_global[0] - t->aspect[0]) / (t->center_global[0] - max[0]);
- }
- else {
- clipx = 0;
- }
-
- if (min[1] < 0.0f && t->center_global[1] > 0.0f && t->center_global[1] < t->aspect[1] * 0.5f) {
- vec[1] *= t->center_global[1] / (t->center_global[1] - min[1]);
- }
- else if (max[1] > t->aspect[1] && t->center_global[1] < t->aspect[1]) {
- vec[1] *= (t->center_global[1] - t->aspect[1]) / (t->center_global[1] - max[1]);
- }
- else {
- clipy = 0;
- }
- }
- else {
- if (min[0] < 0.0f) {
- vec[0] -= min[0];
- }
- else if (max[0] > t->aspect[0]) {
- vec[0] -= max[0] - t->aspect[0];
- }
- else {
- clipx = 0;
- }
-
- if (min[1] < 0.0f) {
- vec[1] -= min[1];
- }
- else if (max[1] > t->aspect[1]) {
- vec[1] -= max[1] - t->aspect[1];
- }
- else {
- clipy = 0;
- }
- }
-
- return (clipx || clipy);
-}
-
-void clipUVData(TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (int a = 0; a < tc->data_len; a++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if ((td->flag & TD_SKIP) || (!td->loc)) {
- continue;
- }
-
- td->loc[0] = min_ff(max_ff(0.0f, td->loc[0]), t->aspect[0]);
- td->loc[1] = min_ff(max_ff(0.0f, td->loc[1]), t->aspect[1]);
- }
- }
-}
-
-/* ********************* ANIMATION EDITORS (GENERAL) ************************* */
-
-/* This function tests if a point is on the "mouse" side of the cursor/frame-marking */
-static bool FrameOnMouseSide(char side, float frame, float cframe)
-{
- /* both sides, so it doesn't matter */
- if (side == 'B') {
- return true;
- }
-
- /* only on the named side */
- if (side == 'R') {
- return (frame >= cframe);
- }
- else {
- return (frame <= cframe);
- }
-}
-
-/* ********************* NLA EDITOR ************************* */
-
-static void createTransNlaData(bContext *C, TransInfo *t)
-{
- Scene *scene = t->scene;
- SpaceNla *snla = NULL;
- TransData *td = NULL;
- TransDataNla *tdn = NULL;
-
- bAnimContext ac;
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
-
- int count = 0;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* determine what type of data we are operating on */
- if (ANIM_animdata_get_context(C, &ac) == 0) {
- return;
- }
- snla = (SpaceNla *)ac.sl;
-
- /* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- /* which side of the current frame should be allowed */
- if (t->mode == TFM_TIME_EXTEND) {
- /* only side on which mouse is gets transformed */
- float xmouse, ymouse;
-
- UI_view2d_region_to_view(&ac.ar->v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse);
- t->frame_side = (xmouse > CFRA) ? 'R' : 'L';
- }
- else {
- /* normal transform - both sides of current frame are considered */
- t->frame_side = 'B';
- }
-
- /* loop 1: count how many strips are selected (consider each strip as 2 points) */
- for (ale = anim_data.first; ale; ale = ale->next) {
- NlaTrack *nlt = (NlaTrack *)ale->data;
- NlaStrip *strip;
-
- /* make some meta-strips for chains of selected strips */
- BKE_nlastrips_make_metas(&nlt->strips, 1);
-
- /* only consider selected strips */
- for (strip = nlt->strips.first; strip; strip = strip->next) {
- // TODO: we can make strips have handles later on...
- /* transition strips can't get directly transformed */
- if (strip->type != NLASTRIP_TYPE_TRANSITION) {
- if (strip->flag & NLASTRIP_FLAG_SELECT) {
- if (FrameOnMouseSide(t->frame_side, strip->start, (float)CFRA)) {
- count++;
- }
- if (FrameOnMouseSide(t->frame_side, strip->end, (float)CFRA)) {
- count++;
- }
- }
- }
- }
- }
-
- /* stop if trying to build list if nothing selected */
- if (count == 0) {
- /* clear temp metas that may have been created but aren't needed now
- * because they fell on the wrong side of CFRA
- */
- for (ale = anim_data.first; ale; ale = ale->next) {
- NlaTrack *nlt = (NlaTrack *)ale->data;
- BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
- }
-
- /* cleanup temp list */
- ANIM_animdata_freelist(&anim_data);
- return;
- }
-
- /* allocate memory for data */
- tc->data_len = count;
-
- tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(NLA Editor)");
- td = tc->data;
- tc->custom.type.data = tdn = MEM_callocN(tc->data_len * sizeof(TransDataNla),
- "TransDataNla (NLA Editor)");
- tc->custom.type.use_free = true;
-
- /* loop 2: build transdata array */
- for (ale = anim_data.first; ale; ale = ale->next) {
- /* only if a real NLA-track */
- if (ale->type == ANIMTYPE_NLATRACK) {
- AnimData *adt = ale->adt;
- NlaTrack *nlt = (NlaTrack *)ale->data;
- NlaStrip *strip;
-
- /* only consider selected strips */
- for (strip = nlt->strips.first; strip; strip = strip->next) {
- // TODO: we can make strips have handles later on...
- /* transition strips can't get directly transformed */
- if (strip->type != NLASTRIP_TYPE_TRANSITION) {
- if (strip->flag & NLASTRIP_FLAG_SELECT) {
- /* our transform data is constructed as follows:
- * - only the handles on the right side of the current-frame get included
- * - td structs are transform-elements operated on by the transform system
- * and represent a single handle. The storage/pointer used (val or loc) depends on
- * whether we're scaling or transforming. Ultimately though, the handles
- * the td writes to will simply be a dummy in tdn
- * - for each strip being transformed, a single tdn struct is used, so in some
- * cases, there will need to be 1 of these tdn elements in the array skipped...
- */
- float center[3], yval;
-
- /* firstly, init tdn settings */
- tdn->id = ale->id;
- tdn->oldTrack = tdn->nlt = nlt;
- tdn->strip = strip;
- tdn->trackIndex = BLI_findindex(&adt->nla_tracks, nlt);
-
- yval = (float)(tdn->trackIndex * NLACHANNEL_STEP(snla));
-
- tdn->h1[0] = strip->start;
- tdn->h1[1] = yval;
- tdn->h2[0] = strip->end;
- tdn->h2[1] = yval;
-
- center[0] = (float)CFRA;
- center[1] = yval;
- center[2] = 0.0f;
-
- /* set td's based on which handles are applicable */
- if (FrameOnMouseSide(t->frame_side, strip->start, (float)CFRA)) {
- /* just set tdn to assume that it only has one handle for now */
- tdn->handle = -1;
-
- /* now, link the transform data up to this data */
- if (ELEM(t->mode, TFM_TRANSLATION, TFM_TIME_EXTEND)) {
- td->loc = tdn->h1;
- copy_v3_v3(td->iloc, tdn->h1);
-
- /* store all the other gunk that is required by transform */
- copy_v3_v3(td->center, center);
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
-
- td->flag |= TD_SELECTED;
- td->dist = 0.0f;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
- }
- else {
- /* time scaling only needs single value */
- td->val = &tdn->h1[0];
- td->ival = tdn->h1[0];
- }
-
- td->extra = tdn;
- td++;
- }
- if (FrameOnMouseSide(t->frame_side, strip->end, (float)CFRA)) {
- /* if tdn is already holding the start handle,
- * then we're doing both, otherwise, only end */
- tdn->handle = (tdn->handle) ? 2 : 1;
-
- /* now, link the transform data up to this data */
- if (ELEM(t->mode, TFM_TRANSLATION, TFM_TIME_EXTEND)) {
- td->loc = tdn->h2;
- copy_v3_v3(td->iloc, tdn->h2);
-
- /* store all the other gunk that is required by transform */
- copy_v3_v3(td->center, center);
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
-
- td->flag |= TD_SELECTED;
- td->dist = 0.0f;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
- }
- else {
- /* time scaling only needs single value */
- td->val = &tdn->h2[0];
- td->ival = tdn->h2[0];
- }
-
- td->extra = tdn;
- td++;
- }
-
- /* If both handles were used, skip the next tdn (i.e. leave it blank)
- * since the counting code is dumb.
- * Otherwise, just advance to the next one.
- */
- if (tdn->handle == 2) {
- tdn += 2;
- }
- else {
- tdn++;
- }
- }
- }
- }
- }
- }
-
- /* cleanup temp list */
- ANIM_animdata_freelist(&anim_data);
-}
-
-/* ********************* ACTION EDITOR ****************** */
-
-static int gpf_cmp_frame(void *thunk, const void *a, const void *b)
-{
- const bGPDframe *frame_a = a;
- const bGPDframe *frame_b = b;
-
- if (frame_a->framenum < frame_b->framenum) {
- return -1;
- }
- if (frame_a->framenum > frame_b->framenum) {
- return 1;
- }
- *((bool *)thunk) = true;
- /* selected last */
- if ((frame_a->flag & GP_FRAME_SELECT) && ((frame_b->flag & GP_FRAME_SELECT) == 0)) {
- return 1;
- }
- return 0;
-}
-
-static int masklay_shape_cmp_frame(void *thunk, const void *a, const void *b)
-{
- const MaskLayerShape *frame_a = a;
- const MaskLayerShape *frame_b = b;
-
- if (frame_a->frame < frame_b->frame) {
- return -1;
- }
- if (frame_a->frame > frame_b->frame) {
- return 1;
- }
- *((bool *)thunk) = true;
- /* selected last */
- if ((frame_a->flag & MASK_SHAPE_SELECT) && ((frame_b->flag & MASK_SHAPE_SELECT) == 0)) {
- return 1;
- }
- return 0;
-}
-
-/* Called by special_aftertrans_update to make sure selected gp-frames replace
- * any other gp-frames which may reside on that frame (that are not selected).
- * It also makes sure gp-frames are still stored in chronological order after
- * transform.
- */
-static void posttrans_gpd_clean(bGPdata *gpd)
-{
- bGPDlayer *gpl;
-
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- bGPDframe *gpf, *gpfn;
- bool is_double = false;
-
- BLI_listbase_sort_r(&gpl->frames, gpf_cmp_frame, &is_double);
-
- if (is_double) {
- for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
- gpfn = gpf->next;
- if (gpfn && gpf->framenum == gpfn->framenum) {
- BKE_gpencil_layer_delframe(gpl, gpf);
- }
- }
- }
-
-#ifdef DEBUG
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- BLI_assert(!gpf->next || gpf->framenum < gpf->next->framenum);
- }
-#endif
- }
- /* set cache flag to dirty */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
-}
-
-static void posttrans_mask_clean(Mask *mask)
-{
- MaskLayer *masklay;
-
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskLayerShape *masklay_shape, *masklay_shape_next;
- bool is_double = false;
-
- BLI_listbase_sort_r(&masklay->splines_shapes, masklay_shape_cmp_frame, &is_double);
-
- if (is_double) {
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
- masklay_shape = masklay_shape_next) {
- masklay_shape_next = masklay_shape->next;
- if (masklay_shape_next && masklay_shape->frame == masklay_shape_next->frame) {
- BKE_mask_layer_shape_unlink(masklay, masklay_shape);
- }
- }
- }
-
-#ifdef DEBUG
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
- masklay_shape = masklay_shape->next) {
- BLI_assert(!masklay_shape->next || masklay_shape->frame < masklay_shape->next->frame);
- }
-#endif
- }
-}
-
-/* Time + Average value */
-typedef struct tRetainedKeyframe {
- struct tRetainedKeyframe *next, *prev;
- float frame; /* frame to cluster around */
- float val; /* average value */
-
- size_t tot_count; /* number of keyframes that have been averaged */
- size_t del_count; /* number of keyframes of this sort that have been deleted so far */
-} tRetainedKeyframe;
-
-/* Called during special_aftertrans_update to make sure selected keyframes replace
- * any other keyframes which may reside on that frame (that is not selected).
- */
-static void posttrans_fcurve_clean(FCurve *fcu, const bool use_handle)
-{
- /* NOTE: We assume that all keys are sorted */
- ListBase retained_keys = {NULL, NULL};
- const bool can_average_points = ((fcu->flag & (FCURVE_INT_VALUES | FCURVE_DISCRETE_VALUES)) ==
- 0);
-
- /* sanity checks */
- if ((fcu->totvert == 0) || (fcu->bezt == NULL)) {
- return;
- }
-
- /* 1) Identify selected keyframes, and average the values on those
- * in case there are collisions due to multiple keys getting scaled
- * to all end up on the same frame
- */
- for (int i = 0; i < fcu->totvert; i++) {
- BezTriple *bezt = &fcu->bezt[i];
-
- if (BEZT_ISSEL_ANY(bezt)) {
- bool found = false;
-
- /* If there's another selected frame here, merge it */
- for (tRetainedKeyframe *rk = retained_keys.last; rk; rk = rk->prev) {
- if (IS_EQT(rk->frame, bezt->vec[1][0], BEZT_BINARYSEARCH_THRESH)) {
- rk->val += bezt->vec[1][1];
- rk->tot_count++;
-
- found = true;
- break;
- }
- else if (rk->frame < bezt->vec[1][0]) {
- /* Terminate early if have passed the supposed insertion point? */
- break;
- }
- }
-
- /* If nothing found yet, create a new one */
- if (found == false) {
- tRetainedKeyframe *rk = MEM_callocN(sizeof(tRetainedKeyframe), "tRetainedKeyframe");
-
- rk->frame = bezt->vec[1][0];
- rk->val = bezt->vec[1][1];
- rk->tot_count = 1;
-
- BLI_addtail(&retained_keys, rk);
- }
- }
- }
-
- if (BLI_listbase_is_empty(&retained_keys)) {
- /* This may happen if none of the points were selected... */
- if (G.debug & G_DEBUG) {
- printf("%s: nothing to do for FCurve %p (rna_path = '%s')\n", __func__, fcu, fcu->rna_path);
- }
- return;
- }
- else {
- /* Compute the average values for each retained keyframe */
- for (tRetainedKeyframe *rk = retained_keys.first; rk; rk = rk->next) {
- rk->val = rk->val / (float)rk->tot_count;
- }
- }
-
- /* 2) Delete all keyframes duplicating the "retained keys" found above
- * - Most of these will be unselected keyframes
- * - Some will be selected keyframes though. For those, we only keep the last one
- * (or else everything is gone), and replace its value with the averaged value.
- */
- for (int i = fcu->totvert - 1; i >= 0; i--) {
- BezTriple *bezt = &fcu->bezt[i];
-
- /* Is this keyframe a candidate for deletion? */
- /* TODO: Replace loop with an O(1) lookup instead */
- for (tRetainedKeyframe *rk = retained_keys.last; rk; rk = rk->prev) {
- if (IS_EQT(bezt->vec[1][0], rk->frame, BEZT_BINARYSEARCH_THRESH)) {
- /* Selected keys are treated with greater care than unselected ones... */
- if (BEZT_ISSEL_ANY(bezt)) {
- /* - If this is the last selected key left (based on rk->del_count) ==> UPDATE IT
- * (or else we wouldn't have any keyframe left here)
- * - Otherwise, there are still other selected keyframes on this frame
- * to be merged down still ==> DELETE IT
- */
- if (rk->del_count == rk->tot_count - 1) {
- /* Update keyframe... */
- if (can_average_points) {
- /* TODO: update handles too? */
- bezt->vec[1][1] = rk->val;
- }
- }
- else {
- /* Delete Keyframe */
- delete_fcurve_key(fcu, i, 0);
- }
-
- /* Update count of how many we've deleted
- * - It should only matter that we're doing this for all but the last one
- */
- rk->del_count++;
- }
- else {
- /* Always delete - Unselected keys don't matter */
- delete_fcurve_key(fcu, i, 0);
- }
-
- /* Stop the RK search... we've found our match now */
- break;
- }
- }
- }
-
- /* 3) Recalculate handles */
- testhandles_fcurve(fcu, use_handle);
-
- /* cleanup */
- BLI_freelistN(&retained_keys);
-}
-
-/* Called by special_aftertrans_update to make sure selected keyframes replace
- * any other keyframes which may reside on that frame (that is not selected).
- * remake_action_ipos should have already been called
- */
-static void posttrans_action_clean(bAnimContext *ac, bAction *act)
-{
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
-
- /* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
- ANIM_animdata_filter(ac, &anim_data, filter, act, ANIMCONT_ACTION);
-
- /* loop through relevant data, removing keyframes as appropriate
- * - all keyframes are converted in/out of global time
- */
- for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(ac, ale);
-
- if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
- posttrans_fcurve_clean(ale->key_data, false); /* only use handles in graph editor */
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
- }
- else {
- posttrans_fcurve_clean(ale->key_data, false); /* only use handles in graph editor */
- }
- }
-
- /* free temp data */
- ANIM_animdata_freelist(&anim_data);
-}
-
-/* ----------------------------- */
-
-/* fully select selected beztriples, but only include if it's on the right side of cfra */
-static int count_fcurve_keys(FCurve *fcu, char side, float cfra, bool is_prop_edit)
-{
- BezTriple *bezt;
- int i, count = 0, count_all = 0;
-
- if (ELEM(NULL, fcu, fcu->bezt)) {
- return count;
- }
-
- /* only include points that occur on the right side of cfra */
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
- /* no need to adjust the handle selection since they are assumed
- * selected (like graph editor with SIPO_NOHANDLES) */
- if (bezt->f2 & SELECT) {
- count++;
- }
-
- count_all++;
- }
- }
-
- if (is_prop_edit && count > 0) {
- return count_all;
- }
- else {
- return count;
- }
-}
-
-/* fully select selected beztriples, but only include if it's on the right side of cfra */
-static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra, bool is_prop_edit)
-{
- bGPDframe *gpf;
- int count = 0, count_all = 0;
-
- if (gpl == NULL) {
- return count;
- }
-
- /* only include points that occur on the right side of cfra */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) {
- if (gpf->flag & GP_FRAME_SELECT) {
- count++;
- }
- count_all++;
- }
- }
-
- if (is_prop_edit && count > 0) {
- return count_all;
- }
- else {
- return count;
- }
-}
-
-/* fully select selected beztriples, but only include if it's on the right side of cfra */
-static int count_masklayer_frames(MaskLayer *masklay, char side, float cfra, bool is_prop_edit)
-{
- MaskLayerShape *masklayer_shape;
- int count = 0, count_all = 0;
-
- if (masklay == NULL) {
- return count;
- }
-
- /* only include points that occur on the right side of cfra */
- for (masklayer_shape = masklay->splines_shapes.first; masklayer_shape;
- masklayer_shape = masklayer_shape->next) {
- if (FrameOnMouseSide(side, (float)masklayer_shape->frame, cfra)) {
- if (masklayer_shape->flag & MASK_SHAPE_SELECT) {
- count++;
- }
- count_all++;
- }
- }
-
- if (is_prop_edit && count > 0) {
- return count_all;
- }
- else {
- return count;
- }
-}
-
-/* This function assigns the information to transdata */
-static void TimeToTransData(TransData *td, float *time, AnimData *adt, float ypos)
-{
- /* memory is calloc'ed, so that should zero everything nicely for us */
- td->val = time;
- td->ival = *(time);
-
- td->center[0] = td->ival;
- td->center[1] = ypos;
-
- /* store the AnimData where this keyframe exists as a keyframe of the
- * active action as td->extra.
- */
- td->extra = adt;
-}
-
-/* This function advances the address to which td points to, so it must return
- * the new address so that the next time new transform data is added, it doesn't
- * overwrite the existing ones... i.e. td = IcuToTransData(td, icu, ob, side, cfra);
- *
- * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
- * on the named side are used.
- */
-static TransData *ActionFCurveToTransData(TransData *td,
- TransData2D **td2dv,
- FCurve *fcu,
- AnimData *adt,
- char side,
- float cfra,
- bool is_prop_edit,
- float ypos)
-{
- BezTriple *bezt;
- TransData2D *td2d = *td2dv;
- int i;
-
- if (ELEM(NULL, fcu, fcu->bezt)) {
- return td;
- }
-
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- /* only add selected keyframes (for now, proportional edit is not enabled) */
- if (is_prop_edit || (bezt->f2 & SELECT)) { /* note this MUST match count_fcurve_keys(),
- * so can't use BEZT_ISSEL_ANY() macro */
- /* only add if on the right 'side' of the current frame */
- if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
- TimeToTransData(td, bezt->vec[1], adt, ypos);
-
- if (bezt->f2 & SELECT) {
- td->flag |= TD_SELECTED;
- }
-
- /*set flags to move handles as necessary*/
- td->flag |= TD_MOVEHANDLE1 | TD_MOVEHANDLE2;
- td2d->h1 = bezt->vec[0];
- td2d->h2 = bezt->vec[2];
-
- copy_v2_v2(td2d->ih1, td2d->h1);
- copy_v2_v2(td2d->ih2, td2d->h2);
-
- td++;
- td2d++;
- }
- }
- }
-
- *td2dv = td2d;
-
- return td;
-}
-
-/* helper struct for gp-frame transforms (only used here) */
-typedef struct tGPFtransdata {
- float val; /* where transdata writes transform */
- int *sdata; /* pointer to gpf->framenum */
-} tGPFtransdata;
-
-/* This function helps flush transdata written to tempdata into the gp-frames */
-void flushTransIntFrameActionData(TransInfo *t)
-{
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
- tGPFtransdata *tfd = tc->custom.type.data;
-
- /* flush data! */
- for (int i = 0; i < tc->data_len; i++, tfd++) {
- *(tfd->sdata) = round_fl_to_int(tfd->val);
- }
-}
-
-/* This function advances the address to which td points to, so it must return
- * the new address so that the next time new transform data is added, it doesn't
- * overwrite the existing ones... i.e. td = GPLayerToTransData(td, ipo, ob, side, cfra);
- *
- * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
- * on the named side are used.
- */
-static int GPLayerToTransData(TransData *td,
- tGPFtransdata *tfd,
- bGPDlayer *gpl,
- char side,
- float cfra,
- bool is_prop_edit,
- float ypos)
-{
- bGPDframe *gpf;
- int count = 0;
-
- /* check for select frames on right side of current frame */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if (is_prop_edit || (gpf->flag & GP_FRAME_SELECT)) {
- if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) {
- /* memory is calloc'ed, so that should zero everything nicely for us */
- td->val = &tfd->val;
- td->ival = (float)gpf->framenum;
-
- td->center[0] = td->ival;
- td->center[1] = ypos;
-
- tfd->val = (float)gpf->framenum;
- tfd->sdata = &gpf->framenum;
-
- /* advance td now */
- td++;
- tfd++;
- count++;
- }
- }
- }
-
- return count;
-}
-
-/* refer to comment above #GPLayerToTransData, this is the same but for masks */
-static int MaskLayerToTransData(TransData *td,
- tGPFtransdata *tfd,
- MaskLayer *masklay,
- char side,
- float cfra,
- bool is_prop_edit,
- float ypos)
-{
- MaskLayerShape *masklay_shape;
- int count = 0;
-
- /* check for select frames on right side of current frame */
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
- masklay_shape = masklay_shape->next) {
- if (is_prop_edit || (masklay_shape->flag & MASK_SHAPE_SELECT)) {
- if (FrameOnMouseSide(side, (float)masklay_shape->frame, cfra)) {
- /* memory is calloc'ed, so that should zero everything nicely for us */
- td->val = &tfd->val;
- td->ival = (float)masklay_shape->frame;
-
- td->center[0] = td->ival;
- td->center[1] = ypos;
-
- tfd->val = (float)masklay_shape->frame;
- tfd->sdata = &masklay_shape->frame;
-
- /* advance td now */
- td++;
- tfd++;
- count++;
- }
- }
- }
-
- return count;
-}
-
-static void createTransActionData(bContext *C, TransInfo *t)
-{
- Scene *scene = t->scene;
- TransData *td = NULL;
- TransData2D *td2d = NULL;
- tGPFtransdata *tfd = NULL;
-
- rcti *mask = &t->ar->v2d.mask;
- rctf *datamask = &t->ar->v2d.cur;
-
- float xsize = BLI_rctf_size_x(datamask);
- float ysize = BLI_rctf_size_y(datamask);
- float xmask = BLI_rcti_size_x(mask);
- float ymask = BLI_rcti_size_y(mask);
-
- bAnimContext ac;
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
-
- int count = 0;
- float cfra;
- float ypos = 1.0f / ((ysize / xsize) * (xmask / ymask)) * BLI_rctf_cent_y(&t->ar->v2d.cur);
-
- /* determine what type of data we are operating on */
- if (ANIM_animdata_get_context(C, &ac) == 0) {
- return;
- }
-
- /* filter data */
- if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT);
- }
- else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
- }
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- /* which side of the current frame should be allowed */
- if (t->mode == TFM_TIME_EXTEND) {
- /* only side on which mouse is gets transformed */
- float xmouse, ymouse;
-
- UI_view2d_region_to_view(&ac.ar->v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse);
- t->frame_side = (xmouse > CFRA) ? 'R' : 'L'; // XXX use t->frame_side
- }
- else {
- /* normal transform - both sides of current frame are considered */
- t->frame_side = 'B';
- }
-
- /* loop 1: fully select ipo-keys and count how many BezTriples are selected */
- for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
- int adt_count = 0;
- /* convert current-frame to action-time (slightly less accurate, especially under
- * higher scaling ratios, but is faster than converting all points)
- */
- if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
- }
- else {
- cfra = (float)CFRA;
- }
-
- if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
- adt_count = count_fcurve_keys(ale->key_data, t->frame_side, cfra, is_prop_edit);
- }
- else if (ale->type == ANIMTYPE_GPLAYER) {
- adt_count = count_gplayer_frames(ale->data, t->frame_side, cfra, is_prop_edit);
- }
- else if (ale->type == ANIMTYPE_MASKLAYER) {
- adt_count = count_masklayer_frames(ale->data, t->frame_side, cfra, is_prop_edit);
- }
- else {
- BLI_assert(0);
- }
-
- if (adt_count > 0) {
- count += adt_count;
- ale->tag = true;
- }
- }
-
- /* stop if trying to build list if nothing selected */
- if (count == 0) {
- /* cleanup temp list */
- ANIM_animdata_freelist(&anim_data);
- return;
- }
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* allocate memory for data */
- tc->data_len = count;
-
- tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(Action Editor)");
- tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "transdata2d");
- td = tc->data;
- td2d = tc->data_2d;
-
- if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- tc->custom.type.data = tfd = MEM_callocN(sizeof(tGPFtransdata) * count, "tGPFtransdata");
- tc->custom.type.use_free = true;
- }
-
- /* loop 2: build transdata array */
- for (ale = anim_data.first; ale; ale = ale->next) {
-
- if (is_prop_edit && !ale->tag) {
- continue;
- }
-
- cfra = (float)CFRA;
-
- {
- AnimData *adt;
- adt = ANIM_nla_mapping_get(&ac, ale);
- if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
- }
- }
-
- if (ale->type == ANIMTYPE_GPLAYER) {
- bGPDlayer *gpl = (bGPDlayer *)ale->data;
- int i;
-
- i = GPLayerToTransData(td, tfd, gpl, t->frame_side, cfra, is_prop_edit, ypos);
- td += i;
- tfd += i;
- }
- else if (ale->type == ANIMTYPE_MASKLAYER) {
- MaskLayer *masklay = (MaskLayer *)ale->data;
- int i;
-
- i = MaskLayerToTransData(td, tfd, masklay, t->frame_side, cfra, is_prop_edit, ypos);
- td += i;
- tfd += i;
- }
- else {
- AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
- FCurve *fcu = (FCurve *)ale->key_data;
-
- td = ActionFCurveToTransData(td, &td2d, fcu, adt, t->frame_side, cfra, is_prop_edit, ypos);
- }
- }
-
- /* calculate distances for proportional editing */
- if (is_prop_edit) {
- td = tc->data;
-
- for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt;
-
- /* F-Curve may not have any keyframes */
- if (!ale->tag) {
- continue;
- }
-
- adt = ANIM_nla_mapping_get(&ac, ale);
- if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
- }
- else {
- cfra = (float)CFRA;
- }
-
- if (ale->type == ANIMTYPE_GPLAYER) {
- bGPDlayer *gpl = (bGPDlayer *)ale->data;
- bGPDframe *gpf;
-
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if (gpf->flag & GP_FRAME_SELECT) {
- td->dist = td->rdist = 0.0f;
- }
- else {
- bGPDframe *gpf_iter;
- int min = INT_MAX;
- for (gpf_iter = gpl->frames.first; gpf_iter; gpf_iter = gpf_iter->next) {
- if (gpf_iter->flag & GP_FRAME_SELECT) {
- if (FrameOnMouseSide(t->frame_side, (float)gpf_iter->framenum, cfra)) {
- int val = abs(gpf->framenum - gpf_iter->framenum);
- if (val < min) {
- min = val;
- }
- }
- }
- }
- td->dist = td->rdist = min;
- }
- td++;
- }
- }
- else if (ale->type == ANIMTYPE_MASKLAYER) {
- MaskLayer *masklay = (MaskLayer *)ale->data;
- MaskLayerShape *masklay_shape;
-
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
- masklay_shape = masklay_shape->next) {
- if (FrameOnMouseSide(t->frame_side, (float)masklay_shape->frame, cfra)) {
- if (masklay_shape->flag & MASK_SHAPE_SELECT) {
- td->dist = td->rdist = 0.0f;
- }
- else {
- MaskLayerShape *masklay_iter;
- int min = INT_MAX;
- for (masklay_iter = masklay->splines_shapes.first; masklay_iter;
- masklay_iter = masklay_iter->next) {
- if (masklay_iter->flag & MASK_SHAPE_SELECT) {
- if (FrameOnMouseSide(t->frame_side, (float)masklay_iter->frame, cfra)) {
- int val = abs(masklay_shape->frame - masklay_iter->frame);
- if (val < min) {
- min = val;
- }
- }
- }
- }
- td->dist = td->rdist = min;
- }
- td++;
- }
- }
- }
- else {
- FCurve *fcu = (FCurve *)ale->key_data;
- BezTriple *bezt;
- int i;
-
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
- if (bezt->f2 & SELECT) {
- td->dist = td->rdist = 0.0f;
- }
- else {
- BezTriple *bezt_iter;
- int j;
- float min = FLT_MAX;
- for (j = 0, bezt_iter = fcu->bezt; j < fcu->totvert; j++, bezt_iter++) {
- if (bezt_iter->f2 & SELECT) {
- if (FrameOnMouseSide(t->frame_side, (float)bezt_iter->vec[1][0], cfra)) {
- float val = fabs(bezt->vec[1][0] - bezt_iter->vec[1][0]);
- if (val < min) {
- min = val;
- }
- }
- }
- }
- td->dist = td->rdist = min;
- }
- td++;
- }
- }
- }
- }
- }
-
- /* cleanup temp list */
- ANIM_animdata_freelist(&anim_data);
-}
-
-/* ********************* GRAPH EDITOR ************************* */
-
-typedef struct TransDataGraph {
- float unit_scale;
- float offset;
-} TransDataGraph;
-
-/* Helper function for createTransGraphEditData, which is responsible for associating
- * source data with transform data
- */
-static void bezt_to_transdata(TransData *td,
- TransData2D *td2d,
- TransDataGraph *tdg,
- AnimData *adt,
- BezTriple *bezt,
- int bi,
- bool selected,
- bool ishandle,
- bool intvals,
- float mtx[3][3],
- float smtx[3][3],
- float unit_scale,
- float offset)
-{
- float *loc = bezt->vec[bi];
- const float *cent = bezt->vec[1];
-
- /* New location from td gets dumped onto the old-location of td2d, which then
- * gets copied to the actual data at td2d->loc2d (bezt->vec[n])
- *
- * Due to NLA mapping, we apply NLA mapping to some of the verts here,
- * and then that mapping will be undone after transform is done.
- */
-
- if (adt) {
- td2d->loc[0] = BKE_nla_tweakedit_remap(adt, loc[0], NLATIME_CONVERT_MAP);
- td2d->loc[1] = (loc[1] + offset) * unit_scale;
- td2d->loc[2] = 0.0f;
- td2d->loc2d = loc;
-
- td->loc = td2d->loc;
- td->center[0] = BKE_nla_tweakedit_remap(adt, cent[0], NLATIME_CONVERT_MAP);
- td->center[1] = (cent[1] + offset) * unit_scale;
- td->center[2] = 0.0f;
-
- copy_v3_v3(td->iloc, td->loc);
- }
- else {
- td2d->loc[0] = loc[0];
- td2d->loc[1] = (loc[1] + offset) * unit_scale;
- td2d->loc[2] = 0.0f;
- td2d->loc2d = loc;
-
- td->loc = td2d->loc;
- copy_v3_v3(td->center, cent);
- td->center[1] = (td->center[1] + offset) * unit_scale;
- copy_v3_v3(td->iloc, td->loc);
- }
-
- if (!ishandle) {
- td2d->h1 = bezt->vec[0];
- td2d->h2 = bezt->vec[2];
- copy_v2_v2(td2d->ih1, td2d->h1);
- copy_v2_v2(td2d->ih2, td2d->h2);
- }
- else {
- td2d->h1 = NULL;
- td2d->h2 = NULL;
- }
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
-
- /* store AnimData info in td->extra, for applying mapping when flushing */
- td->extra = adt;
-
- if (selected) {
- td->flag |= TD_SELECTED;
- td->dist = 0.0f;
- }
- else {
- td->dist = FLT_MAX;
- }
-
- if (ishandle) {
- td->flag |= TD_NOTIMESNAP;
- }
- if (intvals) {
- td->flag |= TD_INTVALUES;
- }
-
- /* copy space-conversion matrices for dealing with non-uniform scales */
- copy_m3_m3(td->mtx, mtx);
- copy_m3_m3(td->smtx, smtx);
-
- tdg->unit_scale = unit_scale;
- tdg->offset = offset;
-}
-
-static bool graph_edit_is_translation_mode(TransInfo *t)
-{
- return ELEM(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE, TFM_TIME_DUPLICATE);
-}
-
-static bool graph_edit_use_local_center(TransInfo *t)
-{
- return ((t->around == V3D_AROUND_LOCAL_ORIGINS) && (graph_edit_is_translation_mode(t) == false));
-}
-
-static void graph_key_shortest_dist(
- TransInfo *t, FCurve *fcu, TransData *td_start, TransData *td, int cfra, bool use_handle)
-{
- int j = 0;
- TransData *td_iter = td_start;
-
- td->dist = FLT_MAX;
- for (; j < fcu->totvert; j++) {
- BezTriple *bezt = fcu->bezt + j;
- if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
- const bool sel2 = (bezt->f2 & SELECT) != 0;
- const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
- const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
-
- if (sel1 || sel2 || sel3) {
- td->dist = td->rdist = min_ff(td->dist, fabs(td_iter->center[0] - td->center[0]));
- }
-
- td_iter += 3;
- }
- }
-}
-
-static void createTransGraphEditData(bContext *C, TransInfo *t)
-{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
- Scene *scene = t->scene;
- ARegion *ar = t->ar;
- View2D *v2d = &ar->v2d;
-
- TransData *td = NULL;
- TransData2D *td2d = NULL;
- TransDataGraph *tdg = NULL;
-
- bAnimContext ac;
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
-
- BezTriple *bezt;
- int count = 0, i;
- float mtx[3][3], smtx[3][3];
- const bool is_translation_mode = graph_edit_is_translation_mode(t);
- const bool use_handle = !(sipo->flag & SIPO_NOHANDLES);
- const bool use_local_center = graph_edit_use_local_center(t);
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
- short anim_map_flag = ANIM_UNITCONV_ONLYSEL | ANIM_UNITCONV_SELVERTS;
-
- /* determine what type of data we are operating on */
- if (ANIM_animdata_get_context(C, &ac) == 0) {
- return;
- }
-
- anim_map_flag |= ANIM_get_normalization_flags(&ac);
-
- /* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- /* which side of the current frame should be allowed */
- // XXX we still want this mode, but how to get this using standard transform too?
- if (t->mode == TFM_TIME_EXTEND) {
- /* only side on which mouse is gets transformed */
- float xmouse, ymouse;
-
- UI_view2d_region_to_view(v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse);
- t->frame_side = (xmouse > CFRA) ? 'R' : 'L'; // XXX use t->frame_side
- }
- else {
- /* normal transform - both sides of current frame are considered */
- t->frame_side = 'B';
- }
-
- /* Loop 1: count how many BezTriples (specifically their verts)
- * are selected (or should be edited). */
- for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
- FCurve *fcu = (FCurve *)ale->key_data;
- float cfra;
- int curvecount = 0;
- bool selected = false;
-
- /* F-Curve may not have any keyframes */
- if (fcu->bezt == NULL) {
- continue;
- }
-
- /* convert current-frame to action-time (slightly less accurate, especially under
- * higher scaling ratios, but is faster than converting all points)
- */
- if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
- }
- else {
- cfra = (float)CFRA;
- }
-
- /* Only include BezTriples whose 'keyframe'
- * occurs on the same side of the current frame as mouse. */
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
- const bool sel2 = (bezt->f2 & SELECT) != 0;
- const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
- const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
-
- if (is_prop_edit) {
- curvecount += 3;
- if (sel2 || sel1 || sel3) {
- selected = true;
- }
- }
- else {
- if (!is_translation_mode || !(sel2)) {
- if (sel1) {
- count++;
- }
-
- if (sel3) {
- count++;
- }
- }
-
- /* only include main vert if selected */
- if (sel2 && !use_local_center) {
- count++;
- }
- }
- }
- }
-
- if (is_prop_edit) {
- if (selected) {
- count += curvecount;
- ale->tag = true;
- }
- }
- }
-
- /* stop if trying to build list if nothing selected */
- if (count == 0) {
- /* cleanup temp list */
- ANIM_animdata_freelist(&anim_data);
- return;
- }
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* allocate memory for data */
- tc->data_len = count;
-
- tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData (Graph Editor)");
- /* For each 2d vert a 3d vector is allocated,
- * so that they can be treated just as if they were 3d verts. */
- tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransData2D (Graph Editor)");
- tc->custom.type.data = MEM_callocN(tc->data_len * sizeof(TransDataGraph), "TransDataGraph");
- tc->custom.type.use_free = true;
-
- td = tc->data;
- td2d = tc->data_2d;
- tdg = tc->custom.type.data;
-
- /* precompute space-conversion matrices for dealing with non-uniform scaling of Graph Editor */
- unit_m3(mtx);
- unit_m3(smtx);
-
- if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) {
- float xscale, yscale;
-
- /* apply scale factors to x and y axes of space-conversion matrices */
- UI_view2d_scale_get(v2d, &xscale, &yscale);
-
- /* mtx is data to global (i.e. view) conversion */
- mul_v3_fl(mtx[0], xscale);
- mul_v3_fl(mtx[1], yscale);
-
- /* smtx is global (i.e. view) to data conversion */
- if (IS_EQF(xscale, 0.0f) == 0) {
- mul_v3_fl(smtx[0], 1.0f / xscale);
- }
- if (IS_EQF(yscale, 0.0f) == 0) {
- mul_v3_fl(smtx[1], 1.0f / yscale);
- }
- }
-
- /* loop 2: build transdata arrays */
- for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
- FCurve *fcu = (FCurve *)ale->key_data;
- bool intvals = (fcu->flag & FCURVE_INT_VALUES) != 0;
- float unit_scale, offset;
- float cfra;
-
- /* F-Curve may not have any keyframes */
- if (fcu->bezt == NULL || (is_prop_edit && ale->tag == 0)) {
- continue;
- }
-
- /* convert current-frame to action-time (slightly less accurate, especially under
- * higher scaling ratios, but is faster than converting all points)
- */
- if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
- }
- else {
- cfra = (float)CFRA;
- }
-
- unit_scale = ANIM_unit_mapping_get_factor(
- ac.scene, ale->id, ale->key_data, anim_map_flag, &offset);
-
- /* only include BezTriples whose 'keyframe' occurs on the same side
- * of the current frame as mouse (if applicable) */
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
- const bool sel2 = (bezt->f2 & SELECT) != 0;
- const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
- const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
-
- TransDataCurveHandleFlags *hdata = NULL;
- /* short h1=1, h2=1; */ /* UNUSED */
-
- if (is_prop_edit) {
- bool is_sel = (sel2 || sel1 || sel3);
- /* we always select all handles for proportional editing if central handle is selected */
- initTransDataCurveHandles(td, bezt);
- bezt_to_transdata(td++,
- td2d++,
- tdg++,
- adt,
- bezt,
- 0,
- is_sel,
- true,
- intvals,
- mtx,
- smtx,
- unit_scale,
- offset);
- initTransDataCurveHandles(td, bezt);
- bezt_to_transdata(td++,
- td2d++,
- tdg++,
- adt,
- bezt,
- 1,
- is_sel,
- false,
- intvals,
- mtx,
- smtx,
- unit_scale,
- offset);
- initTransDataCurveHandles(td, bezt);
- bezt_to_transdata(td++,
- td2d++,
- tdg++,
- adt,
- bezt,
- 2,
- is_sel,
- true,
- intvals,
- mtx,
- smtx,
- unit_scale,
- offset);
- }
- else {
- /* only include handles if selected, irrespective of the interpolation modes.
- * also, only treat handles specially if the center point isn't selected.
- */
- if (!is_translation_mode || !(sel2)) {
- if (sel1) {
- hdata = initTransDataCurveHandles(td, bezt);
- bezt_to_transdata(td++,
- td2d++,
- tdg++,
- adt,
- bezt,
- 0,
- sel1,
- true,
- intvals,
- mtx,
- smtx,
- unit_scale,
- offset);
- }
- else {
- /* h1 = 0; */ /* UNUSED */
- }
-
- if (sel3) {
- if (hdata == NULL) {
- hdata = initTransDataCurveHandles(td, bezt);
- }
- bezt_to_transdata(td++,
- td2d++,
- tdg++,
- adt,
- bezt,
- 2,
- sel3,
- true,
- intvals,
- mtx,
- smtx,
- unit_scale,
- offset);
- }
- else {
- /* h2 = 0; */ /* UNUSED */
- }
- }
-
- /* only include main vert if selected */
- if (sel2 && !use_local_center) {
- /* move handles relative to center */
- if (is_translation_mode) {
- if (sel1) {
- td->flag |= TD_MOVEHANDLE1;
- }
- if (sel3) {
- td->flag |= TD_MOVEHANDLE2;
- }
- }
-
- /* if handles were not selected, store their selection status */
- if (!(sel1) || !(sel3)) {
- if (hdata == NULL) {
- hdata = initTransDataCurveHandles(td, bezt);
- }
- }
-
- bezt_to_transdata(td++,
- td2d++,
- tdg++,
- adt,
- bezt,
- 1,
- sel2,
- false,
- intvals,
- mtx,
- smtx,
- unit_scale,
- offset);
- }
- /* Special hack (must be done after #initTransDataCurveHandles(),
- * as that stores handle settings to restore...):
- *
- * - Check if we've got entire BezTriple selected and we're scaling/rotating that point,
- * then check if we're using auto-handles.
- * - If so, change them auto-handles to aligned handles so that handles get affected too
- */
- if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) && ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM) &&
- ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) {
- if (hdata && (sel1) && (sel3)) {
- bezt->h1 = HD_ALIGN;
- bezt->h2 = HD_ALIGN;
- }
- }
- }
- }
- }
-
- /* Sets handles based on the selection */
- testhandles_fcurve(fcu, use_handle);
- }
-
- if (is_prop_edit) {
- /* loop 2: build transdata arrays */
- td = tc->data;
-
- for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
- FCurve *fcu = (FCurve *)ale->key_data;
- TransData *td_start = td;
- float cfra;
-
- /* F-Curve may not have any keyframes */
- if (fcu->bezt == NULL || (ale->tag == 0)) {
- continue;
- }
-
- /* convert current-frame to action-time (slightly less accurate, especially under
- * higher scaling ratios, but is faster than converting all points)
- */
- if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
- }
- else {
- cfra = (float)CFRA;
- }
-
- /* only include BezTriples whose 'keyframe' occurs on the
- * same side of the current frame as mouse (if applicable) */
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
- const bool sel2 = (bezt->f2 & SELECT) != 0;
- const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
- const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
-
- if (sel1 || sel2) {
- td->dist = td->rdist = 0.0f;
- }
- else {
- graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
- }
- td++;
-
- if (sel2) {
- td->dist = td->rdist = 0.0f;
- }
- else {
- graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
- }
- td++;
-
- if (sel3 || sel2) {
- td->dist = td->rdist = 0.0f;
- }
- else {
- graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
- }
- td++;
- }
- }
- }
- }
-
- /* cleanup temp list */
- ANIM_animdata_freelist(&anim_data);
-}
-
-/* ------------------------ */
-
-/* struct for use in re-sorting BezTriples during Graph Editor transform */
-typedef struct BeztMap {
- BezTriple *bezt;
- unsigned int oldIndex; /* index of bezt in fcu->bezt array before sorting */
- unsigned int newIndex; /* index of bezt in fcu->bezt array after sorting */
- short swapHs; /* swap order of handles (-1=clear; 0=not checked, 1=swap) */
- char pipo, cipo; /* interpolation of current and next segments */
-} BeztMap;
-
-/* This function converts an FCurve's BezTriple array to a BeztMap array
- * NOTE: this allocates memory that will need to get freed later
- */
-static BeztMap *bezt_to_beztmaps(BezTriple *bezts, int totvert, const short UNUSED(use_handle))
-{
- BezTriple *bezt = bezts;
- BezTriple *prevbezt = NULL;
- BeztMap *bezm, *bezms;
- int i;
-
- /* allocate memory for this array */
- if (totvert == 0 || bezts == NULL) {
- return NULL;
- }
- bezm = bezms = MEM_callocN(sizeof(BeztMap) * totvert, "BeztMaps");
-
- /* assign beztriples to beztmaps */
- for (i = 0; i < totvert; i++, bezm++, prevbezt = bezt, bezt++) {
- bezm->bezt = bezt;
-
- bezm->oldIndex = i;
- bezm->newIndex = i;
-
- bezm->pipo = (prevbezt) ? prevbezt->ipo : bezt->ipo;
- bezm->cipo = bezt->ipo;
- }
-
- return bezms;
-}
-
-/* This function copies the code of sort_time_ipocurve, but acts on BeztMap structs instead */
-static void sort_time_beztmaps(BeztMap *bezms, int totvert, const short UNUSED(use_handle))
-{
- BeztMap *bezm;
- int i, ok = 1;
-
- /* keep repeating the process until nothing is out of place anymore */
- while (ok) {
- ok = 0;
-
- bezm = bezms;
- i = totvert;
- while (i--) {
- /* is current bezm out of order (i.e. occurs later than next)? */
- if (i > 0) {
- if (bezm->bezt->vec[1][0] > (bezm + 1)->bezt->vec[1][0]) {
- bezm->newIndex++;
- (bezm + 1)->newIndex--;
-
- SWAP(BeztMap, *bezm, *(bezm + 1));
-
- ok = 1;
- }
- }
-
- /* do we need to check if the handles need to be swapped?
- * optimization: this only needs to be performed in the first loop
- */
- if (bezm->swapHs == 0) {
- if ((bezm->bezt->vec[0][0] > bezm->bezt->vec[1][0]) &&
- (bezm->bezt->vec[2][0] < bezm->bezt->vec[1][0])) {
- /* handles need to be swapped */
- bezm->swapHs = 1;
- }
- else {
- /* handles need to be cleared */
- bezm->swapHs = -1;
- }
- }
-
- bezm++;
- }
- }
-}
-
-/* This function firstly adjusts the pointers that the transdata has to each BezTriple */
-static void beztmap_to_data(
- TransInfo *t, FCurve *fcu, BeztMap *bezms, int totvert, const short UNUSED(use_handle))
-{
- BezTriple *bezts = fcu->bezt;
- BeztMap *bezm;
- TransData2D *td2d;
- TransData *td;
- int i, j;
- char *adjusted;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* dynamically allocate an array of chars to mark whether an TransData's
- * pointers have been fixed already, so that we don't override ones that are
- * already done
- */
- adjusted = MEM_callocN(tc->data_len, "beztmap_adjusted_map");
-
- /* for each beztmap item, find if it is used anywhere */
- bezm = bezms;
- for (i = 0; i < totvert; i++, bezm++) {
- /* loop through transdata, testing if we have a hit
- * for the handles (vec[0]/vec[2]), we must also check if they need to be swapped...
- */
- td2d = tc->data_2d;
- td = tc->data;
- for (j = 0; j < tc->data_len; j++, td2d++, td++) {
- /* skip item if already marked */
- if (adjusted[j] != 0) {
- continue;
- }
-
- /* update all transdata pointers, no need to check for selections etc,
- * since only points that are really needed were created as transdata
- */
- if (td2d->loc2d == bezm->bezt->vec[0]) {
- if (bezm->swapHs == 1) {
- td2d->loc2d = (bezts + bezm->newIndex)->vec[2];
- }
- else {
- td2d->loc2d = (bezts + bezm->newIndex)->vec[0];
- }
- adjusted[j] = 1;
- }
- else if (td2d->loc2d == bezm->bezt->vec[2]) {
- if (bezm->swapHs == 1) {
- td2d->loc2d = (bezts + bezm->newIndex)->vec[0];
- }
- else {
- td2d->loc2d = (bezts + bezm->newIndex)->vec[2];
- }
- adjusted[j] = 1;
- }
- else if (td2d->loc2d == bezm->bezt->vec[1]) {
- td2d->loc2d = (bezts + bezm->newIndex)->vec[1];
-
- /* if only control point is selected, the handle pointers need to be updated as well */
- if (td2d->h1) {
- td2d->h1 = (bezts + bezm->newIndex)->vec[0];
- }
- if (td2d->h2) {
- td2d->h2 = (bezts + bezm->newIndex)->vec[2];
- }
-
- adjusted[j] = 1;
- }
-
- /* the handle type pointer has to be updated too */
- if (adjusted[j] && td->flag & TD_BEZTRIPLE && td->hdata) {
- if (bezm->swapHs == 1) {
- td->hdata->h1 = &(bezts + bezm->newIndex)->h2;
- td->hdata->h2 = &(bezts + bezm->newIndex)->h1;
- }
- else {
- td->hdata->h1 = &(bezts + bezm->newIndex)->h1;
- td->hdata->h2 = &(bezts + bezm->newIndex)->h2;
- }
- }
- }
- }
-
- /* free temp memory used for 'adjusted' array */
- MEM_freeN(adjusted);
-}
-
-/* This function is called by recalcData during the Transform loop to recalculate
- * the handles of curves and sort the keyframes so that the curves draw correctly.
- * It is only called if some keyframes have moved out of order.
- *
- * anim_data is the list of channels (F-Curves) retrieved already containing the
- * channels to work on. It should not be freed here as it may still need to be used.
- */
-void remake_graph_transdata(TransInfo *t, ListBase *anim_data)
-{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
- bAnimListElem *ale;
- const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
-
- /* sort and reassign verts */
- for (ale = anim_data->first; ale; ale = ale->next) {
- FCurve *fcu = (FCurve *)ale->key_data;
-
- if (fcu->bezt) {
- BeztMap *bezm;
-
- /* adjust transform-data pointers */
- /* note, none of these functions use 'use_handle', it could be removed */
- bezm = bezt_to_beztmaps(fcu->bezt, fcu->totvert, use_handle);
- sort_time_beztmaps(bezm, fcu->totvert, use_handle);
- beztmap_to_data(t, fcu, bezm, fcu->totvert, use_handle);
-
- /* free mapping stuff */
- MEM_freeN(bezm);
-
- /* re-sort actual beztriples (perhaps this could be done using the beztmaps to save time?) */
- sort_time_fcurve(fcu);
-
- /* make sure handles are all set correctly */
- testhandles_fcurve(fcu, use_handle);
- }
- }
-}
-
-/* this function is called on recalcData to apply the transforms applied
- * to the transdata on to the actual keyframe data
- */
-void flushTransGraphData(TransInfo *t)
-{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
- TransData *td;
- TransData2D *td2d;
- TransDataGraph *tdg;
- Scene *scene = t->scene;
- double secf = FPS;
- int a;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = tc->data, td2d = tc->data_2d, tdg = tc->custom.type.data; a < tc->data_len;
- a++, td++, td2d++, tdg++) {
- /* pointers to relevant AnimData blocks are stored in the td->extra pointers */
- AnimData *adt = (AnimData *)td->extra;
-
- float inv_unit_scale = 1.0f / tdg->unit_scale;
-
- /* handle snapping for time values
- * - we should still be in NLA-mapping timespace
- * - only apply to keyframes (but never to handles)
- * - don't do this when canceling, or else these changes won't go away
- */
- if ((t->state != TRANS_CANCEL) && (td->flag & TD_NOTIMESNAP) == 0) {
- switch (sipo->autosnap) {
- case SACTSNAP_FRAME: /* snap to nearest frame */
- td2d->loc[0] = floor((double)td2d->loc[0] + 0.5);
- break;
-
- case SACTSNAP_SECOND: /* snap to nearest second */
- td2d->loc[0] = floor(((double)td2d->loc[0] / secf) + 0.5) * secf;
- break;
-
- case SACTSNAP_MARKER: /* snap to nearest marker */
- td2d->loc[0] = (float)ED_markers_find_nearest_marker_time(&t->scene->markers,
- td2d->loc[0]);
- break;
- }
- }
-
- /* we need to unapply the nla-mapping from the time in some situations */
- if (adt) {
- td2d->loc2d[0] = BKE_nla_tweakedit_remap(adt, td2d->loc[0], NLATIME_CONVERT_UNMAP);
- }
- else {
- td2d->loc2d[0] = td2d->loc[0];
- }
-
- /** Time-stepping auto-snapping modes don't get applied for Graph Editor transforms,
- * as these use the generic transform modes which don't account for this sort of thing.
- * These ones aren't affected by NLA mapping, so we do this after the conversion...
- *
- * \note We also have to apply to td->loc,
- * as that's what the handle-adjustment step below looks to,
- * otherwise we get "swimming handles".
- *
- * \note We don't do this when canceling transforms, or else these changes don't go away.
- */
- if ((t->state != TRANS_CANCEL) && (td->flag & TD_NOTIMESNAP) == 0 &&
- ELEM(sipo->autosnap, SACTSNAP_STEP, SACTSNAP_TSTEP)) {
- switch (sipo->autosnap) {
- case SACTSNAP_STEP: /* frame step */
- td2d->loc2d[0] = floor((double)td2d->loc[0] + 0.5);
- td->loc[0] = floor((double)td->loc[0] + 0.5);
- break;
-
- case SACTSNAP_TSTEP: /* second step */
- /* XXX: the handle behavior in this case is still not quite right... */
- td2d->loc[0] = floor(((double)td2d->loc[0] / secf) + 0.5) * secf;
- td->loc[0] = floor(((double)td->loc[0] / secf) + 0.5) * secf;
- break;
- }
- }
-
- /* if int-values only, truncate to integers */
- if (td->flag & TD_INTVALUES) {
- td2d->loc2d[1] = floorf(td2d->loc[1] * inv_unit_scale - tdg->offset + 0.5f);
- }
- else {
- td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale - tdg->offset;
- }
-
- if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) {
- td2d->h1[0] = td2d->ih1[0] + td->loc[0] - td->iloc[0];
- td2d->h1[1] = td2d->ih1[1] + (td->loc[1] - td->iloc[1]) * inv_unit_scale;
- }
-
- if ((td->flag & TD_MOVEHANDLE2) && td2d->h2) {
- td2d->h2[0] = td2d->ih2[0] + td->loc[0] - td->iloc[0];
- td2d->h2[1] = td2d->ih2[1] + (td->loc[1] - td->iloc[1]) * inv_unit_scale;
- }
- }
-}
-
-/* ******************* Sequencer Transform data ******************* */
-
-/* This function applies the rules for transforming a strip so duplicate
- * checks don't need to be added in multiple places.
- *
- * recursive, count and flag MUST be set.
- *
- * seq->depth must be set before running this function so we know if the strips
- * are root level or not
- */
-static void SeqTransInfo(TransInfo *t, Sequence *seq, int *recursive, int *count, int *flag)
-{
- /* for extend we need to do some tricks */
- if (t->mode == TFM_TIME_EXTEND) {
-
- /* *** Extend Transform *** */
-
- Scene *scene = t->scene;
- int cfra = CFRA;
- int left = BKE_sequence_tx_get_final_left(seq, true);
- int right = BKE_sequence_tx_get_final_right(seq, true);
-
- if (seq->depth == 0 && ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK))) {
- *recursive = false;
- *count = 0;
- *flag = 0;
- }
- else if (seq->type == SEQ_TYPE_META) {
-
- /* for meta's we only ever need to extend their children, no matter what depth
- * just check the meta's are in the bounds */
- if (t->frame_side == 'R' && right <= cfra) {
- *recursive = false;
- }
- else if (t->frame_side == 'L' && left >= cfra) {
- *recursive = false;
- }
- else {
- *recursive = true;
- }
-
- *count = 1;
- *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
- }
- else {
-
- *recursive = false; /* not a meta, so no thinking here */
- *count = 1; /* unless its set to 0, extend will never set 2 handles at once */
- *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
-
- if (t->frame_side == 'R') {
- if (right <= cfra) {
- *count = *flag = 0;
- } /* ignore */
- else if (left > cfra) {
- } /* keep the selection */
- else {
- *flag |= SEQ_RIGHTSEL;
- }
- }
- else {
- if (left >= cfra) {
- *count = *flag = 0;
- } /* ignore */
- else if (right < cfra) {
- } /* keep the selection */
- else {
- *flag |= SEQ_LEFTSEL;
- }
- }
- }
- }
- else {
-
- t->frame_side = 'B';
-
- /* *** Normal Transform *** */
-
- if (seq->depth == 0) {
-
- /* Count */
-
- /* Non nested strips (resect selection and handles) */
- if ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK)) {
- *recursive = false;
- *count = 0;
- *flag = 0;
- }
- else {
- if ((seq->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) == (SEQ_LEFTSEL | SEQ_RIGHTSEL)) {
- *flag = seq->flag;
- *count = 2; /* we need 2 transdata's */
- }
- else {
- *flag = seq->flag;
- *count = 1; /* selected or with a handle selected */
- }
-
- /* Recursive */
-
- if ((seq->type == SEQ_TYPE_META) && ((seq->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) == 0)) {
- /* if any handles are selected, don't recurse */
- *recursive = true;
- }
- else {
- *recursive = false;
- }
- }
- }
- else {
- /* Nested, different rules apply */
-
-#ifdef SEQ_TX_NESTED_METAS
- *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
- *count = 1; /* ignore the selection for nested */
- *recursive = (seq->type == SEQ_TYPE_META);
-#else
- if (seq->type == SEQ_TYPE_META) {
- /* Meta's can only directly be moved between channels since they
- * don't have their start and length set directly (children affect that)
- * since this Meta is nested we don't need any of its data in fact.
- * BKE_sequence_calc() will update its settings when run on the toplevel meta */
- *flag = 0;
- *count = 0;
- *recursive = true;
- }
- else {
- *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
- *count = 1; /* ignore the selection for nested */
- *recursive = false;
- }
-#endif
- }
- }
-}
-
-static int SeqTransCount(TransInfo *t, Sequence *parent, ListBase *seqbase, int depth)
-{
- Sequence *seq;
- int tot = 0, recursive, count, flag;
-
- for (seq = seqbase->first; seq; seq = seq->next) {
- seq->depth = depth;
-
- /* 'seq->tmp' is used by seq_tx_get_final_{left, right}
- * to check sequence's range and clamp to it if needed.
- * It's first place where digging into sequences tree, so store link to parent here. */
- seq->tmp = parent;
-
- SeqTransInfo(t, seq, &recursive, &count, &flag); /* ignore the flag */
- tot += count;
-
- if (recursive) {
- tot += SeqTransCount(t, seq, &seq->seqbase, depth + 1);
- }
- }
-
- return tot;
-}
-
-static TransData *SeqToTransData(
- TransData *td, TransData2D *td2d, TransDataSeq *tdsq, Sequence *seq, int flag, int sel_flag)
-{
- int start_left;
-
- switch (sel_flag) {
- case SELECT:
- /* Use seq_tx_get_final_left() and an offset here
- * so transform has the left hand location of the strip.
- * tdsq->start_offset is used when flushing the tx data back */
- start_left = BKE_sequence_tx_get_final_left(seq, false);
- td2d->loc[0] = start_left;
- tdsq->start_offset = start_left - seq->start; /* use to apply the original location */
- break;
- case SEQ_LEFTSEL:
- start_left = BKE_sequence_tx_get_final_left(seq, false);
- td2d->loc[0] = start_left;
- break;
- case SEQ_RIGHTSEL:
- td2d->loc[0] = BKE_sequence_tx_get_final_right(seq, false);
- break;
- }
-
- td2d->loc[1] = seq->machine; /* channel - Y location */
- td2d->loc[2] = 0.0f;
- td2d->loc2d = NULL;
-
- tdsq->seq = seq;
-
- /* Use instead of seq->flag for nested strips and other
- * cases where the selection may need to be modified */
- tdsq->flag = flag;
- tdsq->sel_flag = sel_flag;
-
- td->extra = (void *)tdsq; /* allow us to update the strip from here */
-
- td->flag = 0;
- td->loc = td2d->loc;
- copy_v3_v3(td->center, td->loc);
- copy_v3_v3(td->iloc, td->loc);
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
-
- td->flag |= TD_SELECTED;
- td->dist = 0.0;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-
- /* Time Transform (extend) */
- td->val = td2d->loc;
- td->ival = td2d->loc[0];
-
- return td;
-}
-
-static int SeqToTransData_Recursive(
- TransInfo *t, ListBase *seqbase, TransData *td, TransData2D *td2d, TransDataSeq *tdsq)
-{
- Sequence *seq;
- int recursive, count, flag;
- int tot = 0;
-
- for (seq = seqbase->first; seq; seq = seq->next) {
-
- SeqTransInfo(t, seq, &recursive, &count, &flag);
-
- /* add children first so recalculating metastrips does nested strips first */
- if (recursive) {
- int tot_children = SeqToTransData_Recursive(t, &seq->seqbase, td, td2d, tdsq);
-
- td = td + tot_children;
- td2d = td2d + tot_children;
- tdsq = tdsq + tot_children;
-
- tot += tot_children;
- }
-
- /* use 'flag' which is derived from seq->flag but modified for special cases */
- if (flag & SELECT) {
- if (flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) {
- if (flag & SEQ_LEFTSEL) {
- SeqToTransData(td++, td2d++, tdsq++, seq, flag, SEQ_LEFTSEL);
- tot++;
- }
- if (flag & SEQ_RIGHTSEL) {
- SeqToTransData(td++, td2d++, tdsq++, seq, flag, SEQ_RIGHTSEL);
- tot++;
- }
- }
- else {
- SeqToTransData(td++, td2d++, tdsq++, seq, flag, SELECT);
- tot++;
- }
- }
- }
- return tot;
-}
-
-static void SeqTransDataBounds(TransInfo *t, ListBase *seqbase, TransSeq *ts)
-{
- Sequence *seq;
- int recursive, count, flag;
- int max = INT32_MIN, min = INT32_MAX;
-
- for (seq = seqbase->first; seq; seq = seq->next) {
-
- /* just to get the flag since there are corner cases where this isn't totally obvious */
- SeqTransInfo(t, seq, &recursive, &count, &flag);
-
- /* use 'flag' which is derived from seq->flag but modified for special cases */
- if (flag & SELECT) {
- if (flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) {
- if (flag & SEQ_LEFTSEL) {
- min = min_ii(seq->startdisp, min);
- max = max_ii(seq->startdisp, max);
- }
- if (flag & SEQ_RIGHTSEL) {
- min = min_ii(seq->enddisp, min);
- max = max_ii(seq->enddisp, max);
- }
- }
- else {
- min = min_ii(seq->startdisp, min);
- max = max_ii(seq->enddisp, max);
- }
- }
- }
-
- if (ts) {
- ts->max = max;
- ts->min = min;
- }
-}
-
-static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data)
-{
- Editing *ed = BKE_sequencer_editing_get(t->scene, false);
-
- if (ed != NULL) {
-
- ListBase *seqbasep = ed->seqbasep;
- TransData *td = tc->data;
- int a;
-
- /* prevent updating the same seq twice
- * if the transdata order is changed this will mess up
- * but so will TransDataSeq */
- Sequence *seq_prev = NULL;
- Sequence *seq;
-
- if (!(t->state == TRANS_CANCEL)) {
-
-#if 0 // default 2.4 behavior
-
- /* flush to 2d vector from internally used 3d vector */
- for (a = 0; a < t->total; a++, td++) {
- if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) {
- seq = ((TransDataSeq *)td->extra)->seq;
- BKE_sequence_base_shuffle(seqbasep, seq, t->scene);
- }
-
- seq_prev = seq;
- }
-
-#else // durian hack
- {
- int overlap = 0;
-
- for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
- seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) {
- overlap = 1;
- break;
- }
- }
-
- if (overlap) {
- bool has_effect_root = false, has_effect_any = false;
- for (seq = seqbasep->first; seq; seq = seq->next) {
- seq->tmp = NULL;
- }
-
- td = tc->data;
- for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
- seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev)) {
- /* check effects strips, we cant change their time */
- if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
- has_effect_any = true;
- if (seq->depth == 0) {
- has_effect_root = true;
- }
- }
- else {
- /* Tag seq with a non zero value, used by
- * BKE_sequence_base_shuffle_time to identify the ones to shuffle */
- if (seq->depth == 0) {
- seq->tmp = (void *)1;
- }
- }
- }
- }
-
- if (t->flag & T_ALT_TRANSFORM) {
- int minframe = MAXFRAME;
- td = tc->data;
- for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
- seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev) && (seq->depth == 0)) {
- minframe = min_ii(minframe, seq->startdisp);
- }
- }
-
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (!(seq->flag & SELECT)) {
- if (seq->startdisp >= minframe) {
- seq->machine += MAXSEQ * 2;
- }
- }
- }
-
- BKE_sequence_base_shuffle_time(seqbasep, t->scene);
-
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->machine >= MAXSEQ * 2) {
- seq->machine -= MAXSEQ * 2;
- seq->tmp = (void *)1;
- }
- else {
- seq->tmp = NULL;
- }
- }
-
- BKE_sequence_base_shuffle_time(seqbasep, t->scene);
- }
- else {
- BKE_sequence_base_shuffle_time(seqbasep, t->scene);
- }
-
- if (has_effect_any) {
- /* update effects strips based on strips just moved in time */
- td = tc->data;
- for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
- seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev)) {
- if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
- BKE_sequence_calc(t->scene, seq);
- }
- }
- }
- }
-
- if (has_effect_root) {
- /* now if any effects _still_ overlap, we need to move them up */
- td = tc->data;
- for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
- seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev) && (seq->depth == 0)) {
- if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
- if (BKE_sequence_test_overlap(seqbasep, seq)) {
- BKE_sequence_base_shuffle(seqbasep, seq, t->scene);
- }
- }
- }
- }
- /* done with effects */
- }
- }
- }
-#endif
-
- for (seq = seqbasep->first; seq; seq = seq->next) {
- /* We might want to build a list of effects that need to be updated during transform */
- if (seq->type & SEQ_TYPE_EFFECT) {
- if (seq->seq1 && seq->seq1->flag & SELECT) {
- BKE_sequence_calc(t->scene, seq);
- }
- else if (seq->seq2 && seq->seq2->flag & SELECT) {
- BKE_sequence_calc(t->scene, seq);
- }
- else if (seq->seq3 && seq->seq3->flag & SELECT) {
- BKE_sequence_calc(t->scene, seq);
- }
- }
- }
-
- BKE_sequencer_sort(t->scene);
- }
- else {
- /* Canceled, need to update the strips display */
- for (a = 0; a < tc->data_len; a++, td++) {
- seq = ((TransDataSeq *)td->extra)->seq;
- if ((seq != seq_prev) && (seq->depth == 0)) {
- if (seq->flag & SEQ_OVERLAP) {
- BKE_sequence_base_shuffle(seqbasep, seq, t->scene);
- }
-
- BKE_sequence_calc_disp(t->scene, seq);
- }
- seq_prev = seq;
- }
- }
- }
-
- if ((custom_data->data != NULL) && custom_data->use_free) {
- TransSeq *ts = custom_data->data;
- MEM_freeN(ts->tdseq);
- MEM_freeN(custom_data->data);
- custom_data->data = NULL;
- }
-
- DEG_id_tag_update(&t->scene->id, ID_RECALC_SEQUENCER_STRIPS);
-}
-
-static void createTransSeqData(bContext *C, TransInfo *t)
-{
-#define XXX_DURIAN_ANIM_TX_HACK
-
- View2D *v2d = UI_view2d_fromcontext(C);
- Scene *scene = t->scene;
- Editing *ed = BKE_sequencer_editing_get(t->scene, false);
- TransData *td = NULL;
- TransData2D *td2d = NULL;
- TransDataSeq *tdsq = NULL;
- TransSeq *ts = NULL;
- int xmouse;
-
- int count = 0;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- if (ed == NULL) {
- tc->data_len = 0;
- return;
- }
-
- tc->custom.type.free_cb = freeSeqData;
-
- xmouse = (int)UI_view2d_region_to_view_x(v2d, t->mouse.imval[0]);
-
- /* which side of the current frame should be allowed */
- if (t->mode == TFM_TIME_EXTEND) {
- /* only side on which mouse is gets transformed */
- t->frame_side = (xmouse > CFRA) ? 'R' : 'L';
- }
- else {
- /* normal transform - both sides of current frame are considered */
- t->frame_side = 'B';
- }
-
-#ifdef XXX_DURIAN_ANIM_TX_HACK
- {
- Sequence *seq;
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- /* hack */
- if ((seq->flag & SELECT) == 0 && seq->type & SEQ_TYPE_EFFECT) {
- Sequence *seq_user;
- int i;
- for (i = 0; i < 3; i++) {
- seq_user = *((&seq->seq1) + i);
- if (seq_user && (seq_user->flag & SELECT) && !(seq_user->flag & SEQ_LOCK) &&
- !(seq_user->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL))) {
- seq->flag |= SELECT;
- }
- }
- }
- }
- }
-#endif
-
- count = SeqTransCount(t, NULL, ed->seqbasep, 0);
-
- /* allocate memory for data */
- tc->data_len = count;
-
- /* stop if trying to build list if nothing selected */
- if (count == 0) {
- return;
- }
-
- tc->custom.type.data = ts = MEM_callocN(sizeof(TransSeq), "transseq");
- tc->custom.type.use_free = true;
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransSeq TransData");
- td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransSeq TransData2D");
- ts->tdseq = tdsq = MEM_callocN(tc->data_len * sizeof(TransDataSeq), "TransSeq TransDataSeq");
-
- /* loop 2: build transdata array */
- SeqToTransData_Recursive(t, ed->seqbasep, td, td2d, tdsq);
- SeqTransDataBounds(t, ed->seqbasep, ts);
-
- /* set the snap mode based on how close the mouse is at the end/start points */
- if (abs(xmouse - ts->max) > abs(xmouse - ts->min)) {
- ts->snap_left = true;
- }
-
-#undef XXX_DURIAN_ANIM_TX_HACK
-}
-
-/* *********************** Object Transform data ******************* */
-
-/* Little helper function for ObjectToTransData used to give certain
- * constraints (ChildOf, FollowPath, and others that may be added)
- * inverse corrections for transform, so that they aren't in CrazySpace.
- * These particular constraints benefit from this, but others don't, hence
- * this semi-hack ;-) - Aligorith
- */
-static bool constraints_list_needinv(TransInfo *t, ListBase *list)
-{
- bConstraint *con;
-
- /* loop through constraints, checking if there's one of the mentioned
- * constraints needing special crazyspace corrections
- */
- if (list) {
- for (con = list->first; con; con = con->next) {
- /* only consider constraint if it is enabled, and has influence on result */
- if ((con->flag & CONSTRAINT_DISABLE) == 0 && (con->enforce != 0.0f)) {
- /* (affirmative) returns for specific constraints here... */
- /* constraints that require this regardless */
- if (ELEM(con->type,
- CONSTRAINT_TYPE_FOLLOWPATH,
- CONSTRAINT_TYPE_CLAMPTO,
- CONSTRAINT_TYPE_ARMATURE,
- CONSTRAINT_TYPE_OBJECTSOLVER,
- CONSTRAINT_TYPE_FOLLOWTRACK)) {
- return true;
- }
-
- /* constraints that require this only under special conditions */
- if (con->type == CONSTRAINT_TYPE_CHILDOF) {
- /* ChildOf constraint only works when using all location components, see T42256. */
- bChildOfConstraint *data = (bChildOfConstraint *)con->data;
-
- if ((data->flag & CHILDOF_LOCX) && (data->flag & CHILDOF_LOCY) &&
- (data->flag & CHILDOF_LOCZ)) {
- return true;
- }
- }
- else if (con->type == CONSTRAINT_TYPE_ROTLIKE) {
- /* CopyRot constraint only does this when rotating, and offset is on */
- bRotateLikeConstraint *data = (bRotateLikeConstraint *)con->data;
-
- if ((data->flag & ROTLIKE_OFFSET) && (t->mode == TFM_ROTATION)) {
- return true;
- }
- }
- else if (con->type == CONSTRAINT_TYPE_TRANSFORM) {
- /* Transform constraint needs it for rotation at least (r.57309),
- * but doing so when translating may also mess things up [#36203]
- */
-
- if (t->mode == TFM_ROTATION) {
- return true;
- }
- /* ??? (t->mode == TFM_SCALE) ? */
- }
- }
- }
- }
-
- /* no appropriate candidates found */
- return false;
-}
-
-/* transcribe given object into TransData for Transforming */
-static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
-{
- Scene *scene = t->scene;
- bool constinv;
- bool skip_invert = false;
-
- if (t->mode != TFM_DUMMY && ob->rigidbody_object) {
- float rot[3][3], scale[3];
- float ctime = BKE_scene_frame_get(scene);
-
- /* only use rigid body transform if simulation is running,
- * avoids problems with initial setup of rigid bodies */
- if (BKE_rigidbody_check_sim_running(scene->rigidbody_world, ctime)) {
-
- /* save original object transform */
- copy_v3_v3(td->ext->oloc, ob->loc);
-
- if (ob->rotmode > 0) {
- copy_v3_v3(td->ext->orot, ob->rot);
- }
- else if (ob->rotmode == ROT_MODE_AXISANGLE) {
- td->ext->orotAngle = ob->rotAngle;
- copy_v3_v3(td->ext->orotAxis, ob->rotAxis);
- }
- else {
- copy_qt_qt(td->ext->oquat, ob->quat);
- }
- /* update object's loc/rot to get current rigid body transform */
- mat4_to_loc_rot_size(ob->loc, rot, scale, ob->obmat);
- sub_v3_v3(ob->loc, ob->dloc);
- BKE_object_mat3_to_rot(ob, rot, false); /* drot is already corrected here */
- }
- }
-
- /* axismtx has the real orientation */
- copy_m3_m4(td->axismtx, ob->obmat);
- normalize_m3(td->axismtx);
-
- td->con = ob->constraints.first;
-
- /* hack: temporarily disable tracking and/or constraints when getting
- * object matrix, if tracking is on, or if constraints don't need
- * inverse correction to stop it from screwing up space conversion
- * matrix later
- */
- constinv = constraints_list_needinv(t, &ob->constraints);
-
- /* disable constraints inversion for dummy pass */
- if (t->mode == TFM_DUMMY) {
- skip_invert = true;
- }
-
- /* NOTE: This is not really following copy-on-write design and we should not
- * be re-evaluating the evaluated object. But as the comment above mentioned
- * this is part of a hack.
- * More proper solution would be to make a shallow copy of the object and
- * evaluate that, and access matrix of that evaluated copy of the object.
- * Might be more tricky than it sounds, if some logic later on accesses the
- * object matrix via td->ob->obmat. */
- Object *object_eval = DEG_get_evaluated_object(t->depsgraph, ob);
- if (skip_invert == false && constinv == false) {
- object_eval->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc checks this */
- /* It is possible to have transform data initialization prior to a
- * complete dependency graph evaluated. Happens, for example, when
- * changing transformation mode. */
- BKE_object_tfm_copy(object_eval, ob);
- BKE_object_where_is_calc(t->depsgraph, t->scene, object_eval);
- object_eval->transflag &= ~OB_NO_CONSTRAINTS;
- }
- else {
- BKE_object_where_is_calc(t->depsgraph, t->scene, object_eval);
- }
- /* Copy newly evaluated fields to the original object, similar to how
- * active dependency graph will do it. */
- copy_m4_m4(ob->obmat, object_eval->obmat);
- /* Only copy negative scale flag, this is the only flag which is modified by
- * the BKE_object_where_is_calc(). The rest of the flags we need to keep,
- * otherwise we might loose dupli flags (see T61787). */
- ob->transflag &= ~OB_NEG_SCALE;
- ob->transflag |= (object_eval->transflag & OB_NEG_SCALE);
-
- td->ob = ob;
-
- td->loc = ob->loc;
- copy_v3_v3(td->iloc, td->loc);
-
- if (ob->rotmode > 0) {
- td->ext->rot = ob->rot;
- td->ext->rotAxis = NULL;
- td->ext->rotAngle = NULL;
- td->ext->quat = NULL;
-
- copy_v3_v3(td->ext->irot, ob->rot);
- copy_v3_v3(td->ext->drot, ob->drot);
- }
- else if (ob->rotmode == ROT_MODE_AXISANGLE) {
- td->ext->rot = NULL;
- td->ext->rotAxis = ob->rotAxis;
- td->ext->rotAngle = &ob->rotAngle;
- td->ext->quat = NULL;
-
- td->ext->irotAngle = ob->rotAngle;
- copy_v3_v3(td->ext->irotAxis, ob->rotAxis);
- // td->ext->drotAngle = ob->drotAngle; // XXX, not implemented
- // copy_v3_v3(td->ext->drotAxis, ob->drotAxis); // XXX, not implemented
- }
- else {
- td->ext->rot = NULL;
- td->ext->rotAxis = NULL;
- td->ext->rotAngle = NULL;
- td->ext->quat = ob->quat;
-
- copy_qt_qt(td->ext->iquat, ob->quat);
- copy_qt_qt(td->ext->dquat, ob->dquat);
- }
- td->ext->rotOrder = ob->rotmode;
-
- td->ext->size = ob->scale;
- copy_v3_v3(td->ext->isize, ob->scale);
- copy_v3_v3(td->ext->dscale, ob->dscale);
-
- copy_v3_v3(td->center, ob->obmat[3]);
-
- copy_m4_m4(td->ext->obmat, ob->obmat);
-
- /* is there a need to set the global<->data space conversion matrices? */
- if (ob->parent || constinv) {
- float obmtx[3][3], totmat[3][3], obinv[3][3];
-
- /* Get the effect of parenting, and/or certain constraints.
- * NOTE: some Constraints, and also Tracking should never get this
- * done, as it doesn't work well.
- */
- BKE_object_to_mat3(ob, obmtx);
- copy_m3_m4(totmat, ob->obmat);
- invert_m3_m3(obinv, totmat);
- mul_m3_m3m3(td->smtx, obmtx, obinv);
- invert_m3_m3(td->mtx, td->smtx);
- }
- else {
- /* no conversion to/from dataspace */
- unit_m3(td->smtx);
- unit_m3(td->mtx);
- }
-}
-
-static void trans_object_base_deps_flag_prepare(ViewLayer *view_layer)
-{
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- base->object->id.tag &= ~LIB_TAG_DOIT;
- }
-}
-
-static void set_trans_object_base_deps_flag_cb(ID *id,
- eDepsObjectComponentType component,
- void *UNUSED(user_data))
-{
- /* Here we only handle object IDs. */
- if (GS(id->name) != ID_OB) {
- return;
- }
- if (!ELEM(component, DEG_OB_COMP_TRANSFORM, DEG_OB_COMP_GEOMETRY)) {
- return;
- }
- id->tag |= LIB_TAG_DOIT;
-}
-
-static void flush_trans_object_base_deps_flag(Depsgraph *depsgraph, Object *object)
-{
- object->id.tag |= LIB_TAG_DOIT;
- DEG_foreach_dependent_ID_component(
- depsgraph, &object->id, DEG_OB_COMP_TRANSFORM, set_trans_object_base_deps_flag_cb, NULL);
-}
-
-static void trans_object_base_deps_flag_finish(const TransInfo *t, ViewLayer *view_layer)
-{
-
- if ((t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) == 0) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- if (base->object->id.tag & LIB_TAG_DOIT) {
- base->flag_legacy |= BA_SNAP_FIX_DEPS_FIASCO;
- }
- }
- }
-}
-
-/* sets flags in Bases to define whether they take part in transform */
-/* it deselects Bases, so we have to call the clear function always after */
-static void set_trans_object_base_flags(TransInfo *t)
-{
- Main *bmain = CTX_data_main(t->context);
- ViewLayer *view_layer = t->view_layer;
- View3D *v3d = t->view;
- Scene *scene = t->scene;
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
- /* NOTE: if Base selected and has parent selected:
- * base->flag_legacy = BA_WAS_SEL
- */
- /* Don't do it if we're not actually going to recalculate anything. */
- if (t->mode == TFM_DUMMY) {
- return;
- }
- /* Makes sure base flags and object flags are identical. */
- BKE_scene_base_flag_to_objects(t->view_layer);
- /* Make sure depsgraph is here. */
- DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
- /* Clear all flags we need. It will be used to detect dependencies. */
- trans_object_base_deps_flag_prepare(view_layer);
- /* Traverse all bases and set all possible flags. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- base->flag_legacy &= ~BA_WAS_SEL;
- if (BASE_SELECTED_EDITABLE(v3d, base)) {
- Object *ob = base->object;
- Object *parsel = ob->parent;
- /* If parent selected, deselect. */
- while (parsel != NULL) {
- if (parsel->base_flag & BASE_SELECTED) {
- Base *parbase = BKE_view_layer_base_find(view_layer, parsel);
- if (parbase != NULL) { /* in rare cases this can fail */
- if (BASE_SELECTED_EDITABLE(v3d, parbase)) {
- break;
- }
- }
- }
- parsel = parsel->parent;
- }
- if (parsel != NULL) {
- /* Rotation around local centers are allowed to propagate. */
- if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
- (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)) {
- base->flag_legacy |= BA_TRANSFORM_CHILD;
- }
- else {
- base->flag &= ~BASE_SELECTED;
- base->flag_legacy |= BA_WAS_SEL;
- }
- }
- flush_trans_object_base_deps_flag(depsgraph, ob);
- }
- }
- /* Store temporary bits in base indicating that base is being modified
- * (directly or indirectly) by transforming objects.
- */
- trans_object_base_deps_flag_finish(t, view_layer);
-}
-
-static bool mark_children(Object *ob)
-{
- if (ob->flag & (SELECT | BA_TRANSFORM_CHILD)) {
- return true;
- }
-
- if (ob->parent) {
- if (mark_children(ob->parent)) {
- ob->flag |= BA_TRANSFORM_CHILD;
- return true;
- }
- }
-
- return false;
-}
-
-static int count_proportional_objects(TransInfo *t)
-{
- int total = 0;
- ViewLayer *view_layer = t->view_layer;
- View3D *v3d = t->view;
- Scene *scene = t->scene;
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
- /* Clear all flags we need. It will be used to detect dependencies. */
- trans_object_base_deps_flag_prepare(view_layer);
- /* Rotations around local centers are allowed to propagate, so we take all objects. */
- if (!((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
- (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL))) {
- /* Mark all parents. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- if (BASE_SELECTED_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base)) {
- Object *parent = base->object->parent;
- /* flag all parents */
- while (parent != NULL) {
- parent->flag |= BA_TRANSFORM_PARENT;
- parent = parent->parent;
- }
- }
- }
- /* Mark all children. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- /* all base not already selected or marked that is editable */
- if ((base->object->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
- (base->flag & BASE_SELECTED) == 0 &&
- (BASE_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base))) {
- mark_children(base->object);
- }
- }
- }
- /* Flush changed flags to all dependencies. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- Object *ob = base->object;
- /* If base is not selected, not a parent of selection or not a child of
- * selection and it is editable and selectable.
- */
- if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
- (base->flag & BASE_SELECTED) == 0 &&
- (BASE_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base))) {
- flush_trans_object_base_deps_flag(depsgraph, ob);
- total += 1;
- }
- }
- /* Store temporary bits in base indicating that base is being modified
- * (directly or indirectly) by transforming objects.
- */
- trans_object_base_deps_flag_finish(t, view_layer);
- return total;
-}
-
-static void clear_trans_object_base_flags(TransInfo *t)
-{
- ViewLayer *view_layer = t->view_layer;
- Base *base;
-
- for (base = view_layer->object_bases.first; base; base = base->next) {
- if (base->flag_legacy & BA_WAS_SEL) {
- ED_object_base_select(base, BA_SELECT);
- }
-
- base->flag_legacy &= ~(BA_WAS_SEL | BA_SNAP_FIX_DEPS_FIASCO | BA_TEMP_TAG |
- BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT);
- }
-}
-
-/**
- * Auto-keyframing feature - for objects
- *
- * \param tmode: A transform mode.
- *
- * \note Context may not always be available,
- * so must check before using it as it's a luxury for a few cases.
- */
-void autokeyframe_object(bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, int tmode)
-{
- Main *bmain = CTX_data_main(C);
- ID *id = &ob->id;
- FCurve *fcu;
-
- // TODO: this should probably be done per channel instead...
- if (autokeyframe_cfra_can_key(scene, id)) {
- ReportList *reports = CTX_wm_reports(C);
- ToolSettings *ts = scene->toolsettings;
- KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
- ListBase dsources = {NULL, NULL};
- float cfra = (float)CFRA; // xxx this will do for now
- short flag = 0;
-
- /* get flags used for inserting keyframes */
- flag = ANIM_get_keyframing_flags(scene, 1);
-
- /* add datasource override for the object */
- ANIM_relative_keyingset_add_source(&dsources, id, NULL, NULL);
-
- if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
- /* Only insert into active keyingset
- * NOTE: we assume here that the active Keying Set
- * does not need to have its iterator overridden.
- */
- ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) {
- AnimData *adt = ob->adt;
-
- /* only key on available channels */
- if (adt && adt->action) {
- ListBase nla_cache = {NULL, NULL};
- for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) {
- fcu->flag &= ~FCURVE_SELECTED;
- insert_keyframe(bmain,
- reports,
- id,
- adt->action,
- (fcu->grp ? fcu->grp->name : NULL),
- fcu->rna_path,
- fcu->array_index,
- cfra,
- ts->keyframe_type,
- &nla_cache,
- flag);
- }
-
- BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
- }
- }
- else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
- bool do_loc = false, do_rot = false, do_scale = false;
-
- /* filter the conditions when this happens (assume that curarea->spacetype==SPACE_VIE3D) */
- if (tmode == TFM_TRANSLATION) {
- do_loc = true;
- }
- else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
- if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
- if (ob != OBACT(view_layer)) {
- do_loc = true;
- }
- }
- else if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) {
- do_loc = true;
- }
-
- if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
- do_rot = true;
- }
- }
- else if (tmode == TFM_RESIZE) {
- if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
- if (ob != OBACT(view_layer)) {
- do_loc = true;
- }
- }
- else if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) {
- do_loc = true;
- }
-
- if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
- do_scale = true;
- }
- }
-
- /* insert keyframes for the affected sets of channels using the builtin KeyingSets found */
- if (do_loc) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- if (do_rot) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- if (do_scale) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_SCALING_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- }
- /* insert keyframe in all (transform) channels */
- else {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
-
- /* free temp info */
- BLI_freelistN(&dsources);
- }
-}
-
-/* Return if we need to update motion paths, only if they already exist,
- * and we will insert a keyframe at the end of transform. */
-bool motionpath_need_update_object(Scene *scene, Object *ob)
-{
- /* XXX: there's potential here for problems with unkeyed rotations/scale,
- * but for now (until proper data-locality for baking operations),
- * this should be a better fix for T24451 and T37755
- */
-
- if (autokeyframe_cfra_can_key(scene, &ob->id)) {
- return (ob->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
- }
-
- return false;
-}
-
-/**
- * Auto-keyframing feature - for poses/pose-channels
- *
- * \param tmode: A transform mode.
- *
- * targetless_ik: has targetless ik been done on any channels?
- *
- * \note Context may not always be available,
- * so must check before using it as it's a luxury for a few cases.
- */
-void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, int tmode, short targetless_ik)
-{
- Main *bmain = CTX_data_main(C);
- ID *id = &ob->id;
- AnimData *adt = ob->adt;
- bAction *act = (adt) ? adt->action : NULL;
- bPose *pose = ob->pose;
- bPoseChannel *pchan;
- FCurve *fcu;
-
- // TODO: this should probably be done per channel instead...
- if (autokeyframe_cfra_can_key(scene, id)) {
- ReportList *reports = CTX_wm_reports(C);
- ToolSettings *ts = scene->toolsettings;
- KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
- ListBase nla_cache = {NULL, NULL};
- float cfra = (float)CFRA;
- short flag = 0;
-
- /* flag is initialized from UserPref keyframing settings
- * - special exception for targetless IK - INSERTKEY_MATRIX keyframes should get
- * visual keyframes even if flag not set, as it's not that useful otherwise
- * (for quick animation recording)
- */
- flag = ANIM_get_keyframing_flags(scene, 1);
-
- if (targetless_ik) {
- flag |= INSERTKEY_MATRIX;
- }
-
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->flag & (BONE_TRANSFORM | BONE_TRANSFORM_MIRROR)) {
-
- ListBase dsources = {NULL, NULL};
-
- /* clear any 'unkeyed' flag it may have */
- pchan->bone->flag &= ~BONE_UNKEYED;
-
- /* add datasource override for the camera object */
- ANIM_relative_keyingset_add_source(&dsources, id, &RNA_PoseBone, pchan);
-
- /* only insert into active keyingset? */
- if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
- /* run the active Keying Set on the current datasource */
- ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- /* only insert into available channels? */
- else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) {
- if (act) {
- for (fcu = act->curves.first; fcu; fcu = fcu->next) {
- /* only insert keyframes for this F-Curve if it affects the current bone */
- if (strstr(fcu->rna_path, "bones")) {
- char *pchanName = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
-
- /* only if bone name matches too...
- * NOTE: this will do constraints too, but those are ok to do here too?
- */
- if (pchanName && STREQ(pchanName, pchan->name)) {
- insert_keyframe(bmain,
- reports,
- id,
- act,
- ((fcu->grp) ? (fcu->grp->name) : (NULL)),
- fcu->rna_path,
- fcu->array_index,
- cfra,
- ts->keyframe_type,
- &nla_cache,
- flag);
- }
-
- if (pchanName) {
- MEM_freeN(pchanName);
- }
- }
- }
- }
- }
- /* only insert keyframe if needed? */
- else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
- bool do_loc = false, do_rot = false, do_scale = false;
-
- /* Filter the conditions when this happens
- * (assume that 'curarea->spacetype == SPACE_VIEW3D'). */
- if (tmode == TFM_TRANSLATION) {
- if (targetless_ik) {
- do_rot = true;
- }
- else {
- do_loc = true;
- }
- }
- else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
- if (ELEM(scene->toolsettings->transform_pivot_point,
- V3D_AROUND_CURSOR,
- V3D_AROUND_ACTIVE)) {
- do_loc = true;
- }
-
- if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
- do_rot = true;
- }
- }
- else if (tmode == TFM_RESIZE) {
- if (ELEM(scene->toolsettings->transform_pivot_point,
- V3D_AROUND_CURSOR,
- V3D_AROUND_ACTIVE)) {
- do_loc = true;
- }
-
- if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
- do_scale = true;
- }
- }
-
- if (do_loc) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- if (do_rot) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- if (do_scale) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_SCALING_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- }
- /* insert keyframe in all (transform) channels */
- else {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
-
- /* free temp info */
- BLI_freelistN(&dsources);
- }
- }
-
- BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
- }
- else {
- /* tag channels that should have unkeyed data */
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->flag & BONE_TRANSFORM) {
- /* tag this channel */
- pchan->bone->flag |= BONE_UNKEYED;
- }
- }
- }
-}
-
-/* Return if we need to update motion paths, only if they already exist,
- * and we will insert a keyframe at the end of transform. */
-bool motionpath_need_update_pose(Scene *scene, Object *ob)
-{
- if (autokeyframe_cfra_can_key(scene, &ob->id)) {
- return (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
- }
-
- return false;
-}
-
-static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t)
-{
- SpaceClip *sc = t->sa->spacedata.first;
- MovieClip *clip = ED_space_clip_get_clip(sc);
- ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
- const int framenr = ED_space_clip_get_clip_frame_number(sc);
- /* Update coordinates of modified plane tracks. */
- for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first; plane_track;
- plane_track = plane_track->next) {
- bool do_update = false;
- if (plane_track->flag & PLANE_TRACK_HIDDEN) {
- continue;
- }
- do_update |= PLANE_TRACK_VIEW_SELECTED(plane_track) != 0;
- if (do_update == false) {
- if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
- int i;
- for (i = 0; i < plane_track->point_tracksnr; i++) {
- MovieTrackingTrack *track = plane_track->point_tracks[i];
- if (TRACK_VIEW_SELECTED(sc, track)) {
- do_update = true;
- break;
- }
- }
- }
- }
- if (do_update) {
- BKE_tracking_track_plane_from_existing_motion(plane_track, framenr);
- }
- }
- if (t->scene->nodetree != NULL) {
- /* Tracks can be used for stabilization nodes,
- * flush update for such nodes.
- */
- nodeUpdateID(t->scene->nodetree, &clip->id);
- WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL);
- }
-}
-
-static void special_aftertrans_update__mask(bContext *C, TransInfo *t)
-{
- Mask *mask = NULL;
-
- if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sc = t->sa->spacedata.first;
- mask = ED_space_clip_get_mask(sc);
- }
- else if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = t->sa->spacedata.first;
- mask = ED_space_image_get_mask(sima);
- }
- else {
- BLI_assert(0);
- }
-
- if (t->scene->nodetree) {
- /* tracks can be used for stabilization nodes,
- * flush update for such nodes */
- // if (nodeUpdateID(t->scene->nodetree, &mask->id))
- {
- WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id);
- }
- }
-
- /* TODO - dont key all masks... */
- if (IS_AUTOKEY_ON(t->scene)) {
- Scene *scene = t->scene;
-
- ED_mask_layer_shape_auto_key_select(mask, CFRA);
- }
-}
-
-static void special_aftertrans_update__node(bContext *C, TransInfo *t)
-{
- Main *bmain = CTX_data_main(C);
- const bool canceled = (t->state == TRANS_CANCEL);
-
- if (canceled && t->remove_on_cancel) {
- /* remove selected nodes on cancel */
- SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
- bNodeTree *ntree = snode->edittree;
- if (ntree) {
- bNode *node, *node_next;
- for (node = ntree->nodes.first; node; node = node_next) {
- node_next = node->next;
- if (node->flag & NODE_SELECT) {
- nodeRemoveNode(bmain, ntree, node, true);
- }
- }
- }
- }
-}
-
-static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
-{
- /* so automerge supports mirror */
- if ((t->scene->toolsettings->automerge) && ((t->flag & T_EDIT) && t->obedit_type == OB_MESH)) {
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
-
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- BMesh *bm = em->bm;
- char hflag;
- bool has_face_sel = (bm->totfacesel != 0);
-
- if (tc->mirror.axis_flag) {
- TransData *td;
- int i;
-
- /* Rather then adjusting the selection (which the user would notice)
- * tag all mirrored verts, then auto-merge those. */
- BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false);
-
- for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
- if (td->extra) {
- BM_elem_flag_enable((BMVert *)td->extra, BM_ELEM_TAG);
- }
- }
-
- hflag = BM_ELEM_SELECT | BM_ELEM_TAG;
- }
- else {
- hflag = BM_ELEM_SELECT;
- }
-
- EDBM_automerge(t->scene, tc->obedit, true, hflag);
-
- /* Special case, this is needed or faces won't re-select.
- * Flush selected edges to faces. */
- if (has_face_sel && (em->selectmode == SCE_SELECT_FACE)) {
- EDBM_selectmode_flush_ex(em, SCE_SELECT_EDGE);
- }
- }
- }
-}
-
-/* inserting keys, pointcache, redraw events... */
-/**
- * \note Sequencer freeing has its own function now because of a conflict
- * with transform's order of freeing (campbell).
- * Order changed, the sequencer stuff should go back in here
- */
-void special_aftertrans_update(bContext *C, TransInfo *t)
-{
- Main *bmain = CTX_data_main(t->context);
- BLI_assert(bmain == CTX_data_main(C));
-
- Object *ob;
- // short redrawipo=0, resetslowpar=1;
- const bool canceled = (t->state == TRANS_CANCEL);
- const bool duplicate = (t->mode == TFM_TIME_DUPLICATE);
-
- /* early out when nothing happened */
- if (t->data_len_all == 0 || t->mode == TFM_DUMMY) {
- return;
- }
-
- if (t->spacetype == SPACE_VIEW3D) {
- if (t->flag & T_EDIT) {
- /* Special Exception:
- * We don't normally access 't->custom.mode' here, but its needed in this case. */
-
- if (canceled == 0) {
- /* we need to delete the temporary faces before automerging */
- if (t->mode == TFM_EDGE_SLIDE) {
- /* handle multires re-projection, done
- * on transform completion since it's
- * really slow -joeedh */
- projectEdgeSlideData(t, true);
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- EdgeSlideData *sld = tc->custom.mode.data;
-
- if (sld == NULL) {
- continue;
- }
-
- /* Free temporary faces to avoid auto-merging and deleting
- * during cleanup - psy-fi. */
- freeEdgeSlideTempFaces(sld);
- }
- }
- else if (t->mode == TFM_VERT_SLIDE) {
- /* as above */
- projectVertSlideData(t, true);
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- VertSlideData *sld = tc->custom.mode.data;
- freeVertSlideTempFaces(sld);
- }
- }
-
- if (t->obedit_type == OB_MESH) {
- special_aftertrans_update__mesh(C, t);
- }
- }
- else {
- if (t->mode == TFM_EDGE_SLIDE) {
- EdgeSlideParams *slp = t->custom.mode.data;
- slp->perc = 0.0;
- projectEdgeSlideData(t, false);
- }
- else if (t->mode == TFM_VERT_SLIDE) {
- EdgeSlideParams *slp = t->custom.mode.data;
- slp->perc = 0.0;
- projectVertSlideData(t, false);
- }
- }
- }
- }
-
- if (t->options & CTX_GPENCIL_STROKES) {
- /* pass */
- }
- else if (t->spacetype == SPACE_SEQ) {
- /* freeSeqData in transform_conversions.c does this
- * keep here so the else at the end wont run... */
-
- SpaceSeq *sseq = (SpaceSeq *)t->sa->spacedata.first;
-
- /* marker transform, not especially nice but we may want to move markers
- * at the same time as keyframes in the dope sheet. */
- if ((sseq->flag & SEQ_MARKER_TRANS) && (canceled == 0)) {
- /* cant use TFM_TIME_EXTEND
- * for some reason EXTEND is changed into TRANSLATE, so use frame_side instead */
-
- if (t->mode == TFM_SEQ_SLIDE) {
- if (t->frame_side == 'B') {
- ED_markers_post_apply_transform(
- &t->scene->markers, t->scene, TFM_TIME_TRANSLATE, t->values[0], t->frame_side);
- }
- }
- else if (ELEM(t->frame_side, 'L', 'R')) {
- ED_markers_post_apply_transform(
- &t->scene->markers, t->scene, TFM_TIME_EXTEND, t->values[0], t->frame_side);
- }
- }
- }
- else if (t->spacetype == SPACE_IMAGE) {
- if (t->options & CTX_MASK) {
- special_aftertrans_update__mask(C, t);
- }
- }
- else if (t->spacetype == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
- special_aftertrans_update__node(C, t);
- if (canceled == 0) {
- ED_node_post_apply_transform(C, snode->edittree);
-
- ED_node_link_insert(bmain, t->sa);
- }
-
- /* clear link line */
- ED_node_link_intersect_test(t->sa, 0);
- }
- else if (t->spacetype == SPACE_CLIP) {
- if (t->options & CTX_MOVIECLIP) {
- special_aftertrans_update__movieclip(C, t);
- }
- else if (t->options & CTX_MASK) {
- special_aftertrans_update__mask(C, t);
- }
- }
- else if (t->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
- bAnimContext ac;
-
- /* initialize relevant anim-context 'context' data */
- if (ANIM_animdata_get_context(C, &ac) == 0) {
- return;
- }
-
- ob = ac.obact;
-
- if (ELEM(ac.datatype, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY, ANIMCONT_TIMELINE)) {
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
-
- /* get channels to work on */
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- /* these should all be F-Curves */
- for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
- FCurve *fcu = (FCurve *)ale->key_data;
-
- /* 3 cases here for curve cleanups:
- * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
- * 2) canceled == 0 -> user confirmed the transform,
- * so duplicates should be removed
- * 3) canceled + duplicate -> user canceled the transform,
- * but we made duplicates, so get rid of these
- */
- if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
- if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
- posttrans_fcurve_clean(fcu, false); /* only use handles in graph editor */
- ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
- }
- else {
- posttrans_fcurve_clean(fcu, false); /* only use handles in graph editor */
- }
- }
- }
-
- /* free temp memory */
- ANIM_animdata_freelist(&anim_data);
- }
- else if (ac.datatype == ANIMCONT_ACTION) { // TODO: just integrate into the above...
- /* Depending on the lock status, draw necessary views */
- // fixme... some of this stuff is not good
- if (ob) {
- if (ob->pose || BKE_key_from_object(ob)) {
- DEG_id_tag_update(&ob->id,
- ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
- }
- else {
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
- }
- }
-
- /* 3 cases here for curve cleanups:
- * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
- * 2) canceled == 0 -> user confirmed the transform,
- * so duplicates should be removed.
- * 3) canceled + duplicate -> user canceled the transform,
- * but we made duplicates, so get rid of these.
- */
- if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
- posttrans_action_clean(&ac, (bAction *)ac.data);
- }
- }
- else if (ac.datatype == ANIMCONT_GPENCIL) {
- /* remove duplicate frames and also make sure points are in order! */
- /* 3 cases here for curve cleanups:
- * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
- * 2) canceled == 0 -> user confirmed the transform,
- * so duplicates should be removed
- * 3) canceled + duplicate -> user canceled the transform,
- * but we made duplicates, so get rid of these
- */
- if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
- bGPdata *gpd;
-
- // XXX: BAD! this get gpencil datablocks directly from main db...
- // but that's how this currently works :/
- for (gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) {
- if (ID_REAL_USERS(gpd)) {
- posttrans_gpd_clean(gpd);
- }
- }
- }
- }
- else if (ac.datatype == ANIMCONT_MASK) {
- /* remove duplicate frames and also make sure points are in order! */
- /* 3 cases here for curve cleanups:
- * 1) NOTRANSKEYCULL on:
- * Cleanup of duplicates shouldn't be done.
- * 2) canceled == 0:
- * User confirmed the transform, so duplicates should be removed.
- * 3) Canceled + duplicate:
- * User canceled the transform, but we made duplicates, so get rid of these.
- */
- if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
- Mask *mask;
-
- // XXX: BAD! this get gpencil datablocks directly from main db...
- // but that's how this currently works :/
- for (mask = bmain->masks.first; mask; mask = mask->id.next) {
- if (ID_REAL_USERS(mask)) {
- posttrans_mask_clean(mask);
- }
- }
- }
- }
-
- /* marker transform, not especially nice but we may want to move markers
- * at the same time as keyframes in the dope sheet.
- */
- if ((saction->flag & SACTION_MARKERS_MOVE) && (canceled == 0)) {
- if (t->mode == TFM_TIME_TRANSLATE) {
-#if 0
- if (ELEM(t->frame_side, 'L', 'R')) { /* TFM_TIME_EXTEND */
- /* same as below */
- ED_markers_post_apply_transform(
- ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side);
- }
- else /* TFM_TIME_TRANSLATE */
-#endif
- {
- ED_markers_post_apply_transform(
- ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side);
- }
- }
- else if (t->mode == TFM_TIME_SCALE) {
- ED_markers_post_apply_transform(
- ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side);
- }
- }
-
- /* make sure all F-Curves are set correctly */
- if (!ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- ANIM_editkeyframes_refresh(&ac);
- }
-
- /* clear flag that was set for time-slide drawing */
- saction->flag &= ~SACTION_MOVING;
- }
- else if (t->spacetype == SPACE_GRAPH) {
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
- bAnimContext ac;
- const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
-
- /* initialize relevant anim-context 'context' data */
- if (ANIM_animdata_get_context(C, &ac) == 0) {
- return;
- }
-
- if (ac.datatype) {
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
-
- /* get channels to work on */
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
- FCurve *fcu = (FCurve *)ale->key_data;
-
- /* 3 cases here for curve cleanups:
- * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
- * 2) canceled == 0 -> user confirmed the transform,
- * so duplicates should be removed
- * 3) canceled + duplicate -> user canceled the transform,
- * but we made duplicates, so get rid of these
- */
- if ((sipo->flag & SIPO_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
- if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
- posttrans_fcurve_clean(fcu, use_handle);
- ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
- }
- else {
- posttrans_fcurve_clean(fcu, use_handle);
- }
- }
- }
-
- /* free temp memory */
- ANIM_animdata_freelist(&anim_data);
- }
-
- /* Make sure all F-Curves are set correctly, but not if transform was
- * canceled, since then curves were already restored to initial state.
- * Note: if the refresh is really needed after cancel then some way
- * has to be added to not update handle types (see bug 22289).
- */
- if (!canceled) {
- ANIM_editkeyframes_refresh(&ac);
- }
- }
- else if (t->spacetype == SPACE_NLA) {
- bAnimContext ac;
-
- /* initialize relevant anim-context 'context' data */
- if (ANIM_animdata_get_context(C, &ac) == 0) {
- return;
- }
-
- if (ac.datatype) {
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT);
-
- /* get channels to work on */
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- for (ale = anim_data.first; ale; ale = ale->next) {
- NlaTrack *nlt = (NlaTrack *)ale->data;
-
- /* make sure strips are in order again */
- BKE_nlatrack_sort_strips(nlt);
-
- /* remove the temp metas */
- BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
- }
-
- /* free temp memory */
- ANIM_animdata_freelist(&anim_data);
-
- /* perform after-transfrom validation */
- ED_nla_postop_refresh(&ac);
- }
- }
- else if (t->flag & T_EDIT) {
- if (t->obedit_type == OB_MESH) {
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- /* table needs to be created for each edit command, since vertices can move etc */
- ED_mesh_mirror_spatial_table(tc->obedit, em, NULL, NULL, 'e');
- /* TODO(campbell): xform: We need support for many mirror objects at once! */
- break;
- }
- }
- }
- else if (t->flag & T_POSE && (t->mode == TFM_BONESIZE)) {
- /* Handle the exception where for TFM_BONESIZE in edit mode we pretend to be
- * in pose mode (to use bone orientation matrix),
- * in that case we don't do operations like autokeyframing. */
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- ob = tc->poseobj;
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
- }
- else if (t->flag & T_POSE) {
- GSet *motionpath_updates = BLI_gset_ptr_new("motionpath updates");
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
-
- bPoseChannel *pchan;
- short targetless_ik = 0;
-
- ob = tc->poseobj;
-
- if ((t->flag & T_AUTOIK) && (t->options & CTX_AUTOCONFIRM)) {
- /* when running transform non-interactively (operator exec),
- * we need to update the pose otherwise no updates get called during
- * transform and the auto-ik is not applied. see [#26164] */
- struct Object *pose_ob = tc->poseobj;
- BKE_pose_where_is(t->depsgraph, t->scene, pose_ob);
- }
-
- /* set BONE_TRANSFORM flags for autokey, gizmo draw might have changed them */
- if (!canceled && (t->mode != TFM_DUMMY)) {
- count_set_pose_transflags(ob, t->mode, t->around, NULL);
- }
-
- /* if target-less IK grabbing, we calculate the pchan transforms and clear flag */
- if (!canceled && t->mode == TFM_TRANSLATION) {
- targetless_ik = apply_targetless_ik(ob);
- }
- else {
- /* not forget to clear the auto flag */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- bKinematicConstraint *data = has_targetless_ik(pchan);
- if (data) {
- data->flag &= ~CONSTRAINT_IK_AUTO;
- }
- }
- }
-
- if (t->mode == TFM_TRANSLATION) {
- pose_grab_with_ik_clear(bmain, ob);
- }
-
- /* automatic inserting of keys and unkeyed tagging -
- * only if transform wasn't canceled (or TFM_DUMMY) */
- if (!canceled && (t->mode != TFM_DUMMY)) {
- autokeyframe_pose(C, t->scene, ob, t->mode, targetless_ik);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
- else {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
-
- if (t->mode != TFM_DUMMY && motionpath_need_update_pose(t->scene, ob)) {
- BLI_gset_insert(motionpath_updates, ob);
- }
- }
-
- /* Update motion paths once for all transformed bones in an object. */
- GSetIterator gs_iter;
- GSET_ITER (gs_iter, motionpath_updates) {
- bool current_frame_only = canceled;
- ob = BLI_gsetIterator_getKey(&gs_iter);
- ED_pose_recalculate_paths(C, t->scene, ob, current_frame_only);
- }
- BLI_gset_free(motionpath_updates, NULL);
- }
- else if (t->options & CTX_PAINT_CURVE) {
- /* pass */
- }
- else if ((t->view_layer->basact) && (ob = t->view_layer->basact->object) &&
- (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->scene, ob)) {
- /* do nothing */
- }
- else if (t->flag & T_CURSOR) {
- /* do nothing */
- }
- else { /* Objects */
- BLI_assert(t->flag & (T_OBJECT | T_TEXTURE));
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
- bool motionpath_update = false;
-
- for (int i = 0; i < tc->data_len; i++) {
- TransData *td = tc->data + i;
- ListBase pidlist;
- PTCacheID *pid;
- ob = td->ob;
-
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- /* flag object caches as outdated */
- BKE_ptcache_ids_from_object(&pidlist, ob, t->scene, MAX_DUPLI_RECUR);
- for (pid = pidlist.first; pid; pid = pid->next) {
- if (pid->type != PTCACHE_TYPE_PARTICLES) {
- /* particles don't need reset on geometry change */
- pid->cache->flag |= PTCACHE_OUTDATED;
- }
- }
- BLI_freelistN(&pidlist);
-
- /* pointcache refresh */
- if (BKE_ptcache_object_reset(t->scene, ob, PTCACHE_RESET_OUTDATED)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
-
- /* Needed for proper updating of "quick cached" dynamics. */
- /* Creates troubles for moving animated objects without */
- /* autokey though, probably needed is an anim sys override? */
- /* Please remove if some other solution is found. -jahka */
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
-
- /* Set autokey if necessary */
- if (!canceled) {
- autokeyframe_object(C, t->scene, t->view_layer, ob, t->mode);
- }
-
- motionpath_update |= motionpath_need_update_object(t->scene, ob);
-
- /* restore rigid body transform */
- if (ob->rigidbody_object && canceled) {
- float ctime = BKE_scene_frame_get(t->scene);
- if (BKE_rigidbody_check_sim_running(t->scene->rigidbody_world, ctime)) {
- BKE_rigidbody_aftertrans_update(ob,
- td->ext->oloc,
- td->ext->orot,
- td->ext->oquat,
- td->ext->orotAxis,
- td->ext->orotAngle);
- }
- }
- }
-
- if (motionpath_update) {
- /* Update motion paths once for all transformed objects. */
- bool current_frame_only = canceled;
- ED_objects_recalculate_paths(C, t->scene, current_frame_only);
- }
- }
-
- clear_trans_object_base_flags(t);
-}
-
-int special_transform_moving(TransInfo *t)
-{
- if (t->spacetype == SPACE_SEQ) {
- return G_TRANSFORM_SEQ;
- }
- else if (t->spacetype == SPACE_GRAPH) {
- return G_TRANSFORM_FCURVES;
- }
- else if ((t->flag & T_EDIT) || (t->flag & T_POSE)) {
- return G_TRANSFORM_EDIT;
- }
- else if (t->flag & (T_OBJECT | T_TEXTURE)) {
- return G_TRANSFORM_OBJ;
- }
-
- return 0;
-}
-
-/* -------------------------------------------------------------------- */
-/** \name Object Data in Object Mode
- *
- * Use to implement 'Affect Only Origins' feature.
- * We need this to be detached from transform data because,
- * unlike transforming regular objects, we need to transform the children.
- *
- * \{ */
-
-struct XFormObjectData_Extra {
- Object *ob;
- float obmat_orig[4][4];
- bool ob_dtx_axis_orig;
- struct XFormObjectData *xod;
-};
-
-static void trans_obdata_in_obmode_ensure_object(TransInfo *t, Object *ob)
-{
- if (t->obdata_in_obmode_map == NULL) {
- t->obdata_in_obmode_map = BLI_ghash_ptr_new(__func__);
- }
-
- void **xf_p;
- if (!BLI_ghash_ensure_p(t->obdata_in_obmode_map, ob->data, &xf_p)) {
- struct XFormObjectData_Extra *xf = MEM_mallocN(sizeof(*xf), __func__);
- copy_m4_m4(xf->obmat_orig, ob->obmat);
- xf->ob = ob;
- /* Result may be NULL, that's OK. */
- xf->xod = ED_object_data_xform_create(ob->data);
- if (xf->xod) {
- xf->ob_dtx_axis_orig = ob->dtx & OB_AXIS;
- ob->dtx |= OB_AXIS;
- }
- *xf_p = xf;
- }
-}
-
-void trans_obdata_in_obmode_update_all(TransInfo *t)
-{
- struct Main *bmain = CTX_data_main(t->context);
- BKE_scene_graph_evaluated_ensure(t->depsgraph, bmain);
-
- GHashIterator gh_iter;
- GHASH_ITER (gh_iter, t->obdata_in_obmode_map) {
- ID *id = BLI_ghashIterator_getKey(&gh_iter);
- struct XFormObjectData_Extra *xf = BLI_ghashIterator_getValue(&gh_iter);
- if (xf->xod == NULL) {
- continue;
- }
-
- Object *ob_eval = DEG_get_evaluated_object(t->depsgraph, xf->ob);
- float imat[4][4], dmat[4][4];
- invert_m4_m4(imat, xf->obmat_orig);
- mul_m4_m4m4(dmat, imat, ob_eval->obmat);
- invert_m4(dmat);
-
- ED_object_data_xform_by_mat4(xf->xod, dmat);
- DEG_id_tag_update(id, 0);
- }
-}
-
-/** Callback for #GHash free. */
-static void trans_obdata_in_obmode_free_elem(void *xf_p)
-{
- struct XFormObjectData_Extra *xf = xf_p;
- if (xf->xod) {
- if (!xf->ob_dtx_axis_orig) {
- xf->ob->dtx &= ~OB_AXIS;
- DEG_id_tag_update(&xf->ob->id, ID_RECALC_COPY_ON_WRITE);
- }
- ED_object_data_xform_destroy(xf->xod);
- }
- MEM_freeN(xf);
-}
-
-void trans_obdata_in_obmode_free_all(TransInfo *t)
-{
- if (t->obdata_in_obmode_map != NULL) {
- BLI_ghash_free(t->obdata_in_obmode_map, NULL, trans_obdata_in_obmode_free_elem);
- }
-}
-
-/** \} */
-
-static void createTransObject(bContext *C, TransInfo *t)
-{
- TransData *td = NULL;
- TransDataExtension *tx;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
-
- set_trans_object_base_flags(t);
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* count */
- tc->data_len = CTX_DATA_COUNT(C, selected_bases);
-
- if (!tc->data_len) {
- /* clear here, main transform function escapes too */
- clear_trans_object_base_flags(t);
- return;
- }
-
- if (is_prop_edit) {
- tc->data_len += count_proportional_objects(t);
- }
-
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransOb");
- tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), "TransObExtension");
-
- CTX_DATA_BEGIN (C, Base *, base, selected_bases) {
- Object *ob = base->object;
-
- td->flag = TD_SELECTED;
- td->protectflag = ob->protectflag;
- td->ext = tx;
- td->ext->rotOrder = ob->rotmode;
-
- if (base->flag & BA_TRANSFORM_CHILD) {
- td->flag |= TD_NOCENTER;
- td->flag |= TD_NO_LOC;
- }
-
- /* select linked objects, but skip them later */
- if (ID_IS_LINKED(ob)) {
- td->flag |= TD_SKIP;
- }
-
- if (t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) {
- ID *id = ob->data;
- if (!id || id->lib) {
- td->flag |= TD_SKIP;
- }
- else if (BKE_object_is_in_editmode(ob)) {
- /* The object could have edit-mode data from another view-layer,
- * it's such a corner-case it can be skipped for now - Campbell. */
- td->flag |= TD_SKIP;
- }
- }
-
- if (t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) {
- if ((td->flag & TD_SKIP) == 0) {
- trans_obdata_in_obmode_ensure_object(t, ob);
- }
- }
-
- ObjectToTransData(t, td, ob);
- td->val = NULL;
- td++;
- tx++;
- }
- CTX_DATA_END;
-
- if (is_prop_edit) {
- ViewLayer *view_layer = t->view_layer;
- View3D *v3d = t->view;
- Base *base;
-
- for (base = view_layer->object_bases.first; base; base = base->next) {
- Object *ob = base->object;
-
- /* if base is not selected, not a parent of selection
- * or not a child of selection and it is editable and selectable */
- if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
- (base->flag & BASE_SELECTED) == 0 && BASE_EDITABLE(v3d, base) &&
- BASE_SELECTABLE(v3d, base)) {
- td->protectflag = ob->protectflag;
- td->ext = tx;
- td->ext->rotOrder = ob->rotmode;
-
- ObjectToTransData(t, td, ob);
- td->val = NULL;
- td++;
- tx++;
- }
- }
- }
-
- if (t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) {
- GSet *objects_in_transdata = BLI_gset_ptr_new_ex(__func__, tc->data_len);
- td = tc->data;
- for (int i = 0; i < tc->data_len; i++, td++) {
- if ((td->flag & TD_SKIP) == 0) {
- BLI_gset_add(objects_in_transdata, td->ob);
- }
- }
-
- ViewLayer *view_layer = t->view_layer;
- View3D *v3d = t->view;
-
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- Object *ob = base->object;
-
- /* if base is not selected, not a parent of selection
- * or not a child of selection and it is editable and selectable */
- if ((base->flag & BASE_SELECTED) == 0 && BASE_EDITABLE(v3d, base) &&
- BASE_SELECTABLE(v3d, base)) {
-
- Object *ob_parent = ob->parent;
- if (ob_parent != NULL) {
- if (!BLI_gset_haskey(objects_in_transdata, ob)) {
- bool parent_in_transdata = false;
- while (ob_parent != NULL) {
- if (BLI_gset_haskey(objects_in_transdata, ob_parent)) {
- parent_in_transdata = true;
- break;
- }
- ob_parent = ob_parent->parent;
- }
- if (parent_in_transdata) {
- trans_obdata_in_obmode_ensure_object(t, ob);
- }
- }
- }
- }
- }
- BLI_gset_free(objects_in_transdata, NULL);
- }
-}
-
-/* transcribe given node into TransData2D for Transforming */
-static void NodeToTransData(TransData *td, TransData2D *td2d, bNode *node, const float dpi_fac)
-{
- float locx, locy;
-
- /* account for parents (nested nodes) */
- if (node->parent) {
- nodeToView(node->parent, node->locx, node->locy, &locx, &locy);
- }
- else {
- locx = node->locx;
- locy = node->locy;
- }
-
- /* use top-left corner as the transform origin for nodes */
- /* weirdo - but the node system is a mix of free 2d elements and dpi sensitive UI */
-#ifdef USE_NODE_CENTER
- td2d->loc[0] = (locx * dpi_fac) + (BLI_rctf_size_x(&node->totr) * +0.5f);
- td2d->loc[1] = (locy * dpi_fac) + (BLI_rctf_size_y(&node->totr) * -0.5f);
-#else
- td2d->loc[0] = locx * dpi_fac;
- td2d->loc[1] = locy * dpi_fac;
-#endif
- td2d->loc[2] = 0.0f;
- td2d->loc2d = td2d->loc; /* current location */
-
- td->flag = 0;
-
- td->loc = td2d->loc;
- copy_v3_v3(td->iloc, td->loc);
- /* use node center instead of origin (top-left corner) */
- td->center[0] = td2d->loc[0];
- td->center[1] = td2d->loc[1];
- td->center[2] = 0.0f;
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
-
- td->flag |= TD_SELECTED;
- td->dist = 0.0;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-
- td->extra = node;
-}
-
-static bool is_node_parent_select(bNode *node)
-{
- while ((node = node->parent)) {
- if (node->flag & NODE_TRANSFORM) {
- return true;
- }
- }
- return false;
-}
-
-static void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
-{
- const float dpi_fac = UI_DPI_FAC;
- TransData *td;
- TransData2D *td2d;
- SpaceNode *snode = t->sa->spacedata.first;
- bNode *node;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- tc->data_len = 0;
-
- if (!snode->edittree) {
- return;
- }
-
- /* nodes dont support PET and probably never will */
- t->flag &= ~T_PROP_EDIT_ALL;
-
- /* set transform flags on nodes */
- for (node = snode->edittree->nodes.first; node; node = node->next) {
- if (node->flag & NODE_SELECT && is_node_parent_select(node) == false) {
- node->flag |= NODE_TRANSFORM;
- tc->data_len++;
- }
- else {
- node->flag &= ~NODE_TRANSFORM;
- }
- }
-
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransNode TransData");
- td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransNode TransData2D");
-
- for (node = snode->edittree->nodes.first; node; node = node->next) {
- if (node->flag & NODE_TRANSFORM) {
- NodeToTransData(td++, td2d++, node, dpi_fac);
- }
- }
-}
-
-/* *** CLIP EDITOR *** */
-
-/* * motion tracking * */
-
-enum transDataTracking_Mode {
- transDataTracking_ModeTracks = 0,
- transDataTracking_ModeCurves = 1,
- transDataTracking_ModePlaneTracks = 2,
-};
-
-typedef struct TransDataTracking {
- int mode, flag;
-
- /* tracks transformation from main window */
- int area;
- const float *relative, *loc;
- float soffset[2], srelative[2];
- float offset[2];
-
- float (*smarkers)[2];
- int markersnr;
- MovieTrackingMarker *markers;
-
- /* marker transformation from curves editor */
- float *prev_pos, scale;
- short coord;
-
- MovieTrackingTrack *track;
- MovieTrackingPlaneTrack *plane_track;
-} TransDataTracking;
-
-static void markerToTransDataInit(TransData *td,
- TransData2D *td2d,
- TransDataTracking *tdt,
- MovieTrackingTrack *track,
- MovieTrackingMarker *marker,
- int area,
- float loc[2],
- float rel[2],
- const float off[2],
- const float aspect[2])
-{
- int anchor = area == TRACK_AREA_POINT && off;
-
- tdt->mode = transDataTracking_ModeTracks;
-
- if (anchor) {
- td2d->loc[0] = rel[0] * aspect[0]; /* hold original location */
- td2d->loc[1] = rel[1] * aspect[1];
-
- tdt->loc = loc;
- td2d->loc2d = loc; /* current location */
- }
- else {
- td2d->loc[0] = loc[0] * aspect[0]; /* hold original location */
- td2d->loc[1] = loc[1] * aspect[1];
-
- td2d->loc2d = loc; /* current location */
- }
- td2d->loc[2] = 0.0f;
-
- tdt->relative = rel;
- tdt->area = area;
-
- tdt->markersnr = track->markersnr;
- tdt->markers = track->markers;
- tdt->track = track;
-
- if (rel) {
- if (!anchor) {
- td2d->loc[0] += rel[0] * aspect[0];
- td2d->loc[1] += rel[1] * aspect[1];
- }
-
- copy_v2_v2(tdt->srelative, rel);
- }
-
- if (off) {
- copy_v2_v2(tdt->soffset, off);
- }
-
- td->flag = 0;
- td->loc = td2d->loc;
- copy_v3_v3(td->iloc, td->loc);
-
- // copy_v3_v3(td->center, td->loc);
- td->flag |= TD_INDIVIDUAL_SCALE;
- td->center[0] = marker->pos[0] * aspect[0];
- td->center[1] = marker->pos[1] * aspect[1];
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
-
- td->flag |= TD_SELECTED;
- td->dist = 0.0;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-}
-
-static void trackToTransData(const int framenr,
- TransData *td,
- TransData2D *td2d,
- TransDataTracking *tdt,
- MovieTrackingTrack *track,
- const float aspect[2])
-{
- MovieTrackingMarker *marker = BKE_tracking_marker_ensure(track, framenr);
-
- tdt->flag = marker->flag;
- marker->flag &= ~(MARKER_DISABLED | MARKER_TRACKED);
-
- markerToTransDataInit(td++,
- td2d++,
- tdt++,
- track,
- marker,
- TRACK_AREA_POINT,
- track->offset,
- marker->pos,
- track->offset,
- aspect);
-
- if (track->flag & SELECT) {
- markerToTransDataInit(
- td++, td2d++, tdt++, track, marker, TRACK_AREA_POINT, marker->pos, NULL, NULL, aspect);
- }
-
- if (track->pat_flag & SELECT) {
- int a;
-
- for (a = 0; a < 4; a++) {
- markerToTransDataInit(td++,
- td2d++,
- tdt++,
- track,
- marker,
- TRACK_AREA_PAT,
- marker->pattern_corners[a],
- marker->pos,
- NULL,
- aspect);
- }
- }
-
- if (track->search_flag & SELECT) {
- markerToTransDataInit(td++,
- td2d++,
- tdt++,
- track,
- marker,
- TRACK_AREA_SEARCH,
- marker->search_min,
- marker->pos,
- NULL,
- aspect);
-
- markerToTransDataInit(td++,
- td2d++,
- tdt++,
- track,
- marker,
- TRACK_AREA_SEARCH,
- marker->search_max,
- marker->pos,
- NULL,
- aspect);
- }
-}
-
-static void planeMarkerToTransDataInit(TransData *td,
- TransData2D *td2d,
- TransDataTracking *tdt,
- MovieTrackingPlaneTrack *plane_track,
- float corner[2],
- const float aspect[2])
-{
- tdt->mode = transDataTracking_ModePlaneTracks;
- tdt->plane_track = plane_track;
-
- td2d->loc[0] = corner[0] * aspect[0]; /* hold original location */
- td2d->loc[1] = corner[1] * aspect[1];
-
- td2d->loc2d = corner; /* current location */
- td2d->loc[2] = 0.0f;
-
- td->flag = 0;
- td->loc = td2d->loc;
- copy_v3_v3(td->iloc, td->loc);
- copy_v3_v3(td->center, td->loc);
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
-
- td->flag |= TD_SELECTED;
- td->dist = 0.0;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-}
-
-static void planeTrackToTransData(const int framenr,
- TransData *td,
- TransData2D *td2d,
- TransDataTracking *tdt,
- MovieTrackingPlaneTrack *plane_track,
- const float aspect[2])
-{
- MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr);
- int i;
-
- tdt->flag = plane_marker->flag;
- plane_marker->flag &= ~PLANE_MARKER_TRACKED;
-
- for (i = 0; i < 4; i++) {
- planeMarkerToTransDataInit(td++, td2d++, tdt++, plane_track, plane_marker->corners[i], aspect);
- }
-}
-
-static void transDataTrackingFree(TransInfo *UNUSED(t),
- TransDataContainer *UNUSED(tc),
- TransCustomData *custom_data)
-{
- if (custom_data->data) {
- TransDataTracking *tdt = custom_data->data;
- if (tdt->smarkers) {
- MEM_freeN(tdt->smarkers);
- }
-
- MEM_freeN(tdt);
- custom_data->data = NULL;
- }
-}
-
-static void createTransTrackingTracksData(bContext *C, TransInfo *t)
-{
- TransData *td;
- TransData2D *td2d;
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
- ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
- MovieTrackingTrack *track;
- MovieTrackingPlaneTrack *plane_track;
- TransDataTracking *tdt;
- int framenr = ED_space_clip_get_clip_frame_number(sc);
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* count */
- tc->data_len = 0;
-
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
- tc->data_len++; /* offset */
-
- if (track->flag & SELECT) {
- tc->data_len++;
- }
-
- if (track->pat_flag & SELECT) {
- tc->data_len += 4;
- }
-
- if (track->search_flag & SELECT) {
- tc->data_len += 2;
- }
- }
-
- track = track->next;
- }
-
- for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
- if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
- tc->data_len += 4;
- }
- }
-
- if (tc->data_len == 0) {
- return;
- }
-
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransTracking TransData");
- td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D),
- "TransTracking TransData2D");
- tdt = tc->custom.type.data = MEM_callocN(tc->data_len * sizeof(TransDataTracking),
- "TransTracking TransDataTracking");
-
- tc->custom.type.free_cb = transDataTrackingFree;
-
- /* create actual data */
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
- trackToTransData(framenr, td, td2d, tdt, track, t->aspect);
-
- /* offset */
- td++;
- td2d++;
- tdt++;
-
- if (track->flag & SELECT) {
- td++;
- td2d++;
- tdt++;
- }
-
- if (track->pat_flag & SELECT) {
- td += 4;
- td2d += 4;
- tdt += 4;
- }
-
- if (track->search_flag & SELECT) {
- td += 2;
- td2d += 2;
- tdt += 2;
- }
- }
-
- track = track->next;
- }
-
- for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
- if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
- planeTrackToTransData(framenr, td, td2d, tdt, plane_track, t->aspect);
- td += 4;
- td2d += 4;
- tdt += 4;
- }
- }
-}
-
-static void markerToTransCurveDataInit(TransData *td,
- TransData2D *td2d,
- TransDataTracking *tdt,
- MovieTrackingTrack *track,
- MovieTrackingMarker *marker,
- MovieTrackingMarker *prev_marker,
- short coord,
- float size)
-{
- float frames_delta = (marker->framenr - prev_marker->framenr);
-
- tdt->flag = marker->flag;
- marker->flag &= ~MARKER_TRACKED;
-
- tdt->mode = transDataTracking_ModeCurves;
- tdt->coord = coord;
- tdt->scale = 1.0f / size * frames_delta;
- tdt->prev_pos = prev_marker->pos;
- tdt->track = track;
-
- /* calculate values depending on marker's speed */
- td2d->loc[0] = marker->framenr;
- td2d->loc[1] = (marker->pos[coord] - prev_marker->pos[coord]) * size / frames_delta;
- td2d->loc[2] = 0.0f;
-
- td2d->loc2d = marker->pos; /* current location */
-
- td->flag = 0;
- td->loc = td2d->loc;
- copy_v3_v3(td->center, td->loc);
- copy_v3_v3(td->iloc, td->loc);
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
-
- td->flag |= TD_SELECTED;
- td->dist = 0.0;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-}
-
-static void createTransTrackingCurvesData(bContext *C, TransInfo *t)
-{
- TransData *td;
- TransData2D *td2d;
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
- MovieTrackingTrack *track;
- MovieTrackingMarker *marker, *prev_marker;
- TransDataTracking *tdt;
- int i, width, height;
-
- BKE_movieclip_get_size(clip, &sc->user, &width, &height);
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* count */
- tc->data_len = 0;
-
- if ((sc->flag & SC_SHOW_GRAPH_TRACKS_MOTION) == 0) {
- return;
- }
-
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
- for (i = 1; i < track->markersnr; i++) {
- marker = &track->markers[i];
- prev_marker = &track->markers[i - 1];
-
- if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) {
- continue;
- }
-
- if (marker->flag & MARKER_GRAPH_SEL_X) {
- tc->data_len += 1;
- }
-
- if (marker->flag & MARKER_GRAPH_SEL_Y) {
- tc->data_len += 1;
- }
- }
- }
-
- track = track->next;
- }
-
- if (tc->data_len == 0) {
- return;
- }
-
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransTracking TransData");
- td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D),
- "TransTracking TransData2D");
- tc->custom.type.data = tdt = MEM_callocN(tc->data_len * sizeof(TransDataTracking),
- "TransTracking TransDataTracking");
- tc->custom.type.free_cb = transDataTrackingFree;
-
- /* create actual data */
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
- for (i = 1; i < track->markersnr; i++) {
- marker = &track->markers[i];
- prev_marker = &track->markers[i - 1];
-
- if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) {
- continue;
- }
-
- if (marker->flag & MARKER_GRAPH_SEL_X) {
- markerToTransCurveDataInit(
- td, td2d, tdt, track, marker, &track->markers[i - 1], 0, width);
- td += 1;
- td2d += 1;
- tdt += 1;
- }
-
- if (marker->flag & MARKER_GRAPH_SEL_Y) {
- markerToTransCurveDataInit(
- td, td2d, tdt, track, marker, &track->markers[i - 1], 1, height);
-
- td += 1;
- td2d += 1;
- tdt += 1;
- }
- }
- }
-
- track = track->next;
- }
-}
-
-static void createTransTrackingData(bContext *C, TransInfo *t)
-{
- ARegion *ar = CTX_wm_region(C);
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- int width, height;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- tc->data_len = 0;
-
- if (!clip) {
- return;
- }
-
- BKE_movieclip_get_size(clip, &sc->user, &width, &height);
-
- if (width == 0 || height == 0) {
- return;
- }
-
- if (ar->regiontype == RGN_TYPE_PREVIEW) {
- /* transformation was called from graph editor */
- createTransTrackingCurvesData(C, t);
- }
- else {
- createTransTrackingTracksData(C, t);
- }
-}
-
-static void cancelTransTracking(TransInfo *t)
-{
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
- SpaceClip *sc = t->sa->spacedata.first;
- int i, framenr = ED_space_clip_get_clip_frame_number(sc);
- TransDataTracking *tdt_array = tc->custom.type.data;
-
- i = 0;
- while (i < tc->data_len) {
- TransDataTracking *tdt = &tdt_array[i];
-
- if (tdt->mode == transDataTracking_ModeTracks) {
- MovieTrackingTrack *track = tdt->track;
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
-
- marker->flag = tdt->flag;
-
- if (track->flag & SELECT) {
- i++;
- }
-
- if (track->pat_flag & SELECT) {
- i += 4;
- }
-
- if (track->search_flag & SELECT) {
- i += 2;
- }
- }
- else if (tdt->mode == transDataTracking_ModeCurves) {
- MovieTrackingTrack *track = tdt->track;
- MovieTrackingMarker *marker, *prev_marker;
- int a;
-
- for (a = 1; a < track->markersnr; a++) {
- marker = &track->markers[a];
- prev_marker = &track->markers[a - 1];
-
- if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) {
- continue;
- }
-
- if (marker->flag & (MARKER_GRAPH_SEL_X | MARKER_GRAPH_SEL_Y)) {
- marker->flag = tdt->flag;
- }
- }
- }
- else if (tdt->mode == transDataTracking_ModePlaneTracks) {
- MovieTrackingPlaneTrack *plane_track = tdt->plane_track;
- MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr);
-
- plane_marker->flag = tdt->flag;
- i += 3;
- }
-
- i++;
- }
-}
-
-void flushTransTracking(TransInfo *t)
-{
- TransData *td;
- TransData2D *td2d;
- TransDataTracking *tdt;
- int a;
-
- if (t->state == TRANS_CANCEL) {
- cancelTransTracking(t);
- }
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = tc->data, td2d = tc->data_2d, tdt = tc->custom.type.data; a < tc->data_len;
- a++, td2d++, td++, tdt++) {
- if (tdt->mode == transDataTracking_ModeTracks) {
- float loc2d[2];
-
- if (t->mode == TFM_ROTATION && tdt->area == TRACK_AREA_SEARCH) {
- continue;
- }
-
- loc2d[0] = td2d->loc[0] / t->aspect[0];
- loc2d[1] = td2d->loc[1] / t->aspect[1];
-
- if (t->flag & T_ALT_TRANSFORM) {
- if (t->mode == TFM_RESIZE) {
- if (tdt->area != TRACK_AREA_PAT) {
- continue;
- }
- }
- else if (t->mode == TFM_TRANSLATION) {
- if (tdt->area == TRACK_AREA_POINT && tdt->relative) {
- float d[2], d2[2];
-
- if (!tdt->smarkers) {
- tdt->smarkers = MEM_callocN(sizeof(*tdt->smarkers) * tdt->markersnr,
- "flushTransTracking markers");
- for (a = 0; a < tdt->markersnr; a++) {
- copy_v2_v2(tdt->smarkers[a], tdt->markers[a].pos);
- }
- }
-
- sub_v2_v2v2(d, loc2d, tdt->soffset);
- sub_v2_v2(d, tdt->srelative);
-
- sub_v2_v2v2(d2, loc2d, tdt->srelative);
-
- for (a = 0; a < tdt->markersnr; a++) {
- add_v2_v2v2(tdt->markers[a].pos, tdt->smarkers[a], d2);
- }
-
- negate_v2_v2(td2d->loc2d, d);
- }
- }
- }
-
- if (tdt->area != TRACK_AREA_POINT || tdt->relative == NULL) {
- td2d->loc2d[0] = loc2d[0];
- td2d->loc2d[1] = loc2d[1];
-
- if (tdt->relative) {
- sub_v2_v2(td2d->loc2d, tdt->relative);
- }
- }
- }
- else if (tdt->mode == transDataTracking_ModeCurves) {
- td2d->loc2d[tdt->coord] = tdt->prev_pos[tdt->coord] + td2d->loc[1] * tdt->scale;
- }
- else if (tdt->mode == transDataTracking_ModePlaneTracks) {
- td2d->loc2d[0] = td2d->loc[0] / t->aspect[0];
- td2d->loc2d[1] = td2d->loc[1] / t->aspect[1];
- }
- }
-}
-
-/* * masking * */
-
-typedef struct TransDataMasking {
- bool is_handle;
-
- float handle[2], orig_handle[2];
- float vec[3][3];
- MaskSplinePoint *point;
- float parent_matrix[3][3];
- float parent_inverse_matrix[3][3];
- char orig_handle_type;
-
- eMaskWhichHandle which_handle;
-} TransDataMasking;
-
-static void MaskHandleToTransData(MaskSplinePoint *point,
- eMaskWhichHandle which_handle,
- TransData *td,
- TransData2D *td2d,
- TransDataMasking *tdm,
- const float asp[2],
- /*const*/ float parent_matrix[3][3],
- /*const*/ float parent_inverse_matrix[3][3])
-{
- BezTriple *bezt = &point->bezt;
- const bool is_sel_any = MASKPOINT_ISSEL_ANY(point);
-
- tdm->point = point;
- copy_m3_m3(tdm->vec, bezt->vec);
-
- tdm->is_handle = true;
- copy_m3_m3(tdm->parent_matrix, parent_matrix);
- copy_m3_m3(tdm->parent_inverse_matrix, parent_inverse_matrix);
-
- BKE_mask_point_handle(point, which_handle, tdm->handle);
- tdm->which_handle = which_handle;
-
- copy_v2_v2(tdm->orig_handle, tdm->handle);
-
- mul_v2_m3v2(td2d->loc, parent_matrix, tdm->handle);
- td2d->loc[0] *= asp[0];
- td2d->loc[1] *= asp[1];
- td2d->loc[2] = 0.0f;
-
- td2d->loc2d = tdm->handle;
-
- td->flag = 0;
- td->loc = td2d->loc;
- mul_v2_m3v2(td->center, parent_matrix, bezt->vec[1]);
- td->center[0] *= asp[0];
- td->center[1] *= asp[1];
- copy_v3_v3(td->iloc, td->loc);
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
-
- if (is_sel_any) {
- td->flag |= TD_SELECTED;
- }
-
- td->dist = 0.0;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-
- if (which_handle == MASK_WHICH_HANDLE_LEFT) {
- tdm->orig_handle_type = bezt->h1;
- }
- else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
- tdm->orig_handle_type = bezt->h2;
- }
-}
-
-static void MaskPointToTransData(Scene *scene,
- MaskSplinePoint *point,
- TransData *td,
- TransData2D *td2d,
- TransDataMasking *tdm,
- const bool is_prop_edit,
- const float asp[2])
-{
- BezTriple *bezt = &point->bezt;
- const bool is_sel_point = MASKPOINT_ISSEL_KNOT(point);
- const bool is_sel_any = MASKPOINT_ISSEL_ANY(point);
- float parent_matrix[3][3], parent_inverse_matrix[3][3];
-
- BKE_mask_point_parent_matrix_get(point, CFRA, parent_matrix);
- invert_m3_m3(parent_inverse_matrix, parent_matrix);
-
- if (is_prop_edit || is_sel_point) {
- int i;
-
- tdm->point = point;
- copy_m3_m3(tdm->vec, bezt->vec);
-
- for (i = 0; i < 3; i++) {
- copy_m3_m3(tdm->parent_matrix, parent_matrix);
- copy_m3_m3(tdm->parent_inverse_matrix, parent_inverse_matrix);
-
- /* CV coords are scaled by aspects. this is needed for rotations and
- * proportional editing to be consistent with the stretched CV coords
- * that are displayed. this also means that for display and numinput,
- * and when the CV coords are flushed, these are converted each time */
- mul_v2_m3v2(td2d->loc, parent_matrix, bezt->vec[i]);
- td2d->loc[0] *= asp[0];
- td2d->loc[1] *= asp[1];
- td2d->loc[2] = 0.0f;
-
- td2d->loc2d = bezt->vec[i];
-
- td->flag = 0;
- td->loc = td2d->loc;
- mul_v2_m3v2(td->center, parent_matrix, bezt->vec[1]);
- td->center[0] *= asp[0];
- td->center[1] *= asp[1];
- copy_v3_v3(td->iloc, td->loc);
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
-
- if (i == 1) {
- /* scaling weights */
- td->val = &bezt->weight;
- td->ival = *td->val;
- }
- else {
- td->val = NULL;
- }
-
- if (is_sel_any) {
- td->flag |= TD_SELECTED;
- }
- td->dist = 0.0;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-
- if (i == 0) {
- tdm->orig_handle_type = bezt->h1;
- }
- else if (i == 2) {
- tdm->orig_handle_type = bezt->h2;
- }
-
- td++;
- td2d++;
- tdm++;
- }
- }
- else {
- if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
- MaskHandleToTransData(point,
- MASK_WHICH_HANDLE_STICK,
- td,
- td2d,
- tdm,
- asp,
- parent_matrix,
- parent_inverse_matrix);
-
- td++;
- td2d++;
- tdm++;
- }
- else {
- if (bezt->f1 & SELECT) {
- MaskHandleToTransData(point,
- MASK_WHICH_HANDLE_LEFT,
- td,
- td2d,
- tdm,
- asp,
- parent_matrix,
- parent_inverse_matrix);
-
- if (bezt->h1 == HD_VECT) {
- bezt->h1 = HD_FREE;
- }
- else if (bezt->h1 == HD_AUTO) {
- bezt->h1 = HD_ALIGN_DOUBLESIDE;
- bezt->h2 = HD_ALIGN_DOUBLESIDE;
- }
-
- td++;
- td2d++;
- tdm++;
- }
- if (bezt->f3 & SELECT) {
- MaskHandleToTransData(point,
- MASK_WHICH_HANDLE_RIGHT,
- td,
- td2d,
- tdm,
- asp,
- parent_matrix,
- parent_inverse_matrix);
-
- if (bezt->h2 == HD_VECT) {
- bezt->h2 = HD_FREE;
- }
- else if (bezt->h2 == HD_AUTO) {
- bezt->h1 = HD_ALIGN_DOUBLESIDE;
- bezt->h2 = HD_ALIGN_DOUBLESIDE;
- }
-
- td++;
- td2d++;
- tdm++;
- }
- }
- }
-}
-
-static void createTransMaskingData(bContext *C, TransInfo *t)
-{
- Scene *scene = CTX_data_scene(C);
- Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
- TransData *td = NULL;
- TransData2D *td2d = NULL;
- TransDataMasking *tdm = NULL;
- int count = 0, countsel = 0;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT);
- float asp[2];
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- tc->data_len = 0;
-
- if (!mask) {
- return;
- }
-
- if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sc = t->sa->spacedata.first;
- MovieClip *clip = ED_space_clip_get_clip(sc);
- if (!clip) {
- return;
- }
- }
-
- /* count */
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
-
- if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
- continue;
- }
-
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- int i;
-
- for (i = 0; i < spline->tot_point; i++) {
- MaskSplinePoint *point = &spline->points[i];
-
- if (MASKPOINT_ISSEL_ANY(point)) {
- if (MASKPOINT_ISSEL_KNOT(point)) {
- countsel += 3;
- }
- else {
- if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
- countsel += 1;
- }
- else {
- BezTriple *bezt = &point->bezt;
- if (bezt->f1 & SELECT) {
- countsel++;
- }
- if (bezt->f3 & SELECT) {
- countsel++;
- }
- }
- }
- }
-
- if (is_prop_edit) {
- count += 3;
- }
- }
- }
- }
-
- /* note: in prop mode we need at least 1 selected */
- if (countsel == 0) {
- return;
- }
-
- ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]);
-
- tc->data_len = (is_prop_edit) ? count : countsel;
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Mask Editing)");
- /* for each 2d uv coord a 3d vector is allocated, so that they can be
- * treated just as if they were 3d verts */
- td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D),
- "TransObData2D(Mask Editing)");
- tc->custom.type.data = tdm = MEM_callocN(tc->data_len * sizeof(TransDataMasking),
- "TransDataMasking(Mask Editing)");
- tc->custom.type.use_free = true;
-
- /* create data */
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
-
- if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
- continue;
- }
-
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- int i;
-
- for (i = 0; i < spline->tot_point; i++) {
- MaskSplinePoint *point = &spline->points[i];
-
- if (is_prop_edit || MASKPOINT_ISSEL_ANY(point)) {
- MaskPointToTransData(scene, point, td, td2d, tdm, is_prop_edit, asp);
-
- if (is_prop_edit || MASKPOINT_ISSEL_KNOT(point)) {
- td += 3;
- td2d += 3;
- tdm += 3;
- }
- else {
- if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
- td++;
- td2d++;
- tdm++;
- }
- else {
- BezTriple *bezt = &point->bezt;
- if (bezt->f1 & SELECT) {
- td++;
- td2d++;
- tdm++;
- }
- if (bezt->f3 & SELECT) {
- td++;
- td2d++;
- tdm++;
- }
- }
- }
- }
- }
- }
- }
-}
-
-void flushTransMasking(TransInfo *t)
-{
- TransData2D *td;
- TransDataMasking *tdm;
- int a;
- float asp[2], inv[2];
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]);
- inv[0] = 1.0f / asp[0];
- inv[1] = 1.0f / asp[1];
-
- /* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = tc->data_2d, tdm = tc->custom.type.data; a < tc->data_len; a++, td++, tdm++) {
- td->loc2d[0] = td->loc[0] * inv[0];
- td->loc2d[1] = td->loc[1] * inv[1];
- mul_m3_v2(tdm->parent_inverse_matrix, td->loc2d);
-
- if (tdm->is_handle) {
- BKE_mask_point_set_handle(tdm->point,
- tdm->which_handle,
- td->loc2d,
- (t->flag & T_ALT_TRANSFORM) != 0,
- tdm->orig_handle,
- tdm->vec);
- }
-
- if (t->state == TRANS_CANCEL) {
- if (tdm->which_handle == MASK_WHICH_HANDLE_LEFT) {
- tdm->point->bezt.h1 = tdm->orig_handle_type;
- }
- else if (tdm->which_handle == MASK_WHICH_HANDLE_RIGHT) {
- tdm->point->bezt.h2 = tdm->orig_handle_type;
- }
- }
- }
-}
-
-typedef struct TransDataPaintCurve {
- PaintCurvePoint *pcp; /* initial curve point */
- char id;
-} TransDataPaintCurve;
-
-#define PC_IS_ANY_SEL(pc) (((pc)->bez.f1 | (pc)->bez.f2 | (pc)->bez.f3) & SELECT)
-
-static void PaintCurveConvertHandle(
- PaintCurvePoint *pcp, int id, TransData2D *td2d, TransDataPaintCurve *tdpc, TransData *td)
-{
- BezTriple *bezt = &pcp->bez;
- copy_v2_v2(td2d->loc, bezt->vec[id]);
- td2d->loc[2] = 0.0f;
- td2d->loc2d = bezt->vec[id];
-
- td->flag = 0;
- td->loc = td2d->loc;
- copy_v3_v3(td->center, bezt->vec[1]);
- copy_v3_v3(td->iloc, td->loc);
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
- td->flag |= TD_SELECTED;
- td->dist = 0.0;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-
- tdpc->id = id;
- tdpc->pcp = pcp;
-}
-
-static void PaintCurvePointToTransData(PaintCurvePoint *pcp,
- TransData *td,
- TransData2D *td2d,
- TransDataPaintCurve *tdpc)
-{
- BezTriple *bezt = &pcp->bez;
-
- if (pcp->bez.f2 == SELECT) {
- int i;
- for (i = 0; i < 3; i++) {
- copy_v2_v2(td2d->loc, bezt->vec[i]);
- td2d->loc[2] = 0.0f;
- td2d->loc2d = bezt->vec[i];
-
- td->flag = 0;
- td->loc = td2d->loc;
- copy_v3_v3(td->center, bezt->vec[1]);
- copy_v3_v3(td->iloc, td->loc);
-
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
-
- td->ext = NULL;
- td->val = NULL;
- td->flag |= TD_SELECTED;
- td->dist = 0.0;
-
- unit_m3(td->mtx);
- unit_m3(td->smtx);
-
- tdpc->id = i;
- tdpc->pcp = pcp;
-
- td++;
- td2d++;
- tdpc++;
- }
- }
- else {
- if (bezt->f3 & SELECT) {
- PaintCurveConvertHandle(pcp, 2, td2d, tdpc, td);
- td2d++;
- tdpc++;
- td++;
- }
-
- if (bezt->f1 & SELECT) {
- PaintCurveConvertHandle(pcp, 0, td2d, tdpc, td);
- }
- }
-}
-
-static void createTransPaintCurveVerts(bContext *C, TransInfo *t)
-{
- Paint *paint = BKE_paint_get_active_from_context(C);
- PaintCurve *pc;
- PaintCurvePoint *pcp;
- Brush *br;
- TransData *td = NULL;
- TransData2D *td2d = NULL;
- TransDataPaintCurve *tdpc = NULL;
- int i;
- int total = 0;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- tc->data_len = 0;
-
- if (!paint || !paint->brush || !paint->brush->paint_curve) {
- return;
- }
-
- br = paint->brush;
- pc = br->paint_curve;
-
- for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) {
- if (PC_IS_ANY_SEL(pcp)) {
- if (pcp->bez.f2 & SELECT) {
- total += 3;
- continue;
- }
- else {
- if (pcp->bez.f1 & SELECT) {
- total++;
- }
- if (pcp->bez.f3 & SELECT) {
- total++;
- }
- }
- }
- }
-
- if (!total) {
- return;
- }
-
- tc->data_len = total;
- td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransData2D");
- td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData");
- tc->custom.type.data = tdpc = MEM_callocN(tc->data_len * sizeof(TransDataPaintCurve),
- "TransDataPaintCurve");
- tc->custom.type.use_free = true;
-
- for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) {
- if (PC_IS_ANY_SEL(pcp)) {
- PaintCurvePointToTransData(pcp, td, td2d, tdpc);
-
- if (pcp->bez.f2 & SELECT) {
- td += 3;
- td2d += 3;
- tdpc += 3;
- }
- else {
- if (pcp->bez.f1 & SELECT) {
- td++;
- td2d++;
- tdpc++;
- }
- if (pcp->bez.f3 & SELECT) {
- td++;
- td2d++;
- tdpc++;
- }
- }
- }
- }
-}
-
-void flushTransPaintCurve(TransInfo *t)
-{
- int i;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- TransData2D *td2d = tc->data_2d;
- TransDataPaintCurve *tdpc = tc->custom.type.data;
-
- for (i = 0; i < tc->data_len; i++, tdpc++, td2d++) {
- PaintCurvePoint *pcp = tdpc->pcp;
- copy_v2_v2(pcp->bez.vec[tdpc->id], td2d->loc);
- }
-}
-
-static void createTransGPencil_center_get(bGPDstroke *gps, float r_center[3])
-{
- bGPDspoint *pt;
- int i;
-
- zero_v3(r_center);
- int tot_sel = 0;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- add_v3_v3(r_center, &pt->x);
- tot_sel++;
- }
- }
-
- if (tot_sel > 0) {
- mul_v3_fl(r_center, 1.0f / tot_sel);
- }
-}
-
-static void createTransGPencil(bContext *C, TransInfo *t)
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
-
- bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- bool use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) != 0;
-
- Object *obact = CTX_data_active_object(C);
- bGPDlayer *gpl;
- TransData *td = NULL;
- float mtx[3][3], smtx[3][3];
-
- const Scene *scene = CTX_data_scene(C);
- const int cfra_scene = CFRA;
-
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
- const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0;
-
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
-
- /* == Grease Pencil Strokes to Transform Data ==
- * Grease Pencil stroke points can be a mixture of 2D (screen-space),
- * or 3D coordinates. However, they're always saved as 3D points.
- * For now, we just do these without creating TransData2D for the 2D
- * strokes. This may cause issues in future though.
- */
- tc->data_len = 0;
-
- if (gpd == NULL) {
- return;
- }
-
- /* initialize falloff curve */
- if (is_multiedit) {
- BKE_curvemapping_initialize(ts->gp_sculpt.cur_falloff);
- }
-
- /* First Pass: Count the number of data-points required for the strokes,
- * (and additional info about the configuration - e.g. 2D/3D?).
- */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
- bGPDframe *gpf;
- bGPDstroke *gps;
- bGPDframe *init_gpf = gpl->actframe;
- if (is_multiedit) {
- init_gpf = gpl->frames.first;
- }
-
- for (gpf = init_gpf; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
- continue;
- }
-
- if (is_prop_edit) {
- /* Proportional Editing... */
- if (is_prop_edit_connected) {
- /* connected only - so only if selected */
- if (gps->flag & GP_STROKE_SELECT) {
- tc->data_len += gps->totpoints;
- }
- }
- else {
- /* everything goes - connection status doesn't matter */
- tc->data_len += gps->totpoints;
- }
- }
- else {
- /* only selected stroke points are considered */
- if (gps->flag & GP_STROKE_SELECT) {
- bGPDspoint *pt;
- int i;
-
- // TODO: 2D vs 3D?
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- tc->data_len++;
- }
- }
- }
- }
- }
- }
- /* if not multiedit out of loop */
- if (!is_multiedit) {
- break;
- }
- }
- }
- }
-
- /* Stop trying if nothing selected */
- if (tc->data_len == 0) {
- return;
- }
-
- /* Allocate memory for data */
- tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(GPencil)");
- td = tc->data;
-
- unit_m3(smtx);
- unit_m3(mtx);
-
- /* Second Pass: Build transdata array */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
- const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene;
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps;
- float diff_mat[4][4];
- float inverse_diff_mat[4][4];
-
- bGPDframe *init_gpf = gpl->actframe;
- if (is_multiedit) {
- init_gpf = gpl->frames.first;
- }
- /* init multiframe falloff options */
- int f_init = 0;
- int f_end = 0;
-
- if (use_multiframe_falloff) {
- BKE_gpencil_get_range_selected(gpl, &f_init, &f_end);
- }
-
- /* calculate difference matrix */
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
- /* undo matrix */
- invert_m4_m4(inverse_diff_mat, diff_mat);
-
- /* Make a new frame to work on if the layer's frame
- * and the current scene frame don't match up.
- *
- * - 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...
- */
- // XXX: should this be allowed when framelock is enabled?
- if ((gpf->framenum != cfra) && (!is_multiedit)) {
- gpf = BKE_gpencil_frame_addcopy(gpl, cfra);
- /* in some weird situations (framelock enabled) return NULL */
- if (gpf == NULL) {
- continue;
- }
- if (!is_multiedit) {
- init_gpf = gpf;
- }
- }
-
- /* Loop over strokes, adding TransData for points as needed... */
- for (gpf = init_gpf; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
-
- /* if multiframe and falloff, recalculate and save value */
- float falloff = 1.0f; /* by default no falloff */
- if ((is_multiedit) && (use_multiframe_falloff)) {
- /* Faloff depends on distance to active frame (relative to the overall frame range) */
- falloff = BKE_gpencil_multiframe_falloff_calc(
- gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff);
- }
-
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- TransData *head = td;
- TransData *tail = td;
- bool stroke_ok;
-
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
- continue;
- }
- /* What we need to include depends on proportional editing settings... */
- if (is_prop_edit) {
- if (is_prop_edit_connected) {
- /* A) "Connected" - Only those in selected strokes */
- stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
- }
- else {
- /* B) All points, always */
- stroke_ok = true;
- }
- }
- else {
- /* C) Only selected points in selected strokes */
- stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
- }
-
- /* Do stroke... */
- if (stroke_ok && gps->totpoints) {
- bGPDspoint *pt;
- int i;
-
- /* save falloff factor */
- gps->runtime.multi_frame_falloff = falloff;
-
- /* calculate stroke center */
- float center[3];
- createTransGPencil_center_get(gps, center);
-
- /* add all necessary points... */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- bool point_ok;
-
- /* include point? */
- if (is_prop_edit) {
- /* Always all points in strokes that get included */
- point_ok = true;
- }
- else {
- /* Only selected points in selected strokes */
- point_ok = (pt->flag & GP_SPOINT_SELECT) != 0;
- }
-
- /* do point... */
- if (point_ok) {
- copy_v3_v3(td->iloc, &pt->x);
- /* only copy center in local origins.
- * This allows get interesting effects also when move
- * using proportional editing */
- if ((gps->flag & GP_STROKE_SELECT) &&
- (ts->transform_pivot_point == V3D_AROUND_LOCAL_ORIGINS)) {
- copy_v3_v3(td->center, center);
- }
- else {
- copy_v3_v3(td->center, &pt->x);
- }
-
- td->loc = &pt->x;
-
- td->flag = 0;
-
- if (pt->flag & GP_SPOINT_SELECT) {
- td->flag |= TD_SELECTED;
- }
-
- /* for other transform modes (e.g. shrink-fatten), need to additional data
- * but never for scale or mirror
- */
- if ((t->mode != TFM_RESIZE) && (t->mode != TFM_MIRROR)) {
- if (t->mode != TFM_GPENCIL_OPACITY) {
- td->val = &pt->pressure;
- td->ival = pt->pressure;
- }
- else {
- td->val = &pt->strength;
- td->ival = pt->strength;
- }
- }
-
- /* screenspace needs special matrices... */
- if ((gps->flag & (GP_STROKE_3DSPACE | GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) ==
- 0) {
- /* screenspace */
- td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
- }
- else {
- /* configure 2D dataspace points so that they don't play up... */
- if (gps->flag & (GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) {
- td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
- }
- }
- /* apply parent transformations */
- copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */
- copy_m3_m4(td->mtx, diff_mat); /* display position */
- copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */
-
- /* Triangulation must be calculated again,
- * so save the stroke for recalc function */
- td->extra = gps;
-
- /* save pointer to object */
- td->ob = obact;
-
- td++;
- tail++;
- }
- }
-
- /* March over these points, and calculate the proportional editing distances */
- if (is_prop_edit && (head != tail)) {
- /* XXX: for now, we are similar enough that this works... */
- calc_distanceCurveVerts(head, tail - 1);
- }
- }
- }
- }
- /* if not multiedit out of loop */
- if (!is_multiedit) {
- break;
- }
- }
- }
- }
-}
-
-static int countAndCleanTransDataContainer(TransInfo *t)
-{
- BLI_assert(ELEM(t->data_len_all, 0, -1));
- t->data_len_all = 0;
- uint data_container_len_orig = t->data_container_len;
- for (TransDataContainer *th_end = t->data_container - 1,
- *tc = t->data_container + (t->data_container_len - 1);
- tc != th_end;
- tc--) {
- if (tc->data_len == 0) {
- uint index = tc - t->data_container;
- if (index + 1 != t->data_container_len) {
- SWAP(TransDataContainer,
- t->data_container[index],
- t->data_container[t->data_container_len - 1]);
- }
- t->data_container_len -= 1;
- }
- else {
- t->data_len_all += tc->data_len;
- }
- }
- if (data_container_len_orig != t->data_container_len) {
- t->data_container = MEM_reallocN(t->data_container,
- sizeof(*t->data_container) * t->data_container_len);
- }
- return t->data_len_all;
-}
-
-void createTransData(bContext *C, TransInfo *t)
-{
- Scene *scene = t->scene;
- ViewLayer *view_layer = t->view_layer;
- Object *ob = OBACT(view_layer);
-
- bool has_transform_context = true;
- t->data_len_all = -1;
-
- /* if tests must match recalcData for correct updates */
- if (t->options & CTX_CURSOR) {
- t->flag |= T_CURSOR;
- t->obedit_type = -1;
-
- if (t->spacetype == SPACE_IMAGE) {
- createTransCursor_image(t);
- }
- else {
- createTransCursor_view3d(t);
- }
- countAndCleanTransDataContainer(t);
- }
- else if (t->options & CTX_TEXTURE) {
- t->flag |= T_TEXTURE;
- t->obedit_type = -1;
-
- createTransTexspace(t);
- countAndCleanTransDataContainer(t);
- }
- else if (t->options & CTX_EDGE) {
- /* Multi object editing. */
- initTransDataContainers_FromObjectData(t, ob, NULL, 0);
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- tc->data_ext = NULL;
- }
- t->flag |= T_EDIT;
-
- createTransEdge(t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && t->flag & T_PROP_EDIT) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
- }
- else if (t->options & CTX_GPENCIL_STROKES) {
- t->options |= CTX_GPENCIL_STROKES;
- t->flag |= T_POINTS | T_EDIT;
-
- initTransDataContainers_FromObjectData(t, ob, NULL, 0);
- createTransGPencil(C, t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
- }
- else if (t->spacetype == SPACE_IMAGE) {
- t->flag |= T_POINTS | T_2D_EDIT;
- if (t->options & CTX_MASK) {
-
- /* copied from below */
- createTransMaskingData(C, t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, true);
- sort_trans_data_dist(t);
- }
- }
- else if (t->options & CTX_PAINT_CURVE) {
- if (!ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) {
- createTransPaintCurveVerts(C, t);
- countAndCleanTransDataContainer(t);
- }
- else {
- has_transform_context = false;
- }
- }
- else if (t->obedit_type == OB_MESH) {
-
- initTransDataContainers_FromObjectData(t, ob, NULL, 0);
- createTransUVs(C, t);
- countAndCleanTransDataContainer(t);
-
- t->flag |= T_EDIT;
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
- }
- else {
- has_transform_context = false;
- }
- }
- else if (t->spacetype == SPACE_ACTION) {
- t->flag |= T_POINTS | T_2D_EDIT;
- t->obedit_type = -1;
-
- createTransActionData(C, t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- sort_trans_data_selected_first(t);
- /* don't do that, distance has been set in createTransActionData already */
- // set_prop_dist(t, false);
- sort_trans_data_dist(t);
- }
- }
- else if (t->spacetype == SPACE_NLA) {
- t->flag |= T_POINTS | T_2D_EDIT;
- t->obedit_type = -1;
-
- createTransNlaData(C, t);
- countAndCleanTransDataContainer(t);
- }
- else if (t->spacetype == SPACE_SEQ) {
- t->flag |= T_POINTS | T_2D_EDIT;
- t->obedit_type = -1;
-
- t->num.flag |= NUM_NO_FRACTION; /* sequencer has no use for floating point trasnform */
- createTransSeqData(C, t);
- countAndCleanTransDataContainer(t);
- }
- else if (t->spacetype == SPACE_GRAPH) {
- t->flag |= T_POINTS | T_2D_EDIT;
- t->obedit_type = -1;
-
- createTransGraphEditData(C, t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- /* makes selected become first in array */
- sort_trans_data_selected_first(t);
-
- /* don't do that, distance has been set in createTransGraphEditData already */
- set_prop_dist(t, false);
-
- sort_trans_data_dist(t);
- }
- }
- else if (t->spacetype == SPACE_NODE) {
- t->flag |= T_POINTS | T_2D_EDIT;
- t->obedit_type = -1;
-
- createTransNodeData(C, t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
- }
- else if (t->spacetype == SPACE_CLIP) {
- t->flag |= T_POINTS | T_2D_EDIT;
- t->obedit_type = -1;
-
- if (t->options & CTX_MOVIECLIP) {
- createTransTrackingData(C, t);
- countAndCleanTransDataContainer(t);
- }
- else if (t->options & CTX_MASK) {
- /* copied from above */
- createTransMaskingData(C, t);
- countAndCleanTransDataContainer(t);
-
- if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, true);
- sort_trans_data_dist(t);
- }
- }
- else {
- has_transform_context = false;
- }
- }
- else if (t->obedit_type != -1) {
- /* Multi object editing. */
- initTransDataContainers_FromObjectData(t, ob, NULL, 0);
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- tc->data_ext = NULL;
- }
- if (t->obedit_type == OB_MESH) {
- createTransEditVerts(t);
- }
- else if (ELEM(t->obedit_type, OB_CURVE, OB_SURF)) {
- createTransCurveVerts(t);
- }
- else if (t->obedit_type == OB_LATTICE) {
- createTransLatticeVerts(t);
- }
- else if (t->obedit_type == OB_MBALL) {
- createTransMBallVerts(t);
- }
- else if (t->obedit_type == OB_ARMATURE) {
- t->flag &= ~T_PROP_EDIT;
- createTransArmatureVerts(t);
- }
- else {
- printf("edit type not implemented!\n");
- }
-
- countAndCleanTransDataContainer(t);
-
- t->flag |= T_EDIT | T_POINTS;
-
- if (t->data_len_all) {
- if (t->flag & T_PROP_EDIT) {
- if (ELEM(t->obedit_type, OB_CURVE, OB_MESH)) {
- sort_trans_data_selected_first(t);
- if ((t->obedit_type == OB_MESH) && (t->flag & T_PROP_CONNECTED)) {
- /* already calculated by editmesh_set_connectivity_distance */
- }
- else {
- set_prop_dist(t, 0);
- }
- sort_trans_data_dist(t);
- }
- else {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
- }
- else {
- if (ELEM(t->obedit_type, OB_CURVE)) {
- /* Needed because bezier handles can be partially selected
- * and are still added into transform data. */
- sort_trans_data_selected_first(t);
- }
- }
- }
-
- /* exception... hackish, we want bonesize to use bone orientation matrix (ton) */
- if (t->mode == TFM_BONESIZE) {
- t->flag &= ~(T_EDIT | T_POINTS);
- t->flag |= T_POSE;
- t->obedit_type = -1;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- tc->poseobj = tc->obedit;
- tc->obedit = NULL;
- }
- }
- }
- else if (ob && (ob->mode & OB_MODE_POSE)) {
- /* XXX this is currently limited to active armature only... */
-
- /* XXX active-layer checking isn't done
- * as that should probably be checked through context instead. */
-
- /* Multi object editing. */
- initTransDataContainers_FromObjectData(t, ob, NULL, 0);
- createTransPose(t);
- countAndCleanTransDataContainer(t);
- }
- else if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && !(t->options & CTX_PAINT_CURVE)) {
- /* important that ob_armature can be set even when its not selected [#23412]
- * lines below just check is also visible */
- has_transform_context = false;
- Object *ob_armature = modifiers_isDeformedByArmature(ob);
- if (ob_armature && ob_armature->mode & OB_MODE_POSE) {
- Base *base_arm = BKE_view_layer_base_find(t->view_layer, ob_armature);
- if (base_arm) {
- View3D *v3d = t->view;
- if (BASE_VISIBLE(v3d, base_arm)) {
- Object *objects[1];
- objects[0] = ob_armature;
- uint objects_len = 1;
- initTransDataContainers_FromObjectData(t, ob_armature, objects, objects_len);
- createTransPose(t);
- countAndCleanTransDataContainer(t);
- has_transform_context = true;
- }
- }
- }
- }
- else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_start_edit(PE_get_current(scene, ob))) {
- createTransParticleVerts(C, t);
- countAndCleanTransDataContainer(t);
- t->flag |= T_POINTS;
-
- if (t->data_len_all && t->flag & T_PROP_EDIT) {
- sort_trans_data_selected_first(t);
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
- }
- else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
- if ((t->options & CTX_PAINT_CURVE) && !ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) {
- t->flag |= T_POINTS | T_2D_EDIT;
- createTransPaintCurveVerts(C, t);
- countAndCleanTransDataContainer(t);
- }
- else {
- has_transform_context = false;
- }
- }
- else if ((ob) &&
- (ELEM(
- ob->mode, OB_MODE_PAINT_GPENCIL, OB_MODE_SCULPT_GPENCIL, OB_MODE_WEIGHT_GPENCIL))) {
- /* In grease pencil all transformations must be canceled if not Object or Edit. */
- has_transform_context = false;
- }
- else {
- /* Needed for correct Object.obmat after duplication, see: T62135. */
- BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context));
-
- if ((scene->toolsettings->transform_flag & SCE_XFORM_DATA_ORIGIN) != 0) {
- t->flag |= T_OBJECT_DATA_IN_OBJECT_MODE;
- }
-
- createTransObject(C, t);
- countAndCleanTransDataContainer(t);
- t->flag |= T_OBJECT;
-
- if (t->data_len_all && t->flag & T_PROP_EDIT) {
- // selected objects are already first, no need to presort
- set_prop_dist(t, 1);
- sort_trans_data_dist(t);
- }
-
- /* Check if we're transforming the camera from the camera */
- if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) {
- View3D *v3d = t->view;
- RegionView3D *rv3d = t->ar->regiondata;
- if ((rv3d->persp == RV3D_CAMOB) && v3d->camera) {
- /* we could have a flag to easily check an object is being transformed */
- if (v3d->camera->id.tag & LIB_TAG_DOIT) {
- t->flag |= T_CAMERA;
- }
- }
- }
- }
-
- /* Check that 'countAndCleanTransDataContainer' ran. */
- if (has_transform_context) {
- BLI_assert(t->data_len_all != -1);
- }
- else {
- BLI_assert(t->data_len_all == -1);
- t->data_len_all = 0;
- }
-
- BLI_assert((!(t->flag & T_EDIT)) == (!(t->obedit_type != -1)));
-}
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
new file mode 100644
index 00000000000..5862faaf667
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert.c
@@ -0,0 +1,2743 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_space_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_mask_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_kdtree.h"
+
+#include "BKE_animsys.h"
+#include "BKE_armature.h"
+#include "BKE_context.h"
+#include "BKE_fcurve.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_layer.h"
+#include "BKE_key.h"
+#include "BKE_main.h"
+#include "BKE_modifier.h"
+#include "BKE_nla.h"
+#include "BKE_node.h"
+#include "BKE_pointcache.h"
+#include "BKE_rigidbody.h"
+#include "BKE_scene.h"
+#include "BKE_editmesh.h"
+#include "BKE_tracking.h"
+#include "BKE_mask.h"
+
+#include "BIK_api.h"
+
+#include "ED_anim_api.h"
+#include "ED_armature.h"
+#include "ED_particle.h"
+#include "ED_image.h"
+#include "ED_keyframing.h"
+#include "ED_keyframes_edit.h"
+#include "ED_object.h"
+#include "ED_markers.h"
+#include "ED_mesh.h"
+#include "ED_node.h"
+#include "ED_clip.h"
+#include "ED_mask.h"
+
+#include "WM_api.h" /* for WM_event_add_notifier to deal with stabilization nodes */
+#include "WM_types.h"
+
+#include "RNA_access.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/**
+ * Transforming around ourselves is no use, fallback to individual origins,
+ * useful for curve/armatures.
+ */
+void transform_around_single_fallback(TransInfo *t)
+{
+ if ((t->data_len_all == 1) &&
+ (ELEM(t->around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEDIAN, V3D_AROUND_ACTIVE)) &&
+ (ELEM(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL))) {
+ t->around = V3D_AROUND_LOCAL_ORIGINS;
+ }
+}
+
+/* ************************** Functions *************************** */
+
+static int trans_data_compare_dist(const void *a, const void *b)
+{
+ const TransData *td_a = (const TransData *)a;
+ const TransData *td_b = (const TransData *)b;
+
+ if (td_a->dist < td_b->dist) {
+ return -1;
+ }
+ else if (td_a->dist > td_b->dist) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+static int trans_data_compare_rdist(const void *a, const void *b)
+{
+ const TransData *td_a = (const TransData *)a;
+ const TransData *td_b = (const TransData *)b;
+
+ if (td_a->rdist < td_b->rdist) {
+ return -1;
+ }
+ else if (td_a->rdist > td_b->rdist) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+static void sort_trans_data_dist_container(const TransInfo *t, TransDataContainer *tc)
+{
+ TransData *start = tc->data;
+ int i;
+
+ for (i = 0; i < tc->data_len && start->flag & TD_SELECTED; i++) {
+ start++;
+ }
+
+ if (i < tc->data_len) {
+ if (t->flag & T_PROP_CONNECTED) {
+ qsort(start, tc->data_len - i, sizeof(TransData), trans_data_compare_dist);
+ }
+ else {
+ qsort(start, tc->data_len - i, sizeof(TransData), trans_data_compare_rdist);
+ }
+ }
+}
+void sort_trans_data_dist(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ sort_trans_data_dist_container(t, tc);
+ }
+}
+
+/**
+ * Make #TD_SELECTED first in the array.
+ */
+static void sort_trans_data_selected_first_container(TransDataContainer *tc)
+{
+ TransData *sel, *unsel;
+ TransData temp;
+ unsel = tc->data;
+ sel = tc->data;
+ sel += tc->data_len - 1;
+ while (sel > unsel) {
+ while (unsel->flag & TD_SELECTED) {
+ unsel++;
+ if (unsel == sel) {
+ return;
+ }
+ }
+ while (!(sel->flag & TD_SELECTED)) {
+ sel--;
+ if (unsel == sel) {
+ return;
+ }
+ }
+ temp = *unsel;
+ *unsel = *sel;
+ *sel = temp;
+ sel--;
+ unsel++;
+ }
+}
+static void sort_trans_data_selected_first(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ sort_trans_data_selected_first_container(tc);
+ }
+}
+
+/**
+ * Distance calculated from not-selected vertex to nearest selected vertex.
+ */
+static void set_prop_dist(TransInfo *t, const bool with_dist)
+{
+ int a;
+
+ float _proj_vec[3];
+ const float *proj_vec = NULL;
+
+ /* support for face-islands */
+ const bool use_island = transdata_check_local_islands(t, t->around);
+
+ if (t->flag & T_PROP_PROJECTED) {
+ if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d = t->ar->regiondata;
+ normalize_v3_v3(_proj_vec, rv3d->viewinv[2]);
+ proj_vec = _proj_vec;
+ }
+ }
+
+ /* Count number of selected. */
+ int td_table_len = 0;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (a = 0; a < tc->data_len; a++, td++) {
+ if (td->flag & TD_SELECTED) {
+ td_table_len++;
+ }
+ else {
+ /* By definition transform-data has selected items in beginning. */
+ break;
+ }
+ }
+ }
+
+ /* Pointers to selected's #TransData.
+ * Used to find #TransData from the index returned by #BLI_kdtree_find_nearest. */
+ TransData **td_table = MEM_mallocN(sizeof(*td_table) * td_table_len, __func__);
+
+ /* Create and fill kd-tree of selected's positions - in global or proj_vec space. */
+ KDTree_3d *td_tree = BLI_kdtree_3d_new(td_table_len);
+
+ int td_table_index = 0;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (a = 0; a < tc->data_len; a++, td++) {
+ if (td->flag & TD_SELECTED) {
+ /* Initialize, it was mallocced. */
+ float vec[3];
+ td->rdist = 0.0f;
+
+ if (use_island) {
+ if (tc->use_local_mat) {
+ mul_v3_m4v3(vec, tc->mat, td->iloc);
+ }
+ else {
+ mul_v3_m3v3(vec, td->mtx, td->iloc);
+ }
+ }
+ else {
+ if (tc->use_local_mat) {
+ mul_v3_m4v3(vec, tc->mat, td->center);
+ }
+ else {
+ mul_v3_m3v3(vec, td->mtx, td->center);
+ }
+ }
+
+ if (proj_vec) {
+ float vec_p[3];
+ project_v3_v3v3(vec_p, vec, proj_vec);
+ sub_v3_v3(vec, vec_p);
+ }
+
+ BLI_kdtree_3d_insert(td_tree, td_table_index, vec);
+ td_table[td_table_index++] = td;
+ }
+ else {
+ /* By definition transform-data has selected items in beginning. */
+ break;
+ }
+ }
+ }
+ BLI_assert(td_table_index == td_table_len);
+
+ BLI_kdtree_3d_balance(td_tree);
+
+ /* For each non-selected vertex, find distance to the nearest selected vertex. */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (a = 0; a < tc->data_len; a++, td++) {
+ if ((td->flag & TD_SELECTED) == 0) {
+ float vec[3];
+
+ if (use_island) {
+ if (tc->use_local_mat) {
+ mul_v3_m4v3(vec, tc->mat, td->iloc);
+ }
+ else {
+ mul_v3_m3v3(vec, td->mtx, td->iloc);
+ }
+ }
+ else {
+ if (tc->use_local_mat) {
+ mul_v3_m4v3(vec, tc->mat, td->center);
+ }
+ else {
+ mul_v3_m3v3(vec, td->mtx, td->center);
+ }
+ }
+
+ if (proj_vec) {
+ float vec_p[3];
+ project_v3_v3v3(vec_p, vec, proj_vec);
+ sub_v3_v3(vec, vec_p);
+ }
+
+ KDTreeNearest_3d nearest;
+ const int td_index = BLI_kdtree_3d_find_nearest(td_tree, vec, &nearest);
+
+ td->rdist = -1.0f;
+ if (td_index != -1) {
+ td->rdist = nearest.dist;
+ if (use_island) {
+ copy_v3_v3(td->center, td_table[td_index]->center);
+ copy_m3_m3(td->axismtx, td_table[td_index]->axismtx);
+ }
+ }
+
+ if (with_dist) {
+ td->dist = td->rdist;
+ }
+ }
+ }
+ }
+
+ BLI_kdtree_3d_free(td_tree);
+ MEM_freeN(td_table);
+}
+
+/* ********************* pose mode ************* */
+
+static short apply_targetless_ik(Object *ob)
+{
+ bPoseChannel *pchan, *parchan, *chanlist[256];
+ bKinematicConstraint *data;
+ int segcount, apply = 0;
+
+ /* now we got a difficult situation... we have to find the
+ * target-less IK pchans, and apply transformation to the all
+ * pchans that were in the chain */
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ data = has_targetless_ik(pchan);
+ if (data && (data->flag & CONSTRAINT_IK_AUTO)) {
+
+ /* fill the array with the bones of the chain (armature.c does same, keep it synced) */
+ segcount = 0;
+
+ /* exclude tip from chain? */
+ if (!(data->flag & CONSTRAINT_IK_TIP)) {
+ parchan = pchan->parent;
+ }
+ else {
+ parchan = pchan;
+ }
+
+ /* Find the chain's root & count the segments needed */
+ for (; parchan; parchan = parchan->parent) {
+ chanlist[segcount] = parchan;
+ segcount++;
+
+ if (segcount == data->rootbone || segcount > 255) {
+ break; // 255 is weak
+ }
+ }
+ for (; segcount; segcount--) {
+ Bone *bone;
+ float rmat[4][4] /*, tmat[4][4], imat[4][4]*/;
+
+ /* pose_mat(b) = pose_mat(b-1) * offs_bone * channel * constraint * IK */
+ /* we put in channel the entire result of rmat = (channel * constraint * IK) */
+ /* pose_mat(b) = pose_mat(b-1) * offs_bone * rmat */
+ /* rmat = pose_mat(b) * inv(pose_mat(b-1) * offs_bone ) */
+
+ parchan = chanlist[segcount - 1];
+ bone = parchan->bone;
+ bone->flag |= BONE_TRANSFORM; /* ensures it gets an auto key inserted */
+
+ BKE_armature_mat_pose_to_bone(parchan, parchan->pose_mat, rmat);
+
+ /* apply and decompose, doesn't work for constraints or non-uniform scale well */
+ {
+ float rmat3[3][3], qrmat[3][3], imat3[3][3], smat[3][3];
+ copy_m3_m4(rmat3, rmat);
+
+ /* rotation */
+ /* [#22409] is partially caused by this, as slight numeric error introduced during
+ * the solving process leads to locked-axis values changing. However, we cannot modify
+ * the values here, or else there are huge discrepancies between IK-solver (interactive)
+ * and applied poses. */
+ BKE_pchan_mat3_to_rot(parchan, rmat3, false);
+
+ /* for size, remove rotation */
+ /* causes problems with some constraints (so apply only if needed) */
+ if (data->flag & CONSTRAINT_IK_STRETCH) {
+ BKE_pchan_rot_to_mat3(parchan, qrmat);
+ invert_m3_m3(imat3, qrmat);
+ mul_m3_m3m3(smat, rmat3, imat3);
+ mat3_to_size(parchan->size, smat);
+ }
+
+ /* causes problems with some constraints (e.g. childof), so disable this */
+ /* as it is IK shouldn't affect location directly */
+ /* copy_v3_v3(parchan->loc, rmat[3]); */
+ }
+ }
+
+ apply = 1;
+ data->flag &= ~CONSTRAINT_IK_AUTO;
+ }
+ }
+
+ return apply;
+}
+
+static void bone_children_clear_transflag(int mode, short around, ListBase *lb)
+{
+ Bone *bone = lb->first;
+
+ for (; bone; bone = bone->next) {
+ if ((bone->flag & BONE_HINGE) && (bone->flag & BONE_CONNECTED)) {
+ bone->flag |= BONE_HINGE_CHILD_TRANSFORM;
+ }
+ else if ((bone->flag & BONE_TRANSFORM) && (mode == TFM_ROTATION || mode == TFM_TRACKBALL) &&
+ (around == V3D_AROUND_LOCAL_ORIGINS)) {
+ bone->flag |= BONE_TRANSFORM_CHILD;
+ }
+ else {
+ bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
+ }
+
+ bone_children_clear_transflag(mode, around, &bone->childbase);
+ }
+}
+
+/* sets transform flags in the bones
+ * returns total number of bones with BONE_TRANSFORM */
+int count_set_pose_transflags(Object *ob,
+ const int mode,
+ const short around,
+ bool has_translate_rotate[2])
+{
+ bArmature *arm = ob->data;
+ bPoseChannel *pchan;
+ Bone *bone;
+ int total = 0;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ bone = pchan->bone;
+ if (PBONE_VISIBLE(arm, bone)) {
+ if ((bone->flag & BONE_SELECTED)) {
+ bone->flag |= BONE_TRANSFORM;
+ }
+ else {
+ bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
+ }
+
+ bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM;
+ bone->flag &= ~BONE_TRANSFORM_CHILD;
+ }
+ else {
+ bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
+ }
+ }
+
+ /* make sure no bone can be transformed when a parent is transformed */
+ /* since pchans are depsgraph sorted, the parents are in beginning of list */
+ if (!ELEM(mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ bone = pchan->bone;
+ if (bone->flag & BONE_TRANSFORM) {
+ bone_children_clear_transflag(mode, around, &bone->childbase);
+ }
+ }
+ }
+ /* now count, and check if we have autoIK or have to switch from translate to rotate */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ bone = pchan->bone;
+ if (bone->flag & BONE_TRANSFORM) {
+ total++;
+
+ if (has_translate_rotate != NULL) {
+ if (has_targetless_ik(pchan) == NULL) {
+ if (pchan->parent && (pchan->bone->flag & BONE_CONNECTED)) {
+ if (pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM) {
+ has_translate_rotate[0] = true;
+ }
+ }
+ else {
+ if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC) {
+ has_translate_rotate[0] = true;
+ }
+ }
+ if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT) {
+ has_translate_rotate[1] = true;
+ }
+ }
+ else {
+ has_translate_rotate[0] = true;
+ }
+ }
+ }
+ }
+
+ return total;
+}
+
+/* -------- Auto-IK ---------- */
+
+/* adjust pose-channel's auto-ik chainlen */
+static bool pchan_autoik_adjust(bPoseChannel *pchan, short chainlen)
+{
+ bConstraint *con;
+ bool changed = false;
+
+ /* don't bother to search if no valid constraints */
+ if ((pchan->constflag & (PCHAN_HAS_IK | PCHAN_HAS_TARGET)) == 0) {
+ return changed;
+ }
+
+ /* check if pchan has ik-constraint */
+ for (con = pchan->constraints.first; con; con = con->next) {
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce != 0.0f)) {
+ bKinematicConstraint *data = con->data;
+
+ /* only accept if a temporary one (for auto-ik) */
+ if (data->flag & CONSTRAINT_IK_TEMP) {
+ /* chainlen is new chainlen, but is limited by maximum chainlen */
+ const int old_rootbone = data->rootbone;
+ if ((chainlen == 0) || (chainlen > data->max_rootbone)) {
+ data->rootbone = data->max_rootbone;
+ }
+ else {
+ data->rootbone = chainlen;
+ }
+ changed |= (data->rootbone != old_rootbone);
+ }
+ }
+ }
+
+ return changed;
+}
+
+/* change the chain-length of auto-ik */
+void transform_autoik_update(TransInfo *t, short mode)
+{
+ Main *bmain = CTX_data_main(t->context);
+
+ short *chainlen = &t->settings->autoik_chainlen;
+ bPoseChannel *pchan;
+
+ /* mode determines what change to apply to chainlen */
+ if (mode == 1) {
+ /* mode=1 is from WHEELMOUSEDOWN... increases len */
+ (*chainlen)++;
+ }
+ else if (mode == -1) {
+ /* mode==-1 is from WHEELMOUSEUP... decreases len */
+ if (*chainlen > 0) {
+ (*chainlen)--;
+ }
+ else {
+ /* IK length did not change, skip updates. */
+ return;
+ }
+ }
+
+ /* apply to all pose-channels */
+ bool changed = false;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ /* sanity checks (don't assume t->poseobj is set, or that it is an armature) */
+ if (ELEM(NULL, tc->poseobj, tc->poseobj->pose)) {
+ continue;
+ }
+
+ for (pchan = tc->poseobj->pose->chanbase.first; pchan; pchan = pchan->next) {
+ changed |= pchan_autoik_adjust(pchan, *chainlen);
+ }
+ }
+
+ if (changed) {
+ /* TODO(sergey): Consider doing partial update only. */
+ DEG_relations_tag_update(bmain);
+ }
+}
+
+/* frees temporal IKs */
+static void pose_grab_with_ik_clear(Main *bmain, Object *ob)
+{
+ bKinematicConstraint *data;
+ bPoseChannel *pchan;
+ bConstraint *con, *next;
+ bool relations_changed = false;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ /* clear all temporary lock flags */
+ pchan->ikflag &= ~(BONE_IK_NO_XDOF_TEMP | BONE_IK_NO_YDOF_TEMP | BONE_IK_NO_ZDOF_TEMP);
+
+ pchan->constflag &= ~(PCHAN_HAS_IK | PCHAN_HAS_TARGET);
+
+ /* remove all temporary IK-constraints added */
+ for (con = pchan->constraints.first; con; con = next) {
+ next = con->next;
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
+ data = con->data;
+ if (data->flag & CONSTRAINT_IK_TEMP) {
+ relations_changed = true;
+
+ /* iTaSC needs clear for removed constraints */
+ BIK_clear_data(ob->pose);
+
+ BLI_remlink(&pchan->constraints, con);
+ MEM_freeN(con->data);
+ MEM_freeN(con);
+ continue;
+ }
+ pchan->constflag |= PCHAN_HAS_IK;
+ if (data->tar == NULL || (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0)) {
+ pchan->constflag |= PCHAN_HAS_TARGET;
+ }
+ }
+ }
+ }
+
+ if (relations_changed) {
+ /* TODO(sergey): Consider doing partial update only. */
+ DEG_relations_tag_update(bmain);
+ }
+}
+
+/* ********************* curve/surface ********* */
+
+void calc_distanceCurveVerts(TransData *head, TransData *tail)
+{
+ TransData *td, *td_near = NULL;
+ for (td = head; td <= tail; td++) {
+ if (td->flag & TD_SELECTED) {
+ td_near = td;
+ td->dist = 0.0f;
+ }
+ else if (td_near) {
+ float dist;
+ float vec[3];
+
+ sub_v3_v3v3(vec, td_near->center, td->center);
+ mul_m3_v3(head->mtx, vec);
+ dist = len_v3(vec);
+
+ if (dist < (td - 1)->dist) {
+ td->dist = (td - 1)->dist;
+ }
+ else {
+ td->dist = dist;
+ }
+ }
+ else {
+ td->dist = FLT_MAX;
+ td->flag |= TD_NOTCONNECTED;
+ }
+ }
+ td_near = NULL;
+ for (td = tail; td >= head; td--) {
+ if (td->flag & TD_SELECTED) {
+ td_near = td;
+ td->dist = 0.0f;
+ }
+ else if (td_near) {
+ float dist;
+ float vec[3];
+
+ sub_v3_v3v3(vec, td_near->center, td->center);
+ mul_m3_v3(head->mtx, vec);
+ dist = len_v3(vec);
+
+ if (td->flag & TD_NOTCONNECTED || dist < td->dist || (td + 1)->dist < td->dist) {
+ td->flag &= ~TD_NOTCONNECTED;
+ if (dist < (td + 1)->dist) {
+ td->dist = (td + 1)->dist;
+ }
+ else {
+ td->dist = dist;
+ }
+ }
+ }
+ }
+}
+
+/* Utility function for getting the handle data from bezier's */
+TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt)
+{
+ TransDataCurveHandleFlags *hdata;
+ td->flag |= TD_BEZTRIPLE;
+ hdata = td->hdata = MEM_mallocN(sizeof(TransDataCurveHandleFlags), "CuHandle Data");
+ hdata->ih1 = bezt->h1;
+ hdata->h1 = &bezt->h1;
+ hdata->ih2 = bezt->h2; /* in case the second is not selected */
+ hdata->h2 = &bezt->h2;
+ return hdata;
+}
+
+/* ********************* UV ****************** */
+
+bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
+{
+ bool clipx = true, clipy = true;
+ float min[2], max[2];
+
+ min[0] = min[1] = 0.0f;
+ max[0] = t->aspect[0];
+ max[1] = t->aspect[1];
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ TransData *td;
+ int a;
+
+ for (a = 0, td = tc->data; a < tc->data_len; a++, td++) {
+ minmax_v2v2_v2(min, max, td->loc);
+ }
+ }
+
+ if (resize) {
+ if (min[0] < 0.0f && t->center_global[0] > 0.0f && t->center_global[0] < t->aspect[0] * 0.5f) {
+ vec[0] *= t->center_global[0] / (t->center_global[0] - min[0]);
+ }
+ else if (max[0] > t->aspect[0] && t->center_global[0] < t->aspect[0]) {
+ vec[0] *= (t->center_global[0] - t->aspect[0]) / (t->center_global[0] - max[0]);
+ }
+ else {
+ clipx = 0;
+ }
+
+ if (min[1] < 0.0f && t->center_global[1] > 0.0f && t->center_global[1] < t->aspect[1] * 0.5f) {
+ vec[1] *= t->center_global[1] / (t->center_global[1] - min[1]);
+ }
+ else if (max[1] > t->aspect[1] && t->center_global[1] < t->aspect[1]) {
+ vec[1] *= (t->center_global[1] - t->aspect[1]) / (t->center_global[1] - max[1]);
+ }
+ else {
+ clipy = 0;
+ }
+ }
+ else {
+ if (min[0] < 0.0f) {
+ vec[0] -= min[0];
+ }
+ else if (max[0] > t->aspect[0]) {
+ vec[0] -= max[0] - t->aspect[0];
+ }
+ else {
+ clipx = 0;
+ }
+
+ if (min[1] < 0.0f) {
+ vec[1] -= min[1];
+ }
+ else if (max[1] > t->aspect[1]) {
+ vec[1] -= max[1] - t->aspect[1];
+ }
+ else {
+ clipy = 0;
+ }
+ }
+
+ return (clipx || clipy);
+}
+
+void clipUVData(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (int a = 0; a < tc->data_len; a++, td++) {
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if ((td->flag & TD_SKIP) || (!td->loc)) {
+ continue;
+ }
+
+ td->loc[0] = min_ff(max_ff(0.0f, td->loc[0]), t->aspect[0]);
+ td->loc[1] = min_ff(max_ff(0.0f, td->loc[1]), t->aspect[1]);
+ }
+ }
+}
+
+/* ********************* ANIMATION EDITORS (GENERAL) ************************* */
+
+/* This function tests if a point is on the "mouse" side of the cursor/frame-marking */
+bool FrameOnMouseSide(char side, float frame, float cframe)
+{
+ /* both sides, so it doesn't matter */
+ if (side == 'B') {
+ return true;
+ }
+
+ /* only on the named side */
+ if (side == 'R') {
+ return (frame >= cframe);
+ }
+ else {
+ return (frame <= cframe);
+ }
+}
+
+/* ********************* ACTION EDITOR ****************** */
+
+static int gpf_cmp_frame(void *thunk, const void *a, const void *b)
+{
+ const bGPDframe *frame_a = a;
+ const bGPDframe *frame_b = b;
+
+ if (frame_a->framenum < frame_b->framenum) {
+ return -1;
+ }
+ if (frame_a->framenum > frame_b->framenum) {
+ return 1;
+ }
+ *((bool *)thunk) = true;
+ /* selected last */
+ if ((frame_a->flag & GP_FRAME_SELECT) && ((frame_b->flag & GP_FRAME_SELECT) == 0)) {
+ return 1;
+ }
+ return 0;
+}
+
+static int masklay_shape_cmp_frame(void *thunk, const void *a, const void *b)
+{
+ const MaskLayerShape *frame_a = a;
+ const MaskLayerShape *frame_b = b;
+
+ if (frame_a->frame < frame_b->frame) {
+ return -1;
+ }
+ if (frame_a->frame > frame_b->frame) {
+ return 1;
+ }
+ *((bool *)thunk) = true;
+ /* selected last */
+ if ((frame_a->flag & MASK_SHAPE_SELECT) && ((frame_b->flag & MASK_SHAPE_SELECT) == 0)) {
+ return 1;
+ }
+ return 0;
+}
+
+/* Called by special_aftertrans_update to make sure selected gp-frames replace
+ * any other gp-frames which may reside on that frame (that are not selected).
+ * It also makes sure gp-frames are still stored in chronological order after
+ * transform.
+ */
+static void posttrans_gpd_clean(bGPdata *gpd)
+{
+ bGPDlayer *gpl;
+
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ bGPDframe *gpf, *gpfn;
+ bool is_double = false;
+
+ BLI_listbase_sort_r(&gpl->frames, gpf_cmp_frame, &is_double);
+
+ if (is_double) {
+ for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
+ gpfn = gpf->next;
+ if (gpfn && gpf->framenum == gpfn->framenum) {
+ BKE_gpencil_layer_delframe(gpl, gpf);
+ }
+ }
+ }
+
+#ifdef DEBUG
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ BLI_assert(!gpf->next || gpf->framenum < gpf->next->framenum);
+ }
+#endif
+ }
+ /* set cache flag to dirty */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+}
+
+static void posttrans_mask_clean(Mask *mask)
+{
+ MaskLayer *masklay;
+
+ for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ MaskLayerShape *masklay_shape, *masklay_shape_next;
+ bool is_double = false;
+
+ BLI_listbase_sort_r(&masklay->splines_shapes, masklay_shape_cmp_frame, &is_double);
+
+ if (is_double) {
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
+ masklay_shape = masklay_shape_next) {
+ masklay_shape_next = masklay_shape->next;
+ if (masklay_shape_next && masklay_shape->frame == masklay_shape_next->frame) {
+ BKE_mask_layer_shape_unlink(masklay, masklay_shape);
+ }
+ }
+ }
+
+#ifdef DEBUG
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
+ masklay_shape = masklay_shape->next) {
+ BLI_assert(!masklay_shape->next || masklay_shape->frame < masklay_shape->next->frame);
+ }
+#endif
+ }
+}
+
+/* Time + Average value */
+typedef struct tRetainedKeyframe {
+ struct tRetainedKeyframe *next, *prev;
+ float frame; /* frame to cluster around */
+ float val; /* average value */
+
+ size_t tot_count; /* number of keyframes that have been averaged */
+ size_t del_count; /* number of keyframes of this sort that have been deleted so far */
+} tRetainedKeyframe;
+
+/* Called during special_aftertrans_update to make sure selected keyframes replace
+ * any other keyframes which may reside on that frame (that is not selected).
+ */
+static void posttrans_fcurve_clean(FCurve *fcu, const bool use_handle)
+{
+ /* NOTE: We assume that all keys are sorted */
+ ListBase retained_keys = {NULL, NULL};
+ const bool can_average_points = ((fcu->flag & (FCURVE_INT_VALUES | FCURVE_DISCRETE_VALUES)) ==
+ 0);
+
+ /* sanity checks */
+ if ((fcu->totvert == 0) || (fcu->bezt == NULL)) {
+ return;
+ }
+
+ /* 1) Identify selected keyframes, and average the values on those
+ * in case there are collisions due to multiple keys getting scaled
+ * to all end up on the same frame
+ */
+ for (int i = 0; i < fcu->totvert; i++) {
+ BezTriple *bezt = &fcu->bezt[i];
+
+ if (BEZT_ISSEL_ANY(bezt)) {
+ bool found = false;
+
+ /* If there's another selected frame here, merge it */
+ for (tRetainedKeyframe *rk = retained_keys.last; rk; rk = rk->prev) {
+ if (IS_EQT(rk->frame, bezt->vec[1][0], BEZT_BINARYSEARCH_THRESH)) {
+ rk->val += bezt->vec[1][1];
+ rk->tot_count++;
+
+ found = true;
+ break;
+ }
+ else if (rk->frame < bezt->vec[1][0]) {
+ /* Terminate early if have passed the supposed insertion point? */
+ break;
+ }
+ }
+
+ /* If nothing found yet, create a new one */
+ if (found == false) {
+ tRetainedKeyframe *rk = MEM_callocN(sizeof(tRetainedKeyframe), "tRetainedKeyframe");
+
+ rk->frame = bezt->vec[1][0];
+ rk->val = bezt->vec[1][1];
+ rk->tot_count = 1;
+
+ BLI_addtail(&retained_keys, rk);
+ }
+ }
+ }
+
+ if (BLI_listbase_is_empty(&retained_keys)) {
+ /* This may happen if none of the points were selected... */
+ if (G.debug & G_DEBUG) {
+ printf("%s: nothing to do for FCurve %p (rna_path = '%s')\n", __func__, fcu, fcu->rna_path);
+ }
+ return;
+ }
+ else {
+ /* Compute the average values for each retained keyframe */
+ for (tRetainedKeyframe *rk = retained_keys.first; rk; rk = rk->next) {
+ rk->val = rk->val / (float)rk->tot_count;
+ }
+ }
+
+ /* 2) Delete all keyframes duplicating the "retained keys" found above
+ * - Most of these will be unselected keyframes
+ * - Some will be selected keyframes though. For those, we only keep the last one
+ * (or else everything is gone), and replace its value with the averaged value.
+ */
+ for (int i = fcu->totvert - 1; i >= 0; i--) {
+ BezTriple *bezt = &fcu->bezt[i];
+
+ /* Is this keyframe a candidate for deletion? */
+ /* TODO: Replace loop with an O(1) lookup instead */
+ for (tRetainedKeyframe *rk = retained_keys.last; rk; rk = rk->prev) {
+ if (IS_EQT(bezt->vec[1][0], rk->frame, BEZT_BINARYSEARCH_THRESH)) {
+ /* Selected keys are treated with greater care than unselected ones... */
+ if (BEZT_ISSEL_ANY(bezt)) {
+ /* - If this is the last selected key left (based on rk->del_count) ==> UPDATE IT
+ * (or else we wouldn't have any keyframe left here)
+ * - Otherwise, there are still other selected keyframes on this frame
+ * to be merged down still ==> DELETE IT
+ */
+ if (rk->del_count == rk->tot_count - 1) {
+ /* Update keyframe... */
+ if (can_average_points) {
+ /* TODO: update handles too? */
+ bezt->vec[1][1] = rk->val;
+ }
+ }
+ else {
+ /* Delete Keyframe */
+ delete_fcurve_key(fcu, i, 0);
+ }
+
+ /* Update count of how many we've deleted
+ * - It should only matter that we're doing this for all but the last one
+ */
+ rk->del_count++;
+ }
+ else {
+ /* Always delete - Unselected keys don't matter */
+ delete_fcurve_key(fcu, i, 0);
+ }
+
+ /* Stop the RK search... we've found our match now */
+ break;
+ }
+ }
+ }
+
+ /* 3) Recalculate handles */
+ testhandles_fcurve(fcu, use_handle);
+
+ /* cleanup */
+ BLI_freelistN(&retained_keys);
+}
+
+/* Called by special_aftertrans_update to make sure selected keyframes replace
+ * any other keyframes which may reside on that frame (that is not selected).
+ * remake_action_ipos should have already been called
+ */
+static void posttrans_action_clean(bAnimContext *ac, bAction *act)
+{
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
+ ANIM_animdata_filter(ac, &anim_data, filter, act, ANIMCONT_ACTION);
+
+ /* loop through relevant data, removing keyframes as appropriate
+ * - all keyframes are converted in/out of global time
+ */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+
+ if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
+ posttrans_fcurve_clean(ale->key_data, false); /* only use handles in graph editor */
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
+ }
+ else {
+ posttrans_fcurve_clean(ale->key_data, false); /* only use handles in graph editor */
+ }
+ }
+
+ /* free temp data */
+ ANIM_animdata_freelist(&anim_data);
+}
+
+/* ********************* GRAPH EDITOR ************************* */
+
+/* struct for use in re-sorting BezTriples during Graph Editor transform */
+typedef struct BeztMap {
+ BezTriple *bezt;
+ unsigned int oldIndex; /* index of bezt in fcu->bezt array before sorting */
+ unsigned int newIndex; /* index of bezt in fcu->bezt array after sorting */
+ short swapHs; /* swap order of handles (-1=clear; 0=not checked, 1=swap) */
+ char pipo, cipo; /* interpolation of current and next segments */
+} BeztMap;
+
+/* This function converts an FCurve's BezTriple array to a BeztMap array
+ * NOTE: this allocates memory that will need to get freed later
+ */
+static BeztMap *bezt_to_beztmaps(BezTriple *bezts, int totvert, const short UNUSED(use_handle))
+{
+ BezTriple *bezt = bezts;
+ BezTriple *prevbezt = NULL;
+ BeztMap *bezm, *bezms;
+ int i;
+
+ /* allocate memory for this array */
+ if (totvert == 0 || bezts == NULL) {
+ return NULL;
+ }
+ bezm = bezms = MEM_callocN(sizeof(BeztMap) * totvert, "BeztMaps");
+
+ /* assign beztriples to beztmaps */
+ for (i = 0; i < totvert; i++, bezm++, prevbezt = bezt, bezt++) {
+ bezm->bezt = bezt;
+
+ bezm->oldIndex = i;
+ bezm->newIndex = i;
+
+ bezm->pipo = (prevbezt) ? prevbezt->ipo : bezt->ipo;
+ bezm->cipo = bezt->ipo;
+ }
+
+ return bezms;
+}
+
+/* This function copies the code of sort_time_ipocurve, but acts on BeztMap structs instead */
+static void sort_time_beztmaps(BeztMap *bezms, int totvert, const short UNUSED(use_handle))
+{
+ BeztMap *bezm;
+ int i, ok = 1;
+
+ /* keep repeating the process until nothing is out of place anymore */
+ while (ok) {
+ ok = 0;
+
+ bezm = bezms;
+ i = totvert;
+ while (i--) {
+ /* is current bezm out of order (i.e. occurs later than next)? */
+ if (i > 0) {
+ if (bezm->bezt->vec[1][0] > (bezm + 1)->bezt->vec[1][0]) {
+ bezm->newIndex++;
+ (bezm + 1)->newIndex--;
+
+ SWAP(BeztMap, *bezm, *(bezm + 1));
+
+ ok = 1;
+ }
+ }
+
+ /* do we need to check if the handles need to be swapped?
+ * optimization: this only needs to be performed in the first loop
+ */
+ if (bezm->swapHs == 0) {
+ if ((bezm->bezt->vec[0][0] > bezm->bezt->vec[1][0]) &&
+ (bezm->bezt->vec[2][0] < bezm->bezt->vec[1][0])) {
+ /* handles need to be swapped */
+ bezm->swapHs = 1;
+ }
+ else {
+ /* handles need to be cleared */
+ bezm->swapHs = -1;
+ }
+ }
+
+ bezm++;
+ }
+ }
+}
+
+/* This function firstly adjusts the pointers that the transdata has to each BezTriple */
+static void beztmap_to_data(
+ TransInfo *t, FCurve *fcu, BeztMap *bezms, int totvert, const short UNUSED(use_handle))
+{
+ BezTriple *bezts = fcu->bezt;
+ BeztMap *bezm;
+ TransData2D *td2d;
+ TransData *td;
+ int i, j;
+ char *adjusted;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* dynamically allocate an array of chars to mark whether an TransData's
+ * pointers have been fixed already, so that we don't override ones that are
+ * already done
+ */
+ adjusted = MEM_callocN(tc->data_len, "beztmap_adjusted_map");
+
+ /* for each beztmap item, find if it is used anywhere */
+ bezm = bezms;
+ for (i = 0; i < totvert; i++, bezm++) {
+ /* loop through transdata, testing if we have a hit
+ * for the handles (vec[0]/vec[2]), we must also check if they need to be swapped...
+ */
+ td2d = tc->data_2d;
+ td = tc->data;
+ for (j = 0; j < tc->data_len; j++, td2d++, td++) {
+ /* skip item if already marked */
+ if (adjusted[j] != 0) {
+ continue;
+ }
+
+ /* update all transdata pointers, no need to check for selections etc,
+ * since only points that are really needed were created as transdata
+ */
+ if (td2d->loc2d == bezm->bezt->vec[0]) {
+ if (bezm->swapHs == 1) {
+ td2d->loc2d = (bezts + bezm->newIndex)->vec[2];
+ }
+ else {
+ td2d->loc2d = (bezts + bezm->newIndex)->vec[0];
+ }
+ adjusted[j] = 1;
+ }
+ else if (td2d->loc2d == bezm->bezt->vec[2]) {
+ if (bezm->swapHs == 1) {
+ td2d->loc2d = (bezts + bezm->newIndex)->vec[0];
+ }
+ else {
+ td2d->loc2d = (bezts + bezm->newIndex)->vec[2];
+ }
+ adjusted[j] = 1;
+ }
+ else if (td2d->loc2d == bezm->bezt->vec[1]) {
+ td2d->loc2d = (bezts + bezm->newIndex)->vec[1];
+
+ /* if only control point is selected, the handle pointers need to be updated as well */
+ if (td2d->h1) {
+ td2d->h1 = (bezts + bezm->newIndex)->vec[0];
+ }
+ if (td2d->h2) {
+ td2d->h2 = (bezts + bezm->newIndex)->vec[2];
+ }
+
+ adjusted[j] = 1;
+ }
+
+ /* the handle type pointer has to be updated too */
+ if (adjusted[j] && td->flag & TD_BEZTRIPLE && td->hdata) {
+ if (bezm->swapHs == 1) {
+ td->hdata->h1 = &(bezts + bezm->newIndex)->h2;
+ td->hdata->h2 = &(bezts + bezm->newIndex)->h1;
+ }
+ else {
+ td->hdata->h1 = &(bezts + bezm->newIndex)->h1;
+ td->hdata->h2 = &(bezts + bezm->newIndex)->h2;
+ }
+ }
+ }
+ }
+
+ /* free temp memory used for 'adjusted' array */
+ MEM_freeN(adjusted);
+}
+
+/* This function is called by recalcData during the Transform loop to recalculate
+ * the handles of curves and sort the keyframes so that the curves draw correctly.
+ * It is only called if some keyframes have moved out of order.
+ *
+ * anim_data is the list of channels (F-Curves) retrieved already containing the
+ * channels to work on. It should not be freed here as it may still need to be used.
+ */
+void remake_graph_transdata(TransInfo *t, ListBase *anim_data)
+{
+ SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ bAnimListElem *ale;
+ const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
+
+ /* sort and reassign verts */
+ for (ale = anim_data->first; ale; ale = ale->next) {
+ FCurve *fcu = (FCurve *)ale->key_data;
+
+ if (fcu->bezt) {
+ BeztMap *bezm;
+
+ /* adjust transform-data pointers */
+ /* note, none of these functions use 'use_handle', it could be removed */
+ bezm = bezt_to_beztmaps(fcu->bezt, fcu->totvert, use_handle);
+ sort_time_beztmaps(bezm, fcu->totvert, use_handle);
+ beztmap_to_data(t, fcu, bezm, fcu->totvert, use_handle);
+
+ /* free mapping stuff */
+ MEM_freeN(bezm);
+
+ /* re-sort actual beztriples (perhaps this could be done using the beztmaps to save time?) */
+ sort_time_fcurve(fcu);
+
+ /* make sure handles are all set correctly */
+ testhandles_fcurve(fcu, use_handle);
+ }
+ }
+}
+
+/* *********************** Transform data ******************* */
+
+/* Little helper function for ObjectToTransData used to give certain
+ * constraints (ChildOf, FollowPath, and others that may be added)
+ * inverse corrections for transform, so that they aren't in CrazySpace.
+ * These particular constraints benefit from this, but others don't, hence
+ * this semi-hack ;-) - Aligorith
+ */
+bool constraints_list_needinv(TransInfo *t, ListBase *list)
+{
+ bConstraint *con;
+
+ /* loop through constraints, checking if there's one of the mentioned
+ * constraints needing special crazyspace corrections
+ */
+ if (list) {
+ for (con = list->first; con; con = con->next) {
+ /* only consider constraint if it is enabled, and has influence on result */
+ if ((con->flag & CONSTRAINT_DISABLE) == 0 && (con->enforce != 0.0f)) {
+ /* (affirmative) returns for specific constraints here... */
+ /* constraints that require this regardless */
+ if (ELEM(con->type,
+ CONSTRAINT_TYPE_FOLLOWPATH,
+ CONSTRAINT_TYPE_CLAMPTO,
+ CONSTRAINT_TYPE_ARMATURE,
+ CONSTRAINT_TYPE_OBJECTSOLVER,
+ CONSTRAINT_TYPE_FOLLOWTRACK)) {
+ return true;
+ }
+
+ /* constraints that require this only under special conditions */
+ if (con->type == CONSTRAINT_TYPE_CHILDOF) {
+ /* ChildOf constraint only works when using all location components, see T42256. */
+ bChildOfConstraint *data = (bChildOfConstraint *)con->data;
+
+ if ((data->flag & CHILDOF_LOCX) && (data->flag & CHILDOF_LOCY) &&
+ (data->flag & CHILDOF_LOCZ)) {
+ return true;
+ }
+ }
+ else if (con->type == CONSTRAINT_TYPE_ROTLIKE) {
+ /* CopyRot constraint only does this when rotating, and offset is on */
+ bRotateLikeConstraint *data = (bRotateLikeConstraint *)con->data;
+
+ if (ELEM(data->mix_mode, ROTLIKE_MIX_OFFSET, ROTLIKE_MIX_BEFORE) &&
+ ELEM(t->mode, TFM_ROTATION)) {
+ return true;
+ }
+ }
+ else if (con->type == CONSTRAINT_TYPE_TRANSLIKE) {
+ /* Copy Transforms constraint only does this in the Before mode. */
+ bTransLikeConstraint *data = (bTransLikeConstraint *)con->data;
+
+ if (ELEM(data->mix_mode, TRANSLIKE_MIX_BEFORE) &&
+ ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION)) {
+ return true;
+ }
+ }
+ else if (con->type == CONSTRAINT_TYPE_TRANSFORM) {
+ /* Transform constraint needs it for rotation at least (r.57309),
+ * but doing so when translating may also mess things up [#36203]
+ */
+ bTransformConstraint *data = (bTransformConstraint *)con->data;
+
+ if (data->to == TRANS_ROTATION) {
+ if (t->mode == TFM_ROTATION && data->mix_mode_rot == TRANS_MIXROT_BEFORE) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* no appropriate candidates found */
+ return false;
+}
+
+/**
+ * Auto-keyframing feature - for objects
+ *
+ * \param tmode: A transform mode.
+ *
+ * \note Context may not always be available,
+ * so must check before using it as it's a luxury for a few cases.
+ */
+void autokeyframe_object(bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, int tmode)
+{
+ Main *bmain = CTX_data_main(C);
+ ID *id = &ob->id;
+ FCurve *fcu;
+
+ // TODO: this should probably be done per channel instead...
+ if (autokeyframe_cfra_can_key(scene, id)) {
+ ReportList *reports = CTX_wm_reports(C);
+ ToolSettings *ts = scene->toolsettings;
+ KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
+ ListBase dsources = {NULL, NULL};
+ float cfra = (float)CFRA; // xxx this will do for now
+ short flag = 0;
+
+ /* get flags used for inserting keyframes */
+ flag = ANIM_get_keyframing_flags(scene, 1);
+
+ /* add datasource override for the object */
+ ANIM_relative_keyingset_add_source(&dsources, id, NULL, NULL);
+
+ if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
+ /* Only insert into active keyingset
+ * NOTE: we assume here that the active Keying Set
+ * does not need to have its iterator overridden.
+ */
+ ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) {
+ AnimData *adt = ob->adt;
+
+ /* only key on available channels */
+ if (adt && adt->action) {
+ ListBase nla_cache = {NULL, NULL};
+ for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) {
+ fcu->flag &= ~FCURVE_SELECTED;
+ insert_keyframe(bmain,
+ reports,
+ id,
+ adt->action,
+ (fcu->grp ? fcu->grp->name : NULL),
+ fcu->rna_path,
+ fcu->array_index,
+ cfra,
+ ts->keyframe_type,
+ &nla_cache,
+ flag);
+ }
+
+ BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
+ }
+ }
+ else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
+ bool do_loc = false, do_rot = false, do_scale = false;
+
+ /* filter the conditions when this happens (assume that curarea->spacetype==SPACE_VIE3D) */
+ if (tmode == TFM_TRANSLATION) {
+ do_loc = true;
+ }
+ else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
+ if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
+ if (ob != OBACT(view_layer)) {
+ do_loc = true;
+ }
+ }
+ else if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) {
+ do_loc = true;
+ }
+
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
+ do_rot = true;
+ }
+ }
+ else if (tmode == TFM_RESIZE) {
+ if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
+ if (ob != OBACT(view_layer)) {
+ do_loc = true;
+ }
+ }
+ else if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) {
+ do_loc = true;
+ }
+
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
+ do_scale = true;
+ }
+ }
+
+ /* insert keyframes for the affected sets of channels using the builtin KeyingSets found */
+ if (do_loc) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ if (do_rot) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ if (do_scale) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_SCALING_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ }
+ /* insert keyframe in all (transform) channels */
+ else {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+
+ /* free temp info */
+ BLI_freelistN(&dsources);
+ }
+}
+
+/* Return if we need to update motion paths, only if they already exist,
+ * and we will insert a keyframe at the end of transform. */
+bool motionpath_need_update_object(Scene *scene, Object *ob)
+{
+ /* XXX: there's potential here for problems with unkeyed rotations/scale,
+ * but for now (until proper data-locality for baking operations),
+ * this should be a better fix for T24451 and T37755
+ */
+
+ if (autokeyframe_cfra_can_key(scene, &ob->id)) {
+ return (ob->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
+ }
+
+ return false;
+}
+
+/**
+ * Auto-keyframing feature - for poses/pose-channels
+ *
+ * \param tmode: A transform mode.
+ *
+ * targetless_ik: has targetless ik been done on any channels?
+ *
+ * \note Context may not always be available,
+ * so must check before using it as it's a luxury for a few cases.
+ */
+void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, int tmode, short targetless_ik)
+{
+ Main *bmain = CTX_data_main(C);
+ ID *id = &ob->id;
+ AnimData *adt = ob->adt;
+ bAction *act = (adt) ? adt->action : NULL;
+ bPose *pose = ob->pose;
+ bPoseChannel *pchan;
+ FCurve *fcu;
+
+ // TODO: this should probably be done per channel instead...
+ if (autokeyframe_cfra_can_key(scene, id)) {
+ ReportList *reports = CTX_wm_reports(C);
+ ToolSettings *ts = scene->toolsettings;
+ KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
+ ListBase nla_cache = {NULL, NULL};
+ float cfra = (float)CFRA;
+ short flag = 0;
+
+ /* flag is initialized from UserPref keyframing settings
+ * - special exception for targetless IK - INSERTKEY_MATRIX keyframes should get
+ * visual keyframes even if flag not set, as it's not that useful otherwise
+ * (for quick animation recording)
+ */
+ flag = ANIM_get_keyframing_flags(scene, 1);
+
+ if (targetless_ik) {
+ flag |= INSERTKEY_MATRIX;
+ }
+
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone->flag & (BONE_TRANSFORM | BONE_TRANSFORM_MIRROR)) {
+
+ ListBase dsources = {NULL, NULL};
+
+ /* clear any 'unkeyed' flag it may have */
+ pchan->bone->flag &= ~BONE_UNKEYED;
+
+ /* add datasource override for the camera object */
+ ANIM_relative_keyingset_add_source(&dsources, id, &RNA_PoseBone, pchan);
+
+ /* only insert into active keyingset? */
+ if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
+ /* run the active Keying Set on the current datasource */
+ ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ /* only insert into available channels? */
+ else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) {
+ if (act) {
+ for (fcu = act->curves.first; fcu; fcu = fcu->next) {
+ /* only insert keyframes for this F-Curve if it affects the current bone */
+ if (strstr(fcu->rna_path, "bones")) {
+ char *pchanName = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
+
+ /* only if bone name matches too...
+ * NOTE: this will do constraints too, but those are ok to do here too?
+ */
+ if (pchanName && STREQ(pchanName, pchan->name)) {
+ insert_keyframe(bmain,
+ reports,
+ id,
+ act,
+ ((fcu->grp) ? (fcu->grp->name) : (NULL)),
+ fcu->rna_path,
+ fcu->array_index,
+ cfra,
+ ts->keyframe_type,
+ &nla_cache,
+ flag);
+ }
+
+ if (pchanName) {
+ MEM_freeN(pchanName);
+ }
+ }
+ }
+ }
+ }
+ /* only insert keyframe if needed? */
+ else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
+ bool do_loc = false, do_rot = false, do_scale = false;
+
+ /* Filter the conditions when this happens
+ * (assume that 'curarea->spacetype == SPACE_VIEW3D'). */
+ if (tmode == TFM_TRANSLATION) {
+ if (targetless_ik) {
+ do_rot = true;
+ }
+ else {
+ do_loc = true;
+ }
+ }
+ else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
+ if (ELEM(scene->toolsettings->transform_pivot_point,
+ V3D_AROUND_CURSOR,
+ V3D_AROUND_ACTIVE)) {
+ do_loc = true;
+ }
+
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
+ do_rot = true;
+ }
+ }
+ else if (tmode == TFM_RESIZE) {
+ if (ELEM(scene->toolsettings->transform_pivot_point,
+ V3D_AROUND_CURSOR,
+ V3D_AROUND_ACTIVE)) {
+ do_loc = true;
+ }
+
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
+ do_scale = true;
+ }
+ }
+
+ if (do_loc) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ if (do_rot) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ if (do_scale) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_SCALING_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ }
+ /* insert keyframe in all (transform) channels */
+ else {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+
+ /* free temp info */
+ BLI_freelistN(&dsources);
+ }
+ }
+
+ BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
+ }
+ else {
+ /* tag channels that should have unkeyed data */
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone->flag & BONE_TRANSFORM) {
+ /* tag this channel */
+ pchan->bone->flag |= BONE_UNKEYED;
+ }
+ }
+ }
+}
+
+/* Return if we need to update motion paths, only if they already exist,
+ * and we will insert a keyframe at the end of transform. */
+bool motionpath_need_update_pose(Scene *scene, Object *ob)
+{
+ if (autokeyframe_cfra_can_key(scene, &ob->id)) {
+ return (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
+ }
+
+ return false;
+}
+
+static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t)
+{
+ SpaceClip *sc = t->sa->spacedata.first;
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
+ const int framenr = ED_space_clip_get_clip_frame_number(sc);
+ /* Update coordinates of modified plane tracks. */
+ for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first; plane_track;
+ plane_track = plane_track->next) {
+ bool do_update = false;
+ if (plane_track->flag & PLANE_TRACK_HIDDEN) {
+ continue;
+ }
+ do_update |= PLANE_TRACK_VIEW_SELECTED(plane_track) != 0;
+ if (do_update == false) {
+ if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
+ int i;
+ for (i = 0; i < plane_track->point_tracksnr; i++) {
+ MovieTrackingTrack *track = plane_track->point_tracks[i];
+ if (TRACK_VIEW_SELECTED(sc, track)) {
+ do_update = true;
+ break;
+ }
+ }
+ }
+ }
+ if (do_update) {
+ BKE_tracking_track_plane_from_existing_motion(plane_track, framenr);
+ }
+ }
+ if (t->scene->nodetree != NULL) {
+ /* Tracks can be used for stabilization nodes,
+ * flush update for such nodes.
+ */
+ nodeUpdateID(t->scene->nodetree, &clip->id);
+ WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL);
+ }
+}
+
+static void special_aftertrans_update__mask(bContext *C, TransInfo *t)
+{
+ Mask *mask = NULL;
+
+ if (t->spacetype == SPACE_CLIP) {
+ SpaceClip *sc = t->sa->spacedata.first;
+ mask = ED_space_clip_get_mask(sc);
+ }
+ else if (t->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = t->sa->spacedata.first;
+ mask = ED_space_image_get_mask(sima);
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ if (t->scene->nodetree) {
+ /* tracks can be used for stabilization nodes,
+ * flush update for such nodes */
+ // if (nodeUpdateID(t->scene->nodetree, &mask->id))
+ {
+ WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id);
+ }
+ }
+
+ /* TODO - dont key all masks... */
+ if (IS_AUTOKEY_ON(t->scene)) {
+ Scene *scene = t->scene;
+
+ ED_mask_layer_shape_auto_key_select(mask, CFRA);
+ }
+}
+
+static void special_aftertrans_update__node(bContext *C, TransInfo *t)
+{
+ Main *bmain = CTX_data_main(C);
+ const bool canceled = (t->state == TRANS_CANCEL);
+
+ if (canceled && t->remove_on_cancel) {
+ /* remove selected nodes on cancel */
+ SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
+ bNodeTree *ntree = snode->edittree;
+ if (ntree) {
+ bNode *node, *node_next;
+ for (node = ntree->nodes.first; node; node = node_next) {
+ node_next = node->next;
+ if (node->flag & NODE_SELECT) {
+ nodeRemoveNode(bmain, ntree, node, true);
+ }
+ }
+ }
+ }
+}
+
+static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
+{
+ /* so automerge supports mirror */
+ if ((t->scene->toolsettings->automerge) && ((t->flag & T_EDIT) && t->obedit_type == OB_MESH)) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BMesh *bm = em->bm;
+ char hflag;
+ bool has_face_sel = (bm->totfacesel != 0);
+
+ if (tc->mirror.use_mirror_any) {
+ TransDataMirror *tdm;
+ int i;
+
+ /* Rather then adjusting the selection (which the user would notice)
+ * tag all mirrored verts, then auto-merge those. */
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false);
+
+ for (i = tc->mirror.data_len, tdm = tc->mirror.data; i--; tdm++) {
+ BM_elem_flag_enable((BMVert *)tdm->extra, BM_ELEM_TAG);
+ }
+
+ hflag = BM_ELEM_SELECT | BM_ELEM_TAG;
+ }
+ else {
+ hflag = BM_ELEM_SELECT;
+ }
+
+ if (t->scene->toolsettings->automerge & AUTO_MERGE) {
+ if (t->scene->toolsettings->automerge & AUTO_MERGE_AND_SPLIT) {
+ EDBM_automerge_and_split(
+ tc->obedit, true, true, true, hflag, t->scene->toolsettings->doublimit);
+ }
+ else {
+ EDBM_automerge(tc->obedit, true, hflag, t->scene->toolsettings->doublimit);
+ }
+ }
+
+ /* Special case, this is needed or faces won't re-select.
+ * Flush selected edges to faces. */
+ if (has_face_sel && (em->selectmode == SCE_SELECT_FACE)) {
+ EDBM_selectmode_flush_ex(em, SCE_SELECT_EDGE);
+ }
+ }
+ }
+}
+
+/* inserting keys, pointcache, redraw events... */
+/**
+ * \note Sequencer freeing has its own function now because of a conflict
+ * with transform's order of freeing (campbell).
+ * Order changed, the sequencer stuff should go back in here
+ */
+void special_aftertrans_update(bContext *C, TransInfo *t)
+{
+ Main *bmain = CTX_data_main(t->context);
+ BLI_assert(bmain == CTX_data_main(C));
+
+ Object *ob;
+ // short redrawipo=0, resetslowpar=1;
+ const bool canceled = (t->state == TRANS_CANCEL);
+ const bool duplicate = (t->mode == TFM_TIME_DUPLICATE);
+
+ /* early out when nothing happened */
+ if (t->data_len_all == 0 || t->mode == TFM_DUMMY) {
+ return;
+ }
+
+ if (t->spacetype == SPACE_VIEW3D) {
+ if (t->flag & T_EDIT) {
+ /* Special Exception:
+ * We don't normally access 't->custom.mode' here, but its needed in this case. */
+
+ if (canceled == 0) {
+ /* we need to delete the temporary faces before automerging */
+ if (t->mode == TFM_EDGE_SLIDE) {
+ /* handle multires re-projection, done
+ * on transform completion since it's
+ * really slow -joeedh */
+ projectEdgeSlideData(t, true);
+ }
+ else if (t->mode == TFM_VERT_SLIDE) {
+ /* as above */
+ projectVertSlideData(t, true);
+ }
+
+ if (t->obedit_type == OB_MESH) {
+ special_aftertrans_update__mesh(C, t);
+ }
+ }
+ else {
+ if (t->mode == TFM_EDGE_SLIDE) {
+ EdgeSlideParams *slp = t->custom.mode.data;
+ slp->perc = 0.0;
+ projectEdgeSlideData(t, false);
+ }
+ else if (t->mode == TFM_VERT_SLIDE) {
+ EdgeSlideParams *slp = t->custom.mode.data;
+ slp->perc = 0.0;
+ projectVertSlideData(t, false);
+ }
+ }
+ }
+ }
+
+ if (t->options & CTX_GPENCIL_STROKES) {
+ /* pass */
+ }
+ else if (t->spacetype == SPACE_SEQ) {
+ /* freeSeqData in transform_conversions.c does this
+ * keep here so the else at the end wont run... */
+
+ SpaceSeq *sseq = (SpaceSeq *)t->sa->spacedata.first;
+
+ /* marker transform, not especially nice but we may want to move markers
+ * at the same time as keyframes in the dope sheet. */
+ if ((sseq->flag & SEQ_MARKER_TRANS) && (canceled == 0)) {
+ /* cant use TFM_TIME_EXTEND
+ * for some reason EXTEND is changed into TRANSLATE, so use frame_side instead */
+
+ if (t->mode == TFM_SEQ_SLIDE) {
+ if (t->frame_side == 'B') {
+ ED_markers_post_apply_transform(
+ &t->scene->markers, t->scene, TFM_TIME_TRANSLATE, t->values[0], t->frame_side);
+ }
+ }
+ else if (ELEM(t->frame_side, 'L', 'R')) {
+ ED_markers_post_apply_transform(
+ &t->scene->markers, t->scene, TFM_TIME_EXTEND, t->values[0], t->frame_side);
+ }
+ }
+ }
+ else if (t->spacetype == SPACE_IMAGE) {
+ if (t->options & CTX_MASK) {
+ special_aftertrans_update__mask(C, t);
+ }
+ }
+ else if (t->spacetype == SPACE_NODE) {
+ SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
+ special_aftertrans_update__node(C, t);
+ if (canceled == 0) {
+ ED_node_post_apply_transform(C, snode->edittree);
+
+ ED_node_link_insert(bmain, t->sa);
+ }
+
+ /* clear link line */
+ ED_node_link_intersect_test(t->sa, 0);
+ }
+ else if (t->spacetype == SPACE_CLIP) {
+ if (t->options & CTX_MOVIECLIP) {
+ special_aftertrans_update__movieclip(C, t);
+ }
+ else if (t->options & CTX_MASK) {
+ special_aftertrans_update__mask(C, t);
+ }
+ }
+ else if (t->spacetype == SPACE_ACTION) {
+ SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
+ bAnimContext ac;
+
+ /* initialize relevant anim-context 'context' data */
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return;
+ }
+
+ ob = ac.obact;
+
+ if (ELEM(ac.datatype, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY, ANIMCONT_TIMELINE)) {
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
+
+ /* get channels to work on */
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* these should all be F-Curves */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ FCurve *fcu = (FCurve *)ale->key_data;
+
+ /* 3 cases here for curve cleanups:
+ * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
+ * 2) canceled == 0 -> user confirmed the transform,
+ * so duplicates should be removed
+ * 3) canceled + duplicate -> user canceled the transform,
+ * but we made duplicates, so get rid of these
+ */
+ if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
+ if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
+ posttrans_fcurve_clean(fcu, false); /* only use handles in graph editor */
+ ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
+ }
+ else {
+ posttrans_fcurve_clean(fcu, false); /* only use handles in graph editor */
+ }
+ }
+ }
+
+ /* free temp memory */
+ ANIM_animdata_freelist(&anim_data);
+ }
+ else if (ac.datatype == ANIMCONT_ACTION) { // TODO: just integrate into the above...
+ /* Depending on the lock status, draw necessary views */
+ // fixme... some of this stuff is not good
+ if (ob) {
+ if (ob->pose || BKE_key_from_object(ob)) {
+ DEG_id_tag_update(&ob->id,
+ ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
+ }
+ else {
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+ }
+ }
+
+ /* 3 cases here for curve cleanups:
+ * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
+ * 2) canceled == 0 -> user confirmed the transform,
+ * so duplicates should be removed.
+ * 3) canceled + duplicate -> user canceled the transform,
+ * but we made duplicates, so get rid of these.
+ */
+ if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
+ posttrans_action_clean(&ac, (bAction *)ac.data);
+ }
+ }
+ else if (ac.datatype == ANIMCONT_GPENCIL) {
+ /* remove duplicate frames and also make sure points are in order! */
+ /* 3 cases here for curve cleanups:
+ * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
+ * 2) canceled == 0 -> user confirmed the transform,
+ * so duplicates should be removed
+ * 3) canceled + duplicate -> user canceled the transform,
+ * but we made duplicates, so get rid of these
+ */
+ if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
+ bGPdata *gpd;
+
+ // XXX: BAD! this get gpencil datablocks directly from main db...
+ // but that's how this currently works :/
+ for (gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) {
+ if (ID_REAL_USERS(gpd)) {
+ posttrans_gpd_clean(gpd);
+ }
+ }
+ }
+ }
+ else if (ac.datatype == ANIMCONT_MASK) {
+ /* remove duplicate frames and also make sure points are in order! */
+ /* 3 cases here for curve cleanups:
+ * 1) NOTRANSKEYCULL on:
+ * Cleanup of duplicates shouldn't be done.
+ * 2) canceled == 0:
+ * User confirmed the transform, so duplicates should be removed.
+ * 3) Canceled + duplicate:
+ * User canceled the transform, but we made duplicates, so get rid of these.
+ */
+ if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
+ Mask *mask;
+
+ // XXX: BAD! this get gpencil datablocks directly from main db...
+ // but that's how this currently works :/
+ for (mask = bmain->masks.first; mask; mask = mask->id.next) {
+ if (ID_REAL_USERS(mask)) {
+ posttrans_mask_clean(mask);
+ }
+ }
+ }
+ }
+
+ /* marker transform, not especially nice but we may want to move markers
+ * at the same time as keyframes in the dope sheet.
+ */
+ if ((saction->flag & SACTION_MARKERS_MOVE) && (canceled == 0)) {
+ if (t->mode == TFM_TIME_TRANSLATE) {
+#if 0
+ if (ELEM(t->frame_side, 'L', 'R')) { /* TFM_TIME_EXTEND */
+ /* same as below */
+ ED_markers_post_apply_transform(
+ ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side);
+ }
+ else /* TFM_TIME_TRANSLATE */
+#endif
+ {
+ ED_markers_post_apply_transform(
+ ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side);
+ }
+ }
+ else if (t->mode == TFM_TIME_SCALE) {
+ ED_markers_post_apply_transform(
+ ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side);
+ }
+ }
+
+ /* make sure all F-Curves are set correctly */
+ if (!ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ ANIM_editkeyframes_refresh(&ac);
+ }
+
+ /* clear flag that was set for time-slide drawing */
+ saction->flag &= ~SACTION_MOVING;
+ }
+ else if (t->spacetype == SPACE_GRAPH) {
+ SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ bAnimContext ac;
+ const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
+
+ /* initialize relevant anim-context 'context' data */
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return;
+ }
+
+ if (ac.datatype) {
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
+
+ /* get channels to work on */
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ FCurve *fcu = (FCurve *)ale->key_data;
+
+ /* 3 cases here for curve cleanups:
+ * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
+ * 2) canceled == 0 -> user confirmed the transform,
+ * so duplicates should be removed
+ * 3) canceled + duplicate -> user canceled the transform,
+ * but we made duplicates, so get rid of these
+ */
+ if ((sipo->flag & SIPO_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
+ if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
+ posttrans_fcurve_clean(fcu, use_handle);
+ ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
+ }
+ else {
+ posttrans_fcurve_clean(fcu, use_handle);
+ }
+ }
+ }
+
+ /* free temp memory */
+ ANIM_animdata_freelist(&anim_data);
+ }
+
+ /* Make sure all F-Curves are set correctly, but not if transform was
+ * canceled, since then curves were already restored to initial state.
+ * Note: if the refresh is really needed after cancel then some way
+ * has to be added to not update handle types (see bug 22289).
+ */
+ if (!canceled) {
+ ANIM_editkeyframes_refresh(&ac);
+ }
+ }
+ else if (t->spacetype == SPACE_NLA) {
+ bAnimContext ac;
+
+ /* initialize relevant anim-context 'context' data */
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return;
+ }
+
+ if (ac.datatype) {
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT);
+
+ /* get channels to work on */
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ NlaTrack *nlt = (NlaTrack *)ale->data;
+
+ /* make sure strips are in order again */
+ BKE_nlatrack_sort_strips(nlt);
+
+ /* remove the temp metas */
+ BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
+ }
+
+ /* free temp memory */
+ ANIM_animdata_freelist(&anim_data);
+
+ /* perform after-transfrom validation */
+ ED_nla_postop_refresh(&ac);
+ }
+ }
+ else if (t->flag & T_EDIT) {
+ if (t->obedit_type == OB_MESH) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ /* table needs to be created for each edit command, since vertices can move etc */
+ ED_mesh_mirror_spatial_table(tc->obedit, em, NULL, NULL, 'e');
+ /* TODO(campbell): xform: We need support for many mirror objects at once! */
+ break;
+ }
+ }
+ }
+ else if (t->flag & T_POSE && (t->mode == TFM_BONESIZE)) {
+ /* Handle the exception where for TFM_BONESIZE in edit mode we pretend to be
+ * in pose mode (to use bone orientation matrix),
+ * in that case we don't do operations like auto-keyframing. */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ ob = tc->poseobj;
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+ }
+ else if (t->flag & T_POSE) {
+ GSet *motionpath_updates = BLI_gset_ptr_new("motionpath updates");
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ bPoseChannel *pchan;
+ short targetless_ik = 0;
+
+ ob = tc->poseobj;
+
+ if ((t->flag & T_AUTOIK) && (t->options & CTX_AUTOCONFIRM)) {
+ /* when running transform non-interactively (operator exec),
+ * we need to update the pose otherwise no updates get called during
+ * transform and the auto-ik is not applied. see [#26164] */
+ struct Object *pose_ob = tc->poseobj;
+ BKE_pose_where_is(t->depsgraph, t->scene, pose_ob);
+ }
+
+ /* set BONE_TRANSFORM flags for autokey, gizmo draw might have changed them */
+ if (!canceled && (t->mode != TFM_DUMMY)) {
+ count_set_pose_transflags(ob, t->mode, t->around, NULL);
+ }
+
+ /* if target-less IK grabbing, we calculate the pchan transforms and clear flag */
+ if (!canceled && t->mode == TFM_TRANSLATION) {
+ targetless_ik = apply_targetless_ik(ob);
+ }
+ else {
+ /* not forget to clear the auto flag */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ bKinematicConstraint *data = has_targetless_ik(pchan);
+ if (data) {
+ data->flag &= ~CONSTRAINT_IK_AUTO;
+ }
+ }
+ }
+
+ if (t->mode == TFM_TRANSLATION) {
+ pose_grab_with_ik_clear(bmain, ob);
+ }
+
+ /* automatic inserting of keys and unkeyed tagging -
+ * only if transform wasn't canceled (or TFM_DUMMY) */
+ if (!canceled && (t->mode != TFM_DUMMY)) {
+ autokeyframe_pose(C, t->scene, ob, t->mode, targetless_ik);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+ else {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+
+ if (t->mode != TFM_DUMMY && motionpath_need_update_pose(t->scene, ob)) {
+ BLI_gset_insert(motionpath_updates, ob);
+ }
+ }
+
+ /* Update motion paths once for all transformed bones in an object. */
+ GSetIterator gs_iter;
+ GSET_ITER (gs_iter, motionpath_updates) {
+ const ePosePathCalcRange range = canceled ? POSE_PATH_CALC_RANGE_CURRENT_FRAME :
+ POSE_PATH_CALC_RANGE_CHANGED;
+ ob = BLI_gsetIterator_getKey(&gs_iter);
+ ED_pose_recalculate_paths(C, t->scene, ob, range);
+ }
+ BLI_gset_free(motionpath_updates, NULL);
+ }
+ else if (t->options & CTX_PAINT_CURVE) {
+ /* pass */
+ }
+ else if (t->options & CTX_SCULPT) {
+ /* pass */
+ }
+ else if ((t->view_layer->basact) && (ob = t->view_layer->basact->object) &&
+ (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->depsgraph, t->scene, ob)) {
+ /* do nothing */
+ }
+ else if (t->flag & T_CURSOR) {
+ /* do nothing */
+ }
+ else { /* Objects */
+ BLI_assert(t->flag & (T_OBJECT | T_TEXTURE));
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+ bool motionpath_update = false;
+
+ for (int i = 0; i < tc->data_len; i++) {
+ TransData *td = tc->data + i;
+ ListBase pidlist;
+ PTCacheID *pid;
+ ob = td->ob;
+
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ /* flag object caches as outdated */
+ BKE_ptcache_ids_from_object(&pidlist, ob, t->scene, MAX_DUPLI_RECUR);
+ for (pid = pidlist.first; pid; pid = pid->next) {
+ if (pid->type != PTCACHE_TYPE_PARTICLES) {
+ /* particles don't need reset on geometry change */
+ pid->cache->flag |= PTCACHE_OUTDATED;
+ }
+ }
+ BLI_freelistN(&pidlist);
+
+ /* pointcache refresh */
+ if (BKE_ptcache_object_reset(t->scene, ob, PTCACHE_RESET_OUTDATED)) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+
+ /* Needed for proper updating of "quick cached" dynamics. */
+ /* Creates troubles for moving animated objects without */
+ /* autokey though, probably needed is an anim sys override? */
+ /* Please remove if some other solution is found. -jahka */
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+
+ /* Set autokey if necessary */
+ if (!canceled) {
+ autokeyframe_object(C, t->scene, t->view_layer, ob, t->mode);
+ }
+
+ motionpath_update |= motionpath_need_update_object(t->scene, ob);
+
+ /* restore rigid body transform */
+ if (ob->rigidbody_object && canceled) {
+ float ctime = BKE_scene_frame_get(t->scene);
+ if (BKE_rigidbody_check_sim_running(t->scene->rigidbody_world, ctime)) {
+ BKE_rigidbody_aftertrans_update(ob,
+ td->ext->oloc,
+ td->ext->orot,
+ td->ext->oquat,
+ td->ext->orotAxis,
+ td->ext->orotAngle);
+ }
+ }
+ }
+
+ if (motionpath_update) {
+ /* Update motion paths once for all transformed objects. */
+ const eObjectPathCalcRange range = canceled ? OBJECT_PATH_CALC_RANGE_CURRENT_FRAME :
+ OBJECT_PATH_CALC_RANGE_CHANGED;
+ ED_objects_recalculate_paths(C, t->scene, range);
+ }
+ }
+
+ clear_trans_object_base_flags(t);
+}
+
+int special_transform_moving(TransInfo *t)
+{
+ if (t->spacetype == SPACE_SEQ) {
+ return G_TRANSFORM_SEQ;
+ }
+ else if (t->spacetype == SPACE_GRAPH) {
+ return G_TRANSFORM_FCURVES;
+ }
+ else if ((t->flag & T_EDIT) || (t->flag & T_POSE)) {
+ return G_TRANSFORM_EDIT;
+ }
+ else if (t->flag & (T_OBJECT | T_TEXTURE)) {
+ return G_TRANSFORM_OBJ;
+ }
+
+ return 0;
+}
+
+/** \} */
+
+static int countAndCleanTransDataContainer(TransInfo *t)
+{
+ BLI_assert(ELEM(t->data_len_all, 0, -1));
+ t->data_len_all = 0;
+ uint data_container_len_orig = t->data_container_len;
+ for (TransDataContainer *th_end = t->data_container - 1,
+ *tc = t->data_container + (t->data_container_len - 1);
+ tc != th_end;
+ tc--) {
+ if (tc->data_len == 0) {
+ uint index = tc - t->data_container;
+ if (index + 1 != t->data_container_len) {
+ SWAP(TransDataContainer,
+ t->data_container[index],
+ t->data_container[t->data_container_len - 1]);
+ }
+ t->data_container_len -= 1;
+ }
+ else {
+ t->data_len_all += tc->data_len;
+ }
+ }
+ if (data_container_len_orig != t->data_container_len) {
+ t->data_container = MEM_reallocN(t->data_container,
+ sizeof(*t->data_container) * t->data_container_len);
+ }
+ return t->data_len_all;
+}
+
+void createTransData(bContext *C, TransInfo *t)
+{
+ Scene *scene = t->scene;
+ ViewLayer *view_layer = t->view_layer;
+ Object *ob = OBACT(view_layer);
+
+ bool has_transform_context = true;
+ t->data_len_all = -1;
+
+ /* if tests must match recalcData for correct updates */
+ if (t->options & CTX_CURSOR) {
+ t->flag |= T_CURSOR;
+ t->obedit_type = -1;
+
+ if (t->spacetype == SPACE_IMAGE) {
+ createTransCursor_image(t);
+ }
+ else {
+ createTransCursor_view3d(t);
+ }
+ countAndCleanTransDataContainer(t);
+ }
+ else if ((t->options & CTX_SCULPT) && !(t->options & CTX_PAINT_CURVE)) {
+ createTransSculpt(t);
+ countAndCleanTransDataContainer(t);
+ }
+ else if (t->options & CTX_TEXTURE) {
+ t->flag |= T_TEXTURE;
+ t->obedit_type = -1;
+
+ createTransTexspace(t);
+ countAndCleanTransDataContainer(t);
+ }
+ else if (t->options & CTX_EDGE) {
+ /* Multi object editing. */
+ initTransDataContainers_FromObjectData(t, ob, NULL, 0);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ tc->data_ext = NULL;
+ }
+ t->flag |= T_EDIT;
+
+ createTransEdge(t);
+ countAndCleanTransDataContainer(t);
+
+ if (t->data_len_all && t->flag & T_PROP_EDIT) {
+ sort_trans_data_selected_first(t);
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+ }
+ else if (t->options & CTX_GPENCIL_STROKES) {
+ t->options |= CTX_GPENCIL_STROKES;
+ t->flag |= T_POINTS | T_EDIT;
+
+ initTransDataContainers_FromObjectData(t, ob, NULL, 0);
+ createTransGPencil(C, t);
+ countAndCleanTransDataContainer(t);
+
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
+ sort_trans_data_selected_first(t);
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+ }
+ else if (t->spacetype == SPACE_IMAGE) {
+ t->flag |= T_POINTS | T_2D_EDIT;
+ if (t->options & CTX_MASK) {
+
+ /* copied from below */
+ createTransMaskingData(C, t);
+ countAndCleanTransDataContainer(t);
+
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
+ sort_trans_data_selected_first(t);
+ set_prop_dist(t, true);
+ sort_trans_data_dist(t);
+ }
+ }
+ else if (t->options & CTX_PAINT_CURVE) {
+ if (!ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) {
+ createTransPaintCurveVerts(C, t);
+ countAndCleanTransDataContainer(t);
+ }
+ else {
+ has_transform_context = false;
+ }
+ }
+ else if (t->obedit_type == OB_MESH) {
+
+ initTransDataContainers_FromObjectData(t, ob, NULL, 0);
+ createTransUVs(C, t);
+ countAndCleanTransDataContainer(t);
+
+ t->flag |= T_EDIT;
+
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
+ sort_trans_data_selected_first(t);
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+ }
+ else {
+ has_transform_context = false;
+ }
+ }
+ else if (t->spacetype == SPACE_ACTION) {
+ t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
+ createTransActionData(C, t);
+ countAndCleanTransDataContainer(t);
+
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
+ sort_trans_data_selected_first(t);
+ /* don't do that, distance has been set in createTransActionData already */
+ // set_prop_dist(t, false);
+ sort_trans_data_dist(t);
+ }
+ }
+ else if (t->spacetype == SPACE_NLA) {
+ t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
+ createTransNlaData(C, t);
+ countAndCleanTransDataContainer(t);
+ }
+ else if (t->spacetype == SPACE_SEQ) {
+ t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
+ t->num.flag |= NUM_NO_FRACTION; /* sequencer has no use for floating point trasnform */
+ createTransSeqData(C, t);
+ countAndCleanTransDataContainer(t);
+ }
+ else if (t->spacetype == SPACE_GRAPH) {
+ t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
+ createTransGraphEditData(C, t);
+ countAndCleanTransDataContainer(t);
+
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
+ /* makes selected become first in array */
+ sort_trans_data_selected_first(t);
+
+ /* don't do that, distance has been set in createTransGraphEditData already */
+ set_prop_dist(t, false);
+
+ sort_trans_data_dist(t);
+ }
+ }
+ else if (t->spacetype == SPACE_NODE) {
+ t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
+ createTransNodeData(C, t);
+ countAndCleanTransDataContainer(t);
+
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
+ sort_trans_data_selected_first(t);
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+ }
+ else if (t->spacetype == SPACE_CLIP) {
+ t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
+ if (t->options & CTX_MOVIECLIP) {
+ createTransTrackingData(C, t);
+ countAndCleanTransDataContainer(t);
+ }
+ else if (t->options & CTX_MASK) {
+ /* copied from above */
+ createTransMaskingData(C, t);
+ countAndCleanTransDataContainer(t);
+
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
+ sort_trans_data_selected_first(t);
+ set_prop_dist(t, true);
+ sort_trans_data_dist(t);
+ }
+ }
+ else {
+ has_transform_context = false;
+ }
+ }
+ else if (t->obedit_type != -1) {
+ /* Multi object editing. */
+ initTransDataContainers_FromObjectData(t, ob, NULL, 0);
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ tc->data_ext = NULL;
+ }
+ if (t->obedit_type == OB_MESH) {
+ createTransEditVerts(t);
+ }
+ else if (ELEM(t->obedit_type, OB_CURVE, OB_SURF)) {
+ createTransCurveVerts(t);
+ }
+ else if (t->obedit_type == OB_LATTICE) {
+ createTransLatticeVerts(t);
+ }
+ else if (t->obedit_type == OB_MBALL) {
+ createTransMBallVerts(t);
+ }
+ else if (t->obedit_type == OB_ARMATURE) {
+ t->flag &= ~T_PROP_EDIT;
+ createTransArmatureVerts(t);
+ }
+ else {
+ printf("edit type not implemented!\n");
+ }
+
+ countAndCleanTransDataContainer(t);
+
+ t->flag |= T_EDIT | T_POINTS;
+
+ if (t->data_len_all) {
+ if (t->flag & T_PROP_EDIT) {
+ if (ELEM(t->obedit_type, OB_CURVE, OB_MESH)) {
+ sort_trans_data_selected_first(t);
+ if ((t->obedit_type == OB_MESH) && (t->flag & T_PROP_CONNECTED)) {
+ /* already calculated by editmesh_set_connectivity_distance */
+ }
+ else {
+ set_prop_dist(t, 0);
+ }
+ sort_trans_data_dist(t);
+ }
+ else {
+ sort_trans_data_selected_first(t);
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+ }
+ else {
+ if (ELEM(t->obedit_type, OB_CURVE)) {
+ /* Needed because bezier handles can be partially selected
+ * and are still added into transform data. */
+ sort_trans_data_selected_first(t);
+ }
+ }
+ }
+
+ /* exception... hackish, we want bonesize to use bone orientation matrix (ton) */
+ if (t->mode == TFM_BONESIZE) {
+ t->flag &= ~(T_EDIT | T_POINTS);
+ t->flag |= T_POSE;
+ t->obedit_type = -1;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ tc->poseobj = tc->obedit;
+ tc->obedit = NULL;
+ }
+ }
+ }
+ else if (ob && (ob->mode & OB_MODE_POSE)) {
+ /* XXX this is currently limited to active armature only... */
+
+ /* XXX active-layer checking isn't done
+ * as that should probably be checked through context instead. */
+
+ /* Multi object editing. */
+ initTransDataContainers_FromObjectData(t, ob, NULL, 0);
+ createTransPose(t);
+ countAndCleanTransDataContainer(t);
+ }
+ else if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && !(t->options & CTX_PAINT_CURVE)) {
+ /* important that ob_armature can be set even when its not selected [#23412]
+ * lines below just check is also visible */
+ has_transform_context = false;
+ Object *ob_armature = modifiers_isDeformedByArmature(ob);
+ if (ob_armature && ob_armature->mode & OB_MODE_POSE) {
+ Base *base_arm = BKE_view_layer_base_find(t->view_layer, ob_armature);
+ if (base_arm) {
+ View3D *v3d = t->view;
+ if (BASE_VISIBLE(v3d, base_arm)) {
+ Object *objects[1];
+ objects[0] = ob_armature;
+ uint objects_len = 1;
+ initTransDataContainers_FromObjectData(t, ob_armature, objects, objects_len);
+ createTransPose(t);
+ countAndCleanTransDataContainer(t);
+ has_transform_context = true;
+ }
+ }
+ }
+ }
+ else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) &&
+ PE_start_edit(PE_get_current(t->depsgraph, scene, ob))) {
+ createTransParticleVerts(C, t);
+ countAndCleanTransDataContainer(t);
+ t->flag |= T_POINTS;
+
+ if (t->data_len_all && t->flag & T_PROP_EDIT) {
+ sort_trans_data_selected_first(t);
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+ }
+ else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
+ if ((t->options & CTX_PAINT_CURVE) && !ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) {
+ t->flag |= T_POINTS | T_2D_EDIT;
+ createTransPaintCurveVerts(C, t);
+ countAndCleanTransDataContainer(t);
+ }
+ else {
+ has_transform_context = false;
+ }
+ }
+ else if ((ob) &&
+ (ELEM(
+ ob->mode, OB_MODE_PAINT_GPENCIL, OB_MODE_SCULPT_GPENCIL, OB_MODE_WEIGHT_GPENCIL))) {
+ /* In grease pencil all transformations must be canceled if not Object or Edit. */
+ has_transform_context = false;
+ }
+ else {
+ /* Needed for correct Object.obmat after duplication, see: T62135. */
+ BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context));
+
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_DATA_ORIGIN) != 0) {
+ t->options |= CTX_OBMODE_XFORM_OBDATA;
+ }
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_SKIP_CHILDREN) != 0) {
+ t->options |= CTX_OBMODE_XFORM_SKIP_CHILDREN;
+ }
+
+ createTransObject(C, t);
+ countAndCleanTransDataContainer(t);
+ t->flag |= T_OBJECT;
+
+ if (t->data_len_all && t->flag & T_PROP_EDIT) {
+ // selected objects are already first, no need to presort
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+
+ /* Check if we're transforming the camera from the camera */
+ if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) {
+ View3D *v3d = t->view;
+ RegionView3D *rv3d = t->ar->regiondata;
+ if ((rv3d->persp == RV3D_CAMOB) && v3d->camera) {
+ /* we could have a flag to easily check an object is being transformed */
+ if (v3d->camera->id.tag & LIB_TAG_DOIT) {
+ t->flag |= T_CAMERA;
+ }
+ }
+ }
+ }
+
+ /* Check that 'countAndCleanTransDataContainer' ran. */
+ if (has_transform_context) {
+ BLI_assert(t->data_len_all != -1);
+ }
+ else {
+ BLI_assert(t->data_len_all == -1);
+ t->data_len_all = 0;
+ }
+
+ BLI_assert((!(t->flag & T_EDIT)) == (!(t->obedit_type != -1)));
+}
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
new file mode 100644
index 00000000000..53ff9952d05
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert.h
@@ -0,0 +1,141 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#ifndef __TRANSFORM_CONVERT_H__
+#define __TRANSFORM_CONVERT_H__
+
+struct BezTriple;
+struct ListBase;
+struct Object;
+struct TransData;
+struct TransDataContainer;
+struct TransDataCurveHandleFlags;
+struct TransInfo;
+struct bContext;
+struct bKinematicConstraint;
+struct bPoseChannel;
+
+/* transform_convert.c */
+int count_set_pose_transflags(Object *ob,
+ const int mode,
+ const short around,
+ bool has_translate_rotate[2]);
+void transform_autoik_update(TransInfo *t, short mode);
+void autokeyframe_object(struct bContext *C,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ struct Object *ob,
+ int tmode);
+void autokeyframe_pose(
+ struct bContext *C, struct Scene *scene, struct Object *ob, int tmode, short targetless_ik);
+bool motionpath_need_update_object(struct Scene *scene, struct Object *ob);
+bool motionpath_need_update_pose(struct Scene *scene, struct Object *ob);
+int special_transform_moving(TransInfo *t);
+void remake_graph_transdata(TransInfo *t, struct ListBase *anim_data);
+void special_aftertrans_update(struct bContext *C, TransInfo *t);
+void sort_trans_data_dist(TransInfo *t);
+void createTransData(struct bContext *C, TransInfo *t);
+bool clipUVTransform(TransInfo *t, float vec[2], const bool resize);
+void clipUVData(TransInfo *t);
+
+/* transform_convert_action.c */
+void flushTransIntFrameActionData(TransInfo *t);
+/* transform_convert_armature.c */
+void restoreMirrorPoseBones(TransDataContainer *tc);
+void restoreBones(TransDataContainer *tc);
+/* transform_convert_graph.c */
+void flushTransGraphData(TransInfo *t);
+/* transform_convert_mask.c */
+void flushTransMasking(TransInfo *t);
+/* transform_convert_mesh.c */
+void flushTransUVs(TransInfo *t);
+void trans_mesh_customdata_correction_init(TransInfo *t);
+void trans_mesh_customdata_correction_apply(struct TransDataContainer *tc, bool is_final);
+/* transform_convert_node.c */
+void flushTransNodes(TransInfo *t);
+/* transform_convert_object.c */
+void trans_obdata_in_obmode_update_all(struct TransInfo *t);
+void trans_obchild_in_obmode_update_all(struct TransInfo *t);
+/* transform_convert_paintcurve.c */
+void flushTransPaintCurve(TransInfo *t);
+/* transform_convert_particle.c */
+void flushTransParticles(TransInfo *t);
+/* transform_convert_sequencer.c */
+void flushTransSeq(TransInfo *t);
+/* transform_convert_tracking.c */
+void flushTransTracking(TransInfo *t);
+
+/********************* intern **********************/
+
+/* transform_convert.c */
+void transform_around_single_fallback(TransInfo *t);
+bool constraints_list_needinv(TransInfo *t, ListBase *list);
+void calc_distanceCurveVerts(TransData *head, TransData *tail);
+struct TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt);
+bool FrameOnMouseSide(char side, float frame, float cframe);
+
+/* transform_convert_action.c */
+void createTransActionData(bContext *C, TransInfo *t);
+/* transform_convert_armature.c */
+struct bKinematicConstraint *has_targetless_ik(struct bPoseChannel *pchan);
+void createTransPose(TransInfo *t);
+void createTransArmatureVerts(TransInfo *t);
+/* transform_convert_cursor.c */
+void createTransCursor_image(TransInfo *t);
+void createTransCursor_view3d(TransInfo *t);
+/* transform_convert_curve.c */
+void createTransCurveVerts(TransInfo *t);
+/* transform_convert_graph.c */
+void createTransGraphEditData(bContext *C, TransInfo *t);
+/* transform_convert_gpencil.c */
+void createTransGPencil(bContext *C, TransInfo *t);
+/* transform_convert_lattice.c */
+void createTransLatticeVerts(TransInfo *t);
+/* transform_convert_mask.c */
+void createTransMaskingData(bContext *C, TransInfo *t);
+/* transform_convert_mball.c */
+void createTransMBallVerts(TransInfo *t);
+/* transform_convert_mesh.c */
+void createTransEditVerts(TransInfo *t);
+void createTransEdge(TransInfo *t);
+void createTransUVs(bContext *C, TransInfo *t);
+/* transform_convert_nla.c */
+void createTransNlaData(bContext *C, TransInfo *t);
+/* transform_convert_node.c */
+void createTransNodeData(bContext *UNUSED(C), TransInfo *t);
+/* transform_convert_object.c */
+void clear_trans_object_base_flags(TransInfo *t);
+void createTransObject(bContext *C, TransInfo *t);
+void createTransTexspace(TransInfo *t);
+/* transform_convert_paintcurve.c */
+void createTransPaintCurveVerts(bContext *C, TransInfo *t);
+/* transform_convert_particle.c */
+void createTransParticleVerts(bContext *C, TransInfo *t);
+/* transform_convert_sculpt.c */
+void createTransSculpt(TransInfo *t);
+/* transform_convert_sequence.c */
+void createTransSeqData(bContext *C, TransInfo *t);
+/* transform_convert_tracking.c */
+void createTransTrackingData(bContext *C, TransInfo *t);
+void cancelTransTracking(TransInfo *t);
+#endif
diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c
new file mode 100644
index 00000000000..0b1d2757435
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_action.c
@@ -0,0 +1,575 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_anim_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_mask_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_rect.h"
+
+#include "BKE_nla.h"
+#include "BKE_context.h"
+#include "BKE_report.h"
+
+#include "ED_anim_api.h"
+
+#include "UI_view2d.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* helper struct for gp-frame transforms */
+typedef struct tGPFtransdata {
+ float val; /* where transdata writes transform */
+ int *sdata; /* pointer to gpf->framenum */
+} tGPFtransdata;
+
+/* -------------------------------------------------------------------- */
+/** \name Action Transform Creation
+ *
+ * \{ */
+
+/* fully select selected beztriples, but only include if it's on the right side of cfra */
+static int count_fcurve_keys(FCurve *fcu, char side, float cfra, bool is_prop_edit)
+{
+ BezTriple *bezt;
+ int i, count = 0, count_all = 0;
+
+ if (ELEM(NULL, fcu, fcu->bezt)) {
+ return count;
+ }
+
+ /* only include points that occur on the right side of cfra */
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
+ /* no need to adjust the handle selection since they are assumed
+ * selected (like graph editor with SIPO_NOHANDLES) */
+ if (bezt->f2 & SELECT) {
+ count++;
+ }
+
+ count_all++;
+ }
+ }
+
+ if (is_prop_edit && count > 0) {
+ return count_all;
+ }
+ else {
+ return count;
+ }
+}
+
+/* fully select selected beztriples, but only include if it's on the right side of cfra */
+static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra, bool is_prop_edit)
+{
+ bGPDframe *gpf;
+ int count = 0, count_all = 0;
+
+ if (gpl == NULL) {
+ return count;
+ }
+
+ /* only include points that occur on the right side of cfra */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) {
+ if (gpf->flag & GP_FRAME_SELECT) {
+ count++;
+ }
+ count_all++;
+ }
+ }
+
+ if (is_prop_edit && count > 0) {
+ return count_all;
+ }
+ else {
+ return count;
+ }
+}
+
+/* fully select selected beztriples, but only include if it's on the right side of cfra */
+static int count_masklayer_frames(MaskLayer *masklay, char side, float cfra, bool is_prop_edit)
+{
+ MaskLayerShape *masklayer_shape;
+ int count = 0, count_all = 0;
+
+ if (masklay == NULL) {
+ return count;
+ }
+
+ /* only include points that occur on the right side of cfra */
+ for (masklayer_shape = masklay->splines_shapes.first; masklayer_shape;
+ masklayer_shape = masklayer_shape->next) {
+ if (FrameOnMouseSide(side, (float)masklayer_shape->frame, cfra)) {
+ if (masklayer_shape->flag & MASK_SHAPE_SELECT) {
+ count++;
+ }
+ count_all++;
+ }
+ }
+
+ if (is_prop_edit && count > 0) {
+ return count_all;
+ }
+ else {
+ return count;
+ }
+}
+
+/* This function assigns the information to transdata */
+static void TimeToTransData(TransData *td, float *time, AnimData *adt, float ypos)
+{
+ /* memory is calloc'ed, so that should zero everything nicely for us */
+ td->val = time;
+ td->ival = *(time);
+
+ td->center[0] = td->ival;
+ td->center[1] = ypos;
+
+ /* store the AnimData where this keyframe exists as a keyframe of the
+ * active action as td->extra.
+ */
+ td->extra = adt;
+}
+
+/* This function advances the address to which td points to, so it must return
+ * the new address so that the next time new transform data is added, it doesn't
+ * overwrite the existing ones... i.e. td = IcuToTransData(td, icu, ob, side, cfra);
+ *
+ * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
+ * on the named side are used.
+ */
+static TransData *ActionFCurveToTransData(TransData *td,
+ TransData2D **td2dv,
+ FCurve *fcu,
+ AnimData *adt,
+ char side,
+ float cfra,
+ bool is_prop_edit,
+ float ypos)
+{
+ BezTriple *bezt;
+ TransData2D *td2d = *td2dv;
+ int i;
+
+ if (ELEM(NULL, fcu, fcu->bezt)) {
+ return td;
+ }
+
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ /* only add selected keyframes (for now, proportional edit is not enabled) */
+ if (is_prop_edit || (bezt->f2 & SELECT)) { /* note this MUST match count_fcurve_keys(),
+ * so can't use BEZT_ISSEL_ANY() macro */
+ /* only add if on the right 'side' of the current frame */
+ if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
+ TimeToTransData(td, bezt->vec[1], adt, ypos);
+
+ if (bezt->f2 & SELECT) {
+ td->flag |= TD_SELECTED;
+ }
+
+ /*set flags to move handles as necessary*/
+ td->flag |= TD_MOVEHANDLE1 | TD_MOVEHANDLE2;
+ td2d->h1 = bezt->vec[0];
+ td2d->h2 = bezt->vec[2];
+
+ copy_v2_v2(td2d->ih1, td2d->h1);
+ copy_v2_v2(td2d->ih2, td2d->h2);
+
+ td++;
+ td2d++;
+ }
+ }
+ }
+
+ *td2dv = td2d;
+
+ return td;
+}
+
+/* This function advances the address to which td points to, so it must return
+ * the new address so that the next time new transform data is added, it doesn't
+ * overwrite the existing ones... i.e. td = GPLayerToTransData(td, ipo, ob, side, cfra);
+ *
+ * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
+ * on the named side are used.
+ */
+static int GPLayerToTransData(TransData *td,
+ tGPFtransdata *tfd,
+ bGPDlayer *gpl,
+ char side,
+ float cfra,
+ bool is_prop_edit,
+ float ypos)
+{
+ bGPDframe *gpf;
+ int count = 0;
+
+ /* check for select frames on right side of current frame */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (is_prop_edit || (gpf->flag & GP_FRAME_SELECT)) {
+ if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) {
+ /* memory is calloc'ed, so that should zero everything nicely for us */
+ td->val = &tfd->val;
+ td->ival = (float)gpf->framenum;
+
+ td->center[0] = td->ival;
+ td->center[1] = ypos;
+
+ tfd->val = (float)gpf->framenum;
+ tfd->sdata = &gpf->framenum;
+
+ /* advance td now */
+ td++;
+ tfd++;
+ count++;
+ }
+ }
+ }
+
+ return count;
+}
+
+/* refer to comment above #GPLayerToTransData, this is the same but for masks */
+static int MaskLayerToTransData(TransData *td,
+ tGPFtransdata *tfd,
+ MaskLayer *masklay,
+ char side,
+ float cfra,
+ bool is_prop_edit,
+ float ypos)
+{
+ MaskLayerShape *masklay_shape;
+ int count = 0;
+
+ /* check for select frames on right side of current frame */
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
+ masklay_shape = masklay_shape->next) {
+ if (is_prop_edit || (masklay_shape->flag & MASK_SHAPE_SELECT)) {
+ if (FrameOnMouseSide(side, (float)masklay_shape->frame, cfra)) {
+ /* memory is calloc'ed, so that should zero everything nicely for us */
+ td->val = &tfd->val;
+ td->ival = (float)masklay_shape->frame;
+
+ td->center[0] = td->ival;
+ td->center[1] = ypos;
+
+ tfd->val = (float)masklay_shape->frame;
+ tfd->sdata = &masklay_shape->frame;
+
+ /* advance td now */
+ td++;
+ tfd++;
+ count++;
+ }
+ }
+ }
+
+ return count;
+}
+
+void createTransActionData(bContext *C, TransInfo *t)
+{
+ Scene *scene = t->scene;
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ tGPFtransdata *tfd = NULL;
+
+ rcti *mask = &t->ar->v2d.mask;
+ rctf *datamask = &t->ar->v2d.cur;
+
+ float xsize = BLI_rctf_size_x(datamask);
+ float ysize = BLI_rctf_size_y(datamask);
+ float xmask = BLI_rcti_size_x(mask);
+ float ymask = BLI_rcti_size_y(mask);
+
+ bAnimContext ac;
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
+ int count = 0;
+ float cfra;
+ float ypos = 1.0f / ((ysize / xsize) * (xmask / ymask)) * BLI_rctf_cent_y(&t->ar->v2d.cur);
+
+ /* determine what type of data we are operating on */
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return;
+ }
+
+ /* filter data */
+ if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT);
+ }
+ else {
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
+ }
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* which side of the current frame should be allowed */
+ if (t->mode == TFM_TIME_EXTEND) {
+ /* only side on which mouse is gets transformed */
+ float xmouse, ymouse;
+
+ UI_view2d_region_to_view(&ac.ar->v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse);
+ t->frame_side = (xmouse > CFRA) ? 'R' : 'L'; // XXX use t->frame_side
+ }
+ else {
+ /* normal transform - both sides of current frame are considered */
+ t->frame_side = 'B';
+ }
+
+ /* loop 1: fully select ipo-keys and count how many BezTriples are selected */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ int adt_count = 0;
+ /* convert current-frame to action-time (slightly less accurate, especially under
+ * higher scaling ratios, but is faster than converting all points)
+ */
+ if (adt) {
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ }
+ else {
+ cfra = (float)CFRA;
+ }
+
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
+ adt_count = count_fcurve_keys(ale->key_data, t->frame_side, cfra, is_prop_edit);
+ }
+ else if (ale->type == ANIMTYPE_GPLAYER) {
+ adt_count = count_gplayer_frames(ale->data, t->frame_side, cfra, is_prop_edit);
+ }
+ else if (ale->type == ANIMTYPE_MASKLAYER) {
+ adt_count = count_masklayer_frames(ale->data, t->frame_side, cfra, is_prop_edit);
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ if (adt_count > 0) {
+ count += adt_count;
+ ale->tag = true;
+ }
+ }
+
+ /* stop if trying to build list if nothing selected */
+ if (count == 0) {
+ /* cleanup temp list */
+ ANIM_animdata_freelist(&anim_data);
+ return;
+ }
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* allocate memory for data */
+ tc->data_len = count;
+
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(Action Editor)");
+ tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "transdata2d");
+ td = tc->data;
+ td2d = tc->data_2d;
+
+ if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ tc->custom.type.data = tfd = MEM_callocN(sizeof(tGPFtransdata) * count, "tGPFtransdata");
+ tc->custom.type.use_free = true;
+ }
+
+ /* loop 2: build transdata array */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+
+ if (is_prop_edit && !ale->tag) {
+ continue;
+ }
+
+ cfra = (float)CFRA;
+
+ {
+ AnimData *adt;
+ adt = ANIM_nla_mapping_get(&ac, ale);
+ if (adt) {
+ cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
+ }
+ }
+
+ if (ale->type == ANIMTYPE_GPLAYER) {
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+ int i;
+
+ i = GPLayerToTransData(td, tfd, gpl, t->frame_side, cfra, is_prop_edit, ypos);
+ td += i;
+ tfd += i;
+ }
+ else if (ale->type == ANIMTYPE_MASKLAYER) {
+ MaskLayer *masklay = (MaskLayer *)ale->data;
+ int i;
+
+ i = MaskLayerToTransData(td, tfd, masklay, t->frame_side, cfra, is_prop_edit, ypos);
+ td += i;
+ tfd += i;
+ }
+ else {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ FCurve *fcu = (FCurve *)ale->key_data;
+
+ td = ActionFCurveToTransData(td, &td2d, fcu, adt, t->frame_side, cfra, is_prop_edit, ypos);
+ }
+ }
+
+ /* calculate distances for proportional editing */
+ if (is_prop_edit) {
+ td = tc->data;
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt;
+
+ /* F-Curve may not have any keyframes */
+ if (!ale->tag) {
+ continue;
+ }
+
+ adt = ANIM_nla_mapping_get(&ac, ale);
+ if (adt) {
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ }
+ else {
+ cfra = (float)CFRA;
+ }
+
+ if (ale->type == ANIMTYPE_GPLAYER) {
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+ bGPDframe *gpf;
+
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (gpf->flag & GP_FRAME_SELECT) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ bGPDframe *gpf_iter;
+ int min = INT_MAX;
+ for (gpf_iter = gpl->frames.first; gpf_iter; gpf_iter = gpf_iter->next) {
+ if (gpf_iter->flag & GP_FRAME_SELECT) {
+ if (FrameOnMouseSide(t->frame_side, (float)gpf_iter->framenum, cfra)) {
+ int val = abs(gpf->framenum - gpf_iter->framenum);
+ if (val < min) {
+ min = val;
+ }
+ }
+ }
+ }
+ td->dist = td->rdist = min;
+ }
+ td++;
+ }
+ }
+ else if (ale->type == ANIMTYPE_MASKLAYER) {
+ MaskLayer *masklay = (MaskLayer *)ale->data;
+ MaskLayerShape *masklay_shape;
+
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
+ masklay_shape = masklay_shape->next) {
+ if (FrameOnMouseSide(t->frame_side, (float)masklay_shape->frame, cfra)) {
+ if (masklay_shape->flag & MASK_SHAPE_SELECT) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ MaskLayerShape *masklay_iter;
+ int min = INT_MAX;
+ for (masklay_iter = masklay->splines_shapes.first; masklay_iter;
+ masklay_iter = masklay_iter->next) {
+ if (masklay_iter->flag & MASK_SHAPE_SELECT) {
+ if (FrameOnMouseSide(t->frame_side, (float)masklay_iter->frame, cfra)) {
+ int val = abs(masklay_shape->frame - masklay_iter->frame);
+ if (val < min) {
+ min = val;
+ }
+ }
+ }
+ }
+ td->dist = td->rdist = min;
+ }
+ td++;
+ }
+ }
+ }
+ else {
+ FCurve *fcu = (FCurve *)ale->key_data;
+ BezTriple *bezt;
+ int i;
+
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ if (bezt->f2 & SELECT) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ BezTriple *bezt_iter;
+ int j;
+ float min = FLT_MAX;
+ for (j = 0, bezt_iter = fcu->bezt; j < fcu->totvert; j++, bezt_iter++) {
+ if (bezt_iter->f2 & SELECT) {
+ if (FrameOnMouseSide(t->frame_side, (float)bezt_iter->vec[1][0], cfra)) {
+ float val = fabs(bezt->vec[1][0] - bezt_iter->vec[1][0]);
+ if (val < min) {
+ min = val;
+ }
+ }
+ }
+ }
+ td->dist = td->rdist = min;
+ }
+ td++;
+ }
+ }
+ }
+ }
+ }
+
+ /* cleanup temp list */
+ ANIM_animdata_freelist(&anim_data);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Action Transform Flush
+ *
+ * \{ */
+
+/* This function helps flush transdata written to tempdata into the gp-frames */
+void flushTransIntFrameActionData(TransInfo *t)
+{
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+ tGPFtransdata *tfd = tc->custom.type.data;
+
+ /* flush data! */
+ for (int i = 0; i < tc->data_len; i++, tfd++) {
+ *(tfd->sdata) = round_fl_to_int(tfd->val);
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
new file mode 100644
index 00000000000..cc023688c8e
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -0,0 +1,933 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+
+#include "BIK_api.h"
+
+#include "ED_armature.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan)
+{
+ bConstraint *con = pchan->constraints.first;
+
+ for (; con; con = con->next) {
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce != 0.0f)) {
+ bKinematicConstraint *data = con->data;
+
+ if (data->tar == NULL) {
+ return data;
+ }
+ if (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0) {
+ return data;
+ }
+ }
+ }
+ return NULL;
+}
+
+static void add_pose_transdata(
+ TransInfo *t, bPoseChannel *pchan, Object *ob, TransDataContainer *tc, TransData *td)
+{
+ Bone *bone = pchan->bone;
+ float pmat[3][3], omat[3][3];
+ float cmat[3][3], tmat[3][3];
+ float vec[3];
+
+ copy_v3_v3(vec, pchan->pose_mat[3]);
+ copy_v3_v3(td->center, vec);
+
+ td->ob = ob;
+ td->flag = TD_SELECTED;
+ if (bone->flag & BONE_HINGE_CHILD_TRANSFORM) {
+ td->flag |= TD_NOCENTER;
+ }
+
+ if (bone->flag & BONE_TRANSFORM_CHILD) {
+ td->flag |= TD_NOCENTER;
+ td->flag |= TD_NO_LOC;
+ }
+
+ td->protectflag = pchan->protectflag;
+
+ td->loc = pchan->loc;
+ copy_v3_v3(td->iloc, pchan->loc);
+
+ td->ext->size = pchan->size;
+ copy_v3_v3(td->ext->isize, pchan->size);
+
+ if (pchan->rotmode > 0) {
+ td->ext->rot = pchan->eul;
+ td->ext->rotAxis = NULL;
+ td->ext->rotAngle = NULL;
+ td->ext->quat = NULL;
+
+ copy_v3_v3(td->ext->irot, pchan->eul);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ td->ext->rot = NULL;
+ td->ext->rotAxis = pchan->rotAxis;
+ td->ext->rotAngle = &pchan->rotAngle;
+ td->ext->quat = NULL;
+
+ td->ext->irotAngle = pchan->rotAngle;
+ copy_v3_v3(td->ext->irotAxis, pchan->rotAxis);
+ }
+ else {
+ td->ext->rot = NULL;
+ td->ext->rotAxis = NULL;
+ td->ext->rotAngle = NULL;
+ td->ext->quat = pchan->quat;
+
+ copy_qt_qt(td->ext->iquat, pchan->quat);
+ }
+ td->ext->rotOrder = pchan->rotmode;
+
+ /* proper way to get parent transform + own transform + constraints transform */
+ copy_m3_m4(omat, ob->obmat);
+
+ /* New code, using "generic" BKE_bone_parent_transform_calc_from_pchan(). */
+ {
+ BoneParentTransform bpt;
+ float rpmat[3][3];
+
+ BKE_bone_parent_transform_calc_from_pchan(pchan, &bpt);
+ if (t->mode == TFM_TRANSLATION) {
+ copy_m3_m4(pmat, bpt.loc_mat);
+ }
+ else {
+ copy_m3_m4(pmat, bpt.rotscale_mat);
+ }
+
+ /* Grrr! Exceptional case: When translating pose bones that are either Hinge or NoLocal,
+ * and want align snapping, we just need both loc_mat and rotscale_mat.
+ * So simply always store rotscale mat in td->ext, and always use it to apply rotations...
+ * Ugly to need such hacks! :/ */
+ copy_m3_m4(rpmat, bpt.rotscale_mat);
+
+ if (constraints_list_needinv(t, &pchan->constraints)) {
+ copy_m3_m4(tmat, pchan->constinv);
+ invert_m3_m3(cmat, tmat);
+ mul_m3_series(td->mtx, cmat, omat, pmat);
+ mul_m3_series(td->ext->r_mtx, cmat, omat, rpmat);
+ }
+ else {
+ mul_m3_series(td->mtx, omat, pmat);
+ mul_m3_series(td->ext->r_mtx, omat, rpmat);
+ }
+ invert_m3_m3(td->ext->r_smtx, td->ext->r_mtx);
+ }
+
+ pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
+
+ /* exceptional case: rotate the pose bone which also applies transformation
+ * when a parentless bone has BONE_NO_LOCAL_LOCATION [] */
+ if (!ELEM(t->mode, TFM_TRANSLATION, TFM_RESIZE) &&
+ (pchan->bone->flag & BONE_NO_LOCAL_LOCATION)) {
+ if (pchan->parent) {
+ /* same as td->smtx but without pchan->bone->bone_mat */
+ td->flag |= TD_PBONE_LOCAL_MTX_C;
+ mul_m3_m3m3(td->ext->l_smtx, pchan->bone->bone_mat, td->smtx);
+ }
+ else {
+ td->flag |= TD_PBONE_LOCAL_MTX_P;
+ }
+ }
+
+ /* for axismat we use bone's own transform */
+ copy_m3_m4(pmat, pchan->pose_mat);
+ mul_m3_m3m3(td->axismtx, omat, pmat);
+ normalize_m3(td->axismtx);
+
+ if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
+ bArmature *arm = tc->poseobj->data;
+
+ if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
+ td->loc = NULL;
+ td->val = &bone->dist;
+ td->ival = bone->dist;
+ }
+ else {
+ // abusive storage of scale in the loc pointer :)
+ td->loc = &bone->xwidth;
+ copy_v3_v3(td->iloc, td->loc);
+ td->val = NULL;
+ }
+ }
+
+ /* in this case we can do target-less IK grabbing */
+ if (t->mode == TFM_TRANSLATION) {
+ bKinematicConstraint *data = has_targetless_ik(pchan);
+ if (data) {
+ if (data->flag & CONSTRAINT_IK_TIP) {
+ copy_v3_v3(data->grabtarget, pchan->pose_tail);
+ }
+ else {
+ copy_v3_v3(data->grabtarget, pchan->pose_head);
+ }
+ td->loc = data->grabtarget;
+ copy_v3_v3(td->iloc, td->loc);
+ data->flag |= CONSTRAINT_IK_AUTO;
+
+ /* only object matrix correction */
+ copy_m3_m3(td->mtx, omat);
+ pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
+ }
+ }
+
+ /* store reference to first constraint */
+ td->con = pchan->constraints.first;
+}
+
+/* adds the IK to pchan - returns if added */
+static short pose_grab_with_ik_add(bPoseChannel *pchan)
+{
+ bKinematicConstraint *targetless = NULL;
+ bKinematicConstraint *data;
+ bConstraint *con;
+
+ /* Sanity check */
+ if (pchan == NULL) {
+ return 0;
+ }
+
+ /* Rule: not if there's already an IK on this channel */
+ for (con = pchan->constraints.first; con; con = con->next) {
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
+ data = con->data;
+
+ if (data->tar == NULL || (data->tar->type == OB_ARMATURE && data->subtarget[0] == '\0')) {
+ /* make reference to constraint to base things off later
+ * (if it's the last targetless constraint encountered) */
+ targetless = (bKinematicConstraint *)con->data;
+
+ /* but, if this is a targetless IK, we make it auto anyway (for the children loop) */
+ if (con->enforce != 0.0f) {
+ data->flag |= CONSTRAINT_IK_AUTO;
+
+ /* if no chain length has been specified,
+ * just make things obey standard rotation locks too */
+ if (data->rootbone == 0) {
+ for (; pchan; pchan = pchan->parent) {
+ /* here, we set ik-settings for bone from pchan->protectflag */
+ // XXX: careful with quats/axis-angle rotations where we're locking 4d components
+ if (pchan->protectflag & OB_LOCK_ROTX) {
+ pchan->ikflag |= BONE_IK_NO_XDOF_TEMP;
+ }
+ if (pchan->protectflag & OB_LOCK_ROTY) {
+ pchan->ikflag |= BONE_IK_NO_YDOF_TEMP;
+ }
+ if (pchan->protectflag & OB_LOCK_ROTZ) {
+ pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP;
+ }
+ }
+ }
+
+ return 0;
+ }
+ }
+
+ if ((con->flag & CONSTRAINT_DISABLE) == 0 && (con->enforce != 0.0f)) {
+ return 0;
+ }
+ }
+ }
+
+ con = BKE_constraint_add_for_pose(NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC);
+
+ /* for draw, but also for detecting while pose solving */
+ pchan->constflag |= (PCHAN_HAS_IK | PCHAN_HAS_TARGET);
+
+ data = con->data;
+ if (targetless) {
+ /* if exists, use values from last targetless (but disabled) IK-constraint as base */
+ *data = *targetless;
+ }
+ else {
+ data->flag = CONSTRAINT_IK_TIP;
+ }
+ data->flag |= CONSTRAINT_IK_TEMP | CONSTRAINT_IK_AUTO | CONSTRAINT_IK_POS;
+ copy_v3_v3(data->grabtarget, pchan->pose_tail);
+
+ /* watch-it! has to be 0 here, since we're still on the
+ * same bone for the first time through the loop T25885. */
+ data->rootbone = 0;
+
+ /* we only include bones that are part of a continual connected chain */
+ do {
+ /* here, we set ik-settings for bone from pchan->protectflag */
+ // XXX: careful with quats/axis-angle rotations where we're locking 4d components
+ if (pchan->protectflag & OB_LOCK_ROTX) {
+ pchan->ikflag |= BONE_IK_NO_XDOF_TEMP;
+ }
+ if (pchan->protectflag & OB_LOCK_ROTY) {
+ pchan->ikflag |= BONE_IK_NO_YDOF_TEMP;
+ }
+ if (pchan->protectflag & OB_LOCK_ROTZ) {
+ pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP;
+ }
+
+ /* now we count this pchan as being included */
+ data->rootbone++;
+
+ /* continue to parent, but only if we're connected to it */
+ if (pchan->bone->flag & BONE_CONNECTED) {
+ pchan = pchan->parent;
+ }
+ else {
+ pchan = NULL;
+ }
+ } while (pchan);
+
+ /* make a copy of maximum chain-length */
+ data->max_rootbone = data->rootbone;
+
+ return 1;
+}
+
+/* bone is a candidate to get IK, but we don't do it if it has children connected */
+static short pose_grab_with_ik_children(bPose *pose, Bone *bone)
+{
+ Bone *bonec;
+ short wentdeeper = 0, added = 0;
+
+ /* go deeper if children & children are connected */
+ for (bonec = bone->childbase.first; bonec; bonec = bonec->next) {
+ if (bonec->flag & BONE_CONNECTED) {
+ wentdeeper = 1;
+ added += pose_grab_with_ik_children(pose, bonec);
+ }
+ }
+ if (wentdeeper == 0) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(pose, bone->name);
+ if (pchan) {
+ added += pose_grab_with_ik_add(pchan);
+ }
+ }
+
+ return added;
+}
+
+/* main call which adds temporal IK chains */
+static short pose_grab_with_ik(Main *bmain, Object *ob)
+{
+ bArmature *arm;
+ bPoseChannel *pchan, *parent;
+ Bone *bonec;
+ short tot_ik = 0;
+
+ if ((ob == NULL) || (ob->pose == NULL) || (ob->mode & OB_MODE_POSE) == 0) {
+ return 0;
+ }
+
+ arm = ob->data;
+
+ /* Rule: allow multiple Bones
+ * (but they must be selected, and only one ik-solver per chain should get added) */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone->layer & arm->layer) {
+ if (pchan->bone->flag & BONE_SELECTED) {
+ /* Rule: no IK for solitatry (unconnected) bones */
+ for (bonec = pchan->bone->childbase.first; bonec; bonec = bonec->next) {
+ if (bonec->flag & BONE_CONNECTED) {
+ break;
+ }
+ }
+ if ((pchan->bone->flag & BONE_CONNECTED) == 0 && (bonec == NULL)) {
+ continue;
+ }
+
+ /* rule: if selected Bone is not a root bone, it gets a temporal IK */
+ if (pchan->parent) {
+ /* only adds if there's no IK yet (and no parent bone was selected) */
+ for (parent = pchan->parent; parent; parent = parent->parent) {
+ if (parent->bone->flag & BONE_SELECTED) {
+ break;
+ }
+ }
+ if (parent == NULL) {
+ tot_ik += pose_grab_with_ik_add(pchan);
+ }
+ }
+ else {
+ /* rule: go over the children and add IK to the tips */
+ tot_ik += pose_grab_with_ik_children(ob->pose, pchan->bone);
+ }
+ }
+ }
+ }
+
+ /* iTaSC needs clear for new IK constraints */
+ if (tot_ik) {
+ BIK_clear_data(ob->pose);
+ /* TODO(sergey): Consider doing partial update only. */
+ DEG_relations_tag_update(bmain);
+ }
+
+ return (tot_ik) ? 1 : 0;
+}
+
+static void pose_mirror_info_init(PoseInitData_Mirror *pid,
+ bPoseChannel *pchan,
+ bPoseChannel *pchan_orig,
+ bool is_mirror_relative)
+{
+ pid->pchan = pchan;
+ copy_v3_v3(pid->orig.loc, pchan->loc);
+ copy_v3_v3(pid->orig.size, pchan->size);
+ pid->orig.curve_in_x = pchan->curve_in_x;
+ pid->orig.curve_out_x = pchan->curve_out_x;
+ pid->orig.roll1 = pchan->roll1;
+ pid->orig.roll2 = pchan->roll2;
+
+ if (pchan->rotmode > 0) {
+ copy_v3_v3(pid->orig.eul, pchan->eul);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ copy_v3_v3(pid->orig.axis_angle, pchan->rotAxis);
+ pid->orig.axis_angle[3] = pchan->rotAngle;
+ }
+ else {
+ copy_qt_qt(pid->orig.quat, pchan->quat);
+ }
+
+ if (is_mirror_relative) {
+ float pchan_mtx[4][4];
+ float pchan_mtx_mirror[4][4];
+
+ float flip_mtx[4][4];
+ unit_m4(flip_mtx);
+ flip_mtx[0][0] = -1;
+
+ BKE_pchan_to_mat4(pchan_orig, pchan_mtx_mirror);
+ BKE_pchan_to_mat4(pchan, pchan_mtx);
+
+ mul_m4_m4m4(pchan_mtx_mirror, pchan_mtx_mirror, flip_mtx);
+ mul_m4_m4m4(pchan_mtx_mirror, flip_mtx, pchan_mtx_mirror);
+
+ invert_m4(pchan_mtx_mirror);
+ mul_m4_m4m4(pid->offset_mtx, pchan_mtx, pchan_mtx_mirror);
+ }
+ else {
+ unit_m4(pid->offset_mtx);
+ }
+}
+
+static void pose_mirror_info_restore(const PoseInitData_Mirror *pid)
+{
+ bPoseChannel *pchan = pid->pchan;
+ copy_v3_v3(pchan->loc, pid->orig.loc);
+ copy_v3_v3(pchan->size, pid->orig.size);
+ pchan->curve_in_x = pid->orig.curve_in_x;
+ pchan->curve_out_x = pid->orig.curve_out_x;
+ pchan->roll1 = pid->orig.roll1;
+ pchan->roll2 = pid->orig.roll2;
+
+ if (pchan->rotmode > 0) {
+ copy_v3_v3(pchan->eul, pid->orig.eul);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ copy_v3_v3(pchan->rotAxis, pid->orig.axis_angle);
+ pchan->rotAngle = pid->orig.axis_angle[3];
+ }
+ else {
+ copy_qt_qt(pchan->quat, pid->orig.quat);
+ }
+}
+
+/**
+ * When objects array is NULL, use 't->data_container' as is.
+ */
+void createTransPose(TransInfo *t)
+{
+ Main *bmain = CTX_data_main(t->context);
+
+ t->data_len_all = 0;
+
+ bool has_translate_rotate_buf[2] = {false, false};
+ bool *has_translate_rotate = (t->mode == TFM_TRANSLATION) ? has_translate_rotate_buf : NULL;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Object *ob = tc->poseobj;
+ bPose *pose = ob->pose;
+
+ bArmature *arm;
+
+ /* check validity of state */
+ arm = BKE_armature_from_object(tc->poseobj);
+ if ((arm == NULL) || (pose == NULL)) {
+ continue;
+ }
+
+ const bool mirror = ((pose->flag & POSE_MIRROR_EDIT) != 0);
+
+ /* set flags and count total */
+ tc->data_len = count_set_pose_transflags(ob, t->mode, t->around, has_translate_rotate);
+ if (tc->data_len == 0) {
+ continue;
+ }
+
+ if (arm->flag & ARM_RESTPOS) {
+ if (ELEM(t->mode, TFM_DUMMY, TFM_BONESIZE) == 0) {
+ BKE_report(t->reports, RPT_ERROR, "Cannot change Pose when 'Rest Position' is enabled");
+ tc->data_len = 0;
+ continue;
+ }
+ }
+
+ /* do we need to add temporal IK chains? */
+ if ((pose->flag & POSE_AUTO_IK) && t->mode == TFM_TRANSLATION) {
+ if (pose_grab_with_ik(bmain, ob)) {
+ t->flag |= T_AUTOIK;
+ has_translate_rotate[0] = true;
+ }
+ }
+
+ if (mirror) {
+ int total_mirrored = 0;
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if ((pchan->bone->flag & BONE_TRANSFORM) &&
+ BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) {
+ total_mirrored++;
+ }
+ }
+
+ PoseInitData_Mirror *pid = MEM_mallocN((total_mirrored + 1) * sizeof(PoseInitData_Mirror),
+ "PoseInitData_Mirror");
+
+ /* Trick to terminate iteration. */
+ pid[total_mirrored].pchan = NULL;
+
+ tc->custom.type.data = pid;
+ tc->custom.type.use_free = true;
+ }
+ }
+
+ /* if there are no translatable bones, do rotation */
+ if ((t->mode == TFM_TRANSLATION) && !has_translate_rotate[0]) {
+ if (has_translate_rotate[1]) {
+ t->mode = TFM_ROTATION;
+ }
+ else {
+ t->mode = TFM_RESIZE;
+ }
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (tc->data_len == 0) {
+ continue;
+ }
+ Object *ob = tc->poseobj;
+ TransData *td;
+ TransDataExtension *tdx;
+ int i;
+
+ PoseInitData_Mirror *pid = tc->custom.type.data;
+ int pid_index = 0;
+ bPose *pose = ob->pose;
+
+ if (pose == NULL) {
+ continue;
+ }
+
+ const bool mirror = ((pose->flag & POSE_MIRROR_EDIT) != 0);
+ const bool is_mirror_relative = ((pose->flag & POSE_MIRROR_RELATIVE) != 0);
+
+ tc->poseobj = ob; /* we also allow non-active objects to be transformed, in weightpaint */
+
+ /* init trans data */
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransPoseBone");
+ tdx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension),
+ "TransPoseBoneExt");
+ for (i = 0; i < tc->data_len; i++, td++, tdx++) {
+ td->ext = tdx;
+ td->val = NULL;
+ }
+
+ /* use pose channels to fill trans data */
+ td = tc->data;
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone->flag & BONE_TRANSFORM) {
+ add_pose_transdata(t, pchan, ob, tc, td);
+
+ if (mirror) {
+ bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name);
+ if (pchan_mirror) {
+ pose_mirror_info_init(&pid[pid_index], pchan_mirror, pchan, is_mirror_relative);
+ pid_index++;
+ }
+ }
+
+ td++;
+ }
+ }
+
+ if (td != (tc->data + tc->data_len)) {
+ BKE_report(t->reports, RPT_DEBUG, "Bone selection count error");
+ }
+
+ /* initialize initial auto=ik chainlen's? */
+ if (t->flag & T_AUTOIK) {
+ transform_autoik_update(t, 0);
+ }
+ }
+
+ t->flag |= T_POSE;
+ /* disable PET, its not usable in pose mode yet [#32444] */
+ t->flag &= ~T_PROP_EDIT_ALL;
+}
+
+void restoreMirrorPoseBones(TransDataContainer *tc)
+{
+ bPose *pose = tc->poseobj->pose;
+
+ if (!(pose->flag & POSE_MIRROR_EDIT)) {
+ return;
+ }
+
+ for (PoseInitData_Mirror *pid = tc->custom.type.data; pid->pchan; pid++) {
+ pose_mirror_info_restore(pid);
+ }
+}
+
+void restoreBones(TransDataContainer *tc)
+{
+ bArmature *arm;
+ BoneInitData *bid = tc->custom.type.data;
+ EditBone *ebo;
+
+ if (tc->obedit) {
+ arm = tc->obedit->data;
+ }
+ else {
+ BLI_assert(tc->poseobj != NULL);
+ arm = tc->poseobj->data;
+ }
+
+ while (bid->bone) {
+ ebo = bid->bone;
+
+ ebo->dist = bid->dist;
+ ebo->rad_head = bid->rad_head;
+ ebo->rad_tail = bid->rad_tail;
+ ebo->roll = bid->roll;
+ ebo->xwidth = bid->xwidth;
+ ebo->zwidth = bid->zwidth;
+ copy_v3_v3(ebo->head, bid->head);
+ copy_v3_v3(ebo->tail, bid->tail);
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ EditBone *ebo_child;
+
+ /* Also move connected ebo_child, in case ebo_child's name aren't mirrored properly */
+ for (ebo_child = arm->edbo->first; ebo_child; ebo_child = ebo_child->next) {
+ if ((ebo_child->flag & BONE_CONNECTED) && (ebo_child->parent == ebo)) {
+ copy_v3_v3(ebo_child->head, ebo->tail);
+ ebo_child->rad_head = ebo->rad_tail;
+ }
+ }
+
+ /* Also move connected parent, in case parent's name isn't mirrored properly */
+ if ((ebo->flag & BONE_CONNECTED) && ebo->parent) {
+ EditBone *parent = ebo->parent;
+ copy_v3_v3(parent->tail, ebo->head);
+ parent->rad_tail = ebo->rad_head;
+ }
+ }
+
+ bid++;
+ }
+}
+
+/* ********************* armature ************** */
+void createTransArmatureVerts(TransInfo *t)
+{
+ t->data_len_all = 0;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ EditBone *ebo, *eboflip;
+ bArmature *arm = tc->obedit->data;
+ ListBase *edbo = arm->edbo;
+ bool mirror = ((arm->flag & ARM_MIRROR_EDIT) != 0);
+ int total_mirrored = 0;
+
+ tc->data_len = 0;
+ for (ebo = edbo->first; ebo; ebo = ebo->next) {
+ const int data_len_prev = tc->data_len;
+
+ if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
+ if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
+ if (ebo->flag & BONE_SELECTED) {
+ tc->data_len++;
+ }
+ }
+ else if (t->mode == TFM_BONE_ROLL) {
+ if (ebo->flag & BONE_SELECTED) {
+ tc->data_len++;
+ }
+ }
+ else {
+ if (ebo->flag & BONE_TIPSEL) {
+ tc->data_len++;
+ }
+ if (ebo->flag & BONE_ROOTSEL) {
+ tc->data_len++;
+ }
+ }
+ }
+
+ if (mirror && (data_len_prev < tc->data_len)) {
+ eboflip = ED_armature_ebone_get_mirrored(arm->edbo, ebo);
+ if (eboflip) {
+ total_mirrored++;
+ }
+ }
+ }
+ if (!tc->data_len) {
+ continue;
+ }
+
+ if (mirror) {
+ BoneInitData *bid = MEM_mallocN((total_mirrored + 1) * sizeof(BoneInitData), "BoneInitData");
+
+ /* trick to terminate iteration */
+ bid[total_mirrored].bone = NULL;
+
+ tc->custom.type.data = bid;
+ tc->custom.type.use_free = true;
+ }
+ t->data_len_all += tc->data_len;
+ }
+
+ transform_around_single_fallback(t);
+ t->data_len_all = -1;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (!tc->data_len) {
+ continue;
+ }
+
+ EditBone *ebo, *eboflip;
+ bArmature *arm = tc->obedit->data;
+ ListBase *edbo = arm->edbo;
+ TransData *td, *td_old;
+ float mtx[3][3], smtx[3][3], bonemat[3][3];
+ bool mirror = ((arm->flag & ARM_MIRROR_EDIT) != 0);
+ BoneInitData *bid = tc->custom.type.data;
+
+ copy_m3_m4(mtx, tc->obedit->obmat);
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransEditBone");
+ int i = 0;
+
+ for (ebo = edbo->first; ebo; ebo = ebo->next) {
+ td_old = td;
+ ebo->oldlength =
+ ebo->length; // length==0.0 on extrude, used for scaling radius of bone points
+
+ if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
+ if (t->mode == TFM_BONE_ENVELOPE) {
+ if (ebo->flag & BONE_ROOTSEL) {
+ td->val = &ebo->rad_head;
+ td->ival = *td->val;
+
+ copy_v3_v3(td->center, ebo->head);
+ td->flag = TD_SELECTED;
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+
+ td->loc = NULL;
+ td->ext = NULL;
+ td->ob = tc->obedit;
+
+ td++;
+ }
+ if (ebo->flag & BONE_TIPSEL) {
+ td->val = &ebo->rad_tail;
+ td->ival = *td->val;
+ copy_v3_v3(td->center, ebo->tail);
+ td->flag = TD_SELECTED;
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+
+ td->loc = NULL;
+ td->ext = NULL;
+ td->ob = tc->obedit;
+
+ td++;
+ }
+ }
+ else if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
+ if (ebo->flag & BONE_SELECTED) {
+ if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
+ td->loc = NULL;
+ td->val = &ebo->dist;
+ td->ival = ebo->dist;
+ }
+ else {
+ // abusive storage of scale in the loc pointer :)
+ td->loc = &ebo->xwidth;
+ copy_v3_v3(td->iloc, td->loc);
+ td->val = NULL;
+ }
+ copy_v3_v3(td->center, ebo->head);
+ td->flag = TD_SELECTED;
+
+ /* use local bone matrix */
+ ED_armature_ebone_to_mat3(ebo, bonemat);
+ mul_m3_m3m3(td->mtx, mtx, bonemat);
+ invert_m3_m3(td->smtx, td->mtx);
+
+ copy_m3_m3(td->axismtx, td->mtx);
+ normalize_m3(td->axismtx);
+
+ td->ext = NULL;
+ td->ob = tc->obedit;
+
+ td++;
+ }
+ }
+ else if (t->mode == TFM_BONE_ROLL) {
+ if (ebo->flag & BONE_SELECTED) {
+ td->loc = NULL;
+ td->val = &(ebo->roll);
+ td->ival = ebo->roll;
+
+ copy_v3_v3(td->center, ebo->head);
+ td->flag = TD_SELECTED;
+
+ td->ext = NULL;
+ td->ob = tc->obedit;
+
+ td++;
+ }
+ }
+ else {
+ if (ebo->flag & BONE_TIPSEL) {
+ copy_v3_v3(td->iloc, ebo->tail);
+
+ /* Don't allow single selected tips to have a modified center,
+ * causes problem with snapping (see T45974).
+ * However, in rotation mode, we want to keep that 'rotate bone around root with
+ * only its tip selected' behavior (see T46325). */
+ if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ ((t->mode == TFM_ROTATION) || (ebo->flag & BONE_ROOTSEL))) {
+ copy_v3_v3(td->center, ebo->head);
+ }
+ else {
+ copy_v3_v3(td->center, td->iloc);
+ }
+
+ td->loc = ebo->tail;
+ td->flag = TD_SELECTED;
+ if (ebo->flag & BONE_EDITMODE_LOCKED) {
+ td->protectflag = OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE;
+ }
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+
+ ED_armature_ebone_to_mat3(ebo, td->axismtx);
+
+ if ((ebo->flag & BONE_ROOTSEL) == 0) {
+ td->extra = ebo;
+ td->ival = ebo->roll;
+ }
+
+ td->ext = NULL;
+ td->val = NULL;
+ td->ob = tc->obedit;
+
+ td++;
+ }
+ if (ebo->flag & BONE_ROOTSEL) {
+ copy_v3_v3(td->iloc, ebo->head);
+ copy_v3_v3(td->center, td->iloc);
+ td->loc = ebo->head;
+ td->flag = TD_SELECTED;
+ if (ebo->flag & BONE_EDITMODE_LOCKED) {
+ td->protectflag = OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE;
+ }
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+
+ ED_armature_ebone_to_mat3(ebo, td->axismtx);
+
+ td->extra = ebo; /* to fix roll */
+ td->ival = ebo->roll;
+
+ td->ext = NULL;
+ td->val = NULL;
+ td->ob = tc->obedit;
+
+ td++;
+ }
+ }
+ }
+
+ if (mirror && (td_old != td)) {
+ eboflip = ED_armature_ebone_get_mirrored(arm->edbo, ebo);
+ if (eboflip) {
+ bid[i].bone = eboflip;
+ bid[i].dist = eboflip->dist;
+ bid[i].rad_head = eboflip->rad_head;
+ bid[i].rad_tail = eboflip->rad_tail;
+ bid[i].roll = eboflip->roll;
+ bid[i].xwidth = eboflip->xwidth;
+ bid[i].zwidth = eboflip->zwidth;
+ copy_v3_v3(bid[i].head, eboflip->head);
+ copy_v3_v3(bid[i].tail, eboflip->tail);
+ i++;
+ }
+ }
+ }
+
+ if (mirror) {
+ /* trick to terminate iteration */
+ BLI_assert(i + 1 == (MEM_allocN_len(bid) / sizeof(*bid)));
+ bid[i].bone = NULL;
+ }
+ }
+}
diff --git a/source/blender/editors/transform/transform_convert_cursor.c b/source/blender/editors/transform/transform_convert_cursor.c
new file mode 100644
index 00000000000..621f9dd63e2
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_cursor.c
@@ -0,0 +1,129 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Cursor Transform Creation
+ *
+ * Instead of transforming the selection, move the 2D/3D cursor.
+ *
+ * \{ */
+
+void createTransCursor_image(TransInfo *t)
+{
+ TransData *td;
+ SpaceImage *sima = t->sa->spacedata.first;
+ float *cursor_location = sima->cursor;
+
+ {
+ BLI_assert(t->data_container_len == 1);
+ TransDataContainer *tc = t->data_container;
+ tc->data_len = 1;
+ td = tc->data = MEM_callocN(sizeof(TransData), "TransTexspace");
+ td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
+ }
+
+ td->flag = TD_SELECTED;
+ copy_v3_v3(td->center, cursor_location);
+ td->ob = NULL;
+
+ unit_m3(td->mtx);
+ unit_m3(td->axismtx);
+ pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
+
+ td->loc = cursor_location;
+ copy_v3_v3(td->iloc, cursor_location);
+}
+
+void createTransCursor_view3d(TransInfo *t)
+{
+ TransData *td;
+
+ Scene *scene = t->scene;
+ if (ID_IS_LINKED(scene)) {
+ BKE_report(t->reports, RPT_ERROR, "Linked data can't text-space transform");
+ return;
+ }
+
+ View3DCursor *cursor = &scene->cursor;
+ {
+ BLI_assert(t->data_container_len == 1);
+ TransDataContainer *tc = t->data_container;
+ tc->data_len = 1;
+ td = tc->data = MEM_callocN(sizeof(TransData), "TransTexspace");
+ td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
+ }
+
+ td->flag = TD_SELECTED;
+ copy_v3_v3(td->center, cursor->location);
+ td->ob = NULL;
+
+ unit_m3(td->mtx);
+ BKE_scene_cursor_rot_to_mat3(cursor, td->axismtx);
+ normalize_m3(td->axismtx);
+ pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
+
+ td->loc = cursor->location;
+ copy_v3_v3(td->iloc, cursor->location);
+
+ if (cursor->rotation_mode > 0) {
+ td->ext->rot = cursor->rotation_euler;
+ td->ext->rotAxis = NULL;
+ td->ext->rotAngle = NULL;
+ td->ext->quat = NULL;
+
+ copy_v3_v3(td->ext->irot, cursor->rotation_euler);
+ }
+ else if (cursor->rotation_mode == ROT_MODE_AXISANGLE) {
+ td->ext->rot = NULL;
+ td->ext->rotAxis = cursor->rotation_axis;
+ td->ext->rotAngle = &cursor->rotation_angle;
+ td->ext->quat = NULL;
+
+ td->ext->irotAngle = cursor->rotation_angle;
+ copy_v3_v3(td->ext->irotAxis, cursor->rotation_axis);
+ }
+ else {
+ td->ext->rot = NULL;
+ td->ext->rotAxis = NULL;
+ td->ext->rotAngle = NULL;
+ td->ext->quat = cursor->rotation_quaternion;
+
+ copy_qt_qt(td->ext->iquat, cursor->rotation_quaternion);
+ }
+ td->ext->rotOrder = cursor->rotation_mode;
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c
new file mode 100644
index 00000000000..487de27aff2
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_curve.c
@@ -0,0 +1,422 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_curve_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_curve.h"
+#include "BKE_report.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Curve/Surfaces Transform Creation
+ *
+ * \{ */
+
+/**
+ * For the purpose of transform code we need to behave as if handles are selected,
+ * even when they aren't (see special case below).
+ */
+static int bezt_select_to_transform_triple_flag(const BezTriple *bezt, const bool hide_handles)
+{
+ int flag = 0;
+
+ if (hide_handles) {
+ if (bezt->f2 & SELECT) {
+ flag = (1 << 0) | (1 << 1) | (1 << 2);
+ }
+ }
+ else {
+ flag = (((bezt->f1 & SELECT) ? (1 << 0) : 0) | ((bezt->f2 & SELECT) ? (1 << 1) : 0) |
+ ((bezt->f3 & SELECT) ? (1 << 2) : 0));
+ }
+
+ /* Special case for auto & aligned handles:
+ * When a center point is being moved without the handles,
+ * leaving the handles stationary makes no sense and only causes strange behavior,
+ * where one handle is arbitrarily anchored, the other one is aligned and lengthened
+ * based on where the center point is moved. Also a bug when cancelling, see: T52007.
+ *
+ * A more 'correct' solution could be to store handle locations in 'TransDataCurveHandleFlags'.
+ * However that doesn't resolve odd behavior, so best transform the handles in this case.
+ */
+ if ((flag != ((1 << 0) | (1 << 1) | (1 << 2))) && (flag & (1 << 1))) {
+ if (ELEM(bezt->h1, HD_AUTO, HD_ALIGN) && ELEM(bezt->h2, HD_AUTO, HD_ALIGN)) {
+ flag = (1 << 0) | (1 << 1) | (1 << 2);
+ }
+ }
+
+ return flag;
+}
+
+void createTransCurveVerts(TransInfo *t)
+{
+
+#define SEL_F1 (1 << 0)
+#define SEL_F2 (1 << 1)
+#define SEL_F3 (1 << 2)
+
+ t->data_len_all = 0;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Curve *cu = tc->obedit->data;
+ BLI_assert(cu->editnurb != NULL);
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+ int count = 0, countsel = 0;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ View3D *v3d = t->view;
+ short hide_handles = (v3d != NULL) ?
+ ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) :
+ false;
+
+ /* count total of vertices, check identical as in 2nd loop for making transdata! */
+ ListBase *nurbs = BKE_curve_editNurbs_get(cu);
+ for (Nurb *nu = nurbs->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
+ if (bezt->hide == 0) {
+ const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
+ if (bezt_tx & SEL_F1) {
+ countsel++;
+ }
+ if (bezt_tx & SEL_F2) {
+ countsel++;
+ }
+ if (bezt_tx & SEL_F3) {
+ countsel++;
+ }
+ if (is_prop_edit) {
+ count += 3;
+ }
+ }
+ }
+ }
+ else {
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
+ if (bp->hide == 0) {
+ if (is_prop_edit) {
+ count++;
+ }
+ if (bp->f1 & SELECT) {
+ countsel++;
+ }
+ }
+ }
+ }
+ }
+ /* note: in prop mode we need at least 1 selected */
+ if (countsel == 0) {
+ tc->data_len = 0;
+ continue;
+ }
+
+ if (is_prop_edit) {
+ tc->data_len = count;
+ }
+ else {
+ tc->data_len = countsel;
+ }
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Curve EditMode)");
+
+ t->data_len_all += tc->data_len;
+ }
+
+ transform_around_single_fallback(t);
+ t->data_len_all = -1;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (tc->data_len == 0) {
+ continue;
+ }
+
+ Curve *cu = tc->obedit->data;
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ View3D *v3d = t->view;
+ short hide_handles = (v3d != NULL) ?
+ ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) :
+ false;
+
+ float mtx[3][3], smtx[3][3];
+
+ copy_m3_m4(mtx, tc->obedit->obmat);
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+
+ TransData *td = tc->data;
+ ListBase *nurbs = BKE_curve_editNurbs_get(cu);
+ for (Nurb *nu = nurbs->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ TransData *head, *tail;
+ head = tail = td;
+ for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
+ if (bezt->hide == 0) {
+ TransDataCurveHandleFlags *hdata = NULL;
+ float axismtx[3][3];
+
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ float normal[3], plane[3];
+
+ BKE_nurb_bezt_calc_normal(nu, bezt, normal);
+ BKE_nurb_bezt_calc_plane(nu, bezt, plane);
+
+ if (createSpaceNormalTangent(axismtx, normal, plane)) {
+ /* pass */
+ }
+ else {
+ normalize_v3(normal);
+ axis_dominant_v3_to_m3(axismtx, normal);
+ invert_m3(axismtx);
+ }
+ }
+
+ /* Elements that will be transform (not always a match to selection). */
+ const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
+
+ if (is_prop_edit || bezt_tx & SEL_F1) {
+ copy_v3_v3(td->iloc, bezt->vec[0]);
+ td->loc = bezt->vec[0];
+ copy_v3_v3(td->center,
+ bezt->vec[(hide_handles || (t->around == V3D_AROUND_LOCAL_ORIGINS) ||
+ (bezt->f2 & SELECT)) ?
+ 1 :
+ 0]);
+ if (hide_handles) {
+ if (bezt->f2 & SELECT) {
+ td->flag = TD_SELECTED;
+ }
+ else {
+ td->flag = 0;
+ }
+ }
+ else {
+ if (bezt->f1 & SELECT) {
+ td->flag = TD_SELECTED;
+ }
+ else {
+ td->flag = 0;
+ }
+ }
+ td->ext = NULL;
+ td->val = NULL;
+
+ hdata = initTransDataCurveHandles(td, bezt);
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ copy_m3_m3(td->axismtx, axismtx);
+ }
+
+ td++;
+ tail++;
+ }
+
+ /* This is the Curve Point, the other two are handles */
+ if (is_prop_edit || bezt_tx & SEL_F2) {
+ copy_v3_v3(td->iloc, bezt->vec[1]);
+ td->loc = bezt->vec[1];
+ copy_v3_v3(td->center, td->loc);
+ if (bezt->f2 & SELECT) {
+ td->flag = TD_SELECTED;
+ }
+ else {
+ td->flag = 0;
+ }
+ td->ext = NULL;
+
+ /* TODO - make points scale */
+ if (t->mode == TFM_CURVE_SHRINKFATTEN) { /* || t->mode==TFM_RESIZE) {*/
+ td->val = &(bezt->radius);
+ td->ival = bezt->radius;
+ }
+ else if (t->mode == TFM_TILT) {
+ td->val = &(bezt->tilt);
+ td->ival = bezt->tilt;
+ }
+ else {
+ td->val = NULL;
+ }
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ copy_m3_m3(td->axismtx, axismtx);
+ }
+
+ if ((bezt_tx & SEL_F1) == 0 && (bezt_tx & SEL_F3) == 0) {
+ /* If the middle is selected but the sides arnt, this is needed */
+ if (hdata == NULL) {
+ /* if the handle was not saved by the previous handle */
+ hdata = initTransDataCurveHandles(td, bezt);
+ }
+ }
+
+ td++;
+ tail++;
+ }
+ if (is_prop_edit || bezt_tx & SEL_F3) {
+ copy_v3_v3(td->iloc, bezt->vec[2]);
+ td->loc = bezt->vec[2];
+ copy_v3_v3(td->center,
+ bezt->vec[(hide_handles || (t->around == V3D_AROUND_LOCAL_ORIGINS) ||
+ (bezt->f2 & SELECT)) ?
+ 1 :
+ 2]);
+ if (hide_handles) {
+ if (bezt->f2 & SELECT) {
+ td->flag = TD_SELECTED;
+ }
+ else {
+ td->flag = 0;
+ }
+ }
+ else {
+ if (bezt->f3 & SELECT) {
+ td->flag = TD_SELECTED;
+ }
+ else {
+ td->flag = 0;
+ }
+ }
+ td->ext = NULL;
+ td->val = NULL;
+
+ if (hdata == NULL) {
+ /* if the handle was not saved by the previous handle */
+ hdata = initTransDataCurveHandles(td, bezt);
+ }
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ copy_m3_m3(td->axismtx, axismtx);
+ }
+
+ td++;
+ tail++;
+ }
+
+ (void)hdata; /* quiet warning */
+ }
+ else if (is_prop_edit && head != tail) {
+ calc_distanceCurveVerts(head, tail - 1);
+ head = tail;
+ }
+ }
+ if (is_prop_edit && head != tail) {
+ calc_distanceCurveVerts(head, tail - 1);
+ }
+
+ /* TODO - in the case of tilt and radius we can also avoid allocating the
+ * initTransDataCurveHandles but for now just don't change handle types */
+ if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT, TFM_DUMMY) == 0) {
+ /* sets the handles based on their selection,
+ * do this after the data is copied to the TransData */
+ BKE_nurb_handles_test(nu, !hide_handles);
+ }
+ }
+ else {
+ TransData *head, *tail;
+ head = tail = td;
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
+ if (bp->hide == 0) {
+ if (is_prop_edit || (bp->f1 & SELECT)) {
+ float axismtx[3][3];
+
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ if (nu->pntsv == 1) {
+ float normal[3], plane[3];
+
+ BKE_nurb_bpoint_calc_normal(nu, bp, normal);
+ BKE_nurb_bpoint_calc_plane(nu, bp, plane);
+
+ if (createSpaceNormalTangent(axismtx, normal, plane)) {
+ /* pass */
+ }
+ else {
+ normalize_v3(normal);
+ axis_dominant_v3_to_m3(axismtx, normal);
+ invert_m3(axismtx);
+ }
+ }
+ }
+
+ copy_v3_v3(td->iloc, bp->vec);
+ td->loc = bp->vec;
+ copy_v3_v3(td->center, td->loc);
+ if (bp->f1 & SELECT) {
+ td->flag = TD_SELECTED;
+ }
+ else {
+ td->flag = 0;
+ }
+ td->ext = NULL;
+
+ if (t->mode == TFM_CURVE_SHRINKFATTEN || t->mode == TFM_RESIZE) {
+ td->val = &(bp->radius);
+ td->ival = bp->radius;
+ }
+ else {
+ td->val = &(bp->tilt);
+ td->ival = bp->tilt;
+ }
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ if (nu->pntsv == 1) {
+ copy_m3_m3(td->axismtx, axismtx);
+ }
+ }
+
+ td++;
+ tail++;
+ }
+ }
+ else if (is_prop_edit && head != tail) {
+ calc_distanceCurveVerts(head, tail - 1);
+ head = tail;
+ }
+ }
+ if (is_prop_edit && head != tail) {
+ calc_distanceCurveVerts(head, tail - 1);
+ }
+ }
+ }
+ }
+#undef SEL_F1
+#undef SEL_F2
+#undef SEL_F3
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c
new file mode 100644
index 00000000000..234e383be5f
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_gpencil.c
@@ -0,0 +1,371 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_gpencil_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_report.h"
+
+#include "ED_gpencil.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Gpencil Transform Creation
+ *
+ * \{ */
+
+static void createTransGPencil_center_get(bGPDstroke *gps, float r_center[3])
+{
+ bGPDspoint *pt;
+ int i;
+
+ zero_v3(r_center);
+ int tot_sel = 0;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ add_v3_v3(r_center, &pt->x);
+ tot_sel++;
+ }
+ }
+
+ if (tot_sel > 0) {
+ mul_v3_fl(r_center, 1.0f / tot_sel);
+ }
+}
+
+void createTransGPencil(bContext *C, TransInfo *t)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ bool use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) != 0;
+
+ Object *obact = CTX_data_active_object(C);
+ bGPDlayer *gpl;
+ TransData *td = NULL;
+ float mtx[3][3], smtx[3][3];
+
+ const Scene *scene = CTX_data_scene(C);
+ const int cfra_scene = CFRA;
+
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* == Grease Pencil Strokes to Transform Data ==
+ * Grease Pencil stroke points can be a mixture of 2D (screen-space),
+ * or 3D coordinates. However, they're always saved as 3D points.
+ * For now, we just do these without creating TransData2D for the 2D
+ * strokes. This may cause issues in future though.
+ */
+ tc->data_len = 0;
+
+ if (gpd == NULL) {
+ return;
+ }
+
+ /* initialize falloff curve */
+ if (is_multiedit) {
+ BKE_curvemapping_initialize(ts->gp_sculpt.cur_falloff);
+ }
+
+ /* First Pass: Count the number of data-points required for the strokes,
+ * (and additional info about the configuration - e.g. 2D/3D?).
+ */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ bGPDframe *gpf;
+ bGPDstroke *gps;
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ continue;
+ }
+
+ if (is_prop_edit) {
+ /* Proportional Editing... */
+ if (is_prop_edit_connected) {
+ /* connected only - so only if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ tc->data_len += gps->totpoints;
+ }
+ }
+ else {
+ /* everything goes - connection status doesn't matter */
+ tc->data_len += gps->totpoints;
+ }
+ }
+ else {
+ /* only selected stroke points are considered */
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+
+ // TODO: 2D vs 3D?
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ tc->data_len++;
+ }
+ }
+ }
+ }
+ }
+ }
+ /* if not multiedit out of loop */
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ }
+
+ /* Stop trying if nothing selected */
+ if (tc->data_len == 0) {
+ return;
+ }
+
+ /* Allocate memory for data */
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(GPencil)");
+ td = tc->data;
+
+ unit_m3(smtx);
+ unit_m3(mtx);
+
+ /* Second Pass: Build transdata array */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene;
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps;
+ float diff_mat[4][4];
+ float inverse_diff_mat[4][4];
+
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+ /* init multiframe falloff options */
+ int f_init = 0;
+ int f_end = 0;
+
+ if (use_multiframe_falloff) {
+ BKE_gpencil_get_range_selected(gpl, &f_init, &f_end);
+ }
+
+ /* calculate difference matrix */
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ /* undo matrix */
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+
+ /* Make a new frame to work on if the layer's frame
+ * and the current scene frame don't match up.
+ *
+ * - 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...
+ */
+ // XXX: should this be allowed when framelock is enabled?
+ if ((gpf->framenum != cfra) && (!is_multiedit)) {
+ gpf = BKE_gpencil_frame_addcopy(gpl, cfra);
+ /* in some weird situations (framelock enabled) return NULL */
+ if (gpf == NULL) {
+ continue;
+ }
+ if (!is_multiedit) {
+ init_gpf = gpf;
+ }
+ }
+
+ /* Loop over strokes, adding TransData for points as needed... */
+ for (gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+
+ /* if multiframe and falloff, recalculate and save value */
+ float falloff = 1.0f; /* by default no falloff */
+ if ((is_multiedit) && (use_multiframe_falloff)) {
+ /* Faloff depends on distance to active frame (relative to the overall frame range) */
+ falloff = BKE_gpencil_multiframe_falloff_calc(
+ gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff);
+ }
+
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ TransData *head = td;
+ TransData *tail = td;
+ bool stroke_ok;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ continue;
+ }
+ /* What we need to include depends on proportional editing settings... */
+ if (is_prop_edit) {
+ if (is_prop_edit_connected) {
+ /* A) "Connected" - Only those in selected strokes */
+ stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
+ }
+ else {
+ /* B) All points, always */
+ stroke_ok = true;
+ }
+ }
+ else {
+ /* C) Only selected points in selected strokes */
+ stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
+ }
+
+ /* Do stroke... */
+ if (stroke_ok && gps->totpoints) {
+ bGPDspoint *pt;
+ int i;
+
+ /* save falloff factor */
+ gps->runtime.multi_frame_falloff = falloff;
+
+ /* calculate stroke center */
+ float center[3];
+ createTransGPencil_center_get(gps, center);
+
+ /* add all necessary points... */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ bool point_ok;
+
+ /* include point? */
+ if (is_prop_edit) {
+ /* Always all points in strokes that get included */
+ point_ok = true;
+ }
+ else {
+ /* Only selected points in selected strokes */
+ point_ok = (pt->flag & GP_SPOINT_SELECT) != 0;
+ }
+
+ /* do point... */
+ if (point_ok) {
+ copy_v3_v3(td->iloc, &pt->x);
+ /* only copy center in local origins.
+ * This allows get interesting effects also when move
+ * using proportional editing */
+ if ((gps->flag & GP_STROKE_SELECT) &&
+ (ts->transform_pivot_point == V3D_AROUND_LOCAL_ORIGINS)) {
+ copy_v3_v3(td->center, center);
+ }
+ else {
+ copy_v3_v3(td->center, &pt->x);
+ }
+
+ td->loc = &pt->x;
+
+ td->flag = 0;
+
+ if (pt->flag & GP_SPOINT_SELECT) {
+ td->flag |= TD_SELECTED;
+ }
+
+ /* for other transform modes (e.g. shrink-fatten), need to additional data
+ * but never for scale or mirror
+ */
+ if ((t->mode != TFM_RESIZE) && (t->mode != TFM_MIRROR)) {
+ if (t->mode != TFM_GPENCIL_OPACITY) {
+ td->val = &pt->pressure;
+ td->ival = pt->pressure;
+ }
+ else {
+ td->val = &pt->strength;
+ td->ival = pt->strength;
+ }
+ }
+
+ /* screenspace needs special matrices... */
+ if ((gps->flag & (GP_STROKE_3DSPACE | GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) ==
+ 0) {
+ /* screenspace */
+ td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
+ }
+ else {
+ /* configure 2D dataspace points so that they don't play up... */
+ if (gps->flag & (GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) {
+ td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
+ }
+ }
+ /* apply parent transformations */
+ copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */
+ copy_m3_m4(td->mtx, diff_mat); /* display position */
+ copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */
+
+ /* Triangulation must be calculated again,
+ * so save the stroke for recalc function */
+ td->extra = gps;
+
+ /* save pointer to object */
+ td->ob = obact;
+
+ td++;
+ tail++;
+ }
+ }
+
+ /* March over these points, and calculate the proportional editing distances */
+ if (is_prop_edit && (head != tail)) {
+ /* XXX: for now, we are similar enough that this works... */
+ calc_distanceCurveVerts(head, tail - 1);
+ }
+ }
+ }
+ }
+ /* if not multiedit out of loop */
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c
new file mode 100644
index 00000000000..f3d7592127c
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_graph.c
@@ -0,0 +1,700 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_anim_types.h"
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_fcurve.h"
+#include "BKE_nla.h"
+#include "BKE_report.h"
+
+#include "ED_anim_api.h"
+#include "ED_markers.h"
+
+#include "UI_view2d.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+typedef struct TransDataGraph {
+ float unit_scale;
+ float offset;
+} TransDataGraph;
+
+/* -------------------------------------------------------------------- */
+/** \name Graph Editor Transform Creation
+ *
+ * \{ */
+
+/* Helper function for createTransGraphEditData, which is responsible for associating
+ * source data with transform data
+ */
+static void bezt_to_transdata(TransData *td,
+ TransData2D *td2d,
+ TransDataGraph *tdg,
+ AnimData *adt,
+ BezTriple *bezt,
+ int bi,
+ bool selected,
+ bool ishandle,
+ bool intvals,
+ const float mtx[3][3],
+ const float smtx[3][3],
+ float unit_scale,
+ float offset)
+{
+ float *loc = bezt->vec[bi];
+ const float *cent = bezt->vec[1];
+
+ /* New location from td gets dumped onto the old-location of td2d, which then
+ * gets copied to the actual data at td2d->loc2d (bezt->vec[n])
+ *
+ * Due to NLA mapping, we apply NLA mapping to some of the verts here,
+ * and then that mapping will be undone after transform is done.
+ */
+
+ if (adt) {
+ td2d->loc[0] = BKE_nla_tweakedit_remap(adt, loc[0], NLATIME_CONVERT_MAP);
+ td2d->loc[1] = (loc[1] + offset) * unit_scale;
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = loc;
+
+ td->loc = td2d->loc;
+ td->center[0] = BKE_nla_tweakedit_remap(adt, cent[0], NLATIME_CONVERT_MAP);
+ td->center[1] = (cent[1] + offset) * unit_scale;
+ td->center[2] = 0.0f;
+
+ copy_v3_v3(td->iloc, td->loc);
+ }
+ else {
+ td2d->loc[0] = loc[0];
+ td2d->loc[1] = (loc[1] + offset) * unit_scale;
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = loc;
+
+ td->loc = td2d->loc;
+ copy_v3_v3(td->center, cent);
+ td->center[1] = (td->center[1] + offset) * unit_scale;
+ copy_v3_v3(td->iloc, td->loc);
+ }
+
+ if (!ishandle) {
+ td2d->h1 = bezt->vec[0];
+ td2d->h2 = bezt->vec[2];
+ copy_v2_v2(td2d->ih1, td2d->h1);
+ copy_v2_v2(td2d->ih2, td2d->h2);
+ }
+ else {
+ td2d->h1 = NULL;
+ td2d->h2 = NULL;
+ }
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ /* store AnimData info in td->extra, for applying mapping when flushing */
+ td->extra = adt;
+
+ if (selected) {
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0f;
+ }
+ else {
+ td->dist = FLT_MAX;
+ }
+
+ if (ishandle) {
+ td->flag |= TD_NOTIMESNAP;
+ }
+ if (intvals) {
+ td->flag |= TD_INTVALUES;
+ }
+
+ /* copy space-conversion matrices for dealing with non-uniform scales */
+ copy_m3_m3(td->mtx, mtx);
+ copy_m3_m3(td->smtx, smtx);
+
+ tdg->unit_scale = unit_scale;
+ tdg->offset = offset;
+}
+
+static bool graph_edit_is_translation_mode(TransInfo *t)
+{
+ return ELEM(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE, TFM_TIME_DUPLICATE);
+}
+
+static bool graph_edit_use_local_center(TransInfo *t)
+{
+ return ((t->around == V3D_AROUND_LOCAL_ORIGINS) && (graph_edit_is_translation_mode(t) == false));
+}
+
+static void graph_key_shortest_dist(
+ TransInfo *t, FCurve *fcu, TransData *td_start, TransData *td, int cfra, bool use_handle)
+{
+ int j = 0;
+ TransData *td_iter = td_start;
+
+ td->dist = FLT_MAX;
+ for (; j < fcu->totvert; j++) {
+ BezTriple *bezt = fcu->bezt + j;
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ const bool sel2 = (bezt->f2 & SELECT) != 0;
+ const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+ const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+
+ if (sel1 || sel2 || sel3) {
+ td->dist = td->rdist = min_ff(td->dist, fabs(td_iter->center[0] - td->center[0]));
+ }
+
+ td_iter += 3;
+ }
+ }
+}
+
+void createTransGraphEditData(bContext *C, TransInfo *t)
+{
+ SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ Scene *scene = t->scene;
+ ARegion *ar = t->ar;
+ View2D *v2d = &ar->v2d;
+
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ TransDataGraph *tdg = NULL;
+
+ bAnimContext ac;
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ BezTriple *bezt;
+ int count = 0, i;
+ float mtx[3][3], smtx[3][3];
+ const bool is_translation_mode = graph_edit_is_translation_mode(t);
+ const bool use_handle = !(sipo->flag & SIPO_NOHANDLES);
+ const bool use_local_center = graph_edit_use_local_center(t);
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ short anim_map_flag = ANIM_UNITCONV_ONLYSEL | ANIM_UNITCONV_SELVERTS;
+
+ /* determine what type of data we are operating on */
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return;
+ }
+
+ anim_map_flag |= ANIM_get_normalization_flags(&ac);
+
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* which side of the current frame should be allowed */
+ // XXX we still want this mode, but how to get this using standard transform too?
+ if (t->mode == TFM_TIME_EXTEND) {
+ /* only side on which mouse is gets transformed */
+ float xmouse, ymouse;
+
+ UI_view2d_region_to_view(v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse);
+ t->frame_side = (xmouse > CFRA) ? 'R' : 'L'; // XXX use t->frame_side
+ }
+ else {
+ /* normal transform - both sides of current frame are considered */
+ t->frame_side = 'B';
+ }
+
+ /* Loop 1: count how many BezTriples (specifically their verts)
+ * are selected (or should be edited). */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ FCurve *fcu = (FCurve *)ale->key_data;
+ float cfra;
+ int curvecount = 0;
+ bool selected = false;
+
+ /* F-Curve may not have any keyframes */
+ if (fcu->bezt == NULL) {
+ continue;
+ }
+
+ /* convert current-frame to action-time (slightly less accurate, especially under
+ * higher scaling ratios, but is faster than converting all points)
+ */
+ if (adt) {
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ }
+ else {
+ cfra = (float)CFRA;
+ }
+
+ /* Only include BezTriples whose 'keyframe'
+ * occurs on the same side of the current frame as mouse. */
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ const bool sel2 = (bezt->f2 & SELECT) != 0;
+ const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+ const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+
+ if (is_prop_edit) {
+ curvecount += 3;
+ if (sel2 || sel1 || sel3) {
+ selected = true;
+ }
+ }
+ else {
+ if (!is_translation_mode || !(sel2)) {
+ if (sel1) {
+ count++;
+ }
+
+ if (sel3) {
+ count++;
+ }
+ }
+
+ /* only include main vert if selected */
+ if (sel2 && !use_local_center) {
+ count++;
+ }
+ }
+ }
+ }
+
+ if (is_prop_edit) {
+ if (selected) {
+ count += curvecount;
+ ale->tag = true;
+ }
+ }
+ }
+
+ /* stop if trying to build list if nothing selected */
+ if (count == 0) {
+ /* cleanup temp list */
+ ANIM_animdata_freelist(&anim_data);
+ return;
+ }
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* allocate memory for data */
+ tc->data_len = count;
+
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData (Graph Editor)");
+ /* For each 2d vert a 3d vector is allocated,
+ * so that they can be treated just as if they were 3d verts. */
+ tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransData2D (Graph Editor)");
+ tc->custom.type.data = MEM_callocN(tc->data_len * sizeof(TransDataGraph), "TransDataGraph");
+ tc->custom.type.use_free = true;
+
+ td = tc->data;
+ td2d = tc->data_2d;
+ tdg = tc->custom.type.data;
+
+ /* precompute space-conversion matrices for dealing with non-uniform scaling of Graph Editor */
+ unit_m3(mtx);
+ unit_m3(smtx);
+
+ if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) {
+ float xscale, yscale;
+
+ /* apply scale factors to x and y axes of space-conversion matrices */
+ UI_view2d_scale_get(v2d, &xscale, &yscale);
+
+ /* mtx is data to global (i.e. view) conversion */
+ mul_v3_fl(mtx[0], xscale);
+ mul_v3_fl(mtx[1], yscale);
+
+ /* smtx is global (i.e. view) to data conversion */
+ if (IS_EQF(xscale, 0.0f) == 0) {
+ mul_v3_fl(smtx[0], 1.0f / xscale);
+ }
+ if (IS_EQF(yscale, 0.0f) == 0) {
+ mul_v3_fl(smtx[1], 1.0f / yscale);
+ }
+ }
+
+ /* loop 2: build transdata arrays */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ FCurve *fcu = (FCurve *)ale->key_data;
+ bool intvals = (fcu->flag & FCURVE_INT_VALUES) != 0;
+ float unit_scale, offset;
+ float cfra;
+
+ /* F-Curve may not have any keyframes */
+ if (fcu->bezt == NULL || (is_prop_edit && ale->tag == 0)) {
+ continue;
+ }
+
+ /* convert current-frame to action-time (slightly less accurate, especially under
+ * higher scaling ratios, but is faster than converting all points)
+ */
+ if (adt) {
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ }
+ else {
+ cfra = (float)CFRA;
+ }
+
+ unit_scale = ANIM_unit_mapping_get_factor(
+ ac.scene, ale->id, ale->key_data, anim_map_flag, &offset);
+
+ /* only include BezTriples whose 'keyframe' occurs on the same side
+ * of the current frame as mouse (if applicable) */
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ const bool sel2 = (bezt->f2 & SELECT) != 0;
+ const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+ const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+
+ TransDataCurveHandleFlags *hdata = NULL;
+ /* short h1=1, h2=1; */ /* UNUSED */
+
+ if (is_prop_edit) {
+ bool is_sel = (sel2 || sel1 || sel3);
+ /* we always select all handles for proportional editing if central handle is selected */
+ initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++,
+ td2d++,
+ tdg++,
+ adt,
+ bezt,
+ 0,
+ is_sel,
+ true,
+ intvals,
+ mtx,
+ smtx,
+ unit_scale,
+ offset);
+ initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++,
+ td2d++,
+ tdg++,
+ adt,
+ bezt,
+ 1,
+ is_sel,
+ false,
+ intvals,
+ mtx,
+ smtx,
+ unit_scale,
+ offset);
+ initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++,
+ td2d++,
+ tdg++,
+ adt,
+ bezt,
+ 2,
+ is_sel,
+ true,
+ intvals,
+ mtx,
+ smtx,
+ unit_scale,
+ offset);
+ }
+ else {
+ /* only include handles if selected, irrespective of the interpolation modes.
+ * also, only treat handles specially if the center point isn't selected.
+ */
+ if (!is_translation_mode || !(sel2)) {
+ if (sel1) {
+ hdata = initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++,
+ td2d++,
+ tdg++,
+ adt,
+ bezt,
+ 0,
+ sel1,
+ true,
+ intvals,
+ mtx,
+ smtx,
+ unit_scale,
+ offset);
+ }
+ else {
+ /* h1 = 0; */ /* UNUSED */
+ }
+
+ if (sel3) {
+ if (hdata == NULL) {
+ hdata = initTransDataCurveHandles(td, bezt);
+ }
+ bezt_to_transdata(td++,
+ td2d++,
+ tdg++,
+ adt,
+ bezt,
+ 2,
+ sel3,
+ true,
+ intvals,
+ mtx,
+ smtx,
+ unit_scale,
+ offset);
+ }
+ else {
+ /* h2 = 0; */ /* UNUSED */
+ }
+ }
+
+ /* only include main vert if selected */
+ if (sel2 && !use_local_center) {
+ /* move handles relative to center */
+ if (is_translation_mode) {
+ if (sel1) {
+ td->flag |= TD_MOVEHANDLE1;
+ }
+ if (sel3) {
+ td->flag |= TD_MOVEHANDLE2;
+ }
+ }
+
+ /* if handles were not selected, store their selection status */
+ if (!(sel1) || !(sel3)) {
+ if (hdata == NULL) {
+ hdata = initTransDataCurveHandles(td, bezt);
+ }
+ }
+
+ bezt_to_transdata(td++,
+ td2d++,
+ tdg++,
+ adt,
+ bezt,
+ 1,
+ sel2,
+ false,
+ intvals,
+ mtx,
+ smtx,
+ unit_scale,
+ offset);
+ }
+ /* Special hack (must be done after #initTransDataCurveHandles(),
+ * as that stores handle settings to restore...):
+ *
+ * - Check if we've got entire BezTriple selected and we're scaling/rotating that point,
+ * then check if we're using auto-handles.
+ * - If so, change them auto-handles to aligned handles so that handles get affected too
+ */
+ if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) && ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM) &&
+ ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) {
+ if (hdata && (sel1) && (sel3)) {
+ bezt->h1 = HD_ALIGN;
+ bezt->h2 = HD_ALIGN;
+ }
+ }
+ }
+ }
+ }
+
+ /* Sets handles based on the selection */
+ testhandles_fcurve(fcu, use_handle);
+ }
+
+ if (is_prop_edit) {
+ /* loop 2: build transdata arrays */
+ td = tc->data;
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ FCurve *fcu = (FCurve *)ale->key_data;
+ TransData *td_start = td;
+ float cfra;
+
+ /* F-Curve may not have any keyframes */
+ if (fcu->bezt == NULL || (ale->tag == 0)) {
+ continue;
+ }
+
+ /* convert current-frame to action-time (slightly less accurate, especially under
+ * higher scaling ratios, but is faster than converting all points)
+ */
+ if (adt) {
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ }
+ else {
+ cfra = (float)CFRA;
+ }
+
+ /* only include BezTriples whose 'keyframe' occurs on the
+ * same side of the current frame as mouse (if applicable) */
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ const bool sel2 = (bezt->f2 & SELECT) != 0;
+ const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+ const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+
+ if (sel1 || sel2) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
+ }
+ td++;
+
+ if (sel2) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
+ }
+ td++;
+
+ if (sel3 || sel2) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
+ }
+ td++;
+ }
+ }
+ }
+ }
+
+ /* cleanup temp list */
+ ANIM_animdata_freelist(&anim_data);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Graph Editor Transform Flush
+ *
+ * \{ */
+
+/* this function is called on recalcData to apply the transforms applied
+ * to the transdata on to the actual keyframe data
+ */
+void flushTransGraphData(TransInfo *t)
+{
+ SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ TransData *td;
+ TransData2D *td2d;
+ TransDataGraph *tdg;
+ Scene *scene = t->scene;
+ double secf = FPS;
+ int a;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* flush to 2d vector from internally used 3d vector */
+ for (a = 0, td = tc->data, td2d = tc->data_2d, tdg = tc->custom.type.data; a < tc->data_len;
+ a++, td++, td2d++, tdg++) {
+ /* pointers to relevant AnimData blocks are stored in the td->extra pointers */
+ AnimData *adt = (AnimData *)td->extra;
+
+ float inv_unit_scale = 1.0f / tdg->unit_scale;
+
+ /* Handle snapping for time values:
+ * - We should still be in NLA-mapping time-space.
+ * - Only apply to keyframes (but never to handles).
+ * - Don't do this when canceling, or else these changes won't go away.
+ */
+ if ((t->state != TRANS_CANCEL) && (td->flag & TD_NOTIMESNAP) == 0) {
+ switch (sipo->autosnap) {
+ case SACTSNAP_FRAME: /* snap to nearest frame */
+ td2d->loc[0] = floor((double)td2d->loc[0] + 0.5);
+ break;
+
+ case SACTSNAP_SECOND: /* snap to nearest second */
+ td2d->loc[0] = floor(((double)td2d->loc[0] / secf) + 0.5) * secf;
+ break;
+
+ case SACTSNAP_MARKER: /* snap to nearest marker */
+ td2d->loc[0] = (float)ED_markers_find_nearest_marker_time(&t->scene->markers,
+ td2d->loc[0]);
+ break;
+ }
+ }
+
+ /* we need to unapply the nla-mapping from the time in some situations */
+ if (adt) {
+ td2d->loc2d[0] = BKE_nla_tweakedit_remap(adt, td2d->loc[0], NLATIME_CONVERT_UNMAP);
+ }
+ else {
+ td2d->loc2d[0] = td2d->loc[0];
+ }
+
+ /** Time-stepping auto-snapping modes don't get applied for Graph Editor transforms,
+ * as these use the generic transform modes which don't account for this sort of thing.
+ * These ones aren't affected by NLA mapping, so we do this after the conversion...
+ *
+ * \note We also have to apply to td->loc,
+ * as that's what the handle-adjustment step below looks to,
+ * otherwise we get "swimming handles".
+ *
+ * \note We don't do this when canceling transforms, or else these changes don't go away.
+ */
+ if ((t->state != TRANS_CANCEL) && (td->flag & TD_NOTIMESNAP) == 0 &&
+ ELEM(sipo->autosnap, SACTSNAP_STEP, SACTSNAP_TSTEP)) {
+ switch (sipo->autosnap) {
+ case SACTSNAP_STEP: /* frame step */
+ td2d->loc2d[0] = floor((double)td2d->loc[0] + 0.5);
+ td->loc[0] = floor((double)td->loc[0] + 0.5);
+ break;
+
+ case SACTSNAP_TSTEP: /* second step */
+ /* XXX: the handle behavior in this case is still not quite right... */
+ td2d->loc[0] = floor(((double)td2d->loc[0] / secf) + 0.5) * secf;
+ td->loc[0] = floor(((double)td->loc[0] / secf) + 0.5) * secf;
+ break;
+ }
+ }
+
+ /* if int-values only, truncate to integers */
+ if (td->flag & TD_INTVALUES) {
+ td2d->loc2d[1] = floorf(td2d->loc[1] * inv_unit_scale - tdg->offset + 0.5f);
+ }
+ else {
+ td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale - tdg->offset;
+ }
+
+ if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) {
+ td2d->h1[0] = td2d->ih1[0] + td->loc[0] - td->iloc[0];
+ td2d->h1[1] = td2d->ih1[1] + (td->loc[1] - td->iloc[1]) * inv_unit_scale;
+ }
+
+ if ((td->flag & TD_MOVEHANDLE2) && td2d->h2) {
+ td2d->h2[0] = td2d->ih2[0] + td->loc[0] - td->iloc[0];
+ td2d->h2[1] = td2d->ih2[1] + (td->loc[1] - td->iloc[1]) * inv_unit_scale;
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_lattice.c b/source/blender/editors/transform/transform_convert_lattice.c
new file mode 100644
index 00000000000..15af24090f0
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_lattice.c
@@ -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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_curve_types.h"
+#include "DNA_lattice_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_report.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Curve/Surfaces Transform Creation
+ *
+ * \{ */
+
+void createTransLatticeVerts(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ Lattice *latt = ((Lattice *)tc->obedit->data)->editlatt->latt;
+ TransData *td = NULL;
+ BPoint *bp;
+ float mtx[3][3], smtx[3][3];
+ int a;
+ int count = 0, countsel = 0;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
+ bp = latt->def;
+ a = latt->pntsu * latt->pntsv * latt->pntsw;
+ while (a--) {
+ if (bp->hide == 0) {
+ if (bp->f1 & SELECT) {
+ countsel++;
+ }
+ if (is_prop_edit) {
+ count++;
+ }
+ }
+ bp++;
+ }
+
+ /* note: in prop mode we need at least 1 selected */
+ if (countsel == 0) {
+ return;
+ }
+
+ if (is_prop_edit) {
+ tc->data_len = count;
+ }
+ else {
+ tc->data_len = countsel;
+ }
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Lattice EditMode)");
+
+ copy_m3_m4(mtx, tc->obedit->obmat);
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+
+ td = tc->data;
+ bp = latt->def;
+ a = latt->pntsu * latt->pntsv * latt->pntsw;
+ while (a--) {
+ if (is_prop_edit || (bp->f1 & SELECT)) {
+ if (bp->hide == 0) {
+ copy_v3_v3(td->iloc, bp->vec);
+ td->loc = bp->vec;
+ copy_v3_v3(td->center, td->loc);
+ if (bp->f1 & SELECT) {
+ td->flag = TD_SELECTED;
+ }
+ else {
+ td->flag = 0;
+ }
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ td++;
+ }
+ }
+ bp++;
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_mask.c b/source/blender/editors/transform/transform_convert_mask.c
new file mode 100644
index 00000000000..32152442acf
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_mask.c
@@ -0,0 +1,442 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_mask_types.h"
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_mask.h"
+#include "BKE_report.h"
+
+#include "ED_clip.h"
+#include "ED_mask.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+typedef struct TransDataMasking {
+ bool is_handle;
+
+ float handle[2], orig_handle[2];
+ float vec[3][3];
+ struct MaskSplinePoint *point;
+ float parent_matrix[3][3];
+ float parent_inverse_matrix[3][3];
+ char orig_handle_type;
+
+ eMaskWhichHandle which_handle;
+} TransDataMasking;
+
+/* -------------------------------------------------------------------- */
+/** \name Masking Transform Creation
+ *
+ * \{ */
+
+static void MaskHandleToTransData(MaskSplinePoint *point,
+ eMaskWhichHandle which_handle,
+ TransData *td,
+ TransData2D *td2d,
+ TransDataMasking *tdm,
+ const float asp[2],
+ /*const*/ const float parent_matrix[3][3],
+ /*const*/ const float parent_inverse_matrix[3][3])
+{
+ BezTriple *bezt = &point->bezt;
+ const bool is_sel_any = MASKPOINT_ISSEL_ANY(point);
+
+ tdm->point = point;
+ copy_m3_m3(tdm->vec, bezt->vec);
+
+ tdm->is_handle = true;
+ copy_m3_m3(tdm->parent_matrix, parent_matrix);
+ copy_m3_m3(tdm->parent_inverse_matrix, parent_inverse_matrix);
+
+ BKE_mask_point_handle(point, which_handle, tdm->handle);
+ tdm->which_handle = which_handle;
+
+ copy_v2_v2(tdm->orig_handle, tdm->handle);
+
+ mul_v2_m3v2(td2d->loc, parent_matrix, tdm->handle);
+ td2d->loc[0] *= asp[0];
+ td2d->loc[1] *= asp[1];
+ td2d->loc[2] = 0.0f;
+
+ td2d->loc2d = tdm->handle;
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ mul_v2_m3v2(td->center, parent_matrix, bezt->vec[1]);
+ td->center[0] *= asp[0];
+ td->center[1] *= asp[1];
+ copy_v3_v3(td->iloc, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ if (is_sel_any) {
+ td->flag |= TD_SELECTED;
+ }
+
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+
+ if (which_handle == MASK_WHICH_HANDLE_LEFT) {
+ tdm->orig_handle_type = bezt->h1;
+ }
+ else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
+ tdm->orig_handle_type = bezt->h2;
+ }
+}
+
+static void MaskPointToTransData(Scene *scene,
+ MaskSplinePoint *point,
+ TransData *td,
+ TransData2D *td2d,
+ TransDataMasking *tdm,
+ const bool is_prop_edit,
+ const float asp[2])
+{
+ BezTriple *bezt = &point->bezt;
+ const bool is_sel_point = MASKPOINT_ISSEL_KNOT(point);
+ const bool is_sel_any = MASKPOINT_ISSEL_ANY(point);
+ float parent_matrix[3][3], parent_inverse_matrix[3][3];
+
+ BKE_mask_point_parent_matrix_get(point, CFRA, parent_matrix);
+ invert_m3_m3(parent_inverse_matrix, parent_matrix);
+
+ if (is_prop_edit || is_sel_point) {
+ int i;
+
+ tdm->point = point;
+ copy_m3_m3(tdm->vec, bezt->vec);
+
+ for (i = 0; i < 3; i++) {
+ copy_m3_m3(tdm->parent_matrix, parent_matrix);
+ copy_m3_m3(tdm->parent_inverse_matrix, parent_inverse_matrix);
+
+ /* CV coords are scaled by aspects. this is needed for rotations and
+ * proportional editing to be consistent with the stretched CV coords
+ * that are displayed. this also means that for display and numinput,
+ * and when the CV coords are flushed, these are converted each time */
+ mul_v2_m3v2(td2d->loc, parent_matrix, bezt->vec[i]);
+ td2d->loc[0] *= asp[0];
+ td2d->loc[1] *= asp[1];
+ td2d->loc[2] = 0.0f;
+
+ td2d->loc2d = bezt->vec[i];
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ mul_v2_m3v2(td->center, parent_matrix, bezt->vec[1]);
+ td->center[0] *= asp[0];
+ td->center[1] *= asp[1];
+ copy_v3_v3(td->iloc, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+
+ if (i == 1) {
+ /* scaling weights */
+ td->val = &bezt->weight;
+ td->ival = *td->val;
+ }
+ else {
+ td->val = NULL;
+ }
+
+ if (is_sel_any) {
+ td->flag |= TD_SELECTED;
+ }
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+
+ if (i == 0) {
+ tdm->orig_handle_type = bezt->h1;
+ }
+ else if (i == 2) {
+ tdm->orig_handle_type = bezt->h2;
+ }
+
+ td++;
+ td2d++;
+ tdm++;
+ }
+ }
+ else {
+ if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
+ MaskHandleToTransData(point,
+ MASK_WHICH_HANDLE_STICK,
+ td,
+ td2d,
+ tdm,
+ asp,
+ parent_matrix,
+ parent_inverse_matrix);
+
+ td++;
+ td2d++;
+ tdm++;
+ }
+ else {
+ if (bezt->f1 & SELECT) {
+ MaskHandleToTransData(point,
+ MASK_WHICH_HANDLE_LEFT,
+ td,
+ td2d,
+ tdm,
+ asp,
+ parent_matrix,
+ parent_inverse_matrix);
+
+ if (bezt->h1 == HD_VECT) {
+ bezt->h1 = HD_FREE;
+ }
+ else if (bezt->h1 == HD_AUTO) {
+ bezt->h1 = HD_ALIGN_DOUBLESIDE;
+ bezt->h2 = HD_ALIGN_DOUBLESIDE;
+ }
+
+ td++;
+ td2d++;
+ tdm++;
+ }
+ if (bezt->f3 & SELECT) {
+ MaskHandleToTransData(point,
+ MASK_WHICH_HANDLE_RIGHT,
+ td,
+ td2d,
+ tdm,
+ asp,
+ parent_matrix,
+ parent_inverse_matrix);
+
+ if (bezt->h2 == HD_VECT) {
+ bezt->h2 = HD_FREE;
+ }
+ else if (bezt->h2 == HD_AUTO) {
+ bezt->h1 = HD_ALIGN_DOUBLESIDE;
+ bezt->h2 = HD_ALIGN_DOUBLESIDE;
+ }
+
+ td++;
+ td2d++;
+ tdm++;
+ }
+ }
+ }
+}
+
+void createTransMaskingData(bContext *C, TransInfo *t)
+{
+ Scene *scene = CTX_data_scene(C);
+ Mask *mask = CTX_data_edit_mask(C);
+ MaskLayer *masklay;
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ TransDataMasking *tdm = NULL;
+ int count = 0, countsel = 0;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT);
+ float asp[2];
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ tc->data_len = 0;
+
+ if (!mask) {
+ return;
+ }
+
+ if (t->spacetype == SPACE_CLIP) {
+ SpaceClip *sc = t->sa->spacedata.first;
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ if (!clip) {
+ return;
+ }
+ }
+
+ /* count */
+ for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ MaskSpline *spline;
+
+ if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ continue;
+ }
+
+ for (spline = masklay->splines.first; spline; spline = spline->next) {
+ int i;
+
+ for (i = 0; i < spline->tot_point; i++) {
+ MaskSplinePoint *point = &spline->points[i];
+
+ if (MASKPOINT_ISSEL_ANY(point)) {
+ if (MASKPOINT_ISSEL_KNOT(point)) {
+ countsel += 3;
+ }
+ else {
+ if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
+ countsel += 1;
+ }
+ else {
+ BezTriple *bezt = &point->bezt;
+ if (bezt->f1 & SELECT) {
+ countsel++;
+ }
+ if (bezt->f3 & SELECT) {
+ countsel++;
+ }
+ }
+ }
+ }
+
+ if (is_prop_edit) {
+ count += 3;
+ }
+ }
+ }
+ }
+
+ /* note: in prop mode we need at least 1 selected */
+ if (countsel == 0) {
+ return;
+ }
+
+ ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]);
+
+ tc->data_len = (is_prop_edit) ? count : countsel;
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Mask Editing)");
+ /* for each 2d uv coord a 3d vector is allocated, so that they can be
+ * treated just as if they were 3d verts */
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D),
+ "TransObData2D(Mask Editing)");
+ tc->custom.type.data = tdm = MEM_callocN(tc->data_len * sizeof(TransDataMasking),
+ "TransDataMasking(Mask Editing)");
+ tc->custom.type.use_free = true;
+
+ /* create data */
+ for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ MaskSpline *spline;
+
+ if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ continue;
+ }
+
+ for (spline = masklay->splines.first; spline; spline = spline->next) {
+ int i;
+
+ for (i = 0; i < spline->tot_point; i++) {
+ MaskSplinePoint *point = &spline->points[i];
+
+ if (is_prop_edit || MASKPOINT_ISSEL_ANY(point)) {
+ MaskPointToTransData(scene, point, td, td2d, tdm, is_prop_edit, asp);
+
+ if (is_prop_edit || MASKPOINT_ISSEL_KNOT(point)) {
+ td += 3;
+ td2d += 3;
+ tdm += 3;
+ }
+ else {
+ if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
+ td++;
+ td2d++;
+ tdm++;
+ }
+ else {
+ BezTriple *bezt = &point->bezt;
+ if (bezt->f1 & SELECT) {
+ td++;
+ td2d++;
+ tdm++;
+ }
+ if (bezt->f3 & SELECT) {
+ td++;
+ td2d++;
+ tdm++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Masking Transform Flush
+ *
+ * \{ */
+
+void flushTransMasking(TransInfo *t)
+{
+ TransData2D *td;
+ TransDataMasking *tdm;
+ int a;
+ float asp[2], inv[2];
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]);
+ inv[0] = 1.0f / asp[0];
+ inv[1] = 1.0f / asp[1];
+
+ /* flush to 2d vector from internally used 3d vector */
+ for (a = 0, td = tc->data_2d, tdm = tc->custom.type.data; a < tc->data_len; a++, td++, tdm++) {
+ td->loc2d[0] = td->loc[0] * inv[0];
+ td->loc2d[1] = td->loc[1] * inv[1];
+ mul_m3_v2(tdm->parent_inverse_matrix, td->loc2d);
+
+ if (tdm->is_handle) {
+ BKE_mask_point_set_handle(tdm->point,
+ tdm->which_handle,
+ td->loc2d,
+ (t->flag & T_ALT_TRANSFORM) != 0,
+ tdm->orig_handle,
+ tdm->vec);
+ }
+
+ if (t->state == TRANS_CANCEL) {
+ if (tdm->which_handle == MASK_WHICH_HANDLE_LEFT) {
+ tdm->point->bezt.h1 = tdm->orig_handle_type;
+ }
+ else if (tdm->which_handle == MASK_WHICH_HANDLE_RIGHT) {
+ tdm->point->bezt.h2 = tdm->orig_handle_type;
+ }
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_mball.c b/source/blender/editors/transform/transform_convert_mball.c
new file mode 100644
index 00000000000..5d7e36cc834
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_mball.c
@@ -0,0 +1,130 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_meta_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_report.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Meta Elements Transform Creation
+ *
+ * \{ */
+
+void createTransMBallVerts(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ MetaBall *mb = (MetaBall *)tc->obedit->data;
+ MetaElem *ml;
+ TransData *td;
+ TransDataExtension *tx;
+ float mtx[3][3], smtx[3][3];
+ int count = 0, countsel = 0;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
+ /* count totals */
+ for (ml = mb->editelems->first; ml; ml = ml->next) {
+ if (ml->flag & SELECT) {
+ countsel++;
+ }
+ if (is_prop_edit) {
+ count++;
+ }
+ }
+
+ /* note: in prop mode we need at least 1 selected */
+ if (countsel == 0) {
+ continue;
+ }
+
+ if (is_prop_edit) {
+ tc->data_len = count;
+ }
+ else {
+ tc->data_len = countsel;
+ }
+
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(MBall EditMode)");
+ tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension),
+ "MetaElement_TransExtension");
+
+ copy_m3_m4(mtx, tc->obedit->obmat);
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+
+ for (ml = mb->editelems->first; ml; ml = ml->next) {
+ if (is_prop_edit || (ml->flag & SELECT)) {
+ td->loc = &ml->x;
+ copy_v3_v3(td->iloc, td->loc);
+ copy_v3_v3(td->center, td->loc);
+
+ quat_to_mat3(td->axismtx, ml->quat);
+
+ if (ml->flag & SELECT) {
+ td->flag = TD_SELECTED | TD_USEQUAT | TD_SINGLESIZE;
+ }
+ else {
+ td->flag = TD_USEQUAT;
+ }
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+
+ td->ext = tx;
+
+ /* Radius of MetaElem (mass of MetaElem influence) */
+ if (ml->flag & MB_SCALE_RAD) {
+ td->val = &ml->rad;
+ td->ival = ml->rad;
+ }
+ else {
+ td->val = &ml->s;
+ td->ival = ml->s;
+ }
+
+ /* expx/expy/expz determine "shape" of some MetaElem types */
+ tx->size = &ml->expx;
+ tx->isize[0] = ml->expx;
+ tx->isize[1] = ml->expy;
+ tx->isize[2] = ml->expz;
+
+ /* quat is used for rotation of MetaElem */
+ tx->quat = ml->quat;
+ copy_qt_qt(tx->iquat, ml->quat);
+
+ tx->rot = NULL;
+
+ td++;
+ tx++;
+ }
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
new file mode 100644
index 00000000000..7f9c4ee2fcc
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -0,0 +1,1645 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_alloca.h"
+#include "BLI_bitmap.h"
+#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_linklist_stack.h"
+
+#include "BKE_context.h"
+#include "BKE_crazyspace.h"
+#include "BKE_editmesh.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_modifier.h"
+#include "BKE_scene.h"
+
+#include "ED_image.h"
+#include "ED_mesh.h"
+#include "ED_uvedit.h"
+
+#include "WM_api.h" /* for WM_event_add_notifier to deal with stabilization nodes */
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+#include "bmesh.h"
+
+/* Used for both mirror epsilon and TD_MIRROR_EDGE_ */
+#define TRANSFORM_MAXDIST_MIRROR 0.00002f
+
+/* when transforming islands */
+struct TransIslandData {
+ float co[3];
+ float axismtx[3][3];
+};
+
+/* -------------------------------------------------------------------- */
+/** \name Edit Mesh Verts Transform Creation
+ *
+ * \{ */
+
+static bool bmesh_test_dist_add(BMVert *v,
+ BMVert *v_other,
+ float *dists,
+ const float *dists_prev,
+ /* optionally track original index */
+ int *index,
+ const int *index_prev,
+ const float mtx[3][3])
+{
+ if ((BM_elem_flag_test(v_other, BM_ELEM_SELECT) == 0) &&
+ (BM_elem_flag_test(v_other, BM_ELEM_HIDDEN) == 0)) {
+ const int i = BM_elem_index_get(v);
+ const int i_other = BM_elem_index_get(v_other);
+ float vec[3];
+ float dist_other;
+ sub_v3_v3v3(vec, v->co, v_other->co);
+ mul_m3_v3(mtx, vec);
+
+ dist_other = dists_prev[i] + len_v3(vec);
+ if (dist_other < dists[i_other]) {
+ dists[i_other] = dist_other;
+ if (index != NULL) {
+ index[i_other] = index_prev[i];
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * \param mtx: Measure distance in this space.
+ * \param dists: Store the closest connected distance to selected vertices.
+ * \param index: Optionally store the original index we're measuring the distance to (can be NULL).
+ */
+static void editmesh_set_connectivity_distance(BMesh *bm,
+ const float mtx[3][3],
+ float *dists,
+ int *index)
+{
+ BLI_LINKSTACK_DECLARE(queue, BMVert *);
+
+ /* any BM_ELEM_TAG'd vertex is in 'queue_next', so we don't add in twice */
+ BLI_LINKSTACK_DECLARE(queue_next, BMVert *);
+
+ BLI_LINKSTACK_INIT(queue);
+ BLI_LINKSTACK_INIT(queue_next);
+
+ {
+ BMIter viter;
+ BMVert *v;
+ int i;
+
+ BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
+ float dist;
+ BM_elem_index_set(v, i); /* set_inline */
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT) == 0 || BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
+ dist = FLT_MAX;
+ if (index != NULL) {
+ index[i] = i;
+ }
+ }
+ else {
+ BLI_LINKSTACK_PUSH(queue, v);
+ dist = 0.0f;
+ if (index != NULL) {
+ index[i] = i;
+ }
+ }
+
+ dists[i] = dist;
+ }
+ bm->elem_index_dirty &= ~BM_VERT;
+ }
+
+ /* need to be very careful of feedback loops here, store previous dist's to avoid feedback */
+ float *dists_prev = MEM_dupallocN(dists);
+ int *index_prev = MEM_dupallocN(index); /* may be NULL */
+
+ do {
+ BMVert *v;
+ LinkNode *lnk;
+
+ /* this is correct but slow to do each iteration,
+ * instead sync the dist's while clearing BM_ELEM_TAG (below) */
+#if 0
+ memcpy(dists_prev, dists, sizeof(float) * bm->totvert);
+#endif
+
+ while ((v = BLI_LINKSTACK_POP(queue))) {
+ BLI_assert(dists[BM_elem_index_get(v)] != FLT_MAX);
+
+ /* connected edge-verts */
+ if (v->e != NULL) {
+ BMEdge *e_iter, *e_first;
+
+ e_iter = e_first = v->e;
+
+ /* would normally use BM_EDGES_OF_VERT, but this runs so often,
+ * its faster to iterate on the data directly */
+ do {
+
+ if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == 0) {
+
+ /* edge distance */
+ {
+ BMVert *v_other = BM_edge_other_vert(e_iter, v);
+ if (bmesh_test_dist_add(v, v_other, dists, dists_prev, index, index_prev, mtx)) {
+ if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
+ BM_elem_flag_enable(v_other, BM_ELEM_TAG);
+ BLI_LINKSTACK_PUSH(queue_next, v_other);
+ }
+ }
+ }
+
+ /* face distance */
+ if (e_iter->l) {
+ BMLoop *l_iter_radial, *l_first_radial;
+ /**
+ * imaginary edge diagonally across quad,
+ * \note, this takes advantage of the rules of winding that we
+ * know 2 or more of a verts edges wont reference the same face twice.
+ * Also, if the edge is hidden, the face will be hidden too.
+ */
+ l_iter_radial = l_first_radial = e_iter->l;
+
+ do {
+ if ((l_iter_radial->v == v) && (l_iter_radial->f->len == 4) &&
+ (BM_elem_flag_test(l_iter_radial->f, BM_ELEM_HIDDEN) == 0)) {
+ BMVert *v_other = l_iter_radial->next->next->v;
+ if (bmesh_test_dist_add(v, v_other, dists, dists_prev, index, index_prev, mtx)) {
+ if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
+ BM_elem_flag_enable(v_other, BM_ELEM_TAG);
+ BLI_LINKSTACK_PUSH(queue_next, v_other);
+ }
+ }
+ }
+ } while ((l_iter_radial = l_iter_radial->radial_next) != l_first_radial);
+ }
+ }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
+ }
+ }
+
+ /* clear for the next loop */
+ for (lnk = queue_next; lnk; lnk = lnk->next) {
+ BMVert *v_link = lnk->link;
+ const int i = BM_elem_index_get(v_link);
+
+ BM_elem_flag_disable(v_link, BM_ELEM_TAG);
+
+ /* keep in sync, avoid having to do full memcpy each iteration */
+ dists_prev[i] = dists[i];
+ if (index != NULL) {
+ index_prev[i] = index[i];
+ }
+ }
+
+ BLI_LINKSTACK_SWAP(queue, queue_next);
+
+ /* none should be tagged now since 'queue_next' is empty */
+ BLI_assert(BM_iter_mesh_count_flag(BM_VERTS_OF_MESH, bm, BM_ELEM_TAG, true) == 0);
+
+ } while (BLI_LINKSTACK_SIZE(queue));
+
+ BLI_LINKSTACK_FREE(queue);
+ BLI_LINKSTACK_FREE(queue_next);
+
+ MEM_freeN(dists_prev);
+ if (index_prev != NULL) {
+ MEM_freeN(index_prev);
+ }
+}
+
+static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
+ int *r_island_tot,
+ int **r_island_vert_map,
+ bool calc_single_islands)
+{
+ BMesh *bm = em->bm;
+ struct TransIslandData *trans_islands;
+ char htype;
+ char itype;
+ int i;
+
+ /* group vars */
+ int *groups_array;
+ int(*group_index)[2];
+ int group_tot;
+ void **ele_array;
+
+ int *vert_map;
+
+ if (em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
+ groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totedgesel, __func__);
+ group_tot = BM_mesh_calc_edge_groups(
+ bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT);
+
+ htype = BM_EDGE;
+ itype = BM_VERTS_OF_EDGE;
+ }
+ else { /* (bm->selectmode & SCE_SELECT_FACE) */
+ groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__);
+ group_tot = BM_mesh_calc_face_groups(
+ bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT, BM_VERT);
+
+ htype = BM_FACE;
+ itype = BM_VERTS_OF_FACE;
+ }
+
+ trans_islands = MEM_mallocN(sizeof(*trans_islands) * group_tot, __func__);
+
+ vert_map = MEM_mallocN(sizeof(*vert_map) * bm->totvert, __func__);
+ /* we shouldn't need this, but with incorrect selection flushing
+ * its possible we have a selected vertex that's not in a face,
+ * for now best not crash in that case. */
+ copy_vn_i(vert_map, bm->totvert, -1);
+
+ BM_mesh_elem_table_ensure(bm, htype);
+ ele_array = (htype == BM_FACE) ? (void **)bm->ftable : (void **)bm->etable;
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ /* may be an edge OR a face array */
+ for (i = 0; i < group_tot; i++) {
+ BMEditSelection ese = {NULL};
+
+ const int fg_sta = group_index[i][0];
+ const int fg_len = group_index[i][1];
+ float co[3], no[3], tangent[3];
+ int j;
+
+ zero_v3(co);
+ zero_v3(no);
+ zero_v3(tangent);
+
+ ese.htype = htype;
+
+ /* loop on each face in this group:
+ * - assign r_vert_map
+ * - calculate (co, no)
+ */
+ for (j = 0; j < fg_len; j++) {
+ float tmp_co[3], tmp_no[3], tmp_tangent[3];
+
+ ese.ele = ele_array[groups_array[fg_sta + j]];
+
+ BM_editselection_center(&ese, tmp_co);
+ BM_editselection_normal(&ese, tmp_no);
+ BM_editselection_plane(&ese, tmp_tangent);
+
+ add_v3_v3(co, tmp_co);
+ add_v3_v3(no, tmp_no);
+ add_v3_v3(tangent, tmp_tangent);
+
+ {
+ /* setup vertex map */
+ BMIter iter;
+ BMVert *v;
+
+ /* connected edge-verts */
+ BM_ITER_ELEM (v, &iter, ese.ele, itype) {
+ vert_map[BM_elem_index_get(v)] = i;
+ }
+ }
+ }
+
+ mul_v3_v3fl(trans_islands[i].co, co, 1.0f / (float)fg_len);
+
+ if (createSpaceNormalTangent(trans_islands[i].axismtx, no, tangent)) {
+ /* pass */
+ }
+ else {
+ if (normalize_v3(no) != 0.0f) {
+ axis_dominant_v3_to_m3(trans_islands[i].axismtx, no);
+ invert_m3(trans_islands[i].axismtx);
+ }
+ else {
+ unit_m3(trans_islands[i].axismtx);
+ }
+ }
+ }
+
+ MEM_freeN(groups_array);
+ MEM_freeN(group_index);
+
+ /* for PET we need islands of 1 so connected vertices can use it with V3D_AROUND_LOCAL_ORIGINS */
+ if (calc_single_islands) {
+ BMIter viter;
+ BMVert *v;
+ int group_tot_single = 0;
+
+ BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) {
+ group_tot_single += 1;
+ }
+ }
+
+ if (group_tot_single != 0) {
+ trans_islands = MEM_reallocN(trans_islands,
+ sizeof(*trans_islands) * (group_tot + group_tot_single));
+
+ BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) {
+ struct TransIslandData *v_island = &trans_islands[group_tot];
+ vert_map[i] = group_tot;
+
+ copy_v3_v3(v_island->co, v->co);
+
+ if (is_zero_v3(v->no) != 0.0f) {
+ axis_dominant_v3_to_m3(v_island->axismtx, v->no);
+ invert_m3(v_island->axismtx);
+ }
+ else {
+ unit_m3(v_island->axismtx);
+ }
+
+ group_tot += 1;
+ }
+ }
+ }
+ }
+
+ *r_island_tot = group_tot;
+ *r_island_vert_map = vert_map;
+
+ return trans_islands;
+}
+
+static bool is_in_quadrant_v3(const float co[3], const int quadrant[3], const float epsilon)
+{
+ if (quadrant[0] && ((co[0] * quadrant[0]) < -epsilon)) {
+ return false;
+ }
+ if (quadrant[1] && ((co[1] * quadrant[1]) < -epsilon)) {
+ return false;
+ }
+ if (quadrant[2] && ((co[2] * quadrant[2]) < -epsilon)) {
+ return false;
+ }
+ return true;
+}
+
+static TransDataMirror *editmesh_mirror_data_calc(BMEditMesh *em,
+ bool use_select,
+ const bool use_topology,
+ const bool mirror_axis[3],
+ int *r_mirror_data_len,
+ BLI_bitmap **r_mirror_bitmap)
+{
+ BMesh *bm = em->bm;
+ int *index[3] = {NULL};
+ int i;
+
+ bool test_selected_only = use_select && (mirror_axis[0] + mirror_axis[1] + mirror_axis[2]) == 1;
+ for (i = 0; i < 3; i++) {
+ if (mirror_axis[i]) {
+ index[i] = MEM_mallocN(bm->totvert * sizeof(int), __func__);
+ EDBM_verts_mirror_cache_begin_ex(
+ em, i, false, test_selected_only, use_topology, TRANSFORM_MAXDIST_MIRROR, index[i]);
+ }
+ }
+
+ BMVert *eve;
+ BMIter iter;
+
+ int quadrant[3];
+ {
+ float select_sum[3] = {0};
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ add_v3_v3(select_sum, eve->co);
+ }
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (mirror_axis[i]) {
+ quadrant[i] = select_sum[i] >= 0.0f ? 1 : -1;
+ }
+ else {
+ quadrant[i] = 0;
+ }
+ }
+ }
+
+ /* Tag only elements that will be transformed within the quadrant. */
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+ if ((!use_select || BM_elem_flag_test(eve, BM_ELEM_SELECT)) &&
+ is_in_quadrant_v3(eve->co, quadrant, TRANSFORM_MAXDIST_MIRROR)) {
+ BM_elem_flag_enable(eve, BM_ELEM_TAG);
+ BM_elem_index_set(eve, i);
+ }
+ else {
+ BM_elem_flag_disable(eve, BM_ELEM_TAG);
+ BM_elem_index_set(eve, -1);
+ }
+ }
+
+ for (int a = 0; a < 3; a++) {
+ int *index_iter = index[a];
+ if (index_iter == NULL) {
+ continue;
+ }
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+ if (test_selected_only && !BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ continue;
+ }
+ int elem_index = BM_elem_index_get(eve);
+ if (elem_index != -1) {
+ int i_mirr = index_iter[i];
+ if (i_mirr >= 0) {
+ BMVert *vmir = BM_vert_at_index(bm, i_mirr);
+ BM_elem_index_set(vmir, elem_index);
+
+ /* The slot of this element in the index array no longer needs to be read.
+ * Use to set the mirror sign. */
+ if (index[0] && a > 0) {
+ index[0][i_mirr] = index[0][i];
+ }
+ if (index[1] && a > 1) {
+ index[1][i_mirr] = index[1][i];
+ }
+ /* Use -2 to differ from -1, but both can work. */
+ index_iter[i_mirr] = -2;
+ }
+ }
+ }
+ }
+
+ /* Count mirror elements. */
+ uint mirror_elem_len = 0;
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN | BM_ELEM_TAG)) {
+ /* Not a mirror element. */
+ BM_elem_index_set(eve, -1);
+ continue;
+ }
+ int elem_index = BM_elem_index_get(eve);
+ if (elem_index != -1) {
+ mirror_elem_len++;
+ }
+ }
+
+ TransDataMirror *mirror_data_iter, *mirror_data = NULL;
+ if (mirror_elem_len != 0) {
+ mirror_data = MEM_mallocN(mirror_elem_len * sizeof(*mirror_data), __func__);
+ mirror_data_iter = &mirror_data[0];
+
+ *r_mirror_bitmap = BLI_BITMAP_NEW(bm->totvert, __func__);
+
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ int elem_index = BM_elem_index_get(eve);
+ if (elem_index != -1) {
+ BMVert *v_src = BM_vert_at_index(bm, elem_index);
+
+ mirror_data_iter->loc_src = v_src->co;
+ mirror_data_iter->loc_dst = eve->co;
+ mirror_data_iter->sign_x = index[0] && index[0][i] == -2 ? -1 : 1;
+ mirror_data_iter->sign_y = index[1] && index[1][i] == -2 ? -1 : 1;
+ mirror_data_iter->sign_z = index[2] && index[2][i] == -2 ? -1 : 1;
+ mirror_data_iter->extra = eve;
+
+ mirror_data_iter++;
+
+ BLI_BITMAP_ENABLE(*r_mirror_bitmap, i);
+ }
+ }
+ }
+
+ MEM_SAFE_FREE(index[0]);
+ MEM_SAFE_FREE(index[1]);
+ MEM_SAFE_FREE(index[2]);
+
+ bm->elem_index_dirty |= BM_VERT;
+ *r_mirror_data_len = mirror_elem_len;
+ return mirror_data;
+}
+
+/* way to overwrite what data is edited with transform */
+static void VertsToTransData(TransInfo *t,
+ TransData *td,
+ TransDataExtension *tx,
+ BMEditMesh *em,
+ BMVert *eve,
+ float *bweight,
+ struct TransIslandData *v_island,
+ const bool no_island_center)
+{
+ float *no, _no[3];
+ BLI_assert(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) == 0);
+
+ td->flag = 0;
+ // if (key)
+ // td->loc = key->co;
+ // else
+ td->loc = eve->co;
+ copy_v3_v3(td->iloc, td->loc);
+
+ if ((t->mode == TFM_SHRINKFATTEN) && (em->selectmode & SCE_SELECT_FACE) &&
+ BM_elem_flag_test(eve, BM_ELEM_SELECT) &&
+ (BM_vert_calc_normal_ex(eve, BM_ELEM_SELECT, _no))) {
+ no = _no;
+ }
+ else {
+ no = eve->no;
+ }
+
+ if (v_island) {
+ if (no_island_center) {
+ copy_v3_v3(td->center, td->loc);
+ }
+ else {
+ copy_v3_v3(td->center, v_island->co);
+ }
+ copy_m3_m3(td->axismtx, v_island->axismtx);
+ }
+ else if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ copy_v3_v3(td->center, td->loc);
+ createSpaceNormal(td->axismtx, no);
+ }
+ else {
+ copy_v3_v3(td->center, td->loc);
+
+ /* Setting normals */
+ copy_v3_v3(td->axismtx[2], no);
+ td->axismtx[0][0] = td->axismtx[0][1] = td->axismtx[0][2] = td->axismtx[1][0] =
+ td->axismtx[1][1] = td->axismtx[1][2] = 0.0f;
+ }
+
+ td->ext = NULL;
+ td->val = NULL;
+ td->extra = eve;
+ if (t->mode == TFM_BWEIGHT) {
+ td->val = bweight;
+ td->ival = *bweight;
+ }
+ else if (t->mode == TFM_SKIN_RESIZE) {
+ MVertSkin *vs = CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MVERT_SKIN);
+ if (vs) {
+ /* skin node size */
+ td->ext = tx;
+ copy_v3_v3(tx->isize, vs->radius);
+ tx->size = vs->radius;
+ td->val = vs->radius;
+ }
+ else {
+ td->flag |= TD_SKIP;
+ }
+ }
+ else if (t->mode == TFM_SHRINKFATTEN) {
+ td->ext = tx;
+ tx->isize[0] = BM_vert_calc_shell_factor_ex(eve, no, BM_ELEM_SELECT);
+ }
+}
+
+void createTransEditVerts(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *tob = NULL;
+ TransDataExtension *tx = NULL;
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ Mesh *me = tc->obedit->data;
+ BMesh *bm = em->bm;
+ BMVert *eve;
+ BMIter iter;
+ float(*mappedcos)[3] = NULL, (*quats)[4] = NULL;
+ float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL;
+ float *dists = NULL;
+ int a;
+ const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
+ int cd_vert_bweight_offset = -1;
+
+ struct TransIslandData *island_info = NULL;
+ int island_info_tot;
+ int *island_vert_map = NULL;
+
+ /* Snap rotation along normal needs a common axis for whole islands,
+ * otherwise one get random crazy results, see T59104.
+ * However, we do not want to use the island center for the pivot/translation reference. */
+ const bool is_snap_rotate = ((t->mode == TFM_TRANSLATION) &&
+ /* There is not guarantee that snapping
+ * is initialized yet at this point... */
+ (usingSnappingNormal(t) ||
+ (t->settings->snap_flag & SCE_SNAP_ROTATE) != 0) &&
+ (t->around != V3D_AROUND_LOCAL_ORIGINS));
+ /* Even for translation this is needed because of island-orientation, see: T51651. */
+ const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS) || is_snap_rotate;
+ /* Original index of our connected vertex when connected distances are calculated.
+ * Optional, allocate if needed. */
+ int *dists_index = NULL;
+
+ BLI_bitmap *mirror_bitmap = NULL;
+
+ /**
+ * Quick check if we can transform.
+ *
+ * \note ignore modes here, even in edge/face modes,
+ * transform data is created by selected vertices.
+ * \note in prop mode we need at least 1 selected.
+ */
+ if (bm->totvertsel == 0) {
+ goto cleanup;
+ }
+
+ if (t->mode == TFM_BWEIGHT) {
+ BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT);
+ cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
+ }
+
+ if (tc->mirror.use_mirror_any) {
+ bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+ bool use_select = (t->flag & T_PROP_EDIT) == 0;
+ bool mirror_axis[3] = {tc->mirror.axis_x, tc->mirror.axis_y, tc->mirror.axis_z};
+ tc->mirror.data = editmesh_mirror_data_calc(
+ em, use_select, use_topology, mirror_axis, &tc->mirror.data_len, &mirror_bitmap);
+ }
+
+ int data_len = 0;
+ if (prop_mode) {
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ data_len++;
+ }
+ }
+
+ /* allocating scratch arrays */
+ if (prop_mode & T_PROP_CONNECTED) {
+ dists = MEM_mallocN(em->bm->totvert * sizeof(float), __func__);
+ if (is_island_center) {
+ dists_index = MEM_mallocN(em->bm->totvert * sizeof(int), __func__);
+ }
+ }
+ }
+ else {
+ data_len = bm->totvertsel;
+ }
+
+ if (mirror_bitmap) {
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
+ if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ if (BLI_BITMAP_TEST(mirror_bitmap, a)) {
+ data_len--;
+ }
+ }
+ }
+ }
+
+ BLI_assert(data_len != 0);
+
+ tc->data_len = data_len;
+ tc->data = tob = MEM_callocN(data_len * sizeof(TransData), "TransObData(Mesh EditMode)");
+ if (ELEM(t->mode, TFM_SKIN_RESIZE, TFM_SHRINKFATTEN)) {
+ /* warning, this is overkill, we only need 2 extra floats,
+ * but this stores loads of extra stuff, for TFM_SHRINKFATTEN its even more overkill
+ * since we may not use the 'alt' transform mode to maintain shell thickness,
+ * but with generic transform code its hard to lazy init vars */
+ tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension),
+ "TransObData ext");
+ }
+
+ copy_m3_m4(mtx, tc->obedit->obmat);
+ /* we use a pseudo-inverse so that when one of the axes is scaled to 0,
+ * matrix inversion still works and we can still moving along the other */
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+
+ if (prop_mode & T_PROP_CONNECTED) {
+ editmesh_set_connectivity_distance(em->bm, mtx, dists, dists_index);
+ }
+
+ if (is_island_center) {
+ /* In this specific case, near-by vertices will need to know
+ * the island of the nearest connected vertex. */
+ const bool calc_single_islands = ((prop_mode & T_PROP_CONNECTED) &&
+ (t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ (em->selectmode & SCE_SELECT_VERTEX));
+
+ island_info = editmesh_islands_info_calc(
+ em, &island_info_tot, &island_vert_map, calc_single_islands);
+ }
+
+ /* detect CrazySpace [tm] */
+ if (modifiers_getCageIndex(t->scene, tc->obedit, NULL, 1) != -1) {
+ int totleft = -1;
+ if (modifiers_isCorrectableDeformed(t->scene, tc->obedit)) {
+ BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context));
+
+ /* Use evaluated state because we need b-bone cache. */
+ Scene *scene_eval = (Scene *)DEG_get_evaluated_id(t->depsgraph, &t->scene->id);
+ Object *obedit_eval = (Object *)DEG_get_evaluated_id(t->depsgraph, &tc->obedit->id);
+ BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval);
+ /* check if we can use deform matrices for modifier from the
+ * start up to stack, they are more accurate than quats */
+ totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh(
+ t->depsgraph, scene_eval, obedit_eval, em_eval, &defmats, &defcos);
+ }
+
+ /* if we still have more modifiers, also do crazyspace
+ * correction with quats, relative to the coordinates after
+ * the modifiers that support deform matrices (defcos) */
+
+#if 0 /* TODO, fix crazyspace+extrude so it can be enabled for general use - campbell */
+ if ((totleft > 0) || (totleft == -1))
+#else
+ if (totleft > 0)
+#endif
+ {
+ mappedcos = BKE_crazyspace_get_mapped_editverts(t->depsgraph, tc->obedit);
+ quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats");
+ BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode);
+ if (mappedcos) {
+ MEM_freeN(mappedcos);
+ }
+ }
+
+ if (defcos) {
+ MEM_freeN(defcos);
+ }
+ }
+
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
+ if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+ if (mirror_bitmap && BLI_BITMAP_TEST(mirror_bitmap, a)) {
+ continue;
+ }
+ if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ struct TransIslandData *v_island = NULL;
+ float *bweight = (cd_vert_bweight_offset != -1) ?
+ BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) :
+ NULL;
+
+ if (island_info) {
+ const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a;
+ v_island = (island_vert_map[connected_index] != -1) ?
+ &island_info[island_vert_map[connected_index]] :
+ NULL;
+ }
+
+ /* Do not use the island center in case we are using islands
+ * only to get axis for snap/rotate to normal... */
+ VertsToTransData(t, tob, tx, em, eve, bweight, v_island, is_snap_rotate);
+ if (tx) {
+ tx++;
+ }
+
+ /* selected */
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ tob->flag |= TD_SELECTED;
+ }
+
+ if (prop_mode) {
+ if (prop_mode & T_PROP_CONNECTED) {
+ tob->dist = dists[a];
+ }
+ else {
+ tob->flag |= TD_NOTCONNECTED;
+ tob->dist = FLT_MAX;
+ }
+ }
+
+ /* CrazySpace */
+ const bool use_quats = quats && BM_elem_flag_test(eve, BM_ELEM_TAG);
+ if (use_quats || defmats) {
+ float mat[3][3], qmat[3][3], imat[3][3];
+
+ /* Use both or either quat and defmat correction. */
+ if (use_quats) {
+ quat_to_mat3(qmat, quats[BM_elem_index_get(eve)]);
+
+ if (defmats) {
+ mul_m3_series(mat, defmats[a], qmat, mtx);
+ }
+ else {
+ mul_m3_m3m3(mat, mtx, qmat);
+ }
+ }
+ else {
+ mul_m3_m3m3(mat, mtx, defmats[a]);
+ }
+
+ invert_m3_m3(imat, mat);
+
+ copy_m3_m3(tob->smtx, imat);
+ copy_m3_m3(tob->mtx, mat);
+ }
+ else {
+ copy_m3_m3(tob->smtx, smtx);
+ copy_m3_m3(tob->mtx, mtx);
+ }
+
+ if (tc->mirror.use_mirror_any) {
+ if (tc->mirror.axis_x && fabsf(tob->loc[0]) < TRANSFORM_MAXDIST_MIRROR) {
+ tob->flag |= TD_MIRROR_EDGE_X;
+ }
+ if (tc->mirror.axis_y && fabsf(tob->loc[1]) < TRANSFORM_MAXDIST_MIRROR) {
+ tob->flag |= TD_MIRROR_EDGE_Y;
+ }
+ if (tc->mirror.axis_z && fabsf(tob->loc[2]) < TRANSFORM_MAXDIST_MIRROR) {
+ tob->flag |= TD_MIRROR_EDGE_Z;
+ }
+ }
+
+ tob++;
+ }
+ }
+
+ if (island_info) {
+ MEM_freeN(island_info);
+ MEM_freeN(island_vert_map);
+ }
+
+ cleanup:
+ /* crazy space free */
+ if (quats) {
+ MEM_freeN(quats);
+ }
+ if (defmats) {
+ MEM_freeN(defmats);
+ }
+ if (dists) {
+ MEM_freeN(dists);
+ }
+ if (dists_index) {
+ MEM_freeN(dists_index);
+ }
+ if (mirror_bitmap) {
+ MEM_freeN(mirror_bitmap);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name CustomData Layer Correction (for meshes)
+ *
+ * \{ */
+
+struct TransCustomDataLayerVert {
+ BMVert *v;
+ float co_orig_3d[3];
+ struct LinkNode **cd_loop_groups;
+};
+
+struct TransCustomDataLayer {
+ BMesh *bm;
+
+ int cd_loop_mdisp_offset;
+
+ /** map {BMVert: TransCustomDataLayerVert} */
+ struct GHash *origverts;
+ struct GHash *origfaces;
+ struct BMesh *bm_origfaces;
+
+ struct MemArena *arena;
+ /** Number of math BMLoop layers. */
+ int layer_math_map_num;
+ /** Array size of 'layer_math_map_num'
+ * maps TransCustomDataLayerVert.cd_group index to absolute CustomData layer index */
+ int *layer_math_map;
+
+ /* Array with all elements transformed. */
+ struct TransCustomDataLayerVert *data;
+ int data_len;
+};
+
+static void trans_mesh_customdata_free_cb(struct TransInfo *UNUSED(t),
+ struct TransDataContainer *UNUSED(tc),
+ struct TransCustomData *custom_data)
+{
+ struct TransCustomDataLayer *tcld = custom_data->data;
+ bmesh_edit_end(tcld->bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
+
+ if (tcld->bm_origfaces) {
+ BM_mesh_free(tcld->bm_origfaces);
+ }
+ if (tcld->origfaces) {
+ BLI_ghash_free(tcld->origfaces, NULL, NULL);
+ }
+ if (tcld->origverts) {
+ BLI_ghash_free(tcld->origverts, NULL, NULL);
+ }
+ if (tcld->arena) {
+ BLI_memarena_free(tcld->arena);
+ }
+ if (tcld->layer_math_map) {
+ MEM_freeN(tcld->layer_math_map);
+ }
+
+ MEM_freeN(tcld);
+ custom_data->data = NULL;
+}
+
+static void create_trans_vert_customdata_layer(BMVert *v,
+ struct TransCustomDataLayer *tcld,
+ struct TransCustomDataLayerVert *r_tcld_vert)
+{
+ BMesh *bm = tcld->bm;
+ BMIter liter;
+ int j, l_num;
+ float *loop_weights;
+
+ /* copy face data */
+ // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) {
+ BM_iter_init(&liter, bm, BM_LOOPS_OF_VERT, v);
+ l_num = liter.count;
+ loop_weights = BLI_array_alloca(loop_weights, l_num);
+ for (j = 0; j < l_num; j++) {
+ BMLoop *l = BM_iter_step(&liter);
+ BMLoop *l_prev, *l_next;
+ void **val_p;
+ if (!BLI_ghash_ensure_p(tcld->origfaces, l->f, &val_p)) {
+ BMFace *f_copy = BM_face_copy(tcld->bm_origfaces, bm, l->f, true, true);
+ *val_p = f_copy;
+ }
+
+ if ((l_prev = BM_loop_find_prev_nodouble(l, l->next, FLT_EPSILON)) &&
+ (l_next = BM_loop_find_next_nodouble(l, l_prev, FLT_EPSILON))) {
+ loop_weights[j] = angle_v3v3v3(l_prev->v->co, l->v->co, l_next->v->co);
+ }
+ else {
+ loop_weights[j] = 0.0f;
+ }
+ }
+
+ /* store cd_loop_groups */
+ if (tcld->layer_math_map_num && (l_num != 0)) {
+ r_tcld_vert->cd_loop_groups = BLI_memarena_alloc(tcld->arena,
+ tcld->layer_math_map_num * sizeof(void *));
+ for (j = 0; j < tcld->layer_math_map_num; j++) {
+ const int layer_nr = tcld->layer_math_map[j];
+ r_tcld_vert->cd_loop_groups[j] = BM_vert_loop_groups_data_layer_create(
+ bm, v, layer_nr, loop_weights, tcld->arena);
+ }
+ }
+ else {
+ r_tcld_vert->cd_loop_groups = NULL;
+ }
+
+ r_tcld_vert->v = v;
+ copy_v3_v3(r_tcld_vert->co_orig_3d, v->co);
+ BLI_ghash_insert(tcld->origverts, v, r_tcld_vert);
+}
+
+void trans_mesh_customdata_correction_init(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ BLI_assert(tc->custom.type.data == NULL);
+ int i;
+
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BMesh *bm = em->bm;
+
+ bool use_origfaces;
+ int cd_loop_mdisp_offset;
+ {
+ const bool has_layer_math = CustomData_has_math(&bm->ldata);
+ cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
+ if ((t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) &&
+ /* don't do this at all for non-basis shape keys, too easy to
+ * accidentally break uv maps or vertex colors then */
+ (bm->shapenr <= 1) && (has_layer_math || (cd_loop_mdisp_offset != -1))) {
+ use_origfaces = true;
+ }
+ else {
+ use_origfaces = false;
+ cd_loop_mdisp_offset = -1;
+ }
+ }
+
+ if (use_origfaces) {
+ /* create copies of faces for customdata projection */
+ bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
+
+ struct GHash *origfaces = BLI_ghash_ptr_new(__func__);
+ struct BMesh *bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){
+ .use_toolflags = false,
+ }));
+
+ /* we need to have matching customdata */
+ BM_mesh_copy_init_customdata(bm_origfaces, bm, NULL);
+
+ int *layer_math_map = NULL;
+ int layer_index_dst = 0;
+ {
+ /* TODO: We don't need `sod->layer_math_map` when there are no loops linked
+ * to one of the sliding vertices. */
+ if (CustomData_has_math(&bm->ldata)) {
+ /* over alloc, only 'math' layers are indexed */
+ layer_math_map = MEM_mallocN(bm->ldata.totlayer * sizeof(int), __func__);
+ for (i = 0; i < bm->ldata.totlayer; i++) {
+ if (CustomData_layer_has_math(&bm->ldata, i)) {
+ layer_math_map[layer_index_dst++] = i;
+ }
+ }
+ BLI_assert(layer_index_dst != 0);
+ }
+ }
+
+ struct TransCustomDataLayer *tcld;
+ tc->custom.type.data = tcld = MEM_mallocN(sizeof(*tcld), __func__);
+ tc->custom.type.free_cb = trans_mesh_customdata_free_cb;
+
+ tcld->bm = bm;
+ tcld->origfaces = origfaces;
+ tcld->bm_origfaces = bm_origfaces;
+ tcld->cd_loop_mdisp_offset = cd_loop_mdisp_offset;
+ tcld->layer_math_map = layer_math_map;
+ tcld->layer_math_map_num = layer_index_dst;
+ tcld->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+
+ int data_len = tc->data_len + tc->mirror.data_len;
+ struct GHash *origverts = BLI_ghash_ptr_new_ex(__func__, data_len);
+ tcld->origverts = origverts;
+
+ struct TransCustomDataLayerVert *tcld_vert, *tcld_vert_iter;
+ tcld_vert = BLI_memarena_alloc(tcld->arena, data_len * sizeof(*tcld_vert));
+ tcld_vert_iter = &tcld_vert[0];
+
+ TransData *tob;
+ for (i = tc->data_len, tob = tc->data; i--; tob++, tcld_vert_iter++) {
+ BMVert *v = tob->extra;
+ create_trans_vert_customdata_layer(v, tcld, tcld_vert_iter);
+ }
+
+ TransDataMirror *tdm;
+ for (i = tc->mirror.data_len, tdm = tc->mirror.data; i--; tdm++, tcld_vert_iter++) {
+ BMVert *v = tdm->extra;
+ create_trans_vert_customdata_layer(v, tcld, tcld_vert_iter);
+ }
+
+ tcld->data = tcld_vert;
+ tcld->data_len = data_len;
+ }
+ }
+}
+
+/**
+ * If we're sliding the vert, return its original location, if not, the current location is good.
+ */
+static const float *trans_vert_orig_co_get(struct TransCustomDataLayer *tcld, BMVert *v)
+{
+ struct TransCustomDataLayerVert *tcld_vert = BLI_ghash_lookup(tcld->origverts, v);
+ return tcld_vert ? tcld_vert->co_orig_3d : v->co;
+}
+
+static void trans_mesh_customdata_correction_apply_vert(struct TransCustomDataLayer *tcld,
+ struct TransCustomDataLayerVert *tcld_vert,
+ bool is_final)
+{
+ BMesh *bm = tcld->bm;
+ BMVert *v = tcld_vert->v;
+ const float *co_orig_3d = tcld_vert->co_orig_3d;
+ struct LinkNode **cd_loop_groups = tcld_vert->cd_loop_groups;
+
+ BMIter liter;
+ int j, l_num;
+ float *loop_weights;
+ const bool is_moved = (len_squared_v3v3(v->co, co_orig_3d) > FLT_EPSILON);
+ const bool do_loop_weight = tcld->layer_math_map_num && is_moved;
+ const bool do_loop_mdisps = is_final && is_moved && (tcld->cd_loop_mdisp_offset != -1);
+ const float *v_proj_axis = v->no;
+ /* original (l->prev, l, l->next) projections for each loop ('l' remains unchanged) */
+ float v_proj[3][3];
+
+ if (do_loop_weight || do_loop_mdisps) {
+ project_plane_normalized_v3_v3v3(v_proj[1], co_orig_3d, v_proj_axis);
+ }
+
+ // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT)
+ BM_iter_init(&liter, bm, BM_LOOPS_OF_VERT, v);
+ l_num = liter.count;
+ loop_weights = do_loop_weight ? BLI_array_alloca(loop_weights, l_num) : NULL;
+ for (j = 0; j < l_num; j++) {
+ BMFace *f_copy; /* the copy of 'f' */
+ BMLoop *l = BM_iter_step(&liter);
+
+ f_copy = BLI_ghash_lookup(tcld->origfaces, l->f);
+
+ /* only loop data, no vertex data since that contains shape keys,
+ * and we do not want to mess up other shape keys */
+ BM_loop_interp_from_face(bm, l, f_copy, false, false);
+
+ /* make sure face-attributes are correct (e.g. #MLoopUV, #MLoopCol) */
+ BM_elem_attrs_copy_ex(tcld->bm_origfaces, bm, f_copy, l->f, 0x0, CD_MASK_NORMAL);
+
+ /* weight the loop */
+ if (do_loop_weight) {
+ const float eps = 1.0e-8f;
+ const BMLoop *l_prev = l->prev;
+ const BMLoop *l_next = l->next;
+ const float *co_prev = trans_vert_orig_co_get(tcld, l_prev->v);
+ const float *co_next = trans_vert_orig_co_get(tcld, l_next->v);
+ bool co_prev_ok;
+ bool co_next_ok;
+
+ /* In the unlikely case that we're next to a zero length edge -
+ * walk around the to the next.
+ *
+ * Since we only need to check if the vertex is in this corner,
+ * its not important _which_ loop - as long as its not overlapping
+ * 'sv->co_orig_3d', see: T45096. */
+ project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
+ while (UNLIKELY(((co_prev_ok = (len_squared_v3v3(v_proj[1], v_proj[0]) > eps)) == false) &&
+ ((l_prev = l_prev->prev) != l->next))) {
+ co_prev = trans_vert_orig_co_get(tcld, l_prev->v);
+ project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
+ }
+ project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis);
+ while (UNLIKELY(((co_next_ok = (len_squared_v3v3(v_proj[1], v_proj[2]) > eps)) == false) &&
+ ((l_next = l_next->next) != l->prev))) {
+ co_next = trans_vert_orig_co_get(tcld, l_next->v);
+ project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis);
+ }
+
+ if (co_prev_ok && co_next_ok) {
+ const float dist = dist_signed_squared_to_corner_v3v3v3(
+ v->co, UNPACK3(v_proj), v_proj_axis);
+
+ loop_weights[j] = (dist >= 0.0f) ? 1.0f : ((dist <= -eps) ? 0.0f : (1.0f + (dist / eps)));
+ if (UNLIKELY(!isfinite(loop_weights[j]))) {
+ loop_weights[j] = 0.0f;
+ }
+ }
+ else {
+ loop_weights[j] = 0.0f;
+ }
+ }
+ }
+
+ if (tcld->layer_math_map_num && cd_loop_groups) {
+ if (do_loop_weight) {
+ for (j = 0; j < tcld->layer_math_map_num; j++) {
+ BM_vert_loop_groups_data_layer_merge_weights(
+ bm, cd_loop_groups[j], tcld->layer_math_map[j], loop_weights);
+ }
+ }
+ else {
+ for (j = 0; j < tcld->layer_math_map_num; j++) {
+ BM_vert_loop_groups_data_layer_merge(bm, cd_loop_groups[j], tcld->layer_math_map[j]);
+ }
+ }
+ }
+
+ /* Special handling for multires
+ *
+ * Interpolate from every other loop (not ideal)
+ * However values will only be taken from loops which overlap other mdisps.
+ * */
+ if (do_loop_mdisps) {
+ float(*faces_center)[3] = BLI_array_alloca(faces_center, l_num);
+ BMLoop *l;
+
+ BM_ITER_ELEM_INDEX (l, &liter, v, BM_LOOPS_OF_VERT, j) {
+ BM_face_calc_center_median(l->f, faces_center[j]);
+ }
+
+ BM_ITER_ELEM_INDEX (l, &liter, v, BM_LOOPS_OF_VERT, j) {
+ BMFace *f_copy = BLI_ghash_lookup(tcld->origfaces, l->f);
+ float f_copy_center[3];
+ BMIter liter_other;
+ BMLoop *l_other;
+ int j_other;
+
+ BM_face_calc_center_median(f_copy, f_copy_center);
+
+ BM_ITER_ELEM_INDEX (l_other, &liter_other, v, BM_LOOPS_OF_VERT, j_other) {
+ BM_face_interp_multires_ex(bm,
+ l_other->f,
+ f_copy,
+ faces_center[j_other],
+ f_copy_center,
+ tcld->cd_loop_mdisp_offset);
+ }
+ }
+ }
+}
+
+void trans_mesh_customdata_correction_apply(struct TransDataContainer *tc, bool is_final)
+{
+ struct TransCustomDataLayer *tcld = tc->custom.type.data;
+ if (!tcld) {
+ return;
+ }
+
+ const bool has_mdisps = (tcld->cd_loop_mdisp_offset != -1);
+ struct TransCustomDataLayerVert *tcld_vert_iter = &tcld->data[0];
+
+ for (int i = tcld->data_len; i--; tcld_vert_iter++) {
+ if (tcld_vert_iter->cd_loop_groups || has_mdisps) {
+ trans_mesh_customdata_correction_apply_vert(tcld, tcld_vert_iter, is_final);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edge (for crease) Transform Creation
+ *
+ * \{ */
+
+void createTransEdge(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ TransData *td = NULL;
+ BMEdge *eed;
+ BMIter iter;
+ float mtx[3][3], smtx[3][3];
+ int count = 0, countsel = 0;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ int cd_edge_float_offset;
+
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ countsel++;
+ }
+ if (is_prop_edit) {
+ count++;
+ }
+ }
+ }
+
+ if (countsel == 0) {
+ tc->data_len = 0;
+ continue;
+ }
+
+ if (is_prop_edit) {
+ tc->data_len = count;
+ }
+ else {
+ tc->data_len = countsel;
+ }
+
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransCrease");
+
+ copy_m3_m4(mtx, tc->obedit->obmat);
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+
+ /* create data we need */
+ if (t->mode == TFM_BWEIGHT) {
+ BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_BWEIGHT);
+ cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
+ }
+ else { // if (t->mode == TFM_CREASE) {
+ BLI_assert(t->mode == TFM_CREASE);
+ BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_CREASE);
+ cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
+ }
+
+ BLI_assert(cd_edge_float_offset != -1);
+
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) &&
+ (BM_elem_flag_test(eed, BM_ELEM_SELECT) || is_prop_edit)) {
+ float *fl_ptr;
+ /* need to set center for center calculations */
+ mid_v3_v3v3(td->center, eed->v1->co, eed->v2->co);
+
+ td->loc = NULL;
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ td->flag = TD_SELECTED;
+ }
+ else {
+ td->flag = 0;
+ }
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+
+ td->ext = NULL;
+
+ fl_ptr = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_float_offset);
+ td->val = fl_ptr;
+ td->ival = *fl_ptr;
+
+ td++;
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UVs Transform Creation
+ *
+ * \{ */
+
+static void UVsToTransData(const float aspect[2],
+ TransData *td,
+ TransData2D *td2d,
+ float *uv,
+ const float *center,
+ bool selected)
+{
+ /* uv coords are scaled by aspects. this is needed for rotations and
+ * proportional editing to be consistent with the stretched uv coords
+ * that are displayed. this also means that for display and numinput,
+ * and when the uv coords are flushed, these are converted each time */
+ td2d->loc[0] = uv[0] * aspect[0];
+ td2d->loc[1] = uv[1] * aspect[1];
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = uv;
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ copy_v2_v2(td->center, center ? center : td->loc);
+ td->center[2] = 0.0f;
+ copy_v3_v3(td->iloc, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ if (selected) {
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+ }
+ else {
+ td->dist = FLT_MAX;
+ }
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+}
+
+void createTransUVs(bContext *C, TransInfo *t)
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = CTX_data_edit_image(C);
+ Scene *scene = t->scene;
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0;
+ const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS);
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BMFace *efa;
+ BMIter iter, liter;
+ UvElementMap *elementmap = NULL;
+ BLI_bitmap *island_enabled = NULL;
+ struct {
+ float co[2];
+ int co_num;
+ } *island_center = NULL;
+ int count = 0, countsel = 0, count_rejected = 0;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (!ED_space_image_show_uvedit(sima, tc->obedit)) {
+ continue;
+ }
+
+ /* count */
+ if (is_prop_connected || is_island_center) {
+ /* create element map with island information */
+ const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0;
+ elementmap = BM_uv_element_map_create(em->bm, use_facesel, false, true);
+ if (elementmap == NULL) {
+ return;
+ }
+
+ if (is_prop_connected) {
+ island_enabled = BLI_BITMAP_NEW(elementmap->totalIslands, "TransIslandData(UV Editing)");
+ }
+
+ if (is_island_center) {
+ island_center = MEM_callocN(sizeof(*island_center) * elementmap->totalIslands, __func__);
+ }
+ }
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BMLoop *l;
+
+ if (!uvedit_face_visible_test(scene, tc->obedit, ima, efa)) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ continue;
+ }
+
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ countsel++;
+
+ if (is_prop_connected || island_center) {
+ UvElement *element = BM_uv_element_get(elementmap, efa, l);
+
+ if (is_prop_connected) {
+ BLI_BITMAP_ENABLE(island_enabled, element->island);
+ }
+
+ if (is_island_center) {
+ if (element->flag == false) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ add_v2_v2(island_center[element->island].co, luv->uv);
+ island_center[element->island].co_num++;
+ element->flag = true;
+ }
+ }
+ }
+ }
+
+ if (is_prop_edit) {
+ count++;
+ }
+ }
+ }
+
+ /* note: in prop mode we need at least 1 selected */
+ if (countsel == 0) {
+ goto finally;
+ }
+
+ if (is_island_center) {
+ int i;
+
+ for (i = 0; i < elementmap->totalIslands; i++) {
+ mul_v2_fl(island_center[i].co, 1.0f / island_center[i].co_num);
+ mul_v2_v2(island_center[i].co, t->aspect);
+ }
+ }
+
+ tc->data_len = (is_prop_edit) ? count : countsel;
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(UV Editing)");
+ /* for each 2d uv coord a 3d vector is allocated, so that they can be
+ * treated just as if they were 3d verts */
+ tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransObData2D(UV Editing)");
+
+ if (sima->flag & SI_CLIP_UV) {
+ t->flag |= T_CLIP_UV;
+ }
+
+ td = tc->data;
+ td2d = tc->data_2d;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BMLoop *l;
+
+ if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ const bool selected = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ MLoopUV *luv;
+ const float *center = NULL;
+
+ if (!is_prop_edit && !selected) {
+ continue;
+ }
+
+ if (is_prop_connected || is_island_center) {
+ UvElement *element = BM_uv_element_get(elementmap, efa, l);
+
+ if (is_prop_connected) {
+ if (!BLI_BITMAP_TEST(island_enabled, element->island)) {
+ count_rejected++;
+ continue;
+ }
+ }
+
+ if (is_island_center) {
+ center = island_center[element->island].co;
+ }
+ }
+
+ BM_elem_flag_enable(l, BM_ELEM_TAG);
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ UVsToTransData(t->aspect, td++, td2d++, luv->uv, center, selected);
+ }
+ }
+
+ if (is_prop_connected) {
+ tc->data_len -= count_rejected;
+ }
+
+ if (sima->flag & SI_LIVE_UNWRAP) {
+ ED_uvedit_live_unwrap_begin(t->scene, tc->obedit);
+ }
+
+ finally:
+ if (is_prop_connected || is_island_center) {
+ BM_uv_element_map_free(elementmap);
+
+ if (is_prop_connected) {
+ MEM_freeN(island_enabled);
+ }
+
+ if (island_center) {
+ MEM_freeN(island_center);
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UVs Transform Flush
+ *
+ * \{ */
+
+void flushTransUVs(TransInfo *t)
+{
+ SpaceImage *sima = t->sa->spacedata.first;
+ const bool use_pixel_snap = ((sima->pixel_snap_mode != SI_PIXEL_SNAP_DISABLED) &&
+ (t->state != TRANS_CANCEL));
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData2D *td;
+ int a;
+ float aspect_inv[2], size[2];
+
+ aspect_inv[0] = 1.0f / t->aspect[0];
+ aspect_inv[1] = 1.0f / t->aspect[1];
+
+ if (use_pixel_snap) {
+ int size_i[2];
+ ED_space_image_get_size(sima, &size_i[0], &size_i[1]);
+ size[0] = size_i[0];
+ size[1] = size_i[1];
+ }
+
+ /* flush to 2d vector from internally used 3d vector */
+ for (a = 0, td = tc->data_2d; a < tc->data_len; a++, td++) {
+ td->loc2d[0] = td->loc[0] * aspect_inv[0];
+ td->loc2d[1] = td->loc[1] * aspect_inv[1];
+
+ if (use_pixel_snap) {
+ td->loc2d[0] *= size[0];
+ td->loc2d[1] *= size[1];
+
+ switch (sima->pixel_snap_mode) {
+ case SI_PIXEL_SNAP_CENTER:
+ td->loc2d[0] = roundf(td->loc2d[0] - 0.5f) + 0.5f;
+ td->loc2d[1] = roundf(td->loc2d[1] - 0.5f) + 0.5f;
+ break;
+ case SI_PIXEL_SNAP_CORNER:
+ td->loc2d[0] = roundf(td->loc2d[0]);
+ td->loc2d[1] = roundf(td->loc2d[1]);
+ break;
+ }
+
+ td->loc2d[0] /= size[0];
+ td->loc2d[1] /= size[1];
+ }
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c
new file mode 100644
index 00000000000..114968ec83f
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_nla.c
@@ -0,0 +1,265 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_anim_types.h"
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_listbase.h"
+
+#include "BKE_nla.h"
+#include "BKE_context.h"
+#include "BKE_report.h"
+
+#include "ED_anim_api.h"
+
+#include "UI_view2d.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name NLA Transform Creation
+ *
+ * \{ */
+
+void createTransNlaData(bContext *C, TransInfo *t)
+{
+ Scene *scene = t->scene;
+ SpaceNla *snla = NULL;
+ TransData *td = NULL;
+ TransDataNla *tdn = NULL;
+
+ bAnimContext ac;
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ int count = 0;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* determine what type of data we are operating on */
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return;
+ }
+ snla = (SpaceNla *)ac.sl;
+
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* which side of the current frame should be allowed */
+ if (t->mode == TFM_TIME_EXTEND) {
+ /* only side on which mouse is gets transformed */
+ float xmouse, ymouse;
+
+ UI_view2d_region_to_view(&ac.ar->v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse);
+ t->frame_side = (xmouse > CFRA) ? 'R' : 'L';
+ }
+ else {
+ /* normal transform - both sides of current frame are considered */
+ t->frame_side = 'B';
+ }
+
+ /* loop 1: count how many strips are selected (consider each strip as 2 points) */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ NlaTrack *nlt = (NlaTrack *)ale->data;
+ NlaStrip *strip;
+
+ /* make some meta-strips for chains of selected strips */
+ BKE_nlastrips_make_metas(&nlt->strips, 1);
+
+ /* only consider selected strips */
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ // TODO: we can make strips have handles later on...
+ /* transition strips can't get directly transformed */
+ if (strip->type != NLASTRIP_TYPE_TRANSITION) {
+ if (strip->flag & NLASTRIP_FLAG_SELECT) {
+ if (FrameOnMouseSide(t->frame_side, strip->start, (float)CFRA)) {
+ count++;
+ }
+ if (FrameOnMouseSide(t->frame_side, strip->end, (float)CFRA)) {
+ count++;
+ }
+ }
+ }
+ }
+ }
+
+ /* stop if trying to build list if nothing selected */
+ if (count == 0) {
+ /* clear temp metas that may have been created but aren't needed now
+ * because they fell on the wrong side of CFRA
+ */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ NlaTrack *nlt = (NlaTrack *)ale->data;
+ BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
+ }
+
+ /* cleanup temp list */
+ ANIM_animdata_freelist(&anim_data);
+ return;
+ }
+
+ /* allocate memory for data */
+ tc->data_len = count;
+
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(NLA Editor)");
+ td = tc->data;
+ tc->custom.type.data = tdn = MEM_callocN(tc->data_len * sizeof(TransDataNla),
+ "TransDataNla (NLA Editor)");
+ tc->custom.type.use_free = true;
+
+ /* loop 2: build transdata array */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ /* only if a real NLA-track */
+ if (ale->type == ANIMTYPE_NLATRACK) {
+ AnimData *adt = ale->adt;
+ NlaTrack *nlt = (NlaTrack *)ale->data;
+ NlaStrip *strip;
+
+ /* only consider selected strips */
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ // TODO: we can make strips have handles later on...
+ /* transition strips can't get directly transformed */
+ if (strip->type != NLASTRIP_TYPE_TRANSITION) {
+ if (strip->flag & NLASTRIP_FLAG_SELECT) {
+ /* our transform data is constructed as follows:
+ * - only the handles on the right side of the current-frame get included
+ * - td structs are transform-elements operated on by the transform system
+ * and represent a single handle. The storage/pointer used (val or loc) depends on
+ * whether we're scaling or transforming. Ultimately though, the handles
+ * the td writes to will simply be a dummy in tdn
+ * - for each strip being transformed, a single tdn struct is used, so in some
+ * cases, there will need to be 1 of these tdn elements in the array skipped...
+ */
+ float center[3], yval;
+
+ /* firstly, init tdn settings */
+ tdn->id = ale->id;
+ tdn->oldTrack = tdn->nlt = nlt;
+ tdn->strip = strip;
+ tdn->trackIndex = BLI_findindex(&adt->nla_tracks, nlt);
+
+ yval = (float)(tdn->trackIndex * NLACHANNEL_STEP(snla));
+
+ tdn->h1[0] = strip->start;
+ tdn->h1[1] = yval;
+ tdn->h2[0] = strip->end;
+ tdn->h2[1] = yval;
+
+ center[0] = (float)CFRA;
+ center[1] = yval;
+ center[2] = 0.0f;
+
+ /* set td's based on which handles are applicable */
+ if (FrameOnMouseSide(t->frame_side, strip->start, (float)CFRA)) {
+ /* just set tdn to assume that it only has one handle for now */
+ tdn->handle = -1;
+
+ /* now, link the transform data up to this data */
+ if (ELEM(t->mode, TFM_TRANSLATION, TFM_TIME_EXTEND)) {
+ td->loc = tdn->h1;
+ copy_v3_v3(td->iloc, tdn->h1);
+
+ /* store all the other gunk that is required by transform */
+ copy_v3_v3(td->center, center);
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0f;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+ }
+ else {
+ /* time scaling only needs single value */
+ td->val = &tdn->h1[0];
+ td->ival = tdn->h1[0];
+ }
+
+ td->extra = tdn;
+ td++;
+ }
+ if (FrameOnMouseSide(t->frame_side, strip->end, (float)CFRA)) {
+ /* if tdn is already holding the start handle,
+ * then we're doing both, otherwise, only end */
+ tdn->handle = (tdn->handle) ? 2 : 1;
+
+ /* now, link the transform data up to this data */
+ if (ELEM(t->mode, TFM_TRANSLATION, TFM_TIME_EXTEND)) {
+ td->loc = tdn->h2;
+ copy_v3_v3(td->iloc, tdn->h2);
+
+ /* store all the other gunk that is required by transform */
+ copy_v3_v3(td->center, center);
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0f;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+ }
+ else {
+ /* time scaling only needs single value */
+ td->val = &tdn->h2[0];
+ td->ival = tdn->h2[0];
+ }
+
+ td->extra = tdn;
+ td++;
+ }
+
+ /* If both handles were used, skip the next tdn (i.e. leave it blank)
+ * since the counting code is dumb.
+ * Otherwise, just advance to the next one.
+ */
+ if (tdn->handle == 2) {
+ tdn += 2;
+ }
+ else {
+ tdn++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* cleanup temp list */
+ ANIM_animdata_freelist(&anim_data);
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.c
new file mode 100644
index 00000000000..41e3a79e4c9
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_node.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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_node.h"
+#include "BKE_report.h"
+
+#include "ED_node.h"
+
+#include "UI_interface.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Node Transform Creation
+ *
+ * \{ */
+
+/* transcribe given node into TransData2D for Transforming */
+static void NodeToTransData(TransData *td, TransData2D *td2d, bNode *node, const float dpi_fac)
+{
+ float locx, locy;
+
+ /* account for parents (nested nodes) */
+ if (node->parent) {
+ nodeToView(node->parent, node->locx, node->locy, &locx, &locy);
+ }
+ else {
+ locx = node->locx;
+ locy = node->locy;
+ }
+
+ /* use top-left corner as the transform origin for nodes */
+ /* weirdo - but the node system is a mix of free 2d elements and dpi sensitive UI */
+#ifdef USE_NODE_CENTER
+ td2d->loc[0] = (locx * dpi_fac) + (BLI_rctf_size_x(&node->totr) * +0.5f);
+ td2d->loc[1] = (locy * dpi_fac) + (BLI_rctf_size_y(&node->totr) * -0.5f);
+#else
+ td2d->loc[0] = locx * dpi_fac;
+ td2d->loc[1] = locy * dpi_fac;
+#endif
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = td2d->loc; /* current location */
+
+ td->flag = 0;
+
+ td->loc = td2d->loc;
+ copy_v3_v3(td->iloc, td->loc);
+ /* use node center instead of origin (top-left corner) */
+ td->center[0] = td2d->loc[0];
+ td->center[1] = td2d->loc[1];
+ td->center[2] = 0.0f;
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+
+ td->extra = node;
+}
+
+static bool is_node_parent_select(bNode *node)
+{
+ while ((node = node->parent)) {
+ if (node->flag & NODE_TRANSFORM) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
+{
+ const float dpi_fac = UI_DPI_FAC;
+ TransData *td;
+ TransData2D *td2d;
+ SpaceNode *snode = t->sa->spacedata.first;
+ bNode *node;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ tc->data_len = 0;
+
+ if (!snode->edittree) {
+ return;
+ }
+
+ /* nodes dont support PET and probably never will */
+ t->flag &= ~T_PROP_EDIT_ALL;
+
+ /* set transform flags on nodes */
+ for (node = snode->edittree->nodes.first; node; node = node->next) {
+ if (node->flag & NODE_SELECT && is_node_parent_select(node) == false) {
+ node->flag |= NODE_TRANSFORM;
+ tc->data_len++;
+ }
+ else {
+ node->flag &= ~NODE_TRANSFORM;
+ }
+ }
+
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransNode TransData");
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransNode TransData2D");
+
+ for (node = snode->edittree->nodes.first; node; node = node->next) {
+ if (node->flag & NODE_TRANSFORM) {
+ NodeToTransData(td++, td2d++, node, dpi_fac);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Transform Creation
+ *
+ * \{ */
+
+void flushTransNodes(TransInfo *t)
+{
+ const float dpi_fac = UI_DPI_FAC;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ int a;
+ TransData *td;
+ TransData2D *td2d;
+
+ applyGridAbsolute(t);
+
+ /* flush to 2d vector from internally used 3d vector */
+ for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
+ bNode *node = td->extra;
+ float locx, locy;
+
+ /* weirdo - but the node system is a mix of free 2d elements and dpi sensitive UI */
+#ifdef USE_NODE_CENTER
+ locx = (td2d->loc[0] - (BLI_rctf_size_x(&node->totr)) * +0.5f) / dpi_fac;
+ locy = (td2d->loc[1] - (BLI_rctf_size_y(&node->totr)) * -0.5f) / dpi_fac;
+#else
+ locx = td2d->loc[0] / dpi_fac;
+ locy = td2d->loc[1] / dpi_fac;
+#endif
+
+ /* account for parents (nested nodes) */
+ if (node->parent) {
+ nodeFromView(node->parent, locx, locy, &node->locx, &node->locy);
+ }
+ else {
+ node->locx = locx;
+ node->locy = locy;
+ }
+ }
+
+ /* handle intersection with noodles */
+ if (tc->data_len == 1) {
+ ED_node_link_intersect_test(t->sa, 1);
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c
new file mode 100644
index 00000000000..6e85f6b9bf0
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_object.c
@@ -0,0 +1,949 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_mesh_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_compiler_compat.h"
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_layer.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+#include "BKE_rigidbody.h"
+#include "BKE_scene.h"
+
+#include "ED_object.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Object Mode Custom Data
+ * \{ */
+
+typedef struct TransDataObject {
+
+ /**
+ * Object to object data transform table.
+ * Don't add these to transform data because we may want to include child objects
+ * which aren't being transformed.
+ * - The key is object data #ID.
+ * - The value is #XFormObjectData_Extra.
+ */
+ struct GHash *obdata_in_obmode_map;
+
+ /**
+ * Transform
+ * - The key is object data #Object.
+ * - The value is #XFormObjectSkipChild.
+ */
+ struct GHash *obchild_in_obmode_map;
+
+} TransDataObject;
+
+static void trans_obdata_in_obmode_free_all(TransDataObject *tdo);
+static void trans_obchild_in_obmode_free_all(TransDataObject *tdo);
+
+static void freeTransObjectCustomData(TransInfo *t,
+ TransDataContainer *UNUSED(tc),
+ TransCustomData *custom_data)
+{
+ TransDataObject *tdo = custom_data->data;
+ custom_data->data = NULL;
+
+ if (t->options & CTX_OBMODE_XFORM_OBDATA) {
+ trans_obdata_in_obmode_free_all(tdo);
+ }
+
+ if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) {
+ trans_obchild_in_obmode_free_all(tdo);
+ }
+ MEM_freeN(tdo);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Data in Object Mode
+ *
+ * Use to implement 'Affect Only Origins' feature.
+ * We need this to be detached from transform data because,
+ * unlike transforming regular objects, we need to transform the children.
+ *
+ * \{ */
+
+struct XFormObjectData_Extra {
+ Object *ob;
+ float obmat_orig[4][4];
+ struct XFormObjectData *xod;
+};
+
+static void trans_obdata_in_obmode_ensure_object(TransDataObject *tdo, Object *ob)
+{
+ if (tdo->obdata_in_obmode_map == NULL) {
+ tdo->obdata_in_obmode_map = BLI_ghash_ptr_new(__func__);
+ }
+
+ void **xf_p;
+ if (!BLI_ghash_ensure_p(tdo->obdata_in_obmode_map, ob->data, &xf_p)) {
+ struct XFormObjectData_Extra *xf = MEM_mallocN(sizeof(*xf), __func__);
+ copy_m4_m4(xf->obmat_orig, ob->obmat);
+ xf->ob = ob;
+ /* Result may be NULL, that's OK. */
+ xf->xod = ED_object_data_xform_create(ob->data);
+ *xf_p = xf;
+ }
+}
+
+void trans_obdata_in_obmode_update_all(TransInfo *t)
+{
+ TransDataObject *tdo = t->custom.type.data;
+ if (tdo->obdata_in_obmode_map == NULL) {
+ return;
+ }
+
+ struct Main *bmain = CTX_data_main(t->context);
+ BKE_scene_graph_evaluated_ensure(t->depsgraph, bmain);
+
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, tdo->obdata_in_obmode_map) {
+ ID *id = BLI_ghashIterator_getKey(&gh_iter);
+ struct XFormObjectData_Extra *xf = BLI_ghashIterator_getValue(&gh_iter);
+ if (xf->xod == NULL) {
+ continue;
+ }
+
+ Object *ob_eval = DEG_get_evaluated_object(t->depsgraph, xf->ob);
+ float imat[4][4], dmat[4][4];
+ invert_m4_m4(imat, xf->obmat_orig);
+ mul_m4_m4m4(dmat, imat, ob_eval->obmat);
+ invert_m4(dmat);
+
+ ED_object_data_xform_by_mat4(xf->xod, dmat);
+ if (xf->ob->type == OB_ARMATURE) {
+ /* TODO: none of the current flags properly update armatures, needs investigation. */
+ DEG_id_tag_update(id, 0);
+ }
+ else {
+ DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
+ }
+ }
+}
+
+/** Callback for #GHash free. */
+static void trans_obdata_in_obmode_free_elem(void *xf_p)
+{
+ struct XFormObjectData_Extra *xf = xf_p;
+ if (xf->xod) {
+ ED_object_data_xform_destroy(xf->xod);
+ }
+ MEM_freeN(xf);
+}
+
+static void trans_obdata_in_obmode_free_all(TransDataObject *tdo)
+{
+ if (tdo->obdata_in_obmode_map != NULL) {
+ BLI_ghash_free(tdo->obdata_in_obmode_map, NULL, trans_obdata_in_obmode_free_elem);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Child Skip
+ *
+ * Don't transform unselected children, this is done using the parent inverse matrix.
+ *
+ * \note The complex logic here is caused by mixed selection within a single selection chain,
+ * otherwise we only need #OB_SKIP_CHILD_PARENT_IS_XFORM for single objects.
+ *
+ * \{ */
+
+enum {
+ /**
+ * The parent is transformed, this is held in place.
+ */
+ OB_SKIP_CHILD_PARENT_IS_XFORM = 1,
+ /**
+ * The same as #OB_SKIP_CHILD_PARENT_IS_XFORM,
+ * however this objects parent isn't transformed directly.
+ */
+ OB_SKIP_CHILD_PARENT_IS_XFORM_INDIRECT = 3,
+ /**
+ * Use the parent invert matrix to apply transformation,
+ * this is needed, because breaks in the selection chain prevents this from being transformed.
+ * This is used to add the transform which would have been added
+ * if there weren't breaks in the parent/child chain.
+ */
+ OB_SKIP_CHILD_PARENT_APPLY_TRANSFORM = 2,
+};
+
+struct XFormObjectSkipChild {
+ float obmat_orig[4][4];
+ float parent_obmat_orig[4][4];
+ float parent_obmat_inv_orig[4][4];
+ float parent_recurse_obmat_orig[4][4];
+ float parentinv_orig[4][4];
+ Object *ob_parent_recurse;
+ int mode;
+};
+
+static void trans_obchild_in_obmode_ensure_object(TransDataObject *tdo,
+ Object *ob,
+ Object *ob_parent_recurse,
+ int mode)
+{
+ if (tdo->obchild_in_obmode_map == NULL) {
+ tdo->obchild_in_obmode_map = BLI_ghash_ptr_new(__func__);
+ }
+
+ void **xf_p;
+ if (!BLI_ghash_ensure_p(tdo->obchild_in_obmode_map, ob, &xf_p)) {
+ struct XFormObjectSkipChild *xf = MEM_mallocN(sizeof(*xf), __func__);
+ copy_m4_m4(xf->parentinv_orig, ob->parentinv);
+ copy_m4_m4(xf->obmat_orig, ob->obmat);
+ copy_m4_m4(xf->parent_obmat_orig, ob->parent->obmat);
+ invert_m4_m4(xf->parent_obmat_inv_orig, ob->parent->obmat);
+ if (ob_parent_recurse) {
+ copy_m4_m4(xf->parent_recurse_obmat_orig, ob_parent_recurse->obmat);
+ }
+ xf->mode = mode;
+ xf->ob_parent_recurse = ob_parent_recurse;
+ *xf_p = xf;
+ }
+}
+
+void trans_obchild_in_obmode_update_all(TransInfo *t)
+{
+ TransDataObject *tdo = t->custom.type.data;
+ if (tdo->obchild_in_obmode_map == NULL) {
+ return;
+ }
+
+ struct Main *bmain = CTX_data_main(t->context);
+ BKE_scene_graph_evaluated_ensure(t->depsgraph, bmain);
+
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, tdo->obchild_in_obmode_map) {
+ Object *ob = BLI_ghashIterator_getKey(&gh_iter);
+ struct XFormObjectSkipChild *xf = BLI_ghashIterator_getValue(&gh_iter);
+
+ /* The following blocks below assign 'dmat'. */
+ float dmat[4][4];
+
+ if (xf->mode == OB_SKIP_CHILD_PARENT_IS_XFORM) {
+ /* Parent is transformed, this isn't so compensate. */
+ Object *ob_parent_eval = DEG_get_evaluated_object(t->depsgraph, ob->parent);
+ mul_m4_m4m4(dmat, xf->parent_obmat_inv_orig, ob_parent_eval->obmat);
+ invert_m4(dmat);
+ }
+ else if (xf->mode == OB_SKIP_CHILD_PARENT_IS_XFORM_INDIRECT) {
+ /* Calculate parent matrix (from the root transform). */
+ Object *ob_parent_recurse_eval = DEG_get_evaluated_object(t->depsgraph,
+ xf->ob_parent_recurse);
+ float parent_recurse_obmat_inv[4][4];
+ invert_m4_m4(parent_recurse_obmat_inv, ob_parent_recurse_eval->obmat);
+ mul_m4_m4m4(dmat, xf->parent_recurse_obmat_orig, parent_recurse_obmat_inv);
+ invert_m4(dmat);
+ float parent_obmat_calc[4][4];
+ mul_m4_m4m4(parent_obmat_calc, dmat, xf->parent_obmat_orig);
+
+ /* Apply to the parent inverse matrix. */
+ mul_m4_m4m4(dmat, xf->parent_obmat_inv_orig, parent_obmat_calc);
+ invert_m4(dmat);
+ }
+ else {
+ BLI_assert(xf->mode == OB_SKIP_CHILD_PARENT_APPLY_TRANSFORM);
+ /* Transform this - without transform data. */
+ Object *ob_parent_recurse_eval = DEG_get_evaluated_object(t->depsgraph,
+ xf->ob_parent_recurse);
+ float parent_recurse_obmat_inv[4][4];
+ invert_m4_m4(parent_recurse_obmat_inv, ob_parent_recurse_eval->obmat);
+ mul_m4_m4m4(dmat, xf->parent_recurse_obmat_orig, parent_recurse_obmat_inv);
+ invert_m4(dmat);
+ float obmat_calc[4][4];
+ mul_m4_m4m4(obmat_calc, dmat, xf->obmat_orig);
+ /* obmat_calc is just obmat. */
+
+ /* Get the matrices relative to the parent. */
+ float obmat_parent_relative_orig[4][4];
+ float obmat_parent_relative_calc[4][4];
+ float obmat_parent_relative_inv_orig[4][4];
+
+ mul_m4_m4m4(obmat_parent_relative_orig, xf->parent_obmat_inv_orig, xf->obmat_orig);
+ mul_m4_m4m4(obmat_parent_relative_calc, xf->parent_obmat_inv_orig, obmat_calc);
+ invert_m4_m4(obmat_parent_relative_inv_orig, obmat_parent_relative_orig);
+
+ /* Apply to the parent inverse matrix. */
+ mul_m4_m4m4(dmat, obmat_parent_relative_calc, obmat_parent_relative_inv_orig);
+ }
+
+ mul_m4_m4m4(ob->parentinv, dmat, xf->parentinv_orig);
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+ }
+}
+
+static void trans_obchild_in_obmode_free_all(TransDataObject *tdo)
+{
+ if (tdo->obchild_in_obmode_map != NULL) {
+ BLI_ghash_free(tdo->obchild_in_obmode_map, NULL, MEM_freeN);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Transform Creation
+ *
+ * Instead of transforming the selection, move the 2D/3D cursor.
+ *
+ * \{ */
+
+/* *********************** Object Transform data ******************* */
+
+/* transcribe given object into TransData for Transforming */
+static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
+{
+ Scene *scene = t->scene;
+ bool constinv;
+ bool skip_invert = false;
+
+ if (t->mode != TFM_DUMMY && ob->rigidbody_object) {
+ float rot[3][3], scale[3];
+ float ctime = BKE_scene_frame_get(scene);
+
+ /* only use rigid body transform if simulation is running,
+ * avoids problems with initial setup of rigid bodies */
+ if (BKE_rigidbody_check_sim_running(scene->rigidbody_world, ctime)) {
+
+ /* save original object transform */
+ copy_v3_v3(td->ext->oloc, ob->loc);
+
+ if (ob->rotmode > 0) {
+ copy_v3_v3(td->ext->orot, ob->rot);
+ }
+ else if (ob->rotmode == ROT_MODE_AXISANGLE) {
+ td->ext->orotAngle = ob->rotAngle;
+ copy_v3_v3(td->ext->orotAxis, ob->rotAxis);
+ }
+ else {
+ copy_qt_qt(td->ext->oquat, ob->quat);
+ }
+ /* update object's loc/rot to get current rigid body transform */
+ mat4_to_loc_rot_size(ob->loc, rot, scale, ob->obmat);
+ sub_v3_v3(ob->loc, ob->dloc);
+ BKE_object_mat3_to_rot(ob, rot, false); /* drot is already corrected here */
+ }
+ }
+
+ /* axismtx has the real orientation */
+ copy_m3_m4(td->axismtx, ob->obmat);
+ normalize_m3(td->axismtx);
+
+ td->con = ob->constraints.first;
+
+ /* hack: temporarily disable tracking and/or constraints when getting
+ * object matrix, if tracking is on, or if constraints don't need
+ * inverse correction to stop it from screwing up space conversion
+ * matrix later
+ */
+ constinv = constraints_list_needinv(t, &ob->constraints);
+
+ /* disable constraints inversion for dummy pass */
+ if (t->mode == TFM_DUMMY) {
+ skip_invert = true;
+ }
+
+ /* NOTE: This is not really following copy-on-write design and we should not
+ * be re-evaluating the evaluated object. But as the comment above mentioned
+ * this is part of a hack.
+ * More proper solution would be to make a shallow copy of the object and
+ * evaluate that, and access matrix of that evaluated copy of the object.
+ * Might be more tricky than it sounds, if some logic later on accesses the
+ * object matrix via td->ob->obmat. */
+ Object *object_eval = DEG_get_evaluated_object(t->depsgraph, ob);
+ if (skip_invert == false && constinv == false) {
+ object_eval->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc checks this */
+ /* It is possible to have transform data initialization prior to a
+ * complete dependency graph evaluated. Happens, for example, when
+ * changing transformation mode. */
+ BKE_object_tfm_copy(object_eval, ob);
+ BKE_object_where_is_calc(t->depsgraph, t->scene, object_eval);
+ object_eval->transflag &= ~OB_NO_CONSTRAINTS;
+ }
+ else {
+ BKE_object_where_is_calc(t->depsgraph, t->scene, object_eval);
+ }
+ /* Copy newly evaluated fields to the original object, similar to how
+ * active dependency graph will do it. */
+ copy_m4_m4(ob->obmat, object_eval->obmat);
+ /* Only copy negative scale flag, this is the only flag which is modified by
+ * the BKE_object_where_is_calc(). The rest of the flags we need to keep,
+ * otherwise we might loose dupli flags (see T61787). */
+ ob->transflag &= ~OB_NEG_SCALE;
+ ob->transflag |= (object_eval->transflag & OB_NEG_SCALE);
+
+ td->ob = ob;
+
+ td->loc = ob->loc;
+ copy_v3_v3(td->iloc, td->loc);
+
+ if (ob->rotmode > 0) {
+ td->ext->rot = ob->rot;
+ td->ext->rotAxis = NULL;
+ td->ext->rotAngle = NULL;
+ td->ext->quat = NULL;
+
+ copy_v3_v3(td->ext->irot, ob->rot);
+ copy_v3_v3(td->ext->drot, ob->drot);
+ }
+ else if (ob->rotmode == ROT_MODE_AXISANGLE) {
+ td->ext->rot = NULL;
+ td->ext->rotAxis = ob->rotAxis;
+ td->ext->rotAngle = &ob->rotAngle;
+ td->ext->quat = NULL;
+
+ td->ext->irotAngle = ob->rotAngle;
+ copy_v3_v3(td->ext->irotAxis, ob->rotAxis);
+ // td->ext->drotAngle = ob->drotAngle; // XXX, not implemented
+ // copy_v3_v3(td->ext->drotAxis, ob->drotAxis); // XXX, not implemented
+ }
+ else {
+ td->ext->rot = NULL;
+ td->ext->rotAxis = NULL;
+ td->ext->rotAngle = NULL;
+ td->ext->quat = ob->quat;
+
+ copy_qt_qt(td->ext->iquat, ob->quat);
+ copy_qt_qt(td->ext->dquat, ob->dquat);
+ }
+ td->ext->rotOrder = ob->rotmode;
+
+ td->ext->size = ob->scale;
+ copy_v3_v3(td->ext->isize, ob->scale);
+ copy_v3_v3(td->ext->dscale, ob->dscale);
+
+ copy_v3_v3(td->center, ob->obmat[3]);
+
+ copy_m4_m4(td->ext->obmat, ob->obmat);
+
+ /* is there a need to set the global<->data space conversion matrices? */
+ if (ob->parent || constinv) {
+ float obmtx[3][3], totmat[3][3], obinv[3][3];
+
+ /* Get the effect of parenting, and/or certain constraints.
+ * NOTE: some Constraints, and also Tracking should never get this
+ * done, as it doesn't work well.
+ */
+ BKE_object_to_mat3(ob, obmtx);
+ copy_m3_m4(totmat, ob->obmat);
+ invert_m3_m3(obinv, totmat);
+ mul_m3_m3m3(td->smtx, obmtx, obinv);
+ invert_m3_m3(td->mtx, td->smtx);
+ }
+ else {
+ /* no conversion to/from dataspace */
+ unit_m3(td->smtx);
+ unit_m3(td->mtx);
+ }
+}
+
+static void trans_object_base_deps_flag_prepare(ViewLayer *view_layer)
+{
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ base->object->id.tag &= ~LIB_TAG_DOIT;
+ }
+}
+
+static void set_trans_object_base_deps_flag_cb(ID *id,
+ eDepsObjectComponentType component,
+ void *UNUSED(user_data))
+{
+ /* Here we only handle object IDs. */
+ if (GS(id->name) != ID_OB) {
+ return;
+ }
+ if (!ELEM(component, DEG_OB_COMP_TRANSFORM, DEG_OB_COMP_GEOMETRY)) {
+ return;
+ }
+ id->tag |= LIB_TAG_DOIT;
+}
+
+static void flush_trans_object_base_deps_flag(Depsgraph *depsgraph, Object *object)
+{
+ object->id.tag |= LIB_TAG_DOIT;
+ DEG_foreach_dependent_ID_component(depsgraph,
+ &object->id,
+ DEG_OB_COMP_TRANSFORM,
+ DEG_FOREACH_COMPONENT_IGNORE_TRANSFORM_SOLVERS,
+ set_trans_object_base_deps_flag_cb,
+ NULL);
+}
+
+static void trans_object_base_deps_flag_finish(const TransInfo *t, ViewLayer *view_layer)
+{
+
+ if ((t->options & CTX_OBMODE_XFORM_OBDATA) == 0) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->object->id.tag & LIB_TAG_DOIT) {
+ base->flag_legacy |= BA_SNAP_FIX_DEPS_FIASCO;
+ }
+ }
+ }
+}
+
+/* sets flags in Bases to define whether they take part in transform */
+/* it deselects Bases, so we have to call the clear function always after */
+static void set_trans_object_base_flags(TransInfo *t)
+{
+ Main *bmain = CTX_data_main(t->context);
+ ViewLayer *view_layer = t->view_layer;
+ View3D *v3d = t->view;
+ Scene *scene = t->scene;
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
+ /* NOTE: if Base selected and has parent selected:
+ * base->flag_legacy = BA_WAS_SEL
+ */
+ /* Don't do it if we're not actually going to recalculate anything. */
+ if (t->mode == TFM_DUMMY) {
+ return;
+ }
+ /* Makes sure base flags and object flags are identical. */
+ BKE_scene_base_flag_to_objects(t->view_layer);
+ /* Make sure depsgraph is here. */
+ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
+ /* Clear all flags we need. It will be used to detect dependencies. */
+ trans_object_base_deps_flag_prepare(view_layer);
+ /* Traverse all bases and set all possible flags. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ base->flag_legacy &= ~(BA_WAS_SEL | BA_TRANSFORM_LOCKED_IN_PLACE);
+ if (BASE_SELECTED_EDITABLE(v3d, base)) {
+ Object *ob = base->object;
+ Object *parsel = ob->parent;
+ /* If parent selected, deselect. */
+ while (parsel != NULL) {
+ if (parsel->base_flag & BASE_SELECTED) {
+ Base *parbase = BKE_view_layer_base_find(view_layer, parsel);
+ if (parbase != NULL) { /* in rare cases this can fail */
+ if (BASE_SELECTED_EDITABLE(v3d, parbase)) {
+ break;
+ }
+ }
+ }
+ parsel = parsel->parent;
+ }
+ if (parsel != NULL) {
+ /* Rotation around local centers are allowed to propagate. */
+ if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)) {
+ base->flag_legacy |= BA_TRANSFORM_CHILD;
+ }
+ else {
+ base->flag &= ~BASE_SELECTED;
+ base->flag_legacy |= BA_WAS_SEL;
+ }
+ }
+ flush_trans_object_base_deps_flag(depsgraph, ob);
+ }
+ }
+ /* Store temporary bits in base indicating that base is being modified
+ * (directly or indirectly) by transforming objects.
+ */
+ trans_object_base_deps_flag_finish(t, view_layer);
+}
+
+static bool mark_children(Object *ob)
+{
+ if (ob->flag & (SELECT | BA_TRANSFORM_CHILD)) {
+ return true;
+ }
+
+ if (ob->parent) {
+ if (mark_children(ob->parent)) {
+ ob->flag |= BA_TRANSFORM_CHILD;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int count_proportional_objects(TransInfo *t)
+{
+ int total = 0;
+ ViewLayer *view_layer = t->view_layer;
+ View3D *v3d = t->view;
+ struct Main *bmain = CTX_data_main(t->context);
+ Scene *scene = t->scene;
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
+ /* Clear all flags we need. It will be used to detect dependencies. */
+ trans_object_base_deps_flag_prepare(view_layer);
+ /* Rotations around local centers are allowed to propagate, so we take all objects. */
+ if (!((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL))) {
+ /* Mark all parents. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (BASE_SELECTED_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base)) {
+ Object *parent = base->object->parent;
+ /* flag all parents */
+ while (parent != NULL) {
+ parent->flag |= BA_TRANSFORM_PARENT;
+ parent = parent->parent;
+ }
+ }
+ }
+ /* Mark all children. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ /* all base not already selected or marked that is editable */
+ if ((base->object->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
+ (base->flag & BASE_SELECTED) == 0 &&
+ (BASE_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base))) {
+ mark_children(base->object);
+ }
+ }
+ }
+ /* Flush changed flags to all dependencies. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ Object *ob = base->object;
+ /* If base is not selected, not a parent of selection or not a child of
+ * selection and it is editable and selectable.
+ */
+ if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
+ (base->flag & BASE_SELECTED) == 0 &&
+ (BASE_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base))) {
+ flush_trans_object_base_deps_flag(depsgraph, ob);
+ total += 1;
+ }
+ }
+ /* Store temporary bits in base indicating that base is being modified
+ * (directly or indirectly) by transforming objects.
+ */
+ trans_object_base_deps_flag_finish(t, view_layer);
+ return total;
+}
+
+void clear_trans_object_base_flags(TransInfo *t)
+{
+ ViewLayer *view_layer = t->view_layer;
+ Base *base;
+
+ for (base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->flag_legacy & BA_WAS_SEL) {
+ ED_object_base_select(base, BA_SELECT);
+ }
+
+ base->flag_legacy &= ~(BA_WAS_SEL | BA_SNAP_FIX_DEPS_FIASCO | BA_TEMP_TAG |
+ BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT |
+ BA_TRANSFORM_LOCKED_IN_PLACE);
+ }
+}
+
+void createTransObject(bContext *C, TransInfo *t)
+{
+ TransData *td = NULL;
+ TransDataExtension *tx;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
+ set_trans_object_base_flags(t);
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* count */
+ tc->data_len = CTX_DATA_COUNT(C, selected_bases);
+
+ if (!tc->data_len) {
+ /* clear here, main transform function escapes too */
+ clear_trans_object_base_flags(t);
+ return;
+ }
+
+ if (is_prop_edit) {
+ tc->data_len += count_proportional_objects(t);
+ }
+
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransOb");
+ tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), "TransObExtension");
+
+ TransDataObject *tdo = MEM_callocN(sizeof(*tdo), __func__);
+ t->custom.type.data = tdo;
+ t->custom.type.free_cb = freeTransObjectCustomData;
+
+ CTX_DATA_BEGIN (C, Base *, base, selected_bases) {
+ Object *ob = base->object;
+
+ td->flag = TD_SELECTED;
+ td->protectflag = ob->protectflag;
+ td->ext = tx;
+ td->ext->rotOrder = ob->rotmode;
+
+ if (base->flag & BA_TRANSFORM_CHILD) {
+ td->flag |= TD_NOCENTER;
+ td->flag |= TD_NO_LOC;
+ }
+
+ /* select linked objects, but skip them later */
+ if (ID_IS_LINKED(ob)) {
+ td->flag |= TD_SKIP;
+ }
+
+ if (t->options & CTX_OBMODE_XFORM_OBDATA) {
+ ID *id = ob->data;
+ if (!id || id->lib) {
+ td->flag |= TD_SKIP;
+ }
+ else if (BKE_object_is_in_editmode(ob)) {
+ /* The object could have edit-mode data from another view-layer,
+ * it's such a corner-case it can be skipped for now - Campbell. */
+ td->flag |= TD_SKIP;
+ }
+ }
+
+ if (t->options & CTX_OBMODE_XFORM_OBDATA) {
+ if ((td->flag & TD_SKIP) == 0) {
+ trans_obdata_in_obmode_ensure_object(tdo, ob);
+ }
+ }
+
+ ObjectToTransData(t, td, ob);
+ td->val = NULL;
+ td++;
+ tx++;
+ }
+ CTX_DATA_END;
+
+ if (is_prop_edit) {
+ ViewLayer *view_layer = t->view_layer;
+ View3D *v3d = t->view;
+ Base *base;
+
+ for (base = view_layer->object_bases.first; base; base = base->next) {
+ Object *ob = base->object;
+
+ /* if base is not selected, not a parent of selection
+ * or not a child of selection and it is editable and selectable */
+ if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
+ (base->flag & BASE_SELECTED) == 0 && BASE_EDITABLE(v3d, base) &&
+ BASE_SELECTABLE(v3d, base)) {
+ td->protectflag = ob->protectflag;
+ td->ext = tx;
+ td->ext->rotOrder = ob->rotmode;
+
+ ObjectToTransData(t, td, ob);
+ td->val = NULL;
+ td++;
+ tx++;
+ }
+ }
+ }
+
+ if (t->options & CTX_OBMODE_XFORM_OBDATA) {
+ GSet *objects_in_transdata = BLI_gset_ptr_new_ex(__func__, tc->data_len);
+ td = tc->data;
+ for (int i = 0; i < tc->data_len; i++, td++) {
+ if ((td->flag & TD_SKIP) == 0) {
+ BLI_gset_add(objects_in_transdata, td->ob);
+ }
+ }
+
+ ViewLayer *view_layer = t->view_layer;
+ View3D *v3d = t->view;
+
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ Object *ob = base->object;
+
+ /* if base is not selected, not a parent of selection
+ * or not a child of selection and it is editable and selectable */
+ if ((base->flag_legacy & BA_WAS_SEL) && (base->flag & BASE_SELECTED) == 0 &&
+ BASE_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base)) {
+
+ Object *ob_parent = ob->parent;
+ if (ob_parent != NULL) {
+ if (!BLI_gset_haskey(objects_in_transdata, ob)) {
+ bool parent_in_transdata = false;
+ while (ob_parent != NULL) {
+ if (BLI_gset_haskey(objects_in_transdata, ob_parent)) {
+ parent_in_transdata = true;
+ break;
+ }
+ ob_parent = ob_parent->parent;
+ }
+ if (parent_in_transdata) {
+ trans_obdata_in_obmode_ensure_object(tdo, ob);
+ }
+ }
+ }
+ }
+ }
+ BLI_gset_free(objects_in_transdata, NULL);
+ }
+
+ if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) {
+
+#define BASE_XFORM_INDIRECT(base) \
+ ((base->flag_legacy & BA_WAS_SEL) && (base->flag & BASE_SELECTED) == 0)
+
+ GSet *objects_in_transdata = BLI_gset_ptr_new_ex(__func__, tc->data_len);
+ GHash *objects_parent_root = BLI_ghash_ptr_new_ex(__func__, tc->data_len);
+ td = tc->data;
+ for (int i = 0; i < tc->data_len; i++, td++) {
+ if ((td->flag & TD_SKIP) == 0) {
+ BLI_gset_add(objects_in_transdata, td->ob);
+ }
+ }
+
+ ViewLayer *view_layer = t->view_layer;
+
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ Object *ob = base->object;
+ if (ob->parent != NULL) {
+ if (ob->parent && !BLI_gset_haskey(objects_in_transdata, ob->parent) &&
+ !BLI_gset_haskey(objects_in_transdata, ob)) {
+ if (((base->flag_legacy & BA_WAS_SEL) && (base->flag & BASE_SELECTED) == 0)) {
+ Base *base_parent = BKE_view_layer_base_find(view_layer, ob->parent);
+ if (base_parent && !BASE_XFORM_INDIRECT(base_parent)) {
+ Object *ob_parent_recurse = ob->parent;
+ if (ob_parent_recurse != NULL) {
+ while (ob_parent_recurse != NULL) {
+ if (BLI_gset_haskey(objects_in_transdata, ob_parent_recurse)) {
+ break;
+ }
+ ob_parent_recurse = ob_parent_recurse->parent;
+ }
+
+ if (ob_parent_recurse) {
+ trans_obchild_in_obmode_ensure_object(
+ tdo, ob, ob_parent_recurse, OB_SKIP_CHILD_PARENT_APPLY_TRANSFORM);
+ BLI_ghash_insert(objects_parent_root, ob, ob_parent_recurse);
+ base->flag_legacy |= BA_TRANSFORM_LOCKED_IN_PLACE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ Object *ob = base->object;
+
+ if (BASE_XFORM_INDIRECT(base) || BLI_gset_haskey(objects_in_transdata, ob)) {
+ /* pass. */
+ }
+ else if (ob->parent != NULL) {
+ Base *base_parent = BKE_view_layer_base_find(view_layer, ob->parent);
+ if (base_parent) {
+ if (BASE_XFORM_INDIRECT(base_parent) ||
+ BLI_gset_haskey(objects_in_transdata, ob->parent)) {
+ trans_obchild_in_obmode_ensure_object(tdo, ob, NULL, OB_SKIP_CHILD_PARENT_IS_XFORM);
+ base->flag_legacy |= BA_TRANSFORM_LOCKED_IN_PLACE;
+ }
+ else {
+ Object *ob_parent_recurse = BLI_ghash_lookup(objects_parent_root, ob->parent);
+ if (ob_parent_recurse) {
+ trans_obchild_in_obmode_ensure_object(
+ tdo, ob, ob_parent_recurse, OB_SKIP_CHILD_PARENT_IS_XFORM_INDIRECT);
+ }
+ }
+ }
+ }
+ }
+ BLI_gset_free(objects_in_transdata, NULL);
+ BLI_ghash_free(objects_parent_root, NULL, NULL);
+
+#undef BASE_XFORM_INDIRECT
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Texture Space Transform Creation
+ *
+ * Instead of transforming the selection, move the 2D/3D cursor.
+ *
+ * \{ */
+
+void createTransTexspace(TransInfo *t)
+{
+ ViewLayer *view_layer = t->view_layer;
+ TransData *td;
+ Object *ob;
+ ID *id;
+ short *texflag;
+
+ ob = OBACT(view_layer);
+
+ if (ob == NULL) { // Shouldn't logically happen, but still...
+ return;
+ }
+
+ id = ob->data;
+ if (id == NULL || !ELEM(GS(id->name), ID_ME, ID_CU, ID_MB)) {
+ BKE_report(t->reports, RPT_ERROR, "Unsupported object type for text-space transform");
+ return;
+ }
+
+ if (BKE_object_obdata_is_libdata(ob)) {
+ BKE_report(t->reports, RPT_ERROR, "Linked data can't text-space transform");
+ return;
+ }
+
+ {
+ BLI_assert(t->data_container_len == 1);
+ TransDataContainer *tc = t->data_container;
+ tc->data_len = 1;
+ td = tc->data = MEM_callocN(sizeof(TransData), "TransTexspace");
+ td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
+ }
+
+ td->flag = TD_SELECTED;
+ copy_v3_v3(td->center, ob->obmat[3]);
+ td->ob = ob;
+
+ copy_m3_m4(td->mtx, ob->obmat);
+ copy_m3_m4(td->axismtx, ob->obmat);
+ normalize_m3(td->axismtx);
+ pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
+
+ if (BKE_object_obdata_texspace_get(ob, &texflag, &td->loc, &td->ext->size)) {
+ ob->dtx |= OB_TEXSPACE;
+ *texflag &= ~ME_AUTOSPACE;
+ }
+
+ zero_v3(td->ext->rot);
+
+ copy_v3_v3(td->iloc, td->loc);
+ copy_v3_v3(td->ext->irot, td->ext->rot);
+ copy_v3_v3(td->ext->isize, td->ext->size);
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_paintcurve.c b/source/blender/editors/transform/transform_convert_paintcurve.c
new file mode 100644
index 00000000000..6d46a94214e
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_paintcurve.c
@@ -0,0 +1,227 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_brush_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_paint.h"
+#include "BKE_report.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+typedef struct TransDataPaintCurve {
+ struct PaintCurvePoint *pcp; /* initial curve point */
+ char id;
+} TransDataPaintCurve;
+
+/* -------------------------------------------------------------------- */
+/** \name Paint Curve Transform Creation
+ *
+ * \{ */
+
+#define PC_IS_ANY_SEL(pc) (((pc)->bez.f1 | (pc)->bez.f2 | (pc)->bez.f3) & SELECT)
+
+static void PaintCurveConvertHandle(
+ PaintCurvePoint *pcp, int id, TransData2D *td2d, TransDataPaintCurve *tdpc, TransData *td)
+{
+ BezTriple *bezt = &pcp->bez;
+ copy_v2_v2(td2d->loc, bezt->vec[id]);
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = bezt->vec[id];
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ copy_v3_v3(td->center, bezt->vec[1]);
+ copy_v3_v3(td->iloc, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+
+ tdpc->id = id;
+ tdpc->pcp = pcp;
+}
+
+static void PaintCurvePointToTransData(PaintCurvePoint *pcp,
+ TransData *td,
+ TransData2D *td2d,
+ TransDataPaintCurve *tdpc)
+{
+ BezTriple *bezt = &pcp->bez;
+
+ if (pcp->bez.f2 == SELECT) {
+ int i;
+ for (i = 0; i < 3; i++) {
+ copy_v2_v2(td2d->loc, bezt->vec[i]);
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = bezt->vec[i];
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ copy_v3_v3(td->center, bezt->vec[1]);
+ copy_v3_v3(td->iloc, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+
+ tdpc->id = i;
+ tdpc->pcp = pcp;
+
+ td++;
+ td2d++;
+ tdpc++;
+ }
+ }
+ else {
+ if (bezt->f3 & SELECT) {
+ PaintCurveConvertHandle(pcp, 2, td2d, tdpc, td);
+ td2d++;
+ tdpc++;
+ td++;
+ }
+
+ if (bezt->f1 & SELECT) {
+ PaintCurveConvertHandle(pcp, 0, td2d, tdpc, td);
+ }
+ }
+}
+
+void createTransPaintCurveVerts(bContext *C, TransInfo *t)
+{
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ PaintCurve *pc;
+ PaintCurvePoint *pcp;
+ Brush *br;
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ TransDataPaintCurve *tdpc = NULL;
+ int i;
+ int total = 0;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ tc->data_len = 0;
+
+ if (!paint || !paint->brush || !paint->brush->paint_curve) {
+ return;
+ }
+
+ br = paint->brush;
+ pc = br->paint_curve;
+
+ for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) {
+ if (PC_IS_ANY_SEL(pcp)) {
+ if (pcp->bez.f2 & SELECT) {
+ total += 3;
+ continue;
+ }
+ else {
+ if (pcp->bez.f1 & SELECT) {
+ total++;
+ }
+ if (pcp->bez.f3 & SELECT) {
+ total++;
+ }
+ }
+ }
+ }
+
+ if (!total) {
+ return;
+ }
+
+ tc->data_len = total;
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransData2D");
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData");
+ tc->custom.type.data = tdpc = MEM_callocN(tc->data_len * sizeof(TransDataPaintCurve),
+ "TransDataPaintCurve");
+ tc->custom.type.use_free = true;
+
+ for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) {
+ if (PC_IS_ANY_SEL(pcp)) {
+ PaintCurvePointToTransData(pcp, td, td2d, tdpc);
+
+ if (pcp->bez.f2 & SELECT) {
+ td += 3;
+ td2d += 3;
+ tdpc += 3;
+ }
+ else {
+ if (pcp->bez.f1 & SELECT) {
+ td++;
+ td2d++;
+ tdpc++;
+ }
+ if (pcp->bez.f3 & SELECT) {
+ td++;
+ td2d++;
+ tdpc++;
+ }
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Paint Curve Transform Flush
+ *
+ * \{ */
+
+void flushTransPaintCurve(TransInfo *t)
+{
+ int i;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ TransData2D *td2d = tc->data_2d;
+ TransDataPaintCurve *tdpc = tc->custom.type.data;
+
+ for (i = 0; i < tc->data_len; i++, tdpc++, td2d++) {
+ PaintCurvePoint *pcp = tdpc->pcp;
+ copy_v2_v2(pcp->bez.vec[tdpc->id], td2d->loc);
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_particle.c b/source/blender/editors/transform/transform_convert_particle.c
new file mode 100644
index 00000000000..2a961da018b
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_particle.c
@@ -0,0 +1,248 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_particle_types.h"
+#include "DNA_modifier_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_report.h"
+#include "BKE_particle.h"
+#include "BKE_pointcache.h"
+
+#include "ED_particle.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Particle Edit Transform Creation
+ *
+ * \{ */
+
+void createTransParticleVerts(bContext *C, TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ TransData *td = NULL;
+ TransDataExtension *tx;
+ Object *ob = CTX_data_active_object(C);
+ ParticleEditSettings *pset = PE_settings(t->scene);
+ PTCacheEdit *edit = PE_get_current(t->depsgraph, t->scene, ob);
+ ParticleSystem *psys = NULL;
+ PTCacheEditPoint *point;
+ PTCacheEditKey *key;
+ float mat[4][4];
+ int i, k, transformparticle;
+ int count = 0, hasselected = 0;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
+ if (edit == NULL || t->settings->particle.selectmode == SCE_SELECT_PATH) {
+ return;
+ }
+
+ psys = edit->psys;
+
+ for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) {
+ point->flag &= ~PEP_TRANSFORM;
+ transformparticle = 0;
+
+ if ((point->flag & PEP_HIDE) == 0) {
+ for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
+ if ((key->flag & PEK_HIDE) == 0) {
+ if (key->flag & PEK_SELECT) {
+ hasselected = 1;
+ transformparticle = 1;
+ }
+ else if (is_prop_edit) {
+ transformparticle = 1;
+ }
+ }
+ }
+ }
+
+ if (transformparticle) {
+ count += point->totkey;
+ point->flag |= PEP_TRANSFORM;
+ }
+ }
+
+ /* note: in prop mode we need at least 1 selected */
+ if (hasselected == 0) {
+ return;
+ }
+
+ tc->data_len = count;
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Particle Mode)");
+
+ if (t->mode == TFM_BAKE_TIME) {
+ tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension),
+ "Particle_TransExtension");
+ }
+ else {
+ tx = tc->data_ext = NULL;
+ }
+
+ unit_m4(mat);
+
+ invert_m4_m4(ob->imat, ob->obmat);
+
+ for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) {
+ TransData *head, *tail;
+ head = tail = td;
+
+ if (!(point->flag & PEP_TRANSFORM)) {
+ continue;
+ }
+
+ if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
+ ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
+ psys_mat_hair_to_global(
+ ob, psmd_eval->mesh_final, psys->part->from, psys->particles + i, mat);
+ }
+
+ for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
+ if (key->flag & PEK_USE_WCO) {
+ copy_v3_v3(key->world_co, key->co);
+ mul_m4_v3(mat, key->world_co);
+ td->loc = key->world_co;
+ }
+ else {
+ td->loc = key->co;
+ }
+
+ copy_v3_v3(td->iloc, td->loc);
+ copy_v3_v3(td->center, td->loc);
+
+ if (key->flag & PEK_SELECT) {
+ td->flag |= TD_SELECTED;
+ }
+ else if (!is_prop_edit) {
+ td->flag |= TD_SKIP;
+ }
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+
+ /* don't allow moving roots */
+ if (k == 0 && pset->flag & PE_LOCK_FIRST && (!psys || !(psys->flag & PSYS_GLOBAL_HAIR))) {
+ td->protectflag |= OB_LOCK_LOC;
+ }
+
+ td->ob = ob;
+ td->ext = tx;
+ if (t->mode == TFM_BAKE_TIME) {
+ td->val = key->time;
+ td->ival = *(key->time);
+ /* abuse size and quat for min/max values */
+ td->flag |= TD_NO_EXT;
+ if (k == 0) {
+ tx->size = NULL;
+ }
+ else {
+ tx->size = (key - 1)->time;
+ }
+
+ if (k == point->totkey - 1) {
+ tx->quat = NULL;
+ }
+ else {
+ tx->quat = (key + 1)->time;
+ }
+ }
+
+ td++;
+ if (tx) {
+ tx++;
+ }
+ tail++;
+ }
+ if (is_prop_edit && head != tail) {
+ calc_distanceCurveVerts(head, tail - 1);
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Transform Creation
+ *
+ * \{ */
+
+void flushTransParticles(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Scene *scene = t->scene;
+ ViewLayer *view_layer = t->view_layer;
+ Object *ob = OBACT(view_layer);
+ PTCacheEdit *edit = PE_get_current(t->depsgraph, scene, ob);
+ ParticleSystem *psys = edit->psys;
+ PTCacheEditPoint *point;
+ PTCacheEditKey *key;
+ TransData *td;
+ float mat[4][4], imat[4][4], co[3];
+ int i, k;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
+ /* we do transform in world space, so flush world space position
+ * back to particle local space (only for hair particles) */
+ td = tc->data;
+ for (i = 0, point = edit->points; i < edit->totpoint; i++, point++, td++) {
+ if (!(point->flag & PEP_TRANSFORM)) {
+ continue;
+ }
+
+ if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
+ ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
+ psys_mat_hair_to_global(
+ ob, psmd_eval->mesh_final, psys->part->from, psys->particles + i, mat);
+ invert_m4_m4(imat, mat);
+
+ for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
+ copy_v3_v3(co, key->world_co);
+ mul_m4_v3(imat, co);
+
+ /* optimization for proportional edit */
+ if (!is_prop_edit || !compare_v3v3(key->co, co, 0.0001f)) {
+ copy_v3_v3(key->co, co);
+ point->flag |= PEP_EDIT_RECALC;
+ }
+ }
+ }
+ else {
+ point->flag |= PEP_EDIT_RECALC;
+ }
+ }
+
+ PE_update_object(t->depsgraph, scene, OBACT(view_layer), 1);
+ BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
+ DEG_id_tag_update(&ob->id, ID_RECALC_PSYS_REDO);
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_sculpt.c b/source/blender/editors/transform/transform_convert_sculpt.c
new file mode 100644
index 00000000000..6b584f806b8
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_sculpt.c
@@ -0,0 +1,105 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_paint.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Transform Creation
+ *
+ * \{ */
+
+void createTransSculpt(TransInfo *t)
+{
+ TransData *td;
+
+ Scene *scene = t->scene;
+ if (ID_IS_LINKED(scene)) {
+ BKE_report(t->reports, RPT_ERROR, "Linked data can't text-space transform");
+ return;
+ }
+
+ Object *ob = CTX_data_active_object(t->context);
+ SculptSession *ss = ob->sculpt;
+
+ {
+ BLI_assert(t->data_container_len == 1);
+ TransDataContainer *tc = t->data_container;
+ tc->data_len = 1;
+ tc->is_active = 1;
+ td = tc->data = MEM_callocN(sizeof(TransData), "TransSculpt");
+ td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransSculpt");
+ }
+
+ td->flag = TD_SELECTED;
+ copy_v3_v3(td->center, ss->pivot_pos);
+ mul_m4_v3(ob->obmat, td->center);
+ td->ob = ob;
+
+ td->loc = ss->pivot_pos;
+ copy_v3_v3(td->iloc, ss->pivot_pos);
+
+ if (is_zero_v4(ss->pivot_rot)) {
+ ss->pivot_rot[3] = 1.0f;
+ }
+
+ float obmat_inv[3][3];
+ copy_m3_m4(obmat_inv, ob->obmat);
+ invert_m3(obmat_inv);
+
+ td->ext->rot = NULL;
+ td->ext->rotAxis = NULL;
+ td->ext->rotAngle = NULL;
+ td->ext->quat = ss->pivot_rot;
+ copy_m4_m4(td->ext->obmat, ob->obmat);
+ copy_m3_m3(td->ext->l_smtx, obmat_inv);
+ copy_m3_m4(td->ext->r_mtx, ob->obmat);
+ copy_m3_m3(td->ext->r_smtx, obmat_inv);
+
+ copy_qt_qt(td->ext->iquat, ss->pivot_rot);
+ td->ext->rotOrder = ROT_MODE_QUAT;
+
+ ss->pivot_scale[0] = 1.0f;
+ ss->pivot_scale[1] = 1.0f;
+ ss->pivot_scale[2] = 1.0f;
+ td->ext->size = ss->pivot_scale;
+ copy_v3_v3(ss->init_pivot_scale, ss->pivot_scale);
+ copy_v3_v3(td->ext->isize, ss->init_pivot_scale);
+
+ copy_m3_m3(td->smtx, obmat_inv);
+ copy_m3_m4(td->mtx, ob->obmat);
+ copy_m3_m4(td->axismtx, ob->obmat);
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
new file mode 100644
index 00000000000..86b6ebe3ffa
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -0,0 +1,769 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_sequencer.h"
+#include "BKE_report.h"
+
+#include "UI_view2d.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Sequencer Transform Creation
+ *
+ * \{ */
+
+/* This function applies the rules for transforming a strip so duplicate
+ * checks don't need to be added in multiple places.
+ *
+ * recursive, count and flag MUST be set.
+ *
+ * seq->depth must be set before running this function so we know if the strips
+ * are root level or not
+ */
+static void SeqTransInfo(TransInfo *t, Sequence *seq, int *recursive, int *count, int *flag)
+{
+ /* for extend we need to do some tricks */
+ if (t->mode == TFM_TIME_EXTEND) {
+
+ /* *** Extend Transform *** */
+
+ Scene *scene = t->scene;
+ int cfra = CFRA;
+ int left = BKE_sequence_tx_get_final_left(seq, true);
+ int right = BKE_sequence_tx_get_final_right(seq, true);
+
+ if (seq->depth == 0 && ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK))) {
+ *recursive = false;
+ *count = 0;
+ *flag = 0;
+ }
+ else if (seq->type == SEQ_TYPE_META) {
+
+ /* for meta's we only ever need to extend their children, no matter what depth
+ * just check the meta's are in the bounds */
+ if (t->frame_side == 'R' && right <= cfra) {
+ *recursive = false;
+ }
+ else if (t->frame_side == 'L' && left >= cfra) {
+ *recursive = false;
+ }
+ else {
+ *recursive = true;
+ }
+
+ *count = 1;
+ *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
+ }
+ else {
+
+ *recursive = false; /* not a meta, so no thinking here */
+ *count = 1; /* unless its set to 0, extend will never set 2 handles at once */
+ *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
+
+ if (t->frame_side == 'R') {
+ if (right <= cfra) {
+ *count = *flag = 0;
+ } /* ignore */
+ else if (left > cfra) {
+ } /* keep the selection */
+ else {
+ *flag |= SEQ_RIGHTSEL;
+ }
+ }
+ else {
+ if (left >= cfra) {
+ *count = *flag = 0;
+ } /* ignore */
+ else if (right < cfra) {
+ } /* keep the selection */
+ else {
+ *flag |= SEQ_LEFTSEL;
+ }
+ }
+ }
+ }
+ else {
+
+ t->frame_side = 'B';
+
+ /* *** Normal Transform *** */
+
+ if (seq->depth == 0) {
+
+ /* Count */
+
+ /* Non nested strips (resect selection and handles) */
+ if ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK)) {
+ *recursive = false;
+ *count = 0;
+ *flag = 0;
+ }
+ else {
+ if ((seq->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) == (SEQ_LEFTSEL | SEQ_RIGHTSEL)) {
+ *flag = seq->flag;
+ *count = 2; /* we need 2 transdata's */
+ }
+ else {
+ *flag = seq->flag;
+ *count = 1; /* selected or with a handle selected */
+ }
+
+ /* Recursive */
+
+ if ((seq->type == SEQ_TYPE_META) && ((seq->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) == 0)) {
+ /* if any handles are selected, don't recurse */
+ *recursive = true;
+ }
+ else {
+ *recursive = false;
+ }
+ }
+ }
+ else {
+ /* Nested, different rules apply */
+
+#ifdef SEQ_TX_NESTED_METAS
+ *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
+ *count = 1; /* ignore the selection for nested */
+ *recursive = (seq->type == SEQ_TYPE_META);
+#else
+ if (seq->type == SEQ_TYPE_META) {
+ /* Meta's can only directly be moved between channels since they
+ * don't have their start and length set directly (children affect that)
+ * since this Meta is nested we don't need any of its data in fact.
+ * BKE_sequence_calc() will update its settings when run on the top-level meta. */
+ *flag = 0;
+ *count = 0;
+ *recursive = true;
+ }
+ else {
+ *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
+ *count = 1; /* ignore the selection for nested */
+ *recursive = false;
+ }
+#endif
+ }
+ }
+}
+
+static int SeqTransCount(TransInfo *t, Sequence *parent, ListBase *seqbase, int depth)
+{
+ Sequence *seq;
+ int tot = 0, recursive, count, flag;
+
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ seq->depth = depth;
+
+ /* 'seq->tmp' is used by seq_tx_get_final_{left, right}
+ * to check sequence's range and clamp to it if needed.
+ * It's first place where digging into sequences tree, so store link to parent here. */
+ seq->tmp = parent;
+
+ SeqTransInfo(t, seq, &recursive, &count, &flag); /* ignore the flag */
+ tot += count;
+
+ if (recursive) {
+ tot += SeqTransCount(t, seq, &seq->seqbase, depth + 1);
+ }
+ }
+
+ return tot;
+}
+
+static TransData *SeqToTransData(
+ TransData *td, TransData2D *td2d, TransDataSeq *tdsq, Sequence *seq, int flag, int sel_flag)
+{
+ int start_left;
+
+ switch (sel_flag) {
+ case SELECT:
+ /* Use seq_tx_get_final_left() and an offset here
+ * so transform has the left hand location of the strip.
+ * tdsq->start_offset is used when flushing the tx data back */
+ start_left = BKE_sequence_tx_get_final_left(seq, false);
+ td2d->loc[0] = start_left;
+ tdsq->start_offset = start_left - seq->start; /* use to apply the original location */
+ break;
+ case SEQ_LEFTSEL:
+ start_left = BKE_sequence_tx_get_final_left(seq, false);
+ td2d->loc[0] = start_left;
+ break;
+ case SEQ_RIGHTSEL:
+ td2d->loc[0] = BKE_sequence_tx_get_final_right(seq, false);
+ break;
+ }
+
+ td2d->loc[1] = seq->machine; /* channel - Y location */
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = NULL;
+
+ tdsq->seq = seq;
+
+ /* Use instead of seq->flag for nested strips and other
+ * cases where the selection may need to be modified */
+ tdsq->flag = flag;
+ tdsq->sel_flag = sel_flag;
+
+ td->extra = (void *)tdsq; /* allow us to update the strip from here */
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ copy_v3_v3(td->center, td->loc);
+ copy_v3_v3(td->iloc, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+
+ /* Time Transform (extend) */
+ td->val = td2d->loc;
+ td->ival = td2d->loc[0];
+
+ return td;
+}
+
+static int SeqToTransData_Recursive(
+ TransInfo *t, ListBase *seqbase, TransData *td, TransData2D *td2d, TransDataSeq *tdsq)
+{
+ Sequence *seq;
+ int recursive, count, flag;
+ int tot = 0;
+
+ for (seq = seqbase->first; seq; seq = seq->next) {
+
+ SeqTransInfo(t, seq, &recursive, &count, &flag);
+
+ /* add children first so recalculating metastrips does nested strips first */
+ if (recursive) {
+ int tot_children = SeqToTransData_Recursive(t, &seq->seqbase, td, td2d, tdsq);
+
+ td = td + tot_children;
+ td2d = td2d + tot_children;
+ tdsq = tdsq + tot_children;
+
+ tot += tot_children;
+ }
+
+ /* use 'flag' which is derived from seq->flag but modified for special cases */
+ if (flag & SELECT) {
+ if (flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) {
+ if (flag & SEQ_LEFTSEL) {
+ SeqToTransData(td++, td2d++, tdsq++, seq, flag, SEQ_LEFTSEL);
+ tot++;
+ }
+ if (flag & SEQ_RIGHTSEL) {
+ SeqToTransData(td++, td2d++, tdsq++, seq, flag, SEQ_RIGHTSEL);
+ tot++;
+ }
+ }
+ else {
+ SeqToTransData(td++, td2d++, tdsq++, seq, flag, SELECT);
+ tot++;
+ }
+ }
+ }
+ return tot;
+}
+
+static void SeqTransDataBounds(TransInfo *t, ListBase *seqbase, TransSeq *ts)
+{
+ Sequence *seq;
+ int recursive, count, flag;
+ int max = INT32_MIN, min = INT32_MAX;
+
+ for (seq = seqbase->first; seq; seq = seq->next) {
+
+ /* just to get the flag since there are corner cases where this isn't totally obvious */
+ SeqTransInfo(t, seq, &recursive, &count, &flag);
+
+ /* use 'flag' which is derived from seq->flag but modified for special cases */
+ if (flag & SELECT) {
+ if (flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) {
+ if (flag & SEQ_LEFTSEL) {
+ min = min_ii(seq->startdisp, min);
+ max = max_ii(seq->startdisp, max);
+ }
+ if (flag & SEQ_RIGHTSEL) {
+ min = min_ii(seq->enddisp, min);
+ max = max_ii(seq->enddisp, max);
+ }
+ }
+ else {
+ min = min_ii(seq->startdisp, min);
+ max = max_ii(seq->enddisp, max);
+ }
+ }
+ }
+
+ if (ts) {
+ ts->max = max;
+ ts->min = min;
+ }
+}
+
+static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data)
+{
+ Editing *ed = BKE_sequencer_editing_get(t->scene, false);
+
+ if (ed != NULL) {
+
+ ListBase *seqbasep = ed->seqbasep;
+ TransData *td = tc->data;
+ int a;
+
+ /* prevent updating the same seq twice
+ * if the transdata order is changed this will mess up
+ * but so will TransDataSeq */
+ Sequence *seq_prev = NULL;
+ Sequence *seq;
+
+ if (!(t->state == TRANS_CANCEL)) {
+
+#if 0 // default 2.4 behavior
+
+ /* flush to 2d vector from internally used 3d vector */
+ for (a = 0; a < t->total; a++, td++) {
+ if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) {
+ seq = ((TransDataSeq *)td->extra)->seq;
+ BKE_sequence_base_shuffle(seqbasep, seq, t->scene);
+ }
+
+ seq_prev = seq;
+ }
+
+#else // durian hack
+ {
+ int overlap = 0;
+
+ for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
+ seq = ((TransDataSeq *)td->extra)->seq;
+ if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) {
+ overlap = 1;
+ break;
+ }
+ }
+
+ if (overlap) {
+ bool has_effect_root = false, has_effect_any = false;
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ seq->tmp = NULL;
+ }
+
+ td = tc->data;
+ for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
+ seq = ((TransDataSeq *)td->extra)->seq;
+ if ((seq != seq_prev)) {
+ /* check effects strips, we cant change their time */
+ if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
+ has_effect_any = true;
+ if (seq->depth == 0) {
+ has_effect_root = true;
+ }
+ }
+ else {
+ /* Tag seq with a non zero value, used by
+ * BKE_sequence_base_shuffle_time to identify the ones to shuffle */
+ if (seq->depth == 0) {
+ seq->tmp = (void *)1;
+ }
+ }
+ }
+ }
+
+ if (t->flag & T_ALT_TRANSFORM) {
+ int minframe = MAXFRAME;
+ td = tc->data;
+ for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
+ seq = ((TransDataSeq *)td->extra)->seq;
+ if ((seq != seq_prev) && (seq->depth == 0)) {
+ minframe = min_ii(minframe, seq->startdisp);
+ }
+ }
+
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (!(seq->flag & SELECT)) {
+ if (seq->startdisp >= minframe) {
+ seq->machine += MAXSEQ * 2;
+ }
+ }
+ }
+
+ BKE_sequence_base_shuffle_time(seqbasep, t->scene);
+
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (seq->machine >= MAXSEQ * 2) {
+ seq->machine -= MAXSEQ * 2;
+ seq->tmp = (void *)1;
+ }
+ else {
+ seq->tmp = NULL;
+ }
+ }
+
+ BKE_sequence_base_shuffle_time(seqbasep, t->scene);
+ }
+ else {
+ BKE_sequence_base_shuffle_time(seqbasep, t->scene);
+ }
+
+ if (has_effect_any) {
+ /* update effects strips based on strips just moved in time */
+ td = tc->data;
+ for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
+ seq = ((TransDataSeq *)td->extra)->seq;
+ if ((seq != seq_prev)) {
+ if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
+ BKE_sequence_calc(t->scene, seq);
+ }
+ }
+ }
+ }
+
+ if (has_effect_root) {
+ /* now if any effects _still_ overlap, we need to move them up */
+ td = tc->data;
+ for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
+ seq = ((TransDataSeq *)td->extra)->seq;
+ if ((seq != seq_prev) && (seq->depth == 0)) {
+ if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
+ if (BKE_sequence_test_overlap(seqbasep, seq)) {
+ BKE_sequence_base_shuffle(seqbasep, seq, t->scene);
+ }
+ }
+ }
+ }
+ /* done with effects */
+ }
+ }
+ }
+#endif
+
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ /* We might want to build a list of effects that need to be updated during transform */
+ if (seq->type & SEQ_TYPE_EFFECT) {
+ if (seq->seq1 && seq->seq1->flag & SELECT) {
+ BKE_sequence_calc(t->scene, seq);
+ }
+ else if (seq->seq2 && seq->seq2->flag & SELECT) {
+ BKE_sequence_calc(t->scene, seq);
+ }
+ else if (seq->seq3 && seq->seq3->flag & SELECT) {
+ BKE_sequence_calc(t->scene, seq);
+ }
+ }
+ }
+
+ BKE_sequencer_sort(t->scene);
+ }
+ else {
+ /* Canceled, need to update the strips display */
+ for (a = 0; a < tc->data_len; a++, td++) {
+ seq = ((TransDataSeq *)td->extra)->seq;
+ if ((seq != seq_prev) && (seq->depth == 0)) {
+ if (seq->flag & SEQ_OVERLAP) {
+ BKE_sequence_base_shuffle(seqbasep, seq, t->scene);
+ }
+
+ BKE_sequence_calc_disp(t->scene, seq);
+ }
+ seq_prev = seq;
+ }
+ }
+ }
+
+ if ((custom_data->data != NULL) && custom_data->use_free) {
+ TransSeq *ts = custom_data->data;
+ MEM_freeN(ts->tdseq);
+ MEM_freeN(custom_data->data);
+ custom_data->data = NULL;
+ }
+
+ DEG_id_tag_update(&t->scene->id, ID_RECALC_SEQUENCER_STRIPS);
+}
+
+void createTransSeqData(bContext *C, TransInfo *t)
+{
+#define XXX_DURIAN_ANIM_TX_HACK
+
+ View2D *v2d = UI_view2d_fromcontext(C);
+ Scene *scene = t->scene;
+ Editing *ed = BKE_sequencer_editing_get(t->scene, false);
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ TransDataSeq *tdsq = NULL;
+ TransSeq *ts = NULL;
+ int xmouse;
+
+ int count = 0;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ if (ed == NULL) {
+ tc->data_len = 0;
+ return;
+ }
+
+ tc->custom.type.free_cb = freeSeqData;
+
+ xmouse = (int)UI_view2d_region_to_view_x(v2d, t->mouse.imval[0]);
+
+ /* which side of the current frame should be allowed */
+ if (t->mode == TFM_TIME_EXTEND) {
+ /* only side on which mouse is gets transformed */
+ t->frame_side = (xmouse > CFRA) ? 'R' : 'L';
+ }
+ else {
+ /* normal transform - both sides of current frame are considered */
+ t->frame_side = 'B';
+ }
+
+#ifdef XXX_DURIAN_ANIM_TX_HACK
+ {
+ Sequence *seq;
+ for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ /* hack */
+ if ((seq->flag & SELECT) == 0 && seq->type & SEQ_TYPE_EFFECT) {
+ Sequence *seq_user;
+ int i;
+ for (i = 0; i < 3; i++) {
+ seq_user = *((&seq->seq1) + i);
+ if (seq_user && (seq_user->flag & SELECT) && !(seq_user->flag & SEQ_LOCK) &&
+ !(seq_user->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL))) {
+ seq->flag |= SELECT;
+ }
+ }
+ }
+ }
+ }
+#endif
+
+ count = SeqTransCount(t, NULL, ed->seqbasep, 0);
+
+ /* allocate memory for data */
+ tc->data_len = count;
+
+ /* stop if trying to build list if nothing selected */
+ if (count == 0) {
+ return;
+ }
+
+ tc->custom.type.data = ts = MEM_callocN(sizeof(TransSeq), "transseq");
+ tc->custom.type.use_free = true;
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransSeq TransData");
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransSeq TransData2D");
+ ts->tdseq = tdsq = MEM_callocN(tc->data_len * sizeof(TransDataSeq), "TransSeq TransDataSeq");
+
+ /* loop 2: build transdata array */
+ SeqToTransData_Recursive(t, ed->seqbasep, td, td2d, tdsq);
+ SeqTransDataBounds(t, ed->seqbasep, ts);
+
+ /* set the snap mode based on how close the mouse is at the end/start points */
+ if (abs(xmouse - ts->max) > abs(xmouse - ts->min)) {
+ ts->snap_left = true;
+ }
+
+#undef XXX_DURIAN_ANIM_TX_HACK
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UVs Transform Flush
+ *
+ * \{ */
+
+/* commented _only_ because the meta may have animation data which
+ * needs moving too [#28158] */
+
+#define SEQ_TX_NESTED_METAS
+
+BLI_INLINE void trans_update_seq(Scene *sce, Sequence *seq, int old_start, int sel_flag)
+{
+ if (seq->depth == 0) {
+ /* Calculate this strip and all nested strips.
+ * Children are ALWAYS transformed first so we don't need to do this in another loop.
+ */
+ BKE_sequence_calc(sce, seq);
+ }
+ else {
+ BKE_sequence_calc_disp(sce, seq);
+ }
+
+ if (sel_flag == SELECT) {
+ BKE_sequencer_offset_animdata(sce, seq, seq->start - old_start);
+ }
+}
+
+void flushTransSeq(TransInfo *t)
+{
+ /* Editing null check already done */
+ ListBase *seqbasep = BKE_sequencer_editing_get(t->scene, false)->seqbasep;
+
+ int a, new_frame;
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ TransDataSeq *tdsq = NULL;
+ Sequence *seq;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* prevent updating the same seq twice
+ * if the transdata order is changed this will mess up
+ * but so will TransDataSeq */
+ Sequence *seq_prev = NULL;
+ int old_start_prev = 0, sel_flag_prev = 0;
+
+ /* flush to 2d vector from internally used 3d vector */
+ for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
+ int old_start;
+ tdsq = (TransDataSeq *)td->extra;
+ seq = tdsq->seq;
+ old_start = seq->start;
+ new_frame = round_fl_to_int(td2d->loc[0]);
+
+ switch (tdsq->sel_flag) {
+ case SELECT:
+#ifdef SEQ_TX_NESTED_METAS
+ if ((seq->depth != 0 || BKE_sequence_tx_test(seq))) {
+ /* for meta's, their children move */
+ seq->start = new_frame - tdsq->start_offset;
+ }
+#else
+ if (seq->type != SEQ_TYPE_META && (seq->depth != 0 || seq_tx_test(seq))) {
+ /* for meta's, their children move */
+ seq->start = new_frame - tdsq->start_offset;
+ }
+#endif
+ if (seq->depth == 0) {
+ seq->machine = round_fl_to_int(td2d->loc[1]);
+ CLAMP(seq->machine, 1, MAXSEQ);
+ }
+ break;
+ case SEQ_LEFTSEL: /* no vertical transform */
+ BKE_sequence_tx_set_final_left(seq, new_frame);
+ BKE_sequence_tx_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL);
+
+ /* todo - move this into aftertrans update? - old seq tx needed it anyway */
+ BKE_sequence_single_fix(seq);
+ break;
+ case SEQ_RIGHTSEL: /* no vertical transform */
+ BKE_sequence_tx_set_final_right(seq, new_frame);
+ BKE_sequence_tx_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL);
+
+ /* todo - move this into aftertrans update? - old seq tx needed it anyway */
+ BKE_sequence_single_fix(seq);
+ break;
+ }
+
+ /* Update *previous* seq! Else, we would update a seq after its first transform,
+ * and if it has more than one (like e.g. SEQ_LEFTSEL and SEQ_RIGHTSEL),
+ * the others are not updated! See T38469.
+ */
+ if (seq != seq_prev) {
+ if (seq_prev) {
+ trans_update_seq(t->scene, seq_prev, old_start_prev, sel_flag_prev);
+ }
+
+ seq_prev = seq;
+ old_start_prev = old_start;
+ sel_flag_prev = tdsq->sel_flag;
+ }
+ else {
+ /* We want to accumulate *all* sel_flags for this seq! */
+ sel_flag_prev |= tdsq->sel_flag;
+ }
+ }
+
+ /* Don't forget to update the last seq! */
+ if (seq_prev) {
+ trans_update_seq(t->scene, seq_prev, old_start_prev, sel_flag_prev);
+ }
+
+ /* originally TFM_TIME_EXTEND, transform changes */
+ if (ELEM(t->mode, TFM_SEQ_SLIDE, TFM_TIME_TRANSLATE)) {
+ /* Special annoying case here, need to calc metas with TFM_TIME_EXTEND only */
+
+ /* calc all meta's then effects [#27953] */
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (seq->type == SEQ_TYPE_META && seq->flag & SELECT) {
+ BKE_sequence_calc(t->scene, seq);
+ }
+ }
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (seq->seq1 || seq->seq2 || seq->seq3) {
+ BKE_sequence_calc(t->scene, seq);
+ }
+ }
+
+ /* update effects inside meta's */
+ for (a = 0, seq_prev = NULL, td = tc->data, td2d = tc->data_2d; a < tc->data_len;
+ a++, td++, td2d++, seq_prev = seq) {
+ tdsq = (TransDataSeq *)td->extra;
+ seq = tdsq->seq;
+ if ((seq != seq_prev) && (seq->depth != 0)) {
+ if (seq->seq1 || seq->seq2 || seq->seq3) {
+ BKE_sequence_calc(t->scene, seq);
+ }
+ }
+ }
+ }
+
+ /* need to do the overlap check in a new loop otherwise adjacent strips
+ * will not be updated and we'll get false positives */
+ seq_prev = NULL;
+ for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
+
+ tdsq = (TransDataSeq *)td->extra;
+ seq = tdsq->seq;
+
+ if (seq != seq_prev) {
+ if (seq->depth == 0) {
+ /* test overlap, displays red outline */
+ seq->flag &= ~SEQ_OVERLAP;
+ if (BKE_sequence_test_overlap(seqbasep, seq)) {
+ seq->flag |= SEQ_OVERLAP;
+ }
+ }
+ }
+ seq_prev = seq;
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c
new file mode 100644
index 00000000000..b68b79adbd8
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_tracking.c
@@ -0,0 +1,692 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_movieclip.h"
+#include "BKE_report.h"
+#include "BKE_tracking.h"
+
+#include "ED_clip.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+typedef struct TransDataTracking {
+ int mode, flag;
+
+ /* tracks transformation from main window */
+ int area;
+ const float *relative, *loc;
+ float soffset[2], srelative[2];
+ float offset[2];
+
+ float (*smarkers)[2];
+ int markersnr;
+ MovieTrackingMarker *markers;
+
+ /* marker transformation from curves editor */
+ float *prev_pos, scale;
+ short coord;
+
+ MovieTrackingTrack *track;
+ MovieTrackingPlaneTrack *plane_track;
+} TransDataTracking;
+
+enum transDataTracking_Mode {
+ transDataTracking_ModeTracks = 0,
+ transDataTracking_ModeCurves = 1,
+ transDataTracking_ModePlaneTracks = 2,
+};
+
+/* -------------------------------------------------------------------- */
+/** \name Clip Editor Motion Tracking Transform Creation
+ *
+ * \{ */
+
+static void markerToTransDataInit(TransData *td,
+ TransData2D *td2d,
+ TransDataTracking *tdt,
+ MovieTrackingTrack *track,
+ MovieTrackingMarker *marker,
+ int area,
+ float loc[2],
+ const float rel[2],
+ const float off[2],
+ const float aspect[2])
+{
+ int anchor = area == TRACK_AREA_POINT && off;
+
+ tdt->mode = transDataTracking_ModeTracks;
+
+ if (anchor) {
+ td2d->loc[0] = rel[0] * aspect[0]; /* hold original location */
+ td2d->loc[1] = rel[1] * aspect[1];
+
+ tdt->loc = loc;
+ td2d->loc2d = loc; /* current location */
+ }
+ else {
+ td2d->loc[0] = loc[0] * aspect[0]; /* hold original location */
+ td2d->loc[1] = loc[1] * aspect[1];
+
+ td2d->loc2d = loc; /* current location */
+ }
+ td2d->loc[2] = 0.0f;
+
+ tdt->relative = rel;
+ tdt->area = area;
+
+ tdt->markersnr = track->markersnr;
+ tdt->markers = track->markers;
+ tdt->track = track;
+
+ if (rel) {
+ if (!anchor) {
+ td2d->loc[0] += rel[0] * aspect[0];
+ td2d->loc[1] += rel[1] * aspect[1];
+ }
+
+ copy_v2_v2(tdt->srelative, rel);
+ }
+
+ if (off) {
+ copy_v2_v2(tdt->soffset, off);
+ }
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ copy_v3_v3(td->iloc, td->loc);
+
+ // copy_v3_v3(td->center, td->loc);
+ td->flag |= TD_INDIVIDUAL_SCALE;
+ td->center[0] = marker->pos[0] * aspect[0];
+ td->center[1] = marker->pos[1] * aspect[1];
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+}
+
+static void trackToTransData(const int framenr,
+ TransData *td,
+ TransData2D *td2d,
+ TransDataTracking *tdt,
+ MovieTrackingTrack *track,
+ const float aspect[2])
+{
+ MovieTrackingMarker *marker = BKE_tracking_marker_ensure(track, framenr);
+
+ tdt->flag = marker->flag;
+ marker->flag &= ~(MARKER_DISABLED | MARKER_TRACKED);
+
+ markerToTransDataInit(td++,
+ td2d++,
+ tdt++,
+ track,
+ marker,
+ TRACK_AREA_POINT,
+ track->offset,
+ marker->pos,
+ track->offset,
+ aspect);
+
+ if (track->flag & SELECT) {
+ markerToTransDataInit(
+ td++, td2d++, tdt++, track, marker, TRACK_AREA_POINT, marker->pos, NULL, NULL, aspect);
+ }
+
+ if (track->pat_flag & SELECT) {
+ int a;
+
+ for (a = 0; a < 4; a++) {
+ markerToTransDataInit(td++,
+ td2d++,
+ tdt++,
+ track,
+ marker,
+ TRACK_AREA_PAT,
+ marker->pattern_corners[a],
+ marker->pos,
+ NULL,
+ aspect);
+ }
+ }
+
+ if (track->search_flag & SELECT) {
+ markerToTransDataInit(td++,
+ td2d++,
+ tdt++,
+ track,
+ marker,
+ TRACK_AREA_SEARCH,
+ marker->search_min,
+ marker->pos,
+ NULL,
+ aspect);
+
+ markerToTransDataInit(td++,
+ td2d++,
+ tdt++,
+ track,
+ marker,
+ TRACK_AREA_SEARCH,
+ marker->search_max,
+ marker->pos,
+ NULL,
+ aspect);
+ }
+}
+
+static void planeMarkerToTransDataInit(TransData *td,
+ TransData2D *td2d,
+ TransDataTracking *tdt,
+ MovieTrackingPlaneTrack *plane_track,
+ float corner[2],
+ const float aspect[2])
+{
+ tdt->mode = transDataTracking_ModePlaneTracks;
+ tdt->plane_track = plane_track;
+
+ td2d->loc[0] = corner[0] * aspect[0]; /* hold original location */
+ td2d->loc[1] = corner[1] * aspect[1];
+
+ td2d->loc2d = corner; /* current location */
+ td2d->loc[2] = 0.0f;
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ copy_v3_v3(td->iloc, td->loc);
+ copy_v3_v3(td->center, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+}
+
+static void planeTrackToTransData(const int framenr,
+ TransData *td,
+ TransData2D *td2d,
+ TransDataTracking *tdt,
+ MovieTrackingPlaneTrack *plane_track,
+ const float aspect[2])
+{
+ MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr);
+ int i;
+
+ tdt->flag = plane_marker->flag;
+ plane_marker->flag &= ~PLANE_MARKER_TRACKED;
+
+ for (i = 0; i < 4; i++) {
+ planeMarkerToTransDataInit(td++, td2d++, tdt++, plane_track, plane_marker->corners[i], aspect);
+ }
+}
+
+static void transDataTrackingFree(TransInfo *UNUSED(t),
+ TransDataContainer *UNUSED(tc),
+ TransCustomData *custom_data)
+{
+ if (custom_data->data) {
+ TransDataTracking *tdt = custom_data->data;
+ if (tdt->smarkers) {
+ MEM_freeN(tdt->smarkers);
+ }
+
+ MEM_freeN(tdt);
+ custom_data->data = NULL;
+ }
+}
+
+static void createTransTrackingTracksData(bContext *C, TransInfo *t)
+{
+ TransData *td;
+ TransData2D *td2d;
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
+ MovieTrackingTrack *track;
+ MovieTrackingPlaneTrack *plane_track;
+ TransDataTracking *tdt;
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* count */
+ tc->data_len = 0;
+
+ track = tracksbase->first;
+ while (track) {
+ if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
+ tc->data_len++; /* offset */
+
+ if (track->flag & SELECT) {
+ tc->data_len++;
+ }
+
+ if (track->pat_flag & SELECT) {
+ tc->data_len += 4;
+ }
+
+ if (track->search_flag & SELECT) {
+ tc->data_len += 2;
+ }
+ }
+
+ track = track->next;
+ }
+
+ for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
+ if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
+ tc->data_len += 4;
+ }
+ }
+
+ if (tc->data_len == 0) {
+ return;
+ }
+
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransTracking TransData");
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D),
+ "TransTracking TransData2D");
+ tdt = tc->custom.type.data = MEM_callocN(tc->data_len * sizeof(TransDataTracking),
+ "TransTracking TransDataTracking");
+
+ tc->custom.type.free_cb = transDataTrackingFree;
+
+ /* create actual data */
+ track = tracksbase->first;
+ while (track) {
+ if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
+ trackToTransData(framenr, td, td2d, tdt, track, t->aspect);
+
+ /* offset */
+ td++;
+ td2d++;
+ tdt++;
+
+ if (track->flag & SELECT) {
+ td++;
+ td2d++;
+ tdt++;
+ }
+
+ if (track->pat_flag & SELECT) {
+ td += 4;
+ td2d += 4;
+ tdt += 4;
+ }
+
+ if (track->search_flag & SELECT) {
+ td += 2;
+ td2d += 2;
+ tdt += 2;
+ }
+ }
+
+ track = track->next;
+ }
+
+ for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
+ if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
+ planeTrackToTransData(framenr, td, td2d, tdt, plane_track, t->aspect);
+ td += 4;
+ td2d += 4;
+ tdt += 4;
+ }
+ }
+}
+
+static void markerToTransCurveDataInit(TransData *td,
+ TransData2D *td2d,
+ TransDataTracking *tdt,
+ MovieTrackingTrack *track,
+ MovieTrackingMarker *marker,
+ MovieTrackingMarker *prev_marker,
+ short coord,
+ float size)
+{
+ float frames_delta = (marker->framenr - prev_marker->framenr);
+
+ tdt->flag = marker->flag;
+ marker->flag &= ~MARKER_TRACKED;
+
+ tdt->mode = transDataTracking_ModeCurves;
+ tdt->coord = coord;
+ tdt->scale = 1.0f / size * frames_delta;
+ tdt->prev_pos = prev_marker->pos;
+ tdt->track = track;
+
+ /* calculate values depending on marker's speed */
+ td2d->loc[0] = marker->framenr;
+ td2d->loc[1] = (marker->pos[coord] - prev_marker->pos[coord]) * size / frames_delta;
+ td2d->loc[2] = 0.0f;
+
+ td2d->loc2d = marker->pos; /* current location */
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ copy_v3_v3(td->center, td->loc);
+ copy_v3_v3(td->iloc, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+}
+
+static void createTransTrackingCurvesData(bContext *C, TransInfo *t)
+{
+ TransData *td;
+ TransData2D *td2d;
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ MovieTrackingTrack *track;
+ MovieTrackingMarker *marker, *prev_marker;
+ TransDataTracking *tdt;
+ int i, width, height;
+
+ BKE_movieclip_get_size(clip, &sc->user, &width, &height);
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* count */
+ tc->data_len = 0;
+
+ if ((sc->flag & SC_SHOW_GRAPH_TRACKS_MOTION) == 0) {
+ return;
+ }
+
+ track = tracksbase->first;
+ while (track) {
+ if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
+ for (i = 1; i < track->markersnr; i++) {
+ marker = &track->markers[i];
+ prev_marker = &track->markers[i - 1];
+
+ if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) {
+ continue;
+ }
+
+ if (marker->flag & MARKER_GRAPH_SEL_X) {
+ tc->data_len += 1;
+ }
+
+ if (marker->flag & MARKER_GRAPH_SEL_Y) {
+ tc->data_len += 1;
+ }
+ }
+ }
+
+ track = track->next;
+ }
+
+ if (tc->data_len == 0) {
+ return;
+ }
+
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransTracking TransData");
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D),
+ "TransTracking TransData2D");
+ tc->custom.type.data = tdt = MEM_callocN(tc->data_len * sizeof(TransDataTracking),
+ "TransTracking TransDataTracking");
+ tc->custom.type.free_cb = transDataTrackingFree;
+
+ /* create actual data */
+ track = tracksbase->first;
+ while (track) {
+ if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
+ for (i = 1; i < track->markersnr; i++) {
+ marker = &track->markers[i];
+ prev_marker = &track->markers[i - 1];
+
+ if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) {
+ continue;
+ }
+
+ if (marker->flag & MARKER_GRAPH_SEL_X) {
+ markerToTransCurveDataInit(
+ td, td2d, tdt, track, marker, &track->markers[i - 1], 0, width);
+ td += 1;
+ td2d += 1;
+ tdt += 1;
+ }
+
+ if (marker->flag & MARKER_GRAPH_SEL_Y) {
+ markerToTransCurveDataInit(
+ td, td2d, tdt, track, marker, &track->markers[i - 1], 1, height);
+
+ td += 1;
+ td2d += 1;
+ tdt += 1;
+ }
+ }
+ }
+
+ track = track->next;
+ }
+}
+
+void createTransTrackingData(bContext *C, TransInfo *t)
+{
+ ARegion *ar = CTX_wm_region(C);
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ int width, height;
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ tc->data_len = 0;
+
+ if (!clip) {
+ return;
+ }
+
+ BKE_movieclip_get_size(clip, &sc->user, &width, &height);
+
+ if (width == 0 || height == 0) {
+ return;
+ }
+
+ if (ar->regiontype == RGN_TYPE_PREVIEW) {
+ /* transformation was called from graph editor */
+ createTransTrackingCurvesData(C, t);
+ }
+ else {
+ createTransTrackingTracksData(C, t);
+ }
+}
+
+void cancelTransTracking(TransInfo *t)
+{
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+ SpaceClip *sc = t->sa->spacedata.first;
+ int i, framenr = ED_space_clip_get_clip_frame_number(sc);
+ TransDataTracking *tdt_array = tc->custom.type.data;
+
+ i = 0;
+ while (i < tc->data_len) {
+ TransDataTracking *tdt = &tdt_array[i];
+
+ if (tdt->mode == transDataTracking_ModeTracks) {
+ MovieTrackingTrack *track = tdt->track;
+ MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
+
+ marker->flag = tdt->flag;
+
+ if (track->flag & SELECT) {
+ i++;
+ }
+
+ if (track->pat_flag & SELECT) {
+ i += 4;
+ }
+
+ if (track->search_flag & SELECT) {
+ i += 2;
+ }
+ }
+ else if (tdt->mode == transDataTracking_ModeCurves) {
+ MovieTrackingTrack *track = tdt->track;
+ MovieTrackingMarker *marker, *prev_marker;
+ int a;
+
+ for (a = 1; a < track->markersnr; a++) {
+ marker = &track->markers[a];
+ prev_marker = &track->markers[a - 1];
+
+ if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) {
+ continue;
+ }
+
+ if (marker->flag & (MARKER_GRAPH_SEL_X | MARKER_GRAPH_SEL_Y)) {
+ marker->flag = tdt->flag;
+ }
+ }
+ }
+ else if (tdt->mode == transDataTracking_ModePlaneTracks) {
+ MovieTrackingPlaneTrack *plane_track = tdt->plane_track;
+ MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr);
+
+ plane_marker->flag = tdt->flag;
+ i += 3;
+ }
+
+ i++;
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clip Editor Motion Tracking Transform Creation
+ *
+ * \{ */
+
+void flushTransTracking(TransInfo *t)
+{
+ TransData *td;
+ TransData2D *td2d;
+ TransDataTracking *tdt;
+ int a;
+
+ if (t->state == TRANS_CANCEL) {
+ cancelTransTracking(t);
+ }
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ /* flush to 2d vector from internally used 3d vector */
+ for (a = 0, td = tc->data, td2d = tc->data_2d, tdt = tc->custom.type.data; a < tc->data_len;
+ a++, td2d++, td++, tdt++) {
+ if (tdt->mode == transDataTracking_ModeTracks) {
+ float loc2d[2];
+
+ if (t->mode == TFM_ROTATION && tdt->area == TRACK_AREA_SEARCH) {
+ continue;
+ }
+
+ loc2d[0] = td2d->loc[0] / t->aspect[0];
+ loc2d[1] = td2d->loc[1] / t->aspect[1];
+
+ if (t->flag & T_ALT_TRANSFORM) {
+ if (t->mode == TFM_RESIZE) {
+ if (tdt->area != TRACK_AREA_PAT) {
+ continue;
+ }
+ }
+ else if (t->mode == TFM_TRANSLATION) {
+ if (tdt->area == TRACK_AREA_POINT && tdt->relative) {
+ float d[2], d2[2];
+
+ if (!tdt->smarkers) {
+ tdt->smarkers = MEM_callocN(sizeof(*tdt->smarkers) * tdt->markersnr,
+ "flushTransTracking markers");
+ for (a = 0; a < tdt->markersnr; a++) {
+ copy_v2_v2(tdt->smarkers[a], tdt->markers[a].pos);
+ }
+ }
+
+ sub_v2_v2v2(d, loc2d, tdt->soffset);
+ sub_v2_v2(d, tdt->srelative);
+
+ sub_v2_v2v2(d2, loc2d, tdt->srelative);
+
+ for (a = 0; a < tdt->markersnr; a++) {
+ add_v2_v2v2(tdt->markers[a].pos, tdt->smarkers[a], d2);
+ }
+
+ negate_v2_v2(td2d->loc2d, d);
+ }
+ }
+ }
+
+ if (tdt->area != TRACK_AREA_POINT || tdt->relative == NULL) {
+ td2d->loc2d[0] = loc2d[0];
+ td2d->loc2d[1] = loc2d[1];
+
+ if (tdt->relative) {
+ sub_v2_v2(td2d->loc2d, tdt->relative);
+ }
+ }
+ }
+ else if (tdt->mode == transDataTracking_ModeCurves) {
+ td2d->loc2d[tdt->coord] = tdt->prev_pos[tdt->coord] + td2d->loc[1] * tdt->scale;
+ }
+ else if (tdt->mode == transDataTracking_ModePlaneTracks) {
+ td2d->loc2d[0] = td2d->loc[0] / t->aspect[0];
+ td2d->loc2d[1] = td2d->loc[1] / t->aspect[1];
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 41eb5f1e812..53e36f86a64 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -99,6 +99,7 @@
#include "ED_clip.h"
#include "ED_screen.h"
#include "ED_gpencil.h"
+#include "ED_sculpt.h"
#include "WM_types.h"
#include "WM_api.h"
@@ -109,6 +110,7 @@
#include "UI_view2d.h"
#include "transform.h"
+#include "transform_convert.h"
/* ************************** Functions *************************** */
@@ -222,35 +224,31 @@ static void clipMirrorModifier(TransInfo *t)
}
/* assumes obedit set to mesh object */
-static void editbmesh_apply_to_mirror(TransInfo *t)
+static void transform_apply_to_mirror(TransInfo *t)
{
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- if (tc->mirror.axis_flag) {
- TransData *td = tc->data;
- BMVert *eve;
+ if (tc->mirror.use_mirror_any) {
int i;
-
- for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
- if (td->loc == NULL) {
- break;
- }
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- eve = td->extra;
- if (eve) {
- eve->co[0] = -td->loc[0];
- eve->co[1] = td->loc[1];
- eve->co[2] = td->loc[2];
+ TransData *td;
+ for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
+ if (td->flag & (TD_MIRROR_EDGE_X | TD_MIRROR_EDGE_Y | TD_MIRROR_EDGE_Z)) {
+ if (td->flag & TD_MIRROR_EDGE_X) {
+ td->loc[0] = 0.0f;
+ }
+ if (td->flag & TD_MIRROR_EDGE_Y) {
+ td->loc[1] = 0.0f;
+ }
+ if (td->flag & TD_MIRROR_EDGE_Z) {
+ td->loc[2] = 0.0f;
+ }
}
+ }
- if (td->flag & TD_MIRROR_EDGE) {
- td->loc[0] = 0;
- }
+ TransDataMirror *tdm;
+ for (i = 0, tdm = tc->mirror.data; i < tc->mirror.data_len; i++, tdm++) {
+ tdm->loc_dst[0] = tdm->loc_src[0] * tdm->sign_x;
+ tdm->loc_dst[1] = tdm->loc_src[1] * tdm->sign_y;
+ tdm->loc_dst[2] = tdm->loc_src[2] * tdm->sign_z;
}
}
}
@@ -887,7 +885,7 @@ static void recalcData_objects(TransInfo *t)
clipMirrorModifier(t);
}
if ((t->flag & T_NO_MIRROR) == 0 && (t->options & CTX_NO_MIRROR) == 0) {
- editbmesh_apply_to_mirror(t);
+ transform_apply_to_mirror(t);
}
if (t->mode == TFM_EDGE_SLIDE) {
@@ -1090,12 +1088,12 @@ static void recalcData_objects(TransInfo *t)
GSetIterator gs_iter;
GSET_ITER (gs_iter, motionpath_updates) {
Object *ob = BLI_gsetIterator_getKey(&gs_iter);
- ED_pose_recalculate_paths(t->context, t->scene, ob, true);
+ ED_pose_recalculate_paths(t->context, t->scene, ob, POSE_PATH_CALC_RANGE_CURRENT_FRAME);
}
BLI_gset_free(motionpath_updates, NULL);
}
else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) &&
- PE_get_current(t->scene, base->object)) {
+ PE_get_current(t->depsgraph, t->scene, base->object)) {
if (t->state != TRANS_CANCEL) {
applyProject(t);
}
@@ -1148,10 +1146,14 @@ static void recalcData_objects(TransInfo *t)
if (motionpath_update) {
/* Update motion paths once for all transformed objects. */
- ED_objects_recalculate_paths(t->context, t->scene, true);
+ ED_objects_recalculate_paths(t->context, t->scene, OBJECT_PATH_CALC_RANGE_CHANGED);
+ }
+
+ if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) {
+ trans_obchild_in_obmode_update_all(t);
}
- if (t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) {
+ if (t->options & CTX_OBMODE_XFORM_OBDATA) {
trans_obdata_in_obmode_update_all(t);
}
}
@@ -1201,6 +1203,11 @@ static void recalcData_gpencil_strokes(TransInfo *t)
}
}
+static void recalcData_sculpt(TransInfo *t)
+{
+ ED_sculpt_update_modal_transform(t->context);
+}
+
/* called for updating while transform acts, once per redraw */
void recalcData(TransInfo *t)
{
@@ -1221,6 +1228,9 @@ void recalcData(TransInfo *t)
/* set recalc triangle cache flag */
recalcData_gpencil_strokes(t);
}
+ else if (t->options & CTX_SCULPT) {
+ recalcData_sculpt(t);
+ }
else if (t->spacetype == SPACE_IMAGE) {
recalcData_image(t);
}
@@ -1347,11 +1357,12 @@ void initTransDataContainers_FromObjectData(TransInfo *t,
for (int i = 0; i < objects_len; i++) {
TransDataContainer *tc = &t->data_container[i];
- /* TODO, multiple axes. */
- tc->mirror.axis_flag = (((t->flag & T_NO_MIRROR) == 0) &&
- ((t->options & CTX_NO_MIRROR) == 0) &&
- (objects[i]->type == OB_MESH) &&
- (((Mesh *)objects[i]->data)->editflag & ME_EDIT_MIRROR_X) != 0);
+ if (((t->flag & T_NO_MIRROR) == 0) && ((t->options & CTX_NO_MIRROR) == 0) &&
+ (objects[i]->type == OB_MESH)) {
+ tc->mirror.axis_x = (((Mesh *)objects[i]->data)->editflag & ME_EDIT_MIRROR_X) != 0;
+ tc->mirror.axis_y = (((Mesh *)objects[i]->data)->editflag & ME_EDIT_MIRROR_Y) != 0;
+ tc->mirror.axis_z = (((Mesh *)objects[i]->data)->editflag & ME_EDIT_MIRROR_Z) != 0;
+ }
if (object_mode & OB_MODE_EDIT) {
tc->obedit = objects[i];
@@ -1888,6 +1899,7 @@ void postTrans(bContext *C, TransInfo *t)
MEM_SAFE_FREE(tc->data_ext);
MEM_SAFE_FREE(tc->data_2d);
+ MEM_SAFE_FREE(tc->mirror.data);
}
}
@@ -1923,10 +1935,6 @@ void postTrans(bContext *C, TransInfo *t)
BLI_rng_free(t->rng);
}
- if (t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) {
- trans_obdata_in_obmode_free_all(t);
- }
-
freeSnapping(t);
}
@@ -2339,11 +2347,6 @@ void calculatePropRatio(TransInfo *t)
if (td->flag & TD_SELECTED) {
td->factor = 1.0f;
}
- else if (tc->mirror.axis_flag && (td->loc[0] * tc->mirror.sign) < -0.00001f) {
- td->flag |= TD_SKIP;
- td->factor = 0.0f;
- restoreElement(td);
- }
else if ((connected && (td->flag & TD_NOTCONNECTED || td->dist > t->prop_size)) ||
(connected == 0 && td->rdist > t->prop_size)) {
/*
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index fbfeb4f53de..65fd9c6f5e9 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -55,6 +55,7 @@
#include "BKE_scene.h"
#include "BKE_workspace.h"
#include "BKE_object.h"
+#include "BKE_paint.h"
#include "DEG_depsgraph.h"
@@ -82,13 +83,11 @@
/* local module include */
#include "transform.h"
+#include "transform_convert.h"
#include "MEM_guardedalloc.h"
-#include "GPU_select.h"
#include "GPU_state.h"
-#include "GPU_immediate.h"
-#include "GPU_matrix.h"
#include "DEG_depsgraph_query.h"
@@ -1055,10 +1054,16 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
}
}
else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
- /* pass */
+ if (ob->mode & OB_MODE_SCULPT) {
+ totsel = 1;
+ calc_tw_center_with_matrix(tbounds, ob->sculpt->pivot_pos, false, ob->obmat);
+ mul_m4_v3(ob->obmat, tbounds->center);
+ mul_m4_v3(ob->obmat, tbounds->min);
+ mul_m4_v3(ob->obmat, tbounds->max);
+ }
}
else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) {
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
PTCacheEditPoint *point;
PTCacheEditKey *ek;
int k;
@@ -1163,12 +1168,20 @@ static void gizmo_prepare_mat(const bContext *C,
if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
bGPdata *gpd = CTX_data_gpencil_data(C);
- Object *ob = OBACT(view_layer);
if (gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
/* pass */
}
- else if (ob != NULL) {
- ED_object_calc_active_center(ob, false, rv3d->twmat[3]);
+ else {
+ Object *ob = OBACT(view_layer);
+ if (ob != NULL) {
+ if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) {
+ SculptSession *ss = ob->sculpt;
+ copy_v3_v3(rv3d->twmat[3], ss->pivot_pos);
+ }
+ else {
+ ED_object_calc_active_center(ob, false, rv3d->twmat[3]);
+ }
+ }
}
}
break;
@@ -1284,7 +1297,7 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
PointerRNA toolsettings_ptr;
RNA_pointer_create(&scene->id, &RNA_ToolSettings, scene->toolsettings, &toolsettings_ptr);
- if (type_fn == VIEW3D_GGT_xform_gizmo) {
+ if (ELEM(type_fn, VIEW3D_GGT_xform_gizmo, VIEW3D_GGT_xform_shear)) {
extern PropertyRNA rna_ToolSettings_transform_pivot_point;
const PropertyRNA *props[] = {
&rna_ToolSettings_transform_pivot_point,
@@ -1392,7 +1405,8 @@ void drawDial3d(const TransInfo *t)
scale *= ED_view3d_pixel_size_no_ui_scale(t->ar->regiondata, mat_final[3]);
mul_mat3_m4_fl(mat_final, scale);
- if ((t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) && activeSnap(t)) {
+ if (activeSnap(t) && (!transformModeUseSnap(t) ||
+ (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) {
increment = (t->modifiers & MOD_PRECISION) ? t->snap[2] : t->snap[1];
}
else {
@@ -2294,7 +2308,6 @@ static void WIDGETGROUP_xform_shear_setup(const bContext *UNUSED(C), wmGizmoGrou
interp_v3_v3v3(gz->color, axis_color[i_ortho_a], axis_color[i_ortho_b], 0.75f);
gz->color[3] = 0.5f;
PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_shear, NULL);
- RNA_enum_set(ptr, "shear_axis", 0);
RNA_boolean_set(ptr, "release_confirm", 1);
xgzgroup->gizmo[i][j] = gz;
}
diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c
index e771fe43bd8..2821277ffa0 100644
--- a/source/blender/editors/transform/transform_input.c
+++ b/source/blender/editors/transform/transform_input.c
@@ -389,7 +389,7 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
/* INPUT_VECTOR, INPUT_CUSTOM_RATIO, INPUT_CUSTOM_RATIO_FLIP */
if (t->flag & T_MODAL) {
t->flag |= T_MODAL_CURSOR_SET;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
break;
case HLP_SPRING:
@@ -400,7 +400,7 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
case HLP_CARROW:
if (t->flag & T_MODAL) {
t->flag |= T_MODAL_CURSOR_SET;
- WM_cursor_modal_set(win, CURSOR_NONE);
+ WM_cursor_modal_set(win, WM_CURSOR_NONE);
}
break;
default:
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 1be206e921a..b2d8671fbce 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -53,6 +53,7 @@
#include "ED_mesh.h"
#include "transform.h"
+#include "transform_convert.h"
typedef struct TransformModeItem {
const char *idname;
@@ -301,11 +302,11 @@ static void TRANSFORM_OT_create_orientation(struct wmOperatorType *ot)
WM_operatortype_props_advanced_begin(ot);
RNA_def_boolean(
- ot->srna, "use", false, "Use after creation", "Select orientation after its creation");
+ ot->srna, "use", false, "Use After Creation", "Select orientation after its creation");
RNA_def_boolean(ot->srna,
"overwrite",
false,
- "Overwrite previous",
+ "Overwrite Previous",
"Overwrite previously created orientation with same name");
}
@@ -573,7 +574,7 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
if (flags & P_ORIENT_AXIS_ORTHO) {
prop = RNA_def_property(ot->srna, "orient_axis_ortho", PROP_ENUM, PROP_NONE);
RNA_def_property_ui_text(prop, "Axis Ortho", "");
- RNA_def_property_enum_default(prop, 1);
+ RNA_def_property_enum_default(prop, 0);
RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -910,7 +911,6 @@ static void TRANSFORM_OT_shear(struct wmOperatorType *ot)
ot->poll_property = transform_poll_property;
RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Offset", "", -FLT_MAX, FLT_MAX);
- RNA_def_enum(ot->srna, "shear_axis", rna_enum_axis_xy_items, 0, "Shear Axis", "");
WM_operatortype_props_advanced_begin(ot);
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 14242f6ba40..571ce7a6bc2 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -633,14 +633,12 @@ static void initSnappingMode(TransInfo *t)
(obedit_type == -1)) // Object Mode
{
- if (t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR)) {
+ if (t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR | CTX_OBMODE_XFORM_OBDATA)) {
/* In "Edit Strokes" mode,
* snap tool can perform snap to selected or active objects (see T49632)
- * TODO: perform self snap in gpencil_strokes */
- t->tsnap.modeSelect = SNAP_ALL;
- }
- else if (t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) {
- /* When we're moving the origins, allow snapping onto our own geometry (see T69132). */
+ * TODO: perform self snap in gpencil_strokes.
+ *
+ * When we're moving the origins, allow snapping onto our own geometry (see T69132). */
t->tsnap.modeSelect = SNAP_ALL;
}
else {
@@ -1251,7 +1249,7 @@ static void TargetSnapClosest(TransInfo *t)
for (td = tc->data, i = 0; i < tc->data_len && td->flag & TD_SELECTED; i++, td++) {
const BoundBox *bb = NULL;
- if ((t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) == 0) {
+ if ((t->options & CTX_OBMODE_XFORM_OBDATA) == 0) {
bb = BKE_object_boundbox_get(td->ob);
}
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 7a8a123cf79..1601acb1c8f 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -221,22 +221,40 @@ static void iter_snap_objects(SnapObjectContext *sctx,
Base *base_act = view_layer->basact;
for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) {
- if ((BASE_VISIBLE(v3d, base)) && (base->flag_legacy & BA_SNAP_FIX_DEPS_FIASCO) == 0 &&
- !((snap_select == SNAP_NOT_SELECTED &&
- ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL))) ||
- (snap_select == SNAP_NOT_ACTIVE && base == base_act))) {
- Object *obj_eval = DEG_get_evaluated_object(sctx->depsgraph, base->object);
- if (obj_eval->transflag & OB_DUPLI) {
- DupliObject *dupli_ob;
- ListBase *lb = object_duplilist(sctx->depsgraph, sctx->scene, obj_eval);
- for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
- sob_callback(sctx, use_object_edit_cage, dupli_ob->ob, dupli_ob->mat, data);
- }
- free_object_duplilist(lb);
+
+ if (!BASE_VISIBLE(v3d, base)) {
+ continue;
+ }
+
+ if (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE) {
+ /* pass */
+ }
+ else if (base->flag_legacy & BA_SNAP_FIX_DEPS_FIASCO) {
+ continue;
+ }
+
+ if (snap_select == SNAP_NOT_SELECTED) {
+ if ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL)) {
+ continue;
}
+ }
+ else if (snap_select == SNAP_NOT_ACTIVE) {
+ if (base == base_act) {
+ continue;
+ }
+ }
- sob_callback(sctx, use_object_edit_cage, obj_eval, obj_eval->obmat, data);
+ Object *obj_eval = DEG_get_evaluated_object(sctx->depsgraph, base->object);
+ if (obj_eval->transflag & OB_DUPLI) {
+ DupliObject *dupli_ob;
+ ListBase *lb = object_duplilist(sctx->depsgraph, sctx->scene, obj_eval);
+ for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
+ sob_callback(sctx, use_object_edit_cage, dupli_ob->ob, dupli_ob->mat, data);
+ }
+ free_object_duplilist(lb);
}
+
+ sob_callback(sctx, use_object_edit_cage, obj_eval, obj_eval->obmat, data);
}
}
@@ -336,7 +354,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
const float ray_dir[3],
Object *ob,
Mesh *me,
- float obmat[4][4],
+ const float obmat[4][4],
const unsigned int ob_index,
bool use_hide,
/* read/write args */
@@ -509,7 +527,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
const float ray_dir[3],
Object *ob,
BMEditMesh *em,
- float obmat[4][4],
+ const float obmat[4][4],
const unsigned int ob_index,
/* read/write args */
float *ray_depth,
@@ -692,7 +710,7 @@ static bool raycastObj(SnapObjectContext *sctx,
const float ray_start[3],
const float ray_dir[3],
Object *ob,
- float obmat[4][4],
+ const float obmat[4][4],
const unsigned int ob_index,
bool use_obedit,
bool use_occlusion_test,
@@ -905,10 +923,10 @@ static bool raycastObjects(SnapObjectContext *sctx,
/* Test BoundBox */
static bool snap_bound_box_check_dist(float min[3],
- float max[3],
- float lpmat[4][4],
- float win_size[2],
- float mval[2],
+ const float max[3],
+ const float lpmat[4][4],
+ const float win_size[2],
+ const float mval[2],
float dist_px_sq)
{
/* In vertex and edges you need to get the pixel distance from ray to BoundBox,
@@ -1202,7 +1220,7 @@ static void cb_snap_tri_verts(void *userdata,
static short snap_mesh_polygon(SnapObjectContext *sctx,
SnapData *snapdata,
Object *ob,
- float obmat[4][4],
+ const float obmat[4][4],
/* read/write args */
float *dist_px,
/* return args */
@@ -1254,8 +1272,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
const MPoly *mp = &((SnapObjectData_Mesh *)sod)->poly[*r_index];
const MLoop *ml = &treedata->loop[mp->loopstart];
- if (snapdata->snap_to_flag &
- (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
elem = SCE_SNAP_MODE_EDGE;
BLI_assert(treedata->edge != NULL);
for (int i = mp->totloop; i--; ml++) {
@@ -1292,8 +1309,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
BMFace *f = BM_face_at_index(em->bm, *r_index);
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- if (snapdata->snap_to_flag &
- (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
elem = SCE_SNAP_MODE_EDGE;
BM_mesh_elem_index_ensure(em->bm, BM_EDGE);
BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE);
@@ -1346,7 +1362,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
SnapData *snapdata,
Object *ob,
- float obmat[4][4],
+ const float obmat[4][4],
float original_dist_px,
const float prev_co[3],
/* read/write args */
@@ -1362,22 +1378,6 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
return elem;
}
- float lpmat[4][4];
- mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
-
- struct DistProjectedAABBPrecalc neasrest_precalc;
- dist_squared_to_projected_aabb_precalc(
- &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval);
-
- Nearest2dUserData nearest2d = {
- .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
- };
-
- BVHTreeNearest nearest = {
- .index = -1,
- .dist_sq = SQUARE(original_dist_px),
- };
-
SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob);
if (sod == NULL) {
/* The object is in edit mode, and the key used
@@ -1388,18 +1388,22 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
BLI_assert(sod != NULL);
- if (sod->type == SNAP_MESH) {
- nearest2d.userdata = &((SnapObjectData_Mesh *)sod)->treedata;
- nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get;
- nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get;
- nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy;
- }
- else {
- BLI_assert(sod->type == SNAP_EDIT_MESH);
- nearest2d.userdata = BKE_editmesh_from_object(ob);
- nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get;
- nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get;
- nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy;
+ Nearest2dUserData nearest2d;
+ {
+ nearest2d.is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ if (sod->type == SNAP_MESH) {
+ nearest2d.userdata = &((SnapObjectData_Mesh *)sod)->treedata;
+ nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get;
+ nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get;
+ nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy;
+ }
+ else {
+ BLI_assert(sod->type == SNAP_EDIT_MESH);
+ nearest2d.userdata = BKE_editmesh_from_object(ob);
+ nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get;
+ nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get;
+ nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy;
+ }
}
int vindex[2];
@@ -1409,6 +1413,20 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
nearest2d.get_vert_co(vindex[0], &v_pair[0], nearest2d.userdata);
nearest2d.get_vert_co(vindex[1], &v_pair[1], nearest2d.userdata);
+ struct DistProjectedAABBPrecalc neasrest_precalc;
+ {
+ float lpmat[4][4];
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+
+ dist_squared_to_projected_aabb_precalc(
+ &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval);
+ }
+
+ BVHTreeNearest nearest = {
+ .index = -1,
+ .dist_sq = SQUARE(original_dist_px),
+ };
+
float lambda;
if (!isect_ray_seg_v3(neasrest_precalc.ray_origin,
neasrest_precalc.ray_direction,
@@ -1418,8 +1436,14 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
/* do nothing */
}
else {
- if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
- if (lambda < 0.25f || 0.75f < lambda) {
+ short snap_to_flag = snapdata->snap_to_flag;
+ int e_mode_len = ((snap_to_flag & SCE_SNAP_MODE_EDGE) != 0) +
+ ((snap_to_flag & SCE_SNAP_MODE_VERTEX) != 0) +
+ ((snap_to_flag & SCE_SNAP_MODE_EDGE_MIDPOINT) != 0);
+
+ float range = 1.0f / (2 * e_mode_len - 1);
+ if (snap_to_flag & SCE_SNAP_MODE_VERTEX) {
+ if (lambda < (range) || (1.0f - range) < lambda) {
int v_id = lambda < 0.5f ? 0 : 1;
if (test_projected_vert_dist(&neasrest_precalc,
@@ -1436,8 +1460,9 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
}
}
- if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE_MIDPOINT) {
- if (0.375f < lambda && lambda < 0.625f) {
+ if (snap_to_flag & SCE_SNAP_MODE_EDGE_MIDPOINT) {
+ range *= e_mode_len - 1;
+ if ((range) < lambda && lambda < (1.0f - range)) {
float vmid[3];
mid_v3_v3v3(vmid, v_pair[0], v_pair[1]);
@@ -1468,21 +1493,25 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
if (IN_RANGE(lambda, 0.0f, 1.0f)) {
interp_v3_v3v3(v_near, va_g, vb_g, lambda);
- if ((len_squared_v3v3(prev_co, v_near) > FLT_EPSILON) &&
- test_projected_vert_dist(&neasrest_precalc,
- NULL,
- 0,
- nearest2d.is_persp,
- v_near,
- &nearest.dist_sq,
- nearest.co)) {
- float v_nor[2][3];
- nearest2d.copy_vert_no(vindex[0], v_nor[0], nearest2d.userdata);
- nearest2d.copy_vert_no(vindex[1], v_nor[1], nearest2d.userdata);
- mid_v3_v3v3(nearest.no, v_nor[0], v_nor[1]);
+ if (len_squared_v3v3(prev_co, v_near) > FLT_EPSILON) {
+ dist_squared_to_projected_aabb_precalc(
+ &neasrest_precalc, snapdata->pmat, snapdata->win_size, snapdata->mval);
- nearest.index = *r_index;
- elem = SCE_SNAP_MODE_EDGE_PERPENDICULAR;
+ if (test_projected_vert_dist(&neasrest_precalc,
+ NULL,
+ 0,
+ nearest2d.is_persp,
+ v_near,
+ &nearest.dist_sq,
+ nearest.co)) {
+ float v_nor[2][3];
+ nearest2d.copy_vert_no(vindex[0], v_nor[0], nearest2d.userdata);
+ nearest2d.copy_vert_no(vindex[1], v_nor[1], nearest2d.userdata);
+ mid_v3_v3v3(nearest.no, v_nor[0], v_nor[1]);
+
+ nearest.index = *r_index;
+ elem = SCE_SNAP_MODE_EDGE_PERPENDICULAR;
+ }
}
}
}
@@ -1513,7 +1542,7 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
static short snapArmature(SnapData *snapdata,
Object *ob,
- float obmat[4][4],
+ const float obmat[4][4],
bool use_obedit,
/* read/write args */
float *dist_px,
@@ -1658,7 +1687,7 @@ static short snapArmature(SnapData *snapdata,
static short snapCurve(SnapData *snapdata,
Object *ob,
- float obmat[4][4],
+ const float obmat[4][4],
bool use_obedit,
/* read/write args */
float *dist_px,
@@ -1688,7 +1717,7 @@ static short snapCurve(SnapData *snapdata,
if (use_obedit == false) {
/* Test BoundBox */
- BoundBox *bb = BKE_curve_texspace_get(cu, NULL, NULL, NULL);
+ BoundBox *bb = BKE_curve_boundbox_get(ob);
if (bb && !snap_bound_box_check_dist(
bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) {
return 0;
@@ -1809,7 +1838,7 @@ static short snapCurve(SnapData *snapdata,
/* may extend later (for now just snaps to empty center) */
static short snapEmpty(SnapData *snapdata,
Object *ob,
- float obmat[4][4],
+ const float obmat[4][4],
/* read/write args */
float *dist_px,
/* return args */
@@ -1891,12 +1920,6 @@ static short snapCamera(const SnapObjectContext *sctx,
return retval;
}
- float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
- transpose_m4_m4(tobmat, obmat);
- for (int i = snapdata->clip_plane_len; i--;) {
- mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
- }
-
tracking = &clip->tracking;
BKE_tracking_get_camera_object_matrix(scene, object, orig_camera_mat);
@@ -1942,7 +1965,7 @@ static short snapCamera(const SnapObjectContext *sctx,
mul_m4_v3(vertex_obmat, bundle_pos);
if (test_projected_vert_dist(&neasrest_precalc,
- clip_planes_local,
+ snapdata->clip_plane,
snapdata->clip_plane_len,
is_persp,
bundle_pos,
@@ -1970,7 +1993,7 @@ static short snapMesh(SnapObjectContext *sctx,
SnapData *snapdata,
Object *ob,
Mesh *me,
- float obmat[4][4],
+ const float obmat[4][4],
/* read/write args */
float *dist_px,
/* return args */
@@ -2120,8 +2143,7 @@ static short snapMesh(SnapObjectContext *sctx,
last_index = nearest.index;
}
- if (snapdata->snap_to_flag &
- (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
if (bvhtree[0]) {
/* snap to loose edges */
BLI_bvhtree_find_nearest_projected(bvhtree[0],
@@ -2209,7 +2231,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
SnapData *snapdata,
Object *ob,
BMEditMesh *em,
- float obmat[4][4],
+ const float obmat[4][4],
/* read/write args */
float *dist_px,
/* return args */
@@ -2287,8 +2309,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
}
}
- if (snapdata->snap_to_flag &
- (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
if (sod->bvh_trees[1] == NULL) {
sod->bvh_trees[1] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(**sod->bvh_trees));
}
@@ -2335,7 +2356,6 @@ static short snapEditMesh(SnapObjectContext *sctx,
.index = -1,
.dist_sq = dist_px_sq,
};
- int last_index = nearest.index;
short elem = SCE_SNAP_MODE_VERTEX;
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
@@ -2345,7 +2365,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
}
- if (treedata_vert && snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
+ if (treedata_vert && (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
BLI_bvhtree_find_nearest_projected(treedata_vert->tree,
lpmat,
@@ -2356,12 +2376,11 @@ static short snapEditMesh(SnapObjectContext *sctx,
&nearest,
cb_snap_vert,
&nearest2d);
-
- last_index = nearest.index;
}
- if (treedata_edge && snapdata->snap_to_flag & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT |
- SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ if (treedata_edge && (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE)) {
+ int last_index = nearest.index;
+ nearest.index = -1;
BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_VERT);
BLI_bvhtree_find_nearest_projected(treedata_edge->tree,
lpmat,
@@ -2373,9 +2392,12 @@ static short snapEditMesh(SnapObjectContext *sctx,
cb_snap_edge,
&nearest2d);
- if (last_index != nearest.index) {
+ if (nearest.index != -1) {
elem = SCE_SNAP_MODE_EDGE;
}
+ else {
+ nearest.index = last_index;
+ }
}
if (nearest.index != -1) {
@@ -2770,11 +2792,11 @@ static short transform_snap_context_project_view3d_mixed_impl(
0);
short retval = 0;
- bool has_hit = false;
- int index = -1;
- float loc[3], no[3], obmat[4][4];
+ bool has_hit = false;
Object *ob = NULL;
+ float loc[3], no[3], obmat[4][4];
+ int index = -1;
const ARegion *ar = sctx->v3d_data.ar;
const RegionView3D *rv3d = ar->regiondata;
@@ -2783,7 +2805,6 @@ static short transform_snap_context_project_view3d_mixed_impl(
if (snap_to_flag & SCE_SNAP_MODE_FACE || use_occlusion_test) {
float ray_start[3], ray_normal[3];
-
if (!ED_view3d_win_to_ray_clipped_ex(sctx->depsgraph,
sctx->v3d_data.ar,
sctx->v3d_data.v3d,
@@ -2802,12 +2823,26 @@ static short transform_snap_context_project_view3d_mixed_impl(
if (has_hit && (snap_to_flag & SCE_SNAP_MODE_FACE)) {
retval = SCE_SNAP_MODE_FACE;
+
+ copy_v3_v3(r_loc, loc);
+ if (r_no) {
+ copy_v3_v3(r_no, no);
+ }
+ if (r_ob) {
+ *r_ob = ob;
+ }
+ if (r_obmat) {
+ copy_m4_m4(r_obmat, obmat);
+ }
+ if (r_index) {
+ *r_index = index;
+ }
}
}
if (snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT |
SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
- short elem;
+ short elem_test, elem = 0;
float dist_px_tmp = *dist_px;
SnapData snapdata;
@@ -2815,9 +2850,14 @@ static short transform_snap_context_project_view3d_mixed_impl(
snapdata.win_size[0] = ar->winx;
snapdata.win_size[1] = ar->winy;
copy_v2_v2(snapdata.mval, mval);
- snapdata.snap_to_flag = snap_to_flag;
snapdata.view_proj = rv3d->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO;
+ /* First snap to edge instead of middle or perpendicular. */
+ snapdata.snap_to_flag = snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE);
+ if (snap_to_flag & (SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ snapdata.snap_to_flag |= SCE_SNAP_MODE_EDGE;
+ }
+
planes_from_projmat(
snapdata.pmat, NULL, NULL, NULL, NULL, snapdata.clip_plane[0], snapdata.clip_plane[1]);
@@ -2838,10 +2878,9 @@ static short transform_snap_context_project_view3d_mixed_impl(
new_clipplane[3] += 0.01f;
/* Try to snap only to the polygon. */
- elem = snap_mesh_polygon(sctx, &snapdata, ob, obmat, &dist_px_tmp, loc, no, &index);
-
- if (elem) {
- retval = elem;
+ elem_test = snap_mesh_polygon(sctx, &snapdata, ob, obmat, &dist_px_tmp, loc, no, &index);
+ if (elem_test) {
+ elem = elem_test;
}
/* Add the new clip plane to the beginning of the list. */
@@ -2853,45 +2892,41 @@ static short transform_snap_context_project_view3d_mixed_impl(
snapdata.has_occlusion_plane = true;
}
- elem = snapObjectsRay(sctx, &snapdata, params, &dist_px_tmp, loc, no, &index, &ob, obmat);
-
- if (elem) {
- retval = elem;
+ elem_test = snapObjectsRay(sctx, &snapdata, params, &dist_px_tmp, loc, no, &index, &ob, obmat);
+ if (elem_test) {
+ elem = elem_test;
}
- if ((retval == SCE_SNAP_MODE_EDGE) &&
+ if ((elem == SCE_SNAP_MODE_EDGE) &&
(snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE_MIDPOINT |
SCE_SNAP_MODE_EDGE_PERPENDICULAR))) {
+ snapdata.snap_to_flag = snap_to_flag;
elem = snap_mesh_edge_verts_mixed(
sctx, &snapdata, ob, obmat, *dist_px, prev_co, &dist_px_tmp, loc, no, &index);
}
- if (elem) {
+ if (elem & snap_to_flag) {
retval = elem;
- }
- retval &= snap_to_flag;
- *dist_px = dist_px_tmp;
- }
+ copy_v3_v3(r_loc, loc);
+ if (r_no) {
+ copy_v3_v3(r_no, no);
+ }
+ if (r_ob) {
+ *r_ob = ob;
+ }
+ if (r_obmat) {
+ copy_m4_m4(r_obmat, obmat);
+ }
+ if (r_index) {
+ *r_index = index;
+ }
- if (retval) {
- copy_v3_v3(r_loc, loc);
- if (r_no) {
- copy_v3_v3(r_no, no);
- }
- if (r_ob) {
- *r_ob = ob;
- }
- if (r_obmat) {
- copy_m4_m4(r_obmat, obmat);
- }
- if (r_index) {
- *r_index = index;
+ *dist_px = dist_px_tmp;
}
- return retval;
}
- return 0;
+ return retval;
}
short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index e0f4d1cf465..315a4c73e5f 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -31,12 +31,12 @@
#include "DNA_object_types.h"
#include "BLI_utildefines.h"
-#include "BLI_callbacks.h"
#include "BLI_listbase.h"
#include "BLT_translation.h"
#include "BKE_blender_undo.h"
+#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_main.h"
@@ -172,8 +172,8 @@ static int ed_undo_step_impl(
/* Note: ignore grease pencil for now. */
Main *bmain = CTX_data_main(C);
wm->op_undo_depth++;
- BLI_callback_exec(
- bmain, &scene->id, (step_for_callback > 0) ? BLI_CB_EVT_UNDO_PRE : BLI_CB_EVT_REDO_PRE);
+ BKE_callback_exec_id(
+ bmain, &scene->id, (step_for_callback > 0) ? BKE_CB_EVT_UNDO_PRE : BKE_CB_EVT_REDO_PRE);
wm->op_undo_depth--;
}
@@ -220,8 +220,8 @@ static int ed_undo_step_impl(
Main *bmain = CTX_data_main(C);
scene = CTX_data_scene(C);
wm->op_undo_depth++;
- BLI_callback_exec(
- bmain, &scene->id, step_for_callback > 0 ? BLI_CB_EVT_UNDO_POST : BLI_CB_EVT_REDO_POST);
+ BKE_callback_exec_id(
+ bmain, &scene->id, step_for_callback > 0 ? BKE_CB_EVT_UNDO_POST : BKE_CB_EVT_REDO_POST);
wm->op_undo_depth--;
}
@@ -670,7 +670,7 @@ static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
}
if (item[i].identifier) {
uiItemIntO(column, item[i].name, item[i].icon, op->type->idname, "item", item[i].value);
- ++c;
+ c++;
add_col = true;
}
}
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index c2566d111cf..f5548119e0a 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -245,7 +245,7 @@ bool ED_editors_flush_edits(Main *bmain, bool for_render)
* may cause a flush on saving: T53986. */
if ((ob->sculpt && ob->sculpt->cache) == 0) {
/* flush multires changes (for sculpt) */
- multires_force_update(ob);
+ multires_flush_sculpt_updates(ob);
has_edited = true;
if (for_render) {
diff --git a/source/blender/editors/uvedit/uvedit_buttons.c b/source/blender/editors/uvedit/uvedit_buttons.c
index 2abbe67237e..44bffc76859 100644
--- a/source/blender/editors/uvedit/uvedit_buttons.c
+++ b/source/blender/editors/uvedit/uvedit_buttons.c
@@ -98,7 +98,7 @@ static int uvedit_center(
}
static void uvedit_translate(
- Scene *scene, Object **objects, uint objects_len, Image *ima, float delta[2])
+ Scene *scene, Object **objects, uint objects_len, Image *ima, const float delta[2])
{
BMFace *f;
BMLoop *l;
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index fe761f65702..fafd54804c0 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -54,10 +54,8 @@
#include "GPU_batch.h"
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
-#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
#include "GPU_state.h"
-#include "GPU_draw.h"
#include "ED_image.h"
#include "ED_mesh.h"
@@ -69,6 +67,17 @@
#include "uvedit_intern.h"
+/* Struct containing the needed batches per object.
+ * this optimizes the way how data is requested from
+ * the draw manager. */
+typedef struct UVEditGPUBatches {
+ Object *ob_eval;
+ GPUBatch *faces;
+ GPUBatch *edges;
+ GPUBatch *verts;
+ GPUBatch *facedots;
+} UVEditGPUBatches;
+
static int draw_uvs_face_check(const ToolSettings *ts)
{
/* checks if we are selecting only faces */
@@ -164,40 +173,47 @@ void ED_image_draw_cursor(ARegion *ar, const float cursor[2])
static void uvedit_get_batches(Object *ob,
SpaceImage *sima,
const Scene *scene,
- GPUBatch **faces,
- GPUBatch **edges,
- GPUBatch **verts,
- GPUBatch **facedots)
+ UVEditGPUBatches *batches,
+ float *tot_area,
+ float *tot_area_uv)
{
+ float *tmp_tot_area, *tmp_tot_area_uv;
int drawfaces = draw_uvs_face_check(scene->toolsettings);
const bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0;
const bool draw_faces = (sima->flag & SI_NO_DRAWFACES) == 0;
DRW_mesh_batch_cache_validate(ob->data);
- *edges = DRW_mesh_batch_cache_get_edituv_edges(ob->data);
- *verts = DRW_mesh_batch_cache_get_edituv_verts(ob->data);
+ batches->edges = DRW_mesh_batch_cache_get_edituv_edges(ob->data);
+ batches->verts = DRW_mesh_batch_cache_get_edituv_verts(ob->data);
if (drawfaces) {
- *facedots = DRW_mesh_batch_cache_get_edituv_facedots(ob->data);
+ batches->facedots = DRW_mesh_batch_cache_get_edituv_facedots(ob->data);
}
else {
- *facedots = NULL;
+ batches->facedots = NULL;
}
if (draw_stretch && (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)) {
- *faces = DRW_mesh_batch_cache_get_edituv_faces_strech_area(ob->data);
+ batches->faces = DRW_mesh_batch_cache_get_edituv_faces_stretch_area(
+ ob->data, &tmp_tot_area, &tmp_tot_area_uv);
}
else if (draw_stretch) {
- *faces = DRW_mesh_batch_cache_get_edituv_faces_strech_angle(ob->data);
+ batches->faces = DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(ob->data);
}
else if (draw_faces) {
- *faces = DRW_mesh_batch_cache_get_edituv_faces(ob->data);
+ batches->faces = DRW_mesh_batch_cache_get_edituv_faces(ob->data);
}
else {
- *faces = NULL;
+ batches->faces = NULL;
}
DRW_mesh_batch_cache_create_requested(ob, ob->data, scene, false, false);
+
+ if (draw_stretch && (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)) {
+ /* after create_requested we can load the actual areas */
+ *tot_area += *tmp_tot_area;
+ *tot_area_uv += *tmp_tot_area_uv;
+ }
}
static void draw_uvs_shadow(SpaceImage *UNUSED(sima),
@@ -279,10 +295,14 @@ static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph)
}
/* draws uv's in the image space */
-static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *depsgraph)
+static void draw_uvs(SpaceImage *sima,
+ Scene *scene,
+ Depsgraph *depsgraph,
+ UVEditGPUBatches *batch,
+ float tot_area_ratio,
+ float tot_area_ratio_inv)
{
- GPUBatch *faces, *edges, *verts, *facedots;
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, obedit);
+ Object *ob_eval = batch->ob_eval;
const ToolSettings *ts = scene->toolsettings;
float col1[4], col2[4], col3[4], transparent[4] = {0.0f, 0.0f, 0.0f, 0.0f};
@@ -296,12 +316,10 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
/* When sync selection is enabled, all faces are drawn (except for hidden)
* so if cage is the same as the final, there is no point in drawing this. */
if (!((ts->uv_flag & UV_SYNC_SELECTION) && is_cage_like_final_meshes)) {
- draw_uvs_shadow(sima, scene, obedit, depsgraph);
+ draw_uvs_shadow(sima, scene, ob_eval, depsgraph);
}
}
- uvedit_get_batches(ob_eval, sima, scene, &faces, &edges, &verts, &facedots);
-
bool interpedges;
bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0;
if (ts->uv_flag & UV_SYNC_SELECTION) {
@@ -314,8 +332,8 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
GPU_blend_set_func_separate(
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- if (faces) {
- GPU_batch_program_set_builtin(faces,
+ if (batch->faces) {
+ GPU_batch_program_set_builtin(batch->faces,
(draw_stretch) ? (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA) ?
GPU_SHADER_2D_UV_FACES_STRETCH_AREA :
GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE :
@@ -328,23 +346,27 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
UI_GetThemeColor4fv(TH_FACE_SELECT, col2);
UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, col3);
col3[3] *= 0.2; /* Simulate dithering */
- GPU_batch_uniform_4fv(faces, "faceColor", col1);
- GPU_batch_uniform_4fv(faces, "selectColor", col2);
- GPU_batch_uniform_4fv(faces, "activeColor", col3);
+ GPU_batch_uniform_4fv(batch->faces, "faceColor", col1);
+ GPU_batch_uniform_4fv(batch->faces, "selectColor", col2);
+ GPU_batch_uniform_4fv(batch->faces, "activeColor", col3);
}
else if (sima->dt_uvstretch == SI_UVDT_STRETCH_ANGLE) {
float asp[2];
ED_space_image_get_uv_aspect(sima, &asp[0], &asp[1]);
- GPU_batch_uniform_2fv(faces, "aspect", asp);
+ GPU_batch_uniform_2fv(batch->faces, "aspect", asp);
+ }
+ else if (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA) {
+ GPU_batch_uniform_1f(batch->faces, "totalAreaRatio", tot_area_ratio);
+ GPU_batch_uniform_1f(batch->faces, "totalAreaRatioInv", tot_area_ratio_inv);
}
- GPU_batch_draw(faces);
+ GPU_batch_draw(batch->faces);
if (!draw_stretch) {
GPU_blend(false);
}
}
- if (edges) {
+ if (batch->edges) {
if (sima->flag & SI_SMOOTH_UV) {
GPU_line_smooth(true);
GPU_blend(true);
@@ -356,14 +378,16 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
GPU_viewport_size_get_f(viewport_size);
GPU_line_width(1.0f);
- GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
- GPU_batch_uniform_4fv_array(edges, "colors", 2, (float *)dash_colors);
- GPU_batch_uniform_2f(
- edges, "viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
- GPU_batch_uniform_1i(edges, "colors_len", 2); /* "advanced" mode */
- GPU_batch_uniform_1f(edges, "dash_width", 4.0f);
- GPU_batch_uniform_1f(edges, "dash_factor", 0.5f);
- GPU_batch_draw(edges);
+ GPU_batch_program_set_builtin(batch->edges, GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ GPU_batch_uniform_4fv_array(batch->edges, "colors", 2, (float *)dash_colors);
+ GPU_batch_uniform_2f(batch->edges,
+ "viewport_size",
+ viewport_size[2] / UI_DPI_FAC,
+ viewport_size[3] / UI_DPI_FAC);
+ GPU_batch_uniform_1i(batch->edges, "colors_len", 2); /* "advanced" mode */
+ GPU_batch_uniform_1f(batch->edges, "dash_width", 4.0f);
+ GPU_batch_uniform_1f(batch->edges, "dash_factor", 0.5f);
+ GPU_batch_draw(batch->edges);
break;
}
case SI_UVDT_BLACK:
@@ -376,14 +400,14 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
UI_GetThemeColor4fv(TH_EDGE_SELECT, col2);
GPU_batch_program_set_builtin(
- edges, (interpedges) ? GPU_SHADER_2D_UV_EDGES_SMOOTH : GPU_SHADER_2D_UV_EDGES);
+ batch->edges, (interpedges) ? GPU_SHADER_2D_UV_EDGES_SMOOTH : GPU_SHADER_2D_UV_EDGES);
if (sima->dt_uv == SI_UVDT_OUTLINE) {
/* Black Outline. */
GPU_line_width(3.0f);
- GPU_batch_uniform_4f(edges, "edgeColor", 0.0f, 0.0f, 0.0f, 1.0f);
- GPU_batch_uniform_4f(edges, "selectColor", 0.0f, 0.0f, 0.0f, 1.0f);
- GPU_batch_draw(edges);
+ GPU_batch_uniform_4f(batch->edges, "edgeColor", 0.0f, 0.0f, 0.0f, 1.0f);
+ GPU_batch_uniform_4f(batch->edges, "selectColor", 0.0f, 0.0f, 0.0f, 1.0f);
+ GPU_batch_draw(batch->edges);
UI_GetThemeColor4fv(TH_WIRE_EDIT, col1);
}
@@ -397,9 +421,9 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
/* Inner Line. Use depth test to insure selection is drawn on top. */
GPU_depth_test(true);
GPU_line_width(1.0f);
- GPU_batch_uniform_4fv(edges, "edgeColor", col1);
- GPU_batch_uniform_4fv(edges, "selectColor", col2);
- GPU_batch_draw(edges);
+ GPU_batch_uniform_4fv(batch->edges, "edgeColor", col1);
+ GPU_batch_uniform_4fv(batch->edges, "selectColor", col2);
+ GPU_batch_draw(batch->edges);
GPU_depth_test(false);
glProvokingVertex(GL_LAST_VERTEX_CONVENTION);
@@ -411,44 +435,44 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
GPU_blend(false);
}
}
- if (verts || facedots) {
+ if (batch->verts || batch->facedots) {
UI_GetThemeColor4fv(TH_VERTEX_SELECT, col2);
- if (verts) {
+ if (batch->verts) {
const float point_size = UI_GetThemeValuef(TH_VERTEX_SIZE);
const float pinned_col[4] = {1.0f, 0.0f, 0.0f, 1.0f}; /* TODO Theme? */
UI_GetThemeColor4fv(TH_VERTEX, col1);
GPU_blend(true);
GPU_program_point_size(true);
- GPU_batch_program_set_builtin(verts, GPU_SHADER_2D_UV_VERTS);
- GPU_batch_uniform_4f(verts, "vertColor", col1[0], col1[1], col1[2], 1.0f);
- GPU_batch_uniform_4fv(verts, "selectColor", transparent);
- GPU_batch_uniform_4fv(verts, "pinnedColor", pinned_col);
- GPU_batch_uniform_1f(verts, "pointSize", (point_size + 1.5f) * M_SQRT2);
- GPU_batch_uniform_1f(verts, "outlineWidth", 0.75f);
- GPU_batch_draw(verts);
+ GPU_batch_program_set_builtin(batch->verts, GPU_SHADER_2D_UV_VERTS);
+ GPU_batch_uniform_4f(batch->verts, "vertColor", col1[0], col1[1], col1[2], 1.0f);
+ GPU_batch_uniform_4fv(batch->verts, "selectColor", transparent);
+ GPU_batch_uniform_4fv(batch->verts, "pinnedColor", pinned_col);
+ GPU_batch_uniform_1f(batch->verts, "pointSize", (point_size + 1.5f) * M_SQRT2);
+ GPU_batch_uniform_1f(batch->verts, "outlineWidth", 0.75f);
+ GPU_batch_draw(batch->verts);
/* We have problem in this mode when face order make some verts
* appear unselected because an adjacent face is not selected and
* render after the selected face.
* So, to avoid sorting verts by state we just render selected verts
* on top. A bit overkill but it's simple. */
- GPU_batch_uniform_4fv(verts, "vertColor", transparent);
- GPU_batch_uniform_4fv(verts, "selectColor", col2);
- GPU_batch_draw(verts);
+ GPU_batch_uniform_4fv(batch->verts, "vertColor", transparent);
+ GPU_batch_uniform_4fv(batch->verts, "selectColor", col2);
+ GPU_batch_draw(batch->verts);
GPU_blend(false);
GPU_program_point_size(false);
}
- if (facedots) {
+ if (batch->facedots) {
const float point_size = UI_GetThemeValuef(TH_FACEDOT_SIZE);
GPU_point_size(point_size);
UI_GetThemeColor4fv(TH_WIRE, col1);
- GPU_batch_program_set_builtin(facedots, GPU_SHADER_2D_UV_FACEDOTS);
- GPU_batch_uniform_4fv(facedots, "vertColor", col1);
- GPU_batch_uniform_4fv(facedots, "selectColor", col2);
- GPU_batch_draw(facedots);
+ GPU_batch_program_set_builtin(batch->facedots, GPU_SHADER_2D_UV_FACEDOTS);
+ GPU_batch_uniform_4fv(batch->facedots, "vertColor", col1);
+ GPU_batch_uniform_4fv(batch->facedots, "selectColor", col2);
+ GPU_batch_draw(batch->facedots);
}
}
}
@@ -495,10 +519,32 @@ void ED_uvedit_draw_main(SpaceImage *sima,
GPU_clear_depth(1.0f);
GPU_clear(GPU_DEPTH_BIT);
}
+
+ /* go over all objects and create the batches + add their areas to the total */
+ UVEditGPUBatches *batches = MEM_mallocN(sizeof(UVEditGPUBatches) * objects_len, __func__);
+ float tot_area = 0.0f;
+ float tot_area_uv = 0.0f;
+ float tot_area_ratio = 0.0f;
+ float tot_area_ratio_inv = 0.0f;
+
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *ob_iter = objects[ob_index];
- draw_uvs(sima, scene, ob_iter, depsgraph);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter);
+ batches[ob_index].ob_eval = ob_eval;
+ uvedit_get_batches(ob_eval, sima, scene, &batches[ob_index], &tot_area, &tot_area_uv);
+ }
+
+ if (tot_area > FLT_EPSILON && tot_area_uv > FLT_EPSILON) {
+ tot_area_ratio = tot_area / tot_area_uv;
+ tot_area_ratio_inv = tot_area_uv / tot_area;
+ }
+
+ /* go over all batches created in the previous loop and draw them */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ UVEditGPUBatches *batch = &batches[ob_index];
+ draw_uvs(sima, scene, depsgraph, batch, tot_area_ratio, tot_area_ratio_inv);
}
+ MEM_freeN(batches);
MEM_freeN(objects);
}
else {
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index cd7e5f9ba09..0d258ba542b 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -4458,7 +4458,7 @@ static int uv_select_overlap(bContext *C, const bool extend)
overlap_data[data_index].face_index = face_index;
/* BVH needs 3D, overlap data uses 2D. */
- float tri[3][3] = {
+ const float tri[3][3] = {
{UNPACK2(uv_verts[indices[t][0]]), 0.0f},
{UNPACK2(uv_verts[indices[t][1]]), 0.0f},
{UNPACK2(uv_verts[indices[t][2]]), 0.0f},
@@ -4872,12 +4872,6 @@ static void UV_OT_reveal(wmOperatorType *ot)
/** \name Set 2D Cursor Operator
* \{ */
-static bool uv_set_2d_cursor_poll(bContext *C)
-{
- return ED_operator_uvedit_space_image(C) || ED_space_image_maskedit_poll(C) ||
- ED_space_image_paint_curve(C);
-}
-
static int uv_set_2d_cursor_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -4923,7 +4917,7 @@ static void UV_OT_cursor_set(wmOperatorType *ot)
/* api callbacks */
ot->exec = uv_set_2d_cursor_exec;
ot->invoke = uv_set_2d_cursor_invoke;
- ot->poll = uv_set_2d_cursor_poll;
+ ot->poll = ED_space_image_cursor_poll;
/* properties */
RNA_def_float_vector(ot->srna,
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index 76c3a6d6c4a..5a8301fae67 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -1808,7 +1808,7 @@ static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *ar
GPU_vertbuf_attr_set(
vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + 2]);
- for (j = 1; j < stitch_preview->uvs_per_polygon[i] - 1; ++j) {
+ for (j = 1; j < stitch_preview->uvs_per_polygon[i] - 1; j++) {
GPU_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index]);
GPU_vertbuf_attr_set(
vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 0) * 2]);
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 2d8f40ea5af..1db038bef94 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -1258,7 +1258,7 @@ static void uv_map_rotation_matrix_ex(float result[4][4],
float upangledeg,
float sideangledeg,
float radius,
- float offset[4])
+ const float offset[4])
{
float rotup[4][4], rotside[4][4], viewmatrix[4][4], rotobj[4][4];
float sideangle = 0.0f, upangle = 0.0f;
@@ -2035,9 +2035,9 @@ void UV_OT_reset(wmOperatorType *ot)
/****************** Sphere Project operator ***************/
static void uv_sphere_project(float target[2],
- float source[3],
- float center[3],
- float rotmat[4][4])
+ const float source[3],
+ const float center[3],
+ const float rotmat[4][4])
{
float pv[3];
@@ -2162,9 +2162,9 @@ void UV_OT_sphere_project(wmOperatorType *ot)
/***************** Cylinder Project operator **************/
static void uv_cylinder_project(float target[2],
- float source[3],
- float center[3],
- float rotmat[4][4])
+ const float source[3],
+ const float center[3],
+ const float rotmat[4][4])
{
float pv[3];
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 984a2d01a68..06087cd7fa6 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -105,10 +105,6 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str
freestyle_scene->r.border.xmax = old_scene->r.border.xmax;
freestyle_scene->r.border.ymax = old_scene->r.border.ymax;
strcpy(freestyle_scene->r.pic, old_scene->r.pic);
- freestyle_scene->r.safety.xmin = old_scene->r.safety.xmin;
- freestyle_scene->r.safety.ymin = old_scene->r.safety.ymin;
- freestyle_scene->r.safety.xmax = old_scene->r.safety.xmax;
- freestyle_scene->r.safety.ymax = old_scene->r.safety.ymax;
freestyle_scene->r.dither_intensity = old_scene->r.dither_intensity;
STRNCPY(freestyle_scene->r.engine, old_scene->r.engine);
if (G.debug & G_DEBUG_FREESTYLE) {
@@ -164,7 +160,8 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str
_nodetree_hash = BLI_ghash_ptr_new("BlenderStrokeRenderer::_nodetree_hash");
// Depsgraph
- freestyle_depsgraph = DEG_graph_new(freestyle_scene, view_layer, DAG_EVAL_RENDER);
+ freestyle_depsgraph = DEG_graph_new(
+ freestyle_bmain, freestyle_scene, view_layer, DAG_EVAL_RENDER);
DEG_graph_id_tag_update(freestyle_bmain, freestyle_depsgraph, &freestyle_scene->id, 0);
DEG_graph_id_tag_update(freestyle_bmain, freestyle_depsgraph, &object_camera->id, 0);
DEG_graph_tag_relations_update(freestyle_depsgraph);
@@ -865,7 +862,7 @@ Object *BlenderStrokeRenderer::NewMesh() const
BLI_snprintf(name, MAX_ID_NAME, "0%08xME", mesh_id);
ob->data = BKE_mesh_add(freestyle_bmain, name);
- Collection *collection_master = BKE_collection_master(freestyle_scene);
+ Collection *collection_master = freestyle_scene->master_collection;
BKE_collection_object_add(freestyle_bmain, collection_master, ob);
DEG_graph_tag_relations_update(freestyle_depsgraph);
diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
index 4552ce849f2..07839ac6e61 100644
--- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
+++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
@@ -42,6 +42,7 @@ extern "C" {
#include "DNA_material_types.h"
#include "DNA_text_types.h"
+#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_freestyle.h"
#include "BKE_global.h"
@@ -55,7 +56,6 @@ extern "C" {
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_math_color_blend.h"
-#include "BLI_callbacks.h"
#include "BPY_extern.h"
@@ -80,7 +80,10 @@ static AppView *view = NULL;
static FreestyleLineSet lineset_buffer;
static bool lineset_copied = false;
-static void load_post_callback(struct Main * /*main*/, struct ID * /*id*/, void * /*arg*/)
+static void load_post_callback(struct Main * /*main*/,
+ struct PointerRNA ** /*pointers*/,
+ const int /*num_pointers*/,
+ void * /*arg*/)
{
lineset_copied = false;
}
@@ -111,7 +114,7 @@ void FRS_initialize()
g_freestyle.scene = NULL;
lineset_copied = false;
- BLI_callback_add(&load_post_callback_funcstore, BLI_CB_EVT_LOAD_POST);
+ BKE_callback_add(&load_post_callback_funcstore, BKE_CB_EVT_LOAD_POST);
freestyle_is_initialized = 1;
}
@@ -649,7 +652,7 @@ Render *FRS_do_stroke_rendering(Render *re, ViewLayer *view_layer, int render)
/* Create depsgraph and evaluate scene. */
ViewLayer *scene_view_layer = (ViewLayer *)BLI_findstring(
&re->scene->view_layers, view_layer->name, offsetof(ViewLayer, name));
- Depsgraph *depsgraph = DEG_graph_new(re->scene, scene_view_layer, DAG_EVAL_RENDER);
+ Depsgraph *depsgraph = DEG_graph_new(re->main, re->scene, scene_view_layer, DAG_EVAL_RENDER);
BKE_scene_graph_update_for_newframe(depsgraph, re->main);
// prepare Freestyle:
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
index 5209313f717..2d1a845330b 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -78,17 +78,17 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
bool is_stroke_affected_by_modifier(Object *ob,
char *mlayername,
char *mmaterialname,
- int mpassindex,
- int gpl_passindex,
- int minpoints,
+ const int mpassindex,
+ const int gpl_passindex,
+ const int minpoints,
bGPDlayer *gpl,
bGPDstroke *gps,
- bool inv1,
- bool inv2,
- bool inv3,
- bool inv4)
+ const bool inv1,
+ const bool inv2,
+ const bool inv3,
+ const bool inv4)
{
- Material *ma = give_current_material(ob, gps->mat_nr + 1);
+ Material *ma = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
MaterialGPencilStyle *gp_style = ma->gp_style;
/* omit if filter by layer */
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
index 7f00e072cda..2b1f8dbc71a 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
@@ -35,15 +35,15 @@ struct bGPDstroke;
bool is_stroke_affected_by_modifier(struct Object *ob,
char *mlayername,
char *mmaterialname,
- int mpassindex,
- int gpl_passindex,
- int minpoints,
+ const int mpassindex,
+ const int gpl_passindex,
+ const int minpoints,
bGPDlayer *gpl,
bGPDstroke *gps,
- bool inv1,
- bool inv2,
- bool inv3,
- bool inv4);
+ const bool inv1,
+ const bool inv2,
+ const bool inv3,
+ const bool inv4);
float get_modifier_point_weight(struct MDeformVert *dvert, bool inverse, int def_nr);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
index acf9b5c3642..1f2f0554dd5 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
@@ -158,8 +158,7 @@ static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the armature is missing).
*
- * In other cases it should be impossible to have a type missmatch.
- */
+ * In other cases it should be impossible to have a type mismatch. */
return !mmd->object || mmd->object->type != OB_ARMATURE;
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
index 741acfbe405..cb429b874a2 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
@@ -119,7 +119,7 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData
for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- Material *mat = give_current_material(ob, gps->mat_nr + 1);
+ Material *mat = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
if (mat == NULL) {
continue;
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
index 810a2ba7e25..234b4deeceb 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
@@ -63,8 +63,8 @@ struct GPHookData_cb {
float falloff_sq;
float fac_orig;
- unsigned int use_falloff : 1;
- unsigned int use_uniform : 1;
+ uint use_falloff : 1;
+ uint use_uniform : 1;
float cent[3];
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
index 765967d8346..6b74f96ce31 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
@@ -172,7 +172,7 @@ static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the lattice is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
return !mmd->object || mmd->object->type != OB_LATTICE;
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
index 112dfc2e9dc..e391adde829 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
@@ -126,7 +126,7 @@ static void generateStrokes(GpencilModifierData *md,
int i;
/* check each axis for mirroring */
- for (int xi = 0; xi < 3; ++xi) {
+ for (int xi = 0; xi < 3; xi++) {
if (mmd->flag & (GP_MIRROR_AXIS_X << xi)) {
/* count strokes to avoid infinite loop after adding new strokes to tail of listbase */
@@ -208,7 +208,7 @@ static int getDuplicationFactor(GpencilModifierData *md)
MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md;
int factor = 1;
/* create a duplication for each axis */
- for (int xi = 0; xi < 3; ++xi) {
+ for (int xi = 0; xi < 3; xi++) {
if (mmd->flag & (GP_MIRROR_AXIS_X << xi)) {
factor++;
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
index 346d1e834a6..22610771045 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
@@ -89,38 +89,56 @@ static void deformStroke(GpencilModifierData *md,
return;
}
- if (mmd->modify_color != GP_MODIFY_COLOR_FILL) {
- gps->runtime.tmp_stroke_rgba[3] *= mmd->factor;
- /* if factor is > 1, then force opacity */
- if (mmd->factor > 1.0f) {
- gps->runtime.tmp_stroke_rgba[3] += mmd->factor - 1.0f;
+ if (mmd->opacity_mode == GP_OPACITY_MODE_MATERIAL) {
+ if (mmd->modify_color != GP_MODIFY_COLOR_FILL) {
+ gps->runtime.tmp_stroke_rgba[3] *= mmd->factor;
+ /* if factor is > 1, then force opacity */
+ if (mmd->factor > 1.0f) {
+ gps->runtime.tmp_stroke_rgba[3] += mmd->factor - 1.0f;
+ }
+ CLAMP(gps->runtime.tmp_stroke_rgba[3], 0.0f, 1.0f);
}
- CLAMP(gps->runtime.tmp_stroke_rgba[3], 0.0f, 1.0f);
- }
- if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) {
- gps->runtime.tmp_fill_rgba[3] *= mmd->factor;
- /* if factor is > 1, then force opacity */
- if (mmd->factor > 1.0f && gps->runtime.tmp_fill_rgba[3] > 1e-5) {
- gps->runtime.tmp_fill_rgba[3] += mmd->factor - 1.0f;
+ if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) {
+ gps->runtime.tmp_fill_rgba[3] *= mmd->factor;
+ /* if factor is > 1, then force opacity */
+ if (mmd->factor > 1.0f && gps->runtime.tmp_fill_rgba[3] > 1e-5) {
+ gps->runtime.tmp_fill_rgba[3] += mmd->factor - 1.0f;
+ }
+ CLAMP(gps->runtime.tmp_fill_rgba[3], 0.0f, 1.0f);
}
- CLAMP(gps->runtime.tmp_fill_rgba[3], 0.0f, 1.0f);
- }
- /* if opacity > 1.0, affect the strength of the stroke */
- if (mmd->factor > 1.0f) {
+ /* if opacity > 1.0, affect the strength of the stroke */
+ if (mmd->factor > 1.0f) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ pt->strength += mmd->factor - 1.0f;
+ CLAMP(pt->strength, 0.0f, 1.0f);
+ }
+ }
+ }
+ /* Apply opacity by strength */
+ else {
for (int i = 0; i < gps->totpoints; i++) {
bGPDspoint *pt = &gps->points[i];
MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
/* verify vertex group */
- const float weight = get_modifier_point_weight(
+ float weight = get_modifier_point_weight(
dvert, (mmd->flag & GP_OPACITY_INVERT_VGROUP) != 0, def_nr);
if (weight < 0.0f) {
+ continue;
+ }
+ if (def_nr < 0) {
pt->strength += mmd->factor - 1.0f;
}
else {
- pt->strength += (mmd->factor - 1.0f) * weight;
+ /* High factor values, change weight too. */
+ if ((mmd->factor > 1.0f) && (weight < 1.0f)) {
+ weight += mmd->factor - 1.0f;
+ CLAMP(weight, 0.0f, 1.0f);
+ }
+ pt->strength += (mmd->factor - 1) * weight;
}
CLAMP(pt->strength, 0.0f, 1.0f);
}
@@ -137,7 +155,7 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData
for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- Material *mat = give_current_material(ob, gps->mat_nr + 1);
+ Material *mat = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
if (mat == NULL) {
continue;
}
@@ -152,8 +170,10 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData
deformStroke(md, depsgraph, ob, gpl, gpf, gps);
- gpencil_apply_modifier_material(
- bmain, ob, mat, gh_color, gps, (bool)(mmd->flag & GP_OPACITY_CREATE_COLORS));
+ if (mmd->opacity_mode == GP_OPACITY_MODE_MATERIAL) {
+ gpencil_apply_modifier_material(
+ bmain, ob, mat, gh_color, gps, (bool)(mmd->flag & GP_OPACITY_CREATE_COLORS));
+ }
}
}
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
index 741555722b5..ce75ca59fe1 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
@@ -65,12 +65,16 @@ static void deformStroke(GpencilModifierData *md,
{
SubdivGpencilModifierData *mmd = (SubdivGpencilModifierData *)md;
+ /* It makes sense when adding points to a straight line */
+ /* e.g. for creating thickness variation in later modifiers. */
+ const int minimum_vert = (mmd->flag | GP_SUBDIV_SIMPLE) ? 2 : 3;
+
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
mmd->materialname,
mmd->pass_index,
mmd->layer_pass,
- 3,
+ minimum_vert,
gpl,
gps,
mmd->flag & GP_SUBDIV_INVERT_LAYER,
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
index bfb2c62cef6..f6ddcf89bcf 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
@@ -125,7 +125,7 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData
for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- Material *mat = give_current_material(ob, gps->mat_nr + 1);
+ Material *mat = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
if (mat == NULL) {
continue;
}
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index fb7d3c1ace8..bc08da4b2cb 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -116,6 +116,7 @@ set(SRC
intern/gpu_batch_private.h
intern/gpu_codegen.h
intern/gpu_context_private.h
+ intern/gpu_material_library.h
intern/gpu_matrix_private.h
intern/gpu_primitive_private.h
intern/gpu_private.h
@@ -231,7 +232,94 @@ data_to_c_simple(shaders/gpu_shader_keyframe_diamond_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_keyframe_diamond_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_geometry.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_material.glsl SRC)
+
+data_to_c_simple(shaders/material/gpu_shader_material_add_shader.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_ambient_occlusion.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_anisotropic.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_attribute.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_background.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_bevel.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_blackbody.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_bright_contrast.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_bump.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_camera.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_clamp.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_color_ramp.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_color_util.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_combine_hsv.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_combine_rgb.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_combine_xyz.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_diffuse.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_displacement.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_eevee_specular.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_emission.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_fractal_noise.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_fresnel.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_gamma.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_geometry.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_glass.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_glossy.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_hair_info.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_hash.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_holdout.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_hue_sat_val.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_invert.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_layer_weight.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_light_falloff.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_light_path.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_mapping.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_map_range.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_math.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_math_util.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_mix_rgb.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_mix_shader.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_noise.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_normal.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_normal_map.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_object_info.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_output_material.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_output_world.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_particle_info.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_principled.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_refraction.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_rgb_curves.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_rgb_to_bw.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_separate_hsv.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_separate_rgb.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_separate_xyz.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_set.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_shader_to_rgba.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_squeeze.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_subsurface_scattering.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tangent.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_brick.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_checker.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_environment.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_gradient.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_image.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_magic.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_musgrave.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_noise.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_sky.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_texture_coordinates.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_voronoi.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_wave.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_tex_white_noise.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_toon.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_translucent.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_transparent.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_uv_map.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_vector_curves.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_vector_displacement.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_vector_math.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_velvet.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_vertex_color.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_volume_absorption.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_volume_info.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_volume_principled.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_volume_scatter.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_wireframe.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_world_normals.glsl SRC)
data_to_c_simple(shaders/gpu_shader_gpencil_stroke_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_gpencil_stroke_frag.glsl SRC)
@@ -242,6 +330,8 @@ data_to_c_simple(shaders/gpu_shader_gpencil_fill_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_cfg_world_clip_lib.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_common_obinfos_lib.glsl SRC)
+
if(WITH_MOD_SMOKE)
add_definitions(-DWITH_SMOKE)
diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h
index 175033f70d9..7d8c3347eb4 100644
--- a/source/blender/gpu/GPU_batch.h
+++ b/source/blender/gpu/GPU_batch.h
@@ -193,6 +193,17 @@ GPUBatch *create_BatchInGeneral(GPUPrimType, VertexBufferStuff, ElementListStuff
#endif /* future plans */
+/* GPUDrawList is an API to do lots of similar drawcalls very fast using multidrawindirect.
+ * There is a fallback if the feature is not supported. */
+typedef struct GPUDrawList GPUDrawList;
+
+GPUDrawList *GPU_draw_list_create(int length);
+void GPU_draw_list_discard(GPUDrawList *list);
+void GPU_draw_list_init(GPUDrawList *list, GPUBatch *batch);
+void GPU_draw_list_command_add(
+ GPUDrawList *list, int v_first, int v_count, int i_first, int i_count);
+void GPU_draw_list_submit(GPUDrawList *list);
+
void gpu_batch_init(void);
void gpu_batch_exit(void);
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index 9009c134837..552bad2b0d6 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -41,7 +41,8 @@ struct PBVH;
/* Buffers for drawing from PBVH grids. */
typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers;
-/* build */
+/* Build must be called once before using the other functions, used every time
+ * mesh topology changes. Threaded. */
GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
const struct MPoly *mpoly,
const struct MLoop *mloop,
@@ -54,8 +55,13 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, unsigned int **grid_h
GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading);
-/* update */
+/* Free part of data for update. Not thread safe, must run in OpenGL main thread. */
+void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers);
+void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers,
+ const struct DMFlagMat *grid_flag_mats,
+ int *grid_indices);
+/* Update mesh buffers without topology changes. Threaded. */
enum {
GPU_PBVH_BUFFERS_SHOW_MASK = (1 << 1),
GPU_PBVH_BUFFERS_SHOW_VCOL = (1 << 1),
@@ -85,6 +91,12 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
const struct CCGKey *key,
const int update_flags);
+/* Finish update. Not thread safe, must run in OpenGL main thread. */
+void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers);
+
+/* Free buffers. Not thread safe, must run in OpenGL main thread. */
+void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers);
+
/* draw */
struct GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool wires);
@@ -92,8 +104,4 @@ short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers);
bool GPU_pbvh_buffers_has_mask(GPU_PBVH_Buffers *buffers);
-void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers);
-
-void GPU_pbvh_fix_linking(void);
-
#endif
diff --git a/source/blender/gpu/GPU_shader_interface.h b/source/blender/gpu/GPU_shader_interface.h
index ec97e1b085e..e336aa53d24 100644
--- a/source/blender/gpu/GPU_shader_interface.h
+++ b/source/blender/gpu/GPU_shader_interface.h
@@ -45,13 +45,12 @@ typedef enum {
GPU_UNIFORM_VIEWPROJECTION_INV, /* mat4 ViewProjectionMatrixInverse */
GPU_UNIFORM_NORMAL, /* mat3 NormalMatrix */
- GPU_UNIFORM_ORCO, /* vec3 OrcoTexCoFactors[] */
+ GPU_UNIFORM_ORCO, /* vec4 OrcoTexCoFactors[] */
GPU_UNIFORM_CLIPPLANES, /* vec4 WorldClipPlanes[] */
- GPU_UNIFORM_COLOR, /* vec4 color */
- GPU_UNIFORM_CALLID, /* int callId */
- GPU_UNIFORM_OBJECT_INFO, /* vec3 objectInfo */
- GPU_UNIFORM_OBJECT_COLOR, /* vec4 objectColor */
+ GPU_UNIFORM_COLOR, /* vec4 color */
+ GPU_UNIFORM_BASE_INSTANCE, /* int baseInstance */
+ GPU_UNIFORM_RESOURCE_CHUNK, /* int resourceChunk */
GPU_UNIFORM_CUSTOM, /* custom uniform, not one of the above built-ins */
diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h
index e7600279d6f..4bbcb6a4335 100644
--- a/source/blender/gpu/GPU_viewport.h
+++ b/source/blender/gpu/GPU_viewport.h
@@ -37,14 +37,20 @@ typedef struct GPUViewport GPUViewport;
/* Contains memory pools information */
typedef struct ViewportMemoryPool {
- struct BLI_memblock *calls;
- struct BLI_memblock *states;
+ struct BLI_memblock *commands;
+ struct BLI_memblock *commands_small;
+ struct BLI_memblock *callbuffers;
+ struct BLI_memblock *obmats;
+ struct BLI_memblock *obinfos;
struct BLI_memblock *cullstates;
struct BLI_memblock *shgroups;
struct BLI_memblock *uniforms;
struct BLI_memblock *views;
struct BLI_memblock *passes;
struct BLI_memblock *images;
+ struct GPUUniformBuffer **matrices_ubo;
+ struct GPUUniformBuffer **obinfos_ubo;
+ uint ubo_len;
} ViewportMemoryPool;
/* All FramebufferLists are just the same pointers with different names */
diff --git a/source/blender/gpu/intern/gpu_attr_binding.c b/source/blender/gpu/intern/gpu_attr_binding.c
index 802b15a0c4e..6cb60884620 100644
--- a/source/blender/gpu/intern/gpu_attr_binding.c
+++ b/source/blender/gpu/intern/gpu_attr_binding.c
@@ -67,9 +67,9 @@ void get_attr_locations(const GPUVertFormat *format,
{
AttrBinding_clear(binding);
- for (uint a_idx = 0; a_idx < format->attr_len; ++a_idx) {
+ for (uint a_idx = 0; a_idx < format->attr_len; a_idx++) {
const GPUVertAttr *a = &format->attrs[a_idx];
- for (uint n_idx = 0; n_idx < a->name_len; ++n_idx) {
+ for (uint n_idx = 0; n_idx < a->name_len; n_idx++) {
const char *name = GPU_vertformat_attr_name_get(format, a, n_idx);
const GPUShaderInput *input = GPU_shaderinterface_attr(shaderface, name);
#if TRUST_NO_ONE
diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c
index 583551e3e58..2620ba49799 100644
--- a/source/blender/gpu/intern/gpu_batch.c
+++ b/source/blender/gpu/intern/gpu_batch.c
@@ -39,8 +39,9 @@
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
-static void batch_update_program_bindings(GPUBatch *batch, uint v_first);
+static void batch_update_program_bindings(GPUBatch *batch, uint i_first);
void GPU_batch_vao_cache_clear(GPUBatch *batch)
{
@@ -48,7 +49,7 @@ void GPU_batch_vao_cache_clear(GPUBatch *batch)
return;
}
if (batch->is_dynamic_vao_count) {
- for (int i = 0; i < batch->dynamic_vaos.count; ++i) {
+ for (int i = 0; i < batch->dynamic_vaos.count; i++) {
if (batch->dynamic_vaos.vao_ids[i]) {
GPU_vao_free(batch->dynamic_vaos.vao_ids[i], batch->context);
}
@@ -61,7 +62,7 @@ void GPU_batch_vao_cache_clear(GPUBatch *batch)
MEM_freeN(batch->dynamic_vaos.vao_ids);
}
else {
- for (int i = 0; i < GPU_BATCH_VAO_STATIC_LEN; ++i) {
+ for (int i = 0; i < GPU_BATCH_VAO_STATIC_LEN; i++) {
if (batch->static_vaos.vao_ids[i]) {
GPU_vao_free(batch->static_vaos.vao_ids[i], batch->context);
}
@@ -72,7 +73,7 @@ void GPU_batch_vao_cache_clear(GPUBatch *batch)
}
}
batch->is_dynamic_vao_count = false;
- for (int i = 0; i < GPU_BATCH_VAO_STATIC_LEN; ++i) {
+ for (int i = 0; i < GPU_BATCH_VAO_STATIC_LEN; i++) {
batch->static_vaos.vao_ids[i] = 0;
batch->static_vaos.interfaces[i] = NULL;
}
@@ -98,7 +99,7 @@ void GPU_batch_init_ex(
#endif
batch->verts[0] = verts;
- for (int v = 1; v < GPU_BATCH_VBO_MAX_LEN; ++v) {
+ for (int v = 1; v < GPU_BATCH_VBO_MAX_LEN; v++) {
batch->verts[v] = NULL;
}
batch->inst = NULL;
@@ -116,7 +117,7 @@ void GPU_batch_copy(GPUBatch *batch_dst, GPUBatch *batch_src)
GPU_batch_init_ex(batch_dst, GPU_PRIM_POINTS, batch_src->verts[0], batch_src->elem, 0);
batch_dst->gl_prim_type = batch_src->gl_prim_type;
- for (int v = 1; v < GPU_BATCH_VBO_MAX_LEN; ++v) {
+ for (int v = 1; v < GPU_BATCH_VBO_MAX_LEN; v++) {
batch_dst->verts[v] = batch_src->verts[v];
}
}
@@ -130,7 +131,7 @@ void GPU_batch_clear(GPUBatch *batch)
GPU_vertbuf_discard(batch->inst);
}
if ((batch->owns_flag & ~GPU_BATCH_OWNS_INDEX) != 0) {
- for (int v = 0; v < GPU_BATCH_VBO_MAX_LEN; ++v) {
+ for (int v = 0; v < GPU_BATCH_VBO_MAX_LEN; v++) {
if (batch->verts[v] == NULL) {
break;
}
@@ -207,7 +208,7 @@ int GPU_batch_vertbuf_add_ex(GPUBatch *batch, GPUVertBuf *verts, bool own_vbo)
/* redo the bindings */
GPU_batch_vao_cache_clear(batch);
- for (uint v = 0; v < GPU_BATCH_VBO_MAX_LEN; ++v) {
+ for (uint v = 0; v < GPU_BATCH_VBO_MAX_LEN; v++) {
if (batch->verts[v] == NULL) {
#if TRUST_NO_ONE
/* for now all VertexBuffers must have same vertex_len */
@@ -233,14 +234,14 @@ static GLuint batch_vao_get(GPUBatch *batch)
{
/* Search through cache */
if (batch->is_dynamic_vao_count) {
- for (int i = 0; i < batch->dynamic_vaos.count; ++i) {
+ for (int i = 0; i < batch->dynamic_vaos.count; i++) {
if (batch->dynamic_vaos.interfaces[i] == batch->interface) {
return batch->dynamic_vaos.vao_ids[i];
}
}
}
else {
- for (int i = 0; i < GPU_BATCH_VAO_STATIC_LEN; ++i) {
+ for (int i = 0; i < GPU_BATCH_VAO_STATIC_LEN; i++) {
if (batch->static_vaos.interfaces[i] == batch->interface) {
return batch->static_vaos.vao_ids[i];
}
@@ -265,7 +266,7 @@ static GLuint batch_vao_get(GPUBatch *batch)
GLuint new_vao = 0;
if (!batch->is_dynamic_vao_count) {
int i; /* find first unused slot */
- for (i = 0; i < GPU_BATCH_VAO_STATIC_LEN; ++i) {
+ for (i = 0; i < GPU_BATCH_VAO_STATIC_LEN; i++) {
if (batch->static_vaos.vao_ids[i] == 0) {
break;
}
@@ -279,7 +280,7 @@ static GLuint batch_vao_get(GPUBatch *batch)
/* Not enough place switch to dynamic. */
batch->is_dynamic_vao_count = true;
/* Erase previous entries, they will be added back if drawn again. */
- for (int j = 0; j < GPU_BATCH_VAO_STATIC_LEN; ++j) {
+ for (int j = 0; j < GPU_BATCH_VAO_STATIC_LEN; j++) {
GPU_shaderinterface_remove_batch_ref(
(GPUShaderInterface *)batch->static_vaos.interfaces[j], batch);
GPU_vao_free(batch->static_vaos.vao_ids[j], batch->context);
@@ -295,7 +296,7 @@ static GLuint batch_vao_get(GPUBatch *batch)
if (batch->is_dynamic_vao_count) {
int i; /* find first unused slot */
- for (i = 0; i < batch->dynamic_vaos.count; ++i) {
+ for (i = 0; i < batch->dynamic_vaos.count; i++) {
if (batch->dynamic_vaos.vao_ids[i] == 0) {
break;
}
@@ -351,7 +352,7 @@ void GPU_batch_program_set(GPUBatch *batch, uint32_t program, const GPUShaderInt
void gpu_batch_remove_interface_ref(GPUBatch *batch, const GPUShaderInterface *interface)
{
if (batch->is_dynamic_vao_count) {
- for (int i = 0; i < batch->dynamic_vaos.count; ++i) {
+ for (int i = 0; i < batch->dynamic_vaos.count; i++) {
if (batch->dynamic_vaos.interfaces[i] == interface) {
GPU_vao_free(batch->dynamic_vaos.vao_ids[i], batch->context);
batch->dynamic_vaos.vao_ids[i] = 0;
@@ -362,7 +363,7 @@ void gpu_batch_remove_interface_ref(GPUBatch *batch, const GPUShaderInterface *i
}
else {
int i;
- for (i = 0; i < GPU_BATCH_VAO_STATIC_LEN; ++i) {
+ for (i = 0; i < GPU_BATCH_VAO_STATIC_LEN; i++) {
if (batch->static_vaos.interfaces[i] == interface) {
GPU_vao_free(batch->static_vaos.vao_ids[i], batch->context);
batch->static_vaos.vao_ids[i] = 0;
@@ -386,7 +387,7 @@ static void create_bindings(GPUVertBuf *verts,
GPU_vertbuf_use(verts);
- for (uint a_idx = 0; a_idx < attr_len; ++a_idx) {
+ for (uint a_idx = 0; a_idx < attr_len; a_idx++) {
const GPUVertAttr *a = &format->attrs[a_idx];
if (format->deinterleaved) {
@@ -399,7 +400,7 @@ static void create_bindings(GPUVertBuf *verts,
const GLvoid *pointer = (const GLubyte *)0 + offset + v_first * stride;
- for (uint n_idx = 0; n_idx < a->name_len; ++n_idx) {
+ for (uint n_idx = 0; n_idx < a->name_len; n_idx++) {
const char *name = GPU_vertformat_attr_name_get(format, a, n_idx);
const GPUShaderInput *input = GPU_shaderinterface_attr(interface, name);
@@ -412,7 +413,7 @@ static void create_bindings(GPUVertBuf *verts,
assert(a->fetch_mode == GPU_FETCH_FLOAT);
assert(a->gl_comp_type == GL_FLOAT);
#endif
- for (int i = 0; i < a->comp_len / 4; ++i) {
+ for (int i = 0; i < a->comp_len / 4; i++) {
glEnableVertexAttribArray(input->location + i);
glVertexAttribDivisor(input->location + i, (use_instancing) ? 1 : 0);
glVertexAttribPointer(input->location + i,
@@ -446,16 +447,16 @@ static void create_bindings(GPUVertBuf *verts,
}
}
-static void batch_update_program_bindings(GPUBatch *batch, uint v_first)
+static void batch_update_program_bindings(GPUBatch *batch, uint i_first)
{
/* Reverse order so first vbos have more prevalence (in term of attrib override). */
- for (int v = GPU_BATCH_VBO_MAX_LEN - 1; v > -1; --v) {
+ for (int v = GPU_BATCH_VBO_MAX_LEN - 1; v > -1; v--) {
if (batch->verts[v] != NULL) {
- create_bindings(batch->verts[v], batch->interface, (batch->inst) ? 0 : v_first, false);
+ create_bindings(batch->verts[v], batch->interface, 0, false);
}
}
if (batch->inst) {
- create_bindings(batch->inst, batch->interface, v_first, true);
+ create_bindings(batch->inst, batch->interface, i_first, true);
}
if (batch->elem) {
GPU_indexbuf_use(batch->elem);
@@ -618,12 +619,18 @@ void GPU_batch_draw(GPUBatch *batch)
GPU_batch_program_use_end(batch);
}
+#if GPU_TRACK_INDEX_RANGE
+# define BASE_INDEX(el) ((el)->base_index)
+# define INDEX_TYPE(el) ((el)->gl_index_type)
+#else
+# define BASE_INDEX(el) 0
+# define INDEX_TYPE(el) GL_UNSIGNED_INT
+#endif
+
void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_first, int i_count)
{
-#if TRUST_NO_ONE
BLI_assert(batch->program_in_use);
/* TODO could assert that VAO is bound. */
-#endif
if (v_count == 0) {
v_count = (batch->elem) ? batch->elem->index_len : batch->verts[0]->vertex_len;
@@ -632,8 +639,21 @@ void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_fi
i_count = (batch->inst) ? batch->inst->vertex_len : 1;
}
+ if (v_count == 0 || i_count == 0) {
+ /* Nothing to draw. */
+ return;
+ }
+
+ /* Verify there is enough data do draw. */
+ /* TODO(fclem) Nice to have but this is invalid when using procedural drawcalls.
+ * The right assert would be to check if there is an enabled attrib from each VBO
+ * and check their length. */
+ // BLI_assert(i_first + i_count <= (batch->inst ? batch->inst->vertex_len : INT_MAX));
+ // BLI_assert(v_first + v_count <=
+ // (batch->elem ? batch->elem->index_len : batch->verts[0]->vertex_len));
+
if (!GPU_arb_base_instance_is_supported()) {
- if (i_first > 0 && i_count > 0) {
+ if (i_first > 0) {
/* If using offset drawing with instancing, we must
* use the default VAO and redo bindings. */
glBindVertexArray(GPU_vao_default());
@@ -648,13 +668,8 @@ void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_fi
if (batch->elem) {
const GPUIndexBuf *el = batch->elem;
-#if GPU_TRACK_INDEX_RANGE
- GLenum index_type = el->gl_index_type;
- GLint base_index = el->base_index;
-#else
- GLenum index_type = GL_UNSIGNED_INT;
- GLint base_index = 0;
-#endif
+ GLenum index_type = INDEX_TYPE(el);
+ GLint base_index = BASE_INDEX(el);
void *v_first_ofs = elem_offset(el, v_first);
if (GPU_arb_base_instance_is_supported()) {
@@ -697,6 +712,184 @@ void GPU_draw_primitive(GPUPrimType prim_type, int v_count)
}
/* -------------------------------------------------------------------- */
+/** \name Indirect Draw Calls
+ * \{ */
+
+#if 0
+# define USE_MULTI_DRAW_INDIRECT 0
+#else
+# define USE_MULTI_DRAW_INDIRECT \
+ (GL_ARB_multi_draw_indirect && GPU_arb_base_instance_is_supported())
+#endif
+
+typedef struct GPUDrawCommand {
+ uint v_count;
+ uint i_count;
+ uint v_first;
+ uint i_first;
+} GPUDrawCommand;
+
+typedef struct GPUDrawCommandIndexed {
+ uint v_count;
+ uint i_count;
+ uint v_first;
+ uint base_index;
+ uint i_first;
+} GPUDrawCommandIndexed;
+
+struct GPUDrawList {
+ GPUBatch *batch;
+ uint base_index; /* Avoid dereferencing batch. */
+ uint cmd_offset; /* in bytes, offset inside indirect command buffer. */
+ uint cmd_len; /* Number of used command for the next call. */
+ uint buffer_size; /* in bytes, size of indirect command buffer. */
+ GLuint buffer_id; /* Draw Indirect Buffer id */
+ union {
+ GPUDrawCommand *commands;
+ GPUDrawCommandIndexed *commands_indexed;
+ };
+};
+
+GPUDrawList *GPU_draw_list_create(int length)
+{
+ GPUDrawList *list = MEM_callocN(sizeof(GPUDrawList), "GPUDrawList");
+ /* Alloc the biggest possible command list which is indexed. */
+ list->buffer_size = sizeof(GPUDrawCommandIndexed) * length;
+ if (USE_MULTI_DRAW_INDIRECT) {
+ list->buffer_id = GPU_buf_alloc();
+ glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id);
+ glBufferData(GL_DRAW_INDIRECT_BUFFER, list->buffer_size, NULL, GL_DYNAMIC_DRAW);
+ }
+ else {
+ list->commands = MEM_mallocN(list->buffer_size, "GPUDrawList data");
+ }
+ return list;
+}
+
+void GPU_draw_list_discard(GPUDrawList *list)
+{
+ if (list->buffer_id) {
+ GPU_buf_free(list->buffer_id);
+ }
+ else {
+ MEM_SAFE_FREE(list->commands);
+ }
+ MEM_freeN(list);
+}
+
+void GPU_draw_list_init(GPUDrawList *list, GPUBatch *batch)
+{
+ BLI_assert(batch->phase == GPU_BATCH_READY_TO_DRAW);
+ list->batch = batch;
+ list->base_index = batch->elem ? BASE_INDEX(batch->elem) : UINT_MAX;
+ list->cmd_len = 0;
+
+ if (USE_MULTI_DRAW_INDIRECT) {
+ if (list->commands == NULL) {
+ glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id);
+ if (list->cmd_offset >= list->buffer_size) {
+ /* Orphan buffer data and start fresh. */
+ glBufferData(GL_DRAW_INDIRECT_BUFFER, list->buffer_size, NULL, GL_DYNAMIC_DRAW);
+ list->cmd_offset = 0;
+ }
+ GLenum flags = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT;
+ list->commands = glMapBufferRange(
+ GL_DRAW_INDIRECT_BUFFER, list->cmd_offset, list->buffer_size - list->cmd_offset, flags);
+ }
+ }
+ else {
+ list->cmd_offset = 0;
+ }
+}
+
+void GPU_draw_list_command_add(
+ GPUDrawList *list, int v_first, int v_count, int i_first, int i_count)
+{
+ BLI_assert(list->commands);
+
+ if (v_count == 0 || i_count == 0) {
+ return;
+ }
+
+ if (list->base_index != UINT_MAX) {
+ GPUDrawCommandIndexed *cmd = list->commands_indexed + list->cmd_len;
+ cmd->v_first = v_first;
+ cmd->v_count = v_count;
+ cmd->i_count = i_count;
+ cmd->base_index = list->base_index;
+ cmd->i_first = i_first;
+ }
+ else {
+ GPUDrawCommand *cmd = list->commands + list->cmd_len;
+ cmd->v_first = v_first;
+ cmd->v_count = v_count;
+ cmd->i_count = i_count;
+ cmd->i_first = i_first;
+ }
+
+ list->cmd_len++;
+ uint offset = list->cmd_offset + list->cmd_len * sizeof(GPUDrawCommandIndexed);
+
+ if (offset == list->buffer_size) {
+ GPU_draw_list_submit(list);
+ GPU_draw_list_init(list, list->batch);
+ }
+}
+
+void GPU_draw_list_submit(GPUDrawList *list)
+{
+ GPUBatch *batch = list->batch;
+
+ if (list->cmd_len == 0) {
+ return;
+ }
+
+ BLI_assert(list->commands);
+ BLI_assert(batch->program_in_use);
+ /* TODO could assert that VAO is bound. */
+
+ /* TODO We loose a bit of memory here if we only draw arrays. Fix that. */
+ uintptr_t offset = list->cmd_offset;
+ uint cmd_len = list->cmd_len;
+ size_t bytes_used = cmd_len * sizeof(GPUDrawCommandIndexed);
+ list->cmd_offset += bytes_used;
+ list->cmd_len = 0; /* Avoid reuse. */
+
+ if (USE_MULTI_DRAW_INDIRECT) {
+ GLenum prim = batch->gl_prim_type;
+
+ glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id);
+ glFlushMappedBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, bytes_used);
+ glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER);
+ list->commands = NULL; /* Unmapped */
+
+ if (batch->elem) {
+ glMultiDrawElementsIndirect(prim, INDEX_TYPE(batch->elem), (void *)offset, cmd_len, 0);
+ }
+ else {
+ glMultiDrawArraysIndirect(prim, (void *)offset, cmd_len, 0);
+ }
+ }
+ else {
+ /* Fallback */
+ if (batch->elem) {
+ GPUDrawCommandIndexed *cmd = list->commands_indexed;
+ for (int i = 0; i < cmd_len; i++, cmd++) {
+ GPU_batch_draw_advanced(batch, cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count);
+ }
+ }
+ else {
+ GPUDrawCommand *cmd = list->commands;
+ for (int i = 0; i < cmd_len; i++, cmd++) {
+ GPU_batch_draw_advanced(batch, cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count);
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Utilities
* \{ */
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 6eb8c80c58e..ed606ccb8c6 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -43,10 +43,10 @@
#include "BKE_pbvh.h"
#include "GPU_buffers.h"
-#include "GPU_draw.h"
-#include "GPU_immediate.h"
#include "GPU_batch.h"
+#include "gpu_private.h"
+
#include "bmesh.h"
/* XXX: the rest of the code in this file is used for optimized PBVH
@@ -80,6 +80,7 @@ struct GPU_PBVH_Buffers {
int totgrid;
bool use_bmesh;
+ bool clear_bmesh_on_flush;
uint tot_tri, tot_quad;
@@ -93,8 +94,9 @@ struct GPU_PBVH_Buffers {
};
static struct {
+ GPUVertFormat format;
uint pos, nor, msk, col;
-} g_vbo_id = {0};
+} g_vbo_id = {{0}};
/** \} */
@@ -102,6 +104,27 @@ static struct {
/** \name PBVH Utils
* \{ */
+void gpu_pbvh_init()
+{
+ /* Initialize vertex buffer (match 'VertexBufferFormat'). */
+ if (g_vbo_id.format.attr_len == 0) {
+ g_vbo_id.pos = GPU_vertformat_attr_add(
+ &g_vbo_id.format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ g_vbo_id.nor = GPU_vertformat_attr_add(
+ &g_vbo_id.format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */
+ g_vbo_id.msk = GPU_vertformat_attr_add(
+ &g_vbo_id.format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ g_vbo_id.col = GPU_vertformat_attr_add(
+ &g_vbo_id.format, "ac", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+}
+
+void gpu_pbvh_exit()
+{
+ /* Nothing to do. */
+}
+
/* Allocates a non-initialized buffer to be sent to GPU.
* Return is false it indicates that the memory map failed. */
static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len)
@@ -112,14 +135,7 @@ static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len)
#if 0
if (buffers->vert_buf == NULL) {
/* Initialize vertex buffer (match 'VertexBufferFormat'). */
- static GPUVertFormat format = {0};
- if (format.attr_len == 0) {
- g_vbo_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- g_vbo_id.nor = GPU_vertformat_attr_add(
- &format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- g_vbo_id.msk = GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- }
- buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_DYNAMIC);
+ buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_DYNAMIC);
GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len);
}
else if (vert_len != buffers->vert_buf->vertex_len) {
@@ -128,30 +144,16 @@ static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len)
#else
if (buffers->vert_buf == NULL) {
/* Initialize vertex buffer (match 'VertexBufferFormat'). */
- static GPUVertFormat format = {0};
- if (format.attr_len == 0) {
- g_vbo_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- g_vbo_id.nor = GPU_vertformat_attr_add(
- &format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */
- g_vbo_id.msk = GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- g_vbo_id.col = GPU_vertformat_attr_add(
- &format, "ac", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- }
- buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_STATIC);
+ buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_STATIC);
}
GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len);
#endif
+
return buffers->vert_buf->data != NULL;
}
static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers, GPUPrimType prim)
{
- /* force flushing to the GPU */
- if (buffers->vert_buf->data) {
- GPU_vertbuf_use(buffers->vert_buf);
- }
-
if (buffers->triangles == NULL) {
buffers->triangles = GPU_batch_create(prim,
buffers->vert_buf,
@@ -182,6 +184,7 @@ static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers, GPUPrimType prim)
/** \name Mesh PBVH
* \{ */
+/* Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const MVert *mvert,
const int *vert_indices,
@@ -191,8 +194,8 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const int (*face_vert_indices)[3],
const int update_flags)
{
- const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
- const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
+ const bool show_mask = vmask && (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
+ const bool show_vcol = vcol && (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
bool empty_mask = true;
{
@@ -200,30 +203,38 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
/* Build VBO */
if (gpu_pbvh_vert_buf_data_set(buffers, totelem)) {
+ GPUVertBufRaw pos_step = {0};
+ GPUVertBufRaw nor_step = {0};
+ GPUVertBufRaw msk_step = {0};
+ GPUVertBufRaw col_step = {0};
+
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.pos, &pos_step);
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.nor, &nor_step);
+ if (show_mask) {
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.msk, &msk_step);
+ }
+ if (show_vcol) {
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.col, &col_step);
+ }
+
/* Vertex data is shared if smooth-shaded, but separate
* copies are made for flat shading because normals
* shouldn't be shared. */
if (buffers->smooth) {
- for (uint i = 0; i < totvert; ++i) {
- const MVert *v = &mvert[vert_indices[i]];
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, i, v->co);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, i, v->no);
- }
-
- if (vmask && show_mask) {
- for (uint i = 0; i < buffers->face_indices_len; i++) {
- const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
- for (uint j = 0; j < 3; j++) {
- int vidx = face_vert_indices[i][j];
- int v_index = buffers->mloop[lt->tri[j]].v;
- float fmask = vmask[v_index];
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vidx, &fmask);
- empty_mask = empty_mask && (fmask == 0.0f);
- }
+ for (uint i = 0; i < totvert; i++) {
+ const int vidx = vert_indices[i];
+ const MVert *v = &mvert[vidx];
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), v->co);
+ copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), v->no);
+
+ if (show_mask) {
+ float mask = vmask[vidx];
+ *(float *)GPU_vertbuf_raw_step(&msk_step) = mask;
+ empty_mask = empty_mask && (mask == 0.0f);
}
}
- if (vcol && show_vcol) {
+ if (show_vcol) {
for (uint i = 0; i < buffers->face_indices_len; i++) {
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
for (int j = 0; j < 3; j++) {
@@ -238,8 +249,7 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
else {
/* calculate normal for each polygon only once */
uint mpoly_prev = UINT_MAX;
- short no[3];
- int vbo_index = 0;
+ short no[3] = {0, 0, 0};
for (uint i = 0; i < buffers->face_indices_len; i++) {
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
@@ -263,27 +273,26 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
}
float fmask = 0.0f;
- if (vmask && show_mask) {
+ if (show_mask) {
fmask = (vmask[vtri[0]] + vmask[vtri[1]] + vmask[vtri[2]]) / 3.0f;
}
for (uint j = 0; j < 3; j++) {
const MVert *v = &mvert[vtri[j]];
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index, v->co);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index, no);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index, &fmask);
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), v->co);
+ copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), no);
+ if (show_mask) {
+ *(float *)GPU_vertbuf_raw_step(&msk_step) = fmask;
+ empty_mask = empty_mask && (fmask == 0.0f);
+ }
- if (vcol && show_vcol) {
+ if (show_vcol) {
const uint loop_index = lt->tri[j];
const uchar *elem = &vcol[loop_index].r;
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index, elem);
+ memcpy(GPU_vertbuf_raw_step(&col_step), elem, sizeof(uchar) * 4);
}
-
- vbo_index++;
}
-
- empty_mask = empty_mask && (fmask == 0.0f);
}
}
@@ -300,6 +309,7 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
buffers->mvert = mvert;
}
+/* Threaded - do not call any functions that use OpenGL calls! */
GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
const MPoly *mpoly,
const MLoop *mloop,
@@ -319,7 +329,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
buffers->show_mask = false;
/* Count the number of visible triangles */
- for (i = 0, tottri = 0; i < face_indices_len; ++i) {
+ for (i = 0, tottri = 0; i < face_indices_len; i++) {
const MLoopTri *lt = &looptri[face_indices[i]];
if (!paint_is_face_hidden(lt, mvert, mloop)) {
tottri++;
@@ -338,11 +348,6 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
return buffers;
}
- GPU_BATCH_DISCARD_SAFE(buffers->triangles);
- GPU_BATCH_DISCARD_SAFE(buffers->lines);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
-
/* An element index buffer is used for smooth shading, but flat
* shading requires separate vertex normals so an index buffer
* can't be used there. */
@@ -352,7 +357,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, INT_MAX);
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, INT_MAX);
- for (i = 0; i < face_indices_len; ++i) {
+ for (i = 0; i < face_indices_len; i++) {
const MLoopTri *lt = &looptri[face_indices[i]];
/* Skip hidden faces */
@@ -376,7 +381,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, INT_MAX);
int vert_idx = 0;
- for (i = 0; i < face_indices_len; ++i) {
+ for (i = 0; i < face_indices_len; i++) {
const MLoopTri *lt = &looptri[face_indices[i]];
/* Skip hidden faces */
@@ -431,8 +436,8 @@ static void gpu_pbvh_grid_fill_index_buffers(
BLI_bitmap *gh = buffers->grid_hidden[grid_indices[i]];
- for (int j = 0; j < gridsize - 1; ++j) {
- for (int k = 0; k < gridsize - 1; ++k) {
+ for (int j = 0; j < gridsize - 1; j++) {
+ for (int k = 0; k < gridsize - 1; k++) {
/* Skip hidden grid face */
if (gh && paint_is_grid_face_hidden(gh, gridsize, k, j)) {
continue;
@@ -454,7 +459,10 @@ static void gpu_pbvh_grid_fill_index_buffers(
}
grid_visible = true;
}
- GPU_indexbuf_add_line_verts(&elb_lines, v1, v2);
+
+ if (grid_visible) {
+ GPU_indexbuf_add_line_verts(&elb_lines, v1, v2);
+ }
}
if (grid_visible) {
@@ -506,7 +514,10 @@ static void gpu_pbvh_grid_fill_index_buffers(
}
grid_visible = true;
}
- GPU_indexbuf_add_line_verts(&elb_lines, v1, v2);
+
+ if (grid_visible) {
+ GPU_indexbuf_add_line_verts(&elb_lines, v1, v2);
+ }
}
if (grid_visible) {
@@ -533,6 +544,27 @@ static void gpu_pbvh_grid_fill_index_buffers(
buffers->index_lines_buf_fast = GPU_indexbuf_build(&elb_lines_fast);
}
+void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers,
+ const struct DMFlagMat *grid_flag_mats,
+ int *grid_indices)
+{
+ const bool smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
+
+ if (buffers->smooth != smooth) {
+ buffers->smooth = smooth;
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles);
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast);
+ GPU_BATCH_DISCARD_SAFE(buffers->lines);
+ GPU_BATCH_DISCARD_SAFE(buffers->lines_fast);
+
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf_fast);
+ }
+}
+
+/* Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
CCGElem **grids,
const DMFlagMat *grid_flag_mats,
@@ -546,26 +578,13 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
bool empty_mask = true;
int i, j, k, x, y;
- const bool smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
-
/* Build VBO */
const int has_mask = key->has_mask;
- uint vert_per_grid = (smooth) ? key->grid_area : (SQUARE(key->grid_size - 1) * 4);
- uint vert_count = totgrid * vert_per_grid;
+ buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
- if (buffers->smooth != smooth) {
- buffers->smooth = smooth;
- GPU_BATCH_DISCARD_SAFE(buffers->triangles);
- GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast);
- GPU_BATCH_DISCARD_SAFE(buffers->lines);
- GPU_BATCH_DISCARD_SAFE(buffers->lines_fast);
-
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf_fast);
- }
+ uint vert_per_grid = (buffers->smooth) ? key->grid_area : (SQUARE(key->grid_size - 1) * 4);
+ uint vert_count = totgrid * vert_per_grid;
if (buffers->index_buf == NULL) {
uint visible_quad_len = BKE_pbvh_count_grid_quads(
@@ -589,7 +608,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, totgrid * key->grid_area * 2, vert_count);
}
- for (i = 0; i < totgrid; ++i) {
+ for (i = 0; i < totgrid; i++) {
CCGElem *grid = grids[grid_indices[i]];
int vbo_index = vbo_index_offset;
@@ -688,6 +707,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
buffers->show_mask = !empty_mask;
}
+/* Threaded - do not call any functions that use OpenGL calls! */
GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hidden)
{
GPU_PBVH_Buffers *buffers;
@@ -792,8 +812,24 @@ static int gpu_bmesh_face_visible_count(GSet *bm_faces)
return totface;
}
+void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers)
+{
+ if (buffers->smooth) {
+ /* Smooth needs to recreate index buffer, so we have to invalidate the batch. */
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles);
+ GPU_BATCH_DISCARD_SAFE(buffers->lines);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
+ }
+ else {
+ GPU_BATCH_DISCARD_SAFE(buffers->lines);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
+ }
+}
+
/* Creates a vertex buffer (coordinate, normal, color) and, if smooth
- * shading, an element index buffer. */
+ * shading, an element index buffer.
+ * Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
BMesh *bm,
GSet *bm_faces,
@@ -805,23 +841,16 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
int tottri, totvert, maxvert = 0;
bool empty_mask = true;
- BMFace *f;
+ BMFace *f = NULL;
/* Count visible triangles */
tottri = gpu_bmesh_face_visible_count(bm_faces);
if (buffers->smooth) {
- /* Smooth needs to recreate index buffer, so we have to invalidate the batch. */
- GPU_BATCH_DISCARD_SAFE(buffers->triangles);
- GPU_BATCH_DISCARD_SAFE(buffers->lines);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
/* Count visible vertices */
totvert = gpu_bmesh_vert_visible_count(bm_unique_verts, bm_other_verts);
}
else {
- GPU_BATCH_DISCARD_SAFE(buffers->lines);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
totvert = tottri * 3;
}
@@ -830,9 +859,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
/* Node is just hidden. */
}
else {
- GPU_BATCH_DISCARD_SAFE(buffers->triangles);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
- GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf);
+ buffers->clear_bmesh_on_flush = true;
}
buffers->tot_tri = 0;
return;
@@ -950,7 +977,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
BM_face_as_array_vert_tri(f, v);
- uint idx[3] = {
+ const uint idx[3] = {
BM_elem_index_get(v[0]), BM_elem_index_get(v[1]), BM_elem_index_get(v[2])};
GPU_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]);
@@ -974,7 +1001,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
}
/* Get material index from the last face we iterated on. */
- buffers->material_index = f->mat_nr;
+ buffers->material_index = (f) ? f->mat_nr : 0;
buffers->show_mask = !empty_mask;
@@ -987,6 +1014,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
/** \name Generic
* \{ */
+/* Threaded - do not call any functions that use OpenGL calls! */
GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading)
{
GPU_PBVH_Buffers *buffers;
@@ -1019,6 +1047,21 @@ short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers)
return buffers->material_index;
}
+void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers)
+{
+ /* Free empty bmesh node buffers. */
+ if (buffers->clear_bmesh_on_flush) {
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
+ GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf);
+ }
+
+ /* Force flushing to the GPU. */
+ if (buffers->vert_buf && buffers->vert_buf->data) {
+ GPU_vertbuf_use(buffers->vert_buf);
+ }
+}
+
void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers)
{
if (buffers) {
@@ -1037,7 +1080,3 @@ void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers)
}
/** \} */
-
-void GPU_pbvh_fix_linking()
-{
-}
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 55337596cbe..410e23c9576 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -44,13 +44,13 @@
#include "GPU_glew.h"
#include "GPU_material.h"
#include "GPU_shader.h"
-#include "GPU_texture.h"
#include "GPU_uniformbuffer.h"
#include "GPU_vertex_format.h"
#include "BLI_sys_types.h" /* for intptr_t support */
#include "gpu_codegen.h"
+#include "gpu_material_library.h"
#include <string.h>
#include <stdarg.h>
@@ -58,7 +58,8 @@
extern char datatoc_gpu_shader_material_glsl[];
extern char datatoc_gpu_shader_geometry_glsl[];
-static char *glsl_material_library = NULL;
+extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
+extern char datatoc_common_view_lib_glsl[];
/* -------------------- GPUPass Cache ------------------ */
/**
@@ -147,6 +148,7 @@ typedef struct GPUFunction {
eGPUType paramtype[MAX_PARAMETER];
GPUFunctionQual paramqual[MAX_PARAMETER];
int totparam;
+ GPUMaterialLibrary *library;
} GPUFunction;
/* Indices match the eGPUType enum */
@@ -230,15 +232,17 @@ static char *gpu_str_skip_token(char *str, char *token, int max)
return str;
}
-static void gpu_parse_functions_string(GHash *hash, char *code)
+static void gpu_parse_material_library(GHash *hash, GPUMaterialLibrary *library)
{
GPUFunction *function;
eGPUType type;
GPUFunctionQual qual;
int i;
+ char *code = library->code;
while ((code = strstr(code, "void "))) {
function = MEM_callocN(sizeof(GPUFunction), "GPUFunction");
+ function->library = library;
code = gpu_str_skip_token(code, NULL, 0);
code = gpu_str_skip_token(code, function->name, MAX_FUNCTION_NAME);
@@ -367,11 +371,6 @@ static char *gpu_generate_function_prototyps(GHash *hash)
static GPUFunction *gpu_lookup_function(const char *name)
{
- if (!FUNCTION_HASH) {
- FUNCTION_HASH = BLI_ghash_str_new("GPU_lookup_function gh");
- gpu_parse_functions_string(FUNCTION_HASH, glsl_material_library);
- }
-
return BLI_ghash_lookup(FUNCTION_HASH, (const void *)name);
}
@@ -395,11 +394,6 @@ void gpu_codegen_exit(void)
GPU_shader_free_builtin_shaders();
- if (glsl_material_library) {
- MEM_freeN(glsl_material_library);
- glsl_material_library = NULL;
- }
-
#if 0
if (FUNCTION_PROTOTYPES) {
MEM_freeN(FUNCTION_PROTOTYPES);
@@ -425,7 +419,7 @@ static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *t
}
else if (to == GPU_FLOAT) {
if (from == GPU_VEC4) {
- BLI_dynstr_appendf(ds, "convert_rgba_to_float(%s)", name);
+ BLI_dynstr_appendf(ds, "dot(%s.rgb, vec3(0.2126, 0.7152, 0.0722))", name);
}
else if (from == GPU_VEC3) {
BLI_dynstr_appendf(ds, "(%s.r + %s.g + %s.b) / 3.0", name, name, name);
@@ -790,6 +784,12 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final
else if (input->builtin == GPU_OBJECT_MATRIX) {
BLI_dynstr_append(ds, "objmat");
}
+ else if (input->builtin == GPU_OBJECT_INFO) {
+ BLI_dynstr_append(ds, "ObjectInfo");
+ }
+ else if (input->builtin == GPU_OBJECT_COLOR) {
+ BLI_dynstr_append(ds, "ObjectColor");
+ }
else if (input->builtin == GPU_INVERSE_OBJECT_MATRIX) {
BLI_dynstr_append(ds, "objinv");
}
@@ -852,6 +852,10 @@ static char *code_generate_fragment(GPUMaterial *material,
codegen_set_unique_ids(nodes);
*rbuiltins = builtins = codegen_process_uniforms_functions(material, ds, nodes);
+ if (builtins & (GPU_OBJECT_INFO | GPU_OBJECT_COLOR)) {
+ BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl);
+ }
+
if (builtins & GPU_BARYCENTRIC_TEXCO) {
BLI_dynstr_append(ds, "in vec2 barycentricTexCo;\n");
}
@@ -1000,7 +1004,7 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
/* NOTE : Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */
if (input->attr_type == CD_ORCO) {
/* OPTI : orco is computed from local positions, but only if no modifier is present. */
- BLI_dynstr_append(ds, "uniform vec3 OrcoTexCoFactors[2];\n");
+ BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl);
BLI_dynstr_append(ds, "DEFINE_ATTR(vec4, orco);\n");
}
else if (input->attr_name[0] == '\0') {
@@ -1082,6 +1086,8 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
BLI_dynstr_append(ds, "\n");
+ BLI_dynstr_append(ds, use_geom ? "RESOURCE_ID_VARYING_GEOM\n" : "RESOURCE_ID_VARYING\n");
+
BLI_dynstr_append(ds,
"#define USE_ATTR\n"
"vec3 srgb_to_linear_attr(vec3 c) {\n"
@@ -1091,6 +1097,15 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
"\treturn mix(c1, c2, step(vec3(0.04045), c));\n"
"}\n\n");
+ BLI_dynstr_append(ds,
+ "vec4 srgba_to_linear_attr(vec4 c) {\n"
+ "\tc = max(c, vec4(0.0));\n"
+ "\tvec4 c1 = c * (1.0 / 12.92);\n"
+ "\tvec4 c2 = pow((c + 0.055) * (1.0 / 1.055), vec4(2.4));\n"
+ "\tvec4 final = mix(c1, c2, step(vec4(0.04045), c));"
+ "\treturn vec4(final.xyz, c.a);\n"
+ "}\n\n");
+
/* Prototype because defined later. */
BLI_dynstr_append(ds,
"vec2 hair_get_customdata_vec2(const samplerBuffer);\n"
@@ -1102,6 +1117,8 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
BLI_dynstr_append(ds, "void pass_attr(in vec3 position) {\n");
+ BLI_dynstr_append(ds, use_geom ? "\tPASS_RESOURCE_ID_GEOM\n" : "\tPASS_RESOURCE_ID\n");
+
BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n");
if (builtins & GPU_BARYCENTRIC_TEXCO) {
@@ -1128,8 +1145,8 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
}
else if (input->attr_type == CD_ORCO) {
BLI_dynstr_appendf(ds,
- "\tvar%d%s = OrcoTexCoFactors[0] + (ModelMatrixInverse * "
- "vec4(hair_get_strand_pos(), 1.0)).xyz * OrcoTexCoFactors[1];\n",
+ "\tvar%d%s = OrcoTexCoFactors[0].xyz + (ModelMatrixInverse * "
+ "vec4(hair_get_strand_pos(), 1.0)).xyz * OrcoTexCoFactors[1].xyz;\n",
input->attr_id,
use_geom ? "g" : "");
/* TODO: fix ORCO with modifiers. */
@@ -1184,7 +1201,8 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
}
else if (input->attr_type == CD_ORCO) {
BLI_dynstr_appendf(ds,
- "\tvar%d%s = OrcoTexCoFactors[0] + position * OrcoTexCoFactors[1];\n",
+ "\tvar%d%s = OrcoTexCoFactors[0].xyz + position *"
+ " OrcoTexCoFactors[1].xyz;\n",
input->attr_id,
use_geom ? "g" : "");
/* See mesh_create_loop_orco() for explanation. */
@@ -1195,7 +1213,7 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
}
else if (input->attr_type == CD_MCOL) {
BLI_dynstr_appendf(ds,
- "\tvar%d%s = srgb_to_linear_attr(att%d);\n",
+ "\tvar%d%s = srgba_to_linear_attr(att%d);\n",
input->attr_id,
use_geom ? "g" : "",
input->attr_id);
@@ -1299,6 +1317,8 @@ static char *code_generate_geometry(ListBase *nodes, const char *geom_code, cons
BLI_dynstr_append(ds, "out vec3 worldNormal;\n");
BLI_dynstr_append(ds, "out vec3 viewNormal;\n");
+ BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
+
BLI_dynstr_append(ds, "void main(){\n");
if (builtins & GPU_BARYCENTRIC_DIST) {
@@ -1318,7 +1338,7 @@ static char *code_generate_geometry(ListBase *nodes, const char *geom_code, cons
BLI_dynstr_append(ds, "\tgl_Position = gl_in[2].gl_Position;\n");
BLI_dynstr_append(ds, "\tpass_attr(2);\n");
BLI_dynstr_append(ds, "\tEmitVertex();\n");
- BLI_dynstr_append(ds, "};\n");
+ BLI_dynstr_append(ds, "}\n");
}
}
else {
@@ -1343,9 +1363,13 @@ static char *code_generate_geometry(ListBase *nodes, const char *geom_code, cons
BLI_dynstr_append(ds, "}\n");
}
+ BLI_dynstr_append(ds, "RESOURCE_ID_VARYING\n");
+
/* Generate varying assignments. */
BLI_dynstr_append(ds, "void pass_attr(in int vert) {\n");
+ BLI_dynstr_append(ds, "\tPASS_RESOURCE_ID(vert)\n");
+
/* XXX HACK: Eevee specific. */
if (geom_code == NULL) {
BLI_dynstr_append(ds, "\tworldPosition = worldPositiong[vert];\n");
@@ -1381,20 +1405,15 @@ static char *code_generate_geometry(ListBase *nodes, const char *geom_code, cons
void GPU_code_generate_glsl_lib(void)
{
- DynStr *ds;
-
- /* only initialize the library once */
- if (glsl_material_library) {
+ /* Only parse GLSL shader files once. */
+ if (FUNCTION_HASH) {
return;
}
- ds = BLI_dynstr_new();
-
- BLI_dynstr_append(ds, datatoc_gpu_shader_material_glsl);
-
- glsl_material_library = BLI_dynstr_get_cstring(ds);
-
- BLI_dynstr_free(ds);
+ FUNCTION_HASH = BLI_ghash_str_new("GPU_lookup_function gh");
+ for (int i = 0; gpu_material_libraries[i]; i++) {
+ gpu_parse_material_library(FUNCTION_HASH, gpu_material_libraries[i]);
+ }
}
/* GPU pass binding/unbinding */
@@ -1796,6 +1815,22 @@ GPUNodeLink *GPU_builtin(eGPUBuiltin builtin)
return link;
}
+static void gpu_material_use_library_with_dependencies(GSet *used_libraries,
+ GPUMaterialLibrary *library)
+{
+ if (BLI_gset_add(used_libraries, library->code)) {
+ for (int i = 0; library->dependencies[i]; i++) {
+ gpu_material_use_library_with_dependencies(used_libraries, library->dependencies[i]);
+ }
+ }
+}
+
+static void gpu_material_use_library(GPUMaterial *material, GPUMaterialLibrary *library)
+{
+ GSet *used_libraries = gpu_material_used_libraries(material);
+ gpu_material_use_library_with_dependencies(used_libraries, library);
+}
+
bool GPU_link(GPUMaterial *mat, const char *name, ...)
{
GPUNode *node;
@@ -1810,6 +1845,8 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...)
return false;
}
+ gpu_material_use_library(mat, function->library);
+
node = GPU_node_begin(name);
va_start(params, name);
@@ -1849,6 +1886,8 @@ bool GPU_stack_link(GPUMaterial *material,
return false;
}
+ gpu_material_use_library(material, function->library);
+
node = GPU_node_begin(name);
totin = 0;
totout = 0;
@@ -1962,6 +2001,34 @@ static bool gpu_pass_is_valid(GPUPass *pass)
return (pass->compiled == false || pass->shader != NULL);
}
+static char *code_generate_material_library(GPUMaterial *material, const char *frag_lib)
+{
+ DynStr *ds = BLI_dynstr_new();
+
+ if (frag_lib) {
+ BLI_dynstr_append(ds, frag_lib);
+ }
+
+ GSet *used_libraries = gpu_material_used_libraries(material);
+
+ /* Always include those because they may be needed by the execution function. */
+ gpu_material_use_library_with_dependencies(used_libraries,
+ &gpu_shader_material_world_normals_library);
+
+ /* Add library code in order, for dependencies. */
+ for (int i = 0; gpu_material_libraries[i]; i++) {
+ GPUMaterialLibrary *library = gpu_material_libraries[i];
+ if (BLI_gset_haskey(used_libraries, library->code)) {
+ BLI_dynstr_append(ds, library->code);
+ }
+ }
+
+ char *result = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+
+ return result;
+}
+
GPUPass *GPU_generate_pass(GPUMaterial *material,
GPUNodeLink *frag_outlink,
struct GPUVertAttrLayers *attrs,
@@ -2000,7 +2067,7 @@ GPUPass *GPU_generate_pass(GPUMaterial *material,
/* Either the shader is not compiled or there is a hash collision...
* continue generating the shader strings. */
- char *tmp = BLI_strdupcat(frag_lib, glsl_material_library);
+ char *tmp = code_generate_material_library(material, frag_lib);
geometrycode = code_generate_geometry(nodes, geom_code, defines);
vertexcode = code_generate_vertex(nodes, vert_code, (geometrycode != NULL));
@@ -2097,7 +2164,7 @@ static int count_active_texture_sampler(GPUShader *shader, char *source)
}
/* Catch duplicates. */
bool is_duplicate = false;
- for (int i = 0; i < sampler_len; ++i) {
+ for (int i = 0; i < sampler_len; i++) {
if (samplers_id[i] == id) {
is_duplicate = true;
}
diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h
index 6eb6bc2f05f..4e09f16ebf8 100644
--- a/source/blender/gpu/intern/gpu_codegen.h
+++ b/source/blender/gpu/intern/gpu_codegen.h
@@ -33,6 +33,7 @@ struct GPUNode;
struct GPUOutput;
struct GPUShader;
struct GPUVertAttrLayers;
+struct GSet;
struct ListBase;
/* Pass Generation
@@ -207,4 +208,6 @@ struct GPUTexture **gpu_material_ramp_texture_row_set(GPUMaterial *mat,
float *pixels,
float *row);
+struct GSet *gpu_material_used_libraries(struct GPUMaterial *material);
+
#endif
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index be3655648f5..c9ae6c60293 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -66,9 +66,6 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_glew.h"
-#include "GPU_material.h"
-#include "GPU_matrix.h"
-#include "GPU_shader.h"
#include "GPU_texture.h"
#include "PIL_time.h"
@@ -348,7 +345,7 @@ static void gpu_texture_update_scaled(
}
/* Scale pixels. */
- ImBuf *ibuf = IMB_allocFromBuffer((uint *)rect, rect_float, w, h);
+ ImBuf *ibuf = IMB_allocFromBuffer((uint *)rect, rect_float, w, h, 4);
IMB_scaleImBuf(ibuf, sub_w, sub_h);
if (ibuf->rect_float) {
@@ -648,13 +645,13 @@ void GPU_create_gl_tex(uint *bind,
recth = smaller_power_of_2_limit(recth);
if (frect) {
- ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy);
+ ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy, 4);
IMB_scaleImBuf(ibuf, rectw, recth);
frect = ibuf->rect_float;
}
else {
- ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy);
+ ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy, 4);
IMB_scaleImBuf(ibuf, rectw, recth);
rect = ibuf->rect;
@@ -794,7 +791,7 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf, bool use_srgb)
}
blocksize = (ibuf->dds_data.fourcc == FOURCC_DXT1) ? 8 : 16;
- for (i = 0; i < ibuf->dds_data.nummipmaps && (width || height); ++i) {
+ for (i = 0; i < ibuf->dds_data.nummipmaps && (width || height); i++) {
if (width == 0) {
width = 1;
}
diff --git a/source/blender/gpu/intern/gpu_element.c b/source/blender/gpu/intern/gpu_element.c
index 3f3f246d6d9..166a6236893 100644
--- a/source/blender/gpu/intern/gpu_element.c
+++ b/source/blender/gpu/intern/gpu_element.c
@@ -269,7 +269,7 @@ static uint index_range(const uint values[], uint value_len, uint *min_out, uint
}
uint min_value = RESTART_INDEX;
uint max_value = 0;
- for (uint i = 0; i < value_len; ++i) {
+ for (uint i = 0; i < value_len; i++) {
const uint value = values[i];
if (value == RESTART_INDEX) {
continue;
@@ -307,13 +307,13 @@ static void squeeze_indices_short(GPUIndexBufBuilder *builder,
if (max_index >= 0xFFFF) {
elem->base_index = min_index;
- for (uint i = 0; i < index_len; ++i) {
+ for (uint i = 0; i < index_len; i++) {
data[i] = (values[i] == RESTART_INDEX) ? 0xFFFF : (GLushort)(values[i] - min_index);
}
}
else {
elem->base_index = 0;
- for (uint i = 0; i < index_len; ++i) {
+ for (uint i = 0; i < index_len; i++) {
data[i] = (GLushort)(values[i]);
}
}
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index 5839b34cd19..c6425854ee4 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -365,10 +365,13 @@ void gpu_extensions_init(void)
GG.mip_render_workaround = true;
GG.depth_blitting_workaround = true;
GG.unused_fb_slot_workaround = true;
- GG.context_local_shaders_workaround = true;
+ GG.context_local_shaders_workaround = GLEW_ARB_get_program_binary;
}
/* df/dy calculation factors, those are dependent on driver */
+ GG.dfdyfactors[0] = 1.0;
+ GG.dfdyfactors[1] = 1.0;
+
if ((strstr(vendor, "ATI") && strstr(version, "3.3.10750"))) {
GG.dfdyfactors[0] = 1.0;
GG.dfdyfactors[1] = -1.0;
@@ -383,18 +386,26 @@ void gpu_extensions_init(void)
GG.dfdyfactors[0] = -1.0;
GG.dfdyfactors[1] = 1.0;
}
- else {
- GG.dfdyfactors[0] = 1.0;
- GG.dfdyfactors[1] = 1.0;
- }
if (strstr(version, "Build 10.18.10.3") || strstr(version, "Build 10.18.10.4") ||
- strstr(version, "Build 10.18.14.4") || strstr(version, "Build 10.18.14.5")) {
+ strstr(version, "Build 10.18.10.5") || strstr(version, "Build 10.18.14.4") ||
+ strstr(version, "Build 10.18.14.5")) {
/* Maybe not all of these drivers have problems with `GLEW_ARB_base_instance`.
* But it's hard to test each case. */
GG.glew_arb_base_instance_is_supported = false;
GG.context_local_shaders_workaround = true;
}
+
+ if (strstr(version, "Build 20.19.15.4285")) {
+ /* Somehow fixes armature display issues (see T69743). */
+ GG.context_local_shaders_workaround = true;
+ }
+ }
+ else if ((GG.device == GPU_DEVICE_ATI) && (GG.os == GPU_OS_UNIX) &&
+ (GG.driver == GPU_DRIVER_OPENSOURCE)) {
+ /* See T70187: merging vertices fail. This has been tested from 18.2.2 till 19.3.0~dev of the
+ * Mesa driver */
+ GG.unused_fb_slot_workaround = true;
}
GPU_invalid_tex_init();
diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c
index 7d096058e4c..a531c22365c 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.c
+++ b/source/blender/gpu/intern/gpu_framebuffer.c
@@ -31,7 +31,6 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_framebuffer.h"
-#include "GPU_matrix.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
@@ -46,8 +45,9 @@ typedef enum {
GPU_FB_COLOR_ATTACHMENT2,
GPU_FB_COLOR_ATTACHMENT3,
GPU_FB_COLOR_ATTACHMENT4,
+ GPU_FB_COLOR_ATTACHMENT5,
/* Number of maximum output slots.
- * We support 5 outputs for now (usually we wouldn't need more to preserve fill rate). */
+ * We support 6 outputs for now (usually we wouldn't need more to preserve fill rate). */
/* Keep in mind that GL max is GL_MAX_DRAW_BUFFERS and is at least 8, corresponding to
* the maximum number of COLOR attachments specified by glDrawBuffers. */
GPU_FB_MAX_ATTACHEMENT,
@@ -82,6 +82,7 @@ static GLenum convert_attachment_type_to_gl(GPUAttachmentType type)
[GPU_FB_COLOR_ATTACHMENT2] = GL_COLOR_ATTACHMENT2,
[GPU_FB_COLOR_ATTACHMENT3] = GL_COLOR_ATTACHMENT3,
[GPU_FB_COLOR_ATTACHMENT4] = GL_COLOR_ATTACHMENT4,
+ [GPU_FB_COLOR_ATTACHMENT5] = GL_COLOR_ATTACHMENT5,
};
return table[type];
}
@@ -131,9 +132,11 @@ static void gpu_print_framebuffer_error(GLenum status, char err_out[256])
const char *err = "unknown";
#define FORMAT_STATUS(X) \
- case GL_FRAMEBUFFER_##X: \
+ case GL_FRAMEBUFFER_##X: { \
err = "GL_FRAMEBUFFER_" #X; \
- break;
+ break; \
+ } \
+ ((void)0)
switch (status) {
/* success */
@@ -330,7 +333,7 @@ void GPU_framebuffer_config_array(GPUFrameBuffer *fb, const GPUAttachment *confi
}
int slot = 0;
- for (int i = 1; i < config_len; ++i, ++slot) {
+ for (int i = 1; i < config_len; i++, slot++) {
if (config[i].tex != NULL) {
BLI_assert(GPU_texture_depth(config[i].tex) == false);
gpu_framebuffer_texture_attach_ex(fb, config[i].tex, slot, config[i].layer, config[i].mip);
@@ -384,7 +387,7 @@ static void gpu_framebuffer_update_attachments(GPUFrameBuffer *fb)
BLI_assert(GPU_framebuffer_active_get() == fb);
/* Update attachments */
- for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) {
+ for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; type++) {
if (type >= GPU_FB_COLOR_ATTACHMENT0) {
if (fb->attachments[type].tex) {
@@ -755,7 +758,7 @@ void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *fb,
current_dim[0] = max_ii(current_dim[0] / 2, 1);
current_dim[1] = max_ii(current_dim[1] / 2, 1);
- for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) {
+ for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; type++) {
if (fb->attachments[type].tex != NULL) {
/* Some Intel HDXXX have issue with rendering to a mipmap that is below
* the texture GL_TEXTURE_MAX_LEVEL. So even if it not correct, in this case
@@ -784,7 +787,7 @@ void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *fb,
}
}
- for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) {
+ for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; type++) {
if (fb->attachments[type].tex != NULL) {
/* reset mipmap level range */
GPUTexture *tex = fb->attachments[type].tex;
diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.c
index 0e3019ad122..bed7ab25bb9 100644
--- a/source/blender/gpu/intern/gpu_immediate.c
+++ b/source/blender/gpu/intern/gpu_immediate.c
@@ -72,8 +72,9 @@ typedef struct {
uint16_t prev_enabled_attr_bits; /* <-- only affects this VAO, so we're ok */
} Immediate;
-/* size of internal buffer -- make this adjustable? */
-#define IMM_BUFFER_SIZE (4 * 1024 * 1024)
+/* size of internal buffer */
+#define DEFAULT_INTERNAL_BUFFER_SIZE (4 * 1024 * 1024)
+static uint imm_buffer_size = DEFAULT_INTERNAL_BUFFER_SIZE;
static bool initialized = false;
static Immediate imm;
@@ -87,7 +88,7 @@ void immInit(void)
imm.vbo_id = GPU_buf_alloc();
glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id);
- glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, imm_buffer_size, NULL, GL_DYNAMIC_DRAW);
imm.prim_type = GPU_PRIM_NONE;
imm.strict_vertex_len = true;
@@ -211,26 +212,35 @@ void immBegin(GPUPrimType prim_type, uint vertex_len)
/* how many bytes do we need for this draw call? */
const uint bytes_needed = vertex_buffer_size(&imm.vertex_format, vertex_len);
-#if TRUST_NO_ONE
- assert(bytes_needed <= IMM_BUFFER_SIZE);
-#endif
-
glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id);
/* does the current buffer have enough room? */
- const uint available_bytes = IMM_BUFFER_SIZE - imm.buffer_offset;
- /* ensure vertex data is aligned */
+ const uint available_bytes = imm_buffer_size - imm.buffer_offset;
+ bool recreate_buffer = false;
+ if (bytes_needed > imm_buffer_size) {
+ /* expand the internal buffer */
+ imm_buffer_size = bytes_needed;
+ recreate_buffer = true;
+ }
+ else if (bytes_needed < DEFAULT_INTERNAL_BUFFER_SIZE &&
+ imm_buffer_size > DEFAULT_INTERNAL_BUFFER_SIZE) {
+ /* shrink the internal buffer */
+ imm_buffer_size = DEFAULT_INTERNAL_BUFFER_SIZE;
+ recreate_buffer = true;
+ }
+
+ /* ensure vertex data is aligned */
/* Might waste a little space, but it's safe. */
const uint pre_padding = padding(imm.buffer_offset, imm.vertex_format.stride);
- if ((bytes_needed + pre_padding) <= available_bytes) {
+ if (!recreate_buffer && ((bytes_needed + pre_padding) <= available_bytes)) {
imm.buffer_offset += pre_padding;
}
else {
/* orphan this buffer & start with a fresh one */
/* this method works on all platforms, old & new */
- glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, imm_buffer_size, NULL, GL_DYNAMIC_DRAW);
imm.buffer_offset = 0;
}
@@ -298,7 +308,7 @@ static void immDrawSetup(void)
/* Enable/Disable vertex attributes as needed. */
if (imm.attr_binding.enabled_bits != imm.prev_enabled_attr_bits) {
- for (uint loc = 0; loc < GPU_VERT_ATTR_MAX_LEN; ++loc) {
+ for (uint loc = 0; loc < GPU_VERT_ATTR_MAX_LEN; loc++) {
bool is_enabled = imm.attr_binding.enabled_bits & (1 << loc);
bool was_enabled = imm.prev_enabled_attr_bits & (1 << loc);
@@ -315,7 +325,7 @@ static void immDrawSetup(void)
const uint stride = imm.vertex_format.stride;
- for (uint a_idx = 0; a_idx < imm.vertex_format.attr_len; ++a_idx) {
+ for (uint a_idx = 0; a_idx < imm.vertex_format.attr_len; a_idx++) {
const GPUVertAttr *a = &imm.vertex_format.attrs[a_idx];
const uint offset = imm.buffer_offset + a->offset;
@@ -640,7 +650,7 @@ static void immEndVertex(void) /* and move on to the next vertex */
#if TRUST_NO_ONE
assert(imm.vertex_idx > 0); /* first vertex must have all attributes specified */
#endif
- for (uint a_idx = 0; a_idx < imm.vertex_format.attr_len; ++a_idx) {
+ for (uint a_idx = 0; a_idx < imm.vertex_format.attr_len; a_idx++) {
if ((imm.unassigned_attr_bits >> a_idx) & 1) {
const GPUVertAttr *a = &imm.vertex_format.attrs[a_idx];
diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c
index ca0c2506750..bb3c4344bd4 100644
--- a/source/blender/gpu/intern/gpu_immediate_util.c
+++ b/source/blender/gpu/intern/gpu_immediate_util.c
@@ -28,7 +28,6 @@
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
-#include "GPU_matrix.h"
static const float cube_coords[8][3] = {
{-1, -1, -1},
@@ -167,7 +166,7 @@ static void imm_draw_circle(GPUPrimType prim_type,
int nsegments)
{
immBegin(prim_type, nsegments);
- for (int i = 0; i < nsegments; ++i) {
+ for (int i = 0; i < nsegments; i++) {
const float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments);
immVertex2f(shdr_pos, x + (rad_x * cosf(angle)), y + (rad_y * sinf(angle)));
}
@@ -229,7 +228,7 @@ static void imm_draw_circle_partial(GPUPrimType prim_type,
const float angle_end = -(DEG2RADF(sweep) - angle_start);
nsegments += 1;
immBegin(prim_type, nsegments);
- for (int i = 0; i < nsegments; ++i) {
+ for (int i = 0; i < nsegments; i++) {
const float angle = interpf(angle_start, angle_end, ((float)i / (float)(nsegments - 1)));
const float angle_sin = sinf(angle);
const float angle_cos = cosf(angle);
@@ -263,7 +262,7 @@ static void imm_draw_disk_partial(GPUPrimType prim_type,
const float angle_end = -(DEG2RADF(sweep) - angle_start);
nsegments += 1;
immBegin(prim_type, nsegments * 2);
- for (int i = 0; i < nsegments; ++i) {
+ for (int i = 0; i < nsegments; i++) {
const float angle = interpf(angle_start, angle_end, ((float)i / (float)(nsegments - 1)));
const float angle_sin = sinf(angle);
const float angle_cos = cosf(angle);
@@ -305,7 +304,7 @@ static void imm_draw_circle_3D(
GPUPrimType prim_type, uint pos, float x, float y, float rad, int nsegments)
{
immBegin(prim_type, nsegments);
- for (int i = 0; i < nsegments; ++i) {
+ for (int i = 0; i < nsegments; i++) {
float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments);
immVertex3f(pos, x + rad * cosf(angle), y + rad * sinf(angle), 0.0f);
}
@@ -422,7 +421,7 @@ void imm_draw_cylinder_fill_normal_3d(
uint pos, uint nor, float base, float top, float height, int slices, int stacks)
{
immBegin(GPU_PRIM_TRIS, 6 * slices * stacks);
- for (int i = 0; i < slices; ++i) {
+ for (int i = 0; i < slices; i++) {
const float angle1 = (float)(2 * M_PI) * ((float)i / (float)slices);
const float angle2 = (float)(2 * M_PI) * ((float)(i + 1) / (float)slices);
const float cos1 = cosf(angle1);
@@ -430,7 +429,7 @@ void imm_draw_cylinder_fill_normal_3d(
const float cos2 = cosf(angle2);
const float sin2 = sinf(angle2);
- for (int j = 0; j < stacks; ++j) {
+ for (int j = 0; j < stacks; j++) {
float fac1 = (float)j / (float)stacks;
float fac2 = (float)(j + 1) / (float)stacks;
float r1 = base * (1.f - fac1) + top * fac1;
@@ -478,7 +477,7 @@ void imm_draw_cylinder_wire_3d(
uint pos, float base, float top, float height, int slices, int stacks)
{
immBegin(GPU_PRIM_LINES, 6 * slices * stacks);
- for (int i = 0; i < slices; ++i) {
+ for (int i = 0; i < slices; i++) {
const float angle1 = (float)(2 * M_PI) * ((float)i / (float)slices);
const float angle2 = (float)(2 * M_PI) * ((float)(i + 1) / (float)slices);
const float cos1 = cosf(angle1);
@@ -486,7 +485,7 @@ void imm_draw_cylinder_wire_3d(
const float cos2 = cosf(angle2);
const float sin2 = sinf(angle2);
- for (int j = 0; j < stacks; ++j) {
+ for (int j = 0; j < stacks; j++) {
float fac1 = (float)j / (float)stacks;
float fac2 = (float)(j + 1) / (float)stacks;
float r1 = base * (1.f - fac1) + top * fac1;
@@ -516,7 +515,7 @@ void imm_draw_cylinder_fill_3d(
uint pos, float base, float top, float height, int slices, int stacks)
{
immBegin(GPU_PRIM_TRIS, 6 * slices * stacks);
- for (int i = 0; i < slices; ++i) {
+ for (int i = 0; i < slices; i++) {
const float angle1 = (float)(2 * M_PI) * ((float)i / (float)slices);
const float angle2 = (float)(2 * M_PI) * ((float)(i + 1) / (float)slices);
const float cos1 = cosf(angle1);
@@ -524,7 +523,7 @@ void imm_draw_cylinder_fill_3d(
const float cos2 = cosf(angle2);
const float sin2 = sinf(angle2);
- for (int j = 0; j < stacks; ++j) {
+ for (int j = 0; j < stacks; j++) {
float fac1 = (float)j / (float)stacks;
float fac2 = (float)(j + 1) / (float)stacks;
float r1 = base * (1.f - fac1) + top * fac1;
diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c
index 322ac3be8e2..0009e7d8c47 100644
--- a/source/blender/gpu/intern/gpu_init_exit.c
+++ b/source/blender/gpu/intern/gpu_init_exit.c
@@ -26,7 +26,6 @@
#include "GPU_init_exit.h" /* interface */
#include "GPU_immediate.h"
#include "GPU_batch.h"
-#include "GPU_texture.h"
#include "BKE_global.h"
#include "intern/gpu_codegen.h"
@@ -63,11 +62,13 @@ void GPU_init(void)
immInit();
}
- GPU_pbvh_fix_linking();
+ gpu_pbvh_init();
}
void GPU_exit(void)
{
+ gpu_pbvh_exit();
+
if (!G.background) {
immDestroy();
}
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 20b91c0c95d..2e3a0a8df27 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -37,6 +37,7 @@
#include "BLI_utildefines.h"
#include "BLI_string.h"
#include "BLI_string_utils.h"
+#include "BLI_ghash.h"
#include "BKE_main.h"
#include "BKE_node.h"
@@ -102,6 +103,8 @@ struct GPUMaterial {
GPUTexture *coba_tex; /* 1D Texture array containing all color bands. */
GPUColorBandBuilder *coba_builder;
+ GSet *used_libraries;
+
#ifndef NDEBUG
char name[64];
#endif
@@ -183,6 +186,8 @@ static void gpu_material_free_single(GPUMaterial *material)
if (material->coba_tex != NULL) {
GPU_texture_free(material->coba_tex);
}
+
+ BLI_gset_free(material->used_libraries, NULL);
}
void GPU_material_free(ListBase *gpumaterial)
@@ -328,7 +333,7 @@ static float eval_integral(float x0, float x1, short falloff_type, float sharpne
const float step = range / INTEGRAL_RESOLUTION;
float integral = 0.0f;
- for (int i = 0; i < INTEGRAL_RESOLUTION; ++i) {
+ for (int i = 0; i < INTEGRAL_RESOLUTION; i++) {
float x = x0 + range * ((float)i + 0.5f) / (float)INTEGRAL_RESOLUTION;
float y = eval_profile(x, falloff_type, sharpness, param);
integral += y * step;
@@ -339,7 +344,7 @@ static float eval_integral(float x0, float x1, short falloff_type, float sharpne
#undef INTEGRAL_RESOLUTION
static void compute_sss_kernel(
- GPUSssKernelData *kd, float radii[3], int sample_len, int falloff_type, float sharpness)
+ GPUSssKernelData *kd, const float radii[3], int sample_len, int falloff_type, float sharpness)
{
float rad[3];
/* Minimum radius */
@@ -409,7 +414,7 @@ static void compute_sss_kernel(
sum[2] += kd->kernel[i][2];
}
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; i++) {
if (sum[i] > 0.0f) {
/* Normalize */
for (int j = 0; j < sample_len; j++) {
@@ -445,7 +450,7 @@ static void compute_sss_translucence_kernel(const GPUSssKernelData *kd,
*output = (float *)texels;
/* Last texel should be black, hence the - 1. */
- for (int i = 0; i < resolution - 1; ++i) {
+ for (int i = 0; i < resolution - 1; i++) {
/* Distance from surface. */
float d = kd->max_radius * ((float)i + 0.00001f) / ((float)resolution);
@@ -582,6 +587,11 @@ void gpu_material_add_node(GPUMaterial *material, GPUNode *node)
BLI_addtail(&material->nodes, node);
}
+GSet *gpu_material_used_libraries(GPUMaterial *material)
+{
+ return material->used_libraries;
+}
+
/* Return true if the material compilation has not yet begin or begin. */
eGPUMaterialStatus GPU_material_status(GPUMaterial *mat)
{
@@ -659,6 +669,9 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene,
UNUSED_VARS(name);
#endif
+ mat->used_libraries = BLI_gset_new(
+ BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUMaterial.used_libraries");
+
/* localize tree to create links for reroute and mute */
bNodeTree *localtree = ntreeLocalize(ntree);
ntreeGPUMaterialNodes(localtree, mat, &has_surface_output, &has_volume_output);
diff --git a/source/blender/gpu/intern/gpu_material_library.h b/source/blender/gpu/intern/gpu_material_library.h
new file mode 100644
index 00000000000..3a38eb5c600
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_material_library.h
@@ -0,0 +1,655 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * List of all gpu_shader_material_*.glsl files used by GLSL materials. These
+ * will be parsed to make all functions in them available to use for GPU_link().
+ *
+ * If a file uses functions from another file, it must be added to the list of
+ * dependencies, and be placed after that file in the list. */
+
+#ifndef __GPU_MATERIAL_LIBRARY_H__
+#define __GPU_MATERIAL_LIBRARY_H__
+
+typedef struct GPUMaterialLibrary {
+ char *code;
+ struct GPUMaterialLibrary *dependencies[8];
+} GPUMaterialLibrary;
+
+extern char datatoc_gpu_shader_material_add_shader_glsl[];
+extern char datatoc_gpu_shader_material_ambient_occlusion_glsl[];
+extern char datatoc_gpu_shader_material_anisotropic_glsl[];
+extern char datatoc_gpu_shader_material_attribute_glsl[];
+extern char datatoc_gpu_shader_material_background_glsl[];
+extern char datatoc_gpu_shader_material_bevel_glsl[];
+extern char datatoc_gpu_shader_material_blackbody_glsl[];
+extern char datatoc_gpu_shader_material_bright_contrast_glsl[];
+extern char datatoc_gpu_shader_material_bump_glsl[];
+extern char datatoc_gpu_shader_material_camera_glsl[];
+extern char datatoc_gpu_shader_material_clamp_glsl[];
+extern char datatoc_gpu_shader_material_color_ramp_glsl[];
+extern char datatoc_gpu_shader_material_color_util_glsl[];
+extern char datatoc_gpu_shader_material_combine_hsv_glsl[];
+extern char datatoc_gpu_shader_material_combine_rgb_glsl[];
+extern char datatoc_gpu_shader_material_combine_xyz_glsl[];
+extern char datatoc_gpu_shader_material_diffuse_glsl[];
+extern char datatoc_gpu_shader_material_displacement_glsl[];
+extern char datatoc_gpu_shader_material_eevee_specular_glsl[];
+extern char datatoc_gpu_shader_material_emission_glsl[];
+extern char datatoc_gpu_shader_material_fractal_noise_glsl[];
+extern char datatoc_gpu_shader_material_fresnel_glsl[];
+extern char datatoc_gpu_shader_material_gamma_glsl[];
+extern char datatoc_gpu_shader_material_geometry_glsl[];
+extern char datatoc_gpu_shader_material_glass_glsl[];
+extern char datatoc_gpu_shader_material_glossy_glsl[];
+extern char datatoc_gpu_shader_material_hair_info_glsl[];
+extern char datatoc_gpu_shader_material_hash_glsl[];
+extern char datatoc_gpu_shader_material_holdout_glsl[];
+extern char datatoc_gpu_shader_material_hue_sat_val_glsl[];
+extern char datatoc_gpu_shader_material_invert_glsl[];
+extern char datatoc_gpu_shader_material_layer_weight_glsl[];
+extern char datatoc_gpu_shader_material_light_falloff_glsl[];
+extern char datatoc_gpu_shader_material_light_path_glsl[];
+extern char datatoc_gpu_shader_material_mapping_glsl[];
+extern char datatoc_gpu_shader_material_map_range_glsl[];
+extern char datatoc_gpu_shader_material_math_glsl[];
+extern char datatoc_gpu_shader_material_math_util_glsl[];
+extern char datatoc_gpu_shader_material_mix_rgb_glsl[];
+extern char datatoc_gpu_shader_material_mix_shader_glsl[];
+extern char datatoc_gpu_shader_material_noise_glsl[];
+extern char datatoc_gpu_shader_material_normal_glsl[];
+extern char datatoc_gpu_shader_material_normal_map_glsl[];
+extern char datatoc_gpu_shader_material_object_info_glsl[];
+extern char datatoc_gpu_shader_material_output_material_glsl[];
+extern char datatoc_gpu_shader_material_output_world_glsl[];
+extern char datatoc_gpu_shader_material_particle_info_glsl[];
+extern char datatoc_gpu_shader_material_principled_glsl[];
+extern char datatoc_gpu_shader_material_refraction_glsl[];
+extern char datatoc_gpu_shader_material_rgb_curves_glsl[];
+extern char datatoc_gpu_shader_material_rgb_to_bw_glsl[];
+extern char datatoc_gpu_shader_material_separate_hsv_glsl[];
+extern char datatoc_gpu_shader_material_separate_rgb_glsl[];
+extern char datatoc_gpu_shader_material_separate_xyz_glsl[];
+extern char datatoc_gpu_shader_material_set_glsl[];
+extern char datatoc_gpu_shader_material_shader_to_rgba_glsl[];
+extern char datatoc_gpu_shader_material_squeeze_glsl[];
+extern char datatoc_gpu_shader_material_subsurface_scattering_glsl[];
+extern char datatoc_gpu_shader_material_tangent_glsl[];
+extern char datatoc_gpu_shader_material_tex_brick_glsl[];
+extern char datatoc_gpu_shader_material_tex_checker_glsl[];
+extern char datatoc_gpu_shader_material_tex_environment_glsl[];
+extern char datatoc_gpu_shader_material_tex_gradient_glsl[];
+extern char datatoc_gpu_shader_material_tex_image_glsl[];
+extern char datatoc_gpu_shader_material_tex_magic_glsl[];
+extern char datatoc_gpu_shader_material_tex_musgrave_glsl[];
+extern char datatoc_gpu_shader_material_tex_noise_glsl[];
+extern char datatoc_gpu_shader_material_tex_sky_glsl[];
+extern char datatoc_gpu_shader_material_texture_coordinates_glsl[];
+extern char datatoc_gpu_shader_material_tex_voronoi_glsl[];
+extern char datatoc_gpu_shader_material_tex_wave_glsl[];
+extern char datatoc_gpu_shader_material_tex_white_noise_glsl[];
+extern char datatoc_gpu_shader_material_toon_glsl[];
+extern char datatoc_gpu_shader_material_translucent_glsl[];
+extern char datatoc_gpu_shader_material_transparent_glsl[];
+extern char datatoc_gpu_shader_material_uv_map_glsl[];
+extern char datatoc_gpu_shader_material_vector_curves_glsl[];
+extern char datatoc_gpu_shader_material_vector_displacement_glsl[];
+extern char datatoc_gpu_shader_material_vector_math_glsl[];
+extern char datatoc_gpu_shader_material_velvet_glsl[];
+extern char datatoc_gpu_shader_material_vertex_color_glsl[];
+extern char datatoc_gpu_shader_material_volume_absorption_glsl[];
+extern char datatoc_gpu_shader_material_volume_info_glsl[];
+extern char datatoc_gpu_shader_material_volume_principled_glsl[];
+extern char datatoc_gpu_shader_material_volume_scatter_glsl[];
+extern char datatoc_gpu_shader_material_wireframe_glsl[];
+extern char datatoc_gpu_shader_material_world_normals_glsl[];
+
+static GPUMaterialLibrary gpu_shader_material_math_util_library = {
+ .code = datatoc_gpu_shader_material_math_util_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_color_util_library = {
+ .code = datatoc_gpu_shader_material_color_util_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_hash_library = {
+ .code = datatoc_gpu_shader_material_hash_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_noise_library = {
+ .code = datatoc_gpu_shader_material_noise_glsl,
+ .dependencies = {&gpu_shader_material_math_util_library,
+ &gpu_shader_material_hash_library,
+ NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_fractal_noise_library = {
+ .code = datatoc_gpu_shader_material_fractal_noise_glsl,
+ .dependencies = {&gpu_shader_material_noise_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_add_shader_library = {
+ .code = datatoc_gpu_shader_material_add_shader_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_ambient_occlusion_library = {
+ .code = datatoc_gpu_shader_material_ambient_occlusion_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_glossy_library = {
+ .code = datatoc_gpu_shader_material_glossy_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_anisotropic_library = {
+ .code = datatoc_gpu_shader_material_anisotropic_glsl,
+ .dependencies = {&gpu_shader_material_glossy_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_attribute_library = {
+ .code = datatoc_gpu_shader_material_attribute_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_background_library = {
+ .code = datatoc_gpu_shader_material_background_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_bevel_library = {
+ .code = datatoc_gpu_shader_material_bevel_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_blackbody_library = {
+ .code = datatoc_gpu_shader_material_blackbody_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_bright_contrast_library = {
+ .code = datatoc_gpu_shader_material_bright_contrast_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_bump_library = {
+ .code = datatoc_gpu_shader_material_bump_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_camera_library = {
+ .code = datatoc_gpu_shader_material_camera_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_clamp_library = {
+ .code = datatoc_gpu_shader_material_clamp_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_color_ramp_library = {
+ .code = datatoc_gpu_shader_material_color_ramp_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_combine_hsv_library = {
+ .code = datatoc_gpu_shader_material_combine_hsv_glsl,
+ .dependencies = {&gpu_shader_material_color_util_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_combine_rgb_library = {
+ .code = datatoc_gpu_shader_material_combine_rgb_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_combine_xyz_library = {
+ .code = datatoc_gpu_shader_material_combine_xyz_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_diffuse_library = {
+ .code = datatoc_gpu_shader_material_diffuse_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_displacement_library = {
+ .code = datatoc_gpu_shader_material_displacement_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_eevee_specular_library = {
+ .code = datatoc_gpu_shader_material_eevee_specular_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_emission_library = {
+ .code = datatoc_gpu_shader_material_emission_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_fresnel_library = {
+ .code = datatoc_gpu_shader_material_fresnel_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_gamma_library = {
+ .code = datatoc_gpu_shader_material_gamma_glsl,
+ .dependencies = {&gpu_shader_material_math_util_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tangent_library = {
+ .code = datatoc_gpu_shader_material_tangent_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_geometry_library = {
+ .code = datatoc_gpu_shader_material_geometry_glsl,
+ .dependencies = {&gpu_shader_material_tangent_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_glass_library = {
+ .code = datatoc_gpu_shader_material_glass_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_hair_info_library = {
+ .code = datatoc_gpu_shader_material_hair_info_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_holdout_library = {
+ .code = datatoc_gpu_shader_material_holdout_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_hue_sat_val_library = {
+ .code = datatoc_gpu_shader_material_hue_sat_val_glsl,
+ .dependencies = {&gpu_shader_material_color_util_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_invert_library = {
+ .code = datatoc_gpu_shader_material_invert_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_layer_weight_library = {
+ .code = datatoc_gpu_shader_material_layer_weight_glsl,
+ .dependencies = {&gpu_shader_material_fresnel_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_light_falloff_library = {
+ .code = datatoc_gpu_shader_material_light_falloff_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_light_path_library = {
+ .code = datatoc_gpu_shader_material_light_path_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_mapping_library = {
+ .code = datatoc_gpu_shader_material_mapping_glsl,
+ .dependencies = {&gpu_shader_material_math_util_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_map_range_library = {
+ .code = datatoc_gpu_shader_material_map_range_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_math_library = {
+ .code = datatoc_gpu_shader_material_math_glsl,
+ .dependencies = {&gpu_shader_material_math_util_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_mix_rgb_library = {
+ .code = datatoc_gpu_shader_material_mix_rgb_glsl,
+ .dependencies = {&gpu_shader_material_color_util_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_mix_shader_library = {
+ .code = datatoc_gpu_shader_material_mix_shader_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_normal_library = {
+ .code = datatoc_gpu_shader_material_normal_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_normal_map_library = {
+ .code = datatoc_gpu_shader_material_normal_map_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_object_info_library = {
+ .code = datatoc_gpu_shader_material_object_info_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_output_material_library = {
+ .code = datatoc_gpu_shader_material_output_material_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_output_world_library = {
+ .code = datatoc_gpu_shader_material_output_world_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_particle_info_library = {
+ .code = datatoc_gpu_shader_material_particle_info_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_principled_library = {
+ .code = datatoc_gpu_shader_material_principled_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_refraction_library = {
+ .code = datatoc_gpu_shader_material_refraction_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_rgb_curves_library = {
+ .code = datatoc_gpu_shader_material_rgb_curves_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_rgb_to_bw_library = {
+ .code = datatoc_gpu_shader_material_rgb_to_bw_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_separate_hsv_library = {
+ .code = datatoc_gpu_shader_material_separate_hsv_glsl,
+ .dependencies = {&gpu_shader_material_color_util_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_separate_rgb_library = {
+ .code = datatoc_gpu_shader_material_separate_rgb_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_separate_xyz_library = {
+ .code = datatoc_gpu_shader_material_separate_xyz_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_set_library = {
+ .code = datatoc_gpu_shader_material_set_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_shader_to_rgba_library = {
+ .code = datatoc_gpu_shader_material_shader_to_rgba_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_squeeze_library = {
+ .code = datatoc_gpu_shader_material_squeeze_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_subsurface_scattering_library = {
+ .code = datatoc_gpu_shader_material_subsurface_scattering_glsl,
+ .dependencies = {&gpu_shader_material_diffuse_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_brick_library = {
+ .code = datatoc_gpu_shader_material_tex_brick_glsl,
+ .dependencies = {&gpu_shader_material_math_util_library,
+ &gpu_shader_material_hash_library,
+ NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_checker_library = {
+ .code = datatoc_gpu_shader_material_tex_checker_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_environment_library = {
+ .code = datatoc_gpu_shader_material_tex_environment_glsl,
+ .dependencies = {&gpu_shader_material_math_util_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_gradient_library = {
+ .code = datatoc_gpu_shader_material_tex_gradient_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_image_library = {
+ .code = datatoc_gpu_shader_material_tex_image_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_magic_library = {
+ .code = datatoc_gpu_shader_material_tex_magic_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_musgrave_library = {
+ .code = datatoc_gpu_shader_material_tex_musgrave_glsl,
+ .dependencies = {&gpu_shader_material_noise_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_noise_library = {
+ .code = datatoc_gpu_shader_material_tex_noise_glsl,
+ .dependencies = {&gpu_shader_material_fractal_noise_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_sky_library = {
+ .code = datatoc_gpu_shader_material_tex_sky_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_texture_coordinates_library = {
+ .code = datatoc_gpu_shader_material_texture_coordinates_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_voronoi_library = {
+ .code = datatoc_gpu_shader_material_tex_voronoi_glsl,
+ .dependencies = {&gpu_shader_material_math_util_library,
+ &gpu_shader_material_hash_library,
+ NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_wave_library = {
+ .code = datatoc_gpu_shader_material_tex_wave_glsl,
+ .dependencies = {&gpu_shader_material_fractal_noise_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_tex_white_noise_library = {
+ .code = datatoc_gpu_shader_material_tex_white_noise_glsl,
+ .dependencies = {&gpu_shader_material_hash_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_toon_library = {
+ .code = datatoc_gpu_shader_material_toon_glsl,
+ .dependencies = {&gpu_shader_material_diffuse_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_translucent_library = {
+ .code = datatoc_gpu_shader_material_translucent_glsl,
+ .dependencies = {&gpu_shader_material_diffuse_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_transparent_library = {
+ .code = datatoc_gpu_shader_material_transparent_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_uv_map_library = {
+ .code = datatoc_gpu_shader_material_uv_map_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_vector_curves_library = {
+ .code = datatoc_gpu_shader_material_vector_curves_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_vector_displacement_library = {
+ .code = datatoc_gpu_shader_material_vector_displacement_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_vector_math_library = {
+ .code = datatoc_gpu_shader_material_vector_math_glsl,
+ .dependencies = {&gpu_shader_material_math_util_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_velvet_library = {
+ .code = datatoc_gpu_shader_material_velvet_glsl,
+ .dependencies = {&gpu_shader_material_diffuse_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_vertex_color_library = {
+ .code = datatoc_gpu_shader_material_vertex_color_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_volume_absorption_library = {
+ .code = datatoc_gpu_shader_material_volume_absorption_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_volume_info_library = {
+ .code = datatoc_gpu_shader_material_volume_info_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_volume_principled_library = {
+ .code = datatoc_gpu_shader_material_volume_principled_glsl,
+ .dependencies = {&gpu_shader_material_blackbody_library, NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_volume_scatter_library = {
+ .code = datatoc_gpu_shader_material_volume_scatter_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_wireframe_library = {
+ .code = datatoc_gpu_shader_material_wireframe_glsl,
+ .dependencies = {NULL},
+};
+
+static GPUMaterialLibrary gpu_shader_material_world_normals_library = {
+ .code = datatoc_gpu_shader_material_world_normals_glsl,
+ .dependencies = {&gpu_shader_material_texture_coordinates_library, NULL},
+};
+
+static GPUMaterialLibrary *gpu_material_libraries[] = {
+ &gpu_shader_material_math_util_library,
+ &gpu_shader_material_color_util_library,
+ &gpu_shader_material_hash_library,
+ &gpu_shader_material_noise_library,
+ &gpu_shader_material_fractal_noise_library,
+ &gpu_shader_material_add_shader_library,
+ &gpu_shader_material_ambient_occlusion_library,
+ &gpu_shader_material_glossy_library,
+ &gpu_shader_material_anisotropic_library,
+ &gpu_shader_material_attribute_library,
+ &gpu_shader_material_background_library,
+ &gpu_shader_material_bevel_library,
+ &gpu_shader_material_blackbody_library,
+ &gpu_shader_material_bright_contrast_library,
+ &gpu_shader_material_bump_library,
+ &gpu_shader_material_camera_library,
+ &gpu_shader_material_clamp_library,
+ &gpu_shader_material_color_ramp_library,
+ &gpu_shader_material_combine_hsv_library,
+ &gpu_shader_material_combine_rgb_library,
+ &gpu_shader_material_combine_xyz_library,
+ &gpu_shader_material_diffuse_library,
+ &gpu_shader_material_displacement_library,
+ &gpu_shader_material_eevee_specular_library,
+ &gpu_shader_material_emission_library,
+ &gpu_shader_material_fresnel_library,
+ &gpu_shader_material_gamma_library,
+ &gpu_shader_material_tangent_library,
+ &gpu_shader_material_geometry_library,
+ &gpu_shader_material_glass_library,
+ &gpu_shader_material_hair_info_library,
+ &gpu_shader_material_holdout_library,
+ &gpu_shader_material_hue_sat_val_library,
+ &gpu_shader_material_invert_library,
+ &gpu_shader_material_layer_weight_library,
+ &gpu_shader_material_light_falloff_library,
+ &gpu_shader_material_light_path_library,
+ &gpu_shader_material_mapping_library,
+ &gpu_shader_material_map_range_library,
+ &gpu_shader_material_math_library,
+ &gpu_shader_material_mix_rgb_library,
+ &gpu_shader_material_mix_shader_library,
+ &gpu_shader_material_normal_library,
+ &gpu_shader_material_normal_map_library,
+ &gpu_shader_material_object_info_library,
+ &gpu_shader_material_output_material_library,
+ &gpu_shader_material_output_world_library,
+ &gpu_shader_material_particle_info_library,
+ &gpu_shader_material_principled_library,
+ &gpu_shader_material_refraction_library,
+ &gpu_shader_material_rgb_curves_library,
+ &gpu_shader_material_rgb_to_bw_library,
+ &gpu_shader_material_separate_hsv_library,
+ &gpu_shader_material_separate_rgb_library,
+ &gpu_shader_material_separate_xyz_library,
+ &gpu_shader_material_set_library,
+ &gpu_shader_material_shader_to_rgba_library,
+ &gpu_shader_material_squeeze_library,
+ &gpu_shader_material_subsurface_scattering_library,
+ &gpu_shader_material_tex_brick_library,
+ &gpu_shader_material_tex_checker_library,
+ &gpu_shader_material_tex_environment_library,
+ &gpu_shader_material_tex_gradient_library,
+ &gpu_shader_material_tex_image_library,
+ &gpu_shader_material_tex_magic_library,
+ &gpu_shader_material_tex_musgrave_library,
+ &gpu_shader_material_tex_noise_library,
+ &gpu_shader_material_tex_sky_library,
+ &gpu_shader_material_texture_coordinates_library,
+ &gpu_shader_material_tex_voronoi_library,
+ &gpu_shader_material_tex_wave_library,
+ &gpu_shader_material_tex_white_noise_library,
+ &gpu_shader_material_toon_library,
+ &gpu_shader_material_translucent_library,
+ &gpu_shader_material_transparent_library,
+ &gpu_shader_material_uv_map_library,
+ &gpu_shader_material_vector_curves_library,
+ &gpu_shader_material_vector_displacement_library,
+ &gpu_shader_material_vector_math_library,
+ &gpu_shader_material_velvet_library,
+ &gpu_shader_material_vertex_color_library,
+ &gpu_shader_material_volume_absorption_library,
+ &gpu_shader_material_volume_info_library,
+ &gpu_shader_material_volume_principled_library,
+ &gpu_shader_material_volume_scatter_library,
+ &gpu_shader_material_wireframe_library,
+ &gpu_shader_material_world_normals_library,
+ NULL};
+#endif
diff --git a/source/blender/gpu/intern/gpu_private.h b/source/blender/gpu/intern/gpu_private.h
index 43b2da13e28..b9af8f1b38c 100644
--- a/source/blender/gpu/intern/gpu_private.h
+++ b/source/blender/gpu/intern/gpu_private.h
@@ -33,4 +33,8 @@ void gpu_debug_exit(void);
void gpu_framebuffer_module_init(void);
void gpu_framebuffer_module_exit(void);
+/* gpu_pbvh.c */
+void gpu_pbvh_init(void);
+void gpu_pbvh_exit(void);
+
#endif /* __GPU_PRIVATE_H__ */
diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c
index 119aed2f5ed..f12da9ce2f7 100644
--- a/source/blender/gpu/intern/gpu_select.c
+++ b/source/blender/gpu/intern/gpu_select.c
@@ -27,7 +27,6 @@
#include <stdlib.h>
#include "GPU_select.h"
-#include "GPU_extensions.h"
#include "GPU_glew.h"
#include "MEM_guardedalloc.h"
diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c
index 939279d82ff..1fb83b628e1 100644
--- a/source/blender/gpu/intern/gpu_select_pick.c
+++ b/source/blender/gpu/intern/gpu_select_pick.c
@@ -30,7 +30,6 @@
#include "GPU_immediate.h"
#include "GPU_draw.h"
#include "GPU_select.h"
-#include "GPU_extensions.h"
#include "GPU_glew.h"
#include "MEM_guardedalloc.h"
diff --git a/source/blender/gpu/intern/gpu_select_sample_query.c b/source/blender/gpu/intern/gpu_select_sample_query.c
index beea25b4171..6e8b062cff0 100644
--- a/source/blender/gpu/intern/gpu_select_sample_query.c
+++ b/source/blender/gpu/intern/gpu_select_sample_query.c
@@ -29,7 +29,6 @@
#include "GPU_immediate.h"
#include "GPU_draw.h"
#include "GPU_select.h"
-#include "GPU_extensions.h"
#include "GPU_glew.h"
#include "MEM_guardedalloc.h"
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index 3e930d19696..015df078228 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -36,7 +36,6 @@
#include "DNA_space_types.h"
#include "GPU_extensions.h"
-#include "GPU_context.h"
#include "GPU_matrix.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
@@ -249,6 +248,9 @@ static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH])
/* a #version 400 feature, but we use #version 330 maximum so use extension */
strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n");
}
+ if (GLEW_ARB_shader_draw_parameters) {
+ strcat(defines, "#extension GL_ARB_shader_draw_parameters : enable\n");
+ }
}
static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH])
@@ -256,6 +258,9 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH])
/* some useful defines to detect GPU type */
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
strcat(defines, "#define GPU_ATI\n");
+ if (GPU_crappy_amd_driver()) {
+ strcat(defines, "#define GPU_DEPRECATED_AMD_DRIVER\n");
+ }
}
else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY)) {
strcat(defines, "#define GPU_NVIDIA\n");
@@ -275,6 +280,22 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH])
strcat(defines, "#define OS_UNIX\n");
}
+ float derivatives_factors[2];
+ GPU_get_dfdy_factors(derivatives_factors);
+ if (derivatives_factors[0] == 1.0f) {
+ strcat(defines, "#define DFDX_SIGN 1.0\n");
+ }
+ else {
+ strcat(defines, "#define DFDX_SIGN -1.0\n");
+ }
+
+ if (derivatives_factors[1] == 1.0f) {
+ strcat(defines, "#define DFDY_SIGN 1.0\n");
+ }
+ else {
+ strcat(defines, "#define DFDY_SIGN -1.0\n");
+ }
+
return;
}
diff --git a/source/blender/gpu/intern/gpu_shader_interface.c b/source/blender/gpu/intern/gpu_shader_interface.c
index f205ef31ed2..983c5dfc27a 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.c
+++ b/source/blender/gpu/intern/gpu_shader_interface.c
@@ -65,9 +65,8 @@ static const char *BuiltinUniform_name(GPUUniformBuiltin u)
[GPU_UNIFORM_CLIPPLANES] = "WorldClipPlanes",
[GPU_UNIFORM_COLOR] = "color",
- [GPU_UNIFORM_CALLID] = "callId",
- [GPU_UNIFORM_OBJECT_INFO] = "unfobjectinfo",
- [GPU_UNIFORM_OBJECT_COLOR] = "unfobjectcolor",
+ [GPU_UNIFORM_BASE_INSTANCE] = "baseInstance",
+ [GPU_UNIFORM_RESOURCE_CHUNK] = "resourceChunk",
[GPU_UNIFORM_CUSTOM] = NULL,
[GPU_NUM_UNIFORMS] = NULL,
@@ -149,7 +148,7 @@ GPU_INLINE const GPUShaderInput *buckets_lookup(
GPU_INLINE void buckets_free(GPUShaderInput *buckets[GPU_NUM_SHADERINTERFACE_BUCKETS])
{
- for (uint bucket_index = 0; bucket_index < GPU_NUM_SHADERINTERFACE_BUCKETS; ++bucket_index) {
+ for (uint bucket_index = 0; bucket_index < GPU_NUM_SHADERINTERFACE_BUCKETS; bucket_index++) {
GPUShaderInput *input = buckets[bucket_index];
while (input != NULL) {
GPUShaderInput *input_next = input->next;
@@ -164,7 +163,7 @@ static bool setup_builtin_uniform(GPUShaderInput *input, const char *name)
/* TODO: reject DOUBLE, IMAGE, ATOMIC_COUNTER gl_types */
/* detect built-in uniforms (name must match) */
- for (GPUUniformBuiltin u = GPU_UNIFORM_NONE + 1; u < GPU_UNIFORM_CUSTOM; ++u) {
+ for (GPUUniformBuiltin u = GPU_UNIFORM_NONE + 1; u < GPU_UNIFORM_CUSTOM; u++) {
const char *builtin_name = BuiltinUniform_name(u);
if (match(name, builtin_name)) {
input->builtin_type = u;
@@ -236,7 +235,7 @@ GPUShaderInterface *GPU_shaderinterface_create(int32_t program)
shaderface->name_buffer = MEM_mallocN(name_buffer_len, "name_buffer");
/* Attributes */
- for (uint32_t i = 0; i < attr_len; ++i) {
+ for (uint32_t i = 0; i < attr_len; i++) {
GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput Attr");
GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset;
char *name = shaderface->name_buffer + shaderface->name_buffer_offset;
@@ -264,7 +263,7 @@ GPUShaderInterface *GPU_shaderinterface_create(int32_t program)
#endif
}
/* Uniform Blocks */
- for (uint32_t i = 0; i < ubo_len; ++i) {
+ for (uint32_t i = 0; i < ubo_len; i++) {
GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput UBO");
GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset;
char *name = shaderface->name_buffer + shaderface->name_buffer_offset;
@@ -283,7 +282,7 @@ GPUShaderInterface *GPU_shaderinterface_create(int32_t program)
#endif
}
/* Builtin Uniforms */
- for (GPUUniformBuiltin u = GPU_UNIFORM_NONE + 1; u < GPU_UNIFORM_CUSTOM; ++u) {
+ for (GPUUniformBuiltin u = GPU_UNIFORM_NONE + 1; u < GPU_UNIFORM_CUSTOM; u++) {
const char *builtin_name = BuiltinUniform_name(u);
if (glGetUniformLocation(program, builtin_name) != -1) {
add_uniform((GPUShaderInterface *)shaderface, builtin_name);
@@ -306,7 +305,7 @@ void GPU_shaderinterface_discard(GPUShaderInterface *shaderface)
/* Free memory used by name_buffer. */
MEM_freeN(shaderface->name_buffer);
/* Remove this interface from all linked Batches vao cache. */
- for (int i = 0; i < shaderface->batches_len; ++i) {
+ for (int i = 0; i < shaderface->batches_len; i++) {
if (shaderface->batches[i] != NULL) {
gpu_batch_remove_interface_ref(shaderface->batches[i], shaderface);
}
@@ -374,7 +373,7 @@ const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *shaderf
void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *shaderface, GPUBatch *batch)
{
int i; /* find first unused slot */
- for (i = 0; i < shaderface->batches_len; ++i) {
+ for (i = 0; i < shaderface->batches_len; i++) {
if (shaderface->batches[i] == NULL) {
break;
}
@@ -391,7 +390,7 @@ void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *shaderface, GPUBatch
void GPU_shaderinterface_remove_batch_ref(GPUShaderInterface *shaderface, GPUBatch *batch)
{
- for (int i = 0; i < shaderface->batches_len; ++i) {
+ for (int i = 0; i < shaderface->batches_len; i++) {
if (shaderface->batches[i] == batch) {
shaderface->batches[i] = NULL;
break; /* cannot have duplicates */
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index 955b11036ef..a54d90f37f5 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -1471,7 +1471,7 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat gpu_data_format, int mipl
if (GPU_texture_cube(tex)) {
int cube_face_size = buf_size / 6;
- for (int i = 0; i < 6; ++i) {
+ for (int i = 0; i < 6; i++) {
glGetTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
miplvl,
data_format,
@@ -1540,7 +1540,7 @@ void GPU_texture_bind(GPUTexture *tex, int number)
}
if ((G.debug & G_DEBUG)) {
- for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; ++i) {
+ for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; i++) {
if (tex->fb[i] && GPU_framebuffer_bound(tex->fb[i])) {
fprintf(stderr,
"Feedback loop warning!: Attempting to bind "
@@ -1603,7 +1603,7 @@ void GPU_texture_generate_mipmap(GPUTexture *tex)
* GPU_framebuffer_recursive_downsample(). */
int levels = 1 + floor(log2(max_ii(tex->w, tex->h)));
eGPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex->format);
- for (int i = 1; i < levels; ++i) {
+ for (int i = 1; i < levels; i++) {
GPU_texture_add_mipmap(tex, data_format, i, NULL);
}
glBindTexture(tex->target, tex->bindcode);
@@ -1712,7 +1712,7 @@ void GPU_texture_free(GPUTexture *tex)
}
if (tex->refcount == 0) {
- for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; ++i) {
+ for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; i++) {
if (tex->fb[i] != NULL) {
GPU_framebuffer_texture_detach_slot(tex->fb[i], tex, tex->fb_attachment[i]);
}
@@ -1806,7 +1806,7 @@ int GPU_texture_opengl_bindcode(const GPUTexture *tex)
void GPU_texture_attach_framebuffer(GPUTexture *tex, GPUFrameBuffer *fb, int attachment)
{
- for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; ++i) {
+ for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; i++) {
if (tex->fb[i] == NULL) {
tex->fb[i] = fb;
tex->fb_attachment[i] = attachment;
@@ -1820,7 +1820,7 @@ void GPU_texture_attach_framebuffer(GPUTexture *tex, GPUFrameBuffer *fb, int att
/* Return previous attachment point */
int GPU_texture_detach_framebuffer(GPUTexture *tex, GPUFrameBuffer *fb)
{
- for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; ++i) {
+ for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; i++) {
if (tex->fb[i] == fb) {
tex->fb[i] = NULL;
return tex->fb_attachment[i];
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.c b/source/blender/gpu/intern/gpu_vertex_buffer.c
index 2f854fe03ea..eecbcb9ec94 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer.c
+++ b/source/blender/gpu/intern/gpu_vertex_buffer.c
@@ -214,7 +214,7 @@ void GPU_vertbuf_attr_fill_stride(GPUVertBuf *verts, uint a_idx, uint stride, co
}
else {
/* we must copy it per vertex */
- for (uint v = 0; v < vertex_len; ++v) {
+ for (uint v = 0; v < vertex_len; v++) {
memcpy((GLubyte *)verts->data + a->offset + v * format->stride,
(const GLubyte *)data + v * stride,
a->sz);
diff --git a/source/blender/gpu/intern/gpu_vertex_format.c b/source/blender/gpu/intern/gpu_vertex_format.c
index 66e5e254734..65573b71c76 100644
--- a/source/blender/gpu/intern/gpu_vertex_format.c
+++ b/source/blender/gpu/intern/gpu_vertex_format.c
@@ -126,7 +126,7 @@ static uchar copy_attr_name(GPUVertFormat *format, const char *name)
uint available = GPU_VERT_ATTR_NAMES_BUF_LEN - name_offset;
bool terminated = false;
- for (uint i = 0; i < available; ++i) {
+ for (uint i = 0; i < available; i++) {
const char c = name[i];
name_copy[i] = c;
if (c == '\0') {
@@ -303,10 +303,10 @@ uint padding(uint offset, uint alignment)
static void show_pack(uint a_idx, uint sz, uint pad)
{
const char c = 'A' + a_idx;
- for (uint i = 0; i < pad; ++i) {
+ for (uint i = 0; i < pad; i++) {
putchar('-');
}
- for (uint i = 0; i < sz; ++i) {
+ for (uint i = 0; i < sz; i++) {
putchar(c);
}
}
@@ -330,7 +330,7 @@ void VertexFormat_pack(GPUVertFormat *format)
show_pack(0, a0->sz, 0);
#endif
- for (uint a_idx = 1; a_idx < format->attr_len; ++a_idx) {
+ for (uint a_idx = 1; a_idx < format->attr_len; a_idx++) {
GPUVertAttr *a = &format->attrs[a_idx];
uint mid_padding = padding(offset, attr_align(a));
offset += mid_padding;
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index e3c13b0ec14..615af57c1bd 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -39,7 +39,7 @@
#include "GPU_immediate.h"
#include "GPU_texture.h"
#include "GPU_viewport.h"
-#include "GPU_draw.h"
+#include "GPU_uniformbuffer.h"
#include "DRW_engine.h"
@@ -303,7 +303,7 @@ GPUTexture *GPU_viewport_texture_pool_query(
(GPU_texture_width(tmp_tex->texture) == width) &&
(GPU_texture_height(tmp_tex->texture) == height)) {
/* Search if the engine is not already using this texture */
- for (int i = 0; i < MAX_ENGINE_BUFFER_SHARING; ++i) {
+ for (int i = 0; i < MAX_ENGINE_BUFFER_SHARING; i++) {
if (tmp_tex->user[i] == engine) {
break;
}
@@ -339,7 +339,7 @@ static void gpu_viewport_texture_pool_clear_users(GPUViewport *viewport)
for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex_next) {
tmp_tex_next = tmp_tex->next;
bool no_user = true;
- for (int i = 0; i < MAX_ENGINE_BUFFER_SHARING; ++i) {
+ for (int i = 0; i < MAX_ENGINE_BUFFER_SHARING; i++) {
if (tmp_tex->user[i] != NULL) {
tmp_tex->user[i] = NULL;
no_user = false;
@@ -620,11 +620,20 @@ void GPU_viewport_free(GPUViewport *viewport)
MEM_freeN(viewport->fbl);
MEM_freeN(viewport->txl);
- if (viewport->vmempool.calls != NULL) {
- BLI_memblock_destroy(viewport->vmempool.calls, NULL);
+ if (viewport->vmempool.commands != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.commands, NULL);
}
- if (viewport->vmempool.states != NULL) {
- BLI_memblock_destroy(viewport->vmempool.states, NULL);
+ if (viewport->vmempool.commands_small != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.commands_small, NULL);
+ }
+ if (viewport->vmempool.callbuffers != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.callbuffers, NULL);
+ }
+ if (viewport->vmempool.obmats != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.obmats, NULL);
+ }
+ if (viewport->vmempool.obinfos != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.obinfos, NULL);
}
if (viewport->vmempool.cullstates != NULL) {
BLI_memblock_destroy(viewport->vmempool.cullstates, NULL);
@@ -651,6 +660,13 @@ void GPU_viewport_free(GPUViewport *viewport)
BLI_memblock_destroy(viewport->vmempool.images, NULL);
}
+ for (int i = 0; i < viewport->vmempool.ubo_len; i++) {
+ GPU_uniformbuffer_free(viewport->vmempool.matrices_ubo[i]);
+ GPU_uniformbuffer_free(viewport->vmempool.obinfos_ubo[i]);
+ }
+ MEM_SAFE_FREE(viewport->vmempool.matrices_ubo);
+ MEM_SAFE_FREE(viewport->vmempool.obinfos_ubo);
+
DRW_instance_data_list_free(viewport->idatalist);
MEM_freeN(viewport->idatalist);
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl
index 0ce5504dfa8..b0fa9eaed21 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl
@@ -4,12 +4,15 @@ uniform vec2 aspect;
in vec2 pos;
-#ifndef STRETCH_ANGLE
-in float stretch;
-#else
-
+#ifdef STRETCH_ANGLE
in vec2 uv_angles;
in float angle;
+
+#else
+in float ratio;
+uniform float totalAreaRatio;
+uniform float totalAreaRatioInv;
+
#endif
noperspective out vec4 finalColor;
@@ -69,6 +72,12 @@ float angle_normalized_v2v2(vec2 v1, vec2 v2)
return (q) ? a : M_PI - a;
}
+float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_tot_ratio)
+{
+ ratio *= (ratio > 0.0f) ? tot_ratio : -inv_tot_ratio;
+ return (ratio > 1.0f) ? (1.0f / ratio) : ratio;
+}
+
void main()
{
gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
@@ -80,6 +89,9 @@ void main()
float stretch = 1.0 - abs(uv_angle - angle);
stretch = stretch;
stretch = 1.0 - stretch * stretch;
+#else
+ float stretch = 1.0 - area_ratio_to_stretch(ratio, totalAreaRatio, -totalAreaRatioInv);
+
#endif
finalColor = vec4(weight_to_rgb(stretch), 1.0);
diff --git a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
new file mode 100644
index 00000000000..aa1d437c307
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
@@ -0,0 +1,19 @@
+
+/* Need to be included after common_view_lib.glsl for resource_id. */
+#ifndef GPU_OBINFOS_UBO
+#define GPU_OBINFOS_UBO
+struct ObjectInfos {
+ vec4 drw_OrcoTexCoFactors[2];
+ vec4 drw_ObjectColor;
+ vec4 drw_Infos;
+};
+
+layout(std140) uniform infoBlock
+{
+ /* DRW_RESOURCE_CHUNK_LEN = 512 */
+ ObjectInfos drw_infos[512];
+};
+#define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors)
+#define ObjectInfo (drw_infos[resource_id].drw_Infos)
+#define ObjectColor (drw_infos[resource_id].drw_ObjectColor)
+#endif
diff --git a/source/blender/gpu/shaders/gpu_shader_geometry.glsl b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
index f62040589e5..3b4e2e17ccc 100644
--- a/source/blender/gpu/shaders/gpu_shader_geometry.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
@@ -24,7 +24,7 @@ uniform int osd_fvar_count;
{ \
vec2 v[4]; \
int primOffset = (gl_PrimitiveID + PrimitiveIdBase) * 4; \
- for (int i = 0; i < 4; ++i) { \
+ for (int i = 0; i < 4; i++) { \
int index = (primOffset + i) * osd_fvar_count + fvarOffset; \
v[i] = vec2(texelFetch(FVarDataBuffer, index).s, texelFetch(FVarDataBuffer, index + 1).s); \
} \
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl
index 31b359dbe6d..f32c47bcec3 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl
@@ -1,8 +1,5 @@
uniform mat4 ViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
-uniform mat4 ModelMatrix;
-#endif
/* ---- Instantiated Attrs ---- */
in float pos;
@@ -47,11 +44,12 @@ void main()
pPos = vec3(0.0);
}
- gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pPos, 1.0);
+ vec4 wPos = InstanceModelMatrix * vec4(pPos, 1.0);
+ gl_Position = ViewProjectionMatrix * wPos;
finalColor = vec4(color, 1.0);
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * InstanceModelMatrix * vec4(pPos, 1.0)).xyz);
+ world_clip_planes_calc_clip_distance(wPos.xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl
index d9a0ffbbdac..5bd29c55e42 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl
@@ -18,13 +18,14 @@ void main()
{
float len = end - start;
vec3 sta = vec3(0.0, 0.0, -start);
- vec4 pos_4d = vec4(pos * -len + sta, 1.0);
- gl_Position = ViewProjectionMatrix * InstanceModelMatrix * pos_4d;
+ vec4 wPos = InstanceModelMatrix * vec4(pos * -len + sta, 1.0);
+
+ gl_Position = ViewProjectionMatrix * wPos;
gl_PointSize = size;
finalColor = vec4(color, 1.0);
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((InstanceModelMatrix * pos_4d).xyz);
+ world_clip_planes_calc_clip_distance(wPos.xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
index 3e52e43beae..10228a1e985 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
@@ -1,6 +1,5 @@
uniform mat4 ViewProjectionMatrix;
-uniform mat4 ModelMatrix;
/* ---- Instantiated Attrs ---- */
in vec3 pos;
@@ -20,10 +19,10 @@ void main()
{
finalColor = color;
- vec4 pos_4d = vec4(pos * size, 1.0);
- gl_Position = ViewProjectionMatrix * InstanceModelMatrix * pos_4d;
+ vec4 wPos = InstanceModelMatrix * vec4(pos * size, 1.0);
+ gl_Position = ViewProjectionMatrix * wPos;
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * InstanceModelMatrix * pos_4d).xyz);
+ world_clip_planes_calc_clip_distance(wPos.xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl
index 130f46e1e33..32db8d17572 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl
@@ -1,8 +1,6 @@
uniform mat4 ViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
-uniform mat4 ModelMatrix;
-#endif
+
uniform int baseId;
/* ---- Instantiated Attrs ---- */
@@ -21,11 +19,11 @@ flat out uint finalId;
void main()
{
- vec4 pos_4d = vec4(pos * size, 1.0);
- gl_Position = ViewProjectionMatrix * InstanceModelMatrix * pos_4d;
+ vec4 wPos = InstanceModelMatrix * vec4(pos * size, 1.0);
+ gl_Position = ViewProjectionMatrix * wPos;
finalId = uint(baseId + callId);
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * InstanceModelMatrix * pos_4d).xyz);
+ world_clip_planes_calc_clip_distance(wPos.xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl
index eeca6e972fa..b8d31f5540a 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl
@@ -9,5 +9,5 @@ in mat4 InstanceModelMatrix;
void main()
{
- gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pos, 1.0);
+ gl_Position = ViewProjectionMatrix * (InstanceModelMatrix * vec4(pos, 1.0));
}
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
deleted file mode 100644
index 24fef4f05d8..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ /dev/null
@@ -1,3874 +0,0 @@
-
-/* Converters */
-
-float convert_rgba_to_float(vec4 color)
-{
- return dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
-}
-
-float exp_blender(float f)
-{
- return pow(2.71828182846, f);
-}
-
-float compatible_pow(float x, float y)
-{
- if (y == 0.0) { /* x^0 -> 1, including 0^0 */
- return 1.0;
- }
-
- /* glsl pow doesn't accept negative x */
- if (x < 0.0) {
- if (mod(-y, 2.0) == 0.0) {
- return pow(-x, y);
- }
- else {
- return -pow(-x, y);
- }
- }
- else if (x == 0.0) {
- return 0.0;
- }
-
- return pow(x, y);
-}
-
-void rgb_to_hsv(vec4 rgb, out vec4 outcol)
-{
- float cmax, cmin, h, s, v, cdelta;
- vec3 c;
-
- cmax = max(rgb[0], max(rgb[1], rgb[2]));
- cmin = min(rgb[0], min(rgb[1], rgb[2]));
- cdelta = cmax - cmin;
-
- v = cmax;
- if (cmax != 0.0) {
- s = cdelta / cmax;
- }
- else {
- s = 0.0;
- h = 0.0;
- }
-
- if (s == 0.0) {
- h = 0.0;
- }
- else {
- c = (vec3(cmax) - rgb.xyz) / cdelta;
-
- if (rgb.x == cmax) {
- h = c[2] - c[1];
- }
- else if (rgb.y == cmax) {
- h = 2.0 + c[0] - c[2];
- }
- else {
- h = 4.0 + c[1] - c[0];
- }
-
- h /= 6.0;
-
- if (h < 0.0) {
- h += 1.0;
- }
- }
-
- outcol = vec4(h, s, v, rgb.w);
-}
-
-void hsv_to_rgb(vec4 hsv, out vec4 outcol)
-{
- float i, f, p, q, t, h, s, v;
- vec3 rgb;
-
- h = hsv[0];
- s = hsv[1];
- v = hsv[2];
-
- if (s == 0.0) {
- rgb = vec3(v, v, v);
- }
- else {
- if (h == 1.0) {
- h = 0.0;
- }
-
- h *= 6.0;
- i = floor(h);
- f = h - i;
- rgb = vec3(f, f, f);
- p = v * (1.0 - s);
- q = v * (1.0 - (s * f));
- t = v * (1.0 - (s * (1.0 - f)));
-
- if (i == 0.0) {
- rgb = vec3(v, t, p);
- }
- else if (i == 1.0) {
- rgb = vec3(q, v, p);
- }
- else if (i == 2.0) {
- rgb = vec3(p, v, t);
- }
- else if (i == 3.0) {
- rgb = vec3(p, q, v);
- }
- else if (i == 4.0) {
- rgb = vec3(t, p, v);
- }
- else {
- rgb = vec3(v, p, q);
- }
- }
-
- outcol = vec4(rgb, hsv.w);
-}
-
-void color_to_normal_new_shading(vec3 color, out vec3 normal)
-{
- normal = vec3(2.0) * color - vec3(1.0);
-}
-
-void color_to_blender_normal_new_shading(vec3 color, out vec3 normal)
-{
- normal = vec3(2.0, -2.0, -2.0) * color - vec3(1.0);
-}
-
-#ifndef M_PI
-# define M_PI 3.14159265358979323846
-#endif
-#ifndef M_1_PI
-# define M_1_PI 0.318309886183790671538
-#endif
-
-/*********** SHADER NODES ***************/
-
-void particle_info(vec4 sprops,
- vec4 loc,
- vec3 vel,
- vec3 avel,
- out float index,
- out float random,
- out float age,
- out float life_time,
- out vec3 location,
- out float size,
- out vec3 velocity,
- out vec3 angular_velocity)
-{
- index = sprops.x;
- random = loc.w;
- age = sprops.y;
- life_time = sprops.z;
- size = sprops.w;
-
- location = loc.xyz;
- velocity = vel;
- angular_velocity = avel;
-}
-
-void vect_normalize(vec3 vin, out vec3 vout)
-{
- vout = normalize(vin);
-}
-
-void direction_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
-{
- vout = (mat * vec4(vin, 0.0)).xyz;
-}
-
-void normal_transform_transposed_m4v3(vec3 vin, mat4 mat, out vec3 vout)
-{
- vout = transpose(mat3(mat)) * vin;
-}
-
-void point_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
-{
- vout = (mat * vec4(vin, 1.0)).xyz;
-}
-
-void point_texco_remap_square(vec3 vin, out vec3 vout)
-{
- vout = vin * 2.0 - 1.0;
-}
-
-void point_texco_clamp(vec3 vin, sampler2D ima, out vec3 vout)
-{
- vec2 half_texel_size = 0.5 / vec2(textureSize(ima, 0).xy);
- vout = clamp(vin, half_texel_size.xyy, 1.0 - half_texel_size.xyy);
-}
-
-void point_map_to_sphere(vec3 vin, out vec3 vout)
-{
- float len = length(vin);
- float v, u;
- if (len > 0.0) {
- if (vin.x == 0.0 && vin.y == 0.0) {
- u = 0.0;
- }
- else {
- u = (1.0 - atan(vin.x, vin.y) / M_PI) / 2.0;
- }
-
- v = 1.0 - acos(vin.z / len) / M_PI;
- }
- else {
- v = u = 0.0;
- }
-
- vout = vec3(u, v, 0.0);
-}
-
-void point_map_to_tube(vec3 vin, out vec3 vout)
-{
- float u, v;
- v = (vin.z + 1.0) * 0.5;
- float len = sqrt(vin.x * vin.x + vin.y * vin[1]);
- if (len > 0.0) {
- u = (1.0 - (atan(vin.x / len, vin.y / len) / M_PI)) * 0.5;
- }
- else {
- v = u = 0.0;
- }
-
- vout = vec3(u, v, 0.0);
-}
-
-void mapping(
- vec3 vec, vec4 m0, vec4 m1, vec4 m2, vec4 m3, vec3 minvec, vec3 maxvec, out vec3 outvec)
-{
- mat4 mat = mat4(m0, m1, m2, m3);
- outvec = (mat * vec4(vec, 1.0)).xyz;
- outvec = clamp(outvec, minvec, maxvec);
-}
-
-void camera(vec3 co, out vec3 outview, out float outdepth, out float outdist)
-{
- outdepth = abs(co.z);
- outdist = length(co);
- outview = normalize(co);
-}
-
-void math_add(float a, float b, out float result)
-{
- result = a + b;
-}
-
-void math_subtract(float a, float b, out float result)
-{
- result = a - b;
-}
-
-void math_multiply(float a, float b, out float result)
-{
- result = a * b;
-}
-
-void math_divide(float a, float b, out float result)
-{
- result = (b != 0.0) ? a / b : 0.0;
-}
-
-void math_power(float a, float b, out float result)
-{
- if (a >= 0.0) {
- result = compatible_pow(a, b);
- }
- else {
- float fraction = mod(abs(b), 1.0);
- if (fraction > 0.999 || fraction < 0.001) {
- result = compatible_pow(a, floor(b + 0.5));
- }
- else {
- result = 0.0;
- }
- }
-}
-
-void math_logarithm(float a, float b, out float result)
-{
- result = (a > 0.0 && b > 0.0) ? log2(a) / log2(b) : 0.0;
-}
-
-void math_sqrt(float a, float b, out float result)
-{
- result = (a > 0.0) ? sqrt(a) : 0.0;
-}
-
-void math_absolute(float a, float b, out float result)
-{
- result = abs(a);
-}
-
-void math_minimum(float a, float b, out float result)
-{
- result = min(a, b);
-}
-
-void math_maximum(float a, float b, out float result)
-{
- result = max(a, b);
-}
-
-void math_less_than(float a, float b, out float result)
-{
- result = (a < b) ? 1.0 : 0.0;
-}
-
-void math_greater_than(float a, float b, out float result)
-{
- result = (a > b) ? 1.0 : 0.0;
-}
-
-void math_round(float a, float b, out float result)
-{
- result = floor(a + 0.5);
-}
-
-void math_floor(float a, float b, out float result)
-{
- result = floor(a);
-}
-
-void math_ceil(float a, float b, out float result)
-{
- result = ceil(a);
-}
-
-void math_fraction(float a, float b, out float result)
-{
- result = a - floor(a);
-}
-
-/* Change sign to match C convention. mod in GLSL will take absolute for negative numbers.
- * See https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/mod.xhtml
- */
-void math_modulo(float a, float b, out float result)
-{
- result = (b != 0.0) ? sign(a) * mod(abs(a), b) : 0.0;
-}
-
-void math_sine(float a, float b, out float result)
-{
- result = sin(a);
-}
-
-void math_cosine(float a, float b, out float result)
-{
- result = cos(a);
-}
-
-void math_tangent(float a, float b, out float result)
-{
- result = tan(a);
-}
-
-void math_arcsine(float a, float b, out float result)
-{
- result = (a <= 1.0 && a >= -1.0) ? asin(a) : 0.0;
-}
-
-void math_arccosine(float a, float b, out float result)
-{
- result = (a <= 1.0 && a >= -1.0) ? acos(a) : 0.0;
-}
-
-void math_arctangent(float a, float b, out float result)
-{
- result = atan(a);
-}
-
-void math_arctan2(float a, float b, out float result)
-{
- result = atan(a, b);
-}
-
-void squeeze(float val, float width, float center, out float outval)
-{
- outval = 1.0 / (1.0 + pow(2.71828183, -((val - center) * width)));
-}
-
-void map_range(
- float value, float fromMin, float fromMax, float toMin, float toMax, out float result)
-{
- if (fromMax != fromMin) {
- result = toMin + ((value - fromMin) / (fromMax - fromMin)) * (toMax - toMin);
- }
- else {
- result = 0.0;
- }
-}
-
-vec3 safe_divide(vec3 a, vec3 b)
-{
- return vec3((b.x != 0.0) ? a.x / b.x : 0.0,
- (b.y != 0.0) ? a.y / b.y : 0.0,
- (b.z != 0.0) ? a.z / b.z : 0.0);
-}
-
-void vector_math_add(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = a + b;
-}
-
-void vector_math_subtract(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = a - b;
-}
-
-void vector_math_multiply(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = a * b;
-}
-
-void vector_math_divide(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = safe_divide(a, b);
-}
-
-void vector_math_cross(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = cross(a, b);
-}
-
-void vector_math_project(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- float lenSquared = dot(b, b);
- outVector = (lenSquared != 0.0) ? (dot(a, b) / lenSquared) * b : vec3(0.0);
-}
-
-void vector_math_reflect(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = reflect(a, normalize(b));
-}
-
-void vector_math_dot(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outValue = dot(a, b);
-}
-
-void vector_math_distance(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outValue = distance(a, b);
-}
-
-void vector_math_length(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outValue = length(a);
-}
-
-void vector_math_scale(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = a * scale;
-}
-
-void vector_math_normalize(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = normalize(a);
-}
-
-void vector_math_snap(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = floor(safe_divide(a, b)) * b;
-}
-
-void vector_math_floor(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = floor(a);
-}
-
-void vector_math_ceil(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = ceil(a);
-}
-
-void vector_math_modulo(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- math_modulo(a.x, b.x, outVector.x);
- math_modulo(a.y, b.y, outVector.y);
- math_modulo(a.z, b.z, outVector.z);
-}
-
-void vector_math_fraction(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = fract(a);
-}
-
-void vector_math_absolute(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = abs(a);
-}
-
-void vector_math_minimum(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = min(a, b);
-}
-
-void vector_math_maximum(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
-{
- outVector = max(a, b);
-}
-
-void vector_math_mix(float strength, vec3 a, vec3 b, out vec3 outVector)
-{
- outVector = strength * a + (1 - strength) * b;
-}
-
-void vec_math_negate(vec3 v, out vec3 outv)
-{
- outv = -v;
-}
-
-void invert_z(vec3 v, out vec3 outv)
-{
- v.z = -v.z;
- outv = v;
-}
-
-void normal_new_shading(vec3 nor, vec3 dir, out vec3 outnor, out float outdot)
-{
- outnor = dir;
- outdot = dot(normalize(nor), dir);
-}
-
-void curves_vec(float fac, vec3 vec, sampler1DArray curvemap, float layer, out vec3 outvec)
-{
- vec4 co = vec4(vec * 0.5 + 0.5, layer);
- outvec.x = texture(curvemap, co.xw).x;
- outvec.y = texture(curvemap, co.yw).y;
- outvec.z = texture(curvemap, co.zw).z;
- outvec = mix(vec, outvec, fac);
-}
-
-/* ext is vec4(in_x, in_dy, out_x, out_dy). */
-float curve_extrapolate(float x, float y, vec4 ext)
-{
- if (x < 0.0) {
- return y + x * ext.y;
- }
- else if (x > 1.0) {
- return y + (x - 1.0) * ext.w;
- }
- else {
- return y;
- }
-}
-
-#define RANGE_RESCALE(x, min, range) ((x - min) * range)
-
-void curves_rgb(float fac,
- vec4 col,
- sampler1DArray curvemap,
- float layer,
- vec4 range,
- vec4 ext_r,
- vec4 ext_g,
- vec4 ext_b,
- vec4 ext_a,
- out vec4 outcol)
-{
- vec4 co = vec4(RANGE_RESCALE(col.rgb, ext_a.x, range.a), layer);
- vec3 samp;
- samp.r = texture(curvemap, co.xw).a;
- samp.g = texture(curvemap, co.yw).a;
- samp.b = texture(curvemap, co.zw).a;
-
- samp.r = curve_extrapolate(co.x, samp.r, ext_a);
- samp.g = curve_extrapolate(co.y, samp.g, ext_a);
- samp.b = curve_extrapolate(co.z, samp.b, ext_a);
-
- vec3 rgb_min = vec3(ext_r.x, ext_g.x, ext_b.x);
- co.xyz = RANGE_RESCALE(samp.rgb, rgb_min, range.rgb);
-
- samp.r = texture(curvemap, co.xw).r;
- samp.g = texture(curvemap, co.yw).g;
- samp.b = texture(curvemap, co.zw).b;
-
- outcol.r = curve_extrapolate(co.x, samp.r, ext_r);
- outcol.g = curve_extrapolate(co.y, samp.g, ext_g);
- outcol.b = curve_extrapolate(co.z, samp.b, ext_b);
- outcol.a = col.a;
-
- outcol = mix(col, outcol, fac);
-}
-
-void curves_rgb_opti(float fac,
- vec4 col,
- sampler1DArray curvemap,
- float layer,
- vec4 range,
- vec4 ext_a,
- out vec4 outcol)
-{
- vec4 co = vec4(RANGE_RESCALE(col.rgb, ext_a.x, range.a), layer);
- vec3 samp;
- samp.r = texture(curvemap, co.xw).a;
- samp.g = texture(curvemap, co.yw).a;
- samp.b = texture(curvemap, co.zw).a;
-
- outcol.r = curve_extrapolate(co.x, samp.r, ext_a);
- outcol.g = curve_extrapolate(co.y, samp.g, ext_a);
- outcol.b = curve_extrapolate(co.z, samp.b, ext_a);
- outcol.a = col.a;
-
- outcol = mix(col, outcol, fac);
-}
-
-void set_value(float val, out float outval)
-{
- outval = val;
-}
-
-void set_rgb(vec3 col, out vec3 outcol)
-{
- outcol = col;
-}
-
-void set_rgba(vec4 col, out vec4 outcol)
-{
- outcol = col;
-}
-
-void set_value_zero(out float outval)
-{
- outval = 0.0;
-}
-
-void set_value_one(out float outval)
-{
- outval = 1.0;
-}
-
-void set_rgb_zero(out vec3 outval)
-{
- outval = vec3(0.0);
-}
-
-void set_rgb_one(out vec3 outval)
-{
- outval = vec3(1.0);
-}
-
-void set_rgba_zero(out vec4 outval)
-{
- outval = vec4(0.0);
-}
-
-void set_rgba_one(out vec4 outval)
-{
- outval = vec4(1.0);
-}
-
-void brightness_contrast(vec4 col, float brightness, float contrast, out vec4 outcol)
-{
- float a = 1.0 + contrast;
- float b = brightness - contrast * 0.5;
-
- outcol.r = max(a * col.r + b, 0.0);
- outcol.g = max(a * col.g + b, 0.0);
- outcol.b = max(a * col.b + b, 0.0);
- outcol.a = col.a;
-}
-
-void mix_blend(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- outcol = mix(col1, col2, fac);
- outcol.a = col1.a;
-}
-
-void mix_add(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- outcol = mix(col1, col1 + col2, fac);
- outcol.a = col1.a;
-}
-
-void mix_mult(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- outcol = mix(col1, col1 * col2, fac);
- outcol.a = col1.a;
-}
-
-void mix_screen(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- float facm = 1.0 - fac;
-
- outcol = vec4(1.0) - (vec4(facm) + fac * (vec4(1.0) - col2)) * (vec4(1.0) - col1);
- outcol.a = col1.a;
-}
-
-void mix_overlay(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- float facm = 1.0 - fac;
-
- outcol = col1;
-
- if (outcol.r < 0.5) {
- outcol.r *= facm + 2.0 * fac * col2.r;
- }
- else {
- outcol.r = 1.0 - (facm + 2.0 * fac * (1.0 - col2.r)) * (1.0 - outcol.r);
- }
-
- if (outcol.g < 0.5) {
- outcol.g *= facm + 2.0 * fac * col2.g;
- }
- else {
- outcol.g = 1.0 - (facm + 2.0 * fac * (1.0 - col2.g)) * (1.0 - outcol.g);
- }
-
- if (outcol.b < 0.5) {
- outcol.b *= facm + 2.0 * fac * col2.b;
- }
- else {
- outcol.b = 1.0 - (facm + 2.0 * fac * (1.0 - col2.b)) * (1.0 - outcol.b);
- }
-}
-
-void mix_sub(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- outcol = mix(col1, col1 - col2, fac);
- outcol.a = col1.a;
-}
-
-void mix_div(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- float facm = 1.0 - fac;
-
- outcol = col1;
-
- if (col2.r != 0.0) {
- outcol.r = facm * outcol.r + fac * outcol.r / col2.r;
- }
- if (col2.g != 0.0) {
- outcol.g = facm * outcol.g + fac * outcol.g / col2.g;
- }
- if (col2.b != 0.0) {
- outcol.b = facm * outcol.b + fac * outcol.b / col2.b;
- }
-}
-
-void mix_diff(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- outcol = mix(col1, abs(col1 - col2), fac);
- outcol.a = col1.a;
-}
-
-void mix_dark(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- outcol.rgb = min(col1.rgb, col2.rgb * fac);
- outcol.a = col1.a;
-}
-
-void mix_light(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- outcol.rgb = max(col1.rgb, col2.rgb * fac);
- outcol.a = col1.a;
-}
-
-void mix_dodge(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- outcol = col1;
-
- if (outcol.r != 0.0) {
- float tmp = 1.0 - fac * col2.r;
- if (tmp <= 0.0) {
- outcol.r = 1.0;
- }
- else if ((tmp = outcol.r / tmp) > 1.0) {
- outcol.r = 1.0;
- }
- else {
- outcol.r = tmp;
- }
- }
- if (outcol.g != 0.0) {
- float tmp = 1.0 - fac * col2.g;
- if (tmp <= 0.0) {
- outcol.g = 1.0;
- }
- else if ((tmp = outcol.g / tmp) > 1.0) {
- outcol.g = 1.0;
- }
- else {
- outcol.g = tmp;
- }
- }
- if (outcol.b != 0.0) {
- float tmp = 1.0 - fac * col2.b;
- if (tmp <= 0.0) {
- outcol.b = 1.0;
- }
- else if ((tmp = outcol.b / tmp) > 1.0) {
- outcol.b = 1.0;
- }
- else {
- outcol.b = tmp;
- }
- }
-}
-
-void mix_burn(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- float tmp, facm = 1.0 - fac;
-
- outcol = col1;
-
- tmp = facm + fac * col2.r;
- if (tmp <= 0.0) {
- outcol.r = 0.0;
- }
- else if ((tmp = (1.0 - (1.0 - outcol.r) / tmp)) < 0.0) {
- outcol.r = 0.0;
- }
- else if (tmp > 1.0) {
- outcol.r = 1.0;
- }
- else {
- outcol.r = tmp;
- }
-
- tmp = facm + fac * col2.g;
- if (tmp <= 0.0) {
- outcol.g = 0.0;
- }
- else if ((tmp = (1.0 - (1.0 - outcol.g) / tmp)) < 0.0) {
- outcol.g = 0.0;
- }
- else if (tmp > 1.0) {
- outcol.g = 1.0;
- }
- else {
- outcol.g = tmp;
- }
-
- tmp = facm + fac * col2.b;
- if (tmp <= 0.0) {
- outcol.b = 0.0;
- }
- else if ((tmp = (1.0 - (1.0 - outcol.b) / tmp)) < 0.0) {
- outcol.b = 0.0;
- }
- else if (tmp > 1.0) {
- outcol.b = 1.0;
- }
- else {
- outcol.b = tmp;
- }
-}
-
-void mix_hue(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- float facm = 1.0 - fac;
-
- outcol = col1;
-
- vec4 hsv, hsv2, tmp;
- rgb_to_hsv(col2, hsv2);
-
- if (hsv2.y != 0.0) {
- rgb_to_hsv(outcol, hsv);
- hsv.x = hsv2.x;
- hsv_to_rgb(hsv, tmp);
-
- outcol = mix(outcol, tmp, fac);
- outcol.a = col1.a;
- }
-}
-
-void mix_sat(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- float facm = 1.0 - fac;
-
- outcol = col1;
-
- vec4 hsv, hsv2;
- rgb_to_hsv(outcol, hsv);
-
- if (hsv.y != 0.0) {
- rgb_to_hsv(col2, hsv2);
-
- hsv.y = facm * hsv.y + fac * hsv2.y;
- hsv_to_rgb(hsv, outcol);
- }
-}
-
-void mix_val(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- float facm = 1.0 - fac;
-
- vec4 hsv, hsv2;
- rgb_to_hsv(col1, hsv);
- rgb_to_hsv(col2, hsv2);
-
- hsv.z = facm * hsv.z + fac * hsv2.z;
- hsv_to_rgb(hsv, outcol);
-}
-
-void mix_color(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- float facm = 1.0 - fac;
-
- outcol = col1;
-
- vec4 hsv, hsv2, tmp;
- rgb_to_hsv(col2, hsv2);
-
- if (hsv2.y != 0.0) {
- rgb_to_hsv(outcol, hsv);
- hsv.x = hsv2.x;
- hsv.y = hsv2.y;
- hsv_to_rgb(hsv, tmp);
-
- outcol = mix(outcol, tmp, fac);
- outcol.a = col1.a;
- }
-}
-
-void mix_soft(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
- float facm = 1.0 - fac;
-
- vec4 one = vec4(1.0);
- vec4 scr = one - (one - col2) * (one - col1);
- outcol = facm * col1 + fac * ((one - col1) * col2 * col1 + col1 * scr);
-}
-
-void mix_linear(float fac, vec4 col1, vec4 col2, out vec4 outcol)
-{
- fac = clamp(fac, 0.0, 1.0);
-
- outcol = col1 + fac * (2.0 * (col2 - vec4(0.5)));
-}
-
-void valtorgb_opti_constant(
- float fac, float edge, vec4 color1, vec4 color2, out vec4 outcol, out float outalpha)
-{
- outcol = (fac > edge) ? color2 : color1;
- outalpha = outcol.a;
-}
-
-void valtorgb_opti_linear(
- float fac, vec2 mulbias, vec4 color1, vec4 color2, out vec4 outcol, out float outalpha)
-{
- fac = clamp(fac * mulbias.x + mulbias.y, 0.0, 1.0);
- outcol = mix(color1, color2, fac);
- outalpha = outcol.a;
-}
-
-void valtorgb(float fac, sampler1DArray colormap, float layer, out vec4 outcol, out float outalpha)
-{
- outcol = texture(colormap, vec2(fac, layer));
- outalpha = outcol.a;
-}
-
-void valtorgb_nearest(
- float fac, sampler1DArray colormap, float layer, out vec4 outcol, out float outalpha)
-{
- fac = clamp(fac, 0.0, 1.0);
- outcol = texelFetch(colormap, ivec2(fac * (textureSize(colormap, 0).x - 1), layer), 0);
- outalpha = outcol.a;
-}
-
-void rgbtobw(vec4 color, out float outval)
-{
- vec3 factors = vec3(0.2126, 0.7152, 0.0722);
- outval = dot(color.rgb, factors);
-}
-
-void invert(float fac, vec4 col, out vec4 outcol)
-{
- outcol.xyz = mix(col.xyz, vec3(1.0) - col.xyz, fac);
- outcol.w = col.w;
-}
-
-void clamp_vec3(vec3 vec, vec3 min, vec3 max, out vec3 out_vec)
-{
- out_vec = clamp(vec, min, max);
-}
-
-void clamp_value(float value, float min, float max, out float result)
-{
- result = clamp(value, min, max);
-}
-
-void hue_sat(float hue, float sat, float value, float fac, vec4 col, out vec4 outcol)
-{
- vec4 hsv;
-
- rgb_to_hsv(col, hsv);
-
- hsv[0] = fract(hsv[0] + hue + 0.5);
- hsv[1] = clamp(hsv[1] * sat, 0.0, 1.0);
- hsv[2] = hsv[2] * value;
-
- hsv_to_rgb(hsv, outcol);
-
- outcol = mix(col, outcol, fac);
-}
-
-void separate_rgb(vec4 col, out float r, out float g, out float b)
-{
- r = col.r;
- g = col.g;
- b = col.b;
-}
-
-void combine_rgb(float r, float g, float b, out vec4 col)
-{
- col = vec4(r, g, b, 1.0);
-}
-
-void separate_xyz(vec3 vec, out float x, out float y, out float z)
-{
- x = vec.r;
- y = vec.g;
- z = vec.b;
-}
-
-void combine_xyz(float x, float y, float z, out vec3 vec)
-{
- vec = vec3(x, y, z);
-}
-
-void separate_hsv(vec4 col, out float h, out float s, out float v)
-{
- vec4 hsv;
-
- rgb_to_hsv(col, hsv);
- h = hsv[0];
- s = hsv[1];
- v = hsv[2];
-}
-
-void combine_hsv(float h, float s, float v, out vec4 col)
-{
- hsv_to_rgb(vec4(h, s, v, 1.0), col);
-}
-
-void output_node(vec4 rgb, float alpha, out vec4 outrgb)
-{
- outrgb = vec4(rgb.rgb, alpha);
-}
-
-/*********** TEXTURES ***************/
-
-void texco_norm(vec3 normal, out vec3 outnormal)
-{
- /* corresponds to shi->orn, which is negated so cancels
- out blender normal negation */
- outnormal = normalize(normal);
-}
-
-vec3 mtex_2d_mapping(vec3 vec)
-{
- return vec3(vec.xy * 0.5 + vec2(0.5), vec.z);
-}
-
-/** helper method to extract the upper left 3x3 matrix from a 4x4 matrix */
-mat3 to_mat3(mat4 m4)
-{
- mat3 m3;
- m3[0] = m4[0].xyz;
- m3[1] = m4[1].xyz;
- m3[2] = m4[2].xyz;
- return m3;
-}
-
-/*********** NEW SHADER UTILITIES **************/
-
-float fresnel_dielectric_0(float eta)
-{
- /* compute fresnel reflactance at normal incidence => cosi = 1.0 */
- float A = (eta - 1.0) / (eta + 1.0);
-
- return A * A;
-}
-
-float fresnel_dielectric_cos(float cosi, float eta)
-{
- /* compute fresnel reflectance without explicitly computing
- * the refracted direction */
- float c = abs(cosi);
- float g = eta * eta - 1.0 + c * c;
- float result;
-
- if (g > 0.0) {
- g = sqrt(g);
- float A = (g - c) / (g + c);
- float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0);
- result = 0.5 * A * A * (1.0 + B * B);
- }
- else {
- result = 1.0; /* TIR (no refracted component) */
- }
-
- return result;
-}
-
-float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
-{
- /* compute fresnel reflectance without explicitly computing
- * the refracted direction */
- return fresnel_dielectric_cos(dot(Incoming, Normal), eta);
-}
-
-float hypot(float x, float y)
-{
- return sqrt(x * x + y * y);
-}
-
-void generated_from_orco(vec3 orco, out vec3 generated)
-{
-#ifdef VOLUMETRICS
-# ifdef MESH_SHADER
- generated = volumeObjectLocalCoord;
-# else
- generated = worldPosition;
-# endif
-#else
- generated = orco;
-#endif
-}
-
-int floor_to_int(float x)
-{
- return int(floor(x));
-}
-
-int quick_floor(float x)
-{
- return int(x) - ((x < 0) ? 1 : 0);
-}
-
-float integer_noise(int n)
-{
- int nn;
- n = (n + 1013) & 0x7fffffff;
- n = (n >> 13) ^ n;
- nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
- return 0.5 * (float(nn) / 1073741824.0);
-}
-
-/* ***** Jenkins Lookup3 Hash Functions ***** */
-
-/* Source: http://burtleburtle.net/bob/c/lookup3.c */
-
-#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
-
-#define mix(a, b, c) \
- { \
- a -= c; \
- a ^= rot(c, 4); \
- c += b; \
- b -= a; \
- b ^= rot(a, 6); \
- a += c; \
- c -= b; \
- c ^= rot(b, 8); \
- b += a; \
- a -= c; \
- a ^= rot(c, 16); \
- c += b; \
- b -= a; \
- b ^= rot(a, 19); \
- a += c; \
- c -= b; \
- c ^= rot(b, 4); \
- b += a; \
- }
-
-#define final(a, b, c) \
- { \
- c ^= b; \
- c -= rot(b, 14); \
- a ^= c; \
- a -= rot(c, 11); \
- b ^= a; \
- b -= rot(a, 25); \
- c ^= b; \
- c -= rot(b, 16); \
- a ^= c; \
- a -= rot(c, 4); \
- b ^= a; \
- b -= rot(a, 14); \
- c ^= b; \
- c -= rot(b, 24); \
- }
-
-uint hash_uint(uint kx)
-{
- uint a, b, c;
- a = b = c = 0xdeadbeefu + (1u << 2u) + 13u;
-
- a += kx;
- final(a, b, c);
-
- return c;
-}
-
-uint hash_uint2(uint kx, uint ky)
-{
- uint a, b, c;
- a = b = c = 0xdeadbeefu + (2u << 2u) + 13u;
-
- b += ky;
- a += kx;
- final(a, b, c);
-
- return c;
-}
-
-uint hash_uint3(uint kx, uint ky, uint kz)
-{
- uint a, b, c;
- a = b = c = 0xdeadbeefu + (3u << 2u) + 13u;
-
- c += kz;
- b += ky;
- a += kx;
- final(a, b, c);
-
- return c;
-}
-
-uint hash_uint4(uint kx, uint ky, uint kz, uint kw)
-{
- uint a, b, c;
- a = b = c = 0xdeadbeefu + (4u << 2u) + 13u;
-
- a += kx;
- b += ky;
- c += kz;
- mix(a, b, c);
-
- a += kw;
- final(a, b, c);
-
- return c;
-}
-
-#undef rot
-#undef final
-#undef mix
-
-uint hash_int(int kx)
-{
- return hash_uint(uint(kx));
-}
-
-uint hash_int2(int kx, int ky)
-{
- return hash_uint2(uint(kx), uint(ky));
-}
-
-uint hash_int3(int kx, int ky, int kz)
-{
- return hash_uint3(uint(kx), uint(ky), uint(kz));
-}
-
-uint hash_int4(int kx, int ky, int kz, int kw)
-{
- return hash_uint4(uint(kx), uint(ky), uint(kz), uint(kw));
-}
-
-/* Hashing uint or uint[234] into a float in the range [0, 1]. */
-
-float hash_uint_to_float(uint kx)
-{
- return float(hash_uint(kx)) / float(0xFFFFFFFFu);
-}
-
-float hash_uint2_to_float(uint kx, uint ky)
-{
- return float(hash_uint2(kx, ky)) / float(0xFFFFFFFFu);
-}
-
-float hash_uint3_to_float(uint kx, uint ky, uint kz)
-{
- return float(hash_uint3(kx, ky, kz)) / float(0xFFFFFFFFu);
-}
-
-float hash_uint4_to_float(uint kx, uint ky, uint kz, uint kw)
-{
- return float(hash_uint4(kx, ky, kz, kw)) / float(0xFFFFFFFFu);
-}
-
-/* Hashing float or vec[234] into a float in the range [0, 1]. */
-
-float hash_float_to_float(float k)
-{
- return hash_uint_to_float(floatBitsToUint(k));
-}
-
-float hash_vec2_to_float(vec2 k)
-{
- return hash_uint2_to_float(floatBitsToUint(k.x), floatBitsToUint(k.y));
-}
-
-float hash_vec3_to_float(vec3 k)
-{
- return hash_uint3_to_float(floatBitsToUint(k.x), floatBitsToUint(k.y), floatBitsToUint(k.z));
-}
-
-float hash_vec4_to_float(vec4 k)
-{
- return hash_uint4_to_float(
- floatBitsToUint(k.x), floatBitsToUint(k.y), floatBitsToUint(k.z), floatBitsToUint(k.w));
-}
-
-/* Hashing vec[234] into vec[234] of components in the range [0, 1]. */
-
-vec2 hash_vec2_to_vec2(vec2 k)
-{
- return vec2(hash_vec2_to_float(k), hash_vec3_to_float(vec3(k, 1.0)));
-}
-
-vec3 hash_vec3_to_vec3(vec3 k)
-{
- return vec3(
- hash_vec3_to_float(k), hash_vec4_to_float(vec4(k, 1.0)), hash_vec4_to_float(vec4(k, 2.0)));
-}
-
-vec4 hash_vec4_to_vec4(vec4 k)
-{
- return vec4(hash_vec4_to_float(k.xyzw),
- hash_vec4_to_float(k.wxyz),
- hash_vec4_to_float(k.zwxy),
- hash_vec4_to_float(k.yzwx));
-}
-
-/* Hashing float or vec[234] into vec3 of components in range [0, 1]. */
-
-vec3 hash_float_to_vec3(float k)
-{
- return vec3(
- hash_float_to_float(k), hash_vec2_to_float(vec2(k, 1.0)), hash_vec2_to_float(vec2(k, 2.0)));
-}
-
-vec3 hash_vec2_to_vec3(vec2 k)
-{
- return vec3(
- hash_vec2_to_float(k), hash_vec3_to_float(vec3(k, 1.0)), hash_vec3_to_float(vec3(k, 2.0)));
-}
-
-vec3 hash_vec4_to_vec3(vec4 k)
-{
- return vec3(hash_vec4_to_float(k.xyzw), hash_vec4_to_float(k.zxwy), hash_vec4_to_float(k.wzyx));
-}
-
-/* White Noise */
-
-void node_white_noise_1d(vec3 vector, float w, out float value)
-{
- value = hash_float_to_float(w);
-}
-
-void node_white_noise_2d(vec3 vector, float w, out float value)
-{
- value = hash_vec2_to_float(vector.xy);
-}
-
-void node_white_noise_3d(vec3 vector, float w, out float value)
-{
- value = hash_vec3_to_float(vector);
-}
-
-void node_white_noise_4d(vec3 vector, float w, out float value)
-{
- value = hash_vec4_to_float(vec4(vector, w));
-}
-
-/* Cell Noise */
-
-float bits_to_01(uint bits)
-{
- return (float(bits) / 4294967295.0);
-}
-
-float cellnoise(vec3 p)
-{
- int ix = quick_floor(p.x);
- int iy = quick_floor(p.y);
- int iz = quick_floor(p.z);
-
- return hash_uint3_to_float(uint(ix), uint(iy), uint(iz));
-}
-
-vec3 cellnoise_color(vec3 p)
-{
- float r = cellnoise(p.xyz);
- float g = cellnoise(p.yxz);
- float b = cellnoise(p.yzx);
-
- return vec3(r, g, b);
-}
-
-float floorfrac(float x, out int i)
-{
- float x_floor = floor(x);
- i = int(x_floor);
- return x - x_floor;
-}
-
-/* bsdfs */
-
-vec3 tint_from_color(vec3 color)
-{
- float lum = dot(color, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
- return (lum > 0) ? color / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */
-}
-
-void convert_metallic_to_specular_tinted(vec3 basecol,
- vec3 basecol_tint,
- float metallic,
- float specular_fac,
- float specular_tint,
- out vec3 diffuse,
- out vec3 f0)
-{
- vec3 tmp_col = mix(vec3(1.0), basecol_tint, specular_tint);
- f0 = mix((0.08 * specular_fac) * tmp_col, basecol, metallic);
- diffuse = basecol * (1.0 - metallic);
-}
-
-vec3 principled_sheen(float NV, vec3 basecol_tint, float sheen_tint)
-{
- float f = 1.0 - NV;
- /* Temporary fix for T59784. Normal map seems to contain NaNs for tangent space normal maps,
- * therefore we need to clamp value. */
- f = clamp(f, 0.0, 1.0);
- /* Empirical approximation (manual curve fitting). Can be refined. */
- float sheen = f * f * f * 0.077 + f * 0.01 + 0.00026;
- return sheen * mix(vec3(1.0), basecol_tint, sheen_tint);
-}
-
-#ifndef VOLUMETRICS
-void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
-{
- N = normalize(N);
- result = CLOSURE_DEFAULT;
- eevee_closure_diffuse(N, color.rgb, 1.0, result.radiance);
- closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
- result.radiance *= color.rgb;
-}
-
-void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Closure result)
-{
- N = normalize(N);
- vec3 out_spec, ssr_spec;
- eevee_closure_glossy(N, vec3(1.0), vec3(1.0), int(ssr_id), roughness, 1.0, out_spec, ssr_spec);
- vec3 vN = mat3(ViewMatrix) * N;
- result = CLOSURE_DEFAULT;
- result.radiance = out_spec * color.rgb;
- closure_load_ssr_data(ssr_spec * color.rgb, roughness, N, viewCameraVec, int(ssr_id), result);
-}
-
-void node_bsdf_anisotropic(vec4 color,
- float roughness,
- float anisotropy,
- float rotation,
- vec3 N,
- vec3 T,
- out Closure result)
-{
- node_bsdf_glossy(color, roughness, N, -1, result);
-}
-
-void node_bsdf_glass(
- vec4 color, float roughness, float ior, vec3 N, float ssr_id, out Closure result)
-{
- N = normalize(N);
- vec3 out_spec, out_refr, ssr_spec;
- vec3 refr_color = (refractionDepth > 0.0) ? color.rgb * color.rgb :
- color.rgb; /* Simulate 2 transmission event */
- eevee_closure_glass(
- N, vec3(1.0), vec3(1.0), int(ssr_id), roughness, 1.0, ior, out_spec, out_refr, ssr_spec);
- out_refr *= refr_color;
- out_spec *= color.rgb;
- float fresnel = F_eta(ior, dot(N, cameraVec));
- vec3 vN = mat3(ViewMatrix) * N;
- result = CLOSURE_DEFAULT;
- result.radiance = mix(out_refr, out_spec, fresnel);
- closure_load_ssr_data(
- ssr_spec * color.rgb * fresnel, roughness, N, viewCameraVec, int(ssr_id), result);
-}
-
-void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure result)
-{
- node_bsdf_diffuse(color, 0.0, N, result);
-}
-
-void node_bsdf_principled(vec4 base_color,
- float subsurface,
- vec3 subsurface_radius,
- vec4 subsurface_color,
- float metallic,
- float specular,
- float specular_tint,
- float roughness,
- float anisotropic,
- float anisotropic_rotation,
- float sheen,
- float sheen_tint,
- float clearcoat,
- float clearcoat_roughness,
- float ior,
- float transmission,
- float transmission_roughness,
- vec4 emission,
- float alpha,
- vec3 N,
- vec3 CN,
- vec3 T,
- vec3 I,
- float ssr_id,
- float sss_id,
- vec3 sss_scale,
- out Closure result)
-{
- N = normalize(N);
- ior = max(ior, 1e-5);
- metallic = saturate(metallic);
- transmission = saturate(transmission);
- float dielectric = 1.0 - metallic;
- transmission *= dielectric;
- sheen *= dielectric;
- subsurface_color *= dielectric;
-
- vec3 diffuse, f0, out_diff, out_spec, out_trans, out_refr, ssr_spec;
- vec3 ctint = tint_from_color(base_color.rgb);
- convert_metallic_to_specular_tinted(
- base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
-
- float NV = dot(N, cameraVec);
- vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
-
- /* Far from being accurate, but 2 glossy evaluation is too expensive.
- * Most noticeable difference is at grazing angles since the bsdf lut
- * f0 color interpolation is done on top of this interpolation. */
- vec3 f0_glass = mix(vec3(1.0), base_color.rgb, specular_tint);
- float fresnel = F_eta(ior, NV);
- vec3 spec_col = F_color_blend(ior, fresnel, f0_glass) * fresnel;
- f0 = mix(f0, spec_col, transmission);
-
- vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic);
-
- vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
-
- float sss_scalef = avg(sss_scale) * subsurface;
- eevee_closure_principled(N,
- mixed_ss_base_color,
- f0,
- f90,
- int(ssr_id),
- roughness,
- CN,
- clearcoat * 0.25,
- clearcoat_roughness,
- 1.0,
- sss_scalef,
- ior,
- out_diff,
- out_trans,
- out_spec,
- out_refr,
- ssr_spec);
-
- vec3 refr_color = base_color.rgb;
- refr_color *= (refractionDepth > 0.0) ? refr_color :
- vec3(1.0); /* Simulate 2 transmission event */
- out_refr *= refr_color * (1.0 - fresnel) * transmission;
-
- result = CLOSURE_DEFAULT;
- result.radiance = out_spec + out_refr;
- result.radiance += out_diff * out_sheen; /* Coarse approx. */
-
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
-
- vec3 sss_radiance = (out_diff + out_trans) * alpha;
-# ifndef USE_SSS
- result.radiance += sss_radiance * mixed_ss_base_color * (1.0 - transmission);
-# else
-# ifdef USE_SSS_ALBEDO
- vec3 sss_albedo = mixed_ss_base_color;
-# else
- sss_radiance *= mixed_ss_base_color;
-# endif
- sss_radiance *= (1.0 - transmission);
- closure_load_sss_data(sss_scalef,
- sss_radiance,
-# ifdef USE_SSS_ALBEDO
- sss_albedo,
-# endif
- int(sss_id),
- result);
-# endif /* USE_SSS */
-
- result.radiance += emission.rgb;
- result.radiance *= alpha;
- result.transmittance = vec3(1.0 - alpha);
-}
-
-void node_bsdf_principled_dielectric(vec4 base_color,
- float subsurface,
- vec3 subsurface_radius,
- vec4 subsurface_color,
- float metallic,
- float specular,
- float specular_tint,
- float roughness,
- float anisotropic,
- float anisotropic_rotation,
- float sheen,
- float sheen_tint,
- float clearcoat,
- float clearcoat_roughness,
- float ior,
- float transmission,
- float transmission_roughness,
- vec4 emission,
- float alpha,
- vec3 N,
- vec3 CN,
- vec3 T,
- vec3 I,
- float ssr_id,
- float sss_id,
- vec3 sss_scale,
- out Closure result)
-{
- N = normalize(N);
- metallic = saturate(metallic);
- float dielectric = 1.0 - metallic;
-
- vec3 diffuse, f0, out_diff, out_spec, ssr_spec;
- vec3 ctint = tint_from_color(base_color.rgb);
- convert_metallic_to_specular_tinted(
- base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
-
- float NV = dot(N, cameraVec);
- vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
-
- eevee_closure_default(
- N, diffuse, f0, vec3(1.0), int(ssr_id), roughness, 1.0, out_diff, out_spec, ssr_spec);
-
- result = CLOSURE_DEFAULT;
- result.radiance = out_spec + out_diff * (diffuse + out_sheen);
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
- result.radiance += emission.rgb;
- result.radiance *= alpha;
- result.transmittance = vec3(1.0 - alpha);
-}
-
-void node_bsdf_principled_metallic(vec4 base_color,
- float subsurface,
- vec3 subsurface_radius,
- vec4 subsurface_color,
- float metallic,
- float specular,
- float specular_tint,
- float roughness,
- float anisotropic,
- float anisotropic_rotation,
- float sheen,
- float sheen_tint,
- float clearcoat,
- float clearcoat_roughness,
- float ior,
- float transmission,
- float transmission_roughness,
- vec4 emission,
- float alpha,
- vec3 N,
- vec3 CN,
- vec3 T,
- vec3 I,
- float ssr_id,
- float sss_id,
- vec3 sss_scale,
- out Closure result)
-{
- N = normalize(N);
- vec3 out_spec, ssr_spec;
-
- vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
-
- eevee_closure_glossy(N, base_color.rgb, f90, int(ssr_id), roughness, 1.0, out_spec, ssr_spec);
-
- result = CLOSURE_DEFAULT;
- result.radiance = out_spec;
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
- result.radiance += emission.rgb;
- result.radiance *= alpha;
- result.transmittance = vec3(1.0 - alpha);
-}
-
-void node_bsdf_principled_clearcoat(vec4 base_color,
- float subsurface,
- vec3 subsurface_radius,
- vec4 subsurface_color,
- float metallic,
- float specular,
- float specular_tint,
- float roughness,
- float anisotropic,
- float anisotropic_rotation,
- float sheen,
- float sheen_tint,
- float clearcoat,
- float clearcoat_roughness,
- float ior,
- float transmission,
- float transmission_roughness,
- vec4 emission,
- float alpha,
- vec3 N,
- vec3 CN,
- vec3 T,
- vec3 I,
- float ssr_id,
- float sss_id,
- vec3 sss_scale,
- out Closure result)
-{
- vec3 out_spec, ssr_spec;
- N = normalize(N);
-
- vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
-
- eevee_closure_clearcoat(N,
- base_color.rgb,
- f90,
- int(ssr_id),
- roughness,
- CN,
- clearcoat * 0.25,
- clearcoat_roughness,
- 1.0,
- out_spec,
- ssr_spec);
-
- result = CLOSURE_DEFAULT;
- result.radiance = out_spec;
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
- result.radiance += emission.rgb;
- result.radiance *= alpha;
- result.transmittance = vec3(1.0 - alpha);
-}
-
-void node_bsdf_principled_subsurface(vec4 base_color,
- float subsurface,
- vec3 subsurface_radius,
- vec4 subsurface_color,
- float metallic,
- float specular,
- float specular_tint,
- float roughness,
- float anisotropic,
- float anisotropic_rotation,
- float sheen,
- float sheen_tint,
- float clearcoat,
- float clearcoat_roughness,
- float ior,
- float transmission,
- float transmission_roughness,
- vec4 emission,
- float alpha,
- vec3 N,
- vec3 CN,
- vec3 T,
- vec3 I,
- float ssr_id,
- float sss_id,
- vec3 sss_scale,
- out Closure result)
-{
- metallic = saturate(metallic);
- N = normalize(N);
-
- vec3 diffuse, f0, out_diff, out_spec, out_trans, ssr_spec;
- vec3 ctint = tint_from_color(base_color.rgb);
- convert_metallic_to_specular_tinted(
- base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
-
- subsurface_color = subsurface_color * (1.0 - metallic);
- vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
- float sss_scalef = avg(sss_scale) * subsurface;
-
- float NV = dot(N, cameraVec);
- vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
-
- vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
-
- eevee_closure_skin(N,
- mixed_ss_base_color,
- f0,
- f90,
- int(ssr_id),
- roughness,
- 1.0,
- sss_scalef,
- out_diff,
- out_trans,
- out_spec,
- ssr_spec);
-
- result = CLOSURE_DEFAULT;
- result.radiance = out_spec;
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
-
- vec3 sss_radiance = (out_diff + out_trans) * alpha;
-# ifndef USE_SSS
- result.radiance += sss_radiance * mixed_ss_base_color * (1.0 - transmission);
-# else
-# ifdef USE_SSS_ALBEDO
- vec3 sss_albedo = mixed_ss_base_color;
-# else
- sss_radiance *= mixed_ss_base_color;
-# endif
- sss_radiance *= (1.0 - transmission);
- closure_load_sss_data(sss_scalef,
- sss_radiance,
-# ifdef USE_SSS_ALBEDO
- sss_albedo,
-# endif
- int(sss_id),
- result);
-# endif /* USE_SSS */
-
- result.radiance += out_diff * out_sheen;
- result.radiance += emission.rgb;
- result.radiance *= alpha;
- result.transmittance = vec3(1.0 - alpha);
-}
-
-void node_bsdf_principled_glass(vec4 base_color,
- float subsurface,
- vec3 subsurface_radius,
- vec4 subsurface_color,
- float metallic,
- float specular,
- float specular_tint,
- float roughness,
- float anisotropic,
- float anisotropic_rotation,
- float sheen,
- float sheen_tint,
- float clearcoat,
- float clearcoat_roughness,
- float ior,
- float transmission,
- float transmission_roughness,
- vec4 emission,
- float alpha,
- vec3 N,
- vec3 CN,
- vec3 T,
- vec3 I,
- float ssr_id,
- float sss_id,
- vec3 sss_scale,
- out Closure result)
-{
- ior = max(ior, 1e-5);
- N = normalize(N);
-
- vec3 f0, out_spec, out_refr, ssr_spec;
- f0 = mix(vec3(1.0), base_color.rgb, specular_tint);
-
- eevee_closure_glass(
- N, vec3(1.0), vec3(1.0), int(ssr_id), roughness, 1.0, ior, out_spec, out_refr, ssr_spec);
-
- vec3 refr_color = base_color.rgb;
- refr_color *= (refractionDepth > 0.0) ? refr_color :
- vec3(1.0); /* Simulate 2 transmission events */
- out_refr *= refr_color;
-
- float fresnel = F_eta(ior, dot(N, cameraVec));
- vec3 spec_col = F_color_blend(ior, fresnel, f0);
- out_spec *= spec_col;
- ssr_spec *= spec_col * fresnel;
-
- result = CLOSURE_DEFAULT;
- result.radiance = mix(out_refr, out_spec, fresnel);
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
- result.radiance += emission.rgb;
- result.radiance *= alpha;
- result.transmittance = vec3(1.0 - alpha);
-}
-
-void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
-{
- node_bsdf_diffuse(color, 0.0, -N, result);
-}
-
-void node_bsdf_transparent(vec4 color, out Closure result)
-{
- result = CLOSURE_DEFAULT;
- result.radiance = vec3(0.0);
- result.transmittance = abs(color.rgb);
-}
-
-void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out Closure result)
-{
- node_bsdf_diffuse(color, 0.0, N, result);
-}
-
-void node_subsurface_scattering(vec4 color,
- float scale,
- vec3 radius,
- float sharpen,
- float texture_blur,
- vec3 N,
- float sss_id,
- out Closure result)
-{
-# if defined(USE_SSS)
- N = normalize(N);
- vec3 out_diff, out_trans;
- vec3 vN = mat3(ViewMatrix) * N;
- result = CLOSURE_DEFAULT;
- closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
-
- eevee_closure_subsurface(N, color.rgb, 1.0, scale, out_diff, out_trans);
-
- vec3 sss_radiance = out_diff + out_trans;
-# ifdef USE_SSS_ALBEDO
- /* Not perfect for texture_blur not exactly equal to 0.0 or 1.0. */
- vec3 sss_albedo = mix(color.rgb, vec3(1.0), texture_blur);
- sss_radiance *= mix(vec3(1.0), color.rgb, texture_blur);
-# else
- sss_radiance *= color.rgb;
-# endif
- closure_load_sss_data(scale,
- sss_radiance,
-# ifdef USE_SSS_ALBEDO
- sss_albedo,
-# endif
- int(sss_id),
- result);
-# else
- node_bsdf_diffuse(color, 0.0, N, result);
-# endif
-}
-
-void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Closure result)
-{
- N = normalize(N);
- vec3 out_refr;
- color.rgb *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); /* Simulate 2 absorption event. */
- eevee_closure_refraction(N, roughness, ior, out_refr);
- vec3 vN = mat3(ViewMatrix) * N;
- result = CLOSURE_DEFAULT;
- result.ssr_normal = normal_encode(vN, viewCameraVec);
- result.radiance = out_refr * color.rgb;
-}
-
-void node_ambient_occlusion(
- vec4 color, float distance, vec3 normal, out vec4 result_color, out float result_ao)
-{
- vec3 bent_normal;
- vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0);
- result_ao = occlusion_compute(normalize(normal), viewPosition, 1.0, rand, bent_normal);
- result_color = result_ao * color;
-}
-
-void node_wireframe(float size, vec2 barycentric, vec3 barycentric_dist, out float fac)
-{
- vec3 barys = barycentric.xyy;
- barys.z = 1.0 - barycentric.x - barycentric.y;
-
- size *= 0.5;
- vec3 s = step(-size, -barys * barycentric_dist);
-
- fac = max(s.x, max(s.y, s.z));
-}
-
-void node_wireframe_screenspace(float size, vec2 barycentric, out float fac)
-{
- vec3 barys = barycentric.xyy;
- barys.z = 1.0 - barycentric.x - barycentric.y;
-
- size *= (1.0 / 3.0);
- vec3 dx = dFdx(barys);
- vec3 dy = dFdy(barys);
- vec3 deltas = sqrt(dx * dx + dy * dy);
-
- vec3 s = step(-deltas * size, -barys);
-
- fac = max(s.x, max(s.y, s.z));
-}
-
-#else /* VOLUMETRICS */
-
-/* Stub all bsdf functions not compatible with volumetrics. */
-# define node_bsdf_diffuse
-# define node_bsdf_glossy
-# define node_bsdf_anisotropic
-# define node_bsdf_glass
-# define node_bsdf_toon
-# define node_bsdf_principled
-# define node_bsdf_principled_dielectric
-# define node_bsdf_principled_metallic
-# define node_bsdf_principled_clearcoat
-# define node_bsdf_principled_subsurface
-# define node_bsdf_principled_glass
-# define node_bsdf_translucent
-# define node_bsdf_transparent
-# define node_bsdf_velvet
-# define node_subsurface_scattering
-# define node_bsdf_refraction
-# define node_ambient_occlusion
-# define node_wireframe
-# define node_wireframe_screenspace
-
-#endif /* VOLUMETRICS */
-
-/* emission */
-
-void node_emission(vec4 color, float strength, vec3 vN, out Closure result)
-{
- result = CLOSURE_DEFAULT;
-#ifndef VOLUMETRICS
- result.radiance = color.rgb * strength;
- result.ssr_normal = normal_encode(vN, viewCameraVec);
-#else
- result.emission = color.rgb * strength;
-#endif
-}
-
-/* background */
-
-void node_tex_environment_texco(vec3 viewvec, out vec3 worldvec)
-{
-#ifdef MESH_SHADER
- worldvec = worldPosition;
-#else
- vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(viewvec, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
- vec4 co_homogenous = (ProjectionMatrixInverse * v);
-
- vec3 co = co_homogenous.xyz / co_homogenous.w;
-# if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
- worldvec = mat3(ViewMatrixInverse) * co;
-# else
- worldvec = mat3(ModelMatrixInverse) * (mat3(ViewMatrixInverse) * co);
-# endif
-#endif
-}
-
-void node_background(vec4 color, float strength, out Closure result)
-{
-#ifndef VOLUMETRICS
- color *= strength;
- result = CLOSURE_DEFAULT;
- result.radiance = color.rgb;
- result.transmittance = vec3(0.0);
-#else
- result = CLOSURE_DEFAULT;
-#endif
-}
-
-/* volumes */
-
-void node_volume_scatter(vec4 color, float density, float anisotropy, out Closure result)
-{
-#ifdef VOLUMETRICS
- result = Closure(vec3(0.0), color.rgb * density, vec3(0.0), anisotropy);
-#else
- result = CLOSURE_DEFAULT;
-#endif
-}
-
-void node_volume_absorption(vec4 color, float density, out Closure result)
-{
-#ifdef VOLUMETRICS
- result = Closure((1.0 - color.rgb) * density, vec3(0.0), vec3(0.0), 0.0);
-#else
- result = CLOSURE_DEFAULT;
-#endif
-}
-
-void node_blackbody(float temperature, sampler1DArray spectrummap, float layer, out vec4 color)
-{
- if (temperature >= 12000.0) {
- color = vec4(0.826270103, 0.994478524, 1.56626022, 1.0);
- }
- else if (temperature < 965.0) {
- color = vec4(4.70366907, 0.0, 0.0, 1.0);
- }
- else {
- float t = (temperature - 965.0) / (12000.0 - 965.0);
- color = vec4(texture(spectrummap, vec2(t, layer)).rgb, 1.0);
- }
-}
-
-void node_volume_principled(vec4 color,
- float density,
- float anisotropy,
- vec4 absorption_color,
- float emission_strength,
- vec4 emission_color,
- float blackbody_intensity,
- vec4 blackbody_tint,
- float temperature,
- float density_attribute,
- vec4 color_attribute,
- float temperature_attribute,
- sampler1DArray spectrummap,
- float layer,
- out Closure result)
-{
-#ifdef VOLUMETRICS
- vec3 absorption_coeff = vec3(0.0);
- vec3 scatter_coeff = vec3(0.0);
- vec3 emission_coeff = vec3(0.0);
-
- /* Compute density. */
- density = max(density, 0.0);
-
- if (density > 1e-5) {
- density = max(density * density_attribute, 0.0);
- }
-
- if (density > 1e-5) {
- /* Compute scattering and absorption coefficients. */
- vec3 scatter_color = color.rgb * color_attribute.rgb;
-
- scatter_coeff = scatter_color * density;
- absorption_color.rgb = sqrt(max(absorption_color.rgb, 0.0));
- absorption_coeff = max(1.0 - scatter_color, 0.0) * max(1.0 - absorption_color.rgb, 0.0) *
- density;
- }
-
- /* Compute emission. */
- emission_strength = max(emission_strength, 0.0);
-
- if (emission_strength > 1e-5) {
- emission_coeff += emission_strength * emission_color.rgb;
- }
-
- if (blackbody_intensity > 1e-3) {
- /* Add temperature from attribute. */
- float T = max(temperature * max(temperature_attribute, 0.0), 0.0);
-
- /* Stefan-Boltzman law. */
- float T2 = T * T;
- float T4 = T2 * T2;
- float sigma = 5.670373e-8 * 1e-6 / M_PI;
- float intensity = sigma * mix(1.0, T4, blackbody_intensity);
-
- if (intensity > 1e-5) {
- vec4 bb;
- node_blackbody(T, spectrummap, layer, bb);
- emission_coeff += bb.rgb * blackbody_tint.rgb * intensity;
- }
- }
-
- result = Closure(absorption_coeff, scatter_coeff, emission_coeff, anisotropy);
-#else
- result = CLOSURE_DEFAULT;
-#endif
-}
-
-void node_holdout(out Closure result)
-{
- result = CLOSURE_DEFAULT;
-#ifndef VOLUMETRICS
- result.holdout = 1.0;
- result.flag = CLOSURE_HOLDOUT_FLAG;
-#endif
-}
-
-/* closures */
-
-void node_mix_shader(float fac, Closure shader1, Closure shader2, out Closure shader)
-{
- shader = closure_mix(shader1, shader2, fac);
-}
-
-void node_add_shader(Closure shader1, Closure shader2, out Closure shader)
-{
- shader = closure_add(shader1, shader2);
-}
-
-/* fresnel */
-
-void node_fresnel(float ior, vec3 N, vec3 I, out float result)
-{
- N = normalize(N);
- /* handle perspective/orthographic */
- vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
-
- float eta = max(ior, 0.00001);
- result = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? eta : 1.0 / eta);
-}
-
-/* layer_weight */
-
-void node_layer_weight(float blend, vec3 N, vec3 I, out float fresnel, out float facing)
-{
- N = normalize(N);
-
- /* fresnel */
- float eta = max(1.0 - blend, 0.00001);
- vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
-
- fresnel = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? 1.0 / eta : eta);
-
- /* facing */
- facing = abs(dot(I_view, N));
- if (blend != 0.5) {
- blend = clamp(blend, 0.0, 0.99999);
- blend = (blend < 0.5) ? 2.0 * blend : 0.5 / (1.0 - blend);
- facing = pow(facing, blend);
- }
- facing = 1.0 - facing;
-}
-
-/* gamma */
-
-void node_gamma(vec4 col, float gamma, out vec4 outcol)
-{
- outcol = col;
-
- if (col.r > 0.0) {
- outcol.r = compatible_pow(col.r, gamma);
- }
- if (col.g > 0.0) {
- outcol.g = compatible_pow(col.g, gamma);
- }
- if (col.b > 0.0) {
- outcol.b = compatible_pow(col.b, gamma);
- }
-}
-
-/* geometry */
-
-void node_attribute_volume_density(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
-{
-#if defined(MESH_SHADER) && defined(VOLUMETRICS)
- vec3 cos = volumeObjectLocalCoord;
-#else
- vec3 cos = vec3(0.0);
-#endif
- outvec = texture(tex, cos).aaa;
- outcol = vec4(outvec, 1.0);
- outf = avg(outvec);
-}
-
-uniform vec3 volumeColor = vec3(1.0);
-
-void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
-{
-#if defined(MESH_SHADER) && defined(VOLUMETRICS)
- vec3 cos = volumeObjectLocalCoord;
-#else
- vec3 cos = vec3(0.0);
-#endif
-
- vec4 value = texture(tex, cos).rgba;
- /* Density is premultiplied for interpolation, divide it out here. */
- if (value.a > 1e-8) {
- value.rgb /= value.a;
- }
-
- outvec = value.rgb * volumeColor;
- outcol = vec4(outvec, 1.0);
- outf = avg(outvec);
-}
-
-void node_attribute_volume_flame(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
-{
-#if defined(MESH_SHADER) && defined(VOLUMETRICS)
- vec3 cos = volumeObjectLocalCoord;
-#else
- vec3 cos = vec3(0.0);
-#endif
- outf = texture(tex, cos).r;
- outvec = vec3(outf, outf, outf);
- outcol = vec4(outf, outf, outf, 1.0);
-}
-
-void node_attribute_volume_temperature(
- sampler3D tex, vec2 temperature, out vec4 outcol, out vec3 outvec, out float outf)
-{
-#if defined(MESH_SHADER) && defined(VOLUMETRICS)
- vec3 cos = volumeObjectLocalCoord;
-#else
- vec3 cos = vec3(0.0);
-#endif
- float flame = texture(tex, cos).r;
-
- outf = (flame > 0.01) ? temperature.x + flame * (temperature.y - temperature.x) : 0.0;
- outvec = vec3(outf, outf, outf);
- outcol = vec4(outf, outf, outf, 1.0);
-}
-
-void node_volume_info(sampler3D densitySampler,
- sampler3D flameSampler,
- vec2 temperature,
- out vec4 outColor,
- out float outDensity,
- out float outFlame,
- out float outTemprature)
-{
-#if defined(MESH_SHADER) && defined(VOLUMETRICS)
- vec3 p = volumeObjectLocalCoord;
-#else
- vec3 p = vec3(0.0);
-#endif
-
- vec4 density = texture(densitySampler, p);
- outDensity = density.a;
-
- /* Density is premultiplied for interpolation, divide it out here. */
- if (density.a > 1e-8) {
- density.rgb /= density.a;
- }
- outColor = vec4(density.rgb * volumeColor, 1.0);
-
- float flame = texture(flameSampler, p).r;
- outFlame = flame;
-
- outTemprature = (flame > 0.01) ? temperature.x + flame * (temperature.y - temperature.x) : 0.0;
-}
-
-void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf)
-{
- outcol = vec4(attr, 1.0);
- outvec = attr;
- outf = avg(attr);
-}
-
-void node_uvmap(vec3 attr_uv, out vec3 outvec)
-{
- outvec = attr_uv;
-}
-
-void tangent_orco_x(vec3 orco_in, out vec3 orco_out)
-{
- orco_out = orco_in.xzy * vec3(0.0, -0.5, 0.5) + vec3(0.0, 0.25, -0.25);
-}
-
-void tangent_orco_y(vec3 orco_in, out vec3 orco_out)
-{
- orco_out = orco_in.zyx * vec3(-0.5, 0.0, 0.5) + vec3(0.25, 0.0, -0.25);
-}
-
-void tangent_orco_z(vec3 orco_in, out vec3 orco_out)
-{
- orco_out = orco_in.yxz * vec3(-0.5, 0.5, 0.0) + vec3(0.25, -0.25, 0.0);
-}
-
-void node_tangentmap(vec4 attr_tangent, out vec3 tangent)
-{
- tangent = normalize(attr_tangent.xyz);
-}
-
-void node_tangent(vec3 N, vec3 orco, mat4 objmat, out vec3 T)
-{
- T = (objmat * vec4(orco, 0.0)).xyz;
- T = cross(N, normalize(cross(T, N)));
-}
-
-void node_geometry(vec3 I,
- vec3 N,
- vec3 orco,
- mat4 objmat,
- mat4 toworld,
- vec2 barycentric,
- out vec3 position,
- out vec3 normal,
- out vec3 tangent,
- out vec3 true_normal,
- out vec3 incoming,
- out vec3 parametric,
- out float backfacing,
- out float pointiness)
-{
- /* handle perspective/orthographic */
- vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
- incoming = -(toworld * vec4(I_view, 0.0)).xyz;
-
-#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
- position = -incoming;
- true_normal = normal = incoming;
- tangent = parametric = vec3(0.0);
- vec3(0.0);
- backfacing = 0.0;
- pointiness = 0.0;
-#else
-
- position = worldPosition;
-# ifndef VOLUMETRICS
- normal = normalize(N);
- vec3 B = dFdx(worldPosition);
- vec3 T = dFdy(worldPosition);
- true_normal = normalize(cross(B, T));
-# else
- normal = (toworld * vec4(N, 0.0)).xyz;
- true_normal = normal;
-# endif
- tangent_orco_z(orco, orco);
- node_tangent(N, orco, objmat, tangent);
-
- parametric = vec3(barycentric, 0.0);
- backfacing = (gl_FrontFacing) ? 0.0 : 1.0;
- pointiness = 0.5;
-#endif
-}
-
-void generated_texco(vec3 I, vec3 attr_orco, out vec3 generated)
-{
- vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
- vec4 co_homogenous = (ProjectionMatrixInverse * v);
- vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0);
- co.xyz = normalize(co.xyz);
-#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
- generated = (ViewMatrixInverse * co).xyz;
-#else
- generated_from_orco(attr_orco, generated);
-#endif
-}
-
-void node_tex_coord(vec3 I,
- vec3 wN,
- mat4 obmatinv,
- vec4 camerafac,
- vec3 attr_orco,
- vec3 attr_uv,
- out vec3 generated,
- out vec3 normal,
- out vec3 uv,
- out vec3 object,
- out vec3 camera,
- out vec3 window,
- out vec3 reflection)
-{
- generated = attr_orco;
- normal = normalize(normal_world_to_object(wN));
- uv = attr_uv;
- object = (obmatinv * (ViewMatrixInverse * vec4(I, 1.0))).xyz;
- camera = vec3(I.xy, -I.z);
- vec4 projvec = ProjectionMatrix * vec4(I, 1.0);
- window = vec3(mtex_2d_mapping(projvec.xyz / projvec.w).xy * camerafac.xy + camerafac.zw, 0.0);
- reflection = -reflect(cameraVec, normalize(wN));
-}
-
-void node_tex_coord_background(vec3 I,
- vec3 N,
- mat4 obmatinv,
- vec4 camerafac,
- vec3 attr_orco,
- vec3 attr_uv,
- out vec3 generated,
- out vec3 normal,
- out vec3 uv,
- out vec3 object,
- out vec3 camera,
- out vec3 window,
- out vec3 reflection)
-{
- vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
- vec4 co_homogenous = (ProjectionMatrixInverse * v);
-
- vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0);
-
- co = normalize(co);
-
- vec3 coords = (ViewMatrixInverse * co).xyz;
-
- generated = coords;
- normal = -coords;
- uv = vec3(attr_uv.xy, 0.0);
- object = (obmatinv * vec4(coords, 1.0)).xyz;
-
- camera = vec3(co.xy, -co.z);
- window = vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0);
-
- reflection = -coords;
-}
-
-#if defined(WORLD_BACKGROUND) || (defined(PROBE_CAPTURE) && !defined(MESH_SHADER))
-# define node_tex_coord node_tex_coord_background
-#endif
-
-/* textures */
-
-float calc_gradient(vec3 p, int gradient_type)
-{
- float x, y, z;
- x = p.x;
- y = p.y;
- z = p.z;
- if (gradient_type == 0) { /* linear */
- return x;
- }
- else if (gradient_type == 1) { /* quadratic */
- float r = max(x, 0.0);
- return r * r;
- }
- else if (gradient_type == 2) { /* easing */
- float r = min(max(x, 0.0), 1.0);
- float t = r * r;
- return (3.0 * t - 2.0 * t * r);
- }
- else if (gradient_type == 3) { /* diagonal */
- return (x + y) * 0.5;
- }
- else if (gradient_type == 4) { /* radial */
- return atan(y, x) / (M_PI * 2) + 0.5;
- }
- else {
- /* Bias a little bit for the case where p is a unit length vector,
- * to get exactly zero instead of a small random value depending
- * on float precision. */
- float r = max(0.999999 - sqrt(x * x + y * y + z * z), 0.0);
- if (gradient_type == 5) { /* quadratic sphere */
- return r * r;
- }
- else if (gradient_type == 6) { /* sphere */
- return r;
- }
- }
- return 0.0;
-}
-
-void node_tex_gradient(vec3 co, float gradient_type, out vec4 color, out float fac)
-{
- float f = calc_gradient(co, int(gradient_type));
- f = clamp(f, 0.0, 1.0);
-
- color = vec4(f, f, f, 1.0);
- fac = f;
-}
-
-void node_tex_checker(
- vec3 co, vec4 color1, vec4 color2, float scale, out vec4 color, out float fac)
-{
- vec3 p = co * scale;
-
- /* Prevent precision issues on unit coordinates. */
- p = (p + 0.000001) * 0.999999;
-
- int xi = int(abs(floor(p.x)));
- int yi = int(abs(floor(p.y)));
- int zi = int(abs(floor(p.z)));
-
- bool check = ((mod(xi, 2) == mod(yi, 2)) == bool(mod(zi, 2)));
-
- color = check ? color1 : color2;
- fac = check ? 1.0 : 0.0;
-}
-
-vec2 calc_brick_texture(vec3 p,
- float mortar_size,
- float mortar_smooth,
- float bias,
- float brick_width,
- float row_height,
- float offset_amount,
- int offset_frequency,
- float squash_amount,
- int squash_frequency)
-{
- int bricknum, rownum;
- float offset = 0.0;
- float x, y;
-
- rownum = floor_to_int(p.y / row_height);
-
- if (offset_frequency != 0 && squash_frequency != 0) {
- brick_width *= (rownum % squash_frequency != 0) ? 1.0 : squash_amount; /* squash */
- offset = (rownum % offset_frequency != 0) ? 0.0 : (brick_width * offset_amount); /* offset */
- }
-
- bricknum = floor_to_int((p.x + offset) / brick_width);
-
- x = (p.x + offset) - brick_width * bricknum;
- y = p.y - row_height * rownum;
-
- float tint = clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0, 1.0);
-
- float min_dist = min(min(x, y), min(brick_width - x, row_height - y));
- if (min_dist >= mortar_size) {
- return vec2(tint, 0.0);
- }
- else if (mortar_smooth == 0.0) {
- return vec2(tint, 1.0);
- }
- else {
- min_dist = 1.0 - min_dist / mortar_size;
- return vec2(tint, smoothstep(0.0, mortar_smooth, min_dist));
- }
-}
-
-void node_tex_brick(vec3 co,
- vec4 color1,
- vec4 color2,
- vec4 mortar,
- float scale,
- float mortar_size,
- float mortar_smooth,
- float bias,
- float brick_width,
- float row_height,
- float offset_amount,
- float offset_frequency,
- float squash_amount,
- float squash_frequency,
- out vec4 color,
- out float fac)
-{
- vec2 f2 = calc_brick_texture(co * scale,
- mortar_size,
- mortar_smooth,
- bias,
- brick_width,
- row_height,
- offset_amount,
- int(offset_frequency),
- squash_amount,
- int(squash_frequency));
- float tint = f2.x;
- float f = f2.y;
- if (f != 1.0) {
- float facm = 1.0 - tint;
- color1 = facm * color1 + tint * color2;
- }
- color = mix(color1, mortar, f);
- fac = f;
-}
-
-void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac)
-{
- color = vec4(1.0);
- fac = 1.0;
-}
-
-void node_tex_environment_equirectangular(vec3 co, float clamp_size, sampler2D ima, out vec3 uv)
-{
- vec3 nco = normalize(co);
- uv.x = -atan(nco.y, nco.x) / (2.0 * M_PI) + 0.5;
- uv.y = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5;
-
- /* Fix pole bleeding */
- float half_height = clamp_size / float(textureSize(ima, 0).y);
- uv.y = clamp(uv.y, half_height, 1.0 - half_height);
- uv.z = 0.0;
-}
-
-void node_tex_environment_mirror_ball(vec3 co, out vec3 uv)
-{
- vec3 nco = normalize(co);
- nco.y -= 1.0;
-
- float div = 2.0 * sqrt(max(-0.5 * nco.y, 0.0));
- nco /= max(1e-8, div);
-
- uv = 0.5 * nco.xzz + 0.5;
-}
-
-void node_tex_environment_empty(vec3 co, out vec4 color)
-{
- color = vec4(1.0, 0.0, 1.0, 1.0);
-}
-
-/* 16bits floats limits. Higher/Lower values produce +/-inf. */
-#define safe_color(a) (clamp(a, -65520.0, 65520.0))
-
-void tex_color_alpha_clear(vec4 color, out vec4 result)
-{
- result = vec4(color.rgb, 1.0);
-}
-
-void tex_color_alpha_premultiply(vec4 color, out vec4 result)
-{
- result = vec4(color.rgb * color.a, 1.0);
-}
-
-void tex_color_alpha_unpremultiply(vec4 color, out vec4 result)
-{
- if (color.a == 0.0 || color.a == 1.0) {
- result = vec4(color.rgb, 1.0);
- }
- else {
- result = vec4(color.rgb / color.a, 1.0);
- }
-}
-
-void node_tex_image_linear(vec3 co, sampler2D ima, out vec4 color, out float alpha)
-{
- color = safe_color(texture(ima, co.xy));
- alpha = color.a;
-}
-
-void node_tex_image_linear_no_mip(vec3 co, sampler2D ima, out vec4 color, out float alpha)
-{
- color = safe_color(textureLod(ima, co.xy, 0.0));
- alpha = color.a;
-}
-
-void node_tex_image_nearest(vec3 co, sampler2D ima, out vec4 color, out float alpha)
-{
- ivec2 pix = ivec2(fract(co.xy) * textureSize(ima, 0).xy);
- color = safe_color(texelFetch(ima, pix, 0));
- alpha = color.a;
-}
-
-/* @arg f: signed distance to texel center. */
-void cubic_bspline_coefs(vec2 f, out vec2 w0, out vec2 w1, out vec2 w2, out vec2 w3)
-{
- vec2 f2 = f * f;
- vec2 f3 = f2 * f;
- /* Bspline coefs (optimized) */
- w3 = f3 / 6.0;
- w0 = -w3 + f2 * 0.5 - f * 0.5 + 1.0 / 6.0;
- w1 = f3 * 0.5 - f2 * 1.0 + 2.0 / 3.0;
- w2 = 1.0 - w0 - w1 - w3;
-}
-
-void node_tex_image_cubic_ex(
- vec3 co, sampler2D ima, float do_extend, out vec4 color, out float alpha)
-{
- vec2 tex_size = vec2(textureSize(ima, 0).xy);
-
- co.xy *= tex_size;
- /* texel center */
- vec2 tc = floor(co.xy - 0.5) + 0.5;
- vec2 w0, w1, w2, w3;
- cubic_bspline_coefs(co.xy - tc, w0, w1, w2, w3);
-
-#if 1 /* Optimized version using 4 filtered tap. */
- vec2 s0 = w0 + w1;
- vec2 s1 = w2 + w3;
-
- vec2 f0 = w1 / (w0 + w1);
- vec2 f1 = w3 / (w2 + w3);
-
- vec4 final_co;
- final_co.xy = tc - 1.0 + f0;
- final_co.zw = tc + 1.0 + f1;
-
- if (do_extend == 1.0) {
- final_co = clamp(final_co, vec4(0.5), tex_size.xyxy - 0.5);
- }
- final_co /= tex_size.xyxy;
-
- color = safe_color(textureLod(ima, final_co.xy, 0.0)) * s0.x * s0.y;
- color += safe_color(textureLod(ima, final_co.zy, 0.0)) * s1.x * s0.y;
- color += safe_color(textureLod(ima, final_co.xw, 0.0)) * s0.x * s1.y;
- color += safe_color(textureLod(ima, final_co.zw, 0.0)) * s1.x * s1.y;
-
-#else /* Reference bruteforce 16 tap. */
- color = texelFetch(ima, ivec2(tc + vec2(-1.0, -1.0)), 0) * w0.x * w0.y;
- color += texelFetch(ima, ivec2(tc + vec2(0.0, -1.0)), 0) * w1.x * w0.y;
- color += texelFetch(ima, ivec2(tc + vec2(1.0, -1.0)), 0) * w2.x * w0.y;
- color += texelFetch(ima, ivec2(tc + vec2(2.0, -1.0)), 0) * w3.x * w0.y;
-
- color += texelFetch(ima, ivec2(tc + vec2(-1.0, 0.0)), 0) * w0.x * w1.y;
- color += texelFetch(ima, ivec2(tc + vec2(0.0, 0.0)), 0) * w1.x * w1.y;
- color += texelFetch(ima, ivec2(tc + vec2(1.0, 0.0)), 0) * w2.x * w1.y;
- color += texelFetch(ima, ivec2(tc + vec2(2.0, 0.0)), 0) * w3.x * w1.y;
-
- color += texelFetch(ima, ivec2(tc + vec2(-1.0, 1.0)), 0) * w0.x * w2.y;
- color += texelFetch(ima, ivec2(tc + vec2(0.0, 1.0)), 0) * w1.x * w2.y;
- color += texelFetch(ima, ivec2(tc + vec2(1.0, 1.0)), 0) * w2.x * w2.y;
- color += texelFetch(ima, ivec2(tc + vec2(2.0, 1.0)), 0) * w3.x * w2.y;
-
- color += texelFetch(ima, ivec2(tc + vec2(-1.0, 2.0)), 0) * w0.x * w3.y;
- color += texelFetch(ima, ivec2(tc + vec2(0.0, 2.0)), 0) * w1.x * w3.y;
- color += texelFetch(ima, ivec2(tc + vec2(1.0, 2.0)), 0) * w2.x * w3.y;
- color += texelFetch(ima, ivec2(tc + vec2(2.0, 2.0)), 0) * w3.x * w3.y;
-#endif
-
- alpha = color.a;
-}
-
-void node_tex_image_cubic(vec3 co, sampler2D ima, out vec4 color, out float alpha)
-{
- node_tex_image_cubic_ex(co, ima, 0.0, color, alpha);
-}
-
-void node_tex_image_cubic_extend(vec3 co, sampler2D ima, out vec4 color, out float alpha)
-{
- node_tex_image_cubic_ex(co, ima, 1.0, color, alpha);
-}
-
-void node_tex_image_smart(vec3 co, sampler2D ima, out vec4 color, out float alpha)
-{
- /* use cubic for now */
- node_tex_image_cubic_ex(co, ima, 0.0, color, alpha);
-}
-
-void tex_box_sample_linear(
- vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3)
-{
- /* X projection */
- vec2 uv = texco.yz;
- if (N.x < 0.0) {
- uv.x = 1.0 - uv.x;
- }
- color1 = texture(ima, uv);
- /* Y projection */
- uv = texco.xz;
- if (N.y > 0.0) {
- uv.x = 1.0 - uv.x;
- }
- color2 = texture(ima, uv);
- /* Z projection */
- uv = texco.yx;
- if (N.z > 0.0) {
- uv.x = 1.0 - uv.x;
- }
- color3 = texture(ima, uv);
-}
-
-void tex_box_sample_nearest(
- vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3)
-{
- /* X projection */
- vec2 uv = texco.yz;
- if (N.x < 0.0) {
- uv.x = 1.0 - uv.x;
- }
- ivec2 pix = ivec2(uv.xy * textureSize(ima, 0).xy);
- color1 = texelFetch(ima, pix, 0);
- /* Y projection */
- uv = texco.xz;
- if (N.y > 0.0) {
- uv.x = 1.0 - uv.x;
- }
- pix = ivec2(uv.xy * textureSize(ima, 0).xy);
- color2 = texelFetch(ima, pix, 0);
- /* Z projection */
- uv = texco.yx;
- if (N.z > 0.0) {
- uv.x = 1.0 - uv.x;
- }
- pix = ivec2(uv.xy * textureSize(ima, 0).xy);
- color3 = texelFetch(ima, pix, 0);
-}
-
-void tex_box_sample_cubic(
- vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3)
-{
- float alpha;
- /* X projection */
- vec2 uv = texco.yz;
- if (N.x < 0.0) {
- uv.x = 1.0 - uv.x;
- }
- node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color1, alpha);
- /* Y projection */
- uv = texco.xz;
- if (N.y > 0.0) {
- uv.x = 1.0 - uv.x;
- }
- node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color2, alpha);
- /* Z projection */
- uv = texco.yx;
- if (N.z > 0.0) {
- uv.x = 1.0 - uv.x;
- }
- node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color3, alpha);
-}
-
-void tex_box_sample_smart(
- vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3)
-{
- tex_box_sample_cubic(texco, N, ima, color1, color2, color3);
-}
-
-void node_tex_image_box(vec3 texco,
- vec3 N,
- vec4 color1,
- vec4 color2,
- vec4 color3,
- sampler2D ima,
- float blend,
- out vec4 color,
- out float alpha)
-{
- /* project from direction vector to barycentric coordinates in triangles */
- N = abs(N);
- N /= dot(N, vec3(1.0));
-
- /* basic idea is to think of this as a triangle, each corner representing
- * one of the 3 faces of the cube. in the corners we have single textures,
- * in between we blend between two textures, and in the middle we a blend
- * between three textures.
- *
- * the Nxyz values are the barycentric coordinates in an equilateral
- * triangle, which in case of blending, in the middle has a smaller
- * equilateral triangle where 3 textures blend. this divides things into
- * 7 zones, with an if () test for each zone
- * EDIT: Now there is only 4 if's. */
-
- float limit = 0.5 + 0.5 * blend;
-
- vec3 weight;
- weight = N.xyz / (N.xyx + N.yzz);
- weight = clamp((weight - 0.5 * (1.0 - blend)) / max(1e-8, blend), 0.0, 1.0);
-
- /* test for mixes between two textures */
- if (N.z < (1.0 - limit) * (N.y + N.x)) {
- weight.z = 0.0;
- weight.y = 1.0 - weight.x;
- }
- else if (N.x < (1.0 - limit) * (N.y + N.z)) {
- weight.x = 0.0;
- weight.z = 1.0 - weight.y;
- }
- else if (N.y < (1.0 - limit) * (N.x + N.z)) {
- weight.y = 0.0;
- weight.x = 1.0 - weight.z;
- }
- else {
- /* last case, we have a mix between three */
- weight = ((2.0 - limit) * N + (limit - 1.0)) / max(1e-8, blend);
- }
-
- color = weight.x * color1 + weight.y * color2 + weight.z * color3;
- alpha = color.a;
-}
-
-void tex_clip_linear(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
-{
- vec2 tex_size = vec2(textureSize(ima, 0).xy);
- vec2 minco = min(co.xy, 1.0 - co.xy);
- minco = clamp(minco * tex_size + 0.5, 0.0, 1.0);
- float fac = minco.x * minco.y;
-
- color = mix(vec4(0.0), icolor, fac);
- alpha = color.a;
-}
-
-void tex_clip_nearest(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
-{
- vec4 minco = vec4(co.xy, 1.0 - co.xy);
- color = (any(lessThan(minco, vec4(0.0)))) ? vec4(0.0) : icolor;
- alpha = color.a;
-}
-
-void tex_clip_cubic(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
-{
- vec2 tex_size = vec2(textureSize(ima, 0).xy);
-
- co.xy *= tex_size;
- /* texel center */
- vec2 tc = floor(co.xy - 0.5) + 0.5;
- vec2 w0, w1, w2, w3;
- cubic_bspline_coefs(co.xy - tc, w0, w1, w2, w3);
-
- /* TODO Optimize this part. I'm sure there is a smarter way to do that.
- * Could do that when sampling? */
-#define CLIP_CUBIC_SAMPLE(samp, size) \
- (float(all(greaterThan(samp, vec2(-0.5)))) * float(all(lessThan(ivec2(samp), itex_size))))
- ivec2 itex_size = textureSize(ima, 0).xy;
- float fac;
- fac = CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, -1.0), itex_size) * w0.x * w0.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, -1.0), itex_size) * w1.x * w0.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, -1.0), itex_size) * w2.x * w0.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, -1.0), itex_size) * w3.x * w0.y;
-
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 0.0), itex_size) * w0.x * w1.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 0.0), itex_size) * w1.x * w1.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 0.0), itex_size) * w2.x * w1.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 0.0), itex_size) * w3.x * w1.y;
-
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 1.0), itex_size) * w0.x * w2.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 1.0), itex_size) * w1.x * w2.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 1.0), itex_size) * w2.x * w2.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 1.0), itex_size) * w3.x * w2.y;
-
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 2.0), itex_size) * w0.x * w3.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 2.0), itex_size) * w1.x * w3.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 2.0), itex_size) * w2.x * w3.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 2.0), itex_size) * w3.x * w3.y;
-#undef CLIP_CUBIC_SAMPLE
-
- color = mix(vec4(0.0), icolor, fac);
- alpha = color.a;
-}
-
-void tex_clip_smart(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
-{
- tex_clip_cubic(co, ima, icolor, color, alpha);
-}
-
-void node_tex_image_empty(vec3 co, out vec4 color, out float alpha)
-{
- color = vec4(0.0);
- alpha = 0.0;
-}
-
-void node_tex_magic(
- vec3 co, float scale, float distortion, float depth, out vec4 color, out float fac)
-{
- vec3 p = co * scale;
- float x = sin((p.x + p.y + p.z) * 5.0);
- float y = cos((-p.x + p.y - p.z) * 5.0);
- float z = -cos((-p.x - p.y + p.z) * 5.0);
-
- if (depth > 0) {
- x *= distortion;
- y *= distortion;
- z *= distortion;
- y = -cos(x - y + z);
- y *= distortion;
- if (depth > 1) {
- x = cos(x - y - z);
- x *= distortion;
- if (depth > 2) {
- z = sin(-x - y - z);
- z *= distortion;
- if (depth > 3) {
- x = -cos(-x + y - z);
- x *= distortion;
- if (depth > 4) {
- y = -sin(-x + y + z);
- y *= distortion;
- if (depth > 5) {
- y = -cos(-x + y + z);
- y *= distortion;
- if (depth > 6) {
- x = cos(x + y + z);
- x *= distortion;
- if (depth > 7) {
- z = sin(x + y - z);
- z *= distortion;
- if (depth > 8) {
- x = -cos(-x - y + z);
- x *= distortion;
- if (depth > 9) {
- y = -sin(x - y + z);
- y *= distortion;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (distortion != 0.0) {
- distortion *= 2.0;
- x /= distortion;
- y /= distortion;
- z /= distortion;
- }
-
- color = vec4(0.5 - x, 0.5 - y, 0.5 - z, 1.0);
- fac = (color.x + color.y + color.z) / 3.0;
-}
-
-float noise_fade(float t)
-{
- return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
-}
-
-float noise_scale3(float result)
-{
- return 0.9820 * result;
-}
-
-float noise_nerp(float t, float a, float b)
-{
- return (1.0 - t) * a + t * b;
-}
-
-float noise_grad(uint hash, float x, float y, float z)
-{
- uint h = hash & 15u;
- float u = h < 8u ? x : y;
- float vt = ((h == 12u) || (h == 14u)) ? x : z;
- float v = h < 4u ? y : vt;
- return (((h & 1u) != 0u) ? -u : u) + (((h & 2u) != 0u) ? -v : v);
-}
-
-float noise_perlin(float x, float y, float z)
-{
- int X;
- float fx = floorfrac(x, X);
- int Y;
- float fy = floorfrac(y, Y);
- int Z;
- float fz = floorfrac(z, Z);
-
- float u = noise_fade(fx);
- float v = noise_fade(fy);
- float w = noise_fade(fz);
-
- float noise_u[2], noise_v[2];
-
- noise_u[0] = noise_nerp(u,
- noise_grad(hash_int3(X, Y, Z), fx, fy, fz),
- noise_grad(hash_int3(X + 1, Y, Z), fx - 1.0, fy, fz));
-
- noise_u[1] = noise_nerp(u,
- noise_grad(hash_int3(X, Y + 1, Z), fx, fy - 1.0, fz),
- noise_grad(hash_int3(X + 1, Y + 1, Z), fx - 1.0, fy - 1.0, fz));
-
- noise_v[0] = noise_nerp(v, noise_u[0], noise_u[1]);
-
- noise_u[0] = noise_nerp(u,
- noise_grad(hash_int3(X, Y, Z + 1), fx, fy, fz - 1.0),
- noise_grad(hash_int3(X + 1, Y, Z + 1), fx - 1.0, fy, fz - 1.0));
-
- noise_u[1] = noise_nerp(
- u,
- noise_grad(hash_int3(X, Y + 1, Z + 1), fx, fy - 1.0, fz - 1.0),
- noise_grad(hash_int3(X + 1, Y + 1, Z + 1), fx - 1.0, fy - 1.0, fz - 1.0));
-
- noise_v[1] = noise_nerp(v, noise_u[0], noise_u[1]);
-
- float r = noise_scale3(noise_nerp(w, noise_v[0], noise_v[1]));
-
- return (isinf(r)) ? 0.0 : r;
-}
-
-float noise(vec3 p)
-{
- return 0.5 * noise_perlin(p.x, p.y, p.z) + 0.5;
-}
-
-float snoise(vec3 p)
-{
- return noise_perlin(p.x, p.y, p.z);
-}
-
-float noise_turbulence(vec3 p, float octaves, int hard)
-{
- float fscale = 1.0;
- float amp = 1.0;
- float sum = 0.0;
- octaves = clamp(octaves, 0.0, 16.0);
- int n = int(octaves);
- for (int i = 0; i <= n; i++) {
- float t = noise(fscale * p);
- if (hard != 0) {
- t = abs(2.0 * t - 1.0);
- }
- sum += t * amp;
- amp *= 0.5;
- fscale *= 2.0;
- }
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- float t = noise(fscale * p);
- if (hard != 0) {
- t = abs(2.0 * t - 1.0);
- }
- float sum2 = sum + t * amp;
- sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
- sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1));
- return (1.0 - rmd) * sum + rmd * sum2;
- }
- else {
- sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
- return sum;
- }
-}
-
-void node_tex_noise(
- vec3 co, float scale, float detail, float distortion, out vec4 color, out float fac)
-{
- vec3 p = co * scale;
- int hard = 0;
- if (distortion != 0.0) {
- vec3 r, offset = vec3(13.5, 13.5, 13.5);
- r.x = noise(p + offset) * distortion;
- r.y = noise(p) * distortion;
- r.z = noise(p - offset) * distortion;
- p += r;
- }
-
- fac = noise_turbulence(p, detail, hard);
- color = vec4(fac,
- noise_turbulence(vec3(p.y, p.x, p.z), detail, hard),
- noise_turbulence(vec3(p.y, p.z, p.x), detail, hard),
- 1);
-}
-
-/* Musgrave fBm
- *
- * H: fractal increment parameter
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- *
- * from "Texturing and Modelling: A procedural approach"
- */
-
-float noise_musgrave_fBm(vec3 p, float H, float lacunarity, float octaves)
-{
- float rmd;
- float value = 0.0;
- float pwr = 1.0;
- float pwHL = pow(lacunarity, -H);
-
- for (int i = 0; i < int(octaves); i++) {
- value += snoise(p) * pwr;
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- value += rmd * snoise(p) * pwr;
- }
-
- return value;
-}
-
-/* Musgrave Multifractal
- *
- * H: highest fractal dimension
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- */
-
-float noise_musgrave_multi_fractal(vec3 p, float H, float lacunarity, float octaves)
-{
- float rmd;
- float value = 1.0;
- float pwr = 1.0;
- float pwHL = pow(lacunarity, -H);
-
- for (int i = 0; i < int(octaves); i++) {
- value *= (pwr * snoise(p) + 1.0);
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- value *= (rmd * pwr * snoise(p) + 1.0); /* correct? */
- }
-
- return value;
-}
-
-/* Musgrave Heterogeneous Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
-float noise_musgrave_hetero_terrain(vec3 p, float H, float lacunarity, float octaves, float offset)
-{
- float value, increment, rmd;
- float pwHL = pow(lacunarity, -H);
- float pwr = pwHL;
-
- /* first unscaled octave of function; later octaves are scaled */
- value = offset + snoise(p);
- p *= lacunarity;
-
- for (int i = 1; i < int(octaves); i++) {
- increment = (snoise(p) + offset) * pwr * value;
- value += increment;
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- increment = (snoise(p) + offset) * pwr * value;
- value += rmd * increment;
- }
-
- return value;
-}
-
-/* Hybrid Additive/Multiplicative Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
-float noise_musgrave_hybrid_multi_fractal(
- vec3 p, float H, float lacunarity, float octaves, float offset, float gain)
-{
- float result, signal, weight, rmd;
- float pwHL = pow(lacunarity, -H);
- float pwr = pwHL;
-
- result = snoise(p) + offset;
- weight = gain * result;
- p *= lacunarity;
-
- for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
- if (weight > 1.0) {
- weight = 1.0;
- }
-
- signal = (snoise(p) + offset) * pwr;
- pwr *= pwHL;
- result += weight * signal;
- weight *= gain * signal;
- p *= lacunarity;
- }
-
- rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- result += rmd * ((snoise(p) + offset) * pwr);
- }
-
- return result;
-}
-
-/* Ridged Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
-float noise_musgrave_ridged_multi_fractal(
- vec3 p, float H, float lacunarity, float octaves, float offset, float gain)
-{
- float result, signal, weight;
- float pwHL = pow(lacunarity, -H);
- float pwr = pwHL;
-
- signal = offset - abs(snoise(p));
- signal *= signal;
- result = signal;
- weight = 1.0;
-
- for (int i = 1; i < int(octaves); i++) {
- p *= lacunarity;
- weight = clamp(signal * gain, 0.0, 1.0);
- signal = offset - abs(snoise(p));
- signal *= signal;
- signal *= weight;
- result += signal * pwr;
- pwr *= pwHL;
- }
-
- return result;
-}
-
-float svm_musgrave(int type,
- float dimension,
- float lacunarity,
- float octaves,
- float offset,
- float intensity,
- float gain,
- vec3 p)
-{
- if (type == 0 /* NODE_MUSGRAVE_MULTIFRACTAL */) {
- return intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves);
- }
- else if (type == 1 /* NODE_MUSGRAVE_FBM */) {
- return intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves);
- }
- else if (type == 2 /* NODE_MUSGRAVE_HYBRID_MULTIFRACTAL */) {
- return intensity *
- noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
- }
- else if (type == 3 /* NODE_MUSGRAVE_RIDGED_MULTIFRACTAL */) {
- return intensity *
- noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
- }
- else if (type == 4 /* NODE_MUSGRAVE_HETERO_TERRAIN */) {
- return intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, offset);
- }
- return 0.0;
-}
-
-void node_tex_musgrave(vec3 co,
- float scale,
- float detail,
- float dimension,
- float lacunarity,
- float offset,
- float gain,
- float type,
- out vec4 color,
- out float fac)
-{
- fac = svm_musgrave(int(type), dimension, lacunarity, detail, offset, 1.0, gain, co *scale);
-
- color = vec4(fac, fac, fac, 1.0);
-}
-
-void node_tex_sky(vec3 co, out vec4 color)
-{
- color = vec4(1.0);
-}
-
-void node_tex_voronoi(vec3 co,
- float scale,
- float exponent,
- float coloring,
- float metric,
- float feature,
- out vec4 color,
- out float fac)
-{
- vec3 p = co * scale;
- int xx, yy, zz, xi, yi, zi;
- vec4 da = vec4(1e10);
- vec3 pa[4] = vec3[4](vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0));
-
- xi = floor_to_int(p[0]);
- yi = floor_to_int(p[1]);
- zi = floor_to_int(p[2]);
-
- for (xx = xi - 1; xx <= xi + 1; xx++) {
- for (yy = yi - 1; yy <= yi + 1; yy++) {
- for (zz = zi - 1; zz <= zi + 1; zz++) {
- vec3 ip = vec3(xx, yy, zz);
- vec3 vp = cellnoise_color(ip);
- vec3 pd = p - (vp + ip);
-
- float d = 0.0;
- if (metric == 0.0) { /* SHD_VORONOI_DISTANCE 0 */
- d = dot(pd, pd);
- }
- else if (metric == 1.0) { /* SHD_VORONOI_MANHATTAN 1 */
- d = abs(pd[0]) + abs(pd[1]) + abs(pd[2]);
- }
- else if (metric == 2.0) { /* SHD_VORONOI_CHEBYCHEV 2 */
- d = max(abs(pd[0]), max(abs(pd[1]), abs(pd[2])));
- }
- else if (metric == 3.0) { /* SHD_VORONOI_MINKOWSKI 3 */
- d = pow(pow(abs(pd[0]), exponent) + pow(abs(pd[1]), exponent) +
- pow(abs(pd[2]), exponent),
- 1.0 / exponent);
- }
-
- vp += vec3(xx, yy, zz);
- if (d < da[0]) {
- da.yzw = da.xyz;
- da[0] = d;
-
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = pa[0];
- pa[0] = vp;
- }
- else if (d < da[1]) {
- da.zw = da.yz;
- da[1] = d;
-
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = vp;
- }
- else if (d < da[2]) {
- da[3] = da[2];
- da[2] = d;
-
- pa[3] = pa[2];
- pa[2] = vp;
- }
- else if (d < da[3]) {
- da[3] = d;
- pa[3] = vp;
- }
- }
- }
- }
-
- if (coloring == 0.0) {
- /* Intensity output */
- if (feature == 0.0) { /* F1 */
- fac = abs(da[0]);
- }
- else if (feature == 1.0) { /* F2 */
- fac = abs(da[1]);
- }
- else if (feature == 2.0) { /* F3 */
- fac = abs(da[2]);
- }
- else if (feature == 3.0) { /* F4 */
- fac = abs(da[3]);
- }
- else if (feature == 4.0) { /* F2F1 */
- fac = abs(da[1] - da[0]);
- }
- color = vec4(fac, fac, fac, 1.0);
- }
- else {
- /* Color output */
- vec3 col = vec3(fac, fac, fac);
- if (feature == 0.0) { /* F1 */
- col = pa[0];
- }
- else if (feature == 1.0) { /* F2 */
- col = pa[1];
- }
- else if (feature == 2.0) { /* F3 */
- col = pa[2];
- }
- else if (feature == 3.0) { /* F4 */
- col = pa[3];
- }
- else if (feature == 4.0) { /* F2F1 */
- col = abs(pa[1] - pa[0]);
- }
-
- color = vec4(cellnoise_color(col), 1.0);
- fac = (color.x + color.y + color.z) * (1.0 / 3.0);
- }
-}
-
-float calc_wave(
- vec3 p, float distortion, float detail, float detail_scale, int wave_type, int wave_profile)
-{
- float n;
-
- if (wave_type == 0) { /* type bands */
- n = (p.x + p.y + p.z) * 10.0;
- }
- else { /* type rings */
- n = length(p) * 20.0;
- }
-
- if (distortion != 0.0) {
- n += distortion * noise_turbulence(p * detail_scale, detail, 0);
- }
-
- if (wave_profile == 0) { /* profile sin */
- return 0.5 + 0.5 * sin(n);
- }
- else { /* profile saw */
- n /= 2.0 * M_PI;
- n -= int(n);
- return (n < 0.0) ? n + 1.0 : n;
- }
-}
-
-void node_tex_wave(vec3 co,
- float scale,
- float distortion,
- float detail,
- float detail_scale,
- float wave_type,
- float wave_profile,
- out vec4 color,
- out float fac)
-{
- float f;
- f = calc_wave(co * scale, distortion, detail, detail_scale, int(wave_type), int(wave_profile));
-
- color = vec4(f, f, f, 1.0);
- fac = f;
-}
-
-/* light path */
-
-void node_light_path(out float is_camera_ray,
- out float is_shadow_ray,
- out float is_diffuse_ray,
- out float is_glossy_ray,
- out float is_singular_ray,
- out float is_reflection_ray,
- out float is_transmission_ray,
- out float ray_length,
- out float ray_depth,
- out float diffuse_depth,
- out float glossy_depth,
- out float transparent_depth,
- out float transmission_depth)
-{
- /* Supported. */
- is_camera_ray = (rayType == EEVEE_RAY_CAMERA) ? 1.0 : 0.0;
- is_shadow_ray = (rayType == EEVEE_RAY_SHADOW) ? 1.0 : 0.0;
- is_diffuse_ray = (rayType == EEVEE_RAY_DIFFUSE) ? 1.0 : 0.0;
- is_glossy_ray = (rayType == EEVEE_RAY_GLOSSY) ? 1.0 : 0.0;
- /* Kind of supported. */
- is_singular_ray = is_glossy_ray;
- is_reflection_ray = is_glossy_ray;
- is_transmission_ray = is_glossy_ray;
- ray_depth = rayDepth;
- diffuse_depth = (is_diffuse_ray == 1.0) ? rayDepth : 0.0;
- glossy_depth = (is_glossy_ray == 1.0) ? rayDepth : 0.0;
- transmission_depth = (is_transmission_ray == 1.0) ? glossy_depth : 0.0;
- /* Not supported. */
- ray_length = 1.0;
- transparent_depth = 0.0;
-}
-
-void node_light_falloff(
- float strength, float tsmooth, out float quadratic, out float linear, out float constant)
-{
- quadratic = strength;
- linear = strength;
- constant = strength;
-}
-
-void node_object_info(mat4 obmat,
- vec4 obcolor,
- vec4 info,
- float mat_index,
- out vec3 location,
- out vec4 color,
- out float object_index,
- out float material_index,
- out float random)
-{
- location = obmat[3].xyz;
- color = obcolor;
- object_index = info.x;
- material_index = mat_index;
- random = info.z;
-}
-
-void node_normal_map(vec4 info, vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnormal)
-{
- if (all(equal(tangent, vec4(0.0, 0.0, 0.0, 1.0)))) {
- outnormal = normal;
- return;
- }
- tangent *= (gl_FrontFacing ? 1.0 : -1.0);
- vec3 B = tangent.w * cross(normal, tangent.xyz) * info.w;
-
- outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * normal;
- outnormal = normalize(outnormal);
-}
-
-void node_bump(
- float strength, float dist, float height, vec3 N, vec3 surf_pos, float invert, out vec3 result)
-{
- N = mat3(ViewMatrix) * normalize(N);
- dist *= gl_FrontFacing ? invert : -invert;
-
- vec3 dPdx = dFdx(surf_pos);
- vec3 dPdy = dFdy(surf_pos);
-
- /* Get surface tangents from normal. */
- vec3 Rx = cross(dPdy, N);
- vec3 Ry = cross(N, dPdx);
-
- /* Compute surface gradient and determinant. */
- float det = dot(dPdx, Rx);
-
- float dHdx = dFdx(height);
- float dHdy = dFdy(height);
- vec3 surfgrad = dHdx * Rx + dHdy * Ry;
-
- strength = max(strength, 0.0);
-
- result = normalize(abs(det) * N - dist * sign(det) * surfgrad);
- result = normalize(mix(N, result, strength));
-
- result = mat3(ViewMatrixInverse) * result;
-}
-
-void node_bevel(float radius, vec3 N, out vec3 result)
-{
- result = N;
-}
-
-void node_hair_info(out float is_strand,
- out float intercept,
- out float thickness,
- out vec3 tangent,
- out float random)
-{
-#ifdef HAIR_SHADER
- is_strand = 1.0;
- intercept = hairTime;
- thickness = hairThickness;
- tangent = normalize(worldNormal);
- random = wang_hash_noise(
- uint(hairStrandID)); /* TODO: could be precomputed per strand instead. */
-#else
- is_strand = 0.0;
- intercept = 0.0;
- thickness = 0.0;
- tangent = vec3(1.0);
- random = 0.0;
-#endif
-}
-
-void node_displacement_object(
- float height, float midlevel, float scale, vec3 N, mat4 obmat, out vec3 result)
-{
- N = (vec4(N, 0.0) * obmat).xyz;
- result = (height - midlevel) * scale * normalize(N);
- result = (obmat * vec4(result, 0.0)).xyz;
-}
-
-void node_displacement_world(float height, float midlevel, float scale, vec3 N, out vec3 result)
-{
- result = (height - midlevel) * scale * normalize(N);
-}
-
-void node_vector_displacement_tangent(vec4 vector,
- float midlevel,
- float scale,
- vec4 tangent,
- vec3 normal,
- mat4 obmat,
- mat4 viewmat,
- out vec3 result)
-{
- /* TODO(fclem) this is broken. revisit latter. */
- vec3 N_object = normalize(((vec4(normal, 0.0) * viewmat) * obmat).xyz);
- vec3 T_object = normalize(((vec4(tangent.xyz, 0.0) * viewmat) * obmat).xyz);
- vec3 B_object = tangent.w * normalize(cross(N_object, T_object));
-
- vec3 offset = (vector.xyz - vec3(midlevel)) * scale;
- result = offset.x * T_object + offset.y * N_object + offset.z * B_object;
- result = (obmat * vec4(result, 0.0)).xyz;
-}
-
-void node_vector_displacement_object(
- vec4 vector, float midlevel, float scale, mat4 obmat, out vec3 result)
-{
- result = (vector.xyz - vec3(midlevel)) * scale;
- result = (obmat * vec4(result, 0.0)).xyz;
-}
-
-void node_vector_displacement_world(vec4 vector, float midlevel, float scale, out vec3 result)
-{
- result = (vector.xyz - vec3(midlevel)) * scale;
-}
-
-/* output */
-
-void node_output_material(Closure surface, Closure volume, vec3 displacement, out Closure result)
-{
-#ifdef VOLUMETRICS
- result = volume;
-#else
- result = surface;
-#endif
-}
-
-uniform float backgroundAlpha;
-
-void node_output_world(Closure surface, Closure volume, out Closure result)
-{
-#ifndef VOLUMETRICS
- result.radiance = surface.radiance * backgroundAlpha;
- result.transmittance = vec3(1.0 - backgroundAlpha);
-#else
- result = volume;
-#endif /* VOLUMETRICS */
-}
-
-/* TODO : clean this ifdef mess */
-/* EEVEE output */
-void world_normals_get(out vec3 N)
-{
-#ifndef VOLUMETRICS
-# ifdef HAIR_SHADER
- vec3 B = normalize(cross(worldNormal, hairTangent));
- float cos_theta;
- if (hairThicknessRes == 1) {
- vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0);
- /* Random cosine normal distribution on the hair surface. */
- cos_theta = rand.x * 2.0 - 1.0;
- }
- else {
- /* Shade as a cylinder. */
- cos_theta = hairThickTime / hairThickness;
- }
- float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
- N = normalize(worldNormal * sin_theta + B * cos_theta);
-# else
- N = gl_FrontFacing ? worldNormal : -worldNormal;
-# endif
-#else
- generated_from_orco(vec3(0.0), N);
-#endif
-}
-
-#ifndef VOLUMETRICS
-void node_eevee_specular(vec4 diffuse,
- vec4 specular,
- float roughness,
- vec4 emissive,
- float transp,
- vec3 normal,
- float clearcoat,
- float clearcoat_roughness,
- vec3 clearcoat_normal,
- float occlusion,
- float ssr_id,
- out Closure result)
-{
- normal = normalize(normal);
-
- vec3 out_diff, out_spec, ssr_spec;
- eevee_closure_default_clearcoat(normal,
- diffuse.rgb,
- specular.rgb,
- vec3(1.0),
- int(ssr_id),
- roughness,
- clearcoat_normal,
- clearcoat * 0.25,
- clearcoat_roughness,
- occlusion,
- out_diff,
- out_spec,
- ssr_spec);
-
- float alpha = 1.0 - transp;
- result = CLOSURE_DEFAULT;
- result.radiance = out_diff * diffuse.rgb + out_spec + emissive.rgb;
- result.radiance *= alpha;
- result.transmittance = vec3(transp);
-
- closure_load_ssr_data(ssr_spec * alpha, roughness, normal, viewCameraVec, int(ssr_id), result);
-}
-
-void node_shader_to_rgba(Closure cl, out vec4 outcol, out float outalpha)
-{
- vec4 spec_accum = vec4(0.0);
- if (ssrToggle && FLAG_TEST(cl.flag, CLOSURE_SSR_FLAG)) {
- vec3 V = cameraVec;
- vec3 vN = normal_decode(cl.ssr_normal, viewCameraVec);
- vec3 N = transform_direction(ViewMatrixInverse, vN);
- float roughness = cl.ssr_data.a;
- float roughnessSquared = max(1e-3, roughness * roughness);
- fallback_cubemap(N, V, worldPosition, viewPosition, roughness, roughnessSquared, spec_accum);
- }
-
- outalpha = avg(cl.transmittance);
- outcol = vec4((spec_accum.rgb * cl.ssr_data.rgb) + cl.radiance, 1.0);
-
-# ifdef USE_SSS
-# ifdef USE_SSS_ALBEDO
- outcol.rgb += cl.sss_data.rgb * cl.sss_albedo;
-# else
- outcol.rgb += cl.sss_data.rgb;
-# endif
-# endif
-}
-
-#endif /* VOLUMETRICS */
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl
new file mode 100644
index 00000000000..99117400c57
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_add_shader.glsl
@@ -0,0 +1,4 @@
+void node_add_shader(Closure shader1, Closure shader2, out Closure shader)
+{
+ shader = closure_add(shader1, shader2);
+}
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
new file mode 100644
index 00000000000..8f8ebebb5f1
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
@@ -0,0 +1,13 @@
+#ifndef VOLUMETRICS
+void node_ambient_occlusion(
+ vec4 color, float distance, vec3 normal, out vec4 result_color, out float result_ao)
+{
+ vec3 bent_normal;
+ vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0);
+ result_ao = occlusion_compute(normalize(normal), viewPosition, 1.0, rand, bent_normal);
+ result_color = result_ao * color;
+}
+#else
+/* Stub ambient occlusion because it is not compatible with volumetrics. */
+# define node_ambient_occlusion
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl
new file mode 100644
index 00000000000..a8a900b40c6
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl
@@ -0,0 +1,15 @@
+#ifndef VOLUMETRICS
+void node_bsdf_anisotropic(vec4 color,
+ float roughness,
+ float anisotropy,
+ float rotation,
+ vec3 N,
+ vec3 T,
+ out Closure result)
+{
+ node_bsdf_glossy(color, roughness, N, -1, result);
+}
+#else
+/* Stub anisotropic because it is not compatible with volumetrics. */
+# define node_bsdf_anisotropic
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl
new file mode 100644
index 00000000000..10e1b4563bc
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl
@@ -0,0 +1,6 @@
+void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf)
+{
+ outcol = vec4(attr, 1.0);
+ outvec = attr;
+ outf = avg(attr);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_background.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_background.glsl
new file mode 100644
index 00000000000..69ef4dcb7c7
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_background.glsl
@@ -0,0 +1,11 @@
+void node_background(vec4 color, float strength, out Closure result)
+{
+#ifndef VOLUMETRICS
+ color *= strength;
+ result = CLOSURE_DEFAULT;
+ result.radiance = color.rgb;
+ result.transmittance = vec3(0.0);
+#else
+ result = CLOSURE_DEFAULT;
+#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_bevel.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_bevel.glsl
new file mode 100644
index 00000000000..0d99390c2f9
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_bevel.glsl
@@ -0,0 +1,4 @@
+void node_bevel(float radius, vec3 N, out vec3 result)
+{
+ result = N;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_blackbody.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_blackbody.glsl
new file mode 100644
index 00000000000..d0111aa3839
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_blackbody.glsl
@@ -0,0 +1,13 @@
+void node_blackbody(float temperature, sampler1DArray spectrummap, float layer, out vec4 color)
+{
+ if (temperature >= 12000.0) {
+ color = vec4(0.826270103, 0.994478524, 1.56626022, 1.0);
+ }
+ else if (temperature < 965.0) {
+ color = vec4(4.70366907, 0.0, 0.0, 1.0);
+ }
+ else {
+ float t = (temperature - 965.0) / (12000.0 - 965.0);
+ color = vec4(texture(spectrummap, vec2(t, layer)).rgb, 1.0);
+ }
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_bright_contrast.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_bright_contrast.glsl
new file mode 100644
index 00000000000..a5a10833065
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_bright_contrast.glsl
@@ -0,0 +1,10 @@
+void brightness_contrast(vec4 col, float brightness, float contrast, out vec4 outcol)
+{
+ float a = 1.0 + contrast;
+ float b = brightness - contrast * 0.5;
+
+ outcol.r = max(a * col.r + b, 0.0);
+ outcol.g = max(a * col.g + b, 0.0);
+ outcol.b = max(a * col.b + b, 0.0);
+ outcol.a = col.a;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl
new file mode 100644
index 00000000000..9f73f654217
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl
@@ -0,0 +1,44 @@
+void dfdx_v3(vec3 v, out vec3 dy)
+{
+ dy = v + DFDX_SIGN * dFdx(v);
+}
+
+void dfdy_v3(vec3 v, out vec3 dy)
+{
+ dy = v + DFDY_SIGN * dFdy(v);
+}
+
+void node_bump(float strength,
+ float dist,
+ float height,
+ float height_dx,
+ float height_dy,
+ vec3 N,
+ vec3 surf_pos,
+ float invert,
+ out vec3 result)
+{
+ N = mat3(ViewMatrix) * normalize(N);
+ dist *= gl_FrontFacing ? invert : -invert;
+
+ vec3 dPdx = dFdx(surf_pos);
+ vec3 dPdy = dFdy(surf_pos);
+
+ /* Get surface tangents from normal. */
+ vec3 Rx = cross(dPdy, N);
+ vec3 Ry = cross(N, dPdx);
+
+ /* Compute surface gradient and determinant. */
+ float det = dot(dPdx, Rx);
+
+ float dHdx = height_dx - height;
+ float dHdy = height_dy - height;
+ vec3 surfgrad = dHdx * Rx + dHdy * Ry;
+
+ strength = max(strength, 0.0);
+
+ result = normalize(abs(det) * N - dist * sign(det) * surfgrad);
+ result = normalize(mix(N, result, strength));
+
+ result = mat3(ViewMatrixInverse) * result;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl
new file mode 100644
index 00000000000..03e61e9f472
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl
@@ -0,0 +1,6 @@
+void camera(vec3 co, out vec3 outview, out float outdepth, out float outdist)
+{
+ outdepth = abs(co.z);
+ outdist = length(co);
+ outview = normalize(co);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_clamp.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_clamp.glsl
new file mode 100644
index 00000000000..b8842064b6f
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_clamp.glsl
@@ -0,0 +1,4 @@
+void clamp_value(float value, float min, float max, out float result)
+{
+ result = clamp(value, min, max);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_color_ramp.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_color_ramp.glsl
new file mode 100644
index 00000000000..9fe45f91f45
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_color_ramp.glsl
@@ -0,0 +1,28 @@
+void valtorgb_opti_constant(
+ float fac, float edge, vec4 color1, vec4 color2, out vec4 outcol, out float outalpha)
+{
+ outcol = (fac > edge) ? color2 : color1;
+ outalpha = outcol.a;
+}
+
+void valtorgb_opti_linear(
+ float fac, vec2 mulbias, vec4 color1, vec4 color2, out vec4 outcol, out float outalpha)
+{
+ fac = clamp(fac * mulbias.x + mulbias.y, 0.0, 1.0);
+ outcol = mix(color1, color2, fac);
+ outalpha = outcol.a;
+}
+
+void valtorgb(float fac, sampler1DArray colormap, float layer, out vec4 outcol, out float outalpha)
+{
+ outcol = texture(colormap, vec2(fac, layer));
+ outalpha = outcol.a;
+}
+
+void valtorgb_nearest(
+ float fac, sampler1DArray colormap, float layer, out vec4 outcol, out float outalpha)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ outcol = texelFetch(colormap, ivec2(fac * (textureSize(colormap, 0).x - 1), layer), 0);
+ outalpha = outcol.a;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl
new file mode 100644
index 00000000000..a5c3a990d90
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl
@@ -0,0 +1,111 @@
+void rgb_to_hsv(vec4 rgb, out vec4 outcol)
+{
+ float cmax, cmin, h, s, v, cdelta;
+ vec3 c;
+
+ cmax = max(rgb[0], max(rgb[1], rgb[2]));
+ cmin = min(rgb[0], min(rgb[1], rgb[2]));
+ cdelta = cmax - cmin;
+
+ v = cmax;
+ if (cmax != 0.0) {
+ s = cdelta / cmax;
+ }
+ else {
+ s = 0.0;
+ h = 0.0;
+ }
+
+ if (s == 0.0) {
+ h = 0.0;
+ }
+ else {
+ c = (vec3(cmax) - rgb.xyz) / cdelta;
+
+ if (rgb.x == cmax) {
+ h = c[2] - c[1];
+ }
+ else if (rgb.y == cmax) {
+ h = 2.0 + c[0] - c[2];
+ }
+ else {
+ h = 4.0 + c[1] - c[0];
+ }
+
+ h /= 6.0;
+
+ if (h < 0.0) {
+ h += 1.0;
+ }
+ }
+
+ outcol = vec4(h, s, v, rgb.w);
+}
+
+void hsv_to_rgb(vec4 hsv, out vec4 outcol)
+{
+ float i, f, p, q, t, h, s, v;
+ vec3 rgb;
+
+ h = hsv[0];
+ s = hsv[1];
+ v = hsv[2];
+
+ if (s == 0.0) {
+ rgb = vec3(v, v, v);
+ }
+ else {
+ if (h == 1.0) {
+ h = 0.0;
+ }
+
+ h *= 6.0;
+ i = floor(h);
+ f = h - i;
+ rgb = vec3(f, f, f);
+ p = v * (1.0 - s);
+ q = v * (1.0 - (s * f));
+ t = v * (1.0 - (s * (1.0 - f)));
+
+ if (i == 0.0) {
+ rgb = vec3(v, t, p);
+ }
+ else if (i == 1.0) {
+ rgb = vec3(q, v, p);
+ }
+ else if (i == 2.0) {
+ rgb = vec3(p, v, t);
+ }
+ else if (i == 3.0) {
+ rgb = vec3(p, q, v);
+ }
+ else if (i == 4.0) {
+ rgb = vec3(t, p, v);
+ }
+ else {
+ rgb = vec3(v, p, q);
+ }
+ }
+
+ outcol = vec4(rgb, hsv.w);
+}
+
+void color_alpha_clear(vec4 color, out vec4 result)
+{
+ result = vec4(color.rgb, 1.0);
+}
+
+void color_alpha_premultiply(vec4 color, out vec4 result)
+{
+ result = vec4(color.rgb * color.a, 1.0);
+}
+
+void color_alpha_unpremultiply(vec4 color, out vec4 result)
+{
+ if (color.a == 0.0 || color.a == 1.0) {
+ result = vec4(color.rgb, 1.0);
+ }
+ else {
+ result = vec4(color.rgb / color.a, 1.0);
+ }
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl
new file mode 100644
index 00000000000..2ce061da3cb
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl
@@ -0,0 +1,4 @@
+void combine_hsv(float h, float s, float v, out vec4 col)
+{
+ hsv_to_rgb(vec4(h, s, v, 1.0), col);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_combine_rgb.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_combine_rgb.glsl
new file mode 100644
index 00000000000..d9c882a048f
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_combine_rgb.glsl
@@ -0,0 +1,4 @@
+void combine_rgb(float r, float g, float b, out vec4 col)
+{
+ col = vec4(r, g, b, 1.0);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_combine_xyz.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_combine_xyz.glsl
new file mode 100644
index 00000000000..d8d132ff1f9
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_combine_xyz.glsl
@@ -0,0 +1,4 @@
+void combine_xyz(float x, float y, float z, out vec3 vec)
+{
+ vec = vec3(x, y, z);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl
new file mode 100644
index 00000000000..e029905a908
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl
@@ -0,0 +1,13 @@
+#ifndef VOLUMETRICS
+void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
+{
+ N = normalize(N);
+ result = CLOSURE_DEFAULT;
+ eevee_closure_diffuse(N, color.rgb, 1.0, true, result.radiance);
+ closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
+ result.radiance *= color.rgb;
+}
+#else
+/* Stub diffuse because it is not compatible with volumetrics. */
+# define node_bsdf_diffuse
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl
new file mode 100644
index 00000000000..0838b5c8b71
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl
@@ -0,0 +1,12 @@
+void node_displacement_object(
+ float height, float midlevel, float scale, vec3 N, mat4 obmat, out vec3 result)
+{
+ N = (vec4(N, 0.0) * obmat).xyz;
+ result = (height - midlevel) * scale * normalize(N);
+ result = (obmat * vec4(result, 0.0)).xyz;
+}
+
+void node_displacement_world(float height, float midlevel, float scale, vec3 N, out vec3 result)
+{
+ result = (height - midlevel) * scale * normalize(N);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
new file mode 100644
index 00000000000..34062cc8d02
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
@@ -0,0 +1,41 @@
+#ifndef VOLUMETRICS
+void node_eevee_specular(vec4 diffuse,
+ vec4 specular,
+ float roughness,
+ vec4 emissive,
+ float transp,
+ vec3 normal,
+ float clearcoat,
+ float clearcoat_roughness,
+ vec3 clearcoat_normal,
+ float occlusion,
+ float ssr_id,
+ out Closure result)
+{
+ normal = normalize(normal);
+
+ vec3 out_diff, out_spec, ssr_spec;
+ eevee_closure_default_clearcoat(normal,
+ diffuse.rgb,
+ specular.rgb,
+ vec3(1.0),
+ int(ssr_id),
+ roughness,
+ clearcoat_normal,
+ clearcoat * 0.25,
+ clearcoat_roughness,
+ occlusion,
+ true,
+ out_diff,
+ out_spec,
+ ssr_spec);
+
+ float alpha = 1.0 - transp;
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_diff * diffuse.rgb + out_spec + emissive.rgb;
+ result.radiance *= alpha;
+ result.transmittance = vec3(transp);
+
+ closure_load_ssr_data(ssr_spec * alpha, roughness, normal, viewCameraVec, int(ssr_id), result);
+}
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl
new file mode 100644
index 00000000000..092b9ed08bb
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl
@@ -0,0 +1,10 @@
+void node_emission(vec4 color, float strength, vec3 vN, out Closure result)
+{
+ result = CLOSURE_DEFAULT;
+#ifndef VOLUMETRICS
+ result.radiance = color.rgb * strength;
+ result.ssr_normal = normal_encode(vN, viewCameraVec);
+#else
+ result.emission = color.rgb * strength;
+#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl
new file mode 100644
index 00000000000..701b07b4aae
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl
@@ -0,0 +1,111 @@
+/* The fractal_noise functions are all exactly the same except for the input type. */
+float fractal_noise(float p, float octaves)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float sum = 0.0;
+ octaves = clamp(octaves, 0.0, 16.0);
+ int n = int(octaves);
+ for (int i = 0; i <= n; i++) {
+ float t = noise(fscale * p);
+ sum += t * amp;
+ amp *= 0.5;
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = noise(fscale * p);
+ float sum2 = sum + t * amp;
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
+ sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1));
+ return (1.0 - rmd) * sum + rmd * sum2;
+ }
+ else {
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
+ return sum;
+ }
+}
+
+/* The fractal_noise functions are all exactly the same except for the input type. */
+float fractal_noise(vec2 p, float octaves)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float sum = 0.0;
+ octaves = clamp(octaves, 0.0, 16.0);
+ int n = int(octaves);
+ for (int i = 0; i <= n; i++) {
+ float t = noise(fscale * p);
+ sum += t * amp;
+ amp *= 0.5;
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = noise(fscale * p);
+ float sum2 = sum + t * amp;
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
+ sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1));
+ return (1.0 - rmd) * sum + rmd * sum2;
+ }
+ else {
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
+ return sum;
+ }
+}
+
+/* The fractal_noise functions are all exactly the same except for the input type. */
+float fractal_noise(vec3 p, float octaves)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float sum = 0.0;
+ octaves = clamp(octaves, 0.0, 16.0);
+ int n = int(octaves);
+ for (int i = 0; i <= n; i++) {
+ float t = noise(fscale * p);
+ sum += t * amp;
+ amp *= 0.5;
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = noise(fscale * p);
+ float sum2 = sum + t * amp;
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
+ sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1));
+ return (1.0 - rmd) * sum + rmd * sum2;
+ }
+ else {
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
+ return sum;
+ }
+}
+
+/* The fractal_noise functions are all exactly the same except for the input type. */
+float fractal_noise(vec4 p, float octaves)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float sum = 0.0;
+ octaves = clamp(octaves, 0.0, 16.0);
+ int n = int(octaves);
+ for (int i = 0; i <= n; i++) {
+ float t = noise(fscale * p);
+ sum += t * amp;
+ amp *= 0.5;
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = noise(fscale * p);
+ float sum2 = sum + t * amp;
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
+ sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1));
+ return (1.0 - rmd) * sum + rmd * sum2;
+ }
+ else {
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
+ return sum;
+ }
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl
new file mode 100644
index 00000000000..7a4d28f2dd6
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl
@@ -0,0 +1,37 @@
+float fresnel_dielectric_cos(float cosi, float eta)
+{
+ /* compute fresnel reflectance without explicitly computing
+ * the refracted direction */
+ float c = abs(cosi);
+ float g = eta * eta - 1.0 + c * c;
+ float result;
+
+ if (g > 0.0) {
+ g = sqrt(g);
+ float A = (g - c) / (g + c);
+ float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0);
+ result = 0.5 * A * A * (1.0 + B * B);
+ }
+ else {
+ result = 1.0; /* TIR (no refracted component) */
+ }
+
+ return result;
+}
+
+float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
+{
+ /* compute fresnel reflectance without explicitly computing
+ * the refracted direction */
+ return fresnel_dielectric_cos(dot(Incoming, Normal), eta);
+}
+
+void node_fresnel(float ior, vec3 N, vec3 I, out float result)
+{
+ N = normalize(N);
+ /* handle perspective/orthographic */
+ vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
+
+ float eta = max(ior, 0.00001);
+ result = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? eta : 1.0 / eta);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl
new file mode 100644
index 00000000000..5733992f8dd
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl
@@ -0,0 +1,14 @@
+void node_gamma(vec4 col, float gamma, out vec4 outcol)
+{
+ outcol = col;
+
+ if (col.r > 0.0) {
+ outcol.r = compatible_pow(col.r, gamma);
+ }
+ if (col.g > 0.0) {
+ outcol.g = compatible_pow(col.g, gamma);
+ }
+ if (col.b > 0.0) {
+ outcol.b = compatible_pow(col.b, gamma);
+ }
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
new file mode 100644
index 00000000000..79614495499
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
@@ -0,0 +1,46 @@
+void node_geometry(vec3 I,
+ vec3 N,
+ vec3 orco,
+ mat4 objmat,
+ mat4 toworld,
+ vec2 barycentric,
+ out vec3 position,
+ out vec3 normal,
+ out vec3 tangent,
+ out vec3 true_normal,
+ out vec3 incoming,
+ out vec3 parametric,
+ out float backfacing,
+ out float pointiness)
+{
+ /* handle perspective/orthographic */
+ vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
+ incoming = -(toworld * vec4(I_view, 0.0)).xyz;
+
+#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
+ position = -incoming;
+ true_normal = normal = incoming;
+ tangent = parametric = vec3(0.0);
+ vec3(0.0);
+ backfacing = 0.0;
+ pointiness = 0.0;
+#else
+
+ position = worldPosition;
+# ifndef VOLUMETRICS
+ normal = normalize(N);
+ vec3 B = dFdx(worldPosition);
+ vec3 T = dFdy(worldPosition);
+ true_normal = normalize(cross(B, T));
+# else
+ normal = (toworld * vec4(N, 0.0)).xyz;
+ true_normal = normal;
+# endif
+ tangent_orco_z(orco, orco);
+ node_tangent(N, orco, objmat, tangent);
+
+ parametric = vec3(barycentric, 0.0);
+ backfacing = (gl_FrontFacing) ? 0.0 : 1.0;
+ pointiness = 0.5;
+#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl
new file mode 100644
index 00000000000..5038cb3892f
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl
@@ -0,0 +1,32 @@
+#ifndef VOLUMETRICS
+void node_bsdf_glass(
+ vec4 color, float roughness, float ior, vec3 N, float ssr_id, out Closure result)
+{
+ N = normalize(N);
+ vec3 out_spec, out_refr, ssr_spec;
+ vec3 refr_color = (refractionDepth > 0.0) ? color.rgb * color.rgb :
+ color.rgb; /* Simulate 2 transmission event */
+ eevee_closure_glass(N,
+ vec3(1.0),
+ vec3(1.0),
+ int(ssr_id),
+ roughness,
+ 1.0,
+ ior,
+ true,
+ out_spec,
+ out_refr,
+ ssr_spec);
+ out_refr *= refr_color;
+ out_spec *= color.rgb;
+ float fresnel = F_eta(ior, dot(N, cameraVec));
+ vec3 vN = mat3(ViewMatrix) * N;
+ result = CLOSURE_DEFAULT;
+ result.radiance = mix(out_refr, out_spec, fresnel);
+ closure_load_ssr_data(
+ ssr_spec * color.rgb * fresnel, roughness, N, viewCameraVec, int(ssr_id), result);
+}
+#else
+/* Stub glass because it is not compatible with volumetrics. */
+# define node_bsdf_glass
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl
new file mode 100644
index 00000000000..75cc2e770c5
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl
@@ -0,0 +1,16 @@
+#ifndef VOLUMETRICS
+void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Closure result)
+{
+ N = normalize(N);
+ vec3 out_spec, ssr_spec;
+ eevee_closure_glossy(
+ N, vec3(1.0), vec3(1.0), int(ssr_id), roughness, 1.0, true, out_spec, ssr_spec);
+ vec3 vN = mat3(ViewMatrix) * N;
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_spec * color.rgb;
+ closure_load_ssr_data(ssr_spec * color.rgb, roughness, N, viewCameraVec, int(ssr_id), result);
+}
+#else
+/* Stub glossy because it is not compatible with volumetrics. */
+# define node_bsdf_glossy
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
new file mode 100644
index 00000000000..3b23ac976ae
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
@@ -0,0 +1,21 @@
+void node_hair_info(out float is_strand,
+ out float intercept,
+ out float thickness,
+ out vec3 tangent,
+ out float random)
+{
+#ifdef HAIR_SHADER
+ is_strand = 1.0;
+ intercept = hairTime;
+ thickness = hairThickness;
+ tangent = normalize(worldNormal);
+ random = wang_hash_noise(
+ uint(hairStrandID)); /* TODO: could be precomputed per strand instead. */
+#else
+ is_strand = 0.0;
+ intercept = 0.0;
+ thickness = 0.0;
+ tangent = vec3(1.0);
+ random = 0.0;
+#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl
new file mode 100644
index 00000000000..86191451e5f
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl
@@ -0,0 +1,217 @@
+/* ***** Jenkins Lookup3 Hash Functions ***** */
+
+/* Source: http://burtleburtle.net/bob/c/lookup3.c */
+
+#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
+
+#define mix(a, b, c) \
+ { \
+ a -= c; \
+ a ^= rot(c, 4); \
+ c += b; \
+ b -= a; \
+ b ^= rot(a, 6); \
+ a += c; \
+ c -= b; \
+ c ^= rot(b, 8); \
+ b += a; \
+ a -= c; \
+ a ^= rot(c, 16); \
+ c += b; \
+ b -= a; \
+ b ^= rot(a, 19); \
+ a += c; \
+ c -= b; \
+ c ^= rot(b, 4); \
+ b += a; \
+ }
+
+#define final(a, b, c) \
+ { \
+ c ^= b; \
+ c -= rot(b, 14); \
+ a ^= c; \
+ a -= rot(c, 11); \
+ b ^= a; \
+ b -= rot(a, 25); \
+ c ^= b; \
+ c -= rot(b, 16); \
+ a ^= c; \
+ a -= rot(c, 4); \
+ b ^= a; \
+ b -= rot(a, 14); \
+ c ^= b; \
+ c -= rot(b, 24); \
+ }
+
+uint hash_uint(uint kx)
+{
+ uint a, b, c;
+ a = b = c = 0xdeadbeefu + (1u << 2u) + 13u;
+
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+uint hash_uint2(uint kx, uint ky)
+{
+ uint a, b, c;
+ a = b = c = 0xdeadbeefu + (2u << 2u) + 13u;
+
+ b += ky;
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+uint hash_uint3(uint kx, uint ky, uint kz)
+{
+ uint a, b, c;
+ a = b = c = 0xdeadbeefu + (3u << 2u) + 13u;
+
+ c += kz;
+ b += ky;
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+uint hash_uint4(uint kx, uint ky, uint kz, uint kw)
+{
+ uint a, b, c;
+ a = b = c = 0xdeadbeefu + (4u << 2u) + 13u;
+
+ a += kx;
+ b += ky;
+ c += kz;
+ mix(a, b, c);
+
+ a += kw;
+ final(a, b, c);
+
+ return c;
+}
+
+#undef rot
+#undef final
+#undef mix
+
+uint hash_int(int kx)
+{
+ return hash_uint(uint(kx));
+}
+
+uint hash_int2(int kx, int ky)
+{
+ return hash_uint2(uint(kx), uint(ky));
+}
+
+uint hash_int3(int kx, int ky, int kz)
+{
+ return hash_uint3(uint(kx), uint(ky), uint(kz));
+}
+
+uint hash_int4(int kx, int ky, int kz, int kw)
+{
+ return hash_uint4(uint(kx), uint(ky), uint(kz), uint(kw));
+}
+
+/* Hashing uint or uint[234] into a float in the range [0, 1]. */
+
+float hash_uint_to_float(uint kx)
+{
+ return float(hash_uint(kx)) / float(0xFFFFFFFFu);
+}
+
+float hash_uint2_to_float(uint kx, uint ky)
+{
+ return float(hash_uint2(kx, ky)) / float(0xFFFFFFFFu);
+}
+
+float hash_uint3_to_float(uint kx, uint ky, uint kz)
+{
+ return float(hash_uint3(kx, ky, kz)) / float(0xFFFFFFFFu);
+}
+
+float hash_uint4_to_float(uint kx, uint ky, uint kz, uint kw)
+{
+ return float(hash_uint4(kx, ky, kz, kw)) / float(0xFFFFFFFFu);
+}
+
+/* Hashing float or vec[234] into a float in the range [0, 1]. */
+
+float hash_float_to_float(float k)
+{
+ return hash_uint_to_float(floatBitsToUint(k));
+}
+
+float hash_vec2_to_float(vec2 k)
+{
+ return hash_uint2_to_float(floatBitsToUint(k.x), floatBitsToUint(k.y));
+}
+
+float hash_vec3_to_float(vec3 k)
+{
+ return hash_uint3_to_float(floatBitsToUint(k.x), floatBitsToUint(k.y), floatBitsToUint(k.z));
+}
+
+float hash_vec4_to_float(vec4 k)
+{
+ return hash_uint4_to_float(
+ floatBitsToUint(k.x), floatBitsToUint(k.y), floatBitsToUint(k.z), floatBitsToUint(k.w));
+}
+
+/* Hashing vec[234] into vec[234] of components in the range [0, 1]. */
+
+vec2 hash_vec2_to_vec2(vec2 k)
+{
+ return vec2(hash_vec2_to_float(k), hash_vec3_to_float(vec3(k, 1.0)));
+}
+
+vec3 hash_vec3_to_vec3(vec3 k)
+{
+ return vec3(
+ hash_vec3_to_float(k), hash_vec4_to_float(vec4(k, 1.0)), hash_vec4_to_float(vec4(k, 2.0)));
+}
+
+vec4 hash_vec4_to_vec4(vec4 k)
+{
+ return vec4(hash_vec4_to_float(k.xyzw),
+ hash_vec4_to_float(k.wxyz),
+ hash_vec4_to_float(k.zwxy),
+ hash_vec4_to_float(k.yzwx));
+}
+
+/* Hashing float or vec[234] into vec3 of components in range [0, 1]. */
+
+vec3 hash_float_to_vec3(float k)
+{
+ return vec3(
+ hash_float_to_float(k), hash_vec2_to_float(vec2(k, 1.0)), hash_vec2_to_float(vec2(k, 2.0)));
+}
+
+vec3 hash_vec2_to_vec3(vec2 k)
+{
+ return vec3(
+ hash_vec2_to_float(k), hash_vec3_to_float(vec3(k, 1.0)), hash_vec3_to_float(vec3(k, 2.0)));
+}
+
+vec3 hash_vec4_to_vec3(vec4 k)
+{
+ return vec3(hash_vec4_to_float(k.xyzw), hash_vec4_to_float(k.zxwy), hash_vec4_to_float(k.wzyx));
+}
+
+/* Other Hash Functions */
+
+float integer_noise(int n)
+{
+ int nn;
+ n = (n + 1013) & 0x7fffffff;
+ n = (n >> 13) ^ n;
+ nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
+ return 0.5 * (float(nn) / 1073741824.0);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl
new file mode 100644
index 00000000000..50ce2bf2ab8
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl
@@ -0,0 +1,8 @@
+void node_holdout(out Closure result)
+{
+ result = CLOSURE_DEFAULT;
+#ifndef VOLUMETRICS
+ result.holdout = 1.0;
+ result.flag = CLOSURE_HOLDOUT_FLAG;
+#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl
new file mode 100644
index 00000000000..64ac73ecdf3
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl
@@ -0,0 +1,14 @@
+void hue_sat(float hue, float sat, float value, float fac, vec4 col, out vec4 outcol)
+{
+ vec4 hsv;
+
+ rgb_to_hsv(col, hsv);
+
+ hsv[0] = fract(hsv[0] + hue + 0.5);
+ hsv[1] = clamp(hsv[1] * sat, 0.0, 1.0);
+ hsv[2] = hsv[2] * value;
+
+ hsv_to_rgb(hsv, outcol);
+
+ outcol = mix(col, outcol, fac);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_invert.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_invert.glsl
new file mode 100644
index 00000000000..5cf362a9947
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_invert.glsl
@@ -0,0 +1,5 @@
+void invert(float fac, vec4 col, out vec4 outcol)
+{
+ outcol.xyz = mix(col.xyz, vec3(1.0) - col.xyz, fac);
+ outcol.w = col.w;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl
new file mode 100644
index 00000000000..588d295bcc4
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl
@@ -0,0 +1,19 @@
+void node_layer_weight(float blend, vec3 N, vec3 I, out float fresnel, out float facing)
+{
+ N = normalize(N);
+
+ /* fresnel */
+ float eta = max(1.0 - blend, 0.00001);
+ vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
+
+ fresnel = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? 1.0 / eta : eta);
+
+ /* facing */
+ facing = abs(dot(I_view, N));
+ if (blend != 0.5) {
+ blend = clamp(blend, 0.0, 0.99999);
+ blend = (blend < 0.5) ? 2.0 * blend : 0.5 / (1.0 - blend);
+ facing = pow(facing, blend);
+ }
+ facing = 1.0 - facing;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl
new file mode 100644
index 00000000000..f3eae653f95
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl
@@ -0,0 +1,7 @@
+void node_light_falloff(
+ float strength, float tsmooth, out float quadratic, out float linear, out float constant)
+{
+ quadratic = strength;
+ linear = strength;
+ constant = strength;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl
new file mode 100644
index 00000000000..50c87e3f105
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl
@@ -0,0 +1,31 @@
+void node_light_path(out float is_camera_ray,
+ out float is_shadow_ray,
+ out float is_diffuse_ray,
+ out float is_glossy_ray,
+ out float is_singular_ray,
+ out float is_reflection_ray,
+ out float is_transmission_ray,
+ out float ray_length,
+ out float ray_depth,
+ out float diffuse_depth,
+ out float glossy_depth,
+ out float transparent_depth,
+ out float transmission_depth)
+{
+ /* Supported. */
+ is_camera_ray = (rayType == EEVEE_RAY_CAMERA) ? 1.0 : 0.0;
+ is_shadow_ray = (rayType == EEVEE_RAY_SHADOW) ? 1.0 : 0.0;
+ is_diffuse_ray = (rayType == EEVEE_RAY_DIFFUSE) ? 1.0 : 0.0;
+ is_glossy_ray = (rayType == EEVEE_RAY_GLOSSY) ? 1.0 : 0.0;
+ /* Kind of supported. */
+ is_singular_ray = is_glossy_ray;
+ is_reflection_ray = is_glossy_ray;
+ is_transmission_ray = is_glossy_ray;
+ ray_depth = rayDepth;
+ diffuse_depth = (is_diffuse_ray == 1.0) ? rayDepth : 0.0;
+ glossy_depth = (is_glossy_ray == 1.0) ? rayDepth : 0.0;
+ transmission_depth = (is_transmission_ray == 1.0) ? glossy_depth : 0.0;
+ /* Not supported. */
+ ray_length = 1.0;
+ transparent_depth = 0.0;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
new file mode 100644
index 00000000000..a185774f4b3
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
@@ -0,0 +1,10 @@
+void map_range(
+ float value, float fromMin, float fromMax, float toMin, float toMax, out float result)
+{
+ if (fromMax != fromMin) {
+ result = toMin + ((value - fromMin) / (fromMax - fromMin)) * (toMax - toMin);
+ }
+ else {
+ result = 0.0;
+ }
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl
new file mode 100644
index 00000000000..07f152439fe
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl
@@ -0,0 +1,27 @@
+void mapping_mat4(
+ vec3 vec, vec4 m0, vec4 m1, vec4 m2, vec4 m3, vec3 minvec, vec3 maxvec, out vec3 outvec)
+{
+ mat4 mat = mat4(m0, m1, m2, m3);
+ outvec = (mat * vec4(vec, 1.0)).xyz;
+ outvec = clamp(outvec, minvec, maxvec);
+}
+
+void mapping_point(vec3 vector, vec3 location, vec3 rotation, vec3 scale, out vec3 result)
+{
+ result = (euler_to_mat3(rotation) * (vector * scale)) + location;
+}
+
+void mapping_texture(vec3 vector, vec3 location, vec3 rotation, vec3 scale, out vec3 result)
+{
+ result = safe_divide(transpose(euler_to_mat3(rotation)) * (vector - location), scale);
+}
+
+void mapping_vector(vec3 vector, vec3 location, vec3 rotation, vec3 scale, out vec3 result)
+{
+ result = euler_to_mat3(rotation) * (vector * scale);
+}
+
+void mapping_normal(vec3 vector, vec3 location, vec3 rotation, vec3 scale, out vec3 result)
+{
+ result = normalize(euler_to_mat3(rotation) * safe_divide(vector, scale));
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl
new file mode 100644
index 00000000000..4fac770e8fe
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl
@@ -0,0 +1,130 @@
+void math_add(float a, float b, out float result)
+{
+ result = a + b;
+}
+
+void math_subtract(float a, float b, out float result)
+{
+ result = a - b;
+}
+
+void math_multiply(float a, float b, out float result)
+{
+ result = a * b;
+}
+
+void math_divide(float a, float b, out float result)
+{
+ result = safe_divide(a, b);
+}
+
+void math_power(float a, float b, out float result)
+{
+ if (a >= 0.0) {
+ result = compatible_pow(a, b);
+ }
+ else {
+ float fraction = mod(abs(b), 1.0);
+ if (fraction > 0.999 || fraction < 0.001) {
+ result = compatible_pow(a, floor(b + 0.5));
+ }
+ else {
+ result = 0.0;
+ }
+ }
+}
+
+void math_logarithm(float a, float b, out float result)
+{
+ result = (a > 0.0 && b > 0.0) ? log2(a) / log2(b) : 0.0;
+}
+
+void math_sqrt(float a, float b, out float result)
+{
+ result = (a > 0.0) ? sqrt(a) : 0.0;
+}
+
+void math_absolute(float a, float b, out float result)
+{
+ result = abs(a);
+}
+
+void math_minimum(float a, float b, out float result)
+{
+ result = min(a, b);
+}
+
+void math_maximum(float a, float b, out float result)
+{
+ result = max(a, b);
+}
+
+void math_less_than(float a, float b, out float result)
+{
+ result = (a < b) ? 1.0 : 0.0;
+}
+
+void math_greater_than(float a, float b, out float result)
+{
+ result = (a > b) ? 1.0 : 0.0;
+}
+
+void math_round(float a, float b, out float result)
+{
+ result = floor(a + 0.5);
+}
+
+void math_floor(float a, float b, out float result)
+{
+ result = floor(a);
+}
+
+void math_ceil(float a, float b, out float result)
+{
+ result = ceil(a);
+}
+
+void math_fraction(float a, float b, out float result)
+{
+ result = a - floor(a);
+}
+
+void math_modulo(float a, float b, out float result)
+{
+ result = c_mod(a, b);
+}
+
+void math_sine(float a, float b, out float result)
+{
+ result = sin(a);
+}
+
+void math_cosine(float a, float b, out float result)
+{
+ result = cos(a);
+}
+
+void math_tangent(float a, float b, out float result)
+{
+ result = tan(a);
+}
+
+void math_arcsine(float a, float b, out float result)
+{
+ result = (a <= 1.0 && a >= -1.0) ? asin(a) : 0.0;
+}
+
+void math_arccosine(float a, float b, out float result)
+{
+ result = (a <= 1.0 && a >= -1.0) ? acos(a) : 0.0;
+}
+
+void math_arctangent(float a, float b, out float result)
+{
+ result = atan(a);
+}
+
+void math_arctan2(float a, float b, out float result)
+{
+ result = atan(a, b);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
new file mode 100644
index 00000000000..d4f7866b206
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
@@ -0,0 +1,151 @@
+/* Float Math */
+
+float safe_divide(float a, float b)
+{
+ return (b != 0.0) ? a / b : 0.0;
+}
+
+/* Modulo with C sign convention. mod in GLSL will take absolute for negative numbers. */
+float c_mod(float a, float b)
+{
+ return (b != 0.0 && a != b) ? sign(a) * mod(abs(a), b) : 0.0;
+}
+
+float compatible_pow(float x, float y)
+{
+ if (y == 0.0) { /* x^0 -> 1, including 0^0 */
+ return 1.0;
+ }
+
+ /* glsl pow doesn't accept negative x */
+ if (x < 0.0) {
+ if (mod(-y, 2.0) == 0.0) {
+ return pow(-x, y);
+ }
+ else {
+ return -pow(-x, y);
+ }
+ }
+ else if (x == 0.0) {
+ return 0.0;
+ }
+
+ return pow(x, y);
+}
+
+float hypot(float x, float y)
+{
+ return sqrt(x * x + y * y);
+}
+
+int floor_to_int(float x)
+{
+ return int(floor(x));
+}
+
+int quick_floor(float x)
+{
+ return int(x) - ((x < 0) ? 1 : 0);
+}
+
+float floorfrac(float x, out int i)
+{
+ float x_floor = floor(x);
+ i = int(x_floor);
+ return x - x_floor;
+}
+
+/* Vector Math */
+
+vec2 safe_divide(vec2 a, vec2 b)
+{
+ return vec2(safe_divide(a.x, b.x), safe_divide(a.y, b.y));
+}
+
+vec3 safe_divide(vec3 a, vec3 b)
+{
+ return vec3(safe_divide(a.x, b.x), safe_divide(a.y, b.y), safe_divide(a.z, b.z));
+}
+
+vec4 safe_divide(vec4 a, vec4 b)
+{
+ return vec4(
+ safe_divide(a.x, b.x), safe_divide(a.y, b.y), safe_divide(a.z, b.z), safe_divide(a.w, b.w));
+}
+
+vec2 safe_divide(vec2 a, float b)
+{
+ return (b != 0.0) ? a / b : vec2(0.0);
+}
+
+vec3 safe_divide(vec3 a, float b)
+{
+ return (b != 0.0) ? a / b : vec3(0.0);
+}
+
+vec4 safe_divide(vec4 a, float b)
+{
+ return (b != 0.0) ? a / b : vec4(0.0);
+}
+
+vec3 c_mod(vec3 a, vec3 b)
+{
+ return vec3(c_mod(a.x, b.x), c_mod(a.y, b.y), c_mod(a.z, b.z));
+}
+
+void vector_mix(float strength, vec3 a, vec3 b, out vec3 outVector)
+{
+ outVector = strength * a + (1 - strength) * b;
+}
+
+void invert_z(vec3 v, out vec3 outv)
+{
+ v.z = -v.z;
+ outv = v;
+}
+
+void vector_normalize(vec3 normal, out vec3 outnormal)
+{
+ outnormal = normalize(normal);
+}
+
+/* Matirx Math */
+
+mat3 euler_to_mat3(vec3 euler)
+{
+ float cx = cos(euler.x);
+ float cy = cos(euler.y);
+ float cz = cos(euler.z);
+ float sx = sin(euler.x);
+ float sy = sin(euler.y);
+ float sz = sin(euler.z);
+
+ mat3 mat;
+ mat[0][0] = cy * cz;
+ mat[0][1] = cy * sz;
+ mat[0][2] = -sy;
+
+ mat[1][0] = sy * sx * cz - cx * sz;
+ mat[1][1] = sy * sx * sz + cx * cz;
+ mat[1][2] = cy * sx;
+
+ mat[2][0] = sy * cx * cz + sx * sz;
+ mat[2][1] = sy * cx * sz - sx * cz;
+ mat[2][2] = cy * cx;
+ return mat;
+}
+
+void direction_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
+{
+ vout = (mat * vec4(vin, 0.0)).xyz;
+}
+
+void normal_transform_transposed_m4v3(vec3 vin, mat4 mat, out vec3 vout)
+{
+ vout = transpose(mat3(mat)) * vin;
+}
+
+void point_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
+{
+ vout = (mat * vec4(vin, 1.0)).xyz;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl
new file mode 100644
index 00000000000..abe6081489d
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl
@@ -0,0 +1,291 @@
+void mix_blend(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ outcol = mix(col1, col2, fac);
+ outcol.a = col1.a;
+}
+
+void mix_add(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ outcol = mix(col1, col1 + col2, fac);
+ outcol.a = col1.a;
+}
+
+void mix_mult(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ outcol = mix(col1, col1 * col2, fac);
+ outcol.a = col1.a;
+}
+
+void mix_screen(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ float facm = 1.0 - fac;
+
+ outcol = vec4(1.0) - (vec4(facm) + fac * (vec4(1.0) - col2)) * (vec4(1.0) - col1);
+ outcol.a = col1.a;
+}
+
+void mix_overlay(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ float facm = 1.0 - fac;
+
+ outcol = col1;
+
+ if (outcol.r < 0.5) {
+ outcol.r *= facm + 2.0 * fac * col2.r;
+ }
+ else {
+ outcol.r = 1.0 - (facm + 2.0 * fac * (1.0 - col2.r)) * (1.0 - outcol.r);
+ }
+
+ if (outcol.g < 0.5) {
+ outcol.g *= facm + 2.0 * fac * col2.g;
+ }
+ else {
+ outcol.g = 1.0 - (facm + 2.0 * fac * (1.0 - col2.g)) * (1.0 - outcol.g);
+ }
+
+ if (outcol.b < 0.5) {
+ outcol.b *= facm + 2.0 * fac * col2.b;
+ }
+ else {
+ outcol.b = 1.0 - (facm + 2.0 * fac * (1.0 - col2.b)) * (1.0 - outcol.b);
+ }
+}
+
+void mix_sub(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ outcol = mix(col1, col1 - col2, fac);
+ outcol.a = col1.a;
+}
+
+void mix_div(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ float facm = 1.0 - fac;
+
+ outcol = col1;
+
+ if (col2.r != 0.0) {
+ outcol.r = facm * outcol.r + fac * outcol.r / col2.r;
+ }
+ if (col2.g != 0.0) {
+ outcol.g = facm * outcol.g + fac * outcol.g / col2.g;
+ }
+ if (col2.b != 0.0) {
+ outcol.b = facm * outcol.b + fac * outcol.b / col2.b;
+ }
+}
+
+void mix_diff(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ outcol = mix(col1, abs(col1 - col2), fac);
+ outcol.a = col1.a;
+}
+
+void mix_dark(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ outcol.rgb = min(col1.rgb, col2.rgb * fac);
+ outcol.a = col1.a;
+}
+
+void mix_light(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ outcol.rgb = max(col1.rgb, col2.rgb * fac);
+ outcol.a = col1.a;
+}
+
+void mix_dodge(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ outcol = col1;
+
+ if (outcol.r != 0.0) {
+ float tmp = 1.0 - fac * col2.r;
+ if (tmp <= 0.0) {
+ outcol.r = 1.0;
+ }
+ else if ((tmp = outcol.r / tmp) > 1.0) {
+ outcol.r = 1.0;
+ }
+ else {
+ outcol.r = tmp;
+ }
+ }
+ if (outcol.g != 0.0) {
+ float tmp = 1.0 - fac * col2.g;
+ if (tmp <= 0.0) {
+ outcol.g = 1.0;
+ }
+ else if ((tmp = outcol.g / tmp) > 1.0) {
+ outcol.g = 1.0;
+ }
+ else {
+ outcol.g = tmp;
+ }
+ }
+ if (outcol.b != 0.0) {
+ float tmp = 1.0 - fac * col2.b;
+ if (tmp <= 0.0) {
+ outcol.b = 1.0;
+ }
+ else if ((tmp = outcol.b / tmp) > 1.0) {
+ outcol.b = 1.0;
+ }
+ else {
+ outcol.b = tmp;
+ }
+ }
+}
+
+void mix_burn(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ float tmp, facm = 1.0 - fac;
+
+ outcol = col1;
+
+ tmp = facm + fac * col2.r;
+ if (tmp <= 0.0) {
+ outcol.r = 0.0;
+ }
+ else if ((tmp = (1.0 - (1.0 - outcol.r) / tmp)) < 0.0) {
+ outcol.r = 0.0;
+ }
+ else if (tmp > 1.0) {
+ outcol.r = 1.0;
+ }
+ else {
+ outcol.r = tmp;
+ }
+
+ tmp = facm + fac * col2.g;
+ if (tmp <= 0.0) {
+ outcol.g = 0.0;
+ }
+ else if ((tmp = (1.0 - (1.0 - outcol.g) / tmp)) < 0.0) {
+ outcol.g = 0.0;
+ }
+ else if (tmp > 1.0) {
+ outcol.g = 1.0;
+ }
+ else {
+ outcol.g = tmp;
+ }
+
+ tmp = facm + fac * col2.b;
+ if (tmp <= 0.0) {
+ outcol.b = 0.0;
+ }
+ else if ((tmp = (1.0 - (1.0 - outcol.b) / tmp)) < 0.0) {
+ outcol.b = 0.0;
+ }
+ else if (tmp > 1.0) {
+ outcol.b = 1.0;
+ }
+ else {
+ outcol.b = tmp;
+ }
+}
+
+void mix_hue(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ float facm = 1.0 - fac;
+
+ outcol = col1;
+
+ vec4 hsv, hsv2, tmp;
+ rgb_to_hsv(col2, hsv2);
+
+ if (hsv2.y != 0.0) {
+ rgb_to_hsv(outcol, hsv);
+ hsv.x = hsv2.x;
+ hsv_to_rgb(hsv, tmp);
+
+ outcol = mix(outcol, tmp, fac);
+ outcol.a = col1.a;
+ }
+}
+
+void mix_sat(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ float facm = 1.0 - fac;
+
+ outcol = col1;
+
+ vec4 hsv, hsv2;
+ rgb_to_hsv(outcol, hsv);
+
+ if (hsv.y != 0.0) {
+ rgb_to_hsv(col2, hsv2);
+
+ hsv.y = facm * hsv.y + fac * hsv2.y;
+ hsv_to_rgb(hsv, outcol);
+ }
+}
+
+void mix_val(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ float facm = 1.0 - fac;
+
+ vec4 hsv, hsv2;
+ rgb_to_hsv(col1, hsv);
+ rgb_to_hsv(col2, hsv2);
+
+ hsv.z = facm * hsv.z + fac * hsv2.z;
+ hsv_to_rgb(hsv, outcol);
+}
+
+void mix_color(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ float facm = 1.0 - fac;
+
+ outcol = col1;
+
+ vec4 hsv, hsv2, tmp;
+ rgb_to_hsv(col2, hsv2);
+
+ if (hsv2.y != 0.0) {
+ rgb_to_hsv(outcol, hsv);
+ hsv.x = hsv2.x;
+ hsv.y = hsv2.y;
+ hsv_to_rgb(hsv, tmp);
+
+ outcol = mix(outcol, tmp, fac);
+ outcol.a = col1.a;
+ }
+}
+
+void mix_soft(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+ float facm = 1.0 - fac;
+
+ vec4 one = vec4(1.0);
+ vec4 scr = one - (one - col2) * (one - col1);
+ outcol = facm * col1 + fac * ((one - col1) * col2 * col1 + col1 * scr);
+}
+
+void mix_linear(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
+ fac = clamp(fac, 0.0, 1.0);
+
+ outcol = col1 + fac * (2.0 * (col2 - vec4(0.5)));
+}
+
+void clamp_color(vec3 vec, vec3 min, vec3 max, out vec3 out_vec)
+{
+ out_vec = clamp(vec, min, max);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl
new file mode 100644
index 00000000000..c303d21d7c1
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_mix_shader.glsl
@@ -0,0 +1,4 @@
+void node_mix_shader(float fac, Closure shader1, Closure shader2, out Closure shader)
+{
+ shader = closure_mix(shader1, shader2, fac);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl
new file mode 100644
index 00000000000..c184c61c269
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl
@@ -0,0 +1,294 @@
+/* Bilinear Interpolation:
+ *
+ * v2 v3
+ * @ + + + + @ y
+ * + + ^
+ * + + |
+ * + + |
+ * @ + + + + @ @------> x
+ * v0 v1
+ *
+ */
+float bi_mix(float v0, float v1, float v2, float v3, float x, float y)
+{
+ float x1 = 1.0 - x;
+ return (1.0 - y) * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x);
+}
+
+/* Trilinear Interpolation:
+ *
+ * v6 v7
+ * @ + + + + + + @
+ * +\ +\
+ * + \ + \
+ * + \ + \
+ * + \ v4 + \ v5
+ * + @ + + + +++ + @ z
+ * + + + + y ^
+ * v2 @ + +++ + + + @ v3 + \ |
+ * \ + \ + \ |
+ * \ + \ + \|
+ * \ + \ + +---------> x
+ * \+ \+
+ * @ + + + + + + @
+ * v0 v1
+ */
+float tri_mix(float v0,
+ float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6,
+ float v7,
+ float x,
+ float y,
+ float z)
+{
+ float x1 = 1.0 - x;
+ float y1 = 1.0 - y;
+ float z1 = 1.0 - z;
+ return z1 * (y1 * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x)) +
+ z * (y1 * (v4 * x1 + v5 * x) + y * (v6 * x1 + v7 * x));
+}
+
+float quad_mix(float v0,
+ float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6,
+ float v7,
+ float v8,
+ float v9,
+ float v10,
+ float v11,
+ float v12,
+ float v13,
+ float v14,
+ float v15,
+ float x,
+ float y,
+ float z,
+ float w)
+{
+ return mix(tri_mix(v0, v1, v2, v3, v4, v5, v6, v7, x, y, z),
+ tri_mix(v8, v9, v10, v11, v12, v13, v14, v15, x, y, z),
+ w);
+}
+
+float fade(float t)
+{
+ return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
+}
+
+float negate_if(float value, uint condition)
+{
+ return (condition != 0u) ? -value : value;
+}
+
+float noise_grad(uint hash, float x)
+{
+ uint h = hash & 15u;
+ float g = 1u + (h & 7u);
+ return negate_if(g, h & 8u) * x;
+}
+
+float noise_grad(uint hash, float x, float y)
+{
+ uint h = hash & 7u;
+ float u = h < 4u ? x : y;
+ float v = 2.0 * (h < 4u ? y : x);
+ return negate_if(u, h & 1u) + negate_if(v, h & 2u);
+}
+
+float noise_grad(uint hash, float x, float y, float z)
+{
+ uint h = hash & 15u;
+ float u = h < 8u ? x : y;
+ float vt = ((h == 12u) || (h == 14u)) ? x : z;
+ float v = h < 4u ? y : vt;
+ return negate_if(u, h & 1u) + negate_if(v, h & 2u);
+}
+
+float noise_grad(uint hash, float x, float y, float z, float w)
+{
+ uint h = hash & 31u;
+ float u = h < 24u ? x : y;
+ float v = h < 16u ? y : z;
+ float s = h < 8u ? z : w;
+ return negate_if(u, h & 1u) + negate_if(v, h & 2u) + negate_if(s, h & 4u);
+}
+
+float noise_perlin(float x)
+{
+ int X;
+ float fx = floorfrac(x, X);
+ float u = fade(fx);
+
+ float r = mix(noise_grad(hash_int(X), fx), noise_grad(hash_int(X + 1), fx - 1.0), u);
+
+ return r;
+}
+
+float noise_perlin(vec2 vec)
+{
+ int X;
+ int Y;
+
+ float fx = floorfrac(vec.x, X);
+ float fy = floorfrac(vec.y, Y);
+
+ float u = fade(fx);
+ float v = fade(fy);
+
+ float r = bi_mix(noise_grad(hash_int2(X, Y), fx, fy),
+ noise_grad(hash_int2(X + 1, Y), fx - 1.0, fy),
+ noise_grad(hash_int2(X, Y + 1), fx, fy - 1.0),
+ noise_grad(hash_int2(X + 1, Y + 1), fx - 1.0, fy - 1.0),
+ u,
+ v);
+
+ return r;
+}
+
+float noise_perlin(vec3 vec)
+{
+ int X;
+ int Y;
+ int Z;
+
+ float fx = floorfrac(vec.x, X);
+ float fy = floorfrac(vec.y, Y);
+ float fz = floorfrac(vec.z, Z);
+
+ float u = fade(fx);
+ float v = fade(fy);
+ float w = fade(fz);
+
+ float r = tri_mix(noise_grad(hash_int3(X, Y, Z), fx, fy, fz),
+ noise_grad(hash_int3(X + 1, Y, Z), fx - 1, fy, fz),
+ noise_grad(hash_int3(X, Y + 1, Z), fx, fy - 1, fz),
+ noise_grad(hash_int3(X + 1, Y + 1, Z), fx - 1, fy - 1, fz),
+ noise_grad(hash_int3(X, Y, Z + 1), fx, fy, fz - 1),
+ noise_grad(hash_int3(X + 1, Y, Z + 1), fx - 1, fy, fz - 1),
+ noise_grad(hash_int3(X, Y + 1, Z + 1), fx, fy - 1, fz - 1),
+ noise_grad(hash_int3(X + 1, Y + 1, Z + 1), fx - 1, fy - 1, fz - 1),
+ u,
+ v,
+ w);
+
+ return r;
+}
+
+float noise_perlin(vec4 vec)
+{
+ int X;
+ int Y;
+ int Z;
+ int W;
+
+ float fx = floorfrac(vec.x, X);
+ float fy = floorfrac(vec.y, Y);
+ float fz = floorfrac(vec.z, Z);
+ float fw = floorfrac(vec.w, W);
+
+ float u = fade(fx);
+ float v = fade(fy);
+ float t = fade(fz);
+ float s = fade(fw);
+
+ float r = quad_mix(
+ noise_grad(hash_int4(X, Y, Z, W), fx, fy, fz, fw),
+ noise_grad(hash_int4(X + 1, Y, Z, W), fx - 1.0, fy, fz, fw),
+ noise_grad(hash_int4(X, Y + 1, Z, W), fx, fy - 1.0, fz, fw),
+ noise_grad(hash_int4(X + 1, Y + 1, Z, W), fx - 1.0, fy - 1.0, fz, fw),
+ noise_grad(hash_int4(X, Y, Z + 1, W), fx, fy, fz - 1.0, fw),
+ noise_grad(hash_int4(X + 1, Y, Z + 1, W), fx - 1.0, fy, fz - 1.0, fw),
+ noise_grad(hash_int4(X, Y + 1, Z + 1, W), fx, fy - 1.0, fz - 1.0, fw),
+ noise_grad(hash_int4(X + 1, Y + 1, Z + 1, W), fx - 1.0, fy - 1.0, fz - 1.0, fw),
+ noise_grad(hash_int4(X, Y, Z, W + 1), fx, fy, fz, fw - 1.0),
+ noise_grad(hash_int4(X + 1, Y, Z, W + 1), fx - 1.0, fy, fz, fw - 1.0),
+ noise_grad(hash_int4(X, Y + 1, Z, W + 1), fx, fy - 1.0, fz, fw - 1.0),
+ noise_grad(hash_int4(X + 1, Y + 1, Z, W + 1), fx - 1.0, fy - 1.0, fz, fw - 1.0),
+ noise_grad(hash_int4(X, Y, Z + 1, W + 1), fx, fy, fz - 1.0, fw - 1.0),
+ noise_grad(hash_int4(X + 1, Y, Z + 1, W + 1), fx - 1.0, fy, fz - 1.0, fw - 1.0),
+ noise_grad(hash_int4(X, Y + 1, Z + 1, W + 1), fx, fy - 1.0, fz - 1.0, fw - 1.0),
+ noise_grad(hash_int4(X + 1, Y + 1, Z + 1, W + 1), fx - 1.0, fy - 1.0, fz - 1.0, fw - 1.0),
+ u,
+ v,
+ t,
+ s);
+
+ return r;
+}
+
+/* Remap the output of noise to a predictable range [-1, 1].
+ * The scale values were computed experimentally by the OSL developers.
+ */
+float noise_scale1(float result)
+{
+ return 0.2500 * result;
+}
+
+float noise_scale2(float result)
+{
+ return 0.6616 * result;
+}
+
+float noise_scale3(float result)
+{
+ return 0.9820 * result;
+}
+
+float noise_scale4(float result)
+{
+ return 0.8344 * result;
+}
+
+/* Safe Signed And Unsigned Noise */
+
+float snoise(float p)
+{
+ float r = noise_perlin(p);
+ return (isinf(r)) ? 0.0 : noise_scale1(r);
+}
+
+float noise(float p)
+{
+ return 0.5 * snoise(p) + 0.5;
+}
+
+float snoise(vec2 p)
+{
+ float r = noise_perlin(p);
+ return (isinf(r)) ? 0.0 : noise_scale2(r);
+}
+
+float noise(vec2 p)
+{
+ return 0.5 * snoise(p) + 0.5;
+}
+
+float snoise(vec3 p)
+{
+ float r = noise_perlin(p);
+ return (isinf(r)) ? 0.0 : noise_scale3(r);
+}
+
+float noise(vec3 p)
+{
+ return 0.5 * snoise(p) + 0.5;
+}
+
+float snoise(vec4 p)
+{
+ float r = noise_perlin(p);
+ return (isinf(r)) ? 0.0 : noise_scale4(r);
+}
+
+float noise(vec4 p)
+{
+ return 0.5 * snoise(p) + 0.5;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_normal.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_normal.glsl
new file mode 100644
index 00000000000..4f6e68909ad
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_normal.glsl
@@ -0,0 +1,5 @@
+void normal_new_shading(vec3 nor, vec3 dir, out vec3 outnor, out float outdot)
+{
+ outnor = dir;
+ outdot = dot(normalize(nor), dir);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl
new file mode 100644
index 00000000000..6930e0c5dad
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl
@@ -0,0 +1,22 @@
+void node_normal_map(vec4 info, vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnormal)
+{
+ if (all(equal(tangent, vec4(0.0, 0.0, 0.0, 1.0)))) {
+ outnormal = normal;
+ return;
+ }
+ tangent *= (gl_FrontFacing ? 1.0 : -1.0);
+ vec3 B = tangent.w * cross(normal, tangent.xyz) * info.w;
+
+ outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * normal;
+ outnormal = normalize(outnormal);
+}
+
+void color_to_normal_new_shading(vec3 color, out vec3 normal)
+{
+ normal = vec3(2.0) * color - vec3(1.0);
+}
+
+void color_to_blender_normal_new_shading(vec3 color, out vec3 normal)
+{
+ normal = vec3(2.0, -2.0, -2.0) * color - vec3(1.0);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl
new file mode 100644
index 00000000000..ff77b0beea2
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl
@@ -0,0 +1,16 @@
+void node_object_info(mat4 obmat,
+ vec4 obcolor,
+ vec4 info,
+ float mat_index,
+ out vec3 location,
+ out vec4 color,
+ out float object_index,
+ out float material_index,
+ out float random)
+{
+ location = obmat[3].xyz;
+ color = obcolor;
+ object_index = info.x;
+ material_index = mat_index;
+ random = info.z;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl
new file mode 100644
index 00000000000..62f76d46088
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl
@@ -0,0 +1,8 @@
+void node_output_material(Closure surface, Closure volume, vec3 displacement, out Closure result)
+{
+#ifdef VOLUMETRICS
+ result = volume;
+#else
+ result = surface;
+#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl
new file mode 100644
index 00000000000..ba391df185e
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl
@@ -0,0 +1,11 @@
+uniform float backgroundAlpha;
+
+void node_output_world(Closure surface, Closure volume, out Closure result)
+{
+#ifndef VOLUMETRICS
+ result.radiance = surface.radiance * backgroundAlpha;
+ result.transmittance = vec3(1.0 - backgroundAlpha);
+#else
+ result = volume;
+#endif /* VOLUMETRICS */
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl
new file mode 100644
index 00000000000..bdd60c20a81
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl
@@ -0,0 +1,23 @@
+void particle_info(vec4 sprops,
+ vec4 loc,
+ vec3 vel,
+ vec3 avel,
+ out float index,
+ out float random,
+ out float age,
+ out float life_time,
+ out vec3 location,
+ out float size,
+ out vec3 velocity,
+ out vec3 angular_velocity)
+{
+ index = sprops.x;
+ random = loc.w;
+ age = sprops.y;
+ life_time = sprops.z;
+ size = sprops.w;
+
+ location = loc.xyz;
+ velocity = vel;
+ angular_velocity = avel;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
new file mode 100644
index 00000000000..140213a9ed9
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
@@ -0,0 +1,418 @@
+#ifndef VOLUMETRICS
+vec3 tint_from_color(vec3 color)
+{
+ float lum = dot(color, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
+ return (lum > 0) ? color / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */
+}
+
+void convert_metallic_to_specular_tinted(vec3 basecol,
+ vec3 basecol_tint,
+ float metallic,
+ float specular_fac,
+ float specular_tint,
+ out vec3 diffuse,
+ out vec3 f0)
+{
+ vec3 tmp_col = mix(vec3(1.0), basecol_tint, specular_tint);
+ f0 = mix((0.08 * specular_fac) * tmp_col, basecol, metallic);
+ diffuse = basecol * (1.0 - metallic);
+}
+
+vec3 principled_sheen(float NV, vec3 basecol_tint, float sheen_tint)
+{
+ float f = 1.0 - NV;
+ /* Temporary fix for T59784. Normal map seems to contain NaNs for tangent space normal maps,
+ * therefore we need to clamp value. */
+ f = clamp(f, 0.0, 1.0);
+ /* Empirical approximation (manual curve fitting). Can be refined. */
+ float sheen = f * f * f * 0.077 + f * 0.01 + 0.00026;
+ return sheen * mix(vec3(1.0), basecol_tint, sheen_tint);
+}
+
+void node_bsdf_principled(vec4 base_color,
+ float subsurface,
+ vec3 subsurface_radius,
+ vec4 subsurface_color,
+ float metallic,
+ float specular,
+ float specular_tint,
+ float roughness,
+ float anisotropic,
+ float anisotropic_rotation,
+ float sheen,
+ float sheen_tint,
+ float clearcoat,
+ float clearcoat_roughness,
+ float ior,
+ float transmission,
+ float transmission_roughness,
+ vec4 emission,
+ float alpha,
+ vec3 N,
+ vec3 CN,
+ vec3 T,
+ vec3 I,
+ float ssr_id,
+ float sss_id,
+ vec3 sss_scale,
+ out Closure result)
+{
+ N = normalize(N);
+ ior = max(ior, 1e-5);
+ metallic = saturate(metallic);
+ transmission = saturate(transmission);
+ float dielectric = 1.0 - metallic;
+ transmission *= dielectric;
+ sheen *= dielectric;
+ subsurface_color *= dielectric;
+
+ vec3 diffuse, f0, out_diff, out_spec, out_refr, ssr_spec;
+ vec3 ctint = tint_from_color(base_color.rgb);
+ convert_metallic_to_specular_tinted(
+ base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
+
+ float NV = dot(N, cameraVec);
+ vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
+
+ /* Far from being accurate, but 2 glossy evaluation is too expensive.
+ * Most noticeable difference is at grazing angles since the bsdf lut
+ * f0 color interpolation is done on top of this interpolation. */
+ vec3 f0_glass = mix(vec3(1.0), base_color.rgb, specular_tint);
+ float fresnel = F_eta(ior, NV);
+ vec3 spec_col = F_color_blend(ior, fresnel, f0_glass) * fresnel;
+ f0 = mix(f0, spec_col, transmission);
+
+ vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic);
+
+ vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
+
+ float sss_scalef = avg(sss_scale) * subsurface;
+ eevee_closure_principled(N,
+ mixed_ss_base_color,
+ f0,
+ f90,
+ int(ssr_id),
+ roughness,
+ CN,
+ clearcoat * 0.25,
+ clearcoat_roughness,
+ 1.0,
+ sss_scalef,
+ ior,
+ true,
+ out_diff,
+ out_spec,
+ out_refr,
+ ssr_spec);
+
+ vec3 refr_color = base_color.rgb;
+ refr_color *= (refractionDepth > 0.0) ? refr_color :
+ vec3(1.0); /* Simulate 2 transmission event */
+ out_refr *= refr_color * (1.0 - fresnel) * transmission;
+
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_spec + out_refr;
+ result.radiance += out_diff * out_sheen; /* Coarse approx. */
+
+ closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
+
+ mixed_ss_base_color *= alpha * (1.0 - transmission);
+ closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result);
+
+ result.radiance += emission.rgb;
+ result.radiance *= alpha;
+ result.transmittance = vec3(1.0 - alpha);
+}
+
+void node_bsdf_principled_dielectric(vec4 base_color,
+ float subsurface,
+ vec3 subsurface_radius,
+ vec4 subsurface_color,
+ float metallic,
+ float specular,
+ float specular_tint,
+ float roughness,
+ float anisotropic,
+ float anisotropic_rotation,
+ float sheen,
+ float sheen_tint,
+ float clearcoat,
+ float clearcoat_roughness,
+ float ior,
+ float transmission,
+ float transmission_roughness,
+ vec4 emission,
+ float alpha,
+ vec3 N,
+ vec3 CN,
+ vec3 T,
+ vec3 I,
+ float ssr_id,
+ float sss_id,
+ vec3 sss_scale,
+ out Closure result)
+{
+ N = normalize(N);
+ metallic = saturate(metallic);
+ float dielectric = 1.0 - metallic;
+
+ vec3 diffuse, f0, out_diff, out_spec, ssr_spec;
+ vec3 ctint = tint_from_color(base_color.rgb);
+ convert_metallic_to_specular_tinted(
+ base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
+
+ float NV = dot(N, cameraVec);
+ vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
+
+ eevee_closure_default(
+ N, diffuse, f0, vec3(1.0), int(ssr_id), roughness, 1.0, true, out_diff, out_spec, ssr_spec);
+
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_spec + out_diff * (diffuse + out_sheen);
+ closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
+ result.radiance += emission.rgb;
+ result.radiance *= alpha;
+ result.transmittance = vec3(1.0 - alpha);
+}
+
+void node_bsdf_principled_metallic(vec4 base_color,
+ float subsurface,
+ vec3 subsurface_radius,
+ vec4 subsurface_color,
+ float metallic,
+ float specular,
+ float specular_tint,
+ float roughness,
+ float anisotropic,
+ float anisotropic_rotation,
+ float sheen,
+ float sheen_tint,
+ float clearcoat,
+ float clearcoat_roughness,
+ float ior,
+ float transmission,
+ float transmission_roughness,
+ vec4 emission,
+ float alpha,
+ vec3 N,
+ vec3 CN,
+ vec3 T,
+ vec3 I,
+ float ssr_id,
+ float sss_id,
+ vec3 sss_scale,
+ out Closure result)
+{
+ N = normalize(N);
+ vec3 out_spec, ssr_spec;
+
+ vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
+
+ eevee_closure_glossy(
+ N, base_color.rgb, f90, int(ssr_id), roughness, 1.0, true, out_spec, ssr_spec);
+
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_spec;
+ closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
+ result.radiance += emission.rgb;
+ result.radiance *= alpha;
+ result.transmittance = vec3(1.0 - alpha);
+}
+
+void node_bsdf_principled_clearcoat(vec4 base_color,
+ float subsurface,
+ vec3 subsurface_radius,
+ vec4 subsurface_color,
+ float metallic,
+ float specular,
+ float specular_tint,
+ float roughness,
+ float anisotropic,
+ float anisotropic_rotation,
+ float sheen,
+ float sheen_tint,
+ float clearcoat,
+ float clearcoat_roughness,
+ float ior,
+ float transmission,
+ float transmission_roughness,
+ vec4 emission,
+ float alpha,
+ vec3 N,
+ vec3 CN,
+ vec3 T,
+ vec3 I,
+ float ssr_id,
+ float sss_id,
+ vec3 sss_scale,
+ out Closure result)
+{
+ vec3 out_spec, ssr_spec;
+ N = normalize(N);
+
+ vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
+
+ eevee_closure_clearcoat(N,
+ base_color.rgb,
+ f90,
+ int(ssr_id),
+ roughness,
+ CN,
+ clearcoat * 0.25,
+ clearcoat_roughness,
+ 1.0,
+ true,
+ out_spec,
+ ssr_spec);
+
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_spec;
+ closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
+ result.radiance += emission.rgb;
+ result.radiance *= alpha;
+ result.transmittance = vec3(1.0 - alpha);
+}
+
+void node_bsdf_principled_subsurface(vec4 base_color,
+ float subsurface,
+ vec3 subsurface_radius,
+ vec4 subsurface_color,
+ float metallic,
+ float specular,
+ float specular_tint,
+ float roughness,
+ float anisotropic,
+ float anisotropic_rotation,
+ float sheen,
+ float sheen_tint,
+ float clearcoat,
+ float clearcoat_roughness,
+ float ior,
+ float transmission,
+ float transmission_roughness,
+ vec4 emission,
+ float alpha,
+ vec3 N,
+ vec3 CN,
+ vec3 T,
+ vec3 I,
+ float ssr_id,
+ float sss_id,
+ vec3 sss_scale,
+ out Closure result)
+{
+ metallic = saturate(metallic);
+ N = normalize(N);
+
+ vec3 diffuse, f0, out_diff, out_spec, ssr_spec;
+ vec3 ctint = tint_from_color(base_color.rgb);
+ convert_metallic_to_specular_tinted(
+ base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
+
+ subsurface_color = subsurface_color * (1.0 - metallic);
+ vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
+ float sss_scalef = avg(sss_scale) * subsurface;
+
+ float NV = dot(N, cameraVec);
+ vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
+
+ vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
+
+ eevee_closure_skin(N,
+ mixed_ss_base_color,
+ f0,
+ f90,
+ int(ssr_id),
+ roughness,
+ 1.0,
+ sss_scalef,
+ true,
+ out_diff,
+ out_spec,
+ ssr_spec);
+
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_spec;
+ closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
+
+ mixed_ss_base_color *= alpha * (1.0 - transmission);
+ closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result);
+
+ result.radiance += out_diff * out_sheen;
+ result.radiance += emission.rgb;
+ result.radiance *= alpha;
+ result.transmittance = vec3(1.0 - alpha);
+}
+
+void node_bsdf_principled_glass(vec4 base_color,
+ float subsurface,
+ vec3 subsurface_radius,
+ vec4 subsurface_color,
+ float metallic,
+ float specular,
+ float specular_tint,
+ float roughness,
+ float anisotropic,
+ float anisotropic_rotation,
+ float sheen,
+ float sheen_tint,
+ float clearcoat,
+ float clearcoat_roughness,
+ float ior,
+ float transmission,
+ float transmission_roughness,
+ vec4 emission,
+ float alpha,
+ vec3 N,
+ vec3 CN,
+ vec3 T,
+ vec3 I,
+ float ssr_id,
+ float sss_id,
+ vec3 sss_scale,
+ out Closure result)
+{
+ ior = max(ior, 1e-5);
+ N = normalize(N);
+
+ vec3 f0, out_spec, out_refr, ssr_spec;
+ f0 = mix(vec3(1.0), base_color.rgb, specular_tint);
+
+ eevee_closure_glass(N,
+ vec3(1.0),
+ vec3(1.0),
+ int(ssr_id),
+ roughness,
+ 1.0,
+ ior,
+ true,
+ out_spec,
+ out_refr,
+ ssr_spec);
+
+ vec3 refr_color = base_color.rgb;
+ refr_color *= (refractionDepth > 0.0) ? refr_color :
+ vec3(1.0); /* Simulate 2 transmission events */
+ out_refr *= refr_color;
+
+ float fresnel = F_eta(ior, dot(N, cameraVec));
+ vec3 spec_col = F_color_blend(ior, fresnel, f0);
+ out_spec *= spec_col;
+ ssr_spec *= spec_col * fresnel;
+
+ result = CLOSURE_DEFAULT;
+ result.radiance = mix(out_refr, out_spec, fresnel);
+ closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
+ result.radiance += emission.rgb;
+ result.radiance *= alpha;
+ result.transmittance = vec3(1.0 - alpha);
+}
+#else
+/* Stub principled because it is not compatible with volumetrics. */
+# define node_bsdf_principled
+# define node_bsdf_principled_dielectric
+# define node_bsdf_principled_metallic
+# define node_bsdf_principled_clearcoat
+# define node_bsdf_principled_subsurface
+# define node_bsdf_principled_glass
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl
new file mode 100644
index 00000000000..906964e1539
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl
@@ -0,0 +1,16 @@
+#ifndef VOLUMETRICS
+void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Closure result)
+{
+ N = normalize(N);
+ vec3 out_refr;
+ color.rgb *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); /* Simulate 2 absorption event. */
+ eevee_closure_refraction(N, roughness, ior, true, out_refr);
+ vec3 vN = mat3(ViewMatrix) * N;
+ result = CLOSURE_DEFAULT;
+ result.ssr_normal = normal_encode(vN, viewCameraVec);
+ result.radiance = out_refr * color.rgb;
+}
+#else
+/* Stub refraction because it is not compatible with volumetrics. */
+# define node_bsdf_refraction
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_rgb_curves.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_rgb_curves.glsl
new file mode 100644
index 00000000000..054fdddf7c3
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_rgb_curves.glsl
@@ -0,0 +1,73 @@
+/* ext is vec4(in_x, in_dy, out_x, out_dy). */
+float curve_extrapolate(float x, float y, vec4 ext)
+{
+ if (x < 0.0) {
+ return y + x * ext.y;
+ }
+ else if (x > 1.0) {
+ return y + (x - 1.0) * ext.w;
+ }
+ else {
+ return y;
+ }
+}
+
+#define RANGE_RESCALE(x, min, range) ((x - min) * range)
+
+void curves_rgb(float fac,
+ vec4 col,
+ sampler1DArray curvemap,
+ float layer,
+ vec4 range,
+ vec4 ext_r,
+ vec4 ext_g,
+ vec4 ext_b,
+ vec4 ext_a,
+ out vec4 outcol)
+{
+ vec4 co = vec4(RANGE_RESCALE(col.rgb, ext_a.x, range.a), layer);
+ vec3 samp;
+ samp.r = texture(curvemap, co.xw).a;
+ samp.g = texture(curvemap, co.yw).a;
+ samp.b = texture(curvemap, co.zw).a;
+
+ samp.r = curve_extrapolate(co.x, samp.r, ext_a);
+ samp.g = curve_extrapolate(co.y, samp.g, ext_a);
+ samp.b = curve_extrapolate(co.z, samp.b, ext_a);
+
+ vec3 rgb_min = vec3(ext_r.x, ext_g.x, ext_b.x);
+ co.xyz = RANGE_RESCALE(samp.rgb, rgb_min, range.rgb);
+
+ samp.r = texture(curvemap, co.xw).r;
+ samp.g = texture(curvemap, co.yw).g;
+ samp.b = texture(curvemap, co.zw).b;
+
+ outcol.r = curve_extrapolate(co.x, samp.r, ext_r);
+ outcol.g = curve_extrapolate(co.y, samp.g, ext_g);
+ outcol.b = curve_extrapolate(co.z, samp.b, ext_b);
+ outcol.a = col.a;
+
+ outcol = mix(col, outcol, fac);
+}
+
+void curves_rgb_opti(float fac,
+ vec4 col,
+ sampler1DArray curvemap,
+ float layer,
+ vec4 range,
+ vec4 ext_a,
+ out vec4 outcol)
+{
+ vec4 co = vec4(RANGE_RESCALE(col.rgb, ext_a.x, range.a), layer);
+ vec3 samp;
+ samp.r = texture(curvemap, co.xw).a;
+ samp.g = texture(curvemap, co.yw).a;
+ samp.b = texture(curvemap, co.zw).a;
+
+ outcol.r = curve_extrapolate(co.x, samp.r, ext_a);
+ outcol.g = curve_extrapolate(co.y, samp.g, ext_a);
+ outcol.b = curve_extrapolate(co.z, samp.b, ext_a);
+ outcol.a = col.a;
+
+ outcol = mix(col, outcol, fac);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_rgb_to_bw.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_rgb_to_bw.glsl
new file mode 100644
index 00000000000..ceca02a2356
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_rgb_to_bw.glsl
@@ -0,0 +1,5 @@
+void rgbtobw(vec4 color, out float outval)
+{
+ vec3 factors = vec3(0.2126, 0.7152, 0.0722);
+ outval = dot(color.rgb, factors);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl
new file mode 100644
index 00000000000..fb64e424c6c
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl
@@ -0,0 +1,9 @@
+void separate_hsv(vec4 col, out float h, out float s, out float v)
+{
+ vec4 hsv;
+
+ rgb_to_hsv(col, hsv);
+ h = hsv[0];
+ s = hsv[1];
+ v = hsv[2];
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_separate_rgb.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_separate_rgb.glsl
new file mode 100644
index 00000000000..4232b4c001e
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_separate_rgb.glsl
@@ -0,0 +1,6 @@
+void separate_rgb(vec4 col, out float r, out float g, out float b)
+{
+ r = col.r;
+ g = col.g;
+ b = col.b;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_separate_xyz.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_separate_xyz.glsl
new file mode 100644
index 00000000000..fac29ccc135
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_separate_xyz.glsl
@@ -0,0 +1,6 @@
+void separate_xyz(vec3 vec, out float x, out float y, out float z)
+{
+ x = vec.r;
+ y = vec.g;
+ z = vec.b;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_set.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_set.glsl
new file mode 100644
index 00000000000..dc2ecb05351
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_set.glsl
@@ -0,0 +1,44 @@
+void set_value(float val, out float outval)
+{
+ outval = val;
+}
+
+void set_rgb(vec3 col, out vec3 outcol)
+{
+ outcol = col;
+}
+
+void set_rgba(vec4 col, out vec4 outcol)
+{
+ outcol = col;
+}
+
+void set_value_zero(out float outval)
+{
+ outval = 0.0;
+}
+
+void set_value_one(out float outval)
+{
+ outval = 1.0;
+}
+
+void set_rgb_zero(out vec3 outval)
+{
+ outval = vec3(0.0);
+}
+
+void set_rgb_one(out vec3 outval)
+{
+ outval = vec3(1.0);
+}
+
+void set_rgba_zero(out vec4 outval)
+{
+ outval = vec4(0.0);
+}
+
+void set_rgba_one(out vec4 outval)
+{
+ outval = vec4(1.0);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl
new file mode 100644
index 00000000000..4f6df238789
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl
@@ -0,0 +1,21 @@
+#ifndef VOLUMETRICS
+void node_shader_to_rgba(Closure cl, out vec4 outcol, out float outalpha)
+{
+ vec4 spec_accum = vec4(0.0);
+ if (ssrToggle && FLAG_TEST(cl.flag, CLOSURE_SSR_FLAG)) {
+ vec3 V = cameraVec;
+ vec3 vN = normal_decode(cl.ssr_normal, viewCameraVec);
+ vec3 N = transform_direction(ViewMatrixInverse, vN);
+ float roughness = cl.ssr_data.a;
+ float roughnessSquared = max(1e-3, roughness * roughness);
+ fallback_cubemap(N, V, worldPosition, viewPosition, roughness, roughnessSquared, spec_accum);
+ }
+
+ outalpha = avg(cl.transmittance);
+ outcol = vec4((spec_accum.rgb * cl.ssr_data.rgb) + cl.radiance, 1.0);
+
+# ifdef USE_SSS
+ outcol.rgb += cl.sss_irradiance.rgb * cl.sss_albedo;
+# endif
+}
+#endif /* VOLUMETRICS */
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_squeeze.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_squeeze.glsl
new file mode 100644
index 00000000000..b73bdebf7f6
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_squeeze.glsl
@@ -0,0 +1,4 @@
+void squeeze(float val, float width, float center, out float outval)
+{
+ outval = 1.0 / (1.0 + pow(2.71828183, -((val - center) * width)));
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl
new file mode 100644
index 00000000000..241228c0d4c
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl
@@ -0,0 +1,27 @@
+#ifndef VOLUMETRICS
+void node_subsurface_scattering(vec4 color,
+ float scale,
+ vec3 radius,
+ float sharpen,
+ float texture_blur,
+ vec3 N,
+ float sss_id,
+ out Closure result)
+{
+ N = normalize(N);
+ vec3 out_diff;
+ vec3 vN = mat3(ViewMatrix) * N;
+ result = CLOSURE_DEFAULT;
+ closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
+
+ eevee_closure_subsurface(N, color.rgb, 1.0, scale, true, out_diff);
+
+ /* Not perfect for texture_blur not exactly equal to 0.0 or 1.0. */
+ vec3 sss_albedo = mix(color.rgb, vec3(1.0), texture_blur);
+ out_diff *= mix(vec3(1.0), color.rgb, texture_blur);
+ closure_load_sss_data(scale, out_diff, sss_albedo, int(sss_id), result);
+}
+#else
+/* Stub subsurface scattering because it is not compatible with volumetrics. */
+# define node_subsurface_scattering
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl
new file mode 100644
index 00000000000..ff2dbc7ead3
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl
@@ -0,0 +1,25 @@
+void tangent_orco_x(vec3 orco_in, out vec3 orco_out)
+{
+ orco_out = orco_in.xzy * vec3(0.0, -0.5, 0.5) + vec3(0.0, 0.25, -0.25);
+}
+
+void tangent_orco_y(vec3 orco_in, out vec3 orco_out)
+{
+ orco_out = orco_in.zyx * vec3(-0.5, 0.0, 0.5) + vec3(0.25, 0.0, -0.25);
+}
+
+void tangent_orco_z(vec3 orco_in, out vec3 orco_out)
+{
+ orco_out = orco_in.yxz * vec3(-0.5, 0.5, 0.0) + vec3(0.25, -0.25, 0.0);
+}
+
+void node_tangentmap(vec4 attr_tangent, out vec3 tangent)
+{
+ tangent = normalize(attr_tangent.xyz);
+}
+
+void node_tangent(vec3 N, vec3 orco, mat4 objmat, out vec3 T)
+{
+ T = (objmat * vec4(orco, 0.0)).xyz;
+ T = cross(N, normalize(cross(T, N)));
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl
new file mode 100644
index 00000000000..e252e5ba726
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl
@@ -0,0 +1,78 @@
+vec2 calc_brick_texture(vec3 p,
+ float mortar_size,
+ float mortar_smooth,
+ float bias,
+ float brick_width,
+ float row_height,
+ float offset_amount,
+ int offset_frequency,
+ float squash_amount,
+ int squash_frequency)
+{
+ int bricknum, rownum;
+ float offset = 0.0;
+ float x, y;
+
+ rownum = floor_to_int(p.y / row_height);
+
+ if (offset_frequency != 0 && squash_frequency != 0) {
+ brick_width *= (rownum % squash_frequency != 0) ? 1.0 : squash_amount; /* squash */
+ offset = (rownum % offset_frequency != 0) ? 0.0 : (brick_width * offset_amount); /* offset */
+ }
+
+ bricknum = floor_to_int((p.x + offset) / brick_width);
+
+ x = (p.x + offset) - brick_width * bricknum;
+ y = p.y - row_height * rownum;
+
+ float tint = clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0, 1.0);
+
+ float min_dist = min(min(x, y), min(brick_width - x, row_height - y));
+ if (min_dist >= mortar_size) {
+ return vec2(tint, 0.0);
+ }
+ else if (mortar_smooth == 0.0) {
+ return vec2(tint, 1.0);
+ }
+ else {
+ min_dist = 1.0 - min_dist / mortar_size;
+ return vec2(tint, smoothstep(0.0, mortar_smooth, min_dist));
+ }
+}
+
+void node_tex_brick(vec3 co,
+ vec4 color1,
+ vec4 color2,
+ vec4 mortar,
+ float scale,
+ float mortar_size,
+ float mortar_smooth,
+ float bias,
+ float brick_width,
+ float row_height,
+ float offset_amount,
+ float offset_frequency,
+ float squash_amount,
+ float squash_frequency,
+ out vec4 color,
+ out float fac)
+{
+ vec2 f2 = calc_brick_texture(co * scale,
+ mortar_size,
+ mortar_smooth,
+ bias,
+ brick_width,
+ row_height,
+ offset_amount,
+ int(offset_frequency),
+ squash_amount,
+ int(squash_frequency));
+ float tint = f2.x;
+ float f = f2.y;
+ if (f != 1.0) {
+ float facm = 1.0 - tint;
+ color1 = facm * color1 + tint * color2;
+ }
+ color = mix(color1, mortar, f);
+ fac = f;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_checker.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_checker.glsl
new file mode 100644
index 00000000000..f534f3bddf3
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_checker.glsl
@@ -0,0 +1,17 @@
+void node_tex_checker(
+ vec3 co, vec4 color1, vec4 color2, float scale, out vec4 color, out float fac)
+{
+ vec3 p = co * scale;
+
+ /* Prevent precision issues on unit coordinates. */
+ p = (p + 0.000001) * 0.999999;
+
+ int xi = int(abs(floor(p.x)));
+ int yi = int(abs(floor(p.y)));
+ int zi = int(abs(floor(p.z)));
+
+ bool check = ((mod(xi, 2) == mod(yi, 2)) == bool(mod(zi, 2)));
+
+ color = check ? color1 : color2;
+ fac = check ? 1.0 : 0.0;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl
new file mode 100644
index 00000000000..9bd36f8a757
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl
@@ -0,0 +1,44 @@
+void node_tex_environment_texco(vec3 viewvec, out vec3 worldvec)
+{
+#ifdef MESH_SHADER
+ worldvec = worldPosition;
+#else
+ vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(viewvec, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
+ vec4 co_homogenous = (ProjectionMatrixInverse * v);
+
+ vec3 co = co_homogenous.xyz / co_homogenous.w;
+# if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
+ worldvec = mat3(ViewMatrixInverse) * co;
+# else
+ worldvec = mat3(ModelMatrixInverse) * (mat3(ViewMatrixInverse) * co);
+# endif
+#endif
+}
+
+void node_tex_environment_equirectangular(vec3 co, float clamp_size, sampler2D ima, out vec3 uv)
+{
+ vec3 nco = normalize(co);
+ uv.x = -atan(nco.y, nco.x) / (2.0 * M_PI) + 0.5;
+ uv.y = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5;
+
+ /* Fix pole bleeding */
+ float half_height = clamp_size / float(textureSize(ima, 0).y);
+ uv.y = clamp(uv.y, half_height, 1.0 - half_height);
+ uv.z = 0.0;
+}
+
+void node_tex_environment_mirror_ball(vec3 co, out vec3 uv)
+{
+ vec3 nco = normalize(co);
+ nco.y -= 1.0;
+
+ float div = 2.0 * sqrt(max(-0.5 * nco.y, 0.0));
+ nco /= max(1e-8, div);
+
+ uv = 0.5 * nco.xzz + 0.5;
+}
+
+void node_tex_environment_empty(vec3 co, out vec4 color)
+{
+ color = vec4(1.0, 0.0, 1.0, 1.0);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_gradient.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_gradient.glsl
new file mode 100644
index 00000000000..f2f7e615267
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_gradient.glsl
@@ -0,0 +1,47 @@
+float calc_gradient(vec3 p, int gradient_type)
+{
+ float x, y, z;
+ x = p.x;
+ y = p.y;
+ z = p.z;
+ if (gradient_type == 0) { /* linear */
+ return x;
+ }
+ else if (gradient_type == 1) { /* quadratic */
+ float r = max(x, 0.0);
+ return r * r;
+ }
+ else if (gradient_type == 2) { /* easing */
+ float r = min(max(x, 0.0), 1.0);
+ float t = r * r;
+ return (3.0 * t - 2.0 * t * r);
+ }
+ else if (gradient_type == 3) { /* diagonal */
+ return (x + y) * 0.5;
+ }
+ else if (gradient_type == 4) { /* radial */
+ return atan(y, x) / (M_PI * 2) + 0.5;
+ }
+ else {
+ /* Bias a little bit for the case where p is a unit length vector,
+ * to get exactly zero instead of a small random value depending
+ * on float precision. */
+ float r = max(0.999999 - sqrt(x * x + y * y + z * z), 0.0);
+ if (gradient_type == 5) { /* quadratic sphere */
+ return r * r;
+ }
+ else if (gradient_type == 6) { /* sphere */
+ return r;
+ }
+ }
+ return 0.0;
+}
+
+void node_tex_gradient(vec3 co, float gradient_type, out vec4 color, out float fac)
+{
+ float f = calc_gradient(co, int(gradient_type));
+ f = clamp(f, 0.0, 1.0);
+
+ color = vec4(f, f, f, 1.0);
+ fac = f;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl
new file mode 100644
index 00000000000..c234e064d36
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl
@@ -0,0 +1,355 @@
+void point_texco_remap_square(vec3 vin, out vec3 vout)
+{
+ vout = vin * 2.0 - 1.0;
+}
+
+void point_texco_clamp(vec3 vin, sampler2D ima, out vec3 vout)
+{
+ vec2 half_texel_size = 0.5 / vec2(textureSize(ima, 0).xy);
+ vout = clamp(vin, half_texel_size.xyy, 1.0 - half_texel_size.xyy);
+}
+
+void point_map_to_sphere(vec3 vin, out vec3 vout)
+{
+ float len = length(vin);
+ float v, u;
+ if (len > 0.0) {
+ if (vin.x == 0.0 && vin.y == 0.0) {
+ u = 0.0;
+ }
+ else {
+ u = (1.0 - atan(vin.x, vin.y) / M_PI) / 2.0;
+ }
+
+ v = 1.0 - acos(vin.z / len) / M_PI;
+ }
+ else {
+ v = u = 0.0;
+ }
+
+ vout = vec3(u, v, 0.0);
+}
+
+void point_map_to_tube(vec3 vin, out vec3 vout)
+{
+ float u, v;
+ v = (vin.z + 1.0) * 0.5;
+ float len = sqrt(vin.x * vin.x + vin.y * vin[1]);
+ if (len > 0.0) {
+ u = (1.0 - (atan(vin.x / len, vin.y / len) / M_PI)) * 0.5;
+ }
+ else {
+ v = u = 0.0;
+ }
+
+ vout = vec3(u, v, 0.0);
+}
+
+/* 16bits floats limits. Higher/Lower values produce +/-inf. */
+#define safe_color(a) (clamp(a, -65520.0, 65520.0))
+
+void node_tex_image_linear(vec3 co, sampler2D ima, out vec4 color, out float alpha)
+{
+ color = safe_color(texture(ima, co.xy));
+ alpha = color.a;
+}
+
+void node_tex_image_linear_no_mip(vec3 co, sampler2D ima, out vec4 color, out float alpha)
+{
+ color = safe_color(textureLod(ima, co.xy, 0.0));
+ alpha = color.a;
+}
+
+void node_tex_image_nearest(vec3 co, sampler2D ima, out vec4 color, out float alpha)
+{
+ ivec2 pix = ivec2(fract(co.xy) * textureSize(ima, 0).xy);
+ color = safe_color(texelFetch(ima, pix, 0));
+ alpha = color.a;
+}
+
+/* @arg f: signed distance to texel center. */
+void cubic_bspline_coefs(vec2 f, out vec2 w0, out vec2 w1, out vec2 w2, out vec2 w3)
+{
+ vec2 f2 = f * f;
+ vec2 f3 = f2 * f;
+ /* Bspline coefs (optimized) */
+ w3 = f3 / 6.0;
+ w0 = -w3 + f2 * 0.5 - f * 0.5 + 1.0 / 6.0;
+ w1 = f3 * 0.5 - f2 * 1.0 + 2.0 / 3.0;
+ w2 = 1.0 - w0 - w1 - w3;
+}
+
+void node_tex_image_cubic_ex(
+ vec3 co, sampler2D ima, float do_extend, out vec4 color, out float alpha)
+{
+ vec2 tex_size = vec2(textureSize(ima, 0).xy);
+
+ co.xy *= tex_size;
+ /* texel center */
+ vec2 tc = floor(co.xy - 0.5) + 0.5;
+ vec2 w0, w1, w2, w3;
+ cubic_bspline_coefs(co.xy - tc, w0, w1, w2, w3);
+
+#if 1 /* Optimized version using 4 filtered tap. */
+ vec2 s0 = w0 + w1;
+ vec2 s1 = w2 + w3;
+
+ vec2 f0 = w1 / (w0 + w1);
+ vec2 f1 = w3 / (w2 + w3);
+
+ vec4 final_co;
+ final_co.xy = tc - 1.0 + f0;
+ final_co.zw = tc + 1.0 + f1;
+
+ if (do_extend == 1.0) {
+ final_co = clamp(final_co, vec4(0.5), tex_size.xyxy - 0.5);
+ }
+ final_co /= tex_size.xyxy;
+
+ color = safe_color(textureLod(ima, final_co.xy, 0.0)) * s0.x * s0.y;
+ color += safe_color(textureLod(ima, final_co.zy, 0.0)) * s1.x * s0.y;
+ color += safe_color(textureLod(ima, final_co.xw, 0.0)) * s0.x * s1.y;
+ color += safe_color(textureLod(ima, final_co.zw, 0.0)) * s1.x * s1.y;
+
+#else /* Reference bruteforce 16 tap. */
+ color = texelFetch(ima, ivec2(tc + vec2(-1.0, -1.0)), 0) * w0.x * w0.y;
+ color += texelFetch(ima, ivec2(tc + vec2(0.0, -1.0)), 0) * w1.x * w0.y;
+ color += texelFetch(ima, ivec2(tc + vec2(1.0, -1.0)), 0) * w2.x * w0.y;
+ color += texelFetch(ima, ivec2(tc + vec2(2.0, -1.0)), 0) * w3.x * w0.y;
+
+ color += texelFetch(ima, ivec2(tc + vec2(-1.0, 0.0)), 0) * w0.x * w1.y;
+ color += texelFetch(ima, ivec2(tc + vec2(0.0, 0.0)), 0) * w1.x * w1.y;
+ color += texelFetch(ima, ivec2(tc + vec2(1.0, 0.0)), 0) * w2.x * w1.y;
+ color += texelFetch(ima, ivec2(tc + vec2(2.0, 0.0)), 0) * w3.x * w1.y;
+
+ color += texelFetch(ima, ivec2(tc + vec2(-1.0, 1.0)), 0) * w0.x * w2.y;
+ color += texelFetch(ima, ivec2(tc + vec2(0.0, 1.0)), 0) * w1.x * w2.y;
+ color += texelFetch(ima, ivec2(tc + vec2(1.0, 1.0)), 0) * w2.x * w2.y;
+ color += texelFetch(ima, ivec2(tc + vec2(2.0, 1.0)), 0) * w3.x * w2.y;
+
+ color += texelFetch(ima, ivec2(tc + vec2(-1.0, 2.0)), 0) * w0.x * w3.y;
+ color += texelFetch(ima, ivec2(tc + vec2(0.0, 2.0)), 0) * w1.x * w3.y;
+ color += texelFetch(ima, ivec2(tc + vec2(1.0, 2.0)), 0) * w2.x * w3.y;
+ color += texelFetch(ima, ivec2(tc + vec2(2.0, 2.0)), 0) * w3.x * w3.y;
+#endif
+
+ alpha = color.a;
+}
+
+void node_tex_image_cubic(vec3 co, sampler2D ima, out vec4 color, out float alpha)
+{
+ node_tex_image_cubic_ex(co, ima, 0.0, color, alpha);
+}
+
+void node_tex_image_cubic_extend(vec3 co, sampler2D ima, out vec4 color, out float alpha)
+{
+ node_tex_image_cubic_ex(co, ima, 1.0, color, alpha);
+}
+
+void node_tex_image_smart(vec3 co, sampler2D ima, out vec4 color, out float alpha)
+{
+ /* use cubic for now */
+ node_tex_image_cubic_ex(co, ima, 0.0, color, alpha);
+}
+
+void tex_box_sample_linear(
+ vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3)
+{
+ /* X projection */
+ vec2 uv = texco.yz;
+ if (N.x < 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ color1 = texture(ima, uv);
+ /* Y projection */
+ uv = texco.xz;
+ if (N.y > 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ color2 = texture(ima, uv);
+ /* Z projection */
+ uv = texco.yx;
+ if (N.z > 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ color3 = texture(ima, uv);
+}
+
+void tex_box_sample_nearest(
+ vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3)
+{
+ /* X projection */
+ vec2 uv = texco.yz;
+ if (N.x < 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ ivec2 pix = ivec2(uv.xy * textureSize(ima, 0).xy);
+ color1 = texelFetch(ima, pix, 0);
+ /* Y projection */
+ uv = texco.xz;
+ if (N.y > 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ pix = ivec2(uv.xy * textureSize(ima, 0).xy);
+ color2 = texelFetch(ima, pix, 0);
+ /* Z projection */
+ uv = texco.yx;
+ if (N.z > 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ pix = ivec2(uv.xy * textureSize(ima, 0).xy);
+ color3 = texelFetch(ima, pix, 0);
+}
+
+void tex_box_sample_cubic(
+ vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3)
+{
+ float alpha;
+ /* X projection */
+ vec2 uv = texco.yz;
+ if (N.x < 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color1, alpha);
+ /* Y projection */
+ uv = texco.xz;
+ if (N.y > 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color2, alpha);
+ /* Z projection */
+ uv = texco.yx;
+ if (N.z > 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color3, alpha);
+}
+
+void tex_box_sample_smart(
+ vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3)
+{
+ tex_box_sample_cubic(texco, N, ima, color1, color2, color3);
+}
+
+void node_tex_image_box(vec3 texco,
+ vec3 N,
+ vec4 color1,
+ vec4 color2,
+ vec4 color3,
+ sampler2D ima,
+ float blend,
+ out vec4 color,
+ out float alpha)
+{
+ /* project from direction vector to barycentric coordinates in triangles */
+ N = abs(N);
+ N /= dot(N, vec3(1.0));
+
+ /* basic idea is to think of this as a triangle, each corner representing
+ * one of the 3 faces of the cube. in the corners we have single textures,
+ * in between we blend between two textures, and in the middle we a blend
+ * between three textures.
+ *
+ * the Nxyz values are the barycentric coordinates in an equilateral
+ * triangle, which in case of blending, in the middle has a smaller
+ * equilateral triangle where 3 textures blend. this divides things into
+ * 7 zones, with an if () test for each zone
+ * EDIT: Now there is only 4 if's. */
+
+ float limit = 0.5 + 0.5 * blend;
+
+ vec3 weight;
+ weight = N.xyz / (N.xyx + N.yzz);
+ weight = clamp((weight - 0.5 * (1.0 - blend)) / max(1e-8, blend), 0.0, 1.0);
+
+ /* test for mixes between two textures */
+ if (N.z < (1.0 - limit) * (N.y + N.x)) {
+ weight.z = 0.0;
+ weight.y = 1.0 - weight.x;
+ }
+ else if (N.x < (1.0 - limit) * (N.y + N.z)) {
+ weight.x = 0.0;
+ weight.z = 1.0 - weight.y;
+ }
+ else if (N.y < (1.0 - limit) * (N.x + N.z)) {
+ weight.y = 0.0;
+ weight.x = 1.0 - weight.z;
+ }
+ else {
+ /* last case, we have a mix between three */
+ weight = ((2.0 - limit) * N + (limit - 1.0)) / max(1e-8, blend);
+ }
+
+ color = weight.x * color1 + weight.y * color2 + weight.z * color3;
+ alpha = color.a;
+}
+
+void tex_clip_linear(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
+{
+ vec2 tex_size = vec2(textureSize(ima, 0).xy);
+ vec2 minco = min(co.xy, 1.0 - co.xy);
+ minco = clamp(minco * tex_size + 0.5, 0.0, 1.0);
+ float fac = minco.x * minco.y;
+
+ color = mix(vec4(0.0), icolor, fac);
+ alpha = color.a;
+}
+
+void tex_clip_nearest(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
+{
+ vec4 minco = vec4(co.xy, 1.0 - co.xy);
+ color = (any(lessThan(minco, vec4(0.0)))) ? vec4(0.0) : icolor;
+ alpha = color.a;
+}
+
+void tex_clip_cubic(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
+{
+ vec2 tex_size = vec2(textureSize(ima, 0).xy);
+
+ co.xy *= tex_size;
+ /* texel center */
+ vec2 tc = floor(co.xy - 0.5) + 0.5;
+ vec2 w0, w1, w2, w3;
+ cubic_bspline_coefs(co.xy - tc, w0, w1, w2, w3);
+
+ /* TODO Optimize this part. I'm sure there is a smarter way to do that.
+ * Could do that when sampling? */
+#define CLIP_CUBIC_SAMPLE(samp, size) \
+ (float(all(greaterThan(samp, vec2(-0.5)))) * float(all(lessThan(ivec2(samp), itex_size))))
+ ivec2 itex_size = textureSize(ima, 0).xy;
+ float fac;
+ fac = CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, -1.0), itex_size) * w0.x * w0.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, -1.0), itex_size) * w1.x * w0.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, -1.0), itex_size) * w2.x * w0.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, -1.0), itex_size) * w3.x * w0.y;
+
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 0.0), itex_size) * w0.x * w1.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 0.0), itex_size) * w1.x * w1.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 0.0), itex_size) * w2.x * w1.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 0.0), itex_size) * w3.x * w1.y;
+
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 1.0), itex_size) * w0.x * w2.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 1.0), itex_size) * w1.x * w2.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 1.0), itex_size) * w2.x * w2.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 1.0), itex_size) * w3.x * w2.y;
+
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 2.0), itex_size) * w0.x * w3.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 2.0), itex_size) * w1.x * w3.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 2.0), itex_size) * w2.x * w3.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 2.0), itex_size) * w3.x * w3.y;
+#undef CLIP_CUBIC_SAMPLE
+
+ color = mix(vec4(0.0), icolor, fac);
+ alpha = color.a;
+}
+
+void tex_clip_smart(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
+{
+ tex_clip_cubic(co, ima, icolor, color, alpha);
+}
+
+void node_tex_image_empty(vec3 co, out vec4 color, out float alpha)
+{
+ color = vec4(0.0);
+ alpha = 0.0;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl
new file mode 100644
index 00000000000..942c507cc38
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl
@@ -0,0 +1,61 @@
+void node_tex_magic(
+ vec3 co, float scale, float distortion, float depth, out vec4 color, out float fac)
+{
+ vec3 p = co * scale;
+ float x = sin((p.x + p.y + p.z) * 5.0);
+ float y = cos((-p.x + p.y - p.z) * 5.0);
+ float z = -cos((-p.x - p.y + p.z) * 5.0);
+
+ if (depth > 0) {
+ x *= distortion;
+ y *= distortion;
+ z *= distortion;
+ y = -cos(x - y + z);
+ y *= distortion;
+ if (depth > 1) {
+ x = cos(x - y - z);
+ x *= distortion;
+ if (depth > 2) {
+ z = sin(-x - y - z);
+ z *= distortion;
+ if (depth > 3) {
+ x = -cos(-x + y - z);
+ x *= distortion;
+ if (depth > 4) {
+ y = -sin(-x + y + z);
+ y *= distortion;
+ if (depth > 5) {
+ y = -cos(-x + y + z);
+ y *= distortion;
+ if (depth > 6) {
+ x = cos(x + y + z);
+ x *= distortion;
+ if (depth > 7) {
+ z = sin(x + y - z);
+ z *= distortion;
+ if (depth > 8) {
+ x = -cos(-x - y + z);
+ x *= distortion;
+ if (depth > 9) {
+ y = -sin(x - y + z);
+ y *= distortion;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (distortion != 0.0) {
+ distortion *= 2.0;
+ x /= distortion;
+ y /= distortion;
+ z /= distortion;
+ }
+
+ color = vec4(0.5 - x, 0.5 - y, 0.5 - z, 1.0);
+ fac = (color.x + color.y + color.z) / 3.0;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl
new file mode 100644
index 00000000000..7ecca286acd
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl
@@ -0,0 +1,887 @@
+/* 1D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+void node_tex_musgrave_fBm_1d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ float p = w * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value += snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * snoise(p) * pwr;
+ }
+
+ fac = value;
+}
+
+/* 1D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+void node_tex_musgrave_multi_fractal_1d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ float p = w * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value *= (pwr * snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * snoise(p) + 1.0); /* correct? */
+ }
+
+ fac = value;
+}
+
+/* 1D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hetero_terrain_1d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ float p = w * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < int(octaves); i++) {
+ float increment = (snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float increment = (snoise(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ fac = value;
+}
+
+/* 1D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hybrid_multi_fractal_1d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ float p = w * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = snoise(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ float signal = (snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * ((snoise(p) + offset) * pwr);
+ }
+
+ fac = value;
+}
+
+/* 1D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_ridged_multi_fractal_1d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ float p = w * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - abs(snoise(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0;
+
+ for (int i = 1; i < int(octaves); i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - abs(snoise(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ fac = value;
+}
+
+/* 2D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+void node_tex_musgrave_fBm_2d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec2 p = co.xy * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value += snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * snoise(p) * pwr;
+ }
+
+ fac = value;
+}
+
+/* 2D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+void node_tex_musgrave_multi_fractal_2d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec2 p = co.xy * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value *= (pwr * snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * snoise(p) + 1.0); /* correct? */
+ }
+
+ fac = value;
+}
+
+/* 2D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hetero_terrain_2d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec2 p = co.xy * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < int(octaves); i++) {
+ float increment = (snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float increment = (snoise(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ fac = value;
+}
+
+/* 2D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hybrid_multi_fractal_2d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec2 p = co.xy * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = snoise(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ float signal = (snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * ((snoise(p) + offset) * pwr);
+ }
+
+ fac = value;
+}
+
+/* 2D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_ridged_multi_fractal_2d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec2 p = co.xy * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - abs(snoise(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0;
+
+ for (int i = 1; i < int(octaves); i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - abs(snoise(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ fac = value;
+}
+
+/* 3D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+void node_tex_musgrave_fBm_3d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec3 p = co * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value += snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * snoise(p) * pwr;
+ }
+
+ fac = value;
+}
+
+/* 3D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+void node_tex_musgrave_multi_fractal_3d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec3 p = co * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value *= (pwr * snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * snoise(p) + 1.0); /* correct? */
+ }
+
+ fac = value;
+}
+
+/* 3D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hetero_terrain_3d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec3 p = co * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < int(octaves); i++) {
+ float increment = (snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float increment = (snoise(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ fac = value;
+}
+
+/* 3D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hybrid_multi_fractal_3d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec3 p = co * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = snoise(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ float signal = (snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * ((snoise(p) + offset) * pwr);
+ }
+
+ fac = value;
+}
+
+/* 3D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_ridged_multi_fractal_3d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec3 p = co * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - abs(snoise(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0;
+
+ for (int i = 1; i < int(octaves); i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - abs(snoise(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ fac = value;
+}
+
+/* 4D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+void node_tex_musgrave_fBm_4d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec4 p = vec4(co, w) * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value += snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * snoise(p) * pwr;
+ }
+
+ fac = value;
+}
+
+/* 4D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+void node_tex_musgrave_multi_fractal_4d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec4 p = vec4(co, w) * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value *= (pwr * snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * snoise(p) + 1.0); /* correct? */
+ }
+
+ fac = value;
+}
+
+/* 4D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hetero_terrain_4d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec4 p = vec4(co, w) * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < int(octaves); i++) {
+ float increment = (snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float increment = (snoise(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ fac = value;
+}
+
+/* 4D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hybrid_multi_fractal_4d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec4 p = vec4(co, w) * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = snoise(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ float signal = (snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * ((snoise(p) + offset) * pwr);
+ }
+
+ fac = value;
+}
+
+/* 4D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_ridged_multi_fractal_4d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec4 p = vec4(co, w) * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - abs(snoise(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0;
+
+ for (int i = 1; i < int(octaves); i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - abs(snoise(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ fac = value;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
new file mode 100644
index 00000000000..e56b4a1d135
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
@@ -0,0 +1,99 @@
+/* The following offset functions generate random offsets to be added to texture
+ * coordinates to act as a seed since the noise functions don't have seed values.
+ * A seed value is needed for generating distortion textures and color outputs.
+ * The offset's components are in the range [100, 200], not too high to cause
+ * bad precision and not to small to be noticeable. We use float seed because
+ * OSL only support float hashes.
+ */
+
+float random_float_offset(float seed)
+{
+ return 100.0 + hash_float_to_float(seed) * 100.0;
+}
+
+vec2 random_vec2_offset(float seed)
+{
+ return vec2(100.0 + hash_vec2_to_float(vec2(seed, 0.0)) * 100.0,
+ 100.0 + hash_vec2_to_float(vec2(seed, 1.0)) * 100.0);
+}
+
+vec3 random_vec3_offset(float seed)
+{
+ return vec3(100.0 + hash_vec2_to_float(vec2(seed, 0.0)) * 100.0,
+ 100.0 + hash_vec2_to_float(vec2(seed, 1.0)) * 100.0,
+ 100.0 + hash_vec2_to_float(vec2(seed, 2.0)) * 100.0);
+}
+
+vec4 random_vec4_offset(float seed)
+{
+ return vec4(100.0 + hash_vec2_to_float(vec2(seed, 0.0)) * 100.0,
+ 100.0 + hash_vec2_to_float(vec2(seed, 1.0)) * 100.0,
+ 100.0 + hash_vec2_to_float(vec2(seed, 2.0)) * 100.0,
+ 100.0 + hash_vec2_to_float(vec2(seed, 3.0)) * 100.0);
+}
+
+void node_noise_texture_1d(
+ vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color)
+{
+ float p = w * scale;
+ if (distortion != 0.0) {
+ p += noise(p + random_float_offset(0.0)) * distortion;
+ }
+
+ value = fractal_noise(p, detail);
+ color = vec4(value,
+ fractal_noise(p + random_float_offset(1.0), detail),
+ fractal_noise(p + random_float_offset(2.0), detail),
+ 1.0);
+}
+
+void node_noise_texture_2d(
+ vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color)
+{
+ vec2 p = co.xy * scale;
+ if (distortion != 0.0) {
+ p += vec2(noise(p + random_vec2_offset(0.0)) * distortion,
+ noise(p + random_vec2_offset(1.0)) * distortion);
+ }
+
+ value = fractal_noise(p, detail);
+ color = vec4(value,
+ fractal_noise(p + random_vec2_offset(2.0), detail),
+ fractal_noise(p + random_vec2_offset(3.0), detail),
+ 1.0);
+}
+
+void node_noise_texture_3d(
+ vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color)
+{
+ vec3 p = co * scale;
+ if (distortion != 0.0) {
+ p += vec3(noise(p + random_vec3_offset(0.0)) * distortion,
+ noise(p + random_vec3_offset(1.0)) * distortion,
+ noise(p + random_vec3_offset(2.0)) * distortion);
+ }
+
+ value = fractal_noise(p, detail);
+ color = vec4(value,
+ fractal_noise(p + random_vec3_offset(3.0), detail),
+ fractal_noise(p + random_vec3_offset(4.0), detail),
+ 1.0);
+}
+
+void node_noise_texture_4d(
+ vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color)
+{
+ vec4 p = vec4(co, w) * scale;
+ if (distortion != 0.0) {
+ p += vec4(noise(p + random_vec4_offset(0.0)) * distortion,
+ noise(p + random_vec4_offset(1.0)) * distortion,
+ noise(p + random_vec4_offset(2.0)) * distortion,
+ noise(p + random_vec4_offset(3.0)) * distortion);
+ }
+
+ value = fractal_noise(p, detail);
+ color = vec4(value,
+ fractal_noise(p + random_vec4_offset(4.0), detail),
+ fractal_noise(p + random_vec4_offset(5.0), detail),
+ 1.0);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl
new file mode 100644
index 00000000000..981d17b4283
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl
@@ -0,0 +1,4 @@
+void node_tex_sky(vec3 co, out vec4 color)
+{
+ color = vec4(1.0);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl
new file mode 100644
index 00000000000..0d8847176c9
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl
@@ -0,0 +1,1064 @@
+/*
+ * Smooth Voronoi:
+ *
+ * - https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi
+ *
+ * Distance To Edge:
+ *
+ * - https://www.shadertoy.com/view/llG3zy
+ *
+ */
+
+/* **** 1D Voronoi **** */
+
+float voronoi_distance(float a, float b, float metric, float exponent)
+{
+ return distance(a, b);
+}
+
+void node_tex_voronoi_f1_1d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ float scaledCoord = w * scale;
+ float cellPosition = floor(scaledCoord);
+ float localPosition = scaledCoord - cellPosition;
+
+ float minDistance = 8.0;
+ float targetOffset, targetPosition;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ outDistance = minDistance;
+ outColor.xyz = hash_float_to_vec3(cellPosition + targetOffset);
+ outW = safe_divide(targetPosition + cellPosition, scale);
+}
+
+void node_tex_voronoi_smooth_f1_1d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+ smoothness = clamp(smoothness / 2.0, 0, 0.5);
+
+ float scaledCoord = w * scale;
+ float cellPosition = floor(scaledCoord);
+ float localPosition = scaledCoord - cellPosition;
+
+ float smoothDistance = 8.0;
+ float smoothPosition = 0.0;
+ vec3 smoothColor = vec3(0.0);
+ for (int i = -2; i <= 2; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0 - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0 + 3.0 * smoothness;
+ vec3 cellColor = hash_float_to_vec3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ outDistance = smoothDistance;
+ outColor.xyz = smoothColor;
+ outW = safe_divide(cellPosition + smoothPosition, scale);
+}
+
+void node_tex_voronoi_f2_1d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ float scaledCoord = w * scale;
+ float cellPosition = floor(scaledCoord);
+ float localPosition = scaledCoord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ float offsetF1 = 0.0;
+ float positionF1 = 0.0;
+ float offsetF2, positionF2;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ outDistance = distanceF2;
+ outColor.xyz = hash_float_to_vec3(cellPosition + offsetF2);
+ outW = safe_divide(positionF2 + cellPosition, scale);
+}
+
+void node_tex_voronoi_distance_to_edge_1d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ float scaledCoord = w * scale;
+ float cellPosition = floor(scaledCoord);
+ float localPosition = scaledCoord - cellPosition;
+
+ float minDistance = 8.0;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ minDistance = min(distanceToPoint, minDistance);
+ }
+ outDistance = minDistance;
+}
+
+void node_tex_voronoi_n_sphere_radius_1d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ float scaledCoord = w * scale;
+ float cellPosition = floor(scaledCoord);
+ float localPosition = scaledCoord - cellPosition;
+
+ float closestPoint;
+ float closestPointOffset;
+ float minDistance = 8.0;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+
+ minDistance = 8.0;
+ float closestPointToClosestPoint;
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0) {
+ continue;
+ }
+ float cellOffset = float(i) + closestPointOffset;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
+
+/* **** 2D Voronoi **** */
+
+float voronoi_distance(vec2 a, vec2 b, float metric, float exponent)
+{
+ if (metric == 0.0) // SHD_VORONOI_EUCLIDEAN
+ {
+ return distance(a, b);
+ }
+ else if (metric == 1.0) // SHD_VORONOI_MANHATTAN
+ {
+ return abs(a.x - b.x) + abs(a.y - b.y);
+ }
+ else if (metric == 2.0) // SHD_VORONOI_CHEBYCHEV
+ {
+ return max(abs(a.x - b.x), abs(a.y - b.y));
+ }
+ else if (metric == 3.0) // SHD_VORONOI_MINKOWSKI
+ {
+ return pow(pow(abs(a.x - b.x), exponent) + pow(abs(a.y - b.y), exponent), 1.0 / exponent);
+ }
+ else {
+ return 0.0;
+ }
+}
+
+void node_tex_voronoi_f1_2d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec2 scaledCoord = coord.xy * scale;
+ vec2 cellPosition = floor(scaledCoord);
+ vec2 localPosition = scaledCoord - cellPosition;
+
+ float minDistance = 8.0;
+ vec2 targetOffset, targetPosition;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 pointPosition = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ outDistance = minDistance;
+ outColor.xyz = hash_vec2_to_vec3(cellPosition + targetOffset);
+ outPosition = vec3(safe_divide(targetPosition + cellPosition, scale), 0.0);
+}
+
+void node_tex_voronoi_smooth_f1_2d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+ smoothness = clamp(smoothness / 2.0, 0, 0.5);
+
+ vec2 scaledCoord = coord.xy * scale;
+ vec2 cellPosition = floor(scaledCoord);
+ vec2 localPosition = scaledCoord - cellPosition;
+
+ float smoothDistance = 8.0;
+ vec3 smoothColor = vec3(0.0);
+ vec2 smoothPosition = vec2(0.0);
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 pointPosition = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0 - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0 + 3.0 * smoothness;
+ vec3 cellColor = hash_vec2_to_vec3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ outDistance = smoothDistance;
+ outColor.xyz = smoothColor;
+ outPosition = vec3(safe_divide(cellPosition + smoothPosition, scale), 0.0);
+}
+
+void node_tex_voronoi_f2_2d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec2 scaledCoord = coord.xy * scale;
+ vec2 cellPosition = floor(scaledCoord);
+ vec2 localPosition = scaledCoord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vec2 offsetF1 = vec2(0.0);
+ vec2 positionF1 = vec2(0.0);
+ vec2 offsetF2, positionF2;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 pointPosition = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ outDistance = distanceF2;
+ outColor.xyz = hash_vec2_to_vec3(cellPosition + offsetF2);
+ outPosition = vec3(safe_divide(positionF2 + cellPosition, scale), 0.0);
+}
+
+void node_tex_voronoi_distance_to_edge_2d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec2 scaledCoord = coord.xy * scale;
+ vec2 cellPosition = floor(scaledCoord);
+ vec2 localPosition = scaledCoord - cellPosition;
+
+ vec2 vectorToClosest;
+ float minDistance = 8.0;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 vectorToPoint = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 vectorToPoint = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness -
+ localPosition;
+ vec2 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ outDistance = minDistance;
+}
+
+void node_tex_voronoi_n_sphere_radius_2d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec2 scaledCoord = coord.xy * scale;
+ vec2 cellPosition = floor(scaledCoord);
+ vec2 localPosition = scaledCoord - cellPosition;
+
+ vec2 closestPoint;
+ vec2 closestPointOffset;
+ float minDistance = 8.0;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 pointPosition = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ vec2 closestPointToClosestPoint;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0) {
+ continue;
+ }
+ vec2 cellOffset = vec2(i, j) + closestPointOffset;
+ vec2 pointPosition = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
+
+/* **** 3D Voronoi **** */
+
+float voronoi_distance(vec3 a, vec3 b, float metric, float exponent)
+{
+ if (metric == 0.0) // SHD_VORONOI_EUCLIDEAN
+ {
+ return distance(a, b);
+ }
+ else if (metric == 1.0) // SHD_VORONOI_MANHATTAN
+ {
+ return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z);
+ }
+ else if (metric == 2.0) // SHD_VORONOI_CHEBYCHEV
+ {
+ return max(abs(a.x - b.x), max(abs(a.y - b.y), abs(a.z - b.z)));
+ }
+ else if (metric == 3.0) // SHD_VORONOI_MINKOWSKI
+ {
+ return pow(pow(abs(a.x - b.x), exponent) + pow(abs(a.y - b.y), exponent) +
+ pow(abs(a.z - b.z), exponent),
+ 1.0 / exponent);
+ }
+ else {
+ return 0.0;
+ }
+}
+
+void node_tex_voronoi_f1_3d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec3 scaledCoord = coord * scale;
+ vec3 cellPosition = floor(scaledCoord);
+ vec3 localPosition = scaledCoord - cellPosition;
+
+ float minDistance = 8.0;
+ vec3 targetOffset, targetPosition;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 pointPosition = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ }
+ outDistance = minDistance;
+ outColor.xyz = hash_vec3_to_vec3(cellPosition + targetOffset);
+ outPosition = safe_divide(targetPosition + cellPosition, scale);
+}
+
+void node_tex_voronoi_smooth_f1_3d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+ smoothness = clamp(smoothness / 2.0, 0, 0.5);
+
+ vec3 scaledCoord = coord * scale;
+ vec3 cellPosition = floor(scaledCoord);
+ vec3 localPosition = scaledCoord - cellPosition;
+
+ float smoothDistance = 8.0;
+ vec3 smoothColor = vec3(0.0);
+ vec3 smoothPosition = vec3(0.0);
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 pointPosition = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(
+ 0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0 - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0 + 3.0 * smoothness;
+ vec3 cellColor = hash_vec3_to_vec3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ }
+ outDistance = smoothDistance;
+ outColor.xyz = smoothColor;
+ outPosition = safe_divide(cellPosition + smoothPosition, scale);
+}
+
+void node_tex_voronoi_f2_3d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec3 scaledCoord = coord * scale;
+ vec3 cellPosition = floor(scaledCoord);
+ vec3 localPosition = scaledCoord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vec3 offsetF1 = vec3(0.0);
+ vec3 positionF1 = vec3(0.0);
+ vec3 offsetF2, positionF2;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 pointPosition = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ }
+ outDistance = distanceF2;
+ outColor.xyz = hash_vec3_to_vec3(cellPosition + offsetF2);
+ outPosition = safe_divide(positionF2 + cellPosition, scale);
+}
+
+void node_tex_voronoi_distance_to_edge_3d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec3 scaledCoord = coord * scale;
+ vec3 cellPosition = floor(scaledCoord);
+ vec3 localPosition = scaledCoord - cellPosition;
+
+ vec3 vectorToClosest;
+ float minDistance = 8.0;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 vectorToPoint = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 vectorToPoint = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness -
+ localPosition;
+ vec3 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ }
+ outDistance = minDistance;
+}
+
+void node_tex_voronoi_n_sphere_radius_3d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec3 scaledCoord = coord * scale;
+ vec3 cellPosition = floor(scaledCoord);
+ vec3 localPosition = scaledCoord - cellPosition;
+
+ vec3 closestPoint;
+ vec3 closestPointOffset;
+ float minDistance = 8.0;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 pointPosition = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ vec3 closestPointToClosestPoint;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0 && k == 0) {
+ continue;
+ }
+ vec3 cellOffset = vec3(i, j, k) + closestPointOffset;
+ vec3 pointPosition = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
+
+/* **** 4D Voronoi **** */
+
+float voronoi_distance(vec4 a, vec4 b, float metric, float exponent)
+{
+ if (metric == 0.0) // SHD_VORONOI_EUCLIDEAN
+ {
+ return distance(a, b);
+ }
+ else if (metric == 1.0) // SHD_VORONOI_MANHATTAN
+ {
+ return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z) + abs(a.w - b.w);
+ }
+ else if (metric == 2.0) // SHD_VORONOI_CHEBYCHEV
+ {
+ return max(abs(a.x - b.x), max(abs(a.y - b.y), max(abs(a.z - b.z), abs(a.w - b.w))));
+ }
+ else if (metric == 3.0) // SHD_VORONOI_MINKOWSKI
+ {
+ return pow(pow(abs(a.x - b.x), exponent) + pow(abs(a.y - b.y), exponent) +
+ pow(abs(a.z - b.z), exponent) + pow(abs(a.w - b.w), exponent),
+ 1.0 / exponent);
+ }
+ else {
+ return 0.0;
+ }
+}
+
+void node_tex_voronoi_f1_4d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec4 scaledCoord = vec4(coord, w) * scale;
+ vec4 cellPosition = floor(scaledCoord);
+ vec4 localPosition = scaledCoord - cellPosition;
+
+ float minDistance = 8.0;
+ vec4 targetOffset, targetPosition;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 pointPosition = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ outDistance = minDistance;
+ outColor.xyz = hash_vec4_to_vec3(cellPosition + targetOffset);
+ vec4 p = safe_divide(targetPosition + cellPosition, scale);
+ outPosition = p.xyz;
+ outW = p.w;
+}
+
+void node_tex_voronoi_smooth_f1_4d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+ smoothness = clamp(smoothness / 2.0, 0, 0.5);
+
+ vec4 scaledCoord = vec4(coord, w) * scale;
+ vec4 cellPosition = floor(scaledCoord);
+ vec4 localPosition = scaledCoord - cellPosition;
+
+ float smoothDistance = 8.0;
+ vec3 smoothColor = vec3(0.0);
+ vec4 smoothPosition = vec4(0.0);
+ for (int u = -2; u <= 2; u++) {
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 pointPosition = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(
+ 0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0 - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0 + 3.0 * smoothness;
+ vec3 cellColor = hash_vec4_to_vec3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ }
+ }
+ outDistance = smoothDistance;
+ outColor.xyz = smoothColor;
+ vec4 p = safe_divide(cellPosition + smoothPosition, scale);
+ outPosition = p.xyz;
+ outW = p.w;
+}
+
+void node_tex_voronoi_f2_4d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec4 scaledCoord = vec4(coord, w) * scale;
+ vec4 cellPosition = floor(scaledCoord);
+ vec4 localPosition = scaledCoord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vec4 offsetF1 = vec4(0.0);
+ vec4 positionF1 = vec4(0.0);
+ vec4 offsetF2, positionF2;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 pointPosition = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ outDistance = distanceF2;
+ outColor.xyz = hash_vec4_to_vec3(cellPosition + offsetF2);
+ vec4 p = safe_divide(positionF2 + cellPosition, scale);
+ outPosition = p.xyz;
+ outW = p.w;
+}
+
+void node_tex_voronoi_distance_to_edge_4d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec4 scaledCoord = vec4(coord, w) * scale;
+ vec4 cellPosition = floor(scaledCoord);
+ vec4 localPosition = scaledCoord - cellPosition;
+
+ vec4 vectorToClosest;
+ float minDistance = 8.0;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 vectorToPoint = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 vectorToPoint = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness -
+ localPosition;
+ vec4 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ }
+ }
+ outDistance = minDistance;
+}
+
+void node_tex_voronoi_n_sphere_radius_4d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec4 scaledCoord = vec4(coord, w) * scale;
+ vec4 cellPosition = floor(scaledCoord);
+ vec4 localPosition = scaledCoord - cellPosition;
+
+ vec4 closestPoint;
+ vec4 closestPointOffset;
+ float minDistance = 8.0;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 pointPosition = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ vec4 closestPointToClosestPoint;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0 && k == 0 && u == 0) {
+ continue;
+ }
+ vec4 cellOffset = vec4(i, j, k, u) + closestPointOffset;
+ vec4 pointPosition = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl
new file mode 100644
index 00000000000..fa79e3dc310
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl
@@ -0,0 +1,42 @@
+float calc_wave(
+ vec3 p, float distortion, float detail, float detail_scale, int wave_type, int wave_profile)
+{
+ float n;
+
+ if (wave_type == 0) { /* type bands */
+ n = (p.x + p.y + p.z) * 10.0;
+ }
+ else { /* type rings */
+ n = length(p) * 20.0;
+ }
+
+ if (distortion != 0.0) {
+ n += distortion * fractal_noise(p * detail_scale, detail);
+ }
+
+ if (wave_profile == 0) { /* profile sin */
+ return 0.5 + 0.5 * sin(n);
+ }
+ else { /* profile saw */
+ n /= 2.0 * M_PI;
+ n -= int(n);
+ return (n < 0.0) ? n + 1.0 : n;
+ }
+}
+
+void node_tex_wave(vec3 co,
+ float scale,
+ float distortion,
+ float detail,
+ float detail_scale,
+ float wave_type,
+ float wave_profile,
+ out vec4 color,
+ out float fac)
+{
+ float f;
+ f = calc_wave(co * scale, distortion, detail, detail_scale, int(wave_type), int(wave_profile));
+
+ color = vec4(f, f, f, 1.0);
+ fac = f;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl
new file mode 100644
index 00000000000..fce511deb79
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl
@@ -0,0 +1,21 @@
+/* White Noise */
+
+void node_white_noise_1d(vec3 vector, float w, out float value)
+{
+ value = hash_float_to_float(w);
+}
+
+void node_white_noise_2d(vec3 vector, float w, out float value)
+{
+ value = hash_vec2_to_float(vector.xy);
+}
+
+void node_white_noise_3d(vec3 vector, float w, out float value)
+{
+ value = hash_vec3_to_float(vector);
+}
+
+void node_white_noise_4d(vec3 vector, float w, out float value)
+{
+ value = hash_vec4_to_float(vec4(vector, w));
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl
new file mode 100644
index 00000000000..24276156d55
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl
@@ -0,0 +1,92 @@
+vec3 mtex_2d_mapping(vec3 vec)
+{
+ return vec3(vec.xy * 0.5 + vec2(0.5), vec.z);
+}
+
+void generated_from_orco(vec3 orco, out vec3 generated)
+{
+#ifdef VOLUMETRICS
+# ifdef MESH_SHADER
+ generated = volumeObjectLocalCoord;
+# else
+ generated = worldPosition;
+# endif
+#else
+ generated = orco;
+#endif
+}
+
+void generated_texco(vec3 I, vec3 attr_orco, out vec3 generated)
+{
+ vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
+ vec4 co_homogenous = (ProjectionMatrixInverse * v);
+ vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0);
+ co.xyz = normalize(co.xyz);
+#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
+ generated = (ViewMatrixInverse * co).xyz;
+#else
+ generated_from_orco(attr_orco, generated);
+#endif
+}
+
+void node_tex_coord(vec3 I,
+ vec3 wN,
+ mat4 obmatinv,
+ vec4 camerafac,
+ vec3 attr_orco,
+ vec3 attr_uv,
+ out vec3 generated,
+ out vec3 normal,
+ out vec3 uv,
+ out vec3 object,
+ out vec3 camera,
+ out vec3 window,
+ out vec3 reflection)
+{
+ generated = attr_orco;
+ normal = normalize(normal_world_to_object(wN));
+ uv = attr_uv;
+ object = (obmatinv * (ViewMatrixInverse * vec4(I, 1.0))).xyz;
+ camera = vec3(I.xy, -I.z);
+ vec4 projvec = ProjectionMatrix * vec4(I, 1.0);
+ window = vec3(mtex_2d_mapping(projvec.xyz / projvec.w).xy * camerafac.xy + camerafac.zw, 0.0);
+ reflection = -reflect(cameraVec, normalize(wN));
+}
+
+void node_tex_coord_background(vec3 I,
+ vec3 N,
+ mat4 obmatinv,
+ vec4 camerafac,
+ vec3 attr_orco,
+ vec3 attr_uv,
+ out vec3 generated,
+ out vec3 normal,
+ out vec3 uv,
+ out vec3 object,
+ out vec3 camera,
+ out vec3 window,
+ out vec3 reflection)
+{
+ vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
+ vec4 co_homogenous = (ProjectionMatrixInverse * v);
+
+ vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0);
+
+ co = normalize(co);
+
+ vec3 coords = (ViewMatrixInverse * co).xyz;
+
+ generated = coords;
+ normal = -coords;
+ uv = vec3(attr_uv.xy, 0.0);
+ object = (obmatinv * vec4(coords, 1.0)).xyz;
+
+ camera = vec3(co.xy, -co.z);
+ window = vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0);
+
+ reflection = -coords;
+}
+
+#if defined(WORLD_BACKGROUND) || (defined(PROBE_CAPTURE) && !defined(MESH_SHADER))
+# define node_tex_coord node_tex_coord_background
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl
new file mode 100644
index 00000000000..02d288d42bf
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl
@@ -0,0 +1,9 @@
+#ifndef VOLUMETRICS
+void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure result)
+{
+ node_bsdf_diffuse(color, 0.0, N, result);
+}
+#else
+/* Stub toon because it is not compatible with volumetrics. */
+# define node_bsdf_toon
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl
new file mode 100644
index 00000000000..749b3a4c11f
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl
@@ -0,0 +1,13 @@
+#ifndef VOLUMETRICS
+void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
+{
+ N = normalize(N);
+ result = CLOSURE_DEFAULT;
+ eevee_closure_diffuse(-N, color.rgb, 1.0, false, result.radiance);
+ closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
+ result.radiance *= color.rgb;
+}
+#else
+/* Stub translucent because it is not compatible with volumetrics. */
+# define node_bsdf_translucent
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl
new file mode 100644
index 00000000000..800d0f81d4a
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl
@@ -0,0 +1,11 @@
+#ifndef VOLUMETRICS
+void node_bsdf_transparent(vec4 color, out Closure result)
+{
+ result = CLOSURE_DEFAULT;
+ result.radiance = vec3(0.0);
+ result.transmittance = abs(color.rgb);
+}
+#else
+/* Stub transparent because it is not compatible with volumetrics. */
+# define node_bsdf_transparent
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_uv_map.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_uv_map.glsl
new file mode 100644
index 00000000000..d8fcbbfc361
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_uv_map.glsl
@@ -0,0 +1,4 @@
+void node_uvmap(vec3 attr_uv, out vec3 outvec)
+{
+ outvec = attr_uv;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl
new file mode 100644
index 00000000000..35d2e903cf4
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl
@@ -0,0 +1,8 @@
+void curves_vec(float fac, vec3 vec, sampler1DArray curvemap, float layer, out vec3 outvec)
+{
+ vec4 co = vec4(vec * 0.5 + 0.5, layer);
+ outvec.x = texture(curvemap, co.xw).x;
+ outvec.y = texture(curvemap, co.yw).y;
+ outvec.z = texture(curvemap, co.zw).z;
+ outvec = mix(vec, outvec, fac);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl
new file mode 100644
index 00000000000..b6b955dcdb4
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl
@@ -0,0 +1,30 @@
+void node_vector_displacement_tangent(vec4 vector,
+ float midlevel,
+ float scale,
+ vec4 tangent,
+ vec3 normal,
+ mat4 obmat,
+ mat4 viewmat,
+ out vec3 result)
+{
+ /* TODO(fclem) this is broken. revisit latter. */
+ vec3 N_object = normalize(((vec4(normal, 0.0) * viewmat) * obmat).xyz);
+ vec3 T_object = normalize(((vec4(tangent.xyz, 0.0) * viewmat) * obmat).xyz);
+ vec3 B_object = tangent.w * normalize(cross(N_object, T_object));
+
+ vec3 offset = (vector.xyz - vec3(midlevel)) * scale;
+ result = offset.x * T_object + offset.y * N_object + offset.z * B_object;
+ result = (obmat * vec4(result, 0.0)).xyz;
+}
+
+void node_vector_displacement_object(
+ vec4 vector, float midlevel, float scale, mat4 obmat, out vec3 result)
+{
+ result = (vector.xyz - vec3(midlevel)) * scale;
+ result = (obmat * vec4(result, 0.0)).xyz;
+}
+
+void node_vector_displacement_world(vec4 vector, float midlevel, float scale, out vec3 result)
+{
+ result = (vector.xyz - vec3(midlevel)) * scale;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl
new file mode 100644
index 00000000000..93132b6044f
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl
@@ -0,0 +1,100 @@
+void vector_math_add(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = a + b;
+}
+
+void vector_math_subtract(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = a - b;
+}
+
+void vector_math_multiply(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = a * b;
+}
+
+void vector_math_divide(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = safe_divide(a, b);
+}
+
+void vector_math_cross(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = cross(a, b);
+}
+
+void vector_math_project(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ float lenSquared = dot(b, b);
+ outVector = (lenSquared != 0.0) ? (dot(a, b) / lenSquared) * b : vec3(0.0);
+}
+
+void vector_math_reflect(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = reflect(a, normalize(b));
+}
+
+void vector_math_dot(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outValue = dot(a, b);
+}
+
+void vector_math_distance(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outValue = distance(a, b);
+}
+
+void vector_math_length(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outValue = length(a);
+}
+
+void vector_math_scale(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = a * scale;
+}
+
+void vector_math_normalize(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = normalize(a);
+}
+
+void vector_math_snap(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = floor(safe_divide(a, b)) * b;
+}
+
+void vector_math_floor(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = floor(a);
+}
+
+void vector_math_ceil(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = ceil(a);
+}
+
+void vector_math_modulo(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = c_mod(a, b);
+}
+
+void vector_math_fraction(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = fract(a);
+}
+
+void vector_math_absolute(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = abs(a);
+}
+
+void vector_math_minimum(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = min(a, b);
+}
+
+void vector_math_maximum(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = max(a, b);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl
new file mode 100644
index 00000000000..9646ffff8ca
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl
@@ -0,0 +1,9 @@
+#ifndef VOLUMETRICS
+void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out Closure result)
+{
+ node_bsdf_diffuse(color, 0.0, N, result);
+}
+#else
+/* Stub velvet because it is not compatible with volumetrics. */
+# define node_bsdf_velvet
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vertex_color.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vertex_color.glsl
new file mode 100644
index 00000000000..551b838daf8
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_vertex_color.glsl
@@ -0,0 +1,5 @@
+void node_vertex_color(vec4 vertexColor, out vec4 outColor, out float outAlpha)
+{
+ outColor = vertexColor;
+ outAlpha = vertexColor.a;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl
new file mode 100644
index 00000000000..e6c0880cd07
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl
@@ -0,0 +1,8 @@
+void node_volume_absorption(vec4 color, float density, out Closure result)
+{
+#ifdef VOLUMETRICS
+ result = Closure((1.0 - color.rgb) * density, vec3(0.0), vec3(0.0), 0.0);
+#else
+ result = CLOSURE_DEFAULT;
+#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl
new file mode 100644
index 00000000000..501aeb6f34e
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl
@@ -0,0 +1,88 @@
+void node_attribute_volume_density(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
+{
+#if defined(MESH_SHADER) && defined(VOLUMETRICS)
+ vec3 cos = volumeObjectLocalCoord;
+#else
+ vec3 cos = vec3(0.0);
+#endif
+ outvec = texture(tex, cos).aaa;
+ outcol = vec4(outvec, 1.0);
+ outf = avg(outvec);
+}
+
+uniform vec3 volumeColor = vec3(1.0);
+
+void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
+{
+#if defined(MESH_SHADER) && defined(VOLUMETRICS)
+ vec3 cos = volumeObjectLocalCoord;
+#else
+ vec3 cos = vec3(0.0);
+#endif
+
+ vec4 value = texture(tex, cos).rgba;
+ /* Density is premultiplied for interpolation, divide it out here. */
+ if (value.a > 1e-8) {
+ value.rgb /= value.a;
+ }
+
+ outvec = value.rgb * volumeColor;
+ outcol = vec4(outvec, 1.0);
+ outf = avg(outvec);
+}
+
+void node_attribute_volume_flame(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
+{
+#if defined(MESH_SHADER) && defined(VOLUMETRICS)
+ vec3 cos = volumeObjectLocalCoord;
+#else
+ vec3 cos = vec3(0.0);
+#endif
+ outf = texture(tex, cos).r;
+ outvec = vec3(outf, outf, outf);
+ outcol = vec4(outf, outf, outf, 1.0);
+}
+
+void node_attribute_volume_temperature(
+ sampler3D tex, vec2 temperature, out vec4 outcol, out vec3 outvec, out float outf)
+{
+#if defined(MESH_SHADER) && defined(VOLUMETRICS)
+ vec3 cos = volumeObjectLocalCoord;
+#else
+ vec3 cos = vec3(0.0);
+#endif
+ float flame = texture(tex, cos).r;
+
+ outf = (flame > 0.01) ? temperature.x + flame * (temperature.y - temperature.x) : 0.0;
+ outvec = vec3(outf, outf, outf);
+ outcol = vec4(outf, outf, outf, 1.0);
+}
+
+void node_volume_info(sampler3D densitySampler,
+ sampler3D flameSampler,
+ vec2 temperature,
+ out vec4 outColor,
+ out float outDensity,
+ out float outFlame,
+ out float outTemprature)
+{
+#if defined(MESH_SHADER) && defined(VOLUMETRICS)
+ vec3 p = volumeObjectLocalCoord;
+#else
+ vec3 p = vec3(0.0);
+#endif
+
+ vec4 density = texture(densitySampler, p);
+ outDensity = density.a;
+
+ /* Density is premultiplied for interpolation, divide it out here. */
+ if (density.a > 1e-8) {
+ density.rgb /= density.a;
+ }
+ outColor = vec4(density.rgb * volumeColor, 1.0);
+
+ float flame = texture(flameSampler, p).r;
+ outFlame = flame;
+
+ outTemprature = (flame > 0.01) ? temperature.x + flame * (temperature.y - temperature.x) : 0.0;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl
new file mode 100644
index 00000000000..884d5415c51
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl
@@ -0,0 +1,67 @@
+void node_volume_principled(vec4 color,
+ float density,
+ float anisotropy,
+ vec4 absorption_color,
+ float emission_strength,
+ vec4 emission_color,
+ float blackbody_intensity,
+ vec4 blackbody_tint,
+ float temperature,
+ float density_attribute,
+ vec4 color_attribute,
+ float temperature_attribute,
+ sampler1DArray spectrummap,
+ float layer,
+ out Closure result)
+{
+#ifdef VOLUMETRICS
+ vec3 absorption_coeff = vec3(0.0);
+ vec3 scatter_coeff = vec3(0.0);
+ vec3 emission_coeff = vec3(0.0);
+
+ /* Compute density. */
+ density = max(density, 0.0);
+
+ if (density > 1e-5) {
+ density = max(density * density_attribute, 0.0);
+ }
+
+ if (density > 1e-5) {
+ /* Compute scattering and absorption coefficients. */
+ vec3 scatter_color = color.rgb * color_attribute.rgb;
+
+ scatter_coeff = scatter_color * density;
+ absorption_color.rgb = sqrt(max(absorption_color.rgb, 0.0));
+ absorption_coeff = max(1.0 - scatter_color, 0.0) * max(1.0 - absorption_color.rgb, 0.0) *
+ density;
+ }
+
+ /* Compute emission. */
+ emission_strength = max(emission_strength, 0.0);
+
+ if (emission_strength > 1e-5) {
+ emission_coeff += emission_strength * emission_color.rgb;
+ }
+
+ if (blackbody_intensity > 1e-3) {
+ /* Add temperature from attribute. */
+ float T = max(temperature * max(temperature_attribute, 0.0), 0.0);
+
+ /* Stefan-Boltzman law. */
+ float T2 = T * T;
+ float T4 = T2 * T2;
+ float sigma = 5.670373e-8 * 1e-6 / M_PI;
+ float intensity = sigma * mix(1.0, T4, blackbody_intensity);
+
+ if (intensity > 1e-5) {
+ vec4 bb;
+ node_blackbody(T, spectrummap, layer, bb);
+ emission_coeff += bb.rgb * blackbody_tint.rgb * intensity;
+ }
+ }
+
+ result = Closure(absorption_coeff, scatter_coeff, emission_coeff, anisotropy);
+#else
+ result = CLOSURE_DEFAULT;
+#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl
new file mode 100644
index 00000000000..02c54658be5
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl
@@ -0,0 +1,8 @@
+void node_volume_scatter(vec4 color, float density, float anisotropy, out Closure result)
+{
+#ifdef VOLUMETRICS
+ result = Closure(vec3(0.0), color.rgb * density, vec3(0.0), anisotropy);
+#else
+ result = CLOSURE_DEFAULT;
+#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl
new file mode 100644
index 00000000000..2fcf1b8d914
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl
@@ -0,0 +1,31 @@
+#ifndef VOLUMETRICS
+void node_wireframe(float size, vec2 barycentric, vec3 barycentric_dist, out float fac)
+{
+ vec3 barys = barycentric.xyy;
+ barys.z = 1.0 - barycentric.x - barycentric.y;
+
+ size *= 0.5;
+ vec3 s = step(-size, -barys * barycentric_dist);
+
+ fac = max(s.x, max(s.y, s.z));
+}
+
+void node_wireframe_screenspace(float size, vec2 barycentric, out float fac)
+{
+ vec3 barys = barycentric.xyy;
+ barys.z = 1.0 - barycentric.x - barycentric.y;
+
+ size *= (1.0 / 3.0);
+ vec3 dx = dFdx(barys);
+ vec3 dy = dFdy(barys);
+ vec3 deltas = sqrt(dx * dx + dy * dy);
+
+ vec3 s = step(-deltas * size, -barys);
+
+ fac = max(s.x, max(s.y, s.z));
+}
+#else
+/* Stub wireframe because it is not compatible with volumetrics. */
+# define node_wireframe
+# define node_wireframe_screenspace
+#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl
new file mode 100644
index 00000000000..f9691beee6f
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl
@@ -0,0 +1,25 @@
+/* TODO : clean this ifdef mess */
+void world_normals_get(out vec3 N)
+{
+#ifndef VOLUMETRICS
+# ifdef HAIR_SHADER
+ vec3 B = normalize(cross(worldNormal, hairTangent));
+ float cos_theta;
+ if (hairThicknessRes == 1) {
+ vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0);
+ /* Random cosine normal distribution on the hair surface. */
+ cos_theta = rand.x * 2.0 - 1.0;
+ }
+ else {
+ /* Shade as a cylinder. */
+ cos_theta = hairThickTime / hairThickness;
+ }
+ float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
+ N = normalize(worldNormal * sin_theta + B * cos_theta);
+# else
+ N = gl_FrontFacing ? worldNormal : -worldNormal;
+# endif
+#else
+ generated_from_orco(vec3(0.0), N);
+#endif
+}
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index 2ceedca59f7..35910bc32b7 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -795,7 +795,7 @@ static void copypose_error(const iTaSC::ConstraintValues *values,
if (iktarget->controlType & iTaSC::CopyPose::CTL_POSITION) {
// update error
- for (i = 0, error = 0.0, value = values->values; i < values->number; ++i, ++value) {
+ for (i = 0, error = 0.0, value = values->values; i < values->number; i++, value++) {
error += KDL::sqr(value->y - value->yd);
}
iktarget->blenderConstraint->lin_error = (float)KDL::sqrt(error);
@@ -803,7 +803,7 @@ static void copypose_error(const iTaSC::ConstraintValues *values,
}
if (iktarget->controlType & iTaSC::CopyPose::CTL_ROTATION) {
// update error
- for (i = 0, error = 0.0, value = values->values; i < values->number; ++i, ++value) {
+ for (i = 0, error = 0.0, value = values->values; i < values->number; i++, value++) {
error += KDL::sqr(value->y - value->yd);
}
iktarget->blenderConstraint->rot_error = (float)KDL::sqrt(error);
@@ -966,7 +966,7 @@ static int convert_channels(struct Depsgraph *depsgraph,
int a, flag, njoint;
njoint = 0;
- for (a = 0, ikchan = ikscene->channels; a < ikscene->numchan; ++a, ++ikchan) {
+ for (a = 0, ikchan = ikscene->channels; a < ikscene->numchan; a++, ikchan++) {
pchan = tree->pchan[a];
ikchan->pchan = pchan;
ikchan->parent = (a > 0) ? tree->parent[a] : -1;
@@ -1106,7 +1106,7 @@ static void convert_pose(IK_Scene *ikscene)
rot = ikscene->jointArray(0);
for (joint = a = 0, ikchan = ikscene->channels;
a < ikscene->numchan && joint < ikscene->numjoint;
- ++a, ++ikchan) {
+ a++, ikchan++) {
pchan = ikchan->pchan;
bone = pchan->bone;
@@ -1149,7 +1149,7 @@ static void BKE_pose_rest(IK_Scene *ikscene)
rot = ikscene->jointArray(0);
for (joint = a = 0, ikchan = ikscene->channels;
a < ikscene->numchan && joint < ikscene->numjoint;
- ++a, ++ikchan) {
+ a++, ikchan++) {
pchan = ikchan->pchan;
bone = pchan->bone;
@@ -1234,7 +1234,7 @@ static IK_Scene *convert_tree(
BKE_pose_rest(ikscene);
rot = ikscene->jointArray(0);
- for (a = 0, ikchan = ikscene->channels; a < tree->totchannel; ++a, ++ikchan) {
+ for (a = 0, ikchan = ikscene->channels; a < tree->totchannel; a++, ikchan++) {
pchan = ikchan->pchan;
bone = pchan->bone;
@@ -1728,7 +1728,7 @@ static void execute_scene(struct Depsgraph *depsgraph,
int i;
IK_Channel *ikchan;
if (ikparam->flag & ITASC_SIMULATION) {
- for (i = 0, ikchan = ikscene->channels; i < ikscene->numchan; i++, ++ikchan) {
+ for (i = 0, ikchan = ikscene->channels; i < ikscene->numchan; i++, ikchan++) {
// In simulation mode we don't allow external constraint to change our bones,
// mark the channel done also tell Blender that this channel is part of IK tree.
// Cleared on each BKE_pose_where_is()
@@ -1738,7 +1738,7 @@ static void execute_scene(struct Depsgraph *depsgraph,
}
else {
// in animation mode, we must get the bone position from action and constraints
- for (i = 0, ikchan = ikscene->channels; i < ikscene->numchan; i++, ++ikchan) {
+ for (i = 0, ikchan = ikscene->channels; i < ikscene->numchan; i++, ikchan++) {
if (!(ikchan->pchan->flag & POSE_DONE)) {
BKE_pose_where_is_bone(depsgraph, blscene, ikscene->blArmature, ikchan->pchan, ctime, 1);
}
@@ -1749,7 +1749,7 @@ static void execute_scene(struct Depsgraph *depsgraph,
}
}
// only run execute the scene if at least one of our target is enabled
- for (i = ikscene->targets.size(); i > 0; --i) {
+ for (i = ikscene->targets.size(); i > 0; i--) {
IK_Target *iktarget = ikscene->targets[i - 1];
if (!(iktarget->blenderConstraint->flag & CONSTRAINT_OFF)) {
break;
@@ -1816,7 +1816,7 @@ static void execute_scene(struct Depsgraph *depsgraph,
}
}
// compute constraint error
- for (i = ikscene->targets.size(); i > 0; --i) {
+ for (i = ikscene->targets.size(); i > 0; i--) {
IK_Target *iktarget = ikscene->targets[i - 1];
if (!(iktarget->blenderConstraint->flag & CONSTRAINT_OFF) && iktarget->constraint) {
unsigned int nvalues;
@@ -1840,7 +1840,7 @@ static void execute_scene(struct Depsgraph *depsgraph,
float scale;
float length;
float yaxis[3];
- for (i = 0, ikchan = ikscene->channels; i < ikscene->numchan; ++i, ++ikchan) {
+ for (i = 0, ikchan = ikscene->channels; i < ikscene->numchan; i++, ikchan++) {
if (i == 0) {
if (!arm->getRelativeFrame(frame, ikchan->tail)) {
break;
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 571cac41399..9e9c47194e1 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -145,7 +145,8 @@ bool IMB_initImBuf(
struct ImBuf *IMB_allocFromBuffer(const unsigned int *rect,
const float *rectf,
unsigned int w,
- unsigned int h);
+ unsigned int h,
+ unsigned int channels);
/**
*
@@ -217,15 +218,20 @@ typedef enum IMB_BlendMode {
} IMB_BlendMode;
void IMB_blend_color_byte(unsigned char dst[4],
- unsigned char src1[4],
- unsigned char src2[4],
+ const unsigned char src1[4],
+ const unsigned char src2[4],
IMB_BlendMode mode);
-void IMB_blend_color_float(float dst[4], float src1[4], float src2[4], IMB_BlendMode mode);
+void IMB_blend_color_float(float dst[4],
+ const float src1[4],
+ const float src2[4],
+ IMB_BlendMode mode);
void IMB_rect_crop(struct ImBuf *ibuf, const struct rcti *crop);
+void IMB_rect_size_set(struct ImBuf *ibuf, const uint size[2]);
+
void IMB_rectclip(struct ImBuf *dbuf,
- struct ImBuf *sbuf,
+ const struct ImBuf *sbuf,
int *destx,
int *desty,
int *srcx,
@@ -233,7 +239,7 @@ void IMB_rectclip(struct ImBuf *dbuf,
int *width,
int *height);
void IMB_rectcpy(struct ImBuf *drect,
- struct ImBuf *srect,
+ const struct ImBuf *srect,
int destx,
int desty,
int srcx,
@@ -241,11 +247,11 @@ void IMB_rectcpy(struct ImBuf *drect,
int width,
int height);
void IMB_rectblend(struct ImBuf *dbuf,
- struct ImBuf *obuf,
- struct ImBuf *sbuf,
+ const struct ImBuf *obuf,
+ const struct ImBuf *sbuf,
unsigned short *dmask,
- unsigned short *curvemask,
- unsigned short *mmask,
+ const unsigned short *curvemask,
+ const unsigned short *mmask,
float mask_max,
int destx,
int desty,
@@ -258,11 +264,11 @@ void IMB_rectblend(struct ImBuf *dbuf,
IMB_BlendMode mode,
bool accumulate);
void IMB_rectblend_threaded(struct ImBuf *dbuf,
- struct ImBuf *obuf,
- struct ImBuf *sbuf,
+ const struct ImBuf *obuf,
+ const struct ImBuf *sbuf,
unsigned short *dmask,
- unsigned short *curvemask,
- unsigned short *mmask,
+ const unsigned short *curvemask,
+ const unsigned short *mmask,
float mask_max,
int destx,
int desty,
@@ -476,7 +482,7 @@ int imb_get_anim_type(const char *name);
*
* \attention Defined in util.c
*/
-bool IMB_isfloat(struct ImBuf *ibuf);
+bool IMB_isfloat(const struct ImBuf *ibuf);
/* Do byte/float and colorspace conversions need to take alpha into account? */
bool IMB_alpha_affects_rgb(const struct ImBuf *ibuf);
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h
index 065c7e64d07..9ad88f24693 100644
--- a/source/blender/imbuf/intern/IMB_anim.h
+++ b/source/blender/imbuf/intern/IMB_anim.h
@@ -89,7 +89,7 @@ struct anim {
int ib_flags;
int curtype;
int curposition; /* index 0 = 1e, 1 = 2e, enz. */
- int duration;
+ int duration_in_frames;
int frs_sec;
double frs_sec_base;
int x, y;
diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h
index 5048414ac65..52db0b80441 100644
--- a/source/blender/imbuf/intern/IMB_filetype.h
+++ b/source/blender/imbuf/intern/IMB_filetype.h
@@ -33,7 +33,7 @@ typedef struct ImFileType {
int (*is_a)(const unsigned char *buf);
int (*is_a_filepath)(const char *name);
- int (*ftype)(const struct ImFileType *type, struct ImBuf *ibuf);
+ int (*ftype)(const struct ImFileType *type, const struct ImBuf *ibuf);
struct ImBuf *(*load)(const unsigned char *mem,
size_t size,
int flags,
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index 7d2f51af65e..75db3fd3c73 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -428,7 +428,8 @@ bool imb_addrectImBuf(ImBuf *ibuf)
struct ImBuf *IMB_allocFromBuffer(const unsigned int *rect,
const float *rectf,
unsigned int w,
- unsigned int h)
+ unsigned int h,
+ unsigned int channels)
{
ImBuf *ibuf = NULL;
@@ -438,6 +439,7 @@ struct ImBuf *IMB_allocFromBuffer(const unsigned int *rect,
ibuf = IMB_allocImBuf(w, h, 32, 0);
+ ibuf->channels = channels;
if (rectf) {
ibuf->rect_float = MEM_dupallocN(rectf);
ibuf->flags |= IB_rectfloat;
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index 52d8db95054..232a9998ebf 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -199,7 +199,7 @@ static void free_anim_avi(struct anim *anim)
}
# endif
- anim->duration = 0;
+ anim->duration_in_frames = 0;
}
#endif /* WITH_AVI */
@@ -408,7 +408,7 @@ static int startavi(struct anim *anim)
return -1;
}
- anim->duration = anim->avi->header->TotalFrames;
+ anim->duration_in_frames = anim->avi->header->TotalFrames;
anim->params = NULL;
anim->x = anim->avi->header->Width;
@@ -426,7 +426,7 @@ static int startavi(struct anim *anim)
anim->y,
anim->framesize,
anim->interlacing,
- anim->duration);
+ anim->duration_in_frames);
# endif
return 0;
@@ -493,12 +493,13 @@ BLI_INLINE bool need_aligned_ffmpeg_buffer(struct anim *anim)
static int startffmpeg(struct anim *anim)
{
- int i, videoStream;
+ int i, video_stream_index;
AVCodec *pCodec;
AVFormatContext *pFormatCtx = NULL;
AVCodecContext *pCodecCtx;
AVRational frame_rate;
+ AVStream *video_stream;
int frs_num;
double frs_den;
int streamcount;
@@ -528,7 +529,7 @@ static int startffmpeg(struct anim *anim)
av_dump_format(pFormatCtx, 0, anim->name, 0);
/* Find the video stream */
- videoStream = -1;
+ video_stream_index = -1;
for (i = 0; i < pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
@@ -536,17 +537,18 @@ static int startffmpeg(struct anim *anim)
streamcount--;
continue;
}
- videoStream = i;
+ video_stream_index = i;
break;
}
}
- if (videoStream == -1) {
+ if (video_stream_index == -1) {
avformat_close_input(&pFormatCtx);
return -1;
}
- pCodecCtx = pFormatCtx->streams[videoStream]->codec;
+ video_stream = pFormatCtx->streams[video_stream_index];
+ pCodecCtx = video_stream->codec;
/* Find the decoder for the video stream */
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
@@ -567,12 +569,29 @@ static int startffmpeg(struct anim *anim)
return -1;
}
- frame_rate = av_get_r_frame_rate_compat(pFormatCtx, pFormatCtx->streams[videoStream]);
- if (pFormatCtx->streams[videoStream]->nb_frames != 0) {
- anim->duration = pFormatCtx->streams[videoStream]->nb_frames;
+ frame_rate = av_guess_frame_rate(pFormatCtx, video_stream, NULL);
+ anim->duration_in_frames = 0;
+
+ /* Take from the stream if we can. */
+ if (video_stream->nb_frames != 0) {
+ anim->duration_in_frames = video_stream->nb_frames;
+
+ /* Sanity check on the detected duration. This is to work around corruption like reported in
+ * T68091. */
+ if (frame_rate.den != 0 && pFormatCtx->duration > 0) {
+ double stream_sec = anim->duration_in_frames * av_q2d(frame_rate);
+ double container_sec = pFormatCtx->duration / (double)AV_TIME_BASE;
+ if (stream_sec > 4.0 * container_sec) {
+ /* The stream is significantly longer than the container duration, which is
+ * suspicious. */
+ anim->duration_in_frames = 0;
+ }
+ }
}
- else {
- anim->duration = (int)(pFormatCtx->duration * av_q2d(frame_rate) / AV_TIME_BASE + 0.5f);
+ /* Fall back to the container. */
+ if (anim->duration_in_frames == 0) {
+ anim->duration_in_frames = (int)(pFormatCtx->duration * av_q2d(frame_rate) / AV_TIME_BASE +
+ 0.5f);
}
frs_num = frame_rate.num;
@@ -596,7 +615,7 @@ static int startffmpeg(struct anim *anim)
anim->pFormatCtx = pFormatCtx;
anim->pCodecCtx = pCodecCtx;
anim->pCodec = pCodec;
- anim->videoStream = videoStream;
+ anim->videoStream = video_stream_index;
anim->interlacing = 0;
anim->orientation = 0;
@@ -1038,7 +1057,7 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ
v_st = anim->pFormatCtx->streams[anim->videoStream];
- frame_rate = av_q2d(av_get_r_frame_rate_compat(anim->pFormatCtx, v_st));
+ frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL));
st_time = anim->pFormatCtx->start_time;
pts_time_base = av_q2d(v_st->time_base);
@@ -1222,7 +1241,7 @@ static void free_anim_ffmpeg(struct anim *anim)
av_free_packet(&anim->next_packet);
}
}
- anim->duration = 0;
+ anim->duration_in_frames = 0;
}
#endif
@@ -1259,7 +1278,7 @@ static ImBuf *anim_getnew(struct anim *anim)
ibuf = IMB_loadiffname(anim->name, anim->ib_flags, anim->colorspace);
if (ibuf) {
BLI_strncpy(anim->first, anim->name, sizeof(anim->first));
- anim->duration = 1;
+ anim->duration_in_frames = 1;
}
break;
case ANIM_MOVIE:
@@ -1297,7 +1316,7 @@ struct ImBuf *IMB_anim_previewframe(struct anim *anim)
ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
if (ibuf) {
IMB_freeImBuf(ibuf);
- position = anim->duration / 2;
+ position = anim->duration_in_frames / 2;
ibuf = IMB_anim_absolute(anim, position, IMB_TC_NONE, IMB_PROXY_NONE);
}
return ibuf;
@@ -1333,7 +1352,7 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim,
if (position < 0) {
return (NULL);
}
- if (position >= anim->duration) {
+ if (position >= anim->duration_in_frames) {
return (NULL);
}
}
@@ -1398,12 +1417,12 @@ int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc)
{
struct anim_index *idx;
if (tc == IMB_TC_NONE) {
- return anim->duration;
+ return anim->duration_in_frames;
}
idx = IMB_anim_open_index(anim, tc);
if (!idx) {
- return anim->duration;
+ return anim->duration_in_frames;
}
return IMB_indexer_get_duration(idx);
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 36af7ab2571..1b911226c6f 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -3961,8 +3961,7 @@ static void update_glsl_display_processor(const ColorManagedViewSettings *view_s
/* We're using curve mapping's address as a cache ID,
* so we need to make sure re-allocation gives new address here.
- * We do this by allocating new curve mapping before freeing ol one.
- */
+ * We do this by allocating new curve mapping before freeing old one. */
if (use_curve_mapping) {
new_curve_mapping = BKE_curvemapping_copy(view_settings->curve_mapping);
}
diff --git a/source/blender/imbuf/intern/dds/FlipDXT.cpp b/source/blender/imbuf/intern/dds/FlipDXT.cpp
index cf228cea3ea..bfd19f40493 100644
--- a/source/blender/imbuf/intern/dds/FlipDXT.cpp
+++ b/source/blender/imbuf/intern/dds/FlipDXT.cpp
@@ -208,7 +208,7 @@ int FlipDXTCImage(
unsigned int mip_width = width;
unsigned int mip_height = height;
- for (unsigned int i = 0; i < levels; ++i) {
+ for (unsigned int i = 0; i < levels; i++) {
unsigned int blocks_per_row = (mip_width + 3) / 4;
unsigned int blocks_per_col = (mip_height + 3) / 4;
unsigned int blocks = blocks_per_row * blocks_per_col;
@@ -219,13 +219,13 @@ int FlipDXTCImage(
}
else if (mip_height == 2) {
// flip the first 2 lines in each block.
- for (unsigned int i = 0; i < blocks_per_row; ++i) {
+ for (unsigned int i = 0; i < blocks_per_row; i++) {
half_block_function(data + i * block_bytes);
}
}
else {
// flip each block.
- for (unsigned int i = 0; i < blocks; ++i) {
+ for (unsigned int i = 0; i < blocks; i++) {
full_block_function(data + i * block_bytes);
}
@@ -235,7 +235,7 @@ int FlipDXTCImage(
unsigned int row_bytes = block_bytes * blocks_per_row;
uint8_t *temp_line = new uint8_t[row_bytes];
- for (unsigned int y = 0; y < blocks_per_col / 2; ++y) {
+ for (unsigned int y = 0; y < blocks_per_col / 2; y++) {
uint8_t *line1 = data + y * row_bytes;
uint8_t *line2 = data + (blocks_per_col - y - 1) * row_bytes;
diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c
index d1b3bf21e23..c6f8bab325b 100644
--- a/source/blender/imbuf/intern/filetype.c
+++ b/source/blender/imbuf/intern/filetype.c
@@ -40,11 +40,11 @@
# include "dds/dds_api.h"
#endif
-static int imb_ftype_default(const ImFileType *type, ImBuf *ibuf)
+static int imb_ftype_default(const ImFileType *type, const ImBuf *ibuf)
{
return (ibuf->ftype == type->filetype);
}
-static int imb_ftype_iris(const ImFileType *type, ImBuf *ibuf)
+static int imb_ftype_iris(const ImFileType *type, const ImBuf *ibuf)
{
(void)type;
return (ibuf->ftype == IMB_FTYPE_IMAGIC);
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index dd31dafd148..97a0cc85301 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -900,7 +900,7 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
stream_size = avio_size(context->iFormatCtx->pb);
- context->frame_rate = av_q2d(av_get_r_frame_rate_compat(context->iFormatCtx, context->iStream));
+ context->frame_rate = av_q2d(av_guess_frame_rate(context->iFormatCtx, context->iStream, NULL));
context->pts_time_base = av_q2d(context->iStream->time_base);
while (av_read_frame(context->iFormatCtx, &next_packet) >= 0) {
@@ -1150,7 +1150,7 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
/* Don't generate the same file twice! */
if (file_list) {
- for (i = 0; i < IMB_PROXY_MAX_SLOT; ++i) {
+ for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
IMB_Proxy_Size proxy_size = proxy_sizes[i];
if (proxy_size & proxy_sizes_to_build) {
char filename[FILE_MAX];
@@ -1172,7 +1172,7 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
IMB_Proxy_Size built_proxies = IMB_anim_proxy_get_existing(anim);
if (built_proxies != 0) {
- for (i = 0; i < IMB_PROXY_MAX_SLOT; ++i) {
+ for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
IMB_Proxy_Size proxy_size = proxy_sizes[i];
if (proxy_size & built_proxies) {
char filename[FILE_MAX];
@@ -1345,7 +1345,7 @@ IMB_Proxy_Size IMB_anim_proxy_get_existing(struct anim *anim)
const int num_proxy_sizes = IMB_PROXY_MAX_SLOT;
IMB_Proxy_Size existing = 0;
int i;
- for (i = 0; i < num_proxy_sizes; ++i) {
+ for (i = 0; i < num_proxy_sizes; i++) {
IMB_Proxy_Size proxy_size = proxy_sizes[i];
char filename[FILE_MAX];
get_proxy_filename(anim, proxy_size, filename, false);
diff --git a/source/blender/imbuf/intern/jp2.c b/source/blender/imbuf/intern/jp2.c
index 3bf97cb851f..e361df1304a 100644
--- a/source/blender/imbuf/intern/jp2.c
+++ b/source/blender/imbuf/intern/jp2.c
@@ -83,7 +83,7 @@ static OPJ_CODEC_FORMAT format_from_header(const unsigned char mem[JP2_FILEHEADE
int imb_is_a_jp2(const unsigned char *buf)
{
- return check_jp2(buf);
+ return (check_jp2(buf) || check_j2k(buf));
}
/**
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index f18eb2f7303..88dfa42a416 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -1118,7 +1118,7 @@ void IMB_exr_write_channels(void *handle)
if (echan->use_half_float) {
float *rect = echan->rect;
half *cur = current_rect_half;
- for (size_t i = 0; i < num_pixels; ++i, ++cur) {
+ for (size_t i = 0; i < num_pixels; i++, cur++) {
*cur = rect[i * echan->xstride];
}
half *rect_to_write = current_rect_half + (data->height - 1L) * data->width;
@@ -2013,7 +2013,7 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem,
if (!has_rgb && has_luma) {
size_t a;
if (exr_has_chroma(*file)) {
- for (a = 0; a < (size_t)ibuf->x * ibuf->y; ++a) {
+ for (a = 0; a < (size_t)ibuf->x * ibuf->y; a++) {
float *color = ibuf->rect_float + a * 4;
ycc_to_rgb(color[0] * 255.0f,
color[1] * 255.0f,
@@ -2025,7 +2025,7 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem,
}
}
else {
- for (a = 0; a < (size_t)ibuf->x * ibuf->y; ++a) {
+ for (a = 0; a < (size_t)ibuf->x * ibuf->y; a++) {
float *color = ibuf->rect_float + a * 4;
color[1] = color[2] = color[0];
}
diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c
index 76918c216f7..3163a960892 100644
--- a/source/blender/imbuf/intern/rectop.c
+++ b/source/blender/imbuf/intern/rectop.c
@@ -39,8 +39,8 @@
#include "MEM_guardedalloc.h"
void IMB_blend_color_byte(unsigned char dst[4],
- unsigned char src1[4],
- unsigned char src2[4],
+ const unsigned char src1[4],
+ const unsigned char src2[4],
IMB_BlendMode mode)
{
switch (mode) {
@@ -126,7 +126,10 @@ void IMB_blend_color_byte(unsigned char dst[4],
}
}
-void IMB_blend_color_float(float dst[4], float src1[4], float src2[4], IMB_BlendMode mode)
+void IMB_blend_color_float(float dst[4],
+ const float src1[4],
+ const float src2[4],
+ IMB_BlendMode mode)
{
switch (mode) {
case IMB_BLEND_MIX:
@@ -276,10 +279,49 @@ void IMB_rect_crop(ImBuf *ibuf, const rcti *crop)
ibuf->y = size_dst[1];
}
+/** Re-alloc buffers at a new size */
+
+static void rect_realloc_4bytes(void **buf_p, const uint size[2])
+{
+ if (*buf_p == NULL) {
+ return;
+ }
+ MEM_freeN(*buf_p);
+ *buf_p = MEM_mallocN(sizeof(uint) * size[0] * size[1], __func__);
+}
+
+static void rect_realloc_16bytes(void **buf_p, const uint size[2])
+{
+ if (*buf_p == NULL) {
+ return;
+ }
+ MEM_freeN(*buf_p);
+ *buf_p = MEM_mallocN(sizeof(uint[4]) * size[0] * size[1], __func__);
+}
+
+/**
+ * In-place size setting (caller must fill in buffer contents).
+ */
+void IMB_rect_size_set(ImBuf *ibuf, const uint size[2])
+{
+ BLI_assert(size[0] > 0 && size[0] > 0);
+ if ((size[0] == ibuf->x) && (size[1] == ibuf->y)) {
+ return;
+ }
+
+ rect_realloc_4bytes((void **)&ibuf->rect, size);
+ rect_realloc_4bytes((void **)&ibuf->zbuf, size);
+ rect_realloc_4bytes((void **)&ibuf->zbuf_float, size);
+ rect_realloc_16bytes((void **)&ibuf->rect_float, size);
+
+ ibuf->x = size[0];
+ ibuf->y = size[1];
+}
+
/* clipping */
void IMB_rectclip(ImBuf *dbuf,
- ImBuf *sbuf,
+ const ImBuf *sbuf,
int *destx,
int *desty,
int *srcx,
@@ -341,8 +383,8 @@ void IMB_rectclip(ImBuf *dbuf,
}
static void imb_rectclip3(ImBuf *dbuf,
- ImBuf *obuf,
- ImBuf *sbuf,
+ const ImBuf *obuf,
+ const ImBuf *sbuf,
int *destx,
int *desty,
int *origx,
@@ -435,8 +477,14 @@ static void imb_rectclip3(ImBuf *dbuf,
/* copy and blend */
-void IMB_rectcpy(
- ImBuf *dbuf, ImBuf *sbuf, int destx, int desty, int srcx, int srcy, int width, int height)
+void IMB_rectcpy(ImBuf *dbuf,
+ const ImBuf *sbuf,
+ int destx,
+ int desty,
+ int srcx,
+ int srcy,
+ int width,
+ int height)
{
IMB_rectblend(dbuf,
dbuf,
@@ -463,11 +511,11 @@ typedef void (*IMB_blend_func)(unsigned char *dst,
typedef void (*IMB_blend_func_float)(float *dst, const float *src1, const float *src2);
void IMB_rectblend(ImBuf *dbuf,
- ImBuf *obuf,
- ImBuf *sbuf,
+ const ImBuf *obuf,
+ const ImBuf *sbuf,
unsigned short *dmask,
- unsigned short *curvemask,
- unsigned short *texmask,
+ const unsigned short *curvemask,
+ const unsigned short *texmask,
float mask_max,
int destx,
int desty,
@@ -482,9 +530,9 @@ void IMB_rectblend(ImBuf *dbuf,
{
unsigned int *drect = NULL, *orect = NULL, *srect = NULL, *dr, * or, *sr;
float *drectf = NULL, *orectf = NULL, *srectf = NULL, *drf, *orf, *srf;
- unsigned short *cmaskrect = curvemask, *cmr;
+ const unsigned short *cmaskrect = curvemask, *cmr;
unsigned short *dmaskrect = dmask, *dmr;
- unsigned short *texmaskrect = texmask, *tmr;
+ const unsigned short *texmaskrect = texmask, *tmr;
int do_float, do_char, srcskip, destskip, origskip, x;
IMB_blend_func func = NULL;
IMB_blend_func_float func_float = NULL;
@@ -924,8 +972,10 @@ void IMB_rectblend(ImBuf *dbuf,
}
typedef struct RectBlendThreadData {
- ImBuf *dbuf, *obuf, *sbuf;
- unsigned short *dmask, *curvemask, *texmask;
+ ImBuf *dbuf;
+ const ImBuf *obuf, *sbuf;
+ unsigned short *dmask;
+ const unsigned short *curvemask, *texmask;
float mask_max;
int destx, desty, origx, origy;
int srcx, srcy, width;
@@ -956,11 +1006,11 @@ static void rectblend_thread_do(void *data_v, int start_scanline, int num_scanli
}
void IMB_rectblend_threaded(ImBuf *dbuf,
- ImBuf *obuf,
- ImBuf *sbuf,
+ const ImBuf *obuf,
+ const ImBuf *sbuf,
unsigned short *dmask,
- unsigned short *curvemask,
- unsigned short *texmask,
+ const unsigned short *curvemask,
+ const unsigned short *texmask,
float mask_max,
int destx,
int desty,
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
index 44c311eba9d..71750c9c28f 100644
--- a/source/blender/imbuf/intern/stereoimbuf.c
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -68,7 +68,7 @@ static void imb_stereo3d_write_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyp
const int stride_from = width;
const int stride_to = width;
- int anaglyph_encoding[3][3] = {
+ const int anaglyph_encoding[3][3] = {
{0, 1, 1},
{1, 0, 1},
{0, 0, 1},
@@ -810,7 +810,7 @@ static void imb_stereo3d_read_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyph
const int stride_from = width;
const int stride_to = width;
- int anaglyph_encoding[3][3] = {
+ const int anaglyph_encoding[3][3] = {
{0, 1, 1},
{1, 0, 1},
{0, 0, 1},
diff --git a/source/blender/imbuf/intern/targa.c b/source/blender/imbuf/intern/targa.c
index f7b7df52e46..b1077a6ae91 100644
--- a/source/blender/imbuf/intern/targa.c
+++ b/source/blender/imbuf/intern/targa.c
@@ -748,7 +748,7 @@ ImBuf *imb_loadtarga(const unsigned char *mem,
if (cmap) {
/* apply color map */
rect = ibuf->rect;
- for (size = ibuf->x * ibuf->y; size > 0; --size, ++rect) {
+ for (size = ibuf->x * ibuf->y; size > 0; size--, rect++) {
int cmap_index = *rect;
if (cmap_index >= 0 && cmap_index < cmap_max) {
*rect = cmap[cmap_index];
@@ -761,7 +761,7 @@ ImBuf *imb_loadtarga(const unsigned char *mem,
if (tga.pixsize == 16) {
unsigned int col;
rect = ibuf->rect;
- for (size = ibuf->x * ibuf->y; size > 0; --size, ++rect) {
+ for (size = ibuf->x * ibuf->y; size > 0; size--, rect++) {
col = *rect;
cp = (uchar *)rect;
mem = (uchar *)&col;
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c
index ff7cb87960e..27b566e25a2 100644
--- a/source/blender/imbuf/intern/util.c
+++ b/source/blender/imbuf/intern/util.c
@@ -252,6 +252,8 @@ static int isffmpeg(const char *filename)
if (BLI_path_extension_check_n(filename,
".swf",
".jpg",
+ ".jp2",
+ ".j2c",
".png",
".dds",
".tga",
@@ -389,7 +391,7 @@ bool IMB_isanim(const char *filename)
return (type && type != ANIM_SEQUENCE);
}
-bool IMB_isfloat(ImBuf *ibuf)
+bool IMB_isfloat(const ImBuf *ibuf)
{
const ImFileType *type;
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index ef9069acb78..a6212e09567 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -432,10 +432,15 @@ typedef enum ID_Type {
#define ID_BLEND_PATH_FROM_GLOBAL(_id) \
((_id)->lib ? (_id)->lib->filepath : BKE_main_blendfile_path_from_global())
-#define ID_MISSING(_id) (((_id)->tag & LIB_TAG_MISSING) != 0)
+#define ID_MISSING(_id) ((((ID *)(_id))->tag & LIB_TAG_MISSING) != 0)
#define ID_IS_LINKED(_id) (((ID *)(_id))->lib != NULL)
+/* Note that this is a fairly high-level check, should be used at user interaction level, not in
+ * BKE_library_override typically (especially due to the check on LIB_TAG_EXTERN). */
+#define ID_IS_OVERRIDABLE_LIBRARY(_id) \
+ (ID_IS_LINKED(_id) && !ID_MISSING(_id) && (((ID *)(_id))->tag & LIB_TAG_EXTERN) != 0)
+
#define ID_IS_OVERRIDE_LIBRARY(_id) \
(((ID *)(_id))->override_library != NULL && ((ID *)(_id))->override_library->reference != NULL)
@@ -467,7 +472,15 @@ typedef enum ID_Type {
/* id->flag (persitent). */
enum {
+ /* Don't delete the datablock even if unused. */
LIB_FAKEUSER = 1 << 9,
+ /* The datablock structure is a sub-object of a different one.
+ * Direct persistent references are not allowed. */
+ LIB_PRIVATE_DATA = 1 << 10,
+ /* Datablock is from a library and linked indirectly, with LIB_TAG_INDIRECT
+ * tag set. But the current .blend file also has a weak pointer to it that
+ * we want to restore if possible, and silently drop if it's missing. */
+ LIB_INDIRECT_WEAK_LINK = 1 << 11,
};
/**
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index 1718aabc51d..70add4c156f 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -319,6 +319,10 @@ typedef struct DriverTarget {
/** Transform channel index (for DVAR_TYPE_TRANSFORM_CHAN.)*/
short transChan;
+ /** Rotation channel calculation type. */
+ char rotation_mode;
+ char _pad[7];
+
/**
* Flags for the validity of the target
* (NOTE: these get reset every time the types change).
@@ -358,10 +362,36 @@ typedef enum eDriverTarget_TransformChannels {
DTAR_TRANSCHAN_SCALEY,
DTAR_TRANSCHAN_SCALEZ,
DTAR_TRANSCHAN_SCALE_AVG,
+ DTAR_TRANSCHAN_ROTW,
MAX_DTAR_TRANSCHAN_TYPES,
} eDriverTarget_TransformChannels;
+/* Rotation channel mode for Driver Targets */
+typedef enum eDriverTarget_RotationMode {
+ /** Automatic euler mode. */
+ DTAR_ROTMODE_AUTO = 0,
+
+ /** Explicit euler rotation modes - must sync with BLI_math_rotation.h defines. */
+ DTAR_ROTMODE_EULER_XYZ = 1,
+ DTAR_ROTMODE_EULER_XZY,
+ DTAR_ROTMODE_EULER_YXZ,
+ DTAR_ROTMODE_EULER_YZX,
+ DTAR_ROTMODE_EULER_ZXY,
+ DTAR_ROTMODE_EULER_ZYX,
+
+ DTAR_ROTMODE_QUATERNION,
+
+ /** Implements the very common Damped Track + child trick to decompose
+ * rotation into bending followed by twist around the remaining axis. */
+ DTAR_ROTMODE_SWING_TWIST_X,
+ DTAR_ROTMODE_SWING_TWIST_Y,
+ DTAR_ROTMODE_SWING_TWIST_Z,
+
+ DTAR_ROTMODE_EULER_MIN = DTAR_ROTMODE_EULER_XYZ,
+ DTAR_ROTMODE_EULER_MAX = DTAR_ROTMODE_EULER_ZYX,
+} eDriverTarget_RotationMode;
+
/* --- */
/* maximum number of driver targets per variable */
diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h
index 088fd96a5ae..68241df3f93 100644
--- a/source/blender/makesdna/DNA_armature_types.h
+++ b/source/blender/makesdna/DNA_armature_types.h
@@ -60,6 +60,9 @@ typedef struct Bone {
int flag;
+ char inherit_scale_mode;
+ char _pad[7];
+
float arm_head[3];
/** head/tail in Armature Space (rest pos). */
float arm_tail[3];
@@ -229,8 +232,10 @@ typedef enum eBone_Flag {
BONE_UNKEYED = (1 << 13),
/** set to prevent hinge child bones from influencing the transform center */
BONE_HINGE_CHILD_TRANSFORM = (1 << 14),
+#ifdef DNA_DEPRECATED
/** No parent scale */
BONE_NO_SCALE = (1 << 15),
+#endif
/** hidden bone when drawing PoseChannels (for ghost drawing) */
BONE_HIDDEN_PG = (1 << 16),
/** bone should be drawn as OB_WIRE, regardless of draw-types of view+armature */
@@ -254,6 +259,20 @@ typedef enum eBone_Flag {
} eBone_Flag;
+/* bone->inherit_scale_mode */
+typedef enum eBone_InheritScaleMode {
+ /* Inherit all scale and shear. */
+ BONE_INHERIT_SCALE_FULL = 0,
+ /* Inherit scale, but remove final shear. */
+ BONE_INHERIT_SCALE_FIX_SHEAR,
+ /* Inherit average scale. */
+ BONE_INHERIT_SCALE_AVERAGE,
+ /* Inherit no scale or shear. */
+ BONE_INHERIT_SCALE_NONE,
+ /* Inherit effects of shear on parent (same as old disabled Inherit Scale). */
+ BONE_INHERIT_SCALE_NONE_LEGACY,
+} eBone_InheritScaleMode;
+
/* bone->bbone_prev_type, bbone_next_type */
typedef enum eBone_BBoneHandleType {
BBONE_HANDLE_AUTO = 0, /* Default mode based on parents & children. */
diff --git a/source/blender/makesdna/DNA_brush_defaults.h b/source/blender/makesdna/DNA_brush_defaults.h
new file mode 100644
index 00000000000..714c205cda2
--- /dev/null
+++ b/source/blender/makesdna/DNA_brush_defaults.h
@@ -0,0 +1,105 @@
+/*
+ * 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 DNA
+ */
+
+#ifndef __DNA_BRUSH_DEFAULTS_H__
+#define __DNA_BRUSH_DEFAULTS_H__
+
+#include "DNA_texture_defaults.h"
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Brush Struct
+ * \{ */
+
+#define _DNA_DEFAULT_Brush \
+ { \
+ .blend = 0, \
+ .flag = (BRUSH_ALPHA_PRESSURE | BRUSH_SPACE | BRUSH_SPACE_ATTEN), \
+ \
+ .ob_mode = OB_MODE_ALL_PAINT, \
+ \
+ /* BRUSH SCULPT TOOL SETTINGS */ \
+ .weight = 1.0f, /* weight of brush 0 - 1.0 */ \
+ .size = 35, /* radius of the brush in pixels */ \
+ .alpha = 1.0f, /* brush strength/intensity probably variable should be renamed? */ \
+ .autosmooth_factor = 0.0f, \
+ .topology_rake_factor = 0.0f, \
+ .crease_pinch_factor = 0.5f, \
+ .normal_radius_factor = 0.5f, \
+ .sculpt_plane = SCULPT_DISP_DIR_AREA, \
+ /* How far above or below the plane that is found by averaging the faces. */ \
+ .plane_offset = 0.0f, \
+ .plane_trim = 0.5f, \
+ .clone.alpha = 0.5f, \
+ .normal_weight = 0.0f, \
+ .fill_threshold = 0.2f, \
+ \
+ /* BRUSH PAINT TOOL SETTINGS */ \
+ /* Default rgb color of the brush when painting - white. */ \
+ .rgb = {1.0f, 1.0f, 1.0f}, \
+ \
+ .secondary_rgb = {0, 0, 0}, \
+ \
+ /* BRUSH STROKE SETTINGS */ \
+ /* How far each brush dot should be spaced as a percentage of brush diameter. */ \
+ .spacing = 10, \
+ \
+ .smooth_stroke_radius = 75, \
+ .smooth_stroke_factor = 0.9f, \
+ \
+ /* Time delay between dots of paint or sculpting when doing airbrush mode. */ \
+ .rate = 0.1f, \
+ \
+ .jitter = 0.0f, \
+ \
+ .texture_sample_bias = 0, /* value to added to texture samples */ \
+ .texture_overlay_alpha = 33, \
+ .mask_overlay_alpha = 33, \
+ .cursor_overlay_alpha = 33, \
+ .overlay_flags = 0, \
+ \
+ /* brush appearance */ \
+ \
+ /* add mode color is light red */ \
+ .add_col = {1.0, 0.39, 0.39}, \
+ \
+ /* subtract mode color is light blue */ \
+ .sub_col = {0.39, 0.39, 1.0}, \
+ \
+ .stencil_pos = {256, 256}, \
+ .stencil_dimension = {256, 256}, \
+ \
+ /* sculpting defaults to the draw tool for new brushes */ \
+ .sculpt_tool = SCULPT_TOOL_DRAW, \
+ \
+ /* A kernel radius of 1 has almost no effect (T63233). */ \
+ .blur_kernel_radius = 2, \
+ \
+ .mtex = _DNA_DEFAULT_MTex, \
+ .mask_mtex = _DNA_DEFAULT_MTex, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_BRUSH_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 93ce3d9769b..aec28c0fe75 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -113,7 +113,8 @@ typedef struct BrushGpencilSettings {
float gradient_f;
/** factor xy of shape for dots gradients */
float gradient_s[2];
- char _pad_2[4];
+ /** Simplify adaptive factor */
+ float simplify_f;
struct CurveMapping *curve_sensitivity;
struct CurveMapping *curve_strength;
@@ -184,6 +185,8 @@ typedef enum eGP_BrushIcons {
GP_BRUSH_ICON_ERASE_SOFT = 8,
GP_BRUSH_ICON_ERASE_HARD = 9,
GP_BRUSH_ICON_ERASE_STROKE = 10,
+ GP_BRUSH_ICON_AIRBRUSH = 11,
+ GP_BRUSH_ICON_CHISEL = 12,
} eGP_BrushIcons;
typedef enum eBrushCurvePreset {
@@ -198,6 +201,18 @@ typedef enum eBrushCurvePreset {
BRUSH_CURVE_CONSTANT = 8,
} eBrushCurvePreset;
+typedef enum eBrushElasticDeformType {
+ BRUSH_ELASTIC_DEFORM_GRAB = 0,
+ BRUSH_ELASTIC_DEFORM_GRAB_BISCALE = 1,
+ BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE = 2,
+ BRUSH_ELASTIC_DEFORM_SCALE = 3,
+ BRUSH_ELASTIC_DEFORM_TWIST = 4,
+} eBrushElasticDeformType;
+
+typedef enum eAutomasking_flag {
+ BRUSH_AUTOMASKING_TOPOLOGY = (1 << 0),
+} eAutomasking_flag;
+
typedef struct Brush {
ID id;
@@ -295,6 +310,8 @@ typedef struct Brush {
float crease_pinch_factor;
+ float normal_radius_factor;
+
float plane_trim;
/** Affectable height of brush (layer height for layer tool, i.e.). */
float height;
@@ -302,7 +319,13 @@ typedef struct Brush {
float texture_sample_bias;
int curve_preset;
- char _pad1[4];
+ int automasking_flags;
+
+ int elastic_deform_type;
+ float elastic_deform_volume_preservation;
+
+ /* pose */
+ float pose_offset;
/* overlay */
int texture_overlay_alpha;
@@ -384,8 +407,8 @@ typedef enum eBrushFlags {
BRUSH_SIZE_PRESSURE = (1 << 3),
BRUSH_JITTER_PRESSURE = (1 << 4),
BRUSH_SPACING_PRESSURE = (1 << 5),
- BRUSH_FLAG_UNUSED_6 = (1 << 6), /* cleared */
- BRUSH_FLAG_UNUSED_7 = (1 << 7), /* cleared */
+ BRUSH_ORIGINAL_PLANE = (1 << 6),
+ BRUSH_GRAB_ACTIVE_VERTEX = (1 << 7),
BRUSH_ANCHORED = (1 << 8),
BRUSH_DIR_IN = (1 << 9),
BRUSH_SPACE = (1 << 10),
@@ -395,7 +418,7 @@ typedef enum eBrushFlags {
BRUSH_LOCK_ALPHA = (1 << 14),
BRUSH_ORIGINAL_NORMAL = (1 << 15),
BRUSH_OFFSET_PRESSURE = (1 << 16),
- BRUSH_FLAG_UNUSED_17 = (1 << 17), /* cleared */
+ BRUSH_SCENE_SPACING = (1 << 17),
BRUSH_SPACE_ATTEN = (1 << 18),
BRUSH_ADAPTIVE_SPACE = (1 << 19),
BRUSH_LOCK_SIZE = (1 << 20),
@@ -452,6 +475,9 @@ typedef enum eBrushSculptTool {
SCULPT_TOOL_BLOB = 17,
SCULPT_TOOL_CLAY_STRIPS = 18,
SCULPT_TOOL_MASK = 19,
+ SCULPT_TOOL_DRAW_SHARP = 20,
+ SCULPT_TOOL_ELASTIC_DEFORM = 21,
+ SCULPT_TOOL_POSE = 22,
} eBrushSculptTool;
/* Brush.uv_sculpt_tool */
@@ -465,6 +491,7 @@ typedef enum eBrushUVSculptTool {
#define SCULPT_TOOL_HAS_ACCUMULATE(t) \
ELEM(t, \
SCULPT_TOOL_DRAW, \
+ SCULPT_TOOL_DRAW_SHARP, \
SCULPT_TOOL_CREASE, \
SCULPT_TOOL_BLOB, \
SCULPT_TOOL_LAYER, \
@@ -472,6 +499,7 @@ typedef enum eBrushUVSculptTool {
SCULPT_TOOL_CLAY, \
SCULPT_TOOL_CLAY_STRIPS, \
SCULPT_TOOL_ROTATE, \
+ SCULPT_TOOL_SCRAPE, \
SCULPT_TOOL_FLATTEN)
#define SCULPT_TOOL_HAS_NORMAL_WEIGHT(t) ELEM(t, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK)
@@ -484,8 +512,11 @@ typedef enum eBrushUVSculptTool {
SCULPT_TOOL_ROTATE, \
SCULPT_TOOL_THUMB, \
SCULPT_TOOL_LAYER, \
+ SCULPT_TOOL_DRAW_SHARP, \
+ SCULPT_TOOL_ELASTIC_DEFORM, \
+ SCULPT_TOOL_POSE, \
\
- /* These brushes could handle dynamic topology, \
+ /* These brushes could handle dynamic topology, \ \
* but user feedback indicates it's better not to */ \
SCULPT_TOOL_SMOOTH, \
SCULPT_TOOL_MASK) == 0)
@@ -495,6 +526,7 @@ typedef enum eBrushUVSculptTool {
SCULPT_TOOL_GRAB, \
SCULPT_TOOL_ROTATE, \
SCULPT_TOOL_THUMB, \
+ SCULPT_TOOL_DRAW_SHARP, \
SCULPT_TOOL_MASK) == 0)
/* ImagePaintSettings.tool */
diff --git a/source/blender/makesdna/DNA_cachefile_defaults.h b/source/blender/makesdna/DNA_cachefile_defaults.h
new file mode 100644
index 00000000000..4c4ff53ed90
--- /dev/null
+++ b/source/blender/makesdna/DNA_cachefile_defaults.h
@@ -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 DNA
+ */
+
+#ifndef __DNA_CACHEFILE_DEFAULTS_H__
+#define __DNA_CACHEFILE_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name CacheFile Struct
+ * \{ */
+
+#define _DNA_DEFAULT_CacheFile \
+ { \
+ .filepath[0] = '\0', \
+ .override_frame = false, \
+ .frame = 0.0f, \
+ .is_sequence = false, \
+ .scale = 1.0f, \
+ .object_paths ={NULL, NULL}, \
+ \
+ .handle = NULL, \
+ .handle_filepath[0] = '\0', \
+ .handle_readers = NULL, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_CACHEFILE_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_camera_defaults.h b/source/blender/makesdna/DNA_camera_defaults.h
new file mode 100644
index 00000000000..7a28f673ee4
--- /dev/null
+++ b/source/blender/makesdna/DNA_camera_defaults.h
@@ -0,0 +1,67 @@
+/*
+ * 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 DNA
+ */
+
+#ifndef __DNA_CAMERA_DEFAULTS_H__
+#define __DNA_CAMERA_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Camera Struct
+ * \{ */
+
+#define _DNA_DEFAULT_CameraDOFSettings \
+ { \
+ .aperture_fstop = 2.8f, \
+ .aperture_ratio = 1.0f, \
+ .focus_distance = 10.0f, \
+ }
+
+#define _DNA_DEFAULT_CameraStereoSettings \
+ { \
+ .interocular_distance = 0.065f, \
+ .convergence_distance = 30.f * 0.065f, \
+ .pole_merge_angle_from = DEG2RADF(60.0f), \
+ .pole_merge_angle_to = DEG2RADF(75.0f), \
+ }
+
+#define _DNA_DEFAULT_Camera \
+ { \
+ .lens = 50.0f, \
+ .sensor_x = DEFAULT_SENSOR_WIDTH, \
+ .sensor_y = DEFAULT_SENSOR_HEIGHT, \
+ .clip_start = 0.1f, \
+ .clip_end = 1000.0f, \
+ .drawsize = 1.0f, \
+ .ortho_scale = 6.0, \
+ .flag = CAM_SHOWPASSEPARTOUT, \
+ .passepartalpha = 0.5f, \
+ \
+ .dof = _DNA_DEFAULT_CameraDOFSettings, \
+ \
+ .stereo = _DNA_DEFAULT_CameraStereoSettings, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_CAMERA_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index eda52fdf14a..83fc4d2a3f7 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -271,7 +271,9 @@ typedef struct bTrackToConstraint {
typedef struct bRotateLikeConstraint {
struct Object *tar;
int flag;
- int reserved1;
+ char euler_order;
+ char mix_mode;
+ char _pad[2];
/** MAX_ID_NAME-2. */
char subtarget[64];
} bRotateLikeConstraint;
@@ -305,6 +307,8 @@ typedef struct bSameVolumeConstraint {
/* Copy Transform Constraint */
typedef struct bTransLikeConstraint {
struct Object *tar;
+ char mix_mode;
+ char _pad[7];
/** MAX_ID_NAME-2. */
char subtarget[64];
} bTransLikeConstraint;
@@ -441,6 +445,18 @@ typedef struct bTransformConstraint {
/** Extrapolate motion? if 0, confine to ranges. */
char expo;
+ /** Input rotation type - uses the same values as driver targets. */
+ char from_rotation_mode;
+ /** Output euler order override. */
+ char to_euler_order;
+
+ /** Mixing modes for location, rotation, and scale. */
+ char mix_mode_loc;
+ char mix_mode_rot;
+ char mix_mode_scale;
+
+ char _pad[3];
+
/** From_min/max defines range of target transform. */
float from_min[3];
/** To map on to to_min/max range. */
@@ -715,6 +731,20 @@ typedef enum eConstraintChannel_Flags {
CONSTRAINT_CHANNEL_PROTECTED = (1 << 1),
} eConstraintChannel_Flags;
+/* Common enum for constraints that support override. */
+typedef enum eConstraint_EulerOrder {
+ /** Automatic euler mode. */
+ CONSTRAINT_EULER_AUTO = 0,
+
+ /** Explicit euler rotation modes - must sync with BLI_math_rotation.h defines. */
+ CONSTRAINT_EULER_XYZ = 1,
+ CONSTRAINT_EULER_XZY,
+ CONSTRAINT_EULER_YXZ,
+ CONSTRAINT_EULER_YZX,
+ CONSTRAINT_EULER_ZXY,
+ CONSTRAINT_EULER_ZYX,
+} eConstraint_EulerOrder;
+
/* -------------------------------------- */
/* bRotateLikeConstraint.flag */
@@ -725,9 +755,25 @@ typedef enum eCopyRotation_Flags {
ROTLIKE_X_INVERT = (1 << 4),
ROTLIKE_Y_INVERT = (1 << 5),
ROTLIKE_Z_INVERT = (1 << 6),
+#ifdef DNA_DEPRECATED
ROTLIKE_OFFSET = (1 << 7),
+#endif
} eCopyRotation_Flags;
+/* bRotateLikeConstraint.mix_mode */
+typedef enum eCopyRotation_MixMode {
+ /* Replace rotation channel values. */
+ ROTLIKE_MIX_REPLACE = 0,
+ /* Legacy Offset mode - don't use. */
+ ROTLIKE_MIX_OFFSET,
+ /* Add Euler components together. */
+ ROTLIKE_MIX_ADD,
+ /* Multiply the copied rotation on the left. */
+ ROTLIKE_MIX_BEFORE,
+ /* Multiply the copied rotation on the right. */
+ ROTLIKE_MIX_AFTER,
+} eCopyRotation_MixMode;
+
/* bLocateLikeConstraint.flag */
typedef enum eCopyLocation_Flags {
LOCLIKE_X = (1 << 0),
@@ -748,8 +794,19 @@ typedef enum eCopyScale_Flags {
SIZELIKE_Z = (1 << 2),
SIZELIKE_OFFSET = (1 << 3),
SIZELIKE_MULTIPLY = (1 << 4),
+ SIZELIKE_UNIFORM = (1 << 5),
} eCopyScale_Flags;
+/* bTransLikeConstraint.mix_mode */
+typedef enum eCopyTransforms_MixMode {
+ /* Replace rotation channel values. */
+ TRANSLIKE_MIX_REPLACE = 0,
+ /* Multiply the copied transformation on the left, with anti-shear scale handling. */
+ TRANSLIKE_MIX_BEFORE,
+ /* Multiply the copied transformation on the right, with anti-shear scale handling. */
+ TRANSLIKE_MIX_AFTER,
+} eCopyTransforms_MixMode;
+
/* bTransformConstraint.to/from */
typedef enum eTransform_ToFrom {
TRANS_LOCATION = 0,
@@ -757,6 +814,34 @@ typedef enum eTransform_ToFrom {
TRANS_SCALE = 2,
} eTransform_ToFrom;
+/* bTransformConstraint.mix_mode_loc */
+typedef enum eTransform_MixModeLoc {
+ /* Add component values together (default). */
+ TRANS_MIXLOC_ADD = 0,
+ /* Replace component values. */
+ TRANS_MIXLOC_REPLACE,
+} eTransform_MixModeLoc;
+
+/* bTransformConstraint.mix_mode_rot */
+typedef enum eTransform_MixModeRot {
+ /* Add component values together (default). */
+ TRANS_MIXROT_ADD = 0,
+ /* Replace component values. */
+ TRANS_MIXROT_REPLACE,
+ /* Multiply the generated rotation on the left. */
+ TRANS_MIXROT_BEFORE,
+ /* Multiply the generated rotation on the right. */
+ TRANS_MIXROT_AFTER,
+} eTransform_MixModeRot;
+
+/* bTransformConstraint.mix_mode_scale */
+typedef enum eTransform_MixModeScale {
+ /* Replace component values (default). */
+ TRANS_MIXSCALE_REPLACE = 0,
+ /* Multiply component values together. */
+ TRANS_MIXSCALE_MULTIPLY,
+} eTransform_MixModeScale;
+
/* bSameVolumeConstraint.free_axis */
typedef enum eSameVolume_Axis {
SAMEVOL_X = 0,
diff --git a/source/blender/makesdna/DNA_curve_defaults.h b/source/blender/makesdna/DNA_curve_defaults.h
new file mode 100644
index 00000000000..0fdfd5713e9
--- /dev/null
+++ b/source/blender/makesdna/DNA_curve_defaults.h
@@ -0,0 +1,59 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_CURVE_DEFAULTS_H__
+#define __DNA_CURVE_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Curve Struct
+ * \{ */
+
+#define _DNA_DEFAULT_Curve \
+ { \
+ .size = {1, 1, 1}, \
+ .flag = CU_DEFORM_BOUNDS_OFF | CU_PATH_RADIUS, \
+ .pathlen = 100, \
+ .resolu = 12, \
+ .resolv = 12, \
+ .width = 1.0, \
+ .wordspace = 1.0, \
+ .spacing = 1.0f, \
+ .linedist = 1.0, \
+ .fsize = 1.0, \
+ .ulheight = 0.05, \
+ .texflag = CU_AUTOSPACE, \
+ .smallcaps_scale = 0.75f, \
+ /* This one seems to be the best one in most cases, at least for curve deform. */ \
+ .twist_mode = CU_TWIST_MINIMUM, \
+ .bevfac1 = 0.0f, \
+ .bevfac2 = 1.0f, \
+ .bevfac1_mapping = CU_BEVFAC_MAP_RESOLU, \
+ .bevfac2_mapping = CU_BEVFAC_MAP_RESOLU, \
+ .bevresol = 4, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_CURVE_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index bdb3db94c89..759029ad618 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -32,7 +32,6 @@
#define MAXTEXTBOX 256 /* used in readfile.c and editfont.c */
struct AnimData;
-struct BoundBox;
struct EditFont;
struct GHash;
struct Ipo;
@@ -212,8 +211,6 @@ typedef struct Curve {
/** Animation data (must be immediately after id for utilities to use it). */
struct AnimData *adt;
- struct BoundBox *bb;
-
/** Actual data, called splines in rna. */
ListBase nurb;
@@ -229,14 +226,13 @@ typedef struct Curve {
/* texture space, copied as one block in editobject.c */
float loc[3];
float size[3];
- float rot[3];
/** Creation-time type of curve datablock. */
short type;
/** Keep a short because of BKE_object_obdata_texspace_get(). */
short texflag;
- char _pad0[2];
+ char _pad0[6];
short twist_mode;
float twist_smooth, smallcaps_scale;
@@ -308,6 +304,7 @@ typedef struct Curve {
/* Curve.texflag */
enum {
CU_AUTOSPACE = 1,
+ CU_AUTOSPACE_EVALUATED = 2,
};
#if 0 /* Moved to overlay options in 2.8 */
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index 14a078d8386..9799489982d 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -197,6 +197,9 @@ typedef enum CustomDataType {
/** Data types that may be defined for all mesh elements types. */
#define CD_MASK_GENERIC_DATA (CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR)
+/** Multires loop data. */
+#define CD_MASK_MULTIRES_GRIDS (CD_MASK_MDISPS | CD_GRID_PAINT_MASK)
+
typedef struct CustomData_MeshMasks {
uint64_t vmask;
uint64_t emask;
diff --git a/source/blender/makesdna/DNA_defaults.h b/source/blender/makesdna/DNA_defaults.h
new file mode 100644
index 00000000000..5b9297ce46a
--- /dev/null
+++ b/source/blender/makesdna/DNA_defaults.h
@@ -0,0 +1,46 @@
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup DNA
+ *
+ * \see dna_defaults.c for details on how to use this system.
+ */
+
+#ifndef __DNA_DEFAULTS_H__
+#define __DNA_DEFAULTS_H__
+
+#include "dna_type_offsets.h"
+
+extern const void *DNA_default_table[SDNA_TYPE_MAX];
+
+char *_DNA_struct_default_alloc_impl(const char *data_src, size_t size, const char *alloc_str);
+
+/**
+ * Wrap with macro that casts correctly.
+ */
+#define DNA_struct_default_get(struct_name) \
+ (const struct_name *)DNA_default_table[SDNA_TYPE_FROM_STRUCT(struct_name)]
+
+#define DNA_struct_default_alloc(struct_name) \
+ (struct_name *)_DNA_struct_default_alloc_impl( \
+ DNA_default_table[SDNA_TYPE_FROM_STRUCT(struct_name)], sizeof(struct_name), __func__)
+
+#endif /* __DNA_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_genfile.h b/source/blender/makesdna/DNA_genfile.h
index dc4f5512b1a..db65da6fa75 100644
--- a/source/blender/makesdna/DNA_genfile.h
+++ b/source/blender/makesdna/DNA_genfile.h
@@ -103,6 +103,8 @@ void *DNA_struct_reconstruct(const struct SDNA *newsdna,
int DNA_elem_offset(struct SDNA *sdna, const char *stype, const char *vartype, const char *name);
+int DNA_elem_size_nr(const struct SDNA *sdna, short type, short name);
+
bool DNA_struct_find(const struct SDNA *sdna, const char *stype);
bool DNA_struct_elem_find(const struct SDNA *sdna,
const char *stype,
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index f094d630fc8..7d407dc85bc 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -200,6 +200,11 @@ typedef enum eModifyColorGpencil_Flag {
GP_MODIFY_COLOR_FILL = 2,
} eModifyColorGpencil_Flag;
+typedef enum eOpacityModesGpencil_Flag {
+ GP_OPACITY_MODE_MATERIAL = 0,
+ GP_OPACITY_MODE_STRENGTH = 1,
+} eOpacityModesGpencil_Flag;
+
typedef struct TintGpencilModifierData {
GpencilModifierData modifier;
/** Layer name. */
@@ -274,7 +279,9 @@ typedef struct OpacityGpencilModifierData {
float factor;
/** Modify stroke, fill or both. */
char modify_color;
- char _pad[3];
+ /** Mode of opacity, colors or strength */
+ char opacity_mode;
+ char _pad[2];
/** Custom index for passes. */
int layer_pass;
char _pad1[4];
diff --git a/source/blender/makesdna/DNA_image_defaults.h b/source/blender/makesdna/DNA_image_defaults.h
new file mode 100644
index 00000000000..e115f9e2b16
--- /dev/null
+++ b/source/blender/makesdna/DNA_image_defaults.h
@@ -0,0 +1,46 @@
+/*
+ * 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 DNA
+ */
+
+#ifndef __DNA_IMAGE_DEFAULTS_H__
+#define __DNA_IMAGE_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Struct
+ * \{ */
+
+#define _DNA_DEFAULT_Image \
+ { \
+ .aspx = 1.0, \
+ .aspy = 1.0, \
+ .gen_x = 1024, \
+ .gen_y = 1024, \
+ .gen_type = IMA_GENTYPE_GRID, \
+ \
+ .gpuframenr = INT_MAX, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_IMAGE_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_lattice_defaults.h b/source/blender/makesdna/DNA_lattice_defaults.h
new file mode 100644
index 00000000000..052aaba51d7
--- /dev/null
+++ b/source/blender/makesdna/DNA_lattice_defaults.h
@@ -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 DNA
+ */
+
+#ifndef __DNA_LATTICE_DEFAULTS_H__
+#define __DNA_LATTICE_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Lattice Struct
+ * \{ */
+
+#define _DNA_DEFAULT_Lattice \
+ { \
+ .flag = LT_GRID, \
+ .typeu = KEY_BSPLINE, \
+ .typev = KEY_BSPLINE, \
+ .typew = KEY_BSPLINE, \
+ .actbp = LT_ACTBP_NONE, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_LATTICE_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h
index 5f64e3220b7..3af1da46f80 100644
--- a/source/blender/makesdna/DNA_layer_types.h
+++ b/source/blender/makesdna/DNA_layer_types.h
@@ -45,6 +45,8 @@ typedef struct Base {
struct Object *object;
unsigned int lay DNA_DEPRECATED;
int flag_legacy;
+ unsigned short local_collections_bits;
+ short _pad2[3];
/* Pointer to an original base. Is initialized for evaluated view layer.
* NOTE: Only allowed to be accessed from within active dependency graph. */
@@ -66,8 +68,12 @@ typedef struct LayerCollection {
short flag;
short runtime_flag;
char _pad[4];
+
/** Synced with collection->children. */
ListBase layer_collections;
+
+ unsigned short local_collections_bits;
+ short _pad2[3];
} LayerCollection;
typedef struct ViewLayer {
diff --git a/source/blender/makesdna/DNA_light_defaults.h b/source/blender/makesdna/DNA_light_defaults.h
new file mode 100644
index 00000000000..dceaaf7c278
--- /dev/null
+++ b/source/blender/makesdna/DNA_light_defaults.h
@@ -0,0 +1,76 @@
+/*
+ * 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 DNA
+ */
+
+#ifndef __DNA_LIGHT_DEFAULTS_H__
+#define __DNA_LIGHT_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Light Struct
+ * \{ */
+
+#define _DNA_DEFAULT_Light \
+ { \
+ .r = 1.0f, \
+ .g = 1.0f, \
+ .b = 1.0f, \
+ .k = 1.0f, \
+ .energy = 10.0f, \
+ .dist = 25.0f, \
+ .spotsize = DEG2RADF(45.0f), \
+ .spotblend = 0.15f, \
+ .att2 = 1.0f, \
+ .mode = LA_SHADOW, \
+ .bufsize = 512, \
+ .clipsta = 0.05f, \
+ .clipend = 40.0f, \
+ .bleedexp = 2.5f, \
+ .samp = 3, \
+ .bias = 1.0f, \
+ .soft = 3.0f, \
+ .area_size = 0.25f, \
+ .area_sizey = 0.25f, \
+ .area_sizez = 0.25f, \
+ .buffers = 1, \
+ .preview = NULL, \
+ .falloff_type = LA_FALLOFF_INVSQUARE, \
+ .coeff_const = 1.0f, \
+ .coeff_lin = 0.0f, \
+ .coeff_quad = 0.0f, \
+ .cascade_max_dist = 200.0f, \
+ .cascade_count = 4, \
+ .cascade_exponent = 0.8f, \
+ .cascade_fade = 0.1f, \
+ .contact_dist = 0.2f, \
+ .contact_bias = 0.03f, \
+ .contact_spread = 0.2f, \
+ .contact_thickness = 0.2f, \
+ .spec_fac = 1.0f, \
+ .att_dist = 40.0f, \
+ .sun_angle = DEG2RADF(0.526f), \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_LIGHT_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_light_types.h b/source/blender/makesdna/DNA_light_types.h
index 82cab5d1594..ec83d53da5e 100644
--- a/source/blender/makesdna/DNA_light_types.h
+++ b/source/blender/makesdna/DNA_light_types.h
@@ -58,7 +58,10 @@ typedef struct Light {
char _pad2[2];
float clipsta, clipend;
- float bias, soft, bleedbias, bleedexp;
+ float bias;
+ float soft; /* DEPRECATED kept for compatibility. */
+ float bleedbias; /* DEPRECATED kept for compatibility. */
+ float bleedexp; /* DEPRECATED kept for compatibility. */
short bufsize, samp, buffers, filtertype;
char bufflag, buftype;
@@ -82,7 +85,10 @@ typedef struct Light {
float cascade_fade;
int cascade_count;
- float contact_dist, contact_bias, contact_spread, contact_thickness;
+ float contact_dist;
+ float contact_bias;
+ float contact_spread; /* DEPRECATED kept for compatibility. */
+ float contact_thickness;
float spec_fac, att_dist;
diff --git a/source/blender/makesdna/DNA_lightprobe_defaults.h b/source/blender/makesdna/DNA_lightprobe_defaults.h
new file mode 100644
index 00000000000..7c7732d17e4
--- /dev/null
+++ b/source/blender/makesdna/DNA_lightprobe_defaults.h
@@ -0,0 +1,51 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_LIGHTPROBE_DEFAULTS_H__
+#define __DNA_LIGHTPROBE_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name LightProbe Struct
+ * \{ */
+
+#define _DNA_DEFAULT_LightProbe \
+ { \
+ .grid_resolution_x = 4, \
+ .grid_resolution_y = 4, \
+ .grid_resolution_z = 4, \
+ .distinf = 2.5f, \
+ .distpar = 2.5f, \
+ .falloff = 0.2f, \
+ .clipsta = 0.8f, \
+ .clipend = 40.0f, \
+ .vis_bias = 1.0f, \
+ .vis_blur = 0.2f, \
+ .intensity = 1.0f, \
+ .flag = LIGHTPROBE_FLAG_SHOW_INFLUENCE, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_LIGHTPROBE_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_linestyle_defaults.h b/source/blender/makesdna/DNA_linestyle_defaults.h
new file mode 100644
index 00000000000..2f9203050d1
--- /dev/null
+++ b/source/blender/makesdna/DNA_linestyle_defaults.h
@@ -0,0 +1,61 @@
+/*
+ * 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 DNA
+ */
+
+#ifndef __DNA_LINESTYLE_DEFAULTS_H__
+#define __DNA_LINESTYLE_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name FreestyleLineStyle Struct
+ * \{ */
+
+#define _DNA_DEFAULT_FreestyleLineStyle \
+ { \
+ .panel = LS_PANEL_STROKES, \
+ .r = 0, \
+ .g = 0, \
+ .b = 0, \
+ .alpha = 1.0f, \
+ .thickness = 3.0f, \
+ .thickness_position = LS_THICKNESS_CENTER, \
+ .thickness_ratio = 0.5f, \
+ .flag = LS_SAME_OBJECT | LS_NO_SORTING | LS_TEXTURE, \
+ .chaining = LS_CHAINING_PLAIN, \
+ .rounds = 3, \
+ .min_angle = DEG2RADF(0.0f), \
+ .max_angle = DEG2RADF(0.0f), \
+ .min_length = 0.0f, \
+ .max_length = 10000.0f, \
+ .split_length = 100, \
+ .chain_count = 10, \
+ .sort_key = LS_SORT_KEY_DISTANCE_FROM_CAMERA, \
+ .integration_type = LS_INTEGRATION_MEAN, \
+ .texstep = 1.0f, \
+ .pr_texture = TEX_PR_TEXTURE, \
+ .caps = LS_CAPS_BUTT, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_LINESTYLE_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_material_defaults.h b/source/blender/makesdna/DNA_material_defaults.h
new file mode 100644
index 00000000000..cdcb1dd45f7
--- /dev/null
+++ b/source/blender/makesdna/DNA_material_defaults.h
@@ -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 DNA
+ */
+
+#ifndef __DNA_MATERIAL_DEFAULTS_H__
+#define __DNA_MATERIAL_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Material Struct
+ * \{ */
+
+#define _DNA_DEFAULT_Material \
+ { \
+ .r = 0.8, \
+ .g = 0.8, \
+ .b = 0.8, \
+ .specr = 1.0, \
+ .specg = 1.0, \
+ .specb = 1.0, \
+ .a = 1.0f, \
+ .spec = 0.5, \
+ \
+ .roughness = 0.4f, \
+ \
+ .pr_type = MA_SPHERE, \
+ \
+ .alpha_threshold = 0.5f, \
+ \
+ .blend_shadow = MA_BS_SOLID, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_MATERIAL_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_mesh_defaults.h b/source/blender/makesdna/DNA_mesh_defaults.h
new file mode 100644
index 00000000000..f605827d120
--- /dev/null
+++ b/source/blender/makesdna/DNA_mesh_defaults.h
@@ -0,0 +1,45 @@
+/*
+ * 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 DNA
+ */
+
+#ifndef __DNA_MESH_DEFAULTS_H__
+#define __DNA_MESH_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Struct
+ * \{ */
+
+#define _DNA_DEFAULT_Mesh \
+ { \
+ .size = {1.0f, 1.0f, 1.0f}, \
+ .smoothresh = DEG2RADF(30), \
+ .texflag = ME_AUTOSPACE, \
+ .remesh_voxel_size = 0.1f, \
+ .remesh_voxel_adaptivity = 0.0f, \
+ .flag = ME_REMESH_FIX_POLES | ME_REMESH_REPROJECT_VOLUME, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_MESH_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index cb6991ce67a..fb9e522dfa9 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -116,8 +116,6 @@ typedef struct Mesh {
/** Animation data (must be immediately after id for utilities to use it). */
struct AnimData *adt;
- struct BoundBox *bb;
-
/** Old animation system, deprecated for 2.5. */
struct Ipo *ipo DNA_DEPRECATED;
struct Key *key;
@@ -177,7 +175,6 @@ typedef struct Mesh {
/* texture space, copied as one block in editobject.c */
float loc[3];
float size[3];
- float rot[3];
short texflag, flag;
float smoothresh;
@@ -193,7 +190,9 @@ typedef struct Mesh {
short totcol;
float remesh_voxel_size;
- char _pad1[4];
+ float remesh_voxel_adaptivity;
+ char remesh_mode;
+ char _pad1[3];
/** Deprecated multiresolution modeling data, only keep for loading old files. */
struct Multires *mr DNA_DEPRECATED;
@@ -217,6 +216,7 @@ typedef struct TFace {
/* texflag */
enum {
ME_AUTOSPACE = 1,
+ ME_AUTOSPACE_EVALUATED = 2,
};
/* me->editflag */
@@ -252,6 +252,8 @@ enum {
ME_SCULPT_DYNAMIC_TOPOLOGY = 1 << 10,
ME_REMESH_SMOOTH_NORMALS = 1 << 11,
ME_REMESH_REPROJECT_PAINT_MASK = 1 << 12,
+ ME_REMESH_FIX_POLES = 1 << 13,
+ ME_REMESH_REPROJECT_VOLUME = 1 << 14,
};
/* me->cd_flag */
@@ -261,6 +263,12 @@ enum {
ME_CDFLAG_EDGE_CREASE = 1 << 2,
};
+/* me->remesh_mode */
+enum {
+ REMESH_VOXEL = 0,
+ REMESH_QUAD = 1,
+};
+
/* Subsurf Type */
enum {
ME_CC_SUBSURF = 0,
diff --git a/source/blender/makesdna/DNA_meta_defaults.h b/source/blender/makesdna/DNA_meta_defaults.h
new file mode 100644
index 00000000000..723f178ed58
--- /dev/null
+++ b/source/blender/makesdna/DNA_meta_defaults.h
@@ -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 DNA
+ */
+
+#ifndef __DNA_META_DEFAULTS_H__
+#define __DNA_META_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name MetaBall Struct
+ * \{ */
+
+#define _DNA_DEFAULT_MetaBall \
+ { \
+ .size = {1, 1, 1}, \
+ .texflag = MB_AUTOSPACE, \
+ .wiresize = 0.4f, \
+ .rendersize = 0.2f, \
+ .thresh = 0.6f, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_META_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 5243dc1aecd..cceeb9c71d5 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -1594,6 +1594,19 @@ enum {
MOD_LAPLACIANSMOOTH_NORMALIZED = (1 << 5),
};
+typedef struct CorrectiveSmoothDeltaCache {
+ /* delta's between the original positions and the smoothed positions */
+ float (*deltas)[3];
+ unsigned int totverts;
+
+ /* Value of settings when creating the cache.
+ * These are used to check if the cache should be recomputed. */
+ float lambda;
+ short repeat, flag;
+ char smooth_type, rest_source;
+ char _pad[2];
+} CorrectiveSmoothDeltaCache;
+
typedef struct CorrectiveSmoothModifierData {
ModifierData modifier;
@@ -1612,11 +1625,8 @@ typedef struct CorrectiveSmoothModifierData {
/** MAX_VGROUP_NAME. */
char defgrp_name[64];
- /* runtime-only cache (delta's between),
- * delta's between the original positions and the smoothed positions */
- float (*delta_cache)[3];
- unsigned int delta_cache_num;
- char _pad2[4];
+ /* runtime-only cache */
+ CorrectiveSmoothDeltaCache delta_cache;
} CorrectiveSmoothModifierData;
enum {
diff --git a/source/blender/makesdna/DNA_movieclip_types.h b/source/blender/makesdna/DNA_movieclip_types.h
index efda24d6e0e..8de79d9ea2b 100644
--- a/source/blender/makesdna/DNA_movieclip_types.h
+++ b/source/blender/makesdna/DNA_movieclip_types.h
@@ -97,7 +97,7 @@ typedef struct MovieClip {
struct MovieTracking tracking;
/**
* Context of tracking job used to synchronize data
- * like framenumber in SpaceClip clip user.
+ * like frame-number in SpaceClip clip user.
*/
void *tracking_context;
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index af66add01f3..7eecf23195a 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -276,7 +276,10 @@ typedef struct bNode {
short preview_xsize, preview_ysize;
/** Used at runtime when going through the tree. Initialize before use. */
short tmp_flag;
- char _pad2[2];
+ /** Used at runtime to tag derivatives branches. EEVEE only. */
+ char branch_tag;
+ /** Used at runtime when iterating over node branches. */
+ char iter_flag;
/** Runtime during drawing. */
struct uiBlock *block;
@@ -432,7 +435,7 @@ typedef struct bNodeTree {
int flag;
/** Update flags. */
int update;
- /** Flag to prevent reentrant update calls. */
+ /** Flag to prevent re-entrant update calls. */
short is_updating;
/** Generic temporary flag for recursion check (DFS/BFS). */
short done;
@@ -869,20 +872,22 @@ typedef struct NodeTexGradient {
typedef struct NodeTexNoise {
NodeTexBase base;
+ int dimensions;
+ char _pad[4];
} NodeTexNoise;
typedef struct NodeTexVoronoi {
NodeTexBase base;
- int coloring;
- int distance;
+ int dimensions;
int feature;
- char _pad[4];
+ int distance;
+ int coloring DNA_DEPRECATED;
} NodeTexVoronoi;
typedef struct NodeTexMusgrave {
NodeTexBase base;
int musgrave_type;
- char _pad[4];
+ int dimensions;
} NodeTexMusgrave;
typedef struct NodeTexWave {
@@ -994,6 +999,10 @@ typedef struct NodeShaderUVMap {
char uv_map[64];
} NodeShaderUVMap;
+typedef struct NodeShaderVertexColor {
+ char layer_name[64];
+} NodeShaderVertexColor;
+
typedef struct NodeShaderTexIES {
int mode;
@@ -1095,20 +1104,22 @@ typedef struct NodeDenoise {
#define SHD_NOISE_SOFT 0
#define SHD_NOISE_HARD 1
-/* voronoi texture */
-#define SHD_VORONOI_DISTANCE 0
-#define SHD_VORONOI_MANHATTAN 1
-#define SHD_VORONOI_CHEBYCHEV 2
-#define SHD_VORONOI_MINKOWSKI 3
+/* Voronoi Texture */
-#define SHD_VORONOI_INTENSITY 0
-#define SHD_VORONOI_CELLS 1
+enum {
+ SHD_VORONOI_EUCLIDEAN = 0,
+ SHD_VORONOI_MANHATTAN = 1,
+ SHD_VORONOI_CHEBYCHEV = 2,
+ SHD_VORONOI_MINKOWSKI = 3,
+};
-#define SHD_VORONOI_F1 0
-#define SHD_VORONOI_F2 1
-#define SHD_VORONOI_F3 2
-#define SHD_VORONOI_F4 3
-#define SHD_VORONOI_F2F1 4
+enum {
+ SHD_VORONOI_F1 = 0,
+ SHD_VORONOI_F2 = 1,
+ SHD_VORONOI_SMOOTH_F1 = 2,
+ SHD_VORONOI_DISTANCE_TO_EDGE = 3,
+ SHD_VORONOI_N_SPHERE_RADIUS = 4,
+};
/* musgrave texture */
#define SHD_MUSGRAVE_MULTIFRACTAL 0
@@ -1167,6 +1178,14 @@ typedef struct NodeDenoise {
#define SHD_AO_INSIDE 1
#define SHD_AO_LOCAL 2
+/* Mapping node vector types */
+enum {
+ NODE_MAPPING_TYPE_POINT = 0,
+ NODE_MAPPING_TYPE_TEXTURE = 1,
+ NODE_MAPPING_TYPE_VECTOR = 2,
+ NODE_MAPPING_TYPE_NORMAL = 3,
+};
+
/* math node clamp */
#define SHD_MATH_CLAMP 1
diff --git a/source/blender/makesdna/DNA_object_defaults.h b/source/blender/makesdna/DNA_object_defaults.h
new file mode 100644
index 00000000000..1105a8fd4e1
--- /dev/null
+++ b/source/blender/makesdna/DNA_object_defaults.h
@@ -0,0 +1,77 @@
+/*
+ * 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 DNA
+ */
+
+#ifndef __DNA_OBJECT_DEFAULTS_H__
+#define __DNA_OBJECT_DEFAULTS_H__
+
+#include "DNA_vec_defaults.h"
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Struct
+ * \{ */
+
+#define _DNA_DEFAULT_Object \
+ { \
+ /* Type is not very meaningful as a default, normally changed. */ \
+ .type = OB_EMPTY, \
+ .color = {1, 1, 1, 1}, \
+ \
+ .constinv = _DNA_DEFAULT_UNIT_M4, \
+ .parentinv = _DNA_DEFAULT_UNIT_M4, \
+ .obmat = _DNA_DEFAULT_UNIT_M4, \
+ \
+ .scale = {1, 1, 1}, \
+ .dscale = {1, 1, 1}, \
+ /* Objects should default to having Euler XYZ rotations, \
+ * but rotations default to quaternions. */ \
+ .rotmode = ROT_MODE_EUL, \
+ /** See #unit_axis_angle. */ \
+ .rotAxis = {0, 1, 0}, \
+ .rotAngle = 0, \
+ .drotAxis = {0, 1, 0}, \
+ .drotAngle = 0, \
+ .quat = _DNA_DEFAULT_UNIT_QT, \
+ .dquat = _DNA_DEFAULT_UNIT_QT, \
+ .protectflag = OB_LOCK_ROT4D, \
+ \
+ .dt = OB_TEXTURE, \
+ \
+ .empty_drawtype = OB_PLAINAXES, \
+ .empty_drawsize = 1.0, \
+ .empty_image_depth = OB_EMPTY_IMAGE_DEPTH_DEFAULT, \
+ .ima_ofs = {-0.5, -0.5}, \
+ \
+ .instance_faces_scale = 1, \
+ .col_group = 0x01, \
+ .col_mask = 0xffff, \
+ .preview = NULL, \
+ .duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER, \
+ .fluidsimSettings = NULL, \
+ .pc_ids = {NULL, NULL}, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_OBJECT_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index e006014b71f..82a90dfe7a2 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -162,12 +162,14 @@ typedef struct Object_Runtime {
struct Mesh *mesh_eval;
/**
* Mesh structure created during object evaluation.
- * It has deforemation only modifiers applied on it.
+ * It has deformation only modifiers applied on it.
*/
struct Mesh *mesh_deform_eval;
- /* This is a mesh representation of corresponding object.
- * It created when Python calls `object.to_mesh()`. */
+ /**
+ * This is a mesh representation of corresponding object.
+ * It created when Python calls `object.to_mesh()`.
+ */
struct Mesh *object_as_temp_mesh;
/** Runtime evaluated curve-specific data, not stored in the file. */
@@ -181,7 +183,8 @@ typedef struct Object_Runtime {
/** Runtime grease pencil evaluated data created by modifiers */
struct bGPDframe *gpencil_evaluated_frames;
- void *_pad2; /* Padding is here for win32s unconventional struct alignment rules. */
+ unsigned short local_collections_bits;
+ short _pad2[3];
} Object_Runtime;
typedef struct Object {
@@ -501,7 +504,7 @@ enum {
OB_DUPLIROT = 1 << 5,
OB_TRANSFLAG_UNUSED_6 = 1 << 6, /* cleared */
/* runtime, calculate derivedmesh for dupli before it's used */
- OB_DUPLICALCDERIVED = 1 << 7,
+ OB_TRANSFLAG_UNUSED_7 = 1 << 7, /* dirty */
OB_DUPLICOLLECTION = 1 << 8,
OB_DUPLIFACES = 1 << 9,
OB_DUPLIFACES_SCALE = 1 << 10,
@@ -605,7 +608,11 @@ enum {
/* NOTE: this was used as a proper setting in past, so nullify before using */
#define BA_TEMP_TAG (1 << 5)
-/* #define BA_FROMSET (1 << 7) */ /*UNUSED*/
+/**
+ * Even if this is is tagged for transform, this flag means it's being locked in place.
+ * Use for #SCE_XFORM_SKIP_CHILDREN.
+ */
+#define BA_TRANSFORM_LOCKED_IN_PLACE (1 << 7)
#define BA_TRANSFORM_CHILD (1 << 8) /* child of a transformed object */
#define BA_TRANSFORM_PARENT (1 << 13) /* parent of a transformed object */
@@ -684,6 +691,7 @@ enum {
OB_EMPTY_IMAGE_HIDE_ORTHOGRAPHIC = 1 << 1,
OB_EMPTY_IMAGE_HIDE_BACK = 1 << 2,
OB_EMPTY_IMAGE_HIDE_FRONT = 1 << 3,
+ OB_EMPTY_IMAGE_HIDE_NON_AXIS_ALIGNED = 1 << 4,
};
/** #Object.empty_image_flag */
diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h
new file mode 100644
index 00000000000..8d77e57c959
--- /dev/null
+++ b/source/blender/makesdna/DNA_scene_defaults.h
@@ -0,0 +1,368 @@
+/*
+ * 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 DNA
+ */
+
+#ifndef __DNA_SCENE_DEFAULTS_H__
+#define __DNA_SCENE_DEFAULTS_H__
+
+#include "DNA_view3d_defaults.h"
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Scene Struct
+ * \{ */
+
+#define _DNA_DEFAULT_ImageFormatData \
+ { \
+ .planes = R_IMF_PLANES_RGBA, \
+ .imtype = R_IMF_IMTYPE_PNG, \
+ .depth = R_IMF_CHAN_DEPTH_8, \
+ .quality = 90, \
+ .compress = 15, \
+ }
+
+#define _DNA_DEFAULT_BakeData \
+ { \
+ .im_format = _DNA_DEFAULT_ImageFormatData, \
+ .filepath = "//", \
+ .flag = R_BAKE_CLEAR, \
+ .pass_filter = R_BAKE_PASS_FILTER_ALL, \
+ .width = 512, \
+ .height = 512, \
+ .margin = 16, \
+ .normal_space = R_BAKE_SPACE_TANGENT, \
+ .normal_swizzle = {R_BAKE_POSX, R_BAKE_POSY, R_BAKE_POSZ}, \
+ }
+
+#define _DNA_DEFAULT_FFMpegCodecData \
+ { \
+ .audio_mixrate = 48000, \
+ .audio_volume = 1.0f, \
+ .audio_bitrate = 192, \
+ .audio_channels = 2, \
+ }
+
+#define _DNA_DEFAULT_DisplaySafeAreas \
+ { \
+ .title = {10.0f / 100.0f, 5.0f / 100.0f}, \
+ .action = {3.5f / 100.0f, 3.5f / 100.0f}, \
+ .title_center = {17.5f / 100.0f, 5.0f / 100.0f}, \
+ .action_center = {15.0f / 100.0f, 5.0f / 100.0f}, \
+ }
+
+#define _DNA_DEFAULT_RenderData \
+ { \
+ .mode = 0, \
+ .cfra = 1, \
+ .sfra = 1, \
+ .efra = 250, \
+ .frame_step = 1, \
+ .xsch = 1920, \
+ .ysch = 1080, \
+ .xasp = 1, \
+ .yasp = 1, \
+ .tilex = 256, \
+ .tiley = 256, \
+ .size = 100, \
+ \
+ .im_format = _DNA_DEFAULT_ImageFormatData, \
+ \
+ .displaymode = R_OUTPUT_WINDOW, \
+ .framapto = 100, \
+ .images = 100, \
+ .framelen = 1.0, \
+ .blurfac = 0.5, \
+ .frs_sec = 24, \
+ .frs_sec_base = 1, \
+ \
+ /* OCIO_TODO: for forwards compatibility only, so if no tone-curve are used, \
+ * images would look in the same way as in current blender \
+ * \
+ * perhaps at some point should be completely deprecated? \
+ */ \
+ .color_mgt_flag = R_COLOR_MANAGEMENT, \
+ \
+ .gauss = 1.5, \
+ .dither_intensity = 1.0f, \
+ \
+ .bake_mode = 0, \
+ .bake_filter = 16, \
+ .bake_flag = R_BAKE_CLEAR, \
+ .bake_samples = 256, \
+ .bake_biasdist = 0.001f, \
+ \
+ /* BakeData */ \
+ .bake = _DNA_DEFAULT_BakeData, \
+ \
+ .scemode = R_DOCOMP | R_DOSEQ | R_EXTENSION, \
+ \
+ .pic = "//", \
+ \
+ .stamp = R_STAMP_TIME | R_STAMP_FRAME | R_STAMP_DATE | R_STAMP_CAMERA | R_STAMP_SCENE | \
+ R_STAMP_FILENAME | R_STAMP_RENDERTIME | R_STAMP_MEMORY, \
+ .stamp_font_id = 12, \
+ .fg_stamp = {0.8f, 0.8f, 0.8f, 1.0f}, \
+ .bg_stamp = {0.0f, 0.0f, 0.0f, 0.25f}, \
+ \
+ .seq_prev_type = OB_SOLID, \
+ .seq_rend_type = OB_SOLID, \
+ .seq_flag = 0, \
+ \
+ .threads = 1, \
+ \
+ .simplify_subsurf = 6, \
+ .simplify_particles = 1.0f, \
+ \
+ .border.xmin = 0.0f, \
+ .border.ymin = 0.0f, \
+ .border.xmax = 1.0f, \
+ .border.ymax = 1.0f, \
+ \
+ .preview_start_resolution = 64, \
+ \
+ .line_thickness_mode = R_LINE_THICKNESS_ABSOLUTE, \
+ .unit_line_thickness = 1.0f, \
+ \
+ .ffcodecdata = _DNA_DEFAULT_FFMpegCodecData, \
+ }
+
+#define _DNA_DEFAULT_AudioData \
+ { \
+ .distance_model = 2.0f, \
+ .doppler_factor = 1.0f, \
+ .speed_of_sound = 343.3f, \
+ .volume = 1.0f, \
+ .flag = AUDIO_SYNC, \
+ }
+
+#define _DNA_DEFAULT_SceneDisplay \
+ { \
+ .light_direction = {M_SQRT1_3, M_SQRT1_3, M_SQRT1_3}, \
+ .shadow_shift = 0.1f, \
+ .shadow_focus = 0.0f, \
+ \
+ .matcap_ssao_distance = 0.2f, \
+ .matcap_ssao_attenuation = 1.0f, \
+ .matcap_ssao_samples = 16, \
+ \
+ .shading = _DNA_DEFAULT_View3DShading, \
+ \
+ .render_aa = SCE_DISPLAY_AA_SAMPLES_8, \
+ .viewport_aa = SCE_DISPLAY_AA_FXAA, \
+ }
+
+#define _DNA_DEFAULT_PhysicsSettings \
+ { \
+ .gravity = {0.0f, 0.0f -9.81f}, \
+ .flag = PHYS_GLOBAL_GRAVITY, \
+ }
+
+#define _DNA_DEFAULT_SceneEEVEE \
+ { \
+ .gi_diffuse_bounces = 3, \
+ .gi_cubemap_resolution = 512, \
+ .gi_visibility_resolution = 32, \
+ .gi_cubemap_draw_size = 0.3f, \
+ .gi_irradiance_draw_size = 0.1f, \
+ .gi_irradiance_smoothing = 0.1f, \
+ .gi_filter_quality = 3.0f, \
+ \
+ .taa_samples = 16, \
+ .taa_render_samples = 64, \
+ \
+ .sss_samples = 7, \
+ .sss_jitter_threshold = 0.3f, \
+ \
+ .ssr_quality = 0.25f, \
+ .ssr_max_roughness = 0.5f, \
+ .ssr_thickness = 0.2f, \
+ .ssr_border_fade = 0.075f, \
+ .ssr_firefly_fac = 10.0f, \
+ \
+ .volumetric_start = 0.1f, \
+ .volumetric_end = 100.0f, \
+ .volumetric_tile_size = 8, \
+ .volumetric_samples = 64, \
+ .volumetric_sample_distribution = 0.8f, \
+ .volumetric_light_clamp = 0.0f, \
+ .volumetric_shadow_samples = 16, \
+ \
+ .gtao_distance = 0.2f, \
+ .gtao_factor = 1.0f, \
+ .gtao_quality = 0.25f, \
+ \
+ .bokeh_max_size = 100.0f, \
+ .bokeh_threshold = 1.0f, \
+ \
+ .bloom_color = {1.0f, 1.0f, 1.0f}, \
+ .bloom_threshold = 0.8f, \
+ .bloom_knee = 0.5f, \
+ .bloom_intensity = 0.05f, \
+ .bloom_radius = 6.5f, \
+ .bloom_clamp = 0.0f, \
+ \
+ .motion_blur_samples = 8, \
+ .motion_blur_shutter = 0.5f, \
+ \
+ .shadow_cube_size = 512, \
+ .shadow_cascade_size = 1024, \
+ \
+ .light_cache = NULL, \
+ .light_threshold = 0.01f, \
+ \
+ .overscan = 3.0f, \
+ \
+ .flag = SCE_EEVEE_VOLUMETRIC_LIGHTS | SCE_EEVEE_GTAO_BENT_NORMALS | \
+ SCE_EEVEE_GTAO_BOUNCE | SCE_EEVEE_TAA_REPROJECTION | \
+ SCE_EEVEE_SSR_HALF_RESOLUTION | SCE_EEVEE_SHADOW_SOFT, \
+ }
+
+#define _DNA_DEFAULT_Scene \
+ { \
+ .cursor = _DNA_DEFAULT_View3DCursor, \
+ .r = _DNA_DEFAULT_RenderData, \
+ .audio = _DNA_DEFAULT_AudioData, \
+ \
+ .display = _DNA_DEFAULT_SceneDisplay, \
+ \
+ .physics_settings = _DNA_DEFAULT_PhysicsSettings, \
+ \
+ .safe_areas = _DNA_DEFAULT_DisplaySafeAreas, \
+ \
+ .eevee = _DNA_DEFAULT_SceneEEVEE, \
+ }
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ToolSettings Struct
+ * \{ */
+
+#define _DNA_DEFAULTS_CurvePaintSettings \
+ { \
+ .curve_type = CU_BEZIER, \
+ .flag = CURVE_PAINT_FLAG_CORNERS_DETECT, \
+ .error_threshold = 8, \
+ .radius_max = 1.0f, \
+ .corner_angle = DEG2RADF(70.0f), \
+ }
+
+#define _DNA_DEFAULTS_ImagePaintSettings \
+ { \
+ .paint.flags = PAINT_SHOW_BRUSH, \
+ .normal_angle = 80, \
+ .seam_bleed = 2, \
+ }
+
+#define _DNA_DEFAULTS_ParticleBrushData \
+ { \
+ .strength = 0.5f, \
+ .size = 50, \
+ .step = 10, \
+ .count = 10, \
+ }
+
+#define _DNA_DEFAULTS_ParticleEditSettings \
+ { \
+ .flag = PE_KEEP_LENGTHS | PE_LOCK_FIRST | PE_DEFLECT_EMITTER | PE_AUTO_VELOCITY, \
+ .emitterdist = 0.25f, \
+ .totrekey = 5, \
+ .totaddkey = 5, \
+ .brushtype = PE_BRUSH_COMB, \
+ \
+ /* Scene init copies this to all other elements. */ \
+ .brush = {_DNA_DEFAULTS_ParticleBrushData}, \
+ \
+ .draw_step = 2, \
+ .fade_frames = 2, \
+ .selectmode = SCE_SELECT_PATH, \
+ }
+
+#define _DNA_DEFAULTS_GP_Sculpt_Guide \
+ { \
+ .spacing = 20.0f, \
+ }
+
+#define _DNA_DEFAULTS_GP_Sculpt_Settings \
+ { \
+ .guide = _DNA_DEFAULTS_GP_Sculpt_Guide, \
+ }
+
+#define _DNA_DEFAULTS_MeshStatVis \
+ { \
+ .overhang_axis = OB_NEGZ, \
+ .overhang_min = 0, \
+ .overhang_max = DEG2RADF(45.0f), \
+ .thickness_max = 0.1f, \
+ .thickness_samples = 1, \
+ .distort_min = DEG2RADF(5.0f), \
+ .distort_max = DEG2RADF(45.0f), \
+ \
+ .sharp_min = DEG2RADF(90.0f), \
+ .sharp_max = DEG2RADF(180.0f), \
+ }
+
+#define _DNA_DEFAULT_ToolSettings \
+ { \
+ .object_flag = SCE_OBJECT_MODE_LOCK, \
+ .doublimit = 0.001, \
+ .vgroup_weight = 1.0f, \
+ .uvcalc_margin = 0.001f, \
+ .uvcalc_flag = UVCALC_TRANSFORM_CORRECT, \
+ .unwrapper = 1, \
+ .select_thresh = 0.01f, \
+ \
+ .selectmode = SCE_SELECT_VERTEX, \
+ .uv_selectmode = UV_SELECT_VERTEX, \
+ .autokey_mode = AUTOKEY_MODE_NORMAL, \
+ \
+ .transform_pivot_point = V3D_AROUND_CENTER_MEDIAN, \
+ .snap_mode = SCE_SNAP_MODE_INCREMENT, \
+ .snap_node_mode = SCE_SNAP_MODE_GRID, \
+ .snap_uv_mode = SCE_SNAP_MODE_INCREMENT, \
+ .snap_transform_mode_flag = SCE_SNAP_TRANSFORM_MODE_TRANSLATE, \
+ \
+ .curve_paint_settings = _DNA_DEFAULTS_CurvePaintSettings, \
+ \
+ .statvis = _DNA_DEFAULTS_MeshStatVis, \
+ \
+ .proportional_size = 1.0f, \
+ \
+ .imapaint = _DNA_DEFAULTS_ImagePaintSettings, \
+ \
+ .particle = _DNA_DEFAULTS_ParticleEditSettings, \
+ \
+ .gp_sculpt = _DNA_DEFAULTS_GP_Sculpt_Settings, \
+ \
+ /* Annotations */ \
+ .annotate_v3d_align = GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR, \
+ .annotate_thickness = 3, \
+ \
+ /* GP Stroke Placement */ \
+ .gpencil_v3d_align = GP_PROJECT_VIEWSPACE, \
+ .gpencil_v2d_align = GP_PROJECT_VIEWSPACE, \
+ .gpencil_seq_align = GP_PROJECT_VIEWSPACE, \
+ .gpencil_ima_align = GP_PROJECT_VIEWSPACE, \
+ }
+
+/* clang-format off */
+
+#endif /* __DNA_SCENE_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 412bf358a44..ca572f1ddf1 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -669,9 +669,8 @@ typedef struct RenderData {
char _pad0[1];
- /* safety, border and display rect */
- rctf safety, border;
- rcti disprect;
+ /** Render border to render sub-resions. */
+ rctf border;
/* information on different layers to be rendered */
/** Converted to Scene->view_layers. */
@@ -1366,6 +1365,12 @@ typedef struct MeshStatVis {
/* *************************************************************** */
/* Tool Settings */
+/* CurvePaintSettings.surface_plane */
+enum {
+ AUTO_MERGE = 1 << 0,
+ AUTO_MERGE_AND_SPLIT = 1 << 1,
+};
+
typedef struct ToolSettings {
/** Vertex paint. */
VPaint *vpaint;
@@ -1631,7 +1636,7 @@ typedef struct SceneEEVEE {
int motion_blur_samples;
float motion_blur_shutter;
- int shadow_method;
+ int shadow_method DNA_DEPRECATED;
int shadow_cube_size;
int shadow_cascade_size;
@@ -1974,6 +1979,8 @@ extern const char *RE_engine_id_CYCLES;
#define BASE_VISIBLE(v3d, base) \
(((v3d == NULL) || ((v3d)->localvd == NULL) || \
((v3d)->local_view_uuid & (base)->local_view_bits)) && \
+ ((v3d == NULL) || (((v3d)->flag & V3D_LOCAL_COLLECTIONS) == 0) || \
+ ((v3d)->local_collections_uuid & (base)->local_collections_bits)) && \
((v3d == NULL) || \
(((1 << (base)->object->type) & (v3d)->object_type_exclude_viewport) == 0)) && \
(((base)->flag & BASE_VISIBLE) != 0))
@@ -1996,6 +2003,8 @@ extern const char *RE_engine_id_CYCLES;
(((workspace)->object_mode & OD_MODE_EDIT) ? OBACT(_view_layer) : NULL)
#define OBEDIT_FROM_OBACT(ob) ((ob) ? (((ob)->mode & OB_MODE_EDIT) ? ob : NULL) : NULL)
#define OBPOSE_FROM_OBACT(ob) ((ob) ? (((ob)->mode & OB_MODE_POSE) ? ob : NULL) : NULL)
+#define OBWEIGHTPAINT_FROM_OBACT(ob) \
+ ((ob) ? (((ob)->mode & OB_MODE_WEIGHT_PAINT) ? ob : NULL) : NULL)
#define OBEDIT_FROM_VIEW_LAYER(view_layer) OBEDIT_FROM_OBACT(OBACT(view_layer))
#define V3D_CAMERA_LOCAL(v3d) ((!(v3d)->scenelock && (v3d)->camera) ? (v3d)->camera : NULL)
@@ -2019,6 +2028,7 @@ extern const char *RE_engine_id_CYCLES;
enum {
SCE_XFORM_AXIS_ALIGN = (1 << 0),
SCE_XFORM_DATA_ORIGIN = (1 << 1),
+ SCE_XFORM_SKIP_CHILDREN = (1 << 2),
};
/* ToolSettings.object_flag */
@@ -2284,6 +2294,8 @@ typedef enum eGPencil_SimplifyFlags {
SIMPLIFY_GPENCIL_FX = (1 << 5),
/* Simplify layer blending */
SIMPLIFY_GPENCIL_BLEND = (1 << 6),
+ /* Simplify layer tint */
+ SIMPLIFY_GPENCIL_TINT = (1 << 7),
} eGPencil_SimplifyFlags;
/* ToolSettings.gpencil_*_align - Stroke Placement mode flags */
@@ -2317,6 +2329,7 @@ typedef enum eGPencil_GuideTypes {
GP_GUIDE_RADIAL,
GP_GUIDE_PARALLEL,
GP_GUIDE_GRID,
+ GP_GUIDE_ISO,
} eGPencil_GuideTypes;
/* ToolSettings.gpencil_guide_references */
@@ -2383,7 +2396,7 @@ enum {
SCE_EEVEE_SHADOW_HIGH_BITDEPTH = (1 << 10),
SCE_EEVEE_TAA_REPROJECTION = (1 << 11),
// SCE_EEVEE_SSS_ENABLED = (1 << 12), /* Unused */
- SCE_EEVEE_SSS_SEPARATE_ALBEDO = (1 << 13),
+ // SCE_EEVEE_SSS_SEPARATE_ALBEDO = (1 << 13), /* Unused */
SCE_EEVEE_SSR_ENABLED = (1 << 14),
SCE_EEVEE_SSR_REFRACTION = (1 << 15),
SCE_EEVEE_SSR_HALF_RESOLUTION = (1 << 16),
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index aab71c15e44..bf491e2eaea 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -458,16 +458,18 @@ enum {
#ifdef DNA_DEPRECATED_ALLOW
AREA_TEMP_INFO = (1 << 3), /* versioned to make slot reusable */
#endif
- /* update size of regions within the area */
+ /** Update size of regions within the area. */
AREA_FLAG_REGION_SIZE_UPDATE = (1 << 3),
AREA_FLAG_ACTIVE_TOOL_UPDATE = (1 << 4),
// AREA_FLAG_UNUSED_5 = (1 << 5),
- /* used to check if we should switch back to prevspace (of a different type) */
+ /** Used to check if we should switch back to prevspace (of a different type). */
AREA_FLAG_TEMP_TYPE = (1 << 6),
- /* for temporary fullscreens (file browser, image editor render)
- * that are opened above user set fullscreens */
+ /**
+ * For temporary full-screens (file browser, image editor render)
+ * that are opened above user set full-screens.
+ */
AREA_FLAG_STACKED_FULLSCREEN = (1 << 7),
- /* update action zones (even if the mouse is not intersecting them) */
+ /** Update action zones (even if the mouse is not intersecting them). */
AREA_FLAG_ACTIONZONES_UPDATE = (1 << 8),
};
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 087d30ce312..8d9dc77c49b 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -270,6 +270,8 @@ typedef struct Editing {
/* Cache control */
float recycle_max_cost;
int cache_flag;
+
+ struct PrefetchJob *prefetch_job;
} Editing;
/* ************* Effect Variable Structs ********* */
@@ -674,6 +676,8 @@ enum {
SEQ_CACHE_VIEW_PREPROCESSED = (1 << 7),
SEQ_CACHE_VIEW_COMPOSITE = (1 << 8),
SEQ_CACHE_VIEW_FINAL_OUT = (1 << 9),
+
+ SEQ_CACHE_PREFETCH_ENABLE = (1 << 10),
};
#endif /* __DNA_SEQUENCE_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 1691d873f9b..0f957a946d9 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -676,9 +676,10 @@ typedef struct FileSelectParams {
short sort;
/** Display mode flag. */
short display;
- short display_previous;
+ /** Details toggles (file size, creation date, etc.) */
+ char details_flags;
+ char _pad2[3];
/** Filter when (flags & FILE_FILTER) is true. */
- char _pad2[2];
int filter;
/** Max number of levels in dirtree to show at once, 0 to disable recursion. */
@@ -736,8 +737,8 @@ typedef struct SpaceFile {
/* FileSelectParams.display */
enum eFileDisplayType {
FILE_DEFAULTDISPLAY = 0,
- FILE_SHORTDISPLAY = 1,
- FILE_LONGDISPLAY = 2,
+ FILE_VERTICALDISPLAY = 1,
+ FILE_HORIZONTALDISPLAY = 2,
FILE_IMGDISPLAY = 3,
};
@@ -750,6 +751,12 @@ enum eFileSortType {
FILE_SORT_SIZE = 4,
};
+/* FileSelectParams.details_flags */
+enum eFileDetails {
+ FILE_DETAILS_SIZE = (1 << 0),
+ FILE_DETAILS_DATETIME = (1 << 1),
+};
+
/* these values need to be hardcoded in structs, dna does not recognize defines */
/* also defined in BKE */
#define FILE_MAXDIR 768
@@ -787,6 +794,9 @@ typedef enum eFileSel_Params_Flag {
FILE_FILTER = (1 << 8),
FILE_PARAMS_FLAG_UNUSED_9 = (1 << 9), /* cleared */
FILE_GROUP_INSTANCE = (1 << 10),
+ FILE_SORT_INVERT = (1 << 11),
+ FILE_HIDE_TOOL_PROPS = (1 << 12),
+ FILE_CHECK_EXISTING = (1 << 13),
} eFileSel_Params_Flag;
/* sfile->params->rename_flag */
@@ -815,7 +825,7 @@ typedef enum eFileSel_File_Types {
FILE_TYPE_FTFONT = (1 << 7),
FILE_TYPE_SOUND = (1 << 8),
FILE_TYPE_TEXT = (1 << 9),
- /* 1 << 10 was FILE_TYPE_MOVIE_ICON, got rid of this so free slot for future type... */
+ FILE_TYPE_ARCHIVE = (1 << 10),
/** represents folders for filtering */
FILE_TYPE_FOLDER = (1 << 11),
FILE_TYPE_BTX = (1 << 12),
@@ -824,6 +834,8 @@ typedef enum eFileSel_File_Types {
FILE_TYPE_OPERATOR = (1 << 14),
FILE_TYPE_APPLICATIONBUNDLE = (1 << 15),
FILE_TYPE_ALEMBIC = (1 << 16),
+ /** For all kinds of recognized import/export formats. No need for specialized types. */
+ FILE_TYPE_OBJECT_IO = (1 << 17),
/** An FS directory (i.e. S_ISDIR on its path is true). */
FILE_TYPE_DIR = (1 << 30),
@@ -882,8 +894,7 @@ typedef struct FileDirEntryRevision {
int64_t time;
/* Temp caching of UI-generated strings... */
char size_str[16];
- char time_str[8];
- char date_str[16];
+ char datetime_str[16 + 8];
} FileDirEntryRevision;
/* Container for a variant, only relevant in asset context.
@@ -1118,8 +1129,6 @@ typedef enum eSpaceImage_Flag {
SI_SHOW_R = (1 << 27),
SI_SHOW_G = (1 << 28),
SI_SHOW_B = (1 << 29),
-
- SI_NO_DRAWEDGES = (1 << 30),
} eSpaceImage_Flag;
/* SpaceImage.other_uv_filter */
diff --git a/source/blender/makesdna/DNA_speaker_defaults.h b/source/blender/makesdna/DNA_speaker_defaults.h
new file mode 100644
index 00000000000..d252a447701
--- /dev/null
+++ b/source/blender/makesdna/DNA_speaker_defaults.h
@@ -0,0 +1,51 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_SPEAKER_DEFAULTS_H__
+#define __DNA_SPEAKER_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Speaker Struct
+ * \{ */
+
+#define _DNA_DEFAULT_Speaker \
+ { \
+ .attenuation = 1.0f, \
+ .cone_angle_inner = 360.0f, \
+ .cone_angle_outer = 360.0f, \
+ .cone_volume_outer = 1.0f, \
+ .distance_max = FLT_MAX, \
+ .distance_reference = 1.0f, \
+ .flag = 0, \
+ .pitch = 1.0f, \
+ .sound = NULL, \
+ .volume = 1.0f, \
+ .volume_max = 1.0f, \
+ .volume_min = 0.0f, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_SPEAKER_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_texture_defaults.h b/source/blender/makesdna/DNA_texture_defaults.h
new file mode 100644
index 00000000000..d5097c5ea21
--- /dev/null
+++ b/source/blender/makesdna/DNA_texture_defaults.h
@@ -0,0 +1,155 @@
+/*
+ * 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 DNA
+ */
+
+#ifndef __DNA_TEXTURE_DEFAULTS_H__
+#define __DNA_TEXTURE_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Texture Struct
+ * \{ */
+
+#define _DNA_DEFAULT_MTex \
+ { \
+ .texco = TEXCO_UV, \
+ .mapto = MAP_COL, \
+ .object = NULL, \
+ .projx = PROJ_X, \
+ .projy = PROJ_Y, \
+ .projz = PROJ_Z, \
+ .mapping = MTEX_FLAT, \
+ .ofs[0] = 0.0, \
+ .ofs[1] = 0.0, \
+ .ofs[2] = 0.0, \
+ .size[0] = 1.0, \
+ .size[1] = 1.0, \
+ .size[2] = 1.0, \
+ .tex = NULL, \
+ .colormodel = 0, \
+ .r = 1.0, \
+ .g = 0.0, \
+ .b = 1.0, \
+ .k = 1.0, \
+ .def_var = 1.0, \
+ .blendtype = MTEX_BLEND, \
+ .colfac = 1.0, \
+ .norfac = 1.0, \
+ .varfac = 1.0, \
+ .dispfac = 0.2, \
+ .colspecfac = 1.0f, \
+ .mirrfac = 1.0f, \
+ .alphafac = 1.0f, \
+ .difffac = 1.0f, \
+ .specfac = 1.0f, \
+ .emitfac = 1.0f, \
+ .hardfac = 1.0f, \
+ .raymirrfac = 1.0f, \
+ .translfac = 1.0f, \
+ .ambfac = 1.0f, \
+ .colemitfac = 1.0f, \
+ .colreflfac = 1.0f, \
+ .coltransfac = 1.0f, \
+ .densfac = 1.0f, \
+ .scatterfac = 1.0f, \
+ .reflfac = 1.0f, \
+ .shadowfac = 1.0f, \
+ .zenupfac = 1.0f, \
+ .zendownfac = 1.0f, \
+ .blendfac = 1.0f, \
+ .timefac = 1.0f, \
+ .lengthfac = 1.0f, \
+ .clumpfac = 1.0f, \
+ .kinkfac = 1.0f, \
+ .kinkampfac = 1.0f, \
+ .roughfac = 1.0f, \
+ .twistfac = 1.0f, \
+ .padensfac = 1.0f, \
+ .lifefac = 1.0f, \
+ .sizefac = 1.0f, \
+ .ivelfac = 1.0f, \
+ .dampfac = 1.0f, \
+ .gravityfac = 1.0f, \
+ .fieldfac = 1.0f, \
+ .normapspace = MTEX_NSPACE_TANGENT, \
+ .brush_map_mode = MTEX_MAP_MODE_TILED, \
+ .random_angle = 2.0f * (float)M_PI, \
+ .brush_angle_mode = 0, \
+ } \
+
+#define _DNA_DEFAULT_Tex \
+ { \
+ .type = TEX_IMAGE, \
+ .ima = NULL, \
+ .stype = 0, \
+ .flag = TEX_CHECKER_ODD, \
+ .imaflag = TEX_INTERPOL | TEX_MIPMAP | TEX_USEALPHA, \
+ .extend = TEX_REPEAT, \
+ .cropxmin = 0.0, \
+ .cropymin = 0.0, \
+ .cropxmax = 1.0, \
+ .cropymax = 1.0, \
+ .texfilter = TXF_EWA, \
+ .afmax = 8, \
+ .xrepeat = 1, \
+ .yrepeat = 1, \
+ .sfra = 1, \
+ .frames = 0, \
+ .offset = 0, \
+ .noisesize = 0.25, \
+ .noisedepth = 2, \
+ .turbul = 5.0, \
+ .nabla = 0.025, /* also in do_versions. */ \
+ .bright = 1.0, \
+ .contrast = 1.0, \
+ .saturation = 1.0, \
+ .filtersize = 1.0, \
+ .rfac = 1.0, \
+ .gfac = 1.0, \
+ .bfac = 1.0, \
+ /* newnoise: init. */ \
+ .noisebasis = 0, \
+ .noisebasis2 = 0, \
+ /* musgrave */ \
+ .mg_H = 1.0, \
+ .mg_lacunarity = 2.0, \
+ .mg_octaves = 2.0, \
+ .mg_offset = 1.0, \
+ .mg_gain = 1.0, \
+ .ns_outscale = 1.0, \
+ /* distnoise */ \
+ .dist_amount = 1.0, \
+ /* voronoi */ \
+ .vn_w1 = 1.0, \
+ .vn_w2 = 0.0, \
+ .vn_w3 = 0.0, \
+ .vn_w4 = 0.0, \
+ .vn_mexp = 2.5, \
+ .vn_distm = 0, \
+ .vn_coltype = 0, \
+ .preview = NULL, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_TEXTURE_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 3cb96ce8bf8..126b4638ca1 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -64,7 +64,7 @@ typedef struct uiFont {
char _pad0[2];
} uiFont;
-/* this state defines appearance of text */
+/** This state defines appearance of text. */
typedef struct uiFontStyle {
/** Saved in file, 0 is default. */
short uifont_id;
@@ -196,6 +196,9 @@ typedef struct ThemeUI {
unsigned char icon_modifier[4];
/** Shading related items. */
unsigned char icon_shading[4];
+ /** File folders. */
+ unsigned char icon_folder[4];
+ char _pad2[4];
/** Intensity of the border icons. >0 will render an border around themed
* icons. */
float icon_border_intensity;
@@ -342,6 +345,7 @@ typedef struct ThemeSpace {
lock_marker[4];
unsigned char bundle_solid[4];
unsigned char path_before[4], path_after[4];
+ unsigned char path_keyframe_before[4], path_keyframe_after[4];
unsigned char camera_path[4];
unsigned char _pad1[2];
@@ -430,15 +434,22 @@ typedef enum eWireColor_Flags {
TH_WIRECOLOR_TEXTCOLS = (1 << 1),
} eWireColor_Flags;
-/* A theme */
+/**
+ * A theme.
+ *
+ * \note Currently only a single theme is ever used at once.
+ * Different theme presets are stored as external files now.
+ */
typedef struct bTheme {
struct bTheme *next, *prev;
char name[32];
ThemeUI tui;
- /* Individual Spacetypes */
- /* note: ensure UI_THEMESPACE_END is updated when adding */
+ /**
+ * Individual Spacetypes:
+ * \note Ensure #UI_THEMESPACE_END is updated when adding.
+ */
ThemeSpace space_properties;
ThemeSpace space_view3d;
ThemeSpace space_file;
@@ -465,8 +476,10 @@ typedef struct bTheme {
char _pad0[4];
} bTheme;
-#define UI_THEMESPACE_START(btheme) (CHECK_TYPE_INLINE(btheme, bTheme *), &((btheme)->tbuts))
-#define UI_THEMESPACE_END(btheme) (CHECK_TYPE_INLINE(btheme, bTheme *), (&((btheme)->tclip) + 1))
+#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))
typedef struct bAddon {
struct bAddon *next, *prev;
@@ -492,7 +505,7 @@ typedef struct bUserMenu {
ListBase items;
} bUserMenu;
-/* May be part of bUserMenu or other list. */
+/** May be part of #bUserMenu or other list. */
typedef struct bUserMenuItem {
struct bUserMenuItem *next, *prev;
char ui_name[64];
@@ -553,16 +566,44 @@ typedef struct UserDef_Runtime {
char _pad0[7];
} UserDef_Runtime;
+/**
+ * Store UI data here instead of the space
+ * since the space is typically a window which is freed.
+ */
+typedef struct UserDef_SpaceData {
+ char section_active;
+ /** #eUserPref_SpaceData_Flag UI options. */
+ char flag;
+ char _pad0[6];
+} UserDef_SpaceData;
+
+/**
+ * Storage for UI data that to keep it even after the window was closed. (Similar to
+ * #UserDef_SpaceData.)
+ */
+typedef struct UserDef_FileSpaceData {
+ int display_type; /* FileSelectParams.display */
+ int thumbnail_size; /* FileSelectParams.thumbnail_size */
+ int sort_type; /* FileSelectParams.sort */
+ int details_flags; /* FileSelectParams.details_flags */
+ int flag; /* FileSelectParams.flag */
+
+ char _pad[4];
+
+ /** Info used when creating the file browser in a temporary window. */
+ int temp_win_sizex;
+ int temp_win_sizey;
+} UserDef_FileSpaceData;
+
typedef struct UserDef {
- /* UserDef has separate do-version handling, and can be read from other files */
+ /** UserDef has separate do-version handling, and can be read from other files. */
int versionfile, subversionfile;
/** #eUserPref_Flag. */
int flag;
/** #eDupli_ID_Flags. */
short dupflag;
- /**
- * #eUserPref_PrefFlag preferences for the preferences. */
+ /** #eUserPref_PrefFlag preferences for the preferences. */
char pref_flag;
char savetime;
char _pad4[4];
@@ -600,14 +641,12 @@ typedef struct UserDef {
/** #eUserpref_UI_Flag2. */
char uiflag2;
char gpu_flag;
- char _pad8[2];
+ char _pad8[6];
/* Experimental flag for app-templates to make changes to behavior
* which are outside the scope of typical preferences. */
- short app_flag;
- short language;
- short userpref;
- char userpref_flag;
+ char app_flag;
char viewzoom;
+ short language;
int mixbufsize;
int audiodevice;
@@ -638,7 +677,7 @@ typedef struct UserDef {
short transopts;
short menuthreshold1, menuthreshold2;
- /* startup template */
+ /** Startup application template. */
char app_template[64];
struct ListBase themes;
@@ -717,7 +756,7 @@ typedef struct UserDef {
/** Overall sensitivity of 3D mouse. */
float ndof_sensitivity;
float ndof_orbit_sensitivity;
- /** Deadzone of 3D mouse. */
+ /** Dead-zone of 3D mouse. */
float ndof_deadzone;
/** #eNdof_Flag, flags for 3D mouse. */
int ndof_flag;
@@ -765,7 +804,6 @@ typedef struct UserDef {
/** Legacy, for backwards compatibility only. */
int compute_device_type;
- char _pad6[4];
/** Opacity of inactive F-Curves in F-Curve Editor. */
float fcu_inactive_alpha;
@@ -787,8 +825,6 @@ typedef struct UserDef {
/** Pie menu distance from center before a direction is set. */
short pie_menu_threshold;
- struct WalkNavigation walk_navigation;
-
short opensubdiv_compute_type;
/** #eMultiSample_Type, amount of samples for Grease Pencil. */
short gpencil_multisamples;
@@ -797,7 +833,15 @@ typedef struct UserDef {
char viewport_aa;
- char _pad5[2];
+ char render_display_type; /* eUserpref_RenderDisplayType */
+ char filebrowser_display_type; /* eUserpref_TempSpaceDisplayType */
+ char _pad5[4];
+
+ struct WalkNavigation walk_navigation;
+
+ /** The UI for the user preferences. */
+ UserDef_SpaceData space_data;
+ UserDef_FileSpaceData file_space_data;
/** Runtime data (keep last). */
UserDef_Runtime runtime;
@@ -811,7 +855,7 @@ extern UserDef U;
/* Toggles for unfinished 2.8 UserPref design. */
//#define WITH_USERDEF_WORKSPACES
-/** #UserDef.userpref (UI active_section) */
+/** #UserDef_SpaceData.section_active (UI active_section) */
typedef enum eUserPref_Section {
USER_SECTION_INTERFACE = 0,
USER_SECTION_EDITING = 1,
@@ -833,11 +877,12 @@ typedef enum eUserPref_Section {
USER_SECTION_FILE_PATHS = 15,
} eUserPref_Section;
-/* UserDef.userpref_flag (State of the user preferences UI). */
-typedef enum eUserPref_SectionFlag {
- /* Hide/expand keymap preferences. */
- USER_SECTION_INPUT_HIDE_UI_KEYCONFIG = (1 << 0),
-} eUserPref_SectionFlag;
+/** #UserDef_SpaceData.flag (State of the user preferences UI). */
+typedef enum eUserPref_SpaceData_Flag {
+ /** Hide/expand key-map preferences. */
+ USER_SPACEDATA_INPUT_HIDE_UI_KEYCONFIG = (1 << 0),
+ USER_SPACEDATA_ADDONS_SHOW_ONLY_ENABLED = (1 << 1),
+} eUserPref_SpaceData_Flag;
/** #UserDef.flag */
typedef enum eUserPref_Flag {
@@ -868,7 +913,7 @@ typedef enum eUserPref_Flag {
USER_NONEGFRAMES = (1 << 24),
USER_TXT_TABSTOSPACES_DISABLE = (1 << 25),
USER_TOOLTIPS_PYTHON = (1 << 26),
- USER_ADDONS_ENABLED_ONLY = (1 << 27),
+ USER_FLAG_UNUSED_27 = (1 << 27), /* dirty */
} eUserPref_Flag;
typedef enum eUserPref_PrefFlag {
@@ -946,7 +991,11 @@ typedef enum eUserpref_UI_Flag {
USER_ZOOM_HORIZ = (1 << 26), /* for CONTINUE and DOLLY zoom */
USER_SPLASH_DISABLE = (1 << 27),
USER_HIDE_RECENT = (1 << 28),
- USER_SHOW_THUMBNAILS = (1 << 29),
+#ifdef DNA_DEPRECATED
+ USER_SHOW_THUMBNAILS =
+ (1 << 29), /* deprecated - We're just trying if there's much desire for this feature, or if
+ we can make it go for good. Should be cleared if so - Julian, Oct. 2019 */
+#endif
USER_SAVE_PROMPT = (1 << 30),
USER_HIDE_SYSTEM_BOOKMARKS = (1u << 31),
} eUserpref_UI_Flag;
@@ -1089,26 +1138,23 @@ typedef enum eColorPicker_Types {
/** Timecode display styles
* #UserDef.timecode_style */
typedef enum eTimecodeStyles {
- /* as little info as is necessary to show relevant info
- * with '+' to denote the frames
- * i.e. HH:MM:SS+FF, MM:SS+FF, SS+FF, or MM:SS
+ /**
+ * As little info as is necessary to show relevant info with '+' to denote the frames
+ * i.e. HH:MM:SS+FF, MM:SS+FF, SS+FF, or MM:SS.
*/
USER_TIMECODE_MINIMAL = 0,
-
- /* reduced SMPTE - (HH:)MM:SS:FF */
+ /** Reduced SMPTE - (HH:)MM:SS:FF */
USER_TIMECODE_SMPTE_MSF = 1,
-
- /* full SMPTE - HH:MM:SS:FF */
+ /** Full SMPTE - HH:MM:SS:FF */
USER_TIMECODE_SMPTE_FULL = 2,
-
- /* milliseconds for sub-frames - HH:MM:SS.sss */
+ /** Milliseconds for sub-frames - HH:MM:SS.sss. */
USER_TIMECODE_MILLISECONDS = 3,
-
- /* seconds only */
+ /** Seconds only. */
USER_TIMECODE_SECONDS_ONLY = 4,
-
- /* Private (not exposed as generic choices) options. */
- /* milliseconds for sub-frames , SubRip format- HH:MM:SS,sss */
+ /**
+ * Private (not exposed as generic choices) options.
+ * milliseconds for sub-frames , SubRip format- HH:MM:SS,sss.
+ */
USER_TIMECODE_SUBRIP = 100,
} eTimecodeStyles;
@@ -1118,15 +1164,14 @@ typedef enum eNdof_Flag {
NDOF_FLY_HELICOPTER = (1 << 1),
NDOF_LOCK_HORIZON = (1 << 2),
- /* the following might not need to be saved between sessions,
- * but they do need to live somewhere accessible... */
+ /* The following might not need to be saved between sessions,
+ * but they do need to live somewhere accessible. */
NDOF_SHOULD_PAN = (1 << 3),
NDOF_SHOULD_ZOOM = (1 << 4),
NDOF_SHOULD_ROTATE = (1 << 5),
- /* orbit navigation modes */
+ /* Orbit navigation modes. */
- /* exposed as Orbit|Explore in the UI */
NDOF_MODE_ORBIT = (1 << 6),
/* actually... users probably don't care about what the mode
@@ -1183,6 +1228,18 @@ typedef enum eUserpref_FactorDisplay {
USER_FACTOR_AS_PERCENTAGE = 1,
} eUserpref_FactorDisplay;
+typedef enum eUserpref_RenderDisplayType {
+ USER_RENDER_DISPLAY_NONE = 0,
+ USER_RENDER_DISPLAY_SCREEN = 1,
+ USER_RENDER_DISPLAY_AREA = 2,
+ USER_RENDER_DISPLAY_WINDOW = 3
+} eUserpref_RenderDisplayType;
+
+typedef enum eUserpref_TempSpaceDisplayType {
+ USER_TEMP_SPACE_DISPLAY_FULLSCREEN,
+ USER_TEMP_SPACE_DISPLAY_WINDOW,
+} eUserpref_TempSpaceDisplayType;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_vec_defaults.h b/source/blender/makesdna/DNA_vec_defaults.h
new file mode 100644
index 00000000000..7242f5ab114
--- /dev/null
+++ b/source/blender/makesdna/DNA_vec_defaults.h
@@ -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 DNA
+ */
+
+#ifndef __DNA_VEC_DEFAULTS_H__
+#define __DNA_VEC_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Generic Defaults
+ * \{ */
+
+/** See #unit_m4. */
+#define _DNA_DEFAULT_UNIT_M4 \
+ { \
+ {1, 0, 0, 0}, \
+ {0, 1, 0, 0}, \
+ {0, 0, 1, 0}, \
+ {0, 0, 0, 1}, \
+ }
+
+#define _DNA_DEFAULT_UNIT_M3 \
+ { \
+ {1, 0, 0}, \
+ {0, 1, 0}, \
+ {0, 0, 1}, \
+ }
+
+/** See #unit_qt. */
+#define _DNA_DEFAULT_UNIT_QT \
+ {1, 0, 0, 0}
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_VEC_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_view3d_defaults.h b/source/blender/makesdna/DNA_view3d_defaults.h
new file mode 100644
index 00000000000..365b1993d80
--- /dev/null
+++ b/source/blender/makesdna/DNA_view3d_defaults.h
@@ -0,0 +1,116 @@
+/*
+ * 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 DNA
+ */
+
+#ifndef __DNA_VIEW3D_DEFAULTS_H__
+#define __DNA_VIEW3D_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Viewport Struct
+ * \{ */
+
+#define _DNA_DEFAULT_View3DShading \
+ { \
+ .type = OB_SOLID, \
+ .prev_type = OB_SOLID, \
+ .flag = V3D_SHADING_SPECULAR_HIGHLIGHT | V3D_SHADING_XRAY_WIREFRAME | \
+ V3D_SHADING_SCENE_LIGHTS_RENDER | V3D_SHADING_SCENE_WORLD_RENDER, \
+ .light = V3D_LIGHTING_STUDIO, \
+ .shadow_intensity = 0.5f, \
+ .xray_alpha = 0.5f, \
+ .xray_alpha_wire = 0.5f, \
+ .cavity_valley_factor = 1.0f, \
+ .cavity_ridge_factor = 1.0f, \
+ .cavity_type = V3D_SHADING_CAVITY_CURVATURE, \
+ .curvature_ridge_factor = 1.0f, \
+ .curvature_valley_factor = 1.0f, \
+ .single_color = {0.8f, 0.8f, 0.8f}, \
+ .background_color = {0.05f, 0.05f, 0.05f}, \
+ .studiolight_intensity = 1.0f, \
+ }
+
+#define _DNA_DEFAULT_View3DOverlay \
+ { \
+ .wireframe_threshold = 1.0f, \
+ .xray_alpha_bone = 0.5f, \
+ .texture_paint_mode_opacity = 1.0f, \
+ .weight_paint_mode_opacity = 1.0f, \
+ .vertex_paint_mode_opacity = 1.0f, \
+ /* Intentionally different to vertex/paint mode, \
+ * we typically want to see shading too. */ \
+ .sculpt_mode_mask_opacity = 0.75f, \
+ \
+ .edit_flag = V3D_OVERLAY_EDIT_FACES | V3D_OVERLAY_EDIT_SEAMS | \
+ V3D_OVERLAY_EDIT_SHARP | V3D_OVERLAY_EDIT_FREESTYLE_EDGE | \
+ V3D_OVERLAY_EDIT_FREESTYLE_FACE | V3D_OVERLAY_EDIT_EDGES | \
+ V3D_OVERLAY_EDIT_CREASES | V3D_OVERLAY_EDIT_BWEIGHTS | \
+ V3D_OVERLAY_EDIT_CU_HANDLES | V3D_OVERLAY_EDIT_CU_NORMALS, \
+ \
+ .gpencil_paper_opacity = 0.5f, \
+ .gpencil_grid_opacity = 0.9f, \
+ }
+
+#define _DNA_DEFAULT_View3DCursor \
+ { \
+ .rotation_mode = ROT_MODE_XYZ, \
+ .rotation_quaternion = {1, 0, 0, 0}, \
+ .rotation_axis = {0, 1, 0}, \
+ }
+
+#define _DNA_DEFAULT_View3D \
+ { \
+ .spacetype = SPACE_VIEW3D, \
+ .scenelock = true, \
+ .grid = 1.0f, \
+ .gridlines = 16, \
+ .gridsubdiv = 10, \
+ .shading = _DNA_DEFAULT_View3DShading, \
+ .overlay = _DNA_DEFAULT_View3DOverlay, \
+ \
+ .gridflag = V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_FLOOR | V3D_SHOW_ORTHO_GRID, \
+ \
+ .flag = V3D_SELECT_OUTLINE, \
+ .flag2 = V3D_SHOW_RECONSTRUCTION | V3D_SHOW_ANNOTATION, \
+ \
+ .lens = 50.0f, \
+ .clip_start = 0.01f, \
+ .clip_end = 1000.0f, \
+ \
+ .bundle_size = 0.2f, \
+ .bundle_drawtype = OB_PLAINAXES, \
+ \
+ /* stereo */ \
+ .stereo3d_camera = STEREO_3D_ID, \
+ .stereo3d_flag = V3D_S3D_DISPPLANE, \
+ .stereo3d_convergence_alpha = 0.15f, \
+ .stereo3d_volume_alpha = 0.05f, \
+ \
+ /* Grease pencil settings. */ \
+ .vertex_opacity = 1.0f, \
+ .gp_flag = V3D_GP_SHOW_EDIT_LINES, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_VIEW3D_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 51655790fbd..283c361cc56 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -152,7 +152,7 @@ typedef struct View3DShading {
char background_type;
char cavity_type;
char wire_color_type;
- char _pad[6];
+ char _pad[2];
/** FILE_MAXFILE. */
char studio_light[256];
@@ -166,6 +166,7 @@ typedef struct View3DShading {
float studiolight_rot_z;
float studiolight_background;
+ float studiolight_intensity;
float object_outline_color[3];
float xray_alpha;
@@ -179,6 +180,7 @@ typedef struct View3DShading {
float curvature_ridge_factor;
float curvature_valley_factor;
+ struct IDProperty *prop;
} View3DShading;
/** 3D Viewport Overlay settings. */
@@ -264,6 +266,8 @@ typedef struct View3D {
unsigned short local_view_uuid;
char _pad6[2];
int layact DNA_DEPRECATED;
+ unsigned short local_collections_uuid;
+ short _pad7[3];
/** Optional bool for 3d cursor to define center. */
short ob_centre_cursor;
@@ -327,7 +331,7 @@ typedef struct View3D {
#define V3D_S3D_DISPVOLUME (1 << 2)
/** #View3D.flag */
-#define V3D_FLAG_UNUSED_0 (1 << 0) /* cleared */
+#define V3D_LOCAL_COLLECTIONS (1 << 0)
#define V3D_FLAG_UNUSED_1 (1 << 1) /* cleared */
#define V3D_HIDE_HELPLINES (1 << 2)
#define V3D_INVALID_BACKBUF (1 << 3)
@@ -347,6 +351,7 @@ typedef struct View3D {
#define RV3D_CLIPPING (1 << 2)
#define RV3D_NAVIGATING (1 << 3)
#define RV3D_GPULIGHT_UPDATE (1 << 4)
+#define RV3D_PAINTING (1 << 5)
/*#define RV3D_IS_GAME_ENGINE (1 << 5) */ /* UNUSED */
/**
* Disable zbuffer offset, skip calls to #ED_view3d_polygon_offset.
@@ -394,8 +399,9 @@ typedef struct View3D {
#define V3D_GP_SHOW_GRID (1 << 1) /* Activate paper grid */
#define V3D_GP_SHOW_EDIT_LINES (1 << 2)
#define V3D_GP_SHOW_MULTIEDIT_LINES (1 << 3)
-#define V3D_GP_SHOW_ONION_SKIN (1 << 4) /* main switch at view level */
-#define V3D_GP_FADE_NOACTIVE_LAYERS (1 << 5) /* fade layers not active */
+#define V3D_GP_SHOW_ONION_SKIN (1 << 4) /* main switch at view level */
+#define V3D_GP_FADE_NOACTIVE_LAYERS (1 << 5) /* fade layers not active */
+#define V3D_GP_FADE_NOACTIVE_GPENCIL (1 << 6) /* Fade other GPencil objects */
/** #View3DShading.light */
enum {
@@ -418,6 +424,8 @@ enum {
V3D_SHADING_WORLD_ORIENTATION = (1 << 9),
V3D_SHADING_BACKFACE_CULLING = (1 << 10),
V3D_SHADING_DEPTH_OF_FIELD = (1 << 11),
+ V3D_SHADING_SCENE_LIGHTS_RENDER = (1 << 12),
+ V3D_SHADING_SCENE_WORLD_RENDER = (1 << 13),
};
/** #View3DShading.color_type */
diff --git a/source/blender/makesdna/DNA_world_defaults.h b/source/blender/makesdna/DNA_world_defaults.h
new file mode 100644
index 00000000000..c4d934381b4
--- /dev/null
+++ b/source/blender/makesdna/DNA_world_defaults.h
@@ -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 DNA
+ */
+
+#ifndef __DNA_WORLD_DEFAULTS_H__
+#define __DNA_WORLD_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name World Struct
+ * \{ */
+
+#define _DNA_DEFAULT_World \
+ { \
+ .horr = 0.05f, \
+ .horg = 0.05f, \
+ .horb = 0.05f, \
+ \
+ .aodist = 10.0f, \
+ .aoenergy = 1.0f, \
+ \
+ .preview = NULL, \
+ .miststa = 5.0f, \
+ .mistdist = 25.0f, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_WORLD_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt
index 178ef219c4d..bca27442e65 100644
--- a/source/blender/makesdna/intern/CMakeLists.txt
+++ b/source/blender/makesdna/intern/CMakeLists.txt
@@ -77,7 +77,7 @@ add_custom_command(
# -----------------------------------------------------------------------------
# Build bf_dna library
set(INC
-
+ ${CMAKE_CURRENT_BINARY_DIR}
)
set(INC_SYS
@@ -85,6 +85,7 @@ set(INC_SYS
)
set(SRC
+ dna_defaults.c
dna_genfile.c
dna_utils.c
${CMAKE_CURRENT_BINARY_DIR}/dna.c
@@ -126,6 +127,24 @@ set(SRC
../../blenlib/intern/endian_switch.c
../../blenlib/intern/hash_mm2a.c
../../blenlib/intern/listbase.c
+
+ ../DNA_brush_defaults.h
+ ../DNA_cachefile_defaults.h
+ ../DNA_camera_defaults.h
+ ../DNA_curve_defaults.h
+ ../DNA_image_defaults.h
+ ../DNA_lattice_defaults.h
+ ../DNA_light_defaults.h
+ ../DNA_lightprobe_defaults.h
+ ../DNA_linestyle_defaults.h
+ ../DNA_material_defaults.h
+ ../DNA_mesh_defaults.h
+ ../DNA_meta_defaults.h
+ ../DNA_object_defaults.h
+ ../DNA_scene_defaults.h
+ ../DNA_texture_defaults.h
+ ../DNA_vec_defaults.h
+ ../DNA_view3d_defaults.h
)
set(LIB
diff --git a/source/blender/makesdna/intern/dna_defaults.c b/source/blender/makesdna/intern/dna_defaults.c
new file mode 100644
index 00000000000..260f1cd20f6
--- /dev/null
+++ b/source/blender/makesdna/intern/dna_defaults.c
@@ -0,0 +1,273 @@
+/*
+ * 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.
+ *
+ * DNA default value access.
+ */
+
+/** \file
+ * \ingroup DNA
+ *
+ * This API provides direct access to DNA default structs
+ * to avoid duplicating values for initialization, versioning and RNA.
+ * This allows DNA default definitions to be defined in a single header along side the types.
+ * So each `DNA_{name}_types.h` can have an optional `DNA_{name}_defaults.h` file along side it.
+ *
+ * Defining the defaults is optional since it doesn't make sense for some structs to have defaults.
+ *
+ * To create these defaults there is a GDB script which can be handy to get started:
+ * `./source/tools/utils/gdb_struct_repr_c99.py`
+ *
+ * Magic numbers should be replaced with flags before committing.
+ *
+ * The main functions to access these are:
+ * - #DNA_struct_default_get
+ * - #DNA_struct_default_alloc
+ *
+ * These access the struct table #DNA_default_table using the struct number.
+ *
+ * \note Struct members only define their members (pointers are left as NULL set).
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_endian_switch.h"
+#include "BLI_memarena.h"
+#include "BLI_math.h"
+
+#include "DNA_defaults.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_cachefile_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_image_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_light_types.h"
+#include "DNA_lightprobe_types.h"
+#include "DNA_linestyle_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_speaker_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_world_types.h"
+
+#include "DNA_brush_defaults.h"
+#include "DNA_cachefile_defaults.h"
+#include "DNA_camera_defaults.h"
+#include "DNA_curve_defaults.h"
+#include "DNA_image_defaults.h"
+#include "DNA_lattice_defaults.h"
+#include "DNA_light_defaults.h"
+#include "DNA_lightprobe_defaults.h"
+#include "DNA_linestyle_defaults.h"
+#include "DNA_material_defaults.h"
+#include "DNA_mesh_defaults.h"
+#include "DNA_meta_defaults.h"
+#include "DNA_object_defaults.h"
+#include "DNA_scene_defaults.h"
+#include "DNA_speaker_defaults.h"
+#include "DNA_texture_defaults.h"
+#include "DNA_world_defaults.h"
+
+#define SDNA_DEFAULT_DECL_STRUCT(struct_name) \
+ static const struct_name DNA_DEFAULT_##struct_name = _DNA_DEFAULT_##struct_name
+
+/* DNA_brush_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Brush);
+
+/* DNA_cachefile_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(CacheFile);
+
+/* DNA_camera_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Camera);
+
+/* DNA_curve_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Curve);
+
+/* DNA_image_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Image);
+
+/* DNA_lattice_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Lattice);
+
+/* DNA_light_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Light);
+
+/* DNA_lightprobe_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(LightProbe);
+
+/* DNA_linestyle_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(FreestyleLineStyle);
+
+/* DNA_material_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Material);
+
+/* DNA_mesh_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Mesh);
+
+/* DNA_meta_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(MetaBall);
+
+/* DNA_object_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Object);
+
+/* DNA_scene_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Scene);
+SDNA_DEFAULT_DECL_STRUCT(ToolSettings);
+
+/* DNA_speaker_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Speaker);
+
+/* DNA_texture_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Tex);
+
+/* DNA_view3d_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(View3D);
+
+/* DNA_world_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(World);
+
+#undef SDNA_DEFAULT_DECL_STRUCT
+
+/* Reuse existing definitions. */
+extern const struct UserDef U_default;
+#define DNA_DEFAULT_UserDef U_default
+
+extern const bTheme U_theme_default;
+#define DNA_DEFAULT_bTheme U_theme_default
+
+/**
+ * Prevent assigning the wrong struct types since all elements in #DNA_default_table are `void *`.
+ */
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+# define SDNA_TYPE_CHECKED(v, t) (&(v) + (_Generic((v), t : 0)))
+#else
+# define SDNA_TYPE_CHECKED(v, t) (&(v))
+#endif
+
+#define SDNA_DEFAULT_DECL(struct_name) \
+ [SDNA_TYPE_FROM_STRUCT(struct_name)] = SDNA_TYPE_CHECKED(DNA_DEFAULT_##struct_name, struct_name)
+
+#define SDNA_DEFAULT_DECL_EX(struct_name, struct_path) \
+ [SDNA_TYPE_FROM_STRUCT(struct_name)] = SDNA_TYPE_CHECKED(DNA_DEFAULT_##struct_path, struct_name)
+
+/** Keep headers sorted. */
+const void *DNA_default_table[SDNA_TYPE_MAX] = {
+
+ /* DNA_brush_defaults.h */
+ SDNA_DEFAULT_DECL(Brush),
+
+ /* DNA_cachefile_defaults.h */
+ SDNA_DEFAULT_DECL(CacheFile),
+
+ /* DNA_camera_defaults.h */
+ SDNA_DEFAULT_DECL(Camera),
+ SDNA_DEFAULT_DECL_EX(CameraDOFSettings, Camera.dof),
+ SDNA_DEFAULT_DECL_EX(CameraStereoSettings, Camera.stereo),
+
+ /* DNA_curve_defaults.h */
+ SDNA_DEFAULT_DECL(Curve),
+
+ /* DNA_image_defaults.h */
+ SDNA_DEFAULT_DECL(Image),
+
+ /* DNA_lattice_defaults.h */
+ SDNA_DEFAULT_DECL(Lattice),
+
+ /* DNA_light_defaults.h */
+ SDNA_DEFAULT_DECL(Light),
+
+ /* DNA_lightprobe_defaults.h */
+ SDNA_DEFAULT_DECL(LightProbe),
+
+ /* DNA_linestyle_defaults.h */
+ SDNA_DEFAULT_DECL(FreestyleLineStyle),
+
+ /* DNA_material_defaults.h */
+ SDNA_DEFAULT_DECL(Material),
+
+ /* DNA_mesh_defaults.h */
+ SDNA_DEFAULT_DECL(Mesh),
+
+ /* DNA_meta_defaults.h */
+ SDNA_DEFAULT_DECL(MetaBall),
+
+ /* DNA_object_defaults.h */
+ SDNA_DEFAULT_DECL(Object),
+
+ /* DNA_scene_defaults.h */
+ SDNA_DEFAULT_DECL(Scene),
+ SDNA_DEFAULT_DECL_EX(RenderData, Scene.r),
+ SDNA_DEFAULT_DECL_EX(ImageFormatData, Scene.r.im_format),
+ SDNA_DEFAULT_DECL_EX(BakeData, Scene.r.bake),
+ SDNA_DEFAULT_DECL_EX(FFMpegCodecData, Scene.r.ffcodecdata),
+ SDNA_DEFAULT_DECL_EX(DisplaySafeAreas, Scene.safe_areas),
+ SDNA_DEFAULT_DECL_EX(AudioData, Scene.audio),
+ SDNA_DEFAULT_DECL_EX(PhysicsSettings, Scene.physics_settings),
+ SDNA_DEFAULT_DECL_EX(SceneDisplay, Scene.display),
+ SDNA_DEFAULT_DECL_EX(SceneEEVEE, Scene.eevee),
+
+ SDNA_DEFAULT_DECL(ToolSettings),
+ SDNA_DEFAULT_DECL_EX(CurvePaintSettings, ToolSettings.curve_paint_settings),
+ SDNA_DEFAULT_DECL_EX(ImagePaintSettings, ToolSettings.imapaint),
+ SDNA_DEFAULT_DECL_EX(ParticleEditSettings, ToolSettings.particle),
+ SDNA_DEFAULT_DECL_EX(ParticleBrushData, ToolSettings.particle.brush[0]),
+ SDNA_DEFAULT_DECL_EX(MeshStatVis, ToolSettings.statvis),
+ SDNA_DEFAULT_DECL_EX(GP_Sculpt_Settings, ToolSettings.gp_sculpt),
+ SDNA_DEFAULT_DECL_EX(GP_Sculpt_Guide, ToolSettings.gp_sculpt.guide),
+
+ /* DNA_speaker_defaults.h */
+ SDNA_DEFAULT_DECL(Speaker),
+
+ /* DNA_texture_defaults.h */
+ SDNA_DEFAULT_DECL(Tex),
+ SDNA_DEFAULT_DECL_EX(MTex, Brush.mtex),
+
+ /* DNA_userdef_types.h */
+ SDNA_DEFAULT_DECL(UserDef),
+ SDNA_DEFAULT_DECL(bTheme),
+ SDNA_DEFAULT_DECL_EX(UserDef_SpaceData, UserDef.space_data),
+ SDNA_DEFAULT_DECL_EX(UserDef_FileSpaceData, UserDef.file_space_data),
+ SDNA_DEFAULT_DECL_EX(WalkNavigation, UserDef.walk_navigation),
+
+ /* DNA_view3d_defaults.h */
+ SDNA_DEFAULT_DECL(View3D),
+ SDNA_DEFAULT_DECL_EX(View3DOverlay, View3D.overlay),
+ SDNA_DEFAULT_DECL_EX(View3DShading, View3D.shading),
+ SDNA_DEFAULT_DECL_EX(View3DCursor, Scene.cursor),
+
+ /* DNA_world_defaults.h */
+ SDNA_DEFAULT_DECL(World),
+};
+#undef SDNA_DEFAULT_DECL
+#undef SDNA_DEFAULT_DECL_EX
+
+char *_DNA_struct_default_alloc_impl(const char *data_src, size_t size, const char *alloc_str)
+{
+ char *data_dst = MEM_mallocN(size, alloc_str);
+ memcpy(data_dst, data_src, size);
+ return data_dst;
+}
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index 86ba306fc6a..6b3095c7925 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -184,7 +184,7 @@ static bool ispointer(const char *name)
* \param name: Index into sdna->names,
* needed to extract possible pointer/array information.
*/
-static int elementsize(const SDNA *sdna, short type, short name)
+int DNA_elem_size_nr(const SDNA *sdna, short type, short name)
{
int len;
const char *cp = sdna->names[name];
@@ -1059,7 +1059,7 @@ static const char *find_elem(const SDNA *sdna,
otype = sdna->types[old[0]];
oname = sdna->names[old[1]];
- len = elementsize(sdna, old[0], old[1]);
+ len = DNA_elem_size_nr(sdna, old[0], old[1]);
if (elem_strcmp(name, oname) == 0) { /* name equal */
if (strcmp(type, otype) == 0) { /* type equal */
@@ -1102,7 +1102,7 @@ static void reconstruct_elem(const SDNA *newsdna,
* - cast type
* - name partially equal (array differs)
* - type equal: memcpy
- * - types casten
+ * - type cast (per element).
* (nzc 2-4-2001 I want the 'unsigned' bit to be parsed as well. Where
* can I force this?)
*/
@@ -1128,7 +1128,7 @@ static void reconstruct_elem(const SDNA *newsdna,
const int old_name_nr = old[1];
otype = oldsdna->types[old[0]];
oname = oldsdna->names[old[1]];
- len = elementsize(oldsdna, old[0], old[1]);
+ len = DNA_elem_size_nr(oldsdna, old[0], old[1]);
if (strcmp(name, oname) == 0) { /* name equal */
@@ -1247,7 +1247,7 @@ static void reconstruct_struct(const SDNA *newsdna,
type = newsdna->types[spc[0]];
name = newsdna->names[spc[1]];
- elen = elementsize(newsdna, spc[0], spc[1]);
+ elen = DNA_elem_size_nr(newsdna, spc[0], spc[1]);
/* Skip pad bytes which must start with '_pad', see makesdna.c 'is_name_legal'.
* for exact rules. Note that if we fail to skip a pad byte it's harmless,
@@ -1269,7 +1269,7 @@ static void reconstruct_struct(const SDNA *newsdna,
mul = newsdna->names_array_len[spc[1]];
mulo = oldsdna->names_array_len[sppo[1]];
- eleno = elementsize(oldsdna, sppo[0], sppo[1]);
+ eleno = DNA_elem_size_nr(oldsdna, sppo[0], sppo[1]);
elen /= mul;
eleno /= mulo;
@@ -1333,8 +1333,8 @@ void DNA_struct_switch_endian(const SDNA *oldsdna, int oldSDNAnr, char *data)
name = oldsdna->names[spc[1]];
const int old_name_array_len = oldsdna->names_array_len[spc[1]];
- /* elementsize = including arraysize */
- elen = elementsize(oldsdna, spc[0], spc[1]);
+ /* DNA_elem_size_nr = including arraysize */
+ elen = DNA_elem_size_nr(oldsdna, spc[0], spc[1]);
/* test: is type a struct? */
if (spc[0] >= firststructtypenr && !ispointer(name)) {
@@ -1639,6 +1639,8 @@ static void sdna_expand_names(SDNA *sdna)
names_expand_len += sp[1];
}
const char **names_expand = MEM_mallocN(sizeof(*names_expand) * names_expand_len, __func__);
+ short *names_array_len_expand = MEM_mallocN(sizeof(*names_array_len_expand) * names_expand_len,
+ __func__);
int names_expand_index = 0;
for (int struct_nr = 0; struct_nr < sdna->structs_len; struct_nr++) {
@@ -1652,6 +1654,7 @@ static void sdna_expand_names(SDNA *sdna)
sp_expand += 2;
for (int i = 0; i < names_len; i++, sp += 2, sp_expand += 2) {
names_expand[names_expand_index] = sdna->names[sp[1]];
+ names_array_len_expand[names_expand_index] = sdna->names_array_len[sp[1]];
BLI_assert(names_expand_index < SHRT_MAX);
sp_expand[1] = names_expand_index;
names_expand_index++;
@@ -1659,6 +1662,10 @@ static void sdna_expand_names(SDNA *sdna)
}
MEM_freeN((void *)sdna->names);
sdna->names = names_expand;
+
+ MEM_freeN((void *)sdna->names_array_len);
+ sdna->names_array_len = names_array_len_expand;
+
sdna->names_len = names_expand_len;
}
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index f03aacf8dbd..cefc5aded7c 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -392,6 +392,7 @@ extern StructRNA RNA_Mesh;
extern StructRNA RNA_MeshCacheModifier;
extern StructRNA RNA_MeshColor;
extern StructRNA RNA_MeshColorLayer;
+extern StructRNA RNA_MeshLoopColor;
extern StructRNA RNA_MeshDeformModifier;
extern StructRNA RNA_MeshEdge;
extern StructRNA RNA_MeshFloatProperty;
@@ -412,6 +413,7 @@ extern StructRNA RNA_MeshTextureFace;
extern StructRNA RNA_MeshTextureFaceLayer;
extern StructRNA RNA_MeshTexturePoly;
extern StructRNA RNA_MeshTexturePolyLayer;
+extern StructRNA RNA_MeshUVLoop;
extern StructRNA RNA_MeshVertex;
extern StructRNA RNA_MessageSensor;
extern StructRNA RNA_MetaBall;
@@ -1151,24 +1153,37 @@ struct PropertyElemRNA {
};
bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, struct ListBase *r_elements);
+struct ID *RNA_find_real_ID_and_path(struct Main *bmain, struct ID *id, const char **r_path);
+
char *RNA_path_from_ID_to_struct(PointerRNA *ptr);
+
+char *RNA_path_from_real_ID_to_struct(struct Main *bmain, PointerRNA *ptr, struct ID **r_real);
+
char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop);
char *RNA_path_from_ID_to_property_index(PointerRNA *ptr,
PropertyRNA *prop,
int array_dim,
int index);
+char *RNA_path_from_real_ID_to_property_index(struct Main *bmain,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ int array_dim,
+ int index,
+ struct ID **r_real_id);
+
char *RNA_path_resolve_from_type_to_property(struct PointerRNA *ptr,
struct PropertyRNA *prop,
const struct StructRNA *type);
-char *RNA_path_full_ID_py(struct ID *id);
-char *RNA_path_full_struct_py(struct PointerRNA *ptr);
-char *RNA_path_full_property_py_ex(PointerRNA *ptr,
- PropertyRNA *prop,
- int index,
- bool use_fallback);
-char *RNA_path_full_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
+char *RNA_path_full_ID_py(struct Main *bmain, struct ID *id);
+char *RNA_path_full_struct_py(struct Main *bmain, struct PointerRNA *ptr);
+char *RNA_path_full_property_py_ex(
+ struct Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback);
+char *RNA_path_full_property_py(struct Main *bmain,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ int index);
char *RNA_path_struct_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
char *RNA_path_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index 02aaef44a1f..e72a55b5a9e 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -91,6 +91,7 @@ extern const EnumPropertyItem rna_enum_beztriple_keyframe_type_items[];
extern const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[];
extern const EnumPropertyItem rna_enum_beztriple_interpolation_easing_items[];
extern const EnumPropertyItem rna_enum_keyframe_handle_type_items[];
+extern const EnumPropertyItem rna_enum_driver_target_rotation_mode_items[];
extern const EnumPropertyItem rna_enum_keyblock_type_items[];
@@ -183,6 +184,7 @@ extern const EnumPropertyItem rna_enum_file_sort_items[];
extern const EnumPropertyItem rna_enum_node_socket_in_out_items[];
extern const EnumPropertyItem rna_enum_node_math_items[];
+extern const EnumPropertyItem rna_enum_mapping_type_items[];
extern const EnumPropertyItem rna_enum_node_vec_math_items[];
extern const EnumPropertyItem rna_enum_node_filter_items[];
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 2745cfa9740..259f656cc8c 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -164,10 +164,19 @@ set(SRC
../../../../intern/guardedalloc/intern/mallocn_guarded_impl.c
../../../../intern/guardedalloc/intern/mallocn_lockfree_impl.c
../../../../intern/guardedalloc/intern/mmap_win.c
+
+ # Needed for defaults.
+ ../../../../release/datafiles/userdef/userdef_default.c
+ ../../../../release/datafiles/userdef/userdef_default_theme.c
)
set(INC
- ../../../../intern/clog
+ ../../../../intern/clog
+
+ # Needed for defaults forward declarations.
+ ../../../blender/blenloader
+
+ ${CMAKE_BINARY_DIR}/source/blender/makesdna/intern
)
set(INC_SYS
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 5aaddc30e07..2d4da942610 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -409,23 +409,30 @@ static void rna_construct_wrapper_function_name(
}
}
+void *rna_alloc_from_buffer(const char *buffer, int buffer_len)
+{
+ AllocDefRNA *alloc = MEM_callocN(sizeof(AllocDefRNA), "AllocDefRNA");
+ alloc->mem = MEM_mallocN(buffer_len, __func__);
+ memcpy(alloc->mem, buffer, buffer_len);
+ rna_addtail(&DefRNA.allocs, alloc);
+ return alloc->mem;
+}
+
+void *rna_calloc(int buffer_len)
+{
+ AllocDefRNA *alloc = MEM_callocN(sizeof(AllocDefRNA), "AllocDefRNA");
+ alloc->mem = MEM_callocN(buffer_len, __func__);
+ rna_addtail(&DefRNA.allocs, alloc);
+ return alloc->mem;
+}
+
static char *rna_alloc_function_name(const char *structname,
const char *propname,
const char *type)
{
- AllocDefRNA *alloc;
char buffer[2048];
- char *result;
-
rna_construct_function_name(buffer, sizeof(buffer), structname, propname, type);
- result = MEM_callocN(sizeof(char) * strlen(buffer) + 1, "rna_alloc_function_name");
- strcpy(result, buffer);
-
- alloc = MEM_callocN(sizeof(AllocDefRNA), "AllocDefRNA");
- alloc->mem = result;
- rna_addtail(&DefRNA.allocs, alloc);
-
- return result;
+ return rna_alloc_from_buffer(buffer, strlen(buffer) + 1);
}
static StructRNA *rna_find_struct(const char *identifier)
@@ -622,8 +629,8 @@ static char *rna_def_property_get_func(
if (prop->type == PROP_FLOAT) {
if (IS_DNATYPE_FLOAT_COMPAT(dp->dnatype) == 0) {
- if (prop->subtype !=
- PROP_COLOR_GAMMA) { /* colors are an exception. these get translated */
+ /* Colors are an exception. these get translated. */
+ if (prop->subtype != PROP_COLOR_GAMMA) {
CLOG_ERROR(&LOG,
"%s.%s is a '%s' but wrapped as type '%s'.",
srna->identifier,
@@ -2532,6 +2539,12 @@ static void rna_def_struct_function_call_impl_cpp(FILE *f, StructRNA *srna, Func
rna_safe_id(dp->prop->identifier));
}
}
+ else if (dp->prop->flag_parameter & PARM_RNAPTR) {
+ fprintf(f,
+ "(::%s *) &%s",
+ rna_parameter_type_name(dp->prop),
+ rna_safe_id(dp->prop->identifier));
+ }
else {
fprintf(f,
"(::%s *) %s.ptr.data",
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 5a4b4a3fa3d..49fdf9c67d5 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -491,13 +491,22 @@ static ID *rna_ID_copy(ID *id, Main *bmain)
return NULL;
}
-static ID *rna_ID_override_create(ID *id, Main *bmain)
+static ID *rna_ID_override_create(ID *id, Main *bmain, bool remap_local_usages)
{
- if (!BKE_override_library_is_enabled() || id->lib == NULL) {
+ if (!BKE_override_library_is_enabled() || !ID_IS_OVERRIDABLE_LIBRARY(id)) {
return NULL;
}
- return BKE_override_library_create_from_id(bmain, id);
+ if (remap_local_usages) {
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, true);
+ }
+
+ ID *local_id = BKE_override_library_create_from_id(bmain, id, remap_local_usages);
+
+ if (remap_local_usages) {
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ }
+ return local_id;
}
static void rna_ID_update_tag(ID *id, Main *bmain, ReportList *reports, int flag)
@@ -1519,6 +1528,12 @@ static void rna_def_ID(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_USE_MAIN);
parm = RNA_def_pointer(func, "id", "ID", "", "New overridden local copy of the ID");
RNA_def_function_return(func, parm);
+ RNA_def_boolean(func,
+ "remap_local_usages",
+ false,
+ "",
+ "Whether local usages of the linked ID should be remapped to the new "
+ "library override of it");
func = RNA_def_function(srna, "user_clear", "rna_ID_user_clear");
RNA_def_function_ui_description(func,
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 8327456f460..71a3be24810 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -41,12 +41,14 @@
#include "BLT_translation.h"
#include "BKE_animsys.h"
+#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_idcode.h"
#include "BKE_idprop.h"
#include "BKE_fcurve.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#include "BKE_node.h"
#include "DEG_depsgraph.h"
@@ -2056,18 +2058,18 @@ int RNA_property_ui_icon(PropertyRNA *prop)
return rna_ensure_property(prop)->icon;
}
-bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop)
+bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop_orig)
{
ID *id = ptr->owner_id;
int flag;
const char *dummy_info;
- prop = rna_ensure_property(prop);
+ PropertyRNA *prop = rna_ensure_property(prop_orig);
flag = prop->editable ? prop->editable(ptr, &dummy_info) : prop->flag;
return ((flag & PROP_EDITABLE) && (flag & PROP_REGISTER) == 0 &&
(!id || ((!ID_IS_LINKED(id) || (prop->flag & PROP_LIB_EXCEPTION)) &&
- (!id->override_library || RNA_property_overridable_get(ptr, prop)))));
+ (!id->override_library || RNA_property_overridable_get(ptr, prop_orig)))));
}
/**
@@ -2079,15 +2081,15 @@ bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char *
ID *id = ptr->owner_id;
int flag;
- prop = rna_ensure_property(prop);
+ PropertyRNA *prop_type = rna_ensure_property(prop);
*r_info = "";
/* get flag */
- if (prop->editable) {
- flag = prop->editable(ptr, r_info);
+ if (prop_type->editable) {
+ flag = prop_type->editable(ptr, r_info);
}
else {
- flag = prop->flag;
+ flag = prop_type->flag;
if ((flag & PROP_EDITABLE) == 0 || (flag & PROP_REGISTER)) {
*r_info = N_("This property is for internal use only and can't be edited");
}
@@ -2095,17 +2097,21 @@ bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char *
/* property from linked data-block */
if (id) {
- if (ID_IS_LINKED(id) && (prop->flag & PROP_LIB_EXCEPTION) == 0) {
+ if (ID_IS_LINKED(id) && (prop_type->flag & PROP_LIB_EXCEPTION) == 0) {
if (!(*r_info)[0]) {
*r_info = N_("Can't edit this property from a linked data-block");
}
return false;
}
- if (id->override_library != NULL && !RNA_property_overridable_get(ptr, prop)) {
- if (!(*r_info)[0]) {
- *r_info = N_("Can't edit this property from an override data-block");
+ if (id->override_library != NULL) {
+ /* We need the real data property in case of IDProperty here... */
+ PropertyRNA *real_prop = rna_ensure_property_realdata(&prop, ptr);
+ if (real_prop == NULL || !RNA_property_overridable_get(ptr, real_prop)) {
+ if (!(*r_info)[0]) {
+ *r_info = N_("Can't edit this property from an override data-block");
+ }
+ return false;
}
- return false;
}
}
@@ -5757,6 +5763,74 @@ static char *rna_path_from_ID_to_idpgroup(PointerRNA *ptr)
}
}
+/**
+ * Find the actual ID pointer and path from it to the given ID.
+ *
+ * \param id: ID reference to search the global owner for.
+ * \param[out] r_path: Path from the real ID to the initial ID.
+ * \return The ID pointer, or NULL in case of failure.
+ */
+ID *RNA_find_real_ID_and_path(Main *bmain, ID *id, const char **r_path)
+{
+ if (r_path) {
+ *r_path = "";
+ }
+
+ if ((id != NULL) && (id->flag & LIB_PRIVATE_DATA)) {
+ switch (GS(id->name)) {
+ case ID_NT:
+ if (r_path) {
+ *r_path = "node_tree";
+ }
+ return BKE_node_tree_find_owner_ID(bmain, (bNodeTree *)id);
+ case ID_GR:
+ if (r_path) {
+ *r_path = "collection";
+ }
+ return (ID *)BKE_collection_master_scene_search(bmain, (Collection *)id);
+
+ default:
+ return NULL;
+ }
+ }
+ else {
+ return id;
+ }
+}
+
+static char *rna_prepend_real_ID_path(Main *bmain, ID *id, char *path, ID **r_real_id)
+{
+ if (r_real_id != NULL) {
+ *r_real_id = NULL;
+ }
+
+ const char *prefix;
+ ID *real_id = RNA_find_real_ID_and_path(bmain, id, &prefix);
+
+ if (r_real_id != NULL) {
+ *r_real_id = real_id;
+ }
+
+ if (path != NULL) {
+ char *new_path = NULL;
+
+ if (real_id) {
+ if (prefix[0]) {
+ new_path = BLI_sprintfN("%s%s%s", prefix, path[0] == '[' ? "" : ".", path);
+ }
+ else {
+ return path;
+ }
+ }
+
+ MEM_freeN(path);
+ return new_path;
+ }
+ else {
+ return prefix[0] != '\0' ? BLI_strdup(prefix) : NULL;
+ }
+}
+
char *RNA_path_from_ID_to_struct(PointerRNA *ptr)
{
char *ptrpath = NULL;
@@ -5799,6 +5873,14 @@ char *RNA_path_from_ID_to_struct(PointerRNA *ptr)
return ptrpath;
}
+char *RNA_path_from_real_ID_to_struct(Main *bmain, PointerRNA *ptr, struct ID **r_real)
+{
+ char *path = RNA_path_from_ID_to_struct(ptr);
+
+ /* NULL path is valid in that case, when given struct is an ID one... */
+ return rna_prepend_real_ID_path(bmain, ptr->owner_id, path, r_real);
+}
+
static void rna_path_array_multi_from_flat_index(const int dimsize[RNA_MAX_ARRAY_LENGTH],
const int totdims,
const int index_dim,
@@ -5905,6 +5987,16 @@ char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop)
return RNA_path_from_ID_to_property_index(ptr, prop, 0, -1);
}
+char *RNA_path_from_real_ID_to_property_index(
+ Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index, ID **r_real_id)
+{
+ char *path = RNA_path_from_ID_to_property_index(ptr, prop, index_dim, index);
+
+ /* NULL path is always an error here, in that case do not return the 'fake ID from real ID' part
+ * of the path either. */
+ return path != NULL ? rna_prepend_real_ID_path(bmain, ptr->owner_id, path, r_real_id) : NULL;
+}
+
/**
* \return the path to given ptr/prop from the closest ancestor of given type,
* if any (else return NULL).
@@ -5951,20 +6043,34 @@ char *RNA_path_resolve_from_type_to_property(PointerRNA *ptr,
* Get the ID as a python representation, eg:
* bpy.data.foo["bar"]
*/
-char *RNA_path_full_ID_py(ID *id)
+char *RNA_path_full_ID_py(Main *bmain, ID *id)
{
+ const char *path;
+ ID *id_real = RNA_find_real_ID_and_path(bmain, id, &path);
+
+ if (id_real) {
+ id = id_real;
+ }
+ else {
+ path = "";
+ }
+
char id_esc[(sizeof(id->name) - 2) * 2];
BLI_strescape(id_esc, id->name + 2, sizeof(id_esc));
- return BLI_sprintfN("bpy.data.%s[\"%s\"]", BKE_idcode_to_name_plural(GS(id->name)), id_esc);
+ return BLI_sprintfN("bpy.data.%s[\"%s\"]%s%s",
+ BKE_idcode_to_name_plural(GS(id->name)),
+ id_esc,
+ path[0] ? "." : "",
+ path);
}
/**
* Get the ID.struct as a python representation, eg:
* bpy.data.foo["bar"].some_struct
*/
-char *RNA_path_full_struct_py(struct PointerRNA *ptr)
+char *RNA_path_full_struct_py(Main *bmain, struct PointerRNA *ptr)
{
char *id_path;
char *data_path;
@@ -5976,7 +6082,7 @@ char *RNA_path_full_struct_py(struct PointerRNA *ptr)
}
/* never fails */
- id_path = RNA_path_full_ID_py(ptr->owner_id);
+ id_path = RNA_path_full_ID_py(bmain, ptr->owner_id);
data_path = RNA_path_from_ID_to_struct(ptr);
@@ -5996,10 +6102,8 @@ char *RNA_path_full_struct_py(struct PointerRNA *ptr)
* Get the ID.struct.property as a python representation, eg:
* bpy.data.foo["bar"].some_struct.some_prop[10]
*/
-char *RNA_path_full_property_py_ex(PointerRNA *ptr,
- PropertyRNA *prop,
- int index,
- bool use_fallback)
+char *RNA_path_full_property_py_ex(
+ Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback)
{
char *id_path;
const char *data_delim;
@@ -6013,7 +6117,7 @@ char *RNA_path_full_property_py_ex(PointerRNA *ptr,
}
/* never fails */
- id_path = RNA_path_full_ID_py(ptr->owner_id);
+ id_path = RNA_path_full_ID_py(bmain, ptr->owner_id);
data_path = RNA_path_from_ID_to_property(ptr, prop);
if (data_path) {
@@ -6046,9 +6150,9 @@ char *RNA_path_full_property_py_ex(PointerRNA *ptr,
return ret;
}
-char *RNA_path_full_property_py(PointerRNA *ptr, PropertyRNA *prop, int index)
+char *RNA_path_full_property_py(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index)
{
- return RNA_path_full_property_py_ex(ptr, prop, index, false);
+ return RNA_path_full_property_py_ex(bmain, ptr, prop, index, false);
}
/**
@@ -6646,16 +6750,16 @@ char *RNA_pointer_as_string_id(bContext *C, PointerRNA *ptr)
return cstring;
}
-static char *rna_pointer_as_string__bldata(PointerRNA *ptr)
+static char *rna_pointer_as_string__bldata(Main *bmain, PointerRNA *ptr)
{
if (ptr->type == NULL || ptr->owner_id == NULL) {
return BLI_strdup("None");
}
else if (RNA_struct_is_ID(ptr->type)) {
- return RNA_path_full_ID_py(ptr->owner_id);
+ return RNA_path_full_ID_py(bmain, ptr->owner_id);
}
else {
- return RNA_path_full_struct_py(ptr);
+ return RNA_path_full_struct_py(bmain, ptr);
}
}
@@ -6672,7 +6776,7 @@ char *RNA_pointer_as_string(bContext *C,
return RNA_pointer_as_string_id(C, ptr_prop);
}
else {
- return rna_pointer_as_string__bldata(ptr_prop);
+ return rna_pointer_as_string__bldata(CTX_data_main(C), ptr_prop);
}
}
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c
index b0a83ea38c6..b061c72157e 100644
--- a/source/blender/makesrna/intern/rna_access_compare_override.c
+++ b/source/blender/makesrna/intern/rna_access_compare_override.c
@@ -76,8 +76,8 @@ bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop)
}
else {
/* If this is a real 'pure' IDProp (aka custom property), we want to use the IDProp flag. */
- return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) &&
- (((IDProperty *)prop)->flag & IDP_FLAG_OVERRIDABLE_LIBRARY);
+ IDProperty *idprop = (IDProperty *)prop;
+ return (idprop->flag & IDP_FLAG_OVERRIDABLE_LIBRARY) != 0;
}
}
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index 6157ec41f19..e1a24326474 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -668,8 +668,7 @@ static FCurve *rna_Driver_new(
return NULL;
}
- short add_mode = 1;
- FCurve *fcu = verify_driver_fcurve(id, rna_path, array_index, add_mode);
+ FCurve *fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_KEYFRAMES);
BLI_assert(fcu != NULL);
DEG_relations_tag_update(bmain);
diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c
index 17a58a61fb5..f539da488ce 100644
--- a/source/blender/makesrna/intern/rna_animviz.c
+++ b/source/blender/makesrna/intern/rna_animviz.c
@@ -144,7 +144,7 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna)
prop = RNA_def_property(srna, "line_thickness", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "line_thickness");
RNA_def_property_range(prop, 1, 6);
- RNA_def_property_ui_text(prop, "Line thickness", "Line thickness for drawing path");
+ RNA_def_property_ui_text(prop, "Line Thickness", "Line thickness for drawing path");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
/* Settings */
@@ -164,7 +164,7 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna)
/* Use custom color */
prop = RNA_def_property(srna, "use_custom_color", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_CUSTOM);
- RNA_def_property_ui_text(prop, "Custom colors", "Use custom color for this motion path");
+ RNA_def_property_ui_text(prop, "Custom Colors", "Use custom color for this motion path");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
/* Draw lines between keyframes */
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index d3bdcf03d4d..4dc383a2460 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -36,6 +36,8 @@
#ifdef RNA_RUNTIME
+# include "BLI_math_vector.h"
+
# include "BKE_action.h"
# include "BKE_context.h"
# include "BKE_global.h"
@@ -303,6 +305,40 @@ static void rna_Bone_layer_set(PointerRNA *ptr, const bool *values)
BKE_armature_refresh_layer_used(arm);
}
+/* TODO: remove the deprecation stubs. */
+static bool rna_use_inherit_scale_get(char inherit_scale_mode)
+{
+ return inherit_scale_mode <= BONE_INHERIT_SCALE_FIX_SHEAR;
+}
+
+static void rna_use_inherit_scale_set(char *inherit_scale_mode, bool value)
+{
+ bool cur_value = (*inherit_scale_mode <= BONE_INHERIT_SCALE_FIX_SHEAR);
+ if (value != cur_value) {
+ *inherit_scale_mode = (value ? BONE_INHERIT_SCALE_FULL : BONE_INHERIT_SCALE_NONE);
+ }
+}
+
+static bool rna_EditBone_use_inherit_scale_get(PointerRNA *ptr)
+{
+ return rna_use_inherit_scale_get(((EditBone *)ptr->data)->inherit_scale_mode);
+}
+
+static void rna_EditBone_use_inherit_scale_set(PointerRNA *ptr, bool value)
+{
+ rna_use_inherit_scale_set(&((EditBone *)ptr->data)->inherit_scale_mode, value);
+}
+
+static bool rna_Bone_use_inherit_scale_get(PointerRNA *ptr)
+{
+ return rna_use_inherit_scale_get(((Bone *)ptr->data)->inherit_scale_mode);
+}
+
+static void rna_Bone_use_inherit_scale_set(PointerRNA *ptr, bool value)
+{
+ rna_use_inherit_scale_set(&((Bone *)ptr->data)->inherit_scale_mode, value);
+}
+
static void rna_Armature_layer_set(PointerRNA *ptr, const bool *values)
{
bArmature *arm = (bArmature *)ptr->data;
@@ -449,6 +485,22 @@ static void rna_EditBone_matrix_set(PointerRNA *ptr, const float *values)
ED_armature_ebone_from_mat4(ebone, (float(*)[4])values);
}
+static float rna_EditBone_length_get(PointerRNA *ptr)
+{
+ EditBone *ebone = (EditBone *)(ptr->data);
+ return len_v3v3(ebone->head, ebone->tail);
+}
+
+static void rna_EditBone_length_set(PointerRNA *ptr, float length)
+{
+ EditBone *ebone = (EditBone *)(ptr->data);
+ float delta[3];
+
+ sub_v3_v3v3(delta, ebone->tail, ebone->head);
+ normalize_v3(delta);
+ madd_v3_v3v3fl(ebone->tail, ebone->head, delta, length);
+}
+
static void rna_Bone_bbone_handle_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bArmature *arm = (bArmature *)ptr->owner_id;
@@ -613,16 +665,19 @@ static void rna_Armature_transform(bArmature *arm, float *mat)
/* Settings for curved bbone settings -
* The posemode values get applied over the top of the editmode ones. */
-void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
+void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone, bool is_editbone)
{
-# define RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone) \
+# define RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone) \
{ \
if (is_posebone) { \
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update"); \
} \
- else { \
+ else if (is_editbone) { \
RNA_def_property_update(prop, 0, "rna_Armature_editbone_transform_update"); \
} \
+ else { \
+ RNA_def_property_update(prop, 0, "rna_Armature_update_data"); \
+ } \
} \
((void)0)
@@ -634,14 +689,14 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
RNA_def_property_ui_range(prop, -M_PI * 2, M_PI * 2, 10, 2);
RNA_def_property_ui_text(
prop, "Roll In", "Roll offset for the start of the B-Bone, adjusts twist");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
prop = RNA_def_property(srna, "bbone_rollout", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "roll2");
RNA_def_property_ui_range(prop, -M_PI * 2, M_PI * 2, 10, 2);
RNA_def_property_ui_text(
prop, "Roll Out", "Roll offset for the end of the B-Bone, adjusts twist");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
if (is_posebone == false) {
prop = RNA_def_property(srna, "use_endroll_as_inroll", PROP_BOOLEAN, PROP_NONE);
@@ -658,28 +713,28 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_ui_text(
prop, "In X", "X-axis handle offset for start of the B-Bone's curve, adjusts curvature");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
prop = RNA_def_property(srna, "bbone_curveiny", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "curve_in_y");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_ui_text(
prop, "In Y", "Y-axis handle offset for start of the B-Bone's curve, adjusts curvature");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
prop = RNA_def_property(srna, "bbone_curveoutx", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "curve_out_x");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_ui_text(
prop, "Out X", "X-axis handle offset for end of the B-Bone's curve, adjusts curvature");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
prop = RNA_def_property(srna, "bbone_curveouty", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "curve_out_y");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_ui_text(
prop, "Out Y", "Y-axis handle offset for end of the B-Bone's curve, adjusts curvature");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
/* Ease In/Out */
prop = RNA_def_property(srna, "bbone_easein", PROP_FLOAT, PROP_NONE);
@@ -687,14 +742,14 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
RNA_def_property_ui_range(prop, -5.0f, 5.0f, 1, 3);
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Ease In", "Length of first Bezier Handle (for B-Bones only)");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
prop = RNA_def_property(srna, "bbone_easeout", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "ease2");
RNA_def_property_ui_range(prop, -5.0f, 5.0f, 1, 3);
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Ease Out", "Length of second Bezier Handle (for B-Bones only)");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
/* Scale In/Out */
prop = RNA_def_property(srna, "bbone_scaleinx", PROP_FLOAT, PROP_NONE);
@@ -706,7 +761,7 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
"Scale In X",
"X-axis scale factor for start of the B-Bone, "
"adjusts thickness (for tapering effects)");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
prop = RNA_def_property(srna, "bbone_scaleiny", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "scale_in_y");
@@ -717,7 +772,7 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
"Scale In Y",
"Y-axis scale factor for start of the B-Bone, "
"adjusts thickness (for tapering effects)");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
prop = RNA_def_property(srna, "bbone_scaleoutx", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "scale_out_x");
@@ -728,7 +783,7 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
"Scale Out X",
"X-axis scale factor for end of the B-Bone, "
"adjusts thickness (for tapering effects)");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
prop = RNA_def_property(srna, "bbone_scaleouty", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "scale_out_y");
@@ -739,7 +794,7 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
"Scale Out Y",
"Y-axis scale factor for end of the B-Bone, "
"adjusts thickness (for tapering effects)");
- RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
+ RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone);
# undef RNA_DEF_CURVEBONE_UPDATE
}
@@ -770,6 +825,28 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem prop_inherit_scale_mode[] = {
+ {BONE_INHERIT_SCALE_FULL, "FULL", 0, "Full", "Inherit all effects of parent scaling"},
+ {BONE_INHERIT_SCALE_FIX_SHEAR,
+ "FIX_SHEAR",
+ 0,
+ "Fix Shear",
+ "Inherit scaling, but remove shearing of the child in the rest orientation"},
+ {BONE_INHERIT_SCALE_AVERAGE,
+ "AVERAGE",
+ 0,
+ "Average",
+ "Inherit uniform scaling representing the overall change in the volume of the parent"},
+ {BONE_INHERIT_SCALE_NONE, "NONE", 0, "None", "Completely ignore parent scaling"},
+ {BONE_INHERIT_SCALE_NONE_LEGACY,
+ "NONE_LEGACY",
+ 0,
+ "None (Legacy)",
+ "Ignore parent scaling without compensating for parent shear. "
+ "Replicates the effect of disabling the original Inherit Scale checkbox"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
PropertyRNA *prop;
/* strings */
@@ -829,9 +906,25 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
RNA_def_property_ui_text(prop, "Deform", "Enable Bone to deform geometry");
RNA_def_property_update(prop, 0, "rna_Armature_update_data");
+ prop = RNA_def_property(srna, "inherit_scale", PROP_ENUM, PROP_NONE);
+ RNA_def_property_ui_text(
+ prop, "Inherit Scale", "Specifies how the bone inherits scaling from the parent bone");
+ RNA_def_property_enum_sdna(prop, NULL, "inherit_scale_mode");
+ RNA_def_property_enum_items(prop, prop_inherit_scale_mode);
+ RNA_def_property_update(prop, 0, "rna_Armature_update_data");
+
+ /* TODO: remove the compatibility stub. */
prop = RNA_def_property(srna, "use_inherit_scale", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_ui_text(prop, "Inherit Scale", "Bone inherits scaling from parent bone");
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", BONE_NO_SCALE);
+ RNA_def_property_ui_text(
+ prop, "Inherit Scale", "DEPRECATED: Bone inherits scaling from parent bone");
+ if (editbone) {
+ RNA_def_property_boolean_funcs(
+ prop, "rna_EditBone_use_inherit_scale_get", "rna_EditBone_use_inherit_scale_set");
+ }
+ else {
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Bone_use_inherit_scale_get", "rna_Bone_use_inherit_scale_set");
+ }
RNA_def_property_update(prop, 0, "rna_Armature_update_data");
prop = RNA_def_property(srna, "use_local_location", PROP_BOOLEAN, PROP_NONE);
@@ -1030,7 +1123,7 @@ static void rna_def_bone(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Children", "Bones which are children of this bone");
rna_def_bone_common(srna, 0);
- rna_def_bone_curved_common(srna, 0);
+ rna_def_bone_curved_common(srna, false, false);
/* XXX should we define this in PoseChannel wrapping code instead?
* But PoseChannels directly get some of their flags from here... */
@@ -1066,27 +1159,28 @@ static void rna_def_bone(BlenderRNA *brna)
prop = RNA_def_property(srna, "matrix", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_float_sdna(prop, NULL, "bone_mat");
RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_3x3);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Bone Matrix", "3x3 bone matrix");
prop = RNA_def_property(srna, "matrix_local", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_float_sdna(prop, NULL, "arm_mat");
RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "Bone Armature-Relative Matrix", "4x4 bone matrix relative to armature");
prop = RNA_def_property(srna, "tail", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "tail");
RNA_def_property_array(prop, 3);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Tail", "Location of tail end of the bone");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(
+ prop, "Tail", "Location of tail end of the bone relative to its parent");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
prop = RNA_def_property(srna, "tail_local", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "arm_tail");
RNA_def_property_array(prop, 3);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "Armature-Relative Tail", "Location of tail end of the bone relative to armature");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
@@ -1094,7 +1188,7 @@ static void rna_def_bone(BlenderRNA *brna)
prop = RNA_def_property(srna, "head", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "head");
RNA_def_property_array(prop, 3);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "Head", "Location of head end of the bone relative to its parent");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
@@ -1102,11 +1196,16 @@ static void rna_def_bone(BlenderRNA *brna)
prop = RNA_def_property(srna, "head_local", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "arm_head");
RNA_def_property_array(prop, 3);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "Armature-Relative Head", "Location of head end of the bone relative to armature");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
+ prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "length");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Length", "Length of the bone");
+
RNA_api_bone(srna);
}
@@ -1152,8 +1251,16 @@ static void rna_def_edit_bone(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, 0, "rna_Armature_editbone_transform_update");
+ prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_funcs(prop, "rna_EditBone_length_get", "rna_EditBone_length_set", NULL);
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
+ RNA_def_property_ui_text(prop, "Length", "Length of the bone. Changing moves the tail end");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_Armature_editbone_transform_update");
+
rna_def_bone_common(srna, 1);
- rna_def_bone_curved_common(srna, 0);
+ rna_def_bone_curved_common(srna, false, true);
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_HIDDEN_A);
diff --git a/source/blender/makesrna/intern/rna_armature_api.c b/source/blender/makesrna/intern/rna_armature_api.c
index f3bdef75c9c..2b60dbde39f 100644
--- a/source/blender/makesrna/intern/rna_armature_api.c
+++ b/source/blender/makesrna/intern/rna_armature_api.c
@@ -71,14 +71,15 @@ static void rna_Bone_convert_local_to_pose(Bone *bone,
if (is_zero_m4(parent_pose_mat) || is_zero_m4(parent_arm_mat)) {
/* No parent case. */
- BKE_bone_parent_transform_calc_from_matrices(bone->flag, bone_arm_mat, NULL, NULL, &bpt);
+ BKE_bone_parent_transform_calc_from_matrices(
+ bone->flag, bone->inherit_scale_mode, bone_arm_mat, NULL, NULL, &bpt);
}
else {
invert_m4_m4(offs_bone, parent_arm_mat);
mul_m4_m4m4(offs_bone, offs_bone, bone_arm_mat);
BKE_bone_parent_transform_calc_from_matrices(
- bone->flag, offs_bone, parent_arm_mat, parent_pose_mat, &bpt);
+ bone->flag, bone->inherit_scale_mode, offs_bone, parent_arm_mat, parent_pose_mat, &bpt);
}
if (invert) {
diff --git a/source/blender/makesrna/intern/rna_boid.c b/source/blender/makesrna/intern/rna_boid.c
index 722b7b12271..01d1d1ddddb 100644
--- a/source/blender/makesrna/intern/rna_boid.c
+++ b/source/blender/makesrna/intern/rna_boid.c
@@ -355,7 +355,7 @@ static void rna_def_boidrule_avoid(BlenderRNA *brna)
prop = RNA_def_property(srna, "fear_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0f, 100.0f);
RNA_def_property_ui_text(
- prop, "Fear factor", "Avoid object if danger from it is above this threshold");
+ prop, "Fear Factor", "Avoid object if danger from it is above this threshold");
RNA_def_property_update(prop, 0, "rna_Boids_reset");
}
@@ -379,7 +379,7 @@ static void rna_def_boidrule_avoid_collision(BlenderRNA *brna)
prop = RNA_def_property(srna, "look_ahead", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0f, 100.0f);
- RNA_def_property_ui_text(prop, "Look ahead", "Time to look ahead in seconds");
+ RNA_def_property_ui_text(prop, "Look Ahead", "Time to look ahead in seconds");
RNA_def_property_update(prop, 0, "rna_Boids_reset");
}
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 15602599e4e..d7bb941b266 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -70,6 +70,7 @@ static const EnumPropertyItem sculpt_stroke_method_items[] = {
const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
{SCULPT_TOOL_DRAW, "DRAW", ICON_BRUSH_SCULPT_DRAW, "Draw", ""},
+ {SCULPT_TOOL_DRAW_SHARP, "DRAW_SHARP", ICON_BRUSH_SCULPT_DRAW, "Draw Sharp", ""},
{SCULPT_TOOL_CLAY, "CLAY", ICON_BRUSH_CLAY, "Clay", ""},
{SCULPT_TOOL_CLAY_STRIPS, "CLAY_STRIPS", ICON_BRUSH_CLAY_STRIPS, "Clay Strips", ""},
{SCULPT_TOOL_LAYER, "LAYER", ICON_BRUSH_LAYER, "Layer", ""},
@@ -84,8 +85,10 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
{SCULPT_TOOL_PINCH, "PINCH", ICON_BRUSH_PINCH, "Pinch", ""},
{0, "", 0, NULL, NULL},
{SCULPT_TOOL_GRAB, "GRAB", ICON_BRUSH_GRAB, "Grab", ""},
+ {SCULPT_TOOL_ELASTIC_DEFORM, "ELASTIC_DEFORM", ICON_BRUSH_GRAB, "Elastic Deform", ""},
{SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", ICON_BRUSH_SNAKE_HOOK, "Snake Hook", ""},
{SCULPT_TOOL_THUMB, "THUMB", ICON_BRUSH_THUMB, "Thumb", ""},
+ {SCULPT_TOOL_POSE, "POSE", ICON_BRUSH_GRAB, "Pose", ""},
{SCULPT_TOOL_NUDGE, "NUDGE", ICON_BRUSH_NUDGE, "Nudge", ""},
{SCULPT_TOOL_ROTATE, "ROTATE", ICON_BRUSH_ROTATE, "Rotate", ""},
{0, "", 0, NULL, NULL},
@@ -167,6 +170,8 @@ static EnumPropertyItem rna_enum_gpencil_brush_icons_items[] = {
{GP_BRUSH_ICON_INKNOISE, "INKNOISE", ICON_GPBRUSH_INKNOISE, "Ink Noise", ""},
{GP_BRUSH_ICON_BLOCK, "BLOCK", ICON_GPBRUSH_BLOCK, "Block", ""},
{GP_BRUSH_ICON_MARKER, "MARKER", ICON_GPBRUSH_MARKER, "Marker", ""},
+ {GP_BRUSH_ICON_AIRBRUSH, "AIRBRUSH", ICON_GPBRUSH_AIRBRUSH, "Airbrush", ""},
+ {GP_BRUSH_ICON_CHISEL, "CHISEL", ICON_GPBRUSH_CHISEL, "Chisel", ""},
{GP_BRUSH_ICON_FILL, "FILL", ICON_GPBRUSH_FILL, "Fill", ""},
{GP_BRUSH_ICON_ERASE_SOFT, "SOFT", ICON_GPBRUSH_ERASE_SOFT, "Eraser Soft", ""},
{GP_BRUSH_ICON_ERASE_HARD, "HARD", ICON_GPBRUSH_ERASE_HARD, "Eraser Hard", ""},
@@ -382,6 +387,7 @@ static bool rna_BrushCapabilitiesSculpt_has_direction_get(PointerRNA *ptr)
Brush *br = (Brush *)ptr->data;
return !ELEM(br->sculpt_tool,
SCULPT_TOOL_DRAW,
+ SCULPT_TOOL_DRAW_SHARP,
SCULPT_TOOL_CLAY,
SCULPT_TOOL_CLAY_STRIPS,
SCULPT_TOOL_LAYER,
@@ -645,6 +651,7 @@ static const EnumPropertyItem *rna_Brush_direction_itemf(bContext *C,
case PAINT_MODE_SCULPT:
switch (me->sculpt_tool) {
case SCULPT_TOOL_DRAW:
+ case SCULPT_TOOL_DRAW_SHARP:
case SCULPT_TOOL_CREASE:
case SCULPT_TOOL_BLOB:
case SCULPT_TOOL_LAYER:
@@ -1184,6 +1191,14 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+ /* Simplify factor */
+ prop = RNA_def_property(srna, "simplify_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "simplify_f");
+ RNA_def_property_range(prop, 0, 100.0);
+ RNA_def_property_ui_range(prop, 0, 100.0, 1.0f, 3);
+ RNA_def_property_ui_text(prop, "Simplify", "Factor of Simplify using adaptive algorithm");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
/* Curves for pressure */
prop = RNA_def_property(srna, "curve_sensitivity", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "curve_sensitivity");
@@ -1283,7 +1298,7 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
prop = RNA_def_property(srna, "active_smooth_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "active_smooth");
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Active Smooth", "Amount of smoothing while drawing ");
+ RNA_def_property_ui_text(prop, "Active Smooth", "Amount of smoothing while drawing");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
@@ -1291,7 +1306,7 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "era_strength_f");
RNA_def_property_range(prop, 0.0, 100.0);
RNA_def_property_ui_range(prop, 0.0, 100.0, 10, 1);
- RNA_def_property_ui_text(prop, "Affect Stroke Strength", "Amount of erasing for strength ");
+ RNA_def_property_ui_text(prop, "Affect Stroke Strength", "Amount of erasing for strength");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
@@ -1299,7 +1314,7 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "era_thickness_f");
RNA_def_property_range(prop, 0.0, 100.0);
RNA_def_property_ui_range(prop, 0.0, 100.0, 10, 1);
- RNA_def_property_ui_text(prop, "Affect Stroke Thickness", "Amount of erasing for thickness ");
+ RNA_def_property_ui_text(prop, "Affect Stroke Thickness", "Amount of erasing for thickness");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
@@ -1571,6 +1586,16 @@ static void rna_def_brush(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem brush_spacing_unit_items[] = {
+ {0, "VIEW", 0, "View", "Calculate brush spacing relative to the view"},
+ {BRUSH_SCENE_SPACING,
+ "SCENE",
+ 0,
+ "Scene",
+ "Calculate brush spacing relative to the scene using the stroke location"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
static const EnumPropertyItem brush_curve_preset_items[] = {
{BRUSH_CURVE_CUSTOM, "CUSTOM", ICON_RNDCURVE, "Custom", ""},
{BRUSH_CURVE_SMOOTH, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", ""},
@@ -1584,6 +1609,19 @@ static void rna_def_brush(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem brush_elastic_deform_type_items[] = {
+ {BRUSH_ELASTIC_DEFORM_GRAB, "ELASTIC_DEFORM_GRAB", 0, "Grab", ""},
+ {BRUSH_ELASTIC_DEFORM_GRAB_BISCALE, "ELASTIC_DEFORM_GRAB_BISCALE", 0, "Bi-scale Grab", ""},
+ {BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE,
+ "ELASTIC_DEFORM_GRAB_TRISCALE",
+ 0,
+ "Tri-scale Grab",
+ ""},
+ {BRUSH_ELASTIC_DEFORM_SCALE, "ELASTIC_DEFORM_SCALE", 0, "Scale", ""},
+ {BRUSH_ELASTIC_DEFORM_TWIST, "ELASTIC_DEFORM_TWIST", 0, "Twist", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "Brush", "ID");
RNA_def_struct_ui_text(
srna, "Brush", "Brush data-block for storing brush settings for painting and sculpting");
@@ -1592,7 +1630,7 @@ static void rna_def_brush(BlenderRNA *brna)
/* enums */
prop = RNA_def_property(srna, "blend", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_blend_items);
- RNA_def_property_ui_text(prop, "Blending mode", "Brush blending mode");
+ RNA_def_property_ui_text(prop, "Blending Mode", "Brush blending mode");
RNA_def_property_update(prop, 0, "rna_Brush_update");
/**
@@ -1664,6 +1702,11 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Curve Preset", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "elastic_deform_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, brush_elastic_deform_type_items);
+ RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
/* number values */
prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL);
RNA_def_property_int_funcs(prop, NULL, "rna_Brush_set_size", NULL);
@@ -1675,7 +1718,7 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "unprojected_radius", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_funcs(prop, NULL, "rna_Brush_set_unprojected_radius", NULL);
RNA_def_property_range(prop, 0.001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.001, 1, 0, -1);
+ RNA_def_property_ui_range(prop, 0.001, 1, 1, -1);
RNA_def_property_ui_text(prop, "Unprojected Radius", "Radius of brush in Blender units");
RNA_def_property_update(prop, 0, "rna_Brush_size_update");
@@ -1740,7 +1783,6 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 1.0f);
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", "Vertex weight when brush is applied");
@@ -1748,7 +1790,6 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "alpha");
- 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(
@@ -1768,7 +1809,6 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "plane_trim", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "plane_trim");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0, 1.0f);
RNA_def_property_ui_text(
prop,
@@ -1799,6 +1839,16 @@ static void rna_def_brush(BlenderRNA *brna)
prop, "Normal Weight", "How much grab will pull vertexes out of surface during a grab");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "elastic_deform_volume_preservation", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "elastic_deform_volume_preservation");
+ RNA_def_property_range(prop, 0.0f, 0.9f);
+ RNA_def_property_ui_range(prop, 0.0f, 0.9f, 0.01f, 3);
+ RNA_def_property_ui_text(prop,
+ "Volume Preservation",
+ "Poisson ratio for elastic deformation. Higher values preserve volume "
+ "more, but also lead to more bulging");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "rake_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "rake_factor");
RNA_def_property_float_default(prop, 0);
@@ -1809,11 +1859,17 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "crease_pinch_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "crease_pinch_factor");
- RNA_def_property_float_default(prop, 2.0f / 3.0f);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Crease Brush Pinch Factor", "How much the crease brush pinches");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "pose_offset", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "pose_offset");
+ RNA_def_property_range(prop, 0.0f, 2.0f);
+ RNA_def_property_ui_text(
+ prop, "Pose Origin Offset", "Offset of the pose origin in relation to the brush radius");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "auto_smooth_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "autosmooth_factor");
RNA_def_property_float_default(prop, 0);
@@ -1835,6 +1891,16 @@ static void rna_def_brush(BlenderRNA *brna)
"Best used on low-poly meshes as it has a performance impact");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "normal_radius_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "normal_radius_factor");
+ 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,
+ "Normal Radius",
+ "Ratio between the brush radius and the radius that is going to be "
+ "used to sample the normal");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "stencil_pos", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "stencil_pos");
RNA_def_property_array(prop, 2);
@@ -1879,7 +1945,6 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "blur_kernel_radius", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "blur_kernel_radius");
RNA_def_property_range(prop, 1, 10000);
- RNA_def_property_int_default(prop, 2);
RNA_def_property_ui_range(prop, 1, 50, 1, -1);
RNA_def_property_ui_text(
prop, "Kernel Radius", "Radius of kernel used for soften and sharpen in pixels");
@@ -1920,6 +1985,36 @@ static void rna_def_brush(BlenderRNA *brna)
"When locked keep using normal of surface where stroke was initiated");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "use_original_plane", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ORIGINAL_PLANE);
+ RNA_def_property_ui_text(
+ prop,
+ "Original Plane",
+ "When locked keep using the plane origin of surface where stroke was initiated");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop = RNA_def_property(srna, "use_automasking_topology", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_TOPOLOGY);
+ RNA_def_property_ui_text(prop,
+ "Topology Automasking",
+ "Affect only vertices connected to the active vertex under the brush");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop = RNA_def_property(srna, "use_scene_spacing", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
+ RNA_def_property_enum_items(prop, brush_spacing_unit_items);
+ RNA_def_property_ui_text(
+ prop, "Spacing Distance", "Calculate the brush spacing using view or scene distance");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop = RNA_def_property(srna, "use_grab_active_vertex", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_GRAB_ACTIVE_VERTEX);
+ RNA_def_property_ui_text(
+ prop,
+ "Grab Active Vertex",
+ "Apply the maximum grab strength to the active vertex instead of the cursor location");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "use_pressure_strength", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ALPHA_PRESSURE);
RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index 88083f600f8..47a09233769 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -436,7 +436,6 @@ static void rna_def_camera_dof_settings_data(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dependency_update");
prop = RNA_def_property(srna, "focus_distance", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_default(prop, 10.0f);
// RNA_def_property_pointer_sdna(prop, NULL, "focus_distance");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0f, 5000.0f, 1, 2);
@@ -449,7 +448,6 @@ static void rna_def_camera_dof_settings_data(BlenderRNA *brna)
prop,
"F-Stop",
"F-Stop ratio (lower numbers give more defocus, higher numbers give a sharper image)");
- RNA_def_property_float_default(prop, 5.6f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.1f, 128.0f, 10, 1);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dof_update");
@@ -468,7 +466,6 @@ static void rna_def_camera_dof_settings_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "aperture_ratio", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(prop, "Ratio", "Distortion to simulate anamorphic lens bokeh");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_range(prop, 0.01f, FLT_MAX);
RNA_def_property_ui_range(prop, 1.0f, 2.0f, 0.1, 3);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dof_update");
@@ -525,7 +522,6 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "passepartout_alpha", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "passepartalpha");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_ui_text(
prop, "Passepartout Alpha", "Opacity (alpha) of the darkened overlay in Camera view");
RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL);
@@ -552,14 +548,12 @@ void RNA_def_camera(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_update");
prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_ui_text(prop, "Clip Start", "Camera near clipping distance");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_default(prop, 1000.0f);
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_ui_text(prop, "Clip End", "Camera far clipping distance");
@@ -567,7 +561,6 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "lens", PROP_FLOAT, PROP_DISTANCE_CAMERA);
RNA_def_property_float_sdna(prop, NULL, "lens");
- RNA_def_property_float_default(prop, 50.0f);
RNA_def_property_range(prop, 1.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 1.0f, 5000.0f, 100, 4);
RNA_def_property_ui_text(prop, "Focal Length", "Perspective Camera lens value in millimeters");
@@ -575,7 +568,6 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "sensor_width", PROP_FLOAT, PROP_DISTANCE_CAMERA);
RNA_def_property_float_sdna(prop, NULL, "sensor_x");
- RNA_def_property_float_default(prop, 36.0f);
RNA_def_property_range(prop, 1.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 1.0f, 100.f, 100, 4);
RNA_def_property_ui_text(
@@ -584,7 +576,6 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "sensor_height", PROP_FLOAT, PROP_DISTANCE_CAMERA);
RNA_def_property_float_sdna(prop, NULL, "sensor_y");
- RNA_def_property_float_default(prop, 34.0f);
RNA_def_property_range(prop, 1.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 1.0f, 100.f, 100, 4);
RNA_def_property_ui_text(
@@ -593,7 +584,6 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "ortho_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "ortho_scale");
- RNA_def_property_float_default(prop, 6.0f);
RNA_def_property_range(prop, FLT_MIN, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, 10000.0f, 10, 3);
RNA_def_property_ui_text(
@@ -602,7 +592,6 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "display_size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "drawsize");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_range(prop, 0.01f, 1000.0f);
RNA_def_property_ui_range(prop, 0.01, 100, 1, 2);
RNA_def_property_ui_text(
@@ -645,7 +634,6 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_passepartout", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_SHOWPASSEPARTOUT);
- RNA_def_property_boolean_default(prop, true);
RNA_def_property_ui_text(
prop, "Show Passepartout", "Show a darkened overlay outside the image area in Camera view");
RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL);
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 08d2a03b2a9..7732bf531d8 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -256,6 +256,17 @@ static const EnumPropertyItem track_axis_items[] = {
{0, NULL, 0, NULL, NULL},
};
+static const EnumPropertyItem euler_order_items[] = {
+ {CONSTRAINT_EULER_AUTO, "AUTO", 0, "Default", "Euler using the default rotation order"},
+ {CONSTRAINT_EULER_XYZ, "XYZ", 0, "XYZ Euler", "Euler using the XYZ rotation order"},
+ {CONSTRAINT_EULER_XZY, "XZY", 0, "XZY Euler", "Euler using the XZY rotation order"},
+ {CONSTRAINT_EULER_YXZ, "YXZ", 0, "YXZ Euler", "Euler using the YXZ rotation order"},
+ {CONSTRAINT_EULER_YZX, "YZX", 0, "YZX Euler", "Euler using the YZX rotation order"},
+ {CONSTRAINT_EULER_ZXY, "ZXY", 0, "ZXY Euler", "Euler using the ZXY rotation order"},
+ {CONSTRAINT_EULER_ZYX, "ZYX", 0, "ZYX Euler", "Euler using the ZYX rotation order"},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifdef RNA_RUNTIME
static const EnumPropertyItem space_object_items[] = {
@@ -519,6 +530,24 @@ static void rna_Constraint_ik_type_set(struct PointerRNA *ptr, int value)
}
}
+/* DEPRECATED: use_offset replaced with mix_mode */
+static bool rna_Constraint_RotLike_use_offset_get(struct PointerRNA *ptr)
+{
+ bConstraint *con = ptr->data;
+ bRotateLikeConstraint *rotlike = con->data;
+ return rotlike->mix_mode != ROTLIKE_MIX_REPLACE;
+}
+
+static void rna_Constraint_RotLike_use_offset_set(struct PointerRNA *ptr, bool value)
+{
+ bConstraint *con = ptr->data;
+ bRotateLikeConstraint *rotlike = con->data;
+ bool curval = (rotlike->mix_mode != ROTLIKE_MIX_REPLACE);
+ if (curval != value) {
+ rotlike->mix_mode = (value ? ROTLIKE_MIX_OFFSET : ROTLIKE_MIX_REPLACE);
+ }
+}
+
static const EnumPropertyItem *rna_Constraint_owner_space_itemf(bContext *UNUSED(C),
PointerRNA *ptr,
PropertyRNA *UNUSED(prop),
@@ -1287,6 +1316,28 @@ static void rna_def_constraint_rotate_like(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
+ static const EnumPropertyItem mix_mode_items[] = {
+ {ROTLIKE_MIX_REPLACE, "REPLACE", 0, "Replace", "Replace the original rotation with copied"},
+ {ROTLIKE_MIX_ADD, "ADD", 0, "Add", "Add euler component values together"},
+ {ROTLIKE_MIX_BEFORE,
+ "BEFORE",
+ 0,
+ "Before Original",
+ "Apply copied rotation before original, as if the constraint target is a parent"},
+ {ROTLIKE_MIX_AFTER,
+ "AFTER",
+ 0,
+ "After Original",
+ "Apply copied rotation after original, as if the constraint target is a child"},
+ {ROTLIKE_MIX_OFFSET,
+ "OFFSET",
+ 0,
+ "Offset (Legacy)",
+ "Combine rotations like the original Offset checkbox. Does not work well for "
+ "multiple axis rotations"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "CopyRotationConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Copy Rotation Constraint", "Copy the rotation of the target");
RNA_def_struct_sdna_from(srna, "bRotateLikeConstraint", "data");
@@ -1324,9 +1375,25 @@ static void rna_def_constraint_rotate_like(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Invert Z", "Invert the Z rotation");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ prop = RNA_def_property(srna, "euler_order", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "euler_order");
+ RNA_def_property_enum_items(prop, euler_order_items);
+ RNA_def_property_ui_text(prop, "Euler Order", "Explicitly specify the euler rotation order");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "mix_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mix_mode");
+ RNA_def_property_enum_items(prop, mix_mode_items);
+ RNA_def_property_ui_text(
+ prop, "Mix Mode", "Specify how the copied and existing rotations are combined");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ /* DEPRECATED: replaced with mix_mode */
prop = RNA_def_property(srna, "use_offset", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ROTLIKE_OFFSET);
- RNA_def_property_ui_text(prop, "Offset", "Add original rotation into copied rotation");
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Constraint_RotLike_use_offset_get", "rna_Constraint_RotLike_use_offset_set");
+ RNA_def_property_ui_text(
+ prop, "Offset", "DEPRECATED: Add original rotation into copied rotation");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
}
@@ -1364,6 +1431,14 @@ static void rna_def_constraint_size_like(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Power", "Raise the target's scale to the specified power");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ prop = RNA_def_property(srna, "use_make_uniform", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SIZELIKE_UNIFORM);
+ RNA_def_property_ui_text(prop,
+ "Make Uniform",
+ "Redistribute the copied change in volume equally "
+ "between the three axes of the owner");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
prop = RNA_def_property(srna, "use_offset", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SIZELIKE_OFFSET);
RNA_def_property_ui_text(prop, "Offset", "Combine original scale with copied scale");
@@ -1440,6 +1515,28 @@ static void rna_def_constraint_same_volume(BlenderRNA *brna)
static void rna_def_constraint_transform_like(BlenderRNA *brna)
{
StructRNA *srna;
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem mix_mode_items[] = {
+ {TRANSLIKE_MIX_REPLACE,
+ "REPLACE",
+ 0,
+ "Replace",
+ "Replace the original transformation with copied"},
+ {TRANSLIKE_MIX_BEFORE,
+ "BEFORE",
+ 0,
+ "Before Original",
+ "Apply copied transformation before original, as if the constraint target is a parent. "
+ "Scale is handled specially to avoid creating shear"},
+ {TRANSLIKE_MIX_AFTER,
+ "AFTER",
+ 0,
+ "After Original",
+ "Apply copied transformation after original, as if the constraint target is a child. "
+ "Scale is handled specially to avoid creating shear"},
+ {0, NULL, 0, NULL, NULL},
+ };
srna = RNA_def_struct(brna, "CopyTransformsConstraint", "Constraint");
RNA_def_struct_ui_text(
@@ -1452,6 +1549,13 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna)
RNA_def_struct_ui_icon(srna, ICON_CON_TRANSLIKE);
rna_def_constraint_target_common(srna);
+
+ prop = RNA_def_property(srna, "mix_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mix_mode");
+ RNA_def_property_enum_items(prop, mix_mode_items);
+ RNA_def_property_ui_text(
+ prop, "Mix Mode", "Specify how the copied and existing transformations are combined");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
}
static void rna_def_constraint_minmax(BlenderRNA *brna)
@@ -1830,6 +1934,34 @@ static void rna_def_constraint_transform(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem mix_mode_loc_items[] = {
+ {TRANS_MIXLOC_REPLACE, "REPLACE", 0, "Replace", "Replace component values"},
+ {TRANS_MIXLOC_ADD, "ADD", 0, "Add", "Add component values together"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem mix_mode_rot_items[] = {
+ {TRANS_MIXROT_REPLACE, "REPLACE", 0, "Replace", "Replace component values"},
+ {TRANS_MIXROT_ADD, "ADD", 0, "Add", "Add component values together"},
+ {TRANS_MIXROT_BEFORE,
+ "BEFORE",
+ 0,
+ "Before Original",
+ "Apply new rotation before original, as if it was on a parent"},
+ {TRANS_MIXROT_AFTER,
+ "AFTER",
+ 0,
+ "After Original",
+ "Apply new rotation after original, as if it was on a child"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem mix_mode_scale_items[] = {
+ {TRANS_MIXSCALE_REPLACE, "REPLACE", 0, "Replace", "Replace component values"},
+ {TRANS_MIXSCALE_MULTIPLY, "MULTIPLY", 0, "Multiply", "Multiply component values together"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "TransformConstraint", "Constraint");
RNA_def_struct_ui_text(
srna, "Transformation Constraint", "Map transformations of the target to the object");
@@ -1877,6 +2009,18 @@ static void rna_def_constraint_transform(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Extrapolate Motion", "Extrapolate ranges");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ prop = RNA_def_property(srna, "from_rotation_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "from_rotation_mode");
+ RNA_def_property_enum_items(prop, rna_enum_driver_target_rotation_mode_items);
+ RNA_def_property_ui_text(prop, "From Mode", "Specify the type of rotation channels to use");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "to_euler_order", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "to_euler_order");
+ RNA_def_property_enum_items(prop, euler_order_items);
+ RNA_def_property_ui_text(prop, "To Order", "Explicitly specify the output euler rotation order");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
/* Loc */
prop = RNA_def_property(srna, "from_min_x", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "from_min[0]");
@@ -1950,6 +2094,13 @@ static void rna_def_constraint_transform(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "To Maximum Z", "Top range of Z axis destination motion");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ prop = RNA_def_property(srna, "mix_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mix_mode_loc");
+ RNA_def_property_enum_items(prop, mix_mode_loc_items);
+ RNA_def_property_ui_text(
+ prop, "Location Mix Mode", "Specify how to combine the new location with original");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
/* Rot */
prop = RNA_def_property(srna, "from_min_x_rot", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "from_min_rot[0]");
@@ -2023,6 +2174,13 @@ static void rna_def_constraint_transform(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "To Maximum Z", "Top range of Z axis destination motion");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ prop = RNA_def_property(srna, "mix_mode_rot", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mix_mode_rot");
+ RNA_def_property_enum_items(prop, mix_mode_rot_items);
+ RNA_def_property_ui_text(
+ prop, "Rotation Mix Mode", "Specify how to combine the new rotation with original");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
/* Scale */
prop = RNA_def_property(srna, "from_min_x_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "from_min_scale[0]");
@@ -2095,6 +2253,13 @@ static void rna_def_constraint_transform(BlenderRNA *brna)
RNA_def_property_ui_range(prop, -1000.0f, 1000.0f, 10, 3);
RNA_def_property_ui_text(prop, "To Maximum Z", "Top range of Z axis destination motion");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "mix_mode_scale", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mix_mode_scale");
+ RNA_def_property_enum_items(prop, mix_mode_scale_items);
+ RNA_def_property_ui_text(
+ prop, "Scale Mix Mode", "Specify how to combine the new scale with original");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
}
static void rna_def_constraint_location_limit(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index a7dac4100db..6a3ab632fd4 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -291,9 +291,7 @@ static void rna_Curve_texspace_loc_get(PointerRNA *ptr, float *values)
{
Curve *cu = (Curve *)ptr->data;
- if (!cu->bb) {
- BKE_curve_texspace_calc(cu);
- }
+ BKE_curve_texspace_ensure(cu);
copy_v3_v3(values, cu->loc);
}
@@ -309,9 +307,7 @@ static void rna_Curve_texspace_size_get(PointerRNA *ptr, float *values)
{
Curve *cu = (Curve *)ptr->data;
- if (!cu->bb) {
- BKE_curve_texspace_calc(cu);
- }
+ BKE_curve_texspace_ensure(cu);
copy_v3_v3(values, cu->size);
}
@@ -1761,15 +1757,6 @@ static void rna_def_curve(BlenderRNA *brna)
prop, "rna_Curve_texspace_size_get", "rna_Curve_texspace_size_set", NULL);
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
- /* not supported yet */
-# if 0
- prop = RNA_def_property(srna, "texspace_rot", PROP_FLOAT, PROP_EULER);
- RNA_def_property_float(prop, NULL, "rot");
- RNA_def_property_ui_text(prop, "Texture Space Rotation", "Texture space rotation");
- RNA_def_property_editable_func(prop, texspace_editable);
- RNA_def_property_update(prop, 0, "rna_Curve_update_data");
-# endif
-
prop = RNA_def_property(srna, "use_uv_as_generated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CU_UV_ORCO);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 03ab9da2eff..fc22e9e6c74 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -31,6 +31,7 @@
#include "DNA_genfile.h"
#include "DNA_sdna_types.h"
+#include "DNA_defaults.h"
#include "BLI_listbase.h"
#include "BLI_ghash.h"
@@ -68,6 +69,25 @@ static struct {
} g_version_data;
#endif
+#ifndef RNA_RUNTIME
+/**
+ * When set, report details about which defaults are used.
+ * Noisy but handy when investigating default extraction.
+ */
+static bool debugSRNA_defaults = false;
+
+static void print_defult_info(const PropertyDefRNA *dp)
+{
+ fprintf(stderr,
+ "dna_type=%s, dna_offset=%d, dna_struct=%s, dna_name=%s, id=%s\n",
+ dp->dnatype,
+ dp->dnaoffset,
+ dp->dnastructname,
+ dp->dnaname,
+ dp->prop->identifier);
+}
+#endif /* RNA_RUNTIME */
+
/* Duplicated code since we can't link in blenkernel or blenlib */
/* pedantic check for final '.', note '...' are allowed though. */
@@ -378,6 +398,8 @@ typedef struct DNAStructMember {
const char *name;
int arraylength;
int pointerlevel;
+ int offset;
+ int size;
} DNAStructMember;
static int rna_member_cmp(const char *name, const char *oname)
@@ -420,7 +442,8 @@ static int rna_member_cmp(const char *name, const char *oname)
static int rna_find_sdna_member(SDNA *sdna,
const char *structname,
const char *membername,
- DNAStructMember *smember)
+ DNAStructMember *smember,
+ int *offset)
{
const char *dnaname;
const short *sp;
@@ -432,7 +455,11 @@ static int rna_find_sdna_member(SDNA *sdna,
}
structnr = DNA_struct_find_nr_wrapper(sdna, structname);
+ smember->offset = -1;
if (structnr == -1) {
+ if (offset) {
+ *offset = -1;
+ }
return 0;
}
@@ -441,12 +468,15 @@ static int rna_find_sdna_member(SDNA *sdna,
sp += 2;
for (a = 0; a < totmember; a++, sp += 2) {
+ const int size = DNA_elem_size_nr(sdna, sp[0], sp[1]);
dnaname = sdna->alias.names[sp[1]];
cmp = rna_member_cmp(dnaname, membername);
if (cmp == 1) {
smember->type = sdna->alias.types[sp[0]];
smember->name = dnaname;
+ smember->offset = *offset;
+ smember->size = size;
if (strstr(membername, "[")) {
smember->arraylength = 0;
@@ -465,25 +495,36 @@ static int rna_find_sdna_member(SDNA *sdna,
else if (cmp == 2) {
smember->type = "";
smember->name = dnaname;
+ smember->offset = *offset;
+ smember->size = size;
smember->pointerlevel = 0;
smember->arraylength = 0;
membername = strstr(membername, ".") + strlen(".");
- rna_find_sdna_member(sdna, sdna->alias.types[sp[0]], membername, smember);
+ rna_find_sdna_member(sdna, sdna->alias.types[sp[0]], membername, smember, offset);
return 1;
}
else if (cmp == 3) {
smember->type = "";
smember->name = dnaname;
+ smember->offset = *offset;
+ smember->size = size;
smember->pointerlevel = 0;
smember->arraylength = 0;
+ if (offset) {
+ *offset = -1;
+ }
membername = strstr(membername, "->") + strlen("->");
- rna_find_sdna_member(sdna, sdna->alias.types[sp[0]], membername, smember);
+ rna_find_sdna_member(sdna, sdna->alias.types[sp[0]], membername, smember, offset);
return 1;
}
+
+ if (offset && *offset != -1) {
+ *offset += size;
+ }
}
return 0;
@@ -1647,6 +1688,11 @@ void RNA_def_property_ui_range(
DefRNA.error = 1;
}
+ if (step == 0) {
+ CLOG_ERROR(&LOG, "\"%s.%s\", step is zero.", srna->identifier, prop->identifier);
+ DefRNA.error = 1;
+ }
+
if (precision < -1 || precision > UI_PRECISION_FLOAT_MAX) {
CLOG_ERROR(&LOG, "\"%s.%s\", precision outside range.", srna->identifier, prop->identifier);
DefRNA.error = 1;
@@ -1835,6 +1881,12 @@ void RNA_def_property_boolean_default(PropertyRNA *prop, bool value)
case PROP_BOOLEAN: {
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
BLI_assert(ELEM(value, false, true));
+#ifndef RNA_RUNTIME
+ /* Default may be set from items. */
+ if (bprop->defaultvalue) {
+ CLOG_ERROR(&LOG, "\"%s.%s\", set from DNA.", srna->identifier, prop->identifier);
+ }
+#endif
bprop->defaultvalue = value;
break;
}
@@ -1869,6 +1921,11 @@ void RNA_def_property_int_default(PropertyRNA *prop, int value)
switch (prop->type) {
case PROP_INT: {
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
+#ifndef RNA_RUNTIME
+ if (iprop->defaultvalue != 0) {
+ CLOG_ERROR(&LOG, "\"%s.%s\", set from DNA.", srna->identifier, prop->identifier);
+ }
+#endif
iprop->defaultvalue = value;
break;
}
@@ -1886,6 +1943,11 @@ void RNA_def_property_int_array_default(PropertyRNA *prop, const int *array)
switch (prop->type) {
case PROP_INT: {
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
+#ifndef RNA_RUNTIME
+ if (iprop->defaultarray != NULL) {
+ CLOG_ERROR(&LOG, "\"%s.%s\", set from DNA.", srna->identifier, prop->identifier);
+ }
+#endif
iprop->defaultarray = array;
break;
}
@@ -1903,6 +1965,11 @@ void RNA_def_property_float_default(PropertyRNA *prop, float value)
switch (prop->type) {
case PROP_FLOAT: {
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
+#ifndef RNA_RUNTIME
+ if (fprop->defaultvalue != 0) {
+ CLOG_ERROR(&LOG, "\"%s.%s\", set from DNA.", srna->identifier, prop->identifier);
+ }
+#endif
fprop->defaultvalue = value;
break;
}
@@ -1920,6 +1987,11 @@ void RNA_def_property_float_array_default(PropertyRNA *prop, const float *array)
switch (prop->type) {
case PROP_FLOAT: {
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
+#ifndef RNA_RUNTIME
+ if (fprop->defaultarray != NULL) {
+ CLOG_ERROR(&LOG, "\"%s.%s\", set from DNA.", srna->identifier, prop->identifier);
+ }
+#endif
fprop->defaultarray = array; /* WARNING, this array must not come from the stack and lost */
break;
}
@@ -1956,7 +2028,11 @@ void RNA_def_property_string_default(PropertyRNA *prop, const char *value)
// BLI_assert(0);
break;
}
-
+#ifndef RNA_RUNTIME
+ if (sprop->defaultvalue != NULL && sprop->defaultvalue[0]) {
+ CLOG_ERROR(&LOG, "\"%s.%s\", set from DNA.", srna->identifier, prop->identifier);
+ }
+#endif
sprop->defaultvalue = value;
break;
}
@@ -2047,7 +2123,8 @@ static PropertyDefRNA *rna_def_property_sdna(PropertyRNA *prop,
propname = prop->identifier;
}
- if (!rna_find_sdna_member(DefRNA.sdna, structname, propname, &smember)) {
+ int dnaoffset = 0;
+ if (!rna_find_sdna_member(DefRNA.sdna, structname, propname, &smember, &dnaoffset)) {
if (DefRNA.silent) {
return NULL;
}
@@ -2061,6 +2138,7 @@ static PropertyDefRNA *rna_def_property_sdna(PropertyRNA *prop,
if (prop->type == PROP_POINTER) {
dp->dnapointerlevel = 1;
}
+ dp->dnaoffset = smember.offset;
return dp;
}
else {
@@ -2091,6 +2169,8 @@ static PropertyDefRNA *rna_def_property_sdna(PropertyRNA *prop,
dp->dnatype = smember.type;
dp->dnaarraylength = smember.arraylength;
dp->dnapointerlevel = smember.pointerlevel;
+ dp->dnaoffset = smember.offset;
+ dp->dnasize = smember.size;
return dp;
}
@@ -2101,6 +2181,7 @@ void RNA_def_property_boolean_sdna(PropertyRNA *prop,
int bit)
{
PropertyDefRNA *dp;
+ BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
@@ -2131,6 +2212,57 @@ void RNA_def_property_boolean_sdna(PropertyRNA *prop,
}
dp->booleanbit = bit;
+
+#ifndef RNA_RUNTIME
+ /* Set the default if possible. */
+ if (dp->dnaoffset != -1) {
+ int SDNAnr = DNA_struct_find_nr_wrapper(DefRNA.sdna, dp->dnastructname);
+ if (SDNAnr != -1) {
+ const void *default_data = DNA_default_table[SDNAnr];
+ if (default_data) {
+ default_data = POINTER_OFFSET(default_data, dp->dnaoffset);
+ bool has_default = true;
+ if (prop->totarraylength > 0) {
+ has_default = false;
+ if (debugSRNA_defaults) {
+ fprintf(stderr, "%s default: unsupported boolean array default\n", __func__);
+ }
+ }
+ else {
+ if (STREQ(dp->dnatype, "char")) {
+ bprop->defaultvalue = *(const char *)default_data & bit;
+ }
+ else if (STREQ(dp->dnatype, "short")) {
+ bprop->defaultvalue = *(const short *)default_data & bit;
+ }
+ else if (STREQ(dp->dnatype, "int")) {
+ bprop->defaultvalue = *(const int *)default_data & bit;
+ }
+ else {
+ has_default = false;
+ if (debugSRNA_defaults) {
+ fprintf(
+ stderr, "%s default: unsupported boolean type (%s)\n", __func__, dp->dnatype);
+ }
+ }
+
+ if (has_default) {
+ if (dp->booleannegative) {
+ bprop->defaultvalue = !bprop->defaultvalue;
+ }
+
+ if (debugSRNA_defaults) {
+ fprintf(stderr, "value=%d, ", bprop->defaultvalue);
+ print_defult_info(dp);
+ }
+ }
+ }
+ }
+ }
+ }
+#else
+ UNUSED_VARS(bprop);
+#endif
}
}
@@ -2204,6 +2336,96 @@ void RNA_def_property_int_sdna(PropertyRNA *prop, const char *structname, const
prop->subtype == PROP_FACTOR) {
iprop->hardmin = iprop->softmin = 0;
}
+
+#ifndef RNA_RUNTIME
+ /* Set the default if possible. */
+ if (dp->dnaoffset != -1) {
+ int SDNAnr = DNA_struct_find_nr_wrapper(DefRNA.sdna, dp->dnastructname);
+ if (SDNAnr != -1) {
+ const void *default_data = DNA_default_table[SDNAnr];
+ if (default_data) {
+ default_data = POINTER_OFFSET(default_data, dp->dnaoffset);
+ /* NOTE: Currently doesn't store sign, assume chars are unsigned because
+ * we build with this enabled, otherwise check 'PROP_UNSIGNED'. */
+ bool has_default = true;
+ if (prop->totarraylength > 0) {
+ const void *default_data_end = POINTER_OFFSET(default_data, dp->dnasize);
+ const int size_final = sizeof(int) * prop->totarraylength;
+ if (STREQ(dp->dnatype, "char")) {
+ int *defaultarray = rna_calloc(size_final);
+ for (int i = 0; i < prop->totarraylength && default_data < default_data_end; i++) {
+ defaultarray[i] = *(const char *)default_data;
+ default_data = POINTER_OFFSET(default_data, sizeof(char));
+ }
+ iprop->defaultarray = defaultarray;
+ }
+ else if (STREQ(dp->dnatype, "short")) {
+
+ int *defaultarray = rna_calloc(size_final);
+ for (int i = 0; i < prop->totarraylength && default_data < default_data_end; i++) {
+ defaultarray[i] = (prop->subtype != PROP_UNSIGNED) ? *(const short *)default_data :
+ *(const ushort *)default_data;
+ default_data = POINTER_OFFSET(default_data, sizeof(short));
+ }
+ iprop->defaultarray = defaultarray;
+ }
+ else if (STREQ(dp->dnatype, "int")) {
+ int *defaultarray = rna_calloc(size_final);
+ memcpy(defaultarray, default_data, MIN2(size_final, dp->dnasize));
+ iprop->defaultarray = defaultarray;
+ }
+ else {
+ has_default = false;
+ if (debugSRNA_defaults) {
+ fprintf(stderr,
+ "%s default: unsupported int array type (%s)\n",
+ __func__,
+ dp->dnatype);
+ }
+ }
+
+ if (has_default) {
+ if (debugSRNA_defaults) {
+ fprintf(stderr, "value=(");
+ for (int i = 0; i < prop->totarraylength; i++) {
+ fprintf(stderr, "%d, ", iprop->defaultarray[i]);
+ }
+ fprintf(stderr, "), ");
+ print_defult_info(dp);
+ }
+ }
+ }
+ else {
+ if (STREQ(dp->dnatype, "char")) {
+ iprop->defaultvalue = *(const char *)default_data;
+ }
+ else if (STREQ(dp->dnatype, "short")) {
+ iprop->defaultvalue = (prop->subtype != PROP_UNSIGNED) ?
+ *(const short *)default_data :
+ *(const ushort *)default_data;
+ }
+ else if (STREQ(dp->dnatype, "int")) {
+ iprop->defaultvalue = (prop->subtype != PROP_UNSIGNED) ? *(const int *)default_data :
+ *(const uint *)default_data;
+ }
+ else {
+ has_default = false;
+ if (debugSRNA_defaults) {
+ fprintf(stderr, "%s default: unsupported int type (%s)\n", __func__, dp->dnatype);
+ }
+ }
+
+ if (has_default) {
+ if (debugSRNA_defaults) {
+ fprintf(stderr, "value=%d, ", iprop->defaultvalue);
+ print_defult_info(dp);
+ }
+ }
+ }
+ }
+ }
+ }
+#endif
}
}
@@ -2228,8 +2450,8 @@ void RNA_def_property_float_sdna(PropertyRNA *prop, const char *structname, cons
/* silent is for internal use */
if (DefRNA.silent == 0) {
if (dp->dnatype && *dp->dnatype && IS_DNATYPE_FLOAT_COMPAT(dp->dnatype) == 0) {
- if (prop->subtype !=
- PROP_COLOR_GAMMA) { /* colors are an exception. these get translated */
+ /* Colors are an exception. these get translated. */
+ if (prop->subtype != PROP_COLOR_GAMMA) {
CLOG_ERROR(&LOG,
"%s.%s is a '%s' but wrapped as type '%s'.",
srna->identifier,
@@ -2246,6 +2468,70 @@ void RNA_def_property_float_sdna(PropertyRNA *prop, const char *structname, cons
fprop->hardmin = fprop->softmin = 0.0f;
fprop->hardmax = fprop->softmax = 1.0f;
}
+
+#ifndef RNA_RUNTIME
+ /* Set the default if possible. */
+ if (dp->dnaoffset != -1) {
+ int SDNAnr = DNA_struct_find_nr_wrapper(DefRNA.sdna, dp->dnastructname);
+ if (SDNAnr != -1) {
+ const void *default_data = DNA_default_table[SDNAnr];
+ if (default_data) {
+ default_data = POINTER_OFFSET(default_data, dp->dnaoffset);
+ bool has_default = true;
+ if (prop->totarraylength > 0) {
+ if (STREQ(dp->dnatype, "float")) {
+ const int size_final = sizeof(float) * prop->totarraylength;
+ float *defaultarray = rna_calloc(size_final);
+ memcpy(defaultarray, default_data, MIN2(size_final, dp->dnasize));
+ fprop->defaultarray = defaultarray;
+ }
+ else {
+ has_default = false;
+ if (debugSRNA_defaults) {
+ fprintf(stderr,
+ "%s default: unsupported float array type (%s)\n",
+ __func__,
+ dp->dnatype);
+ }
+ }
+
+ if (has_default) {
+ if (debugSRNA_defaults) {
+ fprintf(stderr, "value=(");
+ for (int i = 0; i < prop->totarraylength; i++) {
+ fprintf(stderr, "%g, ", fprop->defaultarray[i]);
+ }
+ fprintf(stderr, "), ");
+ print_defult_info(dp);
+ }
+ }
+ }
+ else {
+ if (STREQ(dp->dnatype, "float")) {
+ fprop->defaultvalue = *(const float *)default_data;
+ }
+ else if (STREQ(dp->dnatype, "char")) {
+ fprop->defaultvalue = (float)*(const char *)default_data * (1.0f / 255.0f);
+ }
+ else {
+ has_default = false;
+ if (debugSRNA_defaults) {
+ fprintf(
+ stderr, "%s default: unsupported float type (%s)\n", __func__, dp->dnatype);
+ }
+ }
+
+ if (has_default) {
+ if (debugSRNA_defaults) {
+ fprintf(stderr, "value=%g, ", fprop->defaultvalue);
+ print_defult_info(dp);
+ }
+ }
+ }
+ }
+ }
+ }
+#endif
}
rna_def_property_sdna(prop, structname, propname);
@@ -2253,7 +2539,8 @@ void RNA_def_property_float_sdna(PropertyRNA *prop, const char *structname, cons
void RNA_def_property_enum_sdna(PropertyRNA *prop, const char *structname, const char *propname)
{
- /* PropertyDefRNA *dp; */
+ PropertyDefRNA *dp;
+ EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
@@ -2267,7 +2554,7 @@ void RNA_def_property_enum_sdna(PropertyRNA *prop, const char *structname, const
return;
}
- if ((/* dp= */ rna_def_property_sdna(prop, structname, propname))) {
+ if ((dp = rna_def_property_sdna(prop, structname, propname))) {
if (prop->arraydimension) {
prop->arraydimension = 0;
prop->totarraylength = 0;
@@ -2277,6 +2564,44 @@ void RNA_def_property_enum_sdna(PropertyRNA *prop, const char *structname, const
DefRNA.error = 1;
}
}
+
+#ifndef RNA_RUNTIME
+ /* Set the default if possible. */
+ if (dp->dnaoffset != -1) {
+ int SDNAnr = DNA_struct_find_nr_wrapper(DefRNA.sdna, dp->dnastructname);
+ if (SDNAnr != -1) {
+ const void *default_data = DNA_default_table[SDNAnr];
+ if (default_data) {
+ default_data = POINTER_OFFSET(default_data, dp->dnaoffset);
+ bool has_default = true;
+ if (STREQ(dp->dnatype, "char")) {
+ eprop->defaultvalue = *(const char *)default_data;
+ }
+ else if (STREQ(dp->dnatype, "short")) {
+ eprop->defaultvalue = *(const short *)default_data;
+ }
+ else if (STREQ(dp->dnatype, "int")) {
+ eprop->defaultvalue = *(const int *)default_data;
+ }
+ else {
+ has_default = false;
+ if (debugSRNA_defaults) {
+ fprintf(stderr, "%s default: unsupported enum type (%s)\n", __func__, dp->dnatype);
+ }
+ }
+
+ if (has_default) {
+ if (debugSRNA_defaults) {
+ fprintf(stderr, "value=%d, ", eprop->defaultvalue);
+ print_defult_info(dp);
+ }
+ }
+ }
+ }
+ }
+#else
+ UNUSED_VARS(eprop);
+#endif
}
}
@@ -2292,12 +2617,23 @@ void RNA_def_property_enum_bitflag_sdna(PropertyRNA *prop,
if (dp) {
dp->enumbitflags = 1;
+
+#ifndef RNA_RUNTIME
+ int defaultvalue_mask = 0;
+ EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
+ for (int i = 0; i < eprop->totitem; i++) {
+ if (eprop->item[i].identifier[0]) {
+ defaultvalue_mask |= eprop->defaultvalue & eprop->item[i].value;
+ }
+ }
+ eprop->defaultvalue = defaultvalue_mask;
+#endif
}
}
void RNA_def_property_string_sdna(PropertyRNA *prop, const char *structname, const char *propname)
{
- /* PropertyDefRNA *dp; */
+ PropertyDefRNA *dp;
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
StructRNA *srna = DefRNA.laststruct;
@@ -2312,12 +2648,31 @@ void RNA_def_property_string_sdna(PropertyRNA *prop, const char *structname, con
return;
}
- if ((/* dp= */ rna_def_property_sdna(prop, structname, propname))) {
+ if ((dp = rna_def_property_sdna(prop, structname, propname))) {
if (prop->arraydimension) {
sprop->maxlength = prop->totarraylength;
prop->arraydimension = 0;
prop->totarraylength = 0;
}
+
+#ifndef RNA_RUNTIME
+ /* Set the default if possible. */
+ if ((dp->dnaoffset != -1) && (dp->dnapointerlevel != 0)) {
+ int SDNAnr = DNA_struct_find_nr_wrapper(DefRNA.sdna, dp->dnastructname);
+ if (SDNAnr != -1) {
+ const void *default_data = DNA_default_table[SDNAnr];
+ if (default_data) {
+ default_data = POINTER_OFFSET(default_data, dp->dnaoffset);
+ sprop->defaultvalue = default_data;
+
+ if (debugSRNA_defaults) {
+ fprintf(stderr, "value=\"%s\", ", sprop->defaultvalue);
+ print_defult_info(dp);
+ }
+ }
+ }
+ }
+#endif
}
}
@@ -2396,8 +2751,9 @@ void RNA_def_property_collection_sdna(PropertyRNA *prop,
structname = ds->dnaname;
}
+ int dnaoffset = 0;
if (lengthpropname[0] == 0 ||
- rna_find_sdna_member(DefRNA.sdna, structname, lengthpropname, &smember)) {
+ rna_find_sdna_member(DefRNA.sdna, structname, lengthpropname, &smember, &dnaoffset)) {
if (lengthpropname[0] == 0) {
dp->dnalengthfixed = prop->totarraylength;
prop->arraydimension = 0;
diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c
index 30a68a4919e..d7e34ff139c 100644
--- a/source/blender/makesrna/intern/rna_dynamicpaint.c
+++ b/source/blender/makesrna/intern/rna_dynamicpaint.c
@@ -472,7 +472,7 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_antialiasing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DPAINT_ANTIALIAS);
- RNA_def_property_ui_text(prop, "Anti-aliasing", "Use 5x multisampling to smooth paint edges");
+ RNA_def_property_ui_text(prop, "Anti-Aliasing", "Use 5x multisampling to smooth paint edges");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_DynamicPaintSurface_reset");
prop = RNA_def_property(srna, "brush_influence_scale", PROP_FLOAT, PROP_FACTOR);
@@ -610,7 +610,7 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DPAINT_MULALPHA);
RNA_def_property_ui_text(
- prop, "Premultiply alpha", "Multiply color by alpha (recommended for Blender input)");
+ prop, "Premultiply Alpha", "Multiply color by alpha (recommended for Blender input)");
prop = RNA_def_property(srna, "image_output_path", PROP_STRING, PROP_DIRPATH);
RNA_def_property_string_sdna(prop, NULL, "image_output_path");
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 6c546940e6d..254f3bc3710 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -132,6 +132,33 @@ const EnumPropertyItem rna_enum_beztriple_interpolation_easing_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_driver_target_rotation_mode_items[] = {
+ {DTAR_ROTMODE_AUTO, "AUTO", 0, "Auto Euler", "Euler using the rotation order of the target"},
+ {DTAR_ROTMODE_EULER_XYZ, "XYZ", 0, "XYZ Euler", "Euler using the XYZ rotation order"},
+ {DTAR_ROTMODE_EULER_XZY, "XZY", 0, "XZY Euler", "Euler using the XZY rotation order"},
+ {DTAR_ROTMODE_EULER_YXZ, "YXZ", 0, "YXZ Euler", "Euler using the YXZ rotation order"},
+ {DTAR_ROTMODE_EULER_YZX, "YZX", 0, "YZX Euler", "Euler using the YZX rotation order"},
+ {DTAR_ROTMODE_EULER_ZXY, "ZXY", 0, "ZXY Euler", "Euler using the ZXY rotation order"},
+ {DTAR_ROTMODE_EULER_ZYX, "ZYX", 0, "ZYX Euler", "Euler using the ZYX rotation order"},
+ {DTAR_ROTMODE_QUATERNION, "QUATERNION", 0, "Quaternion", "Quaternion rotation"},
+ {DTAR_ROTMODE_SWING_TWIST_X,
+ "SWING_TWIST_X",
+ 0,
+ "Swing and X Twist",
+ "Decompose into a swing rotation to aim the X axis, followed by twist around it"},
+ {DTAR_ROTMODE_SWING_TWIST_Y,
+ "SWING_TWIST_Y",
+ 0,
+ "Swing and Y Twist",
+ "Decompose into a swing rotation to aim the Y axis, followed by twist around it"},
+ {DTAR_ROTMODE_SWING_TWIST_Z,
+ "SWING_TWIST_Z",
+ 0,
+ "Swing and Z Twist",
+ "Decompose into a swing rotation to aim the Z axis, followed by twist around it"},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifdef RNA_RUNTIME
# include "WM_api.h"
@@ -1671,9 +1698,12 @@ static void rna_def_drivertarget(BlenderRNA *brna)
{DTAR_TRANSCHAN_LOCX, "LOC_X", 0, "X Location", ""},
{DTAR_TRANSCHAN_LOCY, "LOC_Y", 0, "Y Location", ""},
{DTAR_TRANSCHAN_LOCZ, "LOC_Z", 0, "Z Location", ""},
+ {0, "", 0, NULL, NULL},
{DTAR_TRANSCHAN_ROTX, "ROT_X", 0, "X Rotation", ""},
{DTAR_TRANSCHAN_ROTY, "ROT_Y", 0, "Y Rotation", ""},
{DTAR_TRANSCHAN_ROTZ, "ROT_Z", 0, "Z Rotation", ""},
+ {DTAR_TRANSCHAN_ROTW, "ROT_W", 0, "W Rotation", ""},
+ {0, "", 0, NULL, NULL},
{DTAR_TRANSCHAN_SCALEX, "SCALE_X", 0, "X Scale", ""},
{DTAR_TRANSCHAN_SCALEY, "SCALE_Y", 0, "Y Scale", ""},
{DTAR_TRANSCHAN_SCALEZ, "SCALE_Z", 0, "Z Scale", ""},
@@ -1749,6 +1779,12 @@ static void rna_def_drivertarget(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Type", "Driver variable type");
RNA_def_property_update(prop, 0, "rna_DriverTarget_update_data");
+ prop = RNA_def_property(srna, "rotation_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "rotation_mode");
+ RNA_def_property_enum_items(prop, rna_enum_driver_target_rotation_mode_items);
+ RNA_def_property_ui_text(prop, "Rotation Mode", "Mode for calculating rotation channel values");
+ RNA_def_property_update(prop, 0, "rna_DriverTarget_update_data");
+
prop = RNA_def_property(srna, "transform_space", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, prop_local_space_items);
diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c
index 5d21e718934..2f09b90a81e 100644
--- a/source/blender/makesrna/intern/rna_fluidsim.c
+++ b/source/blender/makesrna/intern/rna_fluidsim.c
@@ -447,7 +447,7 @@ static void rna_def_fluidsim_domain(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(
prop,
- "Remove air bubbles",
+ "Remove Air Bubbles",
"Removes the air gap between fluid surface and obstacles - WARNING: Can result "
"in a dissolving surface in other areas");
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index bd3321377d3..3ad18fcc7a3 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -151,30 +151,7 @@ static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Pointe
static void rna_GPencil_autolock(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bGPdata *gpd = (bGPdata *)ptr->owner_id;
- bGPDlayer *gpl = NULL;
-
- if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) {
- bGPDlayer *layer = BKE_gpencil_layer_getactive(gpd);
-
- /* Lock all other layers */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* unlock active layer */
- if (gpl == layer) {
- gpl->flag &= ~GP_LAYER_LOCKED;
- }
- else {
- gpl->flag |= GP_LAYER_LOCKED;
- }
- }
- }
- else {
- /* If disable is better unlock all layers by default or it looks there is
- * a problem in the UI because the user expects all layers will be unlocked
- */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- gpl->flag &= ~GP_LAYER_LOCKED;
- }
- }
+ BKE_gpencil_layer_autolock_set(gpd, true);
/* standard update */
rna_GPencil_update(bmain, scene, ptr);
@@ -1884,7 +1861,7 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "onion_keytype");
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_enum_items(prop, rna_enum_onion_keyframe_type_items);
- RNA_def_property_ui_text(prop, "Filter By Type", "Type of keyframe (for filtering)");
+ RNA_def_property_ui_text(prop, "Filter by Type", "Type of keyframe (for filtering)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "use_onion_fade", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 0b40cc9f7f9..d3094eca9fd 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -133,6 +133,16 @@ static const EnumPropertyItem modifier_modify_color_items[] = {
{0, NULL, 0, NULL, NULL},
};
+static const EnumPropertyItem modifier_opacity_mode_items[] = {
+ {GP_OPACITY_MODE_MATERIAL,
+ "MATERIAL",
+ 0,
+ "Material",
+ "Modify opacity using alpha channel of material"},
+ {GP_OPACITY_MODE_STRENGTH, "STRENGTH", 0, "Strength", "Modify opacity using point strength"},
+ {0, NULL, 0, NULL, NULL},
+};
+
static const EnumPropertyItem modifier_gphook_falloff_items[] = {
{eGPHook_Falloff_None, "NONE", 0, "No Falloff", ""},
{eGPHook_Falloff_Curve, "CURVE", 0, "Curve", ""},
@@ -1164,6 +1174,11 @@ static void rna_def_modifier_gpencilopacity(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Mode", "Set what colors of the stroke are affected");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "opacity_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, modifier_opacity_mode_items);
+ RNA_def_property_ui_text(prop, "Opacity Mode", "Set what mode used to define opacity");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "layername");
RNA_def_property_ui_text(prop, "Layer", "Layer name");
@@ -1358,7 +1373,7 @@ static void rna_def_modifier_gpencilinstance(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_KEEP_ONTOP);
RNA_def_property_ui_text(
prop,
- "Keep On Top",
+ "Keep on Top",
"Keep the original stroke in front of new instances (only affect by layer)");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
}
@@ -1734,7 +1749,7 @@ static void rna_def_modifier_gpencilhook(BlenderRNA *brna)
prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_HOOK_INVERT_VGROUP);
- RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_ui_text(prop, "Inverse Vertex Group", "Inverse filter");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
@@ -1770,7 +1785,7 @@ static void rna_def_modifier_gpencilhook(BlenderRNA *brna)
prop = RNA_def_property(srna, "falloff_curve", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "curfalloff");
- RNA_def_property_ui_text(prop, "Falloff Curve", "Custom Light Falloff Curve");
+ RNA_def_property_ui_text(prop, "Falloff Curve", "Custom light falloff curve");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "center", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 26f25e4988d..04a59a48b63 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -74,6 +74,11 @@ typedef struct PropertyDefRNA {
const char *dnatype;
int dnaarraylength;
int dnapointerlevel;
+ /**
+ * Offset in bytes within `dnastructname`.
+ * -1 when unusable (follows pointer for e.g.). */
+ int dnaoffset;
+ int dnasize;
/* for finding length of array collections */
const char *dnalengthstructname;
@@ -223,7 +228,7 @@ bool rna_AnimaData_override_apply(struct Main *bmain,
void rna_def_animviz_common(struct StructRNA *srna);
void rna_def_motionpath_common(struct StructRNA *srna);
-void rna_def_bone_curved_common(struct StructRNA *srna, bool is_posebone);
+void rna_def_bone_curved_common(struct StructRNA *srna, bool is_posebone, bool is_editbone);
void rna_def_texmat_common(struct StructRNA *srna, const char *texspace_editable);
void rna_def_mtex_common(struct BlenderRNA *brna,
@@ -543,6 +548,11 @@ PointerRNA rna_array_lookup_int(
/* Duplicated code since we can't link in blenlib */
+#ifndef RNA_RUNTIME
+void *rna_alloc_from_buffer(const char *buffer, int buffer_len);
+void *rna_calloc(int buffer_len);
+#endif
+
void rna_addtail(struct ListBase *listbase, void *vlink);
void rna_freelinkN(struct ListBase *listbase, void *vlink);
void rna_freelistN(struct ListBase *listbase);
diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c
index 1ad006cbc37..bab7375f01b 100644
--- a/source/blender/makesrna/intern/rna_layer.c
+++ b/source/blender/makesrna/intern/rna_layer.c
@@ -120,6 +120,26 @@ static IDProperty *rna_ViewLayer_idprops(PointerRNA *ptr, bool create)
return view_layer->id_properties;
}
+static bool rna_LayerCollection_visible_get(LayerCollection *layer_collection, bContext *C)
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ const bool runtime_visible = (layer_collection->runtime_flag & LAYER_COLLECTION_VISIBLE) != 0;
+
+ if (v3d == NULL) {
+ return runtime_visible;
+ }
+
+ if ((v3d->flag & V3D_LOCAL_COLLECTIONS) == 0) {
+ return runtime_visible;
+ }
+
+ if (v3d->local_collections_uuid & layer_collection->local_collections_bits) {
+ return true;
+ }
+
+ return false;
+}
+
static void rna_ViewLayer_update_render_passes(ID *id)
{
Scene *scene = (Scene *)id;
@@ -156,7 +176,10 @@ static PointerRNA rna_ViewLayer_depsgraph_get(PointerRNA *ptr)
if (GS(id->name) == ID_SCE) {
Scene *scene = (Scene *)id;
ViewLayer *view_layer = (ViewLayer *)ptr->data;
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false);
+ // NOTE: We don't allocate new depsgraph here, so the bmain is ignored. So it's easier to pass
+ // NULL.
+ // Still weak though.
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(NULL, scene, view_layer, false);
return rna_pointer_inherit_refine(ptr, &RNA_Depsgraph, depsgraph);
}
return PointerRNA_NULL;
@@ -177,7 +200,7 @@ static void rna_ViewLayer_update_tagged(ID *id_ptr, ViewLayer *view_layer, Main
# endif
Scene *scene = (Scene *)id_ptr;
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
/* NOTE: This is similar to CTX_data_depsgraph_pointer(). Ideally such access would be
* de-duplicated across all possible cases, but for now this is safest and easiest way to go.
*
@@ -383,6 +406,13 @@ static void rna_def_layer_collection(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Hide in Viewport", "Temporarily hide in viewport");
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollection_update");
+ func = RNA_def_function(srna, "visible_get", "rna_LayerCollection_visible_get");
+ RNA_def_function_ui_description(func,
+ "Whether this collection is visible, take into account the "
+ "collection parent and the viewport");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_return(func, RNA_def_boolean(func, "result", 0, "", ""));
+
/* Run-time flags. */
prop = RNA_def_property(srna, "is_visible", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "runtime_flag", LAYER_COLLECTION_VISIBLE);
diff --git a/source/blender/makesrna/intern/rna_light.c b/source/blender/makesrna/intern/rna_light.c
index 8640c35f1b8..ecee413a8e0 100644
--- a/source/blender/makesrna/intern/rna_light.c
+++ b/source/blender/makesrna/intern/rna_light.c
@@ -150,7 +150,6 @@ static void rna_def_light(BlenderRNA *brna)
prop = RNA_def_property(srna, "specular_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "spec_fac");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_range(prop, 0.0f, 9999.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01, 2);
RNA_def_property_ui_text(prop, "Specular Factor", "Specular reflection multiplier");
@@ -165,7 +164,6 @@ static void rna_def_light(BlenderRNA *brna)
prop = RNA_def_property(srna, "cutoff_distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "att_dist");
- RNA_def_property_float_default(prop, 40.0f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.01f, 100.0f, 1.0, 2);
RNA_def_property_ui_text(
@@ -196,7 +194,6 @@ static void rna_def_light_energy(StructRNA *srna, bool distant)
/* Distant light strength has no unit defined, it's proportional to
* Watt/m^2 and is not sensitive to scene unit scale. */
prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_default(prop, 10.0f);
RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
RNA_def_property_ui_text(prop, "Strength", "Amount of light emitted");
RNA_def_property_update(prop, 0, "rna_Light_draw_update");
@@ -205,7 +202,6 @@ static void rna_def_light_energy(StructRNA *srna, bool distant)
/* Lights with a location have power in Watt, which is sensitive to
* scene unit scale. */
prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_POWER);
- RNA_def_property_float_default(prop, 10.0f);
RNA_def_property_ui_range(prop, 0.0f, 1000000.0f, 10, 5);
RNA_def_property_ui_text(prop, "Power", "Amount of light emitted");
RNA_def_property_update(prop, 0, "rna_Light_draw_update");
@@ -289,7 +285,6 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
prop = RNA_def_property(srna, "shadow_buffer_clip_start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "clipsta");
- RNA_def_property_float_default(prop, 0.05f);
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_ui_text(prop,
@@ -297,46 +292,13 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
"Shadow map clip start, below which objects will not generate shadows");
RNA_def_property_update(prop, 0, "rna_Light_draw_update");
- prop = RNA_def_property(srna, "shadow_buffer_clip_end", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_sdna(prop, NULL, "clipend");
- RNA_def_property_float_default(prop, 40.0f);
- RNA_def_property_range(prop, 1e-6f, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
- RNA_def_property_ui_text(prop,
- "Shadow Buffer Clip End",
- "Shadow map clip end, beyond which objects will not generate shadows");
- RNA_def_property_update(prop, 0, "rna_Light_draw_update");
-
prop = RNA_def_property(srna, "shadow_buffer_bias", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bias");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_range(prop, 0.001f, 9999.0f);
RNA_def_property_ui_range(prop, 0.001f, 5.0f, 1.0, 3);
RNA_def_property_ui_text(prop, "Shadow Buffer Bias", "Bias for reducing self shadowing");
RNA_def_property_update(prop, 0, "rna_Light_update");
- prop = RNA_def_property(srna, "shadow_buffer_bleed_bias", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "bleedbias");
- RNA_def_property_range(prop, 0.f, 1.f);
- RNA_def_property_ui_text(
- prop, "Shadow Buffer Bleed Bias", "Bias for reducing light-bleed on variance shadow maps");
- RNA_def_property_update(prop, 0, "rna_Light_update");
-
- prop = RNA_def_property(srna, "shadow_buffer_exp", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "bleedexp");
- RNA_def_property_float_default(prop, 2.5f);
- RNA_def_property_range(prop, 1.0f, 9999.0f);
- RNA_def_property_ui_text(
- prop, "Shadow Buffer Exponent", "Bias for reducing light-bleed on exponential shadow maps");
- RNA_def_property_update(prop, 0, "rna_Light_update");
-
- prop = RNA_def_property(srna, "shadow_buffer_soft", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "soft");
- RNA_def_property_float_default(prop, 3.0f);
- RNA_def_property_range(prop, 0.0f, 100.0f);
- RNA_def_property_ui_text(prop, "Shadow Buffer Soft", "Size of shadow buffer sampling area");
- RNA_def_property_update(prop, 0, "rna_Light_update");
-
prop = RNA_def_property(srna, "shadow_buffer_samples", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "samp");
RNA_def_property_range(prop, 1, 16);
@@ -351,7 +313,6 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
prop = RNA_def_property(srna, "shadow_soft_size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "area_size");
- RNA_def_property_float_default(prop, 0.25f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 100, 0.1, 3);
RNA_def_property_ui_text(
@@ -370,7 +331,6 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
prop = RNA_def_property(srna, "contact_shadow_distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "contact_dist");
- RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_range(prop, 0.0f, 9999.0f);
RNA_def_property_ui_text(prop,
"Contact Shadow Distance",
@@ -380,23 +340,13 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
prop = RNA_def_property(srna, "contact_shadow_bias", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "contact_bias");
- RNA_def_property_float_default(prop, 0.03f);
RNA_def_property_range(prop, 0.001f, 9999.0f);
RNA_def_property_ui_range(prop, 0.001f, 5.0f, 1.0, 3);
RNA_def_property_ui_text(prop, "Contact Shadow Bias", "Bias to avoid self shadowing");
RNA_def_property_update(prop, 0, "rna_Light_update");
- prop = RNA_def_property(srna, "contact_shadow_soft_size", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "contact_spread");
- RNA_def_property_float_default(prop, 0.2f);
- RNA_def_property_range(prop, 0.0f, 9999.0f);
- RNA_def_property_ui_text(
- prop, "Contact Shadow Soft", "Control how soft the contact shadows will be");
- RNA_def_property_update(prop, 0, "rna_Light_update");
-
prop = RNA_def_property(srna, "contact_shadow_thickness", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "contact_thickness");
- RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_range(prop, 0.0f, 9999.0f);
RNA_def_property_ui_range(prop, 0, 100, 0.1, 3);
RNA_def_property_ui_text(
@@ -406,7 +356,6 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
if (sun) {
prop = RNA_def_property(srna, "shadow_cascade_max_distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "cascade_max_dist");
- RNA_def_property_float_default(prop, 200.0f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_text(prop,
"Cascade Max Distance",
@@ -415,7 +364,6 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
prop = RNA_def_property(srna, "shadow_cascade_count", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "cascade_count");
- RNA_def_property_int_default(prop, 4);
RNA_def_property_range(prop, 1, 4);
RNA_def_property_ui_text(
prop, "Cascade Count", "Number of texture used by the cascaded shadow map");
@@ -423,7 +371,6 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
prop = RNA_def_property(srna, "shadow_cascade_exponent", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "cascade_exponent");
- RNA_def_property_float_default(prop, 0.8f);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop,
"Exponential Distribution",
@@ -432,7 +379,6 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
prop = RNA_def_property(srna, "shadow_cascade_fade", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "cascade_fade");
- RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(
prop, "Cascade Fade", "How smooth is the transition between each cascade");
@@ -484,7 +430,6 @@ static void rna_def_area_light(BlenderRNA *brna)
prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "area_size");
- RNA_def_property_float_default(prop, 0.25f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 100, 0.1, 3);
RNA_def_property_ui_text(
@@ -493,7 +438,6 @@ static void rna_def_area_light(BlenderRNA *brna)
prop = RNA_def_property(srna, "size_y", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "area_sizey");
- RNA_def_property_float_default(prop, 0.25f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 100, 0.1, 3);
RNA_def_property_ui_text(
@@ -524,14 +468,12 @@ static void rna_def_spot_light(BlenderRNA *brna)
prop = RNA_def_property(srna, "spot_blend", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "spotblend");
- RNA_def_property_float_default(prop, 0.15f);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Spot Blend", "The softness of the spotlight edge");
RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "spot_size", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "spotsize");
- RNA_def_property_float_default(prop, DEG2RADF(45.0f));
RNA_def_property_range(prop, DEG2RADF(1.0f), DEG2RADF(180.0f));
RNA_def_property_ui_text(prop, "Spot Size", "Angle of the spotlight beam");
RNA_def_property_update(prop, 0, "rna_Light_draw_update");
@@ -557,7 +499,6 @@ static void rna_def_sun_light(BlenderRNA *brna)
prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "sun_angle");
- RNA_def_property_float_default(prop, DEG2RADF(0.526f));
RNA_def_property_range(prop, DEG2RADF(0.0f), DEG2RADF(180.0f));
RNA_def_property_ui_text(prop, "Angle", "Angular diameter of the Sun as seen from the Earth");
RNA_def_property_update(prop, 0, "rna_Light_update");
diff --git a/source/blender/makesrna/intern/rna_lightprobe.c b/source/blender/makesrna/intern/rna_lightprobe.c
index 463cefdf3f0..d448bdd9401 100644
--- a/source/blender/makesrna/intern/rna_lightprobe.c
+++ b/source/blender/makesrna/intern/rna_lightprobe.c
@@ -86,7 +86,6 @@ static void rna_def_lightprobe(BlenderRNA *brna)
prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "clipsta");
- RNA_def_property_float_default(prop, 0.8f);
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_ui_text(
@@ -95,7 +94,6 @@ static void rna_def_lightprobe(BlenderRNA *brna)
prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "clipend");
- RNA_def_property_float_default(prop, 40.0f);
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_ui_text(
@@ -120,13 +118,11 @@ static void rna_def_lightprobe(BlenderRNA *brna)
prop = RNA_def_property(srna, "influence_distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "distinf");
- RNA_def_property_float_default(prop, 2.5f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_text(prop, "Influence Distance", "Influence distance of the probe");
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
prop = RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Falloff", "Control how fast the probe influence decreases");
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
@@ -149,7 +145,6 @@ static void rna_def_lightprobe(BlenderRNA *brna)
prop = RNA_def_property(srna, "parallax_distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "distpar");
- RNA_def_property_float_default(prop, 2.5f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_text(prop, "Parallax Radius", "Lowest corner of the parallax bounding box");
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
@@ -157,28 +152,24 @@ static void rna_def_lightprobe(BlenderRNA *brna)
/* irradiance grid */
prop = RNA_def_property(srna, "grid_resolution_x", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 1, 256);
- RNA_def_property_int_default(prop, 4);
RNA_def_property_ui_text(
prop, "Resolution X", "Number of sample along the x axis of the volume");
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
prop = RNA_def_property(srna, "grid_resolution_y", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 1, 256);
- RNA_def_property_int_default(prop, 4);
RNA_def_property_ui_text(
prop, "Resolution Y", "Number of sample along the y axis of the volume");
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
prop = RNA_def_property(srna, "grid_resolution_z", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 1, 256);
- RNA_def_property_int_default(prop, 4);
RNA_def_property_ui_text(
prop, "Resolution Z", "Number of sample along the z axis of the volume");
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
prop = RNA_def_property(srna, "visibility_buffer_bias", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "vis_bias");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_range(prop, 0.001f, 9999.0f);
RNA_def_property_ui_range(prop, 0.001f, 5.0f, 1.0, 3);
RNA_def_property_ui_text(prop, "Visibility Bias", "Bias for reducing self shadowing");
@@ -186,7 +177,6 @@ static void rna_def_lightprobe(BlenderRNA *brna)
prop = RNA_def_property(srna, "visibility_bleed_bias", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "vis_bleedbias");
- RNA_def_property_float_default(prop, 0.0f);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(
prop, "Visibility Bleed Bias", "Bias for reducing light-bleed on variance shadow maps");
@@ -194,14 +184,12 @@ static void rna_def_lightprobe(BlenderRNA *brna)
prop = RNA_def_property(srna, "visibility_blur", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "vis_blur");
- RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Visibility Blur", "Filter size of the visibility blur");
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
prop = RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "intensity");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0f, 3.0f, 1.0, 3);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c
index f6cfc33c82e..f5730885193 100644
--- a/source/blender/makesrna/intern/rna_linestyle.c
+++ b/source/blender/makesrna/intern/rna_linestyle.c
@@ -2179,7 +2179,7 @@ static void rna_def_linestyle(BlenderRNA *brna)
prop = RNA_def_property(srna, "texture_spacing", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "texstep");
RNA_def_property_range(prop, 0.01f, 100.0f);
- RNA_def_property_ui_text(prop, "Texture spacing", "Spacing for textures along stroke length");
+ RNA_def_property_ui_text(prop, "Texture Spacing", "Spacing for textures along stroke length");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
/* anim */
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index 8f627ce36ef..9da17c5f0b1 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -370,7 +370,6 @@ static void rna_def_material_display(StructRNA *srna)
prop = RNA_def_property(srna, "roughness", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "roughness");
- RNA_def_property_float_default(prop, 0.25f);
RNA_def_property_range(prop, 0, 1);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Roughness", "Roughness of the material");
@@ -378,7 +377,6 @@ static void rna_def_material_display(StructRNA *srna)
prop = RNA_def_property(srna, "specular_intensity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "spec");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0, 1);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Specular", "How intense (bright) the specular reflection is");
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 81480eda4d6..d5fc422a9f9 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -55,6 +55,12 @@ const EnumPropertyItem rna_enum_mesh_delimit_mode_items[] = {
{0, NULL, 0, NULL, NULL},
};
+static const EnumPropertyItem rna_enum_mesh_remesh_mode_items[] = {
+ {REMESH_VOXEL, "VOXEL", 0, "Voxel", "Use the voxel remesher"},
+ {REMESH_QUAD, "QUAD", 0, "Quad", "Use the quad remesher"},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifdef RNA_RUNTIME
# include "DNA_scene_types.h"
@@ -497,9 +503,7 @@ static void rna_Mesh_texspace_size_get(PointerRNA *ptr, float values[3])
{
Mesh *me = (Mesh *)ptr->data;
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
+ BKE_mesh_texspace_ensure(me);
copy_v3_v3(values, me->size);
}
@@ -508,9 +512,7 @@ static void rna_Mesh_texspace_loc_get(PointerRNA *ptr, float values[3])
{
Mesh *me = (Mesh *)ptr->data;
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
+ BKE_mesh_texspace_ensure(me);
copy_v3_v3(values, me->loc);
}
@@ -541,7 +543,7 @@ static void rna_MeshVertex_undeformed_co_get(PointerRNA *ptr, float values[3])
/* orco is normalized to 0..1, we do inverse to match mvert->co */
float loc[3], size[3];
- BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, NULL, size);
+ BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, size);
madd_v3_v3v3v3(values, loc, orco[(mvert - me->mvert)], size);
}
else {
@@ -1370,7 +1372,7 @@ static int rna_MeshPolygonStringPropertyLayer_data_length(PointerRNA *ptr)
}
/* XXX, we dont have proper byte string support yet, so for now use the (bytes + 1)
- * bmesh API exposes correct python/bytestring access */
+ * bmesh API exposes correct python/byte-string access. */
void rna_MeshStringProperty_s_get(PointerRNA *ptr, char *value)
{
MStringProperty *ms = (MStringProperty *)ptr->data;
@@ -2205,15 +2207,6 @@ void rna_def_texmat_common(StructRNA *srna, const char *texspace_editable)
RNA_def_property_editable_func(prop, texspace_editable);
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
- /* not supported yet */
-# if 0
- prop = RNA_def_property(srna, "texspace_rot", PROP_FLOAT, PROP_EULER);
- RNA_def_property_float(prop, NULL, "rot");
- RNA_def_property_ui_text(prop, "Texture Space Rotation", "Texture space rotation");
- RNA_def_property_editable_func(prop, texspace_editable);
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-# endif
-
/* materials */
prop = RNA_def_property(srna, "materials", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol");
@@ -2421,7 +2414,7 @@ static void rna_def_uv_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_pointer_funcs(
prop, "rna_Mesh_uv_layer_active_get", "rna_Mesh_uv_layer_active_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK);
- RNA_def_property_ui_text(prop, "Active UV loop layer", "Active UV loop layer");
+ RNA_def_property_ui_text(prop, "Active UV Loop Layer", "Active UV loop layer");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
@@ -2429,7 +2422,7 @@ static void rna_def_uv_layers(BlenderRNA *brna, PropertyRNA *cprop)
"rna_Mesh_uv_layer_active_index_get",
"rna_Mesh_uv_layer_active_index_set",
"rna_Mesh_uv_layer_index_range");
- RNA_def_property_ui_text(prop, "Active UV loop layer Index", "Active UV loop layer index");
+ RNA_def_property_ui_text(prop, "Active UV Loop Layer Index", "Active UV loop layer index");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
}
@@ -2809,28 +2802,28 @@ static void rna_def_mesh(BlenderRNA *brna)
prop, "rna_Mesh_uv_layer_clone_get", "rna_Mesh_uv_layer_clone_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
- prop, "Clone UV loop layer", "UV loop layer to be used as cloning source");
+ prop, "Clone UV Loop Layer", "UV loop layer to be used as cloning source");
prop = RNA_def_property(srna, "uv_layer_clone_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop,
"rna_Mesh_uv_layer_clone_index_get",
"rna_Mesh_uv_layer_clone_index_set",
"rna_Mesh_uv_layer_index_range");
- RNA_def_property_ui_text(prop, "Clone UV loop layer Index", "Clone UV loop layer index");
+ RNA_def_property_ui_text(prop, "Clone UV Loop Layer Index", "Clone UV loop layer index");
prop = RNA_def_property(srna, "uv_layer_stencil", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshUVLoopLayer");
RNA_def_property_pointer_funcs(
prop, "rna_Mesh_uv_layer_stencil_get", "rna_Mesh_uv_layer_stencil_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Mask UV loop layer", "UV loop layer to mask the painted area");
+ RNA_def_property_ui_text(prop, "Mask UV Loop Layer", "UV loop layer to mask the painted area");
prop = RNA_def_property(srna, "uv_layer_stencil_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop,
"rna_Mesh_uv_layer_stencil_index_get",
"rna_Mesh_uv_layer_stencil_index_set",
"rna_Mesh_uv_layer_index_range");
- RNA_def_property_ui_text(prop, "Mask UV loop layer Index", "Mask UV loop layer index");
+ RNA_def_property_ui_text(prop, "Mask UV Loop Layer Index", "Mask UV loop layer index");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
/* Vertex colors */
@@ -2994,18 +2987,41 @@ static void rna_def_mesh(BlenderRNA *brna)
/* Remesh */
prop = RNA_def_property(srna, "remesh_voxel_size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "remesh_voxel_size");
- RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_range(prop, 0.00001f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0001f, FLT_MAX, 0.01, 4);
RNA_def_property_ui_text(prop,
- "Voxel size",
+ "Voxel Size",
"Size of the voxel in object space used for volume evaluation. Lower "
"values preserve finer details");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+ prop = RNA_def_property(srna, "remesh_voxel_adaptivity", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "remesh_voxel_adaptivity");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01, 4);
+ RNA_def_property_ui_text(
+ prop,
+ "Adaptivity",
+ "Reduces the final face count by simplifying geometry where detail is not needed, "
+ "generating triangles. A value greater than 0 disables Fix Poles");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+
prop = RNA_def_property(srna, "remesh_smooth_normals", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_SMOOTH_NORMALS);
- RNA_def_property_ui_text(prop, "Smooth normals", "Smooth the normals of the remesher result");
+ RNA_def_property_ui_text(prop, "Smooth Normals", "Smooth the normals of the remesher result");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+
+ prop = RNA_def_property(srna, "remesh_fix_poles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_FIX_POLES);
+ RNA_def_property_ui_text(prop, "Fix Poles", "Produces less poles and a better topology flow");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+
+ prop = RNA_def_property(srna, "remesh_preserve_volume", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_REPROJECT_VOLUME);
+ RNA_def_property_ui_text(
+ prop,
+ "Preserve Volume",
+ "Projects the mesh to preserve the volume and details of the original mesh");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
prop = RNA_def_property(srna, "remesh_preserve_paint_mask", PROP_BOOLEAN, PROP_NONE);
@@ -3013,6 +3029,13 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_boolean_default(prop, false);
RNA_def_property_ui_text(prop, "Preserve Paint Mask", "Keep the current mask on the new mesh");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+
+ prop = RNA_def_property(srna, "remesh_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "remesh_mode");
+ RNA_def_property_enum_items(prop, rna_enum_mesh_remesh_mode_items);
+ RNA_def_property_ui_text(prop, "Remesh Mode", "");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+
/* End remesh */
prop = RNA_def_property(srna, "use_auto_smooth", PROP_BOOLEAN, PROP_NONE);
@@ -3026,7 +3049,6 @@ static void rna_def_mesh(BlenderRNA *brna)
prop = RNA_def_property(srna, "auto_smooth_angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "smoothresh");
- RNA_def_property_float_default(prop, DEG2RADF(180.0f));
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
RNA_def_property_ui_text(prop,
"Auto Smooth Angle",
@@ -3073,22 +3095,12 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
# endif
- /* not supported yet */
-# if 0
- prop = RNA_def_property(srna, "texspace_rot", PROP_FLOAT, PROP_EULER);
- RNA_def_property_float(prop, NULL, "rot");
- RNA_def_property_ui_text(prop, "Texture Space Rotation", "Texture space rotation");
- RNA_def_property_editable_func(prop, texspace_editable);
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-# endif
-
/* editflag */
prop = RNA_def_property(srna, "use_mirror_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_MIRROR_X);
RNA_def_property_ui_text(prop, "X Mirror", "X Axis mirror editing");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-# if 0
prop = RNA_def_property(srna, "use_mirror_y", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_MIRROR_Y);
RNA_def_property_ui_text(prop, "Y Mirror", "Y Axis mirror editing");
@@ -3096,7 +3108,6 @@ static void rna_def_mesh(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_mirror_z", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_MIRROR_Z);
RNA_def_property_ui_text(prop, "Z Mirror", "Z Axis mirror editing");
-# endif
prop = RNA_def_property(srna, "use_mirror_topology", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_MIRROR_TOPO);
diff --git a/source/blender/makesrna/intern/rna_meta.c b/source/blender/makesrna/intern/rna_meta.c
index 451bdda45f5..2b2a928e280 100644
--- a/source/blender/makesrna/intern/rna_meta.c
+++ b/source/blender/makesrna/intern/rna_meta.c
@@ -332,7 +332,6 @@ static void rna_def_metaball(BlenderRNA *brna)
/* number values */
prop = RNA_def_property(srna, "resolution", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "wiresize");
- RNA_def_property_float_default(prop, 0.4f);
RNA_def_property_range(prop, 0.005f, 10000.0f);
RNA_def_property_ui_range(prop, 0.05f, 1000.0f, 2.5f, 3);
RNA_def_property_ui_text(prop, "Wire Size", "Polygonization resolution in the 3D viewport");
@@ -340,7 +339,6 @@ static void rna_def_metaball(BlenderRNA *brna)
prop = RNA_def_property(srna, "render_resolution", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "rendersize");
- RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_range(prop, 0.005f, 10000.0f);
RNA_def_property_ui_range(prop, 0.025f, 1000.0f, 2.5f, 3);
RNA_def_property_ui_text(prop, "Render Size", "Polygonization resolution in rendering");
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 26bb83fe6e8..2a125625681 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -755,6 +755,47 @@ static void rna_HookModifier_object_set(PointerRNA *ptr,
BKE_object_modifier_hook_reset(owner, hmd);
}
+static bool rna_HookModifier_object_override_apply(Main *UNUSED(bmain),
+ PointerRNA *ptr_dst,
+ PointerRNA *ptr_src,
+ PointerRNA *ptr_storage,
+ PropertyRNA *prop_dst,
+ PropertyRNA *prop_src,
+ PropertyRNA *UNUSED(prop_storage),
+ const int len_dst,
+ const int len_src,
+ const int len_storage,
+ PointerRNA *UNUSED(ptr_item_dst),
+ PointerRNA *UNUSED(ptr_item_src),
+ PointerRNA *UNUSED(ptr_item_storage),
+ IDOverrideLibraryPropertyOperation *opop)
+{
+ BLI_assert(len_dst == len_src && (!ptr_storage || len_dst == len_storage) && len_dst == 0);
+ BLI_assert(opop->operation == IDOVERRIDE_LIBRARY_OP_REPLACE &&
+ "Unsupported RNA override operation on Hook modifier target objet pointer");
+ UNUSED_VARS_NDEBUG(ptr_storage, len_dst, len_src, len_storage, opop);
+
+ /* We need a special handling here because setting hook target resets invert parent matrix,
+ * which is evil in our case. */
+ HookModifierData *hmd = ptr_dst->data;
+ Object *owner = (Object *)ptr_dst->owner_id;
+ Object *target_dst = RNA_property_pointer_get(ptr_dst, prop_dst).data;
+ Object *target_src = RNA_property_pointer_get(ptr_src, prop_src).data;
+
+ BLI_assert(target_dst == hmd->object);
+
+ if (target_src == target_dst) {
+ return false;
+ }
+
+ hmd->object = target_src;
+ if (target_src == NULL) {
+ /* The only case where we do want default behavior (with matrix reset). */
+ BKE_object_modifier_hook_reset(owner, hmd);
+ }
+ return true;
+}
+
static void rna_HookModifier_subtarget_set(PointerRNA *ptr, const char *value)
{
Object *owner = (Object *)ptr->owner_id;
@@ -874,7 +915,7 @@ static void rna_MultiresModifier_type_set(PointerRNA *ptr, int value)
Object *ob = (Object *)ptr->owner_id;
MultiresModifierData *mmd = (MultiresModifierData *)ptr->data;
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
mmd->simple = value;
}
@@ -1346,7 +1387,7 @@ static void rna_CorrectiveSmoothModifier_update(Main *bmain, Scene *scene, Point
{
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)ptr->data;
- MEM_SAFE_FREE(csmd->delta_cache);
+ MEM_SAFE_FREE(csmd->delta_cache.deltas);
rna_Modifier_update(bmain, scene, ptr);
}
@@ -2021,7 +2062,7 @@ static void rna_def_modifier_decimate(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_dissolve_boundaries", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_DECIM_FLAG_ALL_BOUNDARY_VERTS);
RNA_def_property_ui_text(
- prop, "All Boundaries", "Dissolve all vertices inbetween face boundaries (planar only)");
+ prop, "All Boundaries", "Dissolve all vertices in between face boundaries (planar only)");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "delimit", PROP_ENUM, PROP_NONE);
@@ -2289,6 +2330,7 @@ static void rna_def_modifier_hook(BlenderRNA *brna)
prop, "Object", "Parent Object for hook, also recalculates and clears offset");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_override_funcs(prop, NULL, NULL, "rna_HookModifier_object_override_apply");
RNA_def_property_pointer_funcs(prop, NULL, "rna_HookModifier_object_set", NULL, NULL);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
@@ -3040,7 +3082,7 @@ static void rna_def_modifier_cast(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_transform", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_CAST_USE_OB_TRANSFORM);
RNA_def_property_ui_text(
- prop, "Use transform", "Use object transform to control projection shape");
+ prop, "Use Transform", "Use object transform to control projection shape");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_FACTOR);
@@ -5862,7 +5904,7 @@ static void rna_def_modifier_surfacedeform(BlenderRNA *brna)
prop = RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 2.0f, 16.0f);
RNA_def_property_ui_text(
- prop, "Interpolation falloff", "Controls how much nearby polygons influence deformation");
+ prop, "Interpolation Falloff", "Controls how much nearby polygons influence deformation");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "is_bound", PROP_BOOLEAN, PROP_NONE);
@@ -6013,7 +6055,7 @@ void RNA_def_modifier(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_ApplyOnSpline);
RNA_def_property_ui_text(
prop,
- "Apply on spline",
+ "Apply on Spline",
"Apply this and all preceding deformation modifiers on splines' points rather than "
"on filled curve/surface");
RNA_def_property_ui_icon(prop, ICON_SURFACE_DATA, 0);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 0909aa42a4d..48562cf2684 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -102,6 +102,26 @@ static const EnumPropertyItem node_chunksize_items[] = {
};
#endif
+const EnumPropertyItem rna_enum_mapping_type_items[] = {
+ {NODE_MAPPING_TYPE_POINT, "POINT", 0, "Point", "Transform a point"},
+ {NODE_MAPPING_TYPE_TEXTURE,
+ "TEXTURE",
+ 0,
+ "Texture",
+ "Transform a texture by inverse mapping the texture coordinate"},
+ {NODE_MAPPING_TYPE_VECTOR,
+ "VECTOR",
+ 0,
+ "Vector",
+ "Transform a direction vector. Location is ignored"},
+ {NODE_MAPPING_TYPE_NORMAL,
+ "NORMAL",
+ 0,
+ "Normal",
+ "Transform a unit normal vector. Location is ignored"},
+ {0, NULL, 0, NULL, NULL},
+};
+
const EnumPropertyItem rna_enum_node_math_items[] = {
{NODE_MATH_ADD, "ADD", 0, "Add", "A + B"},
{NODE_MATH_SUBTRACT, "SUBTRACT", 0, "Subtract", "A - B"},
@@ -246,7 +266,7 @@ int rna_node_tree_type_to_enum(bNodeTreeType *typeinfo)
result = i;
break;
}
- ++i;
+ i++;
}
NODE_TREE_TYPES_END;
return result;
@@ -260,7 +280,7 @@ int rna_node_tree_idname_to_enum(const char *idname)
result = i;
break;
}
- ++i;
+ i++;
}
NODE_TREE_TYPES_END;
return result;
@@ -275,7 +295,7 @@ bNodeTreeType *rna_node_tree_type_from_enum(int value)
result = nt;
break;
}
- ++i;
+ i++;
}
NODE_TREE_TYPES_END;
return result;
@@ -291,7 +311,7 @@ const EnumPropertyItem *rna_node_tree_type_itemf(void *data,
NODE_TREE_TYPES_BEGIN (nt) {
if (poll && !poll(data, nt)) {
- ++i;
+ i++;
continue;
}
@@ -303,7 +323,7 @@ const EnumPropertyItem *rna_node_tree_type_itemf(void *data,
RNA_enum_item_add(&item, &totitem, &tmp);
- ++i;
+ i++;
}
NODE_TREE_TYPES_END;
@@ -326,7 +346,7 @@ int rna_node_type_to_enum(bNodeType *typeinfo)
result = i;
break;
}
- ++i;
+ i++;
}
NODE_TYPES_END;
return result;
@@ -340,7 +360,7 @@ int rna_node_idname_to_enum(const char *idname)
result = i;
break;
}
- ++i;
+ i++;
}
NODE_TYPES_END;
return result;
@@ -355,7 +375,7 @@ bNodeType *rna_node_type_from_enum(int value)
result = ntype;
break;
}
- ++i;
+ i++;
}
NODE_TYPES_END;
return result;
@@ -371,7 +391,7 @@ const EnumPropertyItem *rna_node_type_itemf(void *data,
NODE_TYPES_BEGIN (ntype) {
if (poll && !poll(data, ntype)) {
- ++i;
+ i++;
continue;
}
@@ -383,7 +403,7 @@ const EnumPropertyItem *rna_node_type_itemf(void *data,
RNA_enum_item_add(&item, &totitem, &tmp);
- ++i;
+ i++;
}
NODE_TYPES_END;
@@ -406,7 +426,7 @@ int rna_node_socket_type_to_enum(bNodeSocketType *typeinfo)
result = i;
break;
}
- ++i;
+ i++;
}
NODE_SOCKET_TYPES_END;
return result;
@@ -420,7 +440,7 @@ int rna_node_socket_idname_to_enum(const char *idname)
result = i;
break;
}
- ++i;
+ i++;
}
NODE_SOCKET_TYPES_END;
return result;
@@ -435,7 +455,7 @@ bNodeSocketType *rna_node_socket_type_from_enum(int value)
result = stype;
break;
}
- ++i;
+ i++;
}
NODE_SOCKET_TYPES_END;
return result;
@@ -452,7 +472,7 @@ const EnumPropertyItem *rna_node_socket_type_itemf(void *data,
NODE_SOCKET_TYPES_BEGIN (stype) {
if (poll && !poll(data, stype)) {
- ++i;
+ i++;
continue;
}
@@ -465,7 +485,7 @@ const EnumPropertyItem *rna_node_socket_type_itemf(void *data,
RNA_enum_item_add(&item, &totitem, &tmp);
- ++i;
+ i++;
}
NODE_SOCKET_TYPES_END;
@@ -1462,7 +1482,7 @@ static void rna_Node_draw_label(bNodeTree *ntree, bNode *node, char *label, int
node->typeinfo->ext.call(NULL, &ptr, func, &list);
RNA_parameter_get_lookup(&list, "label", &ret);
- rlabel = *(char **)ret;
+ rlabel = (char *)ret;
BLI_strncpy(label, rlabel != NULL ? rlabel : "", maxlen);
RNA_parameter_list_free(&list);
@@ -2632,8 +2652,8 @@ static PointerRNA rna_NodeInternal_input_template(StructRNA *srna, int index)
bNodeSocketTemplate *stemp = ntype->inputs;
int i = 0;
while (i < index && stemp->type >= 0) {
- ++i;
- ++stemp;
+ i++;
+ stemp++;
}
if (i == index && stemp->type >= 0) {
PointerRNA ptr;
@@ -2651,8 +2671,8 @@ static PointerRNA rna_NodeInternal_output_template(StructRNA *srna, int index)
bNodeSocketTemplate *stemp = ntype->outputs;
int i = 0;
while (i < index && stemp->type >= 0) {
- ++i;
- ++stemp;
+ i++;
+ stemp++;
}
if (i == index && stemp->type >= 0) {
PointerRNA ptr;
@@ -3213,13 +3233,6 @@ static void rna_Image_Node_update_id(Main *UNUSED(bmain), Scene *UNUSED(scene),
nodeUpdate(ntree, node); /* to update image node sockets */
}
-static void rna_Mapping_Node_update(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- bNode *node = ptr->data;
- BKE_texture_mapping_init(node->storage);
- rna_Node_update(bmain, scene, ptr);
-}
-
static void rna_NodeOutputFile_slots_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
bNode *node = ptr->data;
@@ -4034,68 +4047,13 @@ static void def_sh_output_linestyle(StructRNA *srna)
static void def_sh_mapping(StructRNA *srna)
{
- static const EnumPropertyItem prop_vect_type_items[] = {
- {TEXMAP_TYPE_TEXTURE,
- "TEXTURE",
- 0,
- "Texture",
- "Transform a texture by inverse mapping the texture coordinate"},
- {TEXMAP_TYPE_POINT, "POINT", 0, "Point", "Transform a point"},
- {TEXMAP_TYPE_VECTOR, "VECTOR", 0, "Vector", "Transform a direction vector"},
- {TEXMAP_TYPE_NORMAL, "NORMAL", 0, "Normal", "Transform a normal vector with unit length"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static float default_1[3] = {1.f, 1.f, 1.f};
-
PropertyRNA *prop;
- RNA_def_struct_sdna_from(srna, "TexMapping", "storage");
-
prop = RNA_def_property(srna, "vector_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_vect_type_items);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, rna_enum_mapping_type_items);
RNA_def_property_ui_text(prop, "Type", "Type of vector that the mapping transforms");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- prop = RNA_def_property(srna, "translation", PROP_FLOAT, PROP_TRANSLATION);
- RNA_def_property_float_sdna(prop, NULL, "loc");
- RNA_def_property_ui_text(prop, "Location", "");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- /* Not PROP_XYZ, this is now in radians, no more degrees */
- prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_EULER);
- RNA_def_property_float_sdna(prop, NULL, "rot");
- RNA_def_property_ui_text(prop, "Rotation", "");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "size");
- RNA_def_property_float_array_default(prop, default_1);
- RNA_def_property_flag(prop, PROP_PROPORTIONAL);
- RNA_def_property_ui_text(prop, "Scale", "");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- prop = RNA_def_property(srna, "min", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "min");
- RNA_def_property_ui_text(prop, "Minimum", "Minimum value for clipping");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- prop = RNA_def_property(srna, "max", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "max");
- RNA_def_property_float_array_default(prop, default_1);
- RNA_def_property_ui_text(prop, "Maximum", "Maximum value for clipping");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- prop = RNA_def_property(srna, "use_min", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", TEXMAP_CLIP_MIN);
- RNA_def_property_ui_text(prop, "Has Minimum", "Whether to use minimum clipping value");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- prop = RNA_def_property(srna, "use_max", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", TEXMAP_CLIP_MAX);
- RNA_def_property_ui_text(prop, "Has Maximum", "Whether to use maximum clipping value");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
}
static void def_sh_attribute(StructRNA *srna)
@@ -4346,8 +4304,17 @@ static void def_sh_tex_gradient(StructRNA *srna)
static void def_sh_tex_noise(StructRNA *srna)
{
+ PropertyRNA *prop;
+
RNA_def_struct_sdna_from(srna, "NodeTexNoise", "storage");
def_sh_tex(srna);
+
+ prop = RNA_def_property(srna, "noise_dimensions", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "dimensions");
+ RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
+ RNA_def_property_ui_text(
+ prop, "Dimensions", "The dimensions of the space to evaluate the noise in");
+ RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
}
static void def_sh_tex_checker(StructRNA *srna)
@@ -4422,34 +4389,54 @@ static void def_sh_tex_musgrave(StructRNA *srna)
RNA_def_struct_sdna_from(srna, "NodeTexMusgrave", "storage");
def_sh_tex(srna);
+ prop = RNA_def_property(srna, "musgrave_dimensions", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "dimensions");
+ RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
+ RNA_def_property_ui_text(prop, "Dimensions", "");
+ RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
+
prop = RNA_def_property(srna, "musgrave_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "musgrave_type");
RNA_def_property_enum_items(prop, prop_musgrave_type);
RNA_def_property_ui_text(prop, "Type", "");
- RNA_def_property_update(prop, 0, "rna_Node_update");
+ RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
}
static void def_sh_tex_voronoi(StructRNA *srna)
{
- static const EnumPropertyItem prop_coloring_items[] = {
- {SHD_VORONOI_INTENSITY, "INTENSITY", 0, "Intensity", "Only calculate intensity"},
- {SHD_VORONOI_CELLS, "CELLS", 0, "Cells", "Color cells by position"},
- {0, NULL, 0, NULL, NULL},
- };
-
static EnumPropertyItem prop_distance_items[] = {
- {SHD_VORONOI_DISTANCE, "DISTANCE", 0, "Distance", "Distance"},
- {SHD_VORONOI_MANHATTAN, "MANHATTAN", 0, "Manhattan", "Manhattan (city block) distance"},
+ {SHD_VORONOI_EUCLIDEAN, "EUCLIDEAN", 0, "Euclidean", "Euclidean distance"},
+ {SHD_VORONOI_MANHATTAN, "MANHATTAN", 0, "Manhattan", "Manhattan distance"},
{SHD_VORONOI_CHEBYCHEV, "CHEBYCHEV", 0, "Chebychev", "Chebychev distance"},
{SHD_VORONOI_MINKOWSKI, "MINKOWSKI", 0, "Minkowski", "Minkowski distance"},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem prop_feature_items[] = {
- {SHD_VORONOI_F1, "F1", 0, "Closest", "Closest point"},
- {SHD_VORONOI_F2, "F2", 0, "2nd Closest", "2nd closest point"},
- {SHD_VORONOI_F3, "F3", 0, "3rd Closest", "3rd closest point"},
- {SHD_VORONOI_F4, "F4", 0, "4th Closest", "4th closest point"},
- {SHD_VORONOI_F2F1, "F2F1", 0, "Crackle", "Difference between 2nd and 1st closest point"},
+ {SHD_VORONOI_F1,
+ "F1",
+ 0,
+ "F1",
+ "Computes the distance to the closest point as well as its position and color"},
+ {SHD_VORONOI_F2,
+ "F2",
+ 0,
+ "F2",
+ "Computes the distance to the second closest point as well as its position and color"},
+ {SHD_VORONOI_SMOOTH_F1,
+ "SMOOTH_F1",
+ 0,
+ "Smooth F1",
+ "Smoothed version of F1. Weighted sum of neighbour voronoi cells"},
+ {SHD_VORONOI_DISTANCE_TO_EDGE,
+ "DISTANCE_TO_EDGE",
+ 0,
+ "Distance To Edge",
+ "Computes the distance to the edge of the voronoi cell"},
+ {SHD_VORONOI_N_SPHERE_RADIUS,
+ "N_SPHERE_RADIUS",
+ 0,
+ "N-Sphere Radius",
+ "Computes the radius of the n-sphere inscribed in the voronoi cell"},
{0, NULL, 0, NULL, NULL}};
PropertyRNA *prop;
@@ -4457,11 +4444,11 @@ static void def_sh_tex_voronoi(StructRNA *srna)
RNA_def_struct_sdna_from(srna, "NodeTexVoronoi", "storage");
def_sh_tex(srna);
- prop = RNA_def_property(srna, "coloring", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "coloring");
- RNA_def_property_enum_items(prop, prop_coloring_items);
- RNA_def_property_ui_text(prop, "Coloring", "");
- RNA_def_property_update(prop, 0, "rna_Node_update");
+ prop = RNA_def_property(srna, "voronoi_dimensions", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "dimensions");
+ RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
+ RNA_def_property_ui_text(prop, "Dimensions", "");
+ RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
prop = RNA_def_property(srna, "distance", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "distance");
@@ -4473,7 +4460,7 @@ static void def_sh_tex_voronoi(StructRNA *srna)
RNA_def_property_enum_sdna(prop, NULL, "feature");
RNA_def_property_enum_items(prop, prop_feature_items);
RNA_def_property_ui_text(prop, "Feature Output", "");
- RNA_def_property_update(prop, 0, "rna_Node_update");
+ RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
}
static void def_sh_tex_wave(StructRNA *srna)
@@ -4512,11 +4499,11 @@ static void def_sh_tex_white_noise(StructRNA *srna)
{
PropertyRNA *prop;
- prop = RNA_def_property(srna, "dimensions", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "noise_dimensions", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
RNA_def_property_ui_text(
- prop, "Dimensions", "The number of dimensions to evaluate the noise in");
+ prop, "Dimensions", "The dimensions of the space to evaluate the noise in");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
}
@@ -4880,6 +4867,19 @@ static void def_sh_uvmap(StructRNA *srna)
RNA_def_struct_sdna_from(srna, "bNode", NULL);
}
+static void def_sh_vertex_color(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeShaderVertexColor", "storage");
+
+ prop = RNA_def_property(srna, "layer_name", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Vertex Color", "Vertex Color");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ RNA_def_struct_sdna_from(srna, "bNode", NULL);
+}
+
static void def_sh_uvalongstroke(StructRNA *srna)
{
PropertyRNA *prop;
@@ -5719,7 +5719,7 @@ static void def_cmp_dilate_erode(StructRNA *srna)
prop = RNA_def_property(srna, "distance", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "custom2");
RNA_def_property_range(prop, -5000, 5000);
- RNA_def_property_ui_range(prop, -100, 100, 0, -1);
+ RNA_def_property_ui_range(prop, -100, 100, 1, -1);
RNA_def_property_ui_text(prop, "Distance", "Distance to grow/shrink (number of iterations)");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
@@ -5756,7 +5756,7 @@ static void def_cmp_inpaint(StructRNA *srna)
prop = RNA_def_property(srna, "distance", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "custom2");
- RNA_def_property_range(prop, 1, 10000);
+ RNA_def_property_range(prop, 0, 10000);
RNA_def_property_ui_text(prop, "Distance", "Distance to inpaint (number of iterations)");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
@@ -6955,7 +6955,7 @@ static void def_cmp_boxmask(StructRNA *srna)
prop = RNA_def_property(srna, "mask_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, node_masktype_items);
- RNA_def_property_ui_text(prop, "Mask type", "");
+ RNA_def_property_ui_text(prop, "Mask Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
RNA_def_struct_sdna_from(srna, "NodeBoxMask", "storage");
@@ -7002,7 +7002,7 @@ static void def_cmp_ellipsemask(StructRNA *srna)
prop = RNA_def_property(srna, "mask_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, node_masktype_items);
- RNA_def_property_ui_text(prop, "Mask type", "");
+ RNA_def_property_ui_text(prop, "Mask Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
RNA_def_struct_sdna_from(srna, "NodeEllipseMask", "storage");
@@ -7117,7 +7117,7 @@ static void def_cmp_bokehimage(StructRNA *srna)
RNA_def_property_float_sdna(prop, NULL, "lensshift");
RNA_def_property_float_default(prop, 0.0f);
RNA_def_property_range(prop, -1.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Lens shift", "Shift of the lens components");
+ RNA_def_property_ui_text(prop, "Lens Shift", "Shift of the lens components");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index d605aa6b4f7..75594d1b295 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -546,27 +546,27 @@ static void rna_Object_parent_set(PointerRNA *ptr,
}
}
-bool rna_Object_parent_override_apply(Main *UNUSED(bmain),
- PointerRNA *ptr_dst,
- PointerRNA *ptr_src,
- PointerRNA *ptr_storage,
- PropertyRNA *prop_dst,
- PropertyRNA *prop_src,
- PropertyRNA *UNUSED(prop_storage),
- const int len_dst,
- const int len_src,
- const int len_storage,
- PointerRNA *UNUSED(ptr_item_dst),
- PointerRNA *UNUSED(ptr_item_src),
- PointerRNA *UNUSED(ptr_item_storage),
- IDOverrideLibraryPropertyOperation *opop)
+static bool rna_Object_parent_override_apply(Main *UNUSED(bmain),
+ PointerRNA *ptr_dst,
+ PointerRNA *ptr_src,
+ PointerRNA *ptr_storage,
+ PropertyRNA *prop_dst,
+ PropertyRNA *prop_src,
+ PropertyRNA *UNUSED(prop_storage),
+ const int len_dst,
+ const int len_src,
+ const int len_storage,
+ PointerRNA *UNUSED(ptr_item_dst),
+ PointerRNA *UNUSED(ptr_item_src),
+ PointerRNA *UNUSED(ptr_item_storage),
+ IDOverrideLibraryPropertyOperation *opop)
{
BLI_assert(len_dst == len_src && (!ptr_storage || len_dst == len_storage) && len_dst == 0);
BLI_assert(opop->operation == IDOVERRIDE_LIBRARY_OP_REPLACE &&
- "Unsupported RNA override operation on animdata pointer");
+ "Unsupported RNA override operation on object parent pointer");
UNUSED_VARS_NDEBUG(ptr_storage, len_dst, len_src, len_storage, opop);
- /* We need a special handling here because setting parent resets pinvert parent matrix,
+ /* We need a special handling here because setting parent resets invert parent matrix,
* which is evil in our case. */
Object *ob = (Object *)ptr_dst->data;
Object *parent_dst = RNA_property_pointer_get(ptr_dst, prop_dst).data;
@@ -1410,6 +1410,22 @@ static void rna_Object_constraints_clear(Object *object, Main *bmain)
WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, object);
}
+static void rna_Object_constraints_move(
+ Object *object, Main *bmain, ReportList *reports, int from, int to)
+{
+ if (from == to) {
+ return;
+ }
+
+ if (!BLI_listbase_move_index(&object->constraints, from, to)) {
+ BKE_reportf(reports, RPT_ERROR, "Could not move constraint from index '%d' to '%d'", from, to);
+ return;
+ }
+
+ ED_object_constraint_tag_update(bmain, object, NULL);
+ WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT, object);
+}
+
bool rna_Object_constraints_override_apply(Main *UNUSED(bmain),
PointerRNA *ptr_dst,
PointerRNA *ptr_src,
@@ -2041,6 +2057,15 @@ static void rna_def_object_constraints(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "clear", "rna_Object_constraints_clear");
RNA_def_function_flag(func, FUNC_USE_MAIN);
RNA_def_function_ui_description(func, "Remove all constraint from this object");
+
+ func = RNA_def_function(srna, "move", "rna_Object_constraints_move");
+ RNA_def_function_ui_description(func, "Move a constraint to a different position");
+ RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS);
+ parm = RNA_def_int(
+ func, "from_index", -1, INT_MIN, INT_MAX, "From Index", "Index to move", 0, 10000);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "to_index", -1, INT_MIN, INT_MAX, "To Index", "Target index", 0, 10000);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
/* object.modifiers */
@@ -2537,7 +2562,6 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "quat");
RNA_def_property_editable_array_func(prop, "rna_Object_rotation_4d_editable");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
- RNA_def_property_float_array_default(prop, rna_default_quaternion);
RNA_def_property_ui_text(prop, "Quaternion Rotation", "Rotation in Quaternions");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
@@ -2574,7 +2598,6 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_editable_array_func(prop, "rna_Object_scale_editable");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 3);
- RNA_def_property_float_array_default(prop, rna_default_scale_3d);
RNA_def_property_ui_text(prop, "Scale", "Scaling of the object");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
@@ -2611,7 +2634,6 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "delta_rotation_quaternion", PROP_FLOAT, PROP_QUATERNION);
RNA_def_property_float_sdna(prop, NULL, "dquat");
- RNA_def_property_float_array_default(prop, rna_default_quaternion);
RNA_def_property_ui_text(
prop,
"Delta Rotation (Quaternion)",
@@ -2634,7 +2656,6 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "dscale");
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 3);
- RNA_def_property_float_array_default(prop, rna_default_scale_3d);
RNA_def_property_ui_text(prop, "Delta Scale", "Extra scaling added to the scale of the object");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
@@ -2714,7 +2735,7 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "parentinv");
RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
RNA_def_property_ui_text(
- prop, "Matrix", "Inverse of object's parent matrix at time of parenting");
+ prop, "Parent Inverse Matrix", "Inverse of object's parent matrix at time of parenting");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
/* modifiers */
@@ -2821,6 +2842,14 @@ static void rna_def_object(BlenderRNA *brna)
prop, "Display in Orthographic Mode", "Display image in orthographic mode");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ prop = RNA_def_property(srna, "show_empty_image_only_axis_aligned", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "empty_image_visibility_flag", OB_EMPTY_IMAGE_HIDE_NON_AXIS_ALIGNED);
+ RNA_def_property_ui_text(prop,
+ "Display Only Axis Aligned",
+ "Only display the image when it is aligned with the view axis");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
prop = RNA_def_property(srna, "use_empty_image_alpha", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "empty_image_flag", OB_EMPTY_IMAGE_USE_ALPHA_BLEND);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index d3bdfde86ce..56d25f5bebf 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -37,6 +37,7 @@
#include "DNA_object_types.h"
#include "BKE_layer.h"
+#include "BKE_gpencil.h"
#include "DEG_depsgraph.h"
@@ -220,36 +221,43 @@ static bool rna_Object_indirect_only_get(Object *ob, bContext *C, ViewLayer *vie
return ((base->flag & BASE_INDIRECT_ONLY) != 0);
}
-static Base *rna_Object_local_view_property_helper(
- bScreen *sc, View3D *v3d, Object *ob, ReportList *reports, Scene **r_scene)
+static Base *rna_Object_local_view_property_helper(bScreen *sc,
+ View3D *v3d,
+ ViewLayer *view_layer,
+ Object *ob,
+ ReportList *reports,
+ Scene **r_scene)
{
+ wmWindow *win = NULL;
if (v3d->localvd == NULL) {
BKE_report(reports, RPT_ERROR, "Viewport not in local view");
return NULL;
}
- wmWindow *win = ED_screen_window_find(sc, G_MAIN->wm.first);
- ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ if (view_layer == NULL) {
+ win = ED_screen_window_find(sc, G_MAIN->wm.first);
+ view_layer = WM_window_get_active_view_layer(win);
+ }
+
Base *base = BKE_view_layer_base_find(view_layer, ob);
if (base == NULL) {
BKE_reportf(
reports, RPT_WARNING, "Object %s not in view layer %s", ob->id.name + 2, view_layer->name);
}
- if (r_scene) {
+ if (r_scene != NULL && win != NULL) {
*r_scene = win->scene;
}
return base;
}
-static bool rna_Object_local_view_get(Object *ob, ReportList *reports, PointerRNA *v3d_ptr)
+static bool rna_Object_local_view_get(Object *ob, ReportList *reports, View3D *v3d)
{
- bScreen *sc = (bScreen *)v3d_ptr->owner_id;
- View3D *v3d = v3d_ptr->data;
- Base *base = rna_Object_local_view_property_helper(sc, v3d, ob, reports, NULL);
- if (base == NULL) {
- return false; /* Error reported. */
+ if (v3d->localvd == NULL) {
+ BKE_report(reports, RPT_ERROR, "Viewport not in local view");
+ return false;
}
- return (base->local_view_bits & v3d->local_view_uuid) != 0;
+
+ return ((ob->base_local_view_bits & v3d->local_view_uuid) != 0);
}
static void rna_Object_local_view_set(Object *ob,
@@ -260,7 +268,7 @@ static void rna_Object_local_view_set(Object *ob,
bScreen *sc = (bScreen *)v3d_ptr->owner_id;
View3D *v3d = v3d_ptr->data;
Scene *scene;
- Base *base = rna_Object_local_view_property_helper(sc, v3d, ob, reports, &scene);
+ Base *base = rna_Object_local_view_property_helper(sc, v3d, NULL, ob, reports, &scene);
if (base == NULL) {
return; /* Error reported. */
}
@@ -275,7 +283,8 @@ static void rna_Object_local_view_set(Object *ob,
}
}
-/* Convert a given matrix from a space to another (using the object and/or a bone as reference). */
+/* Convert a given matrix from a space to another (using the object and/or a bone as
+ * reference). */
static void rna_Object_mat_convert_space(Object *ob,
ReportList *reports,
bPoseChannel *pchan,
@@ -465,8 +474,8 @@ static int mesh_looptri_to_poly_index(Mesh *me_eval, const MLoopTri *lt)
return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
}
-/* TOOD(sergey): Make the Python API more clear that evaluation might happen, or requite passing
- * fully evaluated depsgraph. */
+/* TOOD(sergey): Make the Python API more clear that evaluation might happen, or requite
+ * passing fully evaluated depsgraph. */
static Object *eval_object_ensure(Object *ob,
bContext *C,
ReportList *reports,
@@ -504,8 +513,8 @@ static void rna_Object_ray_cast(Object *ob,
{
bool success = false;
- /* TODO(sergey): This isn't very reliable check. It is possible to have non-NULL pointer but
- * which is out of date, and possibly dangling one. */
+ /* TODO(sergey): This isn't very reliable check. It is possible to have non-NULL pointer
+ * but which is out of date, and possibly dangling one. */
if (ob->runtime.mesh_eval == NULL &&
(ob = eval_object_ensure(ob, C, reports, rnaptr_depsgraph)) == NULL) {
return;
@@ -685,6 +694,30 @@ static bool rna_Object_update_from_editmode(Object *ob, Main *bmain)
}
return result;
}
+
+bool rna_Object_generate_gpencil_strokes(Object *ob,
+ bContext *C,
+ ReportList *reports,
+ Object *ob_gpencil,
+ bool gpencil_lines,
+ bool use_collections)
+{
+ if (ob->type != OB_CURVE) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Object '%s' not valid for this operation! Only curves supported.",
+ ob->id.name + 2);
+ return false;
+ }
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+
+ BKE_gpencil_convert_curve(bmain, scene, ob_gpencil, ob, gpencil_lines, use_collections, false);
+
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA, NULL);
+
+ return true;
+}
#else /* RNA_RUNTIME */
void RNA_api_object(StructRNA *srna)
@@ -780,7 +813,7 @@ void RNA_api_object(StructRNA *srna)
RNA_def_function_ui_description(func, "Get the local view state for this object");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "viewport", "SpaceView3D", "", "Viewport in local view");
- RNA_def_parameter_flags(parm, 0, PARM_RNAPTR | PARM_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_boolean(func, "result", 0, "", "Object local view state");
RNA_def_function_return(func, parm);
@@ -1128,6 +1161,20 @@ void RNA_api_object(StructRNA *srna)
RNA_def_function_ui_description(func,
"Release memory used by caches associated with this object. "
"Intended to be used by render engines only");
+
+ /* Convert curve object to gpencil strokes. */
+ func = RNA_def_function(srna, "generate_gpencil_strokes", "rna_Object_generate_gpencil_strokes");
+ RNA_def_function_ui_description(func, "Convert a curve object to grease pencil strokes.");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
+
+ parm = RNA_def_pointer(
+ func, "ob_gpencil", "Object", "", "Grease Pencil object used to create new strokes");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_boolean(func, "gpencil_lines", 0, "", "Create Lines");
+ parm = RNA_def_boolean(func, "use_collections", 1, "", "Use Collections");
+
+ parm = RNA_def_boolean(func, "result", 0, "", "Result");
+ RNA_def_function_return(func, parm);
}
#endif /* RNA_RUNTIME */
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index d082dfc694c..87b14b56504 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -120,18 +120,38 @@ static const EnumPropertyItem empty_vortex_shape_items[] = {
# include "ED_object.h"
+static bool rna_Cache_get_valid_owner_ID(PointerRNA *ptr, Object **ob, Scene **scene)
+{
+ switch (GS(ptr->owner_id->name)) {
+ case ID_OB:
+ *ob = (Object *)ptr->owner_id;
+ break;
+ case ID_SCE:
+ *scene = (Scene *)ptr->owner_id;
+ break;
+ default:
+ BLI_assert(!"Trying to get PTCacheID from an invalid ID type "
+ "(Only scenes and objects are supported).");
+ break;
+ }
+
+ return (*ob != NULL || *scene != NULL);
+}
+
static void rna_Cache_change(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
- Object *ob = (Object *)ptr->owner_id;
- PointCache *cache = (PointCache *)ptr->data;
+ Object *ob = NULL;
+ Scene *scene = NULL;
- if (!ob) {
+ if (!rna_Cache_get_valid_owner_ID(ptr, &ob, &scene)) {
return;
}
+ PointCache *cache = (PointCache *)ptr->data;
+
cache->flag |= PTCACHE_OUTDATED;
- PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
+ PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
@@ -146,14 +166,16 @@ static void rna_Cache_change(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerR
static void rna_Cache_toggle_disk_cache(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
- Object *ob = (Object *)ptr->owner_id;
- PointCache *cache = (PointCache *)ptr->data;
+ Object *ob = NULL;
+ Scene *scene = NULL;
- if (!ob) {
+ if (!rna_Cache_get_valid_owner_ID(ptr, &ob, &scene)) {
return;
}
- PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
+ PointCache *cache = (PointCache *)ptr->data;
+
+ PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
/* smoke can only use disk cache */
if (pid.cache && pid.type != PTCACHE_TYPE_SMOKE_DOMAIN) {
@@ -166,18 +188,20 @@ static void rna_Cache_toggle_disk_cache(Main *UNUSED(bmain), Scene *UNUSED(scene
static void rna_Cache_idname_change(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
- Object *ob = (Object *)ptr->owner_id;
- PointCache *cache = (PointCache *)ptr->data;
- bool use_new_name = true;
+ Object *ob = NULL;
+ Scene *scene = NULL;
- if (!ob) {
+ if (!rna_Cache_get_valid_owner_ID(ptr, &ob, &scene)) {
return;
}
+ PointCache *cache = (PointCache *)ptr->data;
+ bool use_new_name = true;
+
/* TODO: check for proper characters */
if (cache->flag & PTCACHE_EXTERNAL) {
- PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
+ PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
if (pid.cache) {
BKE_ptcache_load_external(&pid);
@@ -190,7 +214,7 @@ static void rna_Cache_idname_change(Main *UNUSED(bmain), Scene *UNUSED(scene), P
PTCacheID *pid = NULL, *pid2 = NULL;
ListBase pidlist;
- BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
+ BKE_ptcache_ids_from_object(&pidlist, ob, scene, 0);
for (pid = pidlist.first; pid; pid = pid->next) {
if (pid->cache == cache) {
@@ -240,13 +264,19 @@ static void rna_Cache_list_begin(CollectionPropertyIterator *iter, PointerRNA *p
static void rna_Cache_active_point_cache_index_range(
PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
{
- Object *ob = (Object *)ptr->owner_id;
- PointCache *cache = ptr->data;
- PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
-
*min = 0;
*max = 0;
+ Object *ob = NULL;
+ Scene *scene = NULL;
+
+ if (!rna_Cache_get_valid_owner_ID(ptr, &ob, &scene)) {
+ return;
+ }
+
+ PointCache *cache = ptr->data;
+ PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
+
if (pid.cache) {
*max = max_ii(0, BLI_listbase_count(pid.ptcaches) - 1);
}
@@ -254,11 +284,18 @@ static void rna_Cache_active_point_cache_index_range(
static int rna_Cache_active_point_cache_index_get(PointerRNA *ptr)
{
- Object *ob = (Object *)ptr->owner_id;
- PointCache *cache = ptr->data;
- PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
int num = 0;
+ Object *ob = NULL;
+ Scene *scene = NULL;
+
+ if (!rna_Cache_get_valid_owner_ID(ptr, &ob, &scene)) {
+ return num;
+ }
+
+ PointCache *cache = ptr->data;
+ PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
+
if (pid.cache) {
num = BLI_findindex(pid.ptcaches, cache);
}
@@ -268,9 +305,15 @@ static int rna_Cache_active_point_cache_index_get(PointerRNA *ptr)
static void rna_Cache_active_point_cache_index_set(struct PointerRNA *ptr, int value)
{
- Object *ob = (Object *)ptr->owner_id;
+ Object *ob = NULL;
+ Scene *scene = NULL;
+
+ if (!rna_Cache_get_valid_owner_ID(ptr, &ob, &scene)) {
+ return;
+ }
+
PointCache *cache = ptr->data;
- PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
+ PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
if (pid.cache) {
*(pid.cache_ptr) = BLI_findlink(pid.ptcaches, value);
@@ -280,13 +323,19 @@ static void rna_Cache_active_point_cache_index_set(struct PointerRNA *ptr, int v
static void rna_PointCache_frame_step_range(
PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
{
- Object *ob = (Object *)ptr->owner_id;
- PointCache *cache = ptr->data;
- PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
-
*min = 1;
*max = 20;
+ Object *ob = NULL;
+ Scene *scene = NULL;
+
+ if (!rna_Cache_get_valid_owner_ID(ptr, &ob, &scene)) {
+ return;
+ }
+
+ PointCache *cache = ptr->data;
+ PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
+
if (pid.cache) {
*max = pid.max_step;
}
@@ -294,14 +343,16 @@ static void rna_PointCache_frame_step_range(
int rna_Cache_info_length(PointerRNA *ptr)
{
- PointCache *cache = (PointCache *)ptr->data;
- Object *ob = (Object *)ptr->owner_id;
+ Object *ob = NULL;
+ Scene *scene = NULL;
- if (!ob) {
+ if (!rna_Cache_get_valid_owner_ID(ptr, &ob, &scene)) {
return 0;
}
- PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
+ PointCache *cache = (PointCache *)ptr->data;
+
+ PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
if (cache->flag & PTCACHE_FLAG_INFO_DIRTY) {
BKE_ptcache_update_info(&pid);
@@ -1262,13 +1313,17 @@ static void rna_def_field(BlenderRNA *brna)
ICON_FORCE_LENNARDJONES,
"Lennard-Jones",
"Forcefield based on the Lennard-Jones potential"},
- {PFIELD_TEXTURE, "TEXTURE", ICON_FORCE_TEXTURE, "Texture", "Forcefield based on a texture"},
+ {PFIELD_TEXTURE, "TEXTURE", ICON_FORCE_TEXTURE, "Texture", "Force field based on a texture"},
{PFIELD_GUIDE,
"GUIDE",
ICON_FORCE_CURVE,
"Curve Guide",
"Create a force along a curve object"},
- {PFIELD_BOID, "BOID", ICON_FORCE_BOID, "Boid", ""},
+ {PFIELD_BOID,
+ "BOID",
+ ICON_FORCE_BOID,
+ "Boid",
+ "Create a force that acts as a boid's predators or target"},
{PFIELD_TURBULENCE,
"TURBULENCE",
ICON_FORCE_TURBULENCE,
@@ -1888,7 +1943,7 @@ static void rna_def_softbody(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_estimate_matrix", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "solverflags", SBSO_ESTIMATEIPO);
- RNA_def_property_ui_text(prop, "Estimate matrix", "Estimate matrix... split to COM, ROT, SCALE");
+ RNA_def_property_ui_text(prop, "Estimate Matrix", "Estimate matrix... split to COM, ROT, SCALE");
/***********************************************************************************/
/* these are not exactly settings, but reading calculated results*/
@@ -1897,7 +1952,7 @@ static void rna_def_softbody(BlenderRNA *brna)
/* translation */
prop = RNA_def_property(srna, "location_mass_center", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "lcom");
- RNA_def_property_ui_text(prop, "Center of mass", "Location of Center of mass");
+ RNA_def_property_ui_text(prop, "Center of Mass", "Location of center of mass");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
/* matrix */
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 98ecb053641..211d9e19ab4 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -1891,7 +1891,7 @@ static void rna_def_fluid_settings(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "viscosity_beta");
RNA_def_property_range(prop, 0.0f, 100.0f);
RNA_def_property_ui_range(prop, 0.0f, 2.0f, 1, 3);
- RNA_def_property_ui_text(prop, "Stiff viscosity", "Creates viscosity for expanding fluid");
+ RNA_def_property_ui_text(prop, "Stiff Viscosity", "Creates viscosity for expanding fluid");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
/* Double density relaxation */
@@ -2398,7 +2398,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_DIE_ON_COL);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(
- prop, "Die on hit", "Particles die when they collide with a deflector object");
+ prop, "Die on Hit", "Particles die when they collide with a deflector object");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop = RNA_def_property(srna, "use_size_deflect", PROP_BOOLEAN, PROP_NONE);
@@ -3297,7 +3297,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "keyed_loops");
RNA_def_property_range(prop, 1.0f, 10000.0f);
RNA_def_property_ui_range(prop, 1.0f, 100.0f, 0.1, 3);
- RNA_def_property_ui_text(prop, "Loop count", "Number of times the keys are looped");
+ RNA_def_property_ui_text(prop, "Loop Count", "Number of times the keys are looped");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
/* modified dm support */
@@ -3594,7 +3594,7 @@ static void rna_def_particle_system(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_keyed_timing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PSYS_KEYED_TIMING);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Keyed timing", "Use key times");
+ RNA_def_property_ui_text(prop, "Keyed Timing", "Use key times");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
prop = RNA_def_property(srna, "targets", PROP_COLLECTION, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index 7637930f37f..0f8f8d39c41 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -274,6 +274,12 @@ static void rna_PoseChannel_rotation_mode_set(PointerRNA *ptr, int value)
pchan->rotmode = value;
}
+static float rna_PoseChannel_length_get(PointerRNA *ptr)
+{
+ bPoseChannel *pchan = ptr->data;
+ return len_v3v3(pchan->pose_head, pchan->pose_tail);
+}
+
static void rna_PoseChannel_name_set(PointerRNA *ptr, const char *value)
{
Object *ob = (Object *)ptr->owner_id;
@@ -601,6 +607,24 @@ static void rna_PoseChannel_constraints_remove(
}
}
+static void rna_PoseChannel_constraints_move(
+ ID *id, bPoseChannel *pchan, Main *bmain, ReportList *reports, int from, int to)
+{
+ Object *ob = (Object *)id;
+
+ if (from == to) {
+ return;
+ }
+
+ if (!BLI_listbase_move_index(&pchan->constraints, from, to)) {
+ BKE_reportf(reports, RPT_ERROR, "Could not move constraint from index '%d' to '%d'", from, to);
+ return;
+ }
+
+ ED_object_constraint_tag_update(bmain, ob, NULL);
+ WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT, ob);
+}
+
bool rna_PoseChannel_constraints_override_apply(Main *UNUSED(bmain),
PointerRNA *ptr_dst,
PointerRNA *ptr_src,
@@ -929,6 +953,15 @@ static void rna_def_pose_channel_constraints(BlenderRNA *brna, PropertyRNA *cpro
parm = RNA_def_pointer(func, "constraint", "Constraint", "", "Removed constraint");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+ func = RNA_def_function(srna, "move", "rna_PoseChannel_constraints_move");
+ RNA_def_function_ui_description(func, "Move a constraint to a different position");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
+ parm = RNA_def_int(
+ func, "from_index", -1, INT_MIN, INT_MAX, "From Index", "Index to move", 0, 10000);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "to_index", -1, INT_MIN, INT_MAX, "To Index", "Target index", 0, 10000);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
static void rna_def_pose_channel(BlenderRNA *brna)
@@ -1044,7 +1077,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
/* Curved bones settings - Applied on top of restpose values */
- rna_def_bone_curved_common(srna, true);
+ rna_def_bone_curved_common(srna, true, false);
/* Custom BBone next/prev sources */
prop = RNA_def_property(srna, "bbone_custom_handle_start", PROP_POINTER, PROP_NONE);
@@ -1108,6 +1141,11 @@ static void rna_def_pose_channel(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Pose Tail Position", "Location of tail of the channel's bone");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
+ prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_funcs(prop, "rna_PoseChannel_length_get", NULL, NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Length", "Length of the bone");
+
/* IK Settings */
prop = RNA_def_property(srna, "is_in_ik_chain", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_PoseChannel_has_ik_get", NULL);
@@ -1261,7 +1299,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Custom Object", "Object that defines custom draw type for this bone");
RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
- RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_dependency_update");
prop = RNA_def_property(srna, "custom_shape_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "custom_scale");
@@ -1419,7 +1457,7 @@ static void rna_def_pose_itasc(BlenderRNA *brna)
prop = RNA_def_property(srna, "step_count", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "numstep");
RNA_def_property_range(prop, 1.f, 50.f);
- RNA_def_property_ui_text(prop, "Num steps", "Divide the frame interval into this many steps");
+ RNA_def_property_ui_text(prop, "Num Steps", "Divide the frame interval into this many steps");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update");
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
@@ -1440,7 +1478,7 @@ static void rna_def_pose_itasc(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_auto_step", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ITASC_AUTO_STEP);
RNA_def_property_ui_text(prop,
- "Auto step",
+ "Auto Step",
"Automatically determine the optimal number of steps for best "
"performance/accuracy trade off");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update");
@@ -1449,14 +1487,14 @@ static void rna_def_pose_itasc(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "minstep");
RNA_def_property_range(prop, 0.0f, 0.1f);
RNA_def_property_ui_text(
- prop, "Min step", "Lower bound for timestep in second in case of automatic substeps");
+ prop, "Min Step", "Lower bound for timestep in second in case of automatic substeps");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update");
prop = RNA_def_property(srna, "step_max", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "maxstep");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(
- prop, "Max step", "Higher bound for timestep in second in case of automatic substeps");
+ prop, "Max Step", "Higher bound for timestep in second in case of automatic substeps");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update");
prop = RNA_def_property(srna, "feedback", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 6e21d02c0b3..26c8df4c7bb 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -613,7 +613,10 @@ static bool rna_Property_overridable_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- return (prop->flag_override & PROPOVERRIDE_OVERRIDABLE_LIBRARY) != 0;
+ IDProperty *idprop = rna_idproperty_check(&prop, ptr);
+
+ return idprop != NULL ? (idprop->flag & IDP_FLAG_OVERRIDABLE_LIBRARY) != 0 :
+ (prop->flag_override & PROPOVERRIDE_OVERRIDABLE_LIBRARY) != 0;
}
static bool rna_Property_use_output_get(PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 7d9a3cf06b8..1f967df7232 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -47,8 +47,6 @@
#include "ED_object.h"
#include "ED_gpencil.h"
-#include "GPU_extensions.h"
-
#include "DRW_engine.h"
#include "RNA_define.h"
@@ -143,7 +141,7 @@ const EnumPropertyItem rna_enum_proportional_falloff_curve_only_items[] = {
/* keep for operators, not used here */
const EnumPropertyItem rna_enum_mesh_select_mode_items[] = {
- {SCE_SELECT_VERTEX, "VERTEX", ICON_VERTEXSEL, "Vertex", "Vertex selection mode"},
+ {SCE_SELECT_VERTEX, "VERT", ICON_VERTEXSEL, "Vertex", "Vertex selection mode"},
{SCE_SELECT_EDGE, "EDGE", ICON_EDGESEL, "Edge", "Edge selection mode"},
{SCE_SELECT_FACE, "FACE", ICON_FACESEL, "Face", "Face selection mode"},
{0, NULL, 0, NULL, NULL},
@@ -712,20 +710,7 @@ static void rna_ToolSettings_snap_mode_set(struct PointerRNA *ptr, int value)
/* Grease Pencil update cache */
static void rna_GPencil_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
- /* mark all grease pencil datablocks of the scene */
- FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, ob) {
- if (ob->type == OB_GPENCIL) {
- bGPdata *gpd = (bGPdata *)ob->data;
- gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- }
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- }
- FOREACH_SCENE_COLLECTION_END;
-
- WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
+ ED_gpencil_tag_scene_gpencil(scene);
}
/* Grease Pencil Interpolation settings */
@@ -749,6 +734,35 @@ static void rna_GPencilInterpolateSettings_type_set(PointerRNA *ptr, int value)
}
}
+static void rna_Gpencil_selectmode_update(bContext *C, PointerRNA *ptr)
+{
+ ToolSettings *ts = (ToolSettings *)ptr->data;
+ /* If the mode is not Stroke, don't extend selection. */
+ if ((ts->gpencil_selectmode_edit & GP_SELECTMODE_STROKE) == 0) {
+ return;
+ }
+
+ /* Extend selection to all points in all selected strokes. */
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ if ((gps->flag & GP_STROKE_SELECT) && (gps->totpoints > 1)) {
+ bGPDspoint *pt;
+ for (int i = 0; i < gps->totpoints; i++) {
+ pt = &gps->points[i];
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ }
+}
+
static void rna_Gpencil_mask_point_update(Main *UNUSED(bmain),
Scene *UNUSED(scene),
PointerRNA *ptr)
@@ -2625,7 +2639,6 @@ static void rna_def_view3d_cursor(BlenderRNA *brna)
prop = RNA_def_property(srna, "rotation_quaternion", PROP_FLOAT, PROP_QUATERNION);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_float_sdna(prop, NULL, "rotation_quaternion");
- RNA_def_property_float_array_default(prop, rna_default_quaternion);
RNA_def_property_ui_text(
prop, "Quaternion Rotation", "Rotation in quaternions (keep normalized)");
RNA_def_property_update(prop, NC_WINDOW, NULL);
@@ -2929,24 +2942,35 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "transform_pivot_point", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "transform_pivot_point");
RNA_def_property_enum_items(prop, rna_enum_transform_pivot_items_full);
- RNA_def_property_ui_text(prop, "Pivot Point", "Pivot center for rotation/scaling");
+ RNA_def_property_ui_text(prop, "Transform Pivot Point", "Pivot center for rotation/scaling");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "use_transform_pivot_point_align", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "transform_flag", SCE_XFORM_AXIS_ALIGN);
RNA_def_property_ui_text(
prop, "Only Locations", "Manipulate origins (object, pose and weight paint mode only)");
- RNA_def_property_update(prop, NC_SCENE, NULL);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "use_transform_data_origin", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "transform_flag", SCE_XFORM_DATA_ORIGIN);
- RNA_def_property_ui_text(prop, "Data Origins", "Manipulate object data");
- RNA_def_property_update(prop, NC_SCENE, NULL);
+ RNA_def_property_ui_text(prop, "Transform Origins", "Manipulate object data");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "use_transform_skip_children", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "transform_flag", SCE_XFORM_SKIP_CHILDREN);
+ RNA_def_property_ui_text(prop, "Transform Parents", "Don't transform children");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "use_mesh_automerge", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "automerge", 0);
+ RNA_def_property_boolean_sdna(prop, NULL, "automerge", AUTO_MERGE);
RNA_def_property_ui_text(
- prop, "Auto Merge", "Automatically merge vertices moved to the same location");
+ prop, "Auto Merge Vertices", "Automatically merge vertices moved to the same location");
+ RNA_def_property_ui_icon(prop, ICON_AUTOMERGE_OFF, 1);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+
+ prop = RNA_def_property(srna, "use_mesh_automerge_and_split", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "automerge", AUTO_MERGE_AND_SPLIT);
+ RNA_def_property_ui_text(prop, "Split Edges & Faces", "Automatically split edges and faces");
RNA_def_property_ui_icon(prop, ICON_AUTOMERGE_OFF, 1);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
@@ -3108,6 +3132,8 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_enum_items(prop, gpencil_selectmode_items);
RNA_def_property_ui_text(prop, "Select Mode", "");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_Gpencil_selectmode_update");
/* Grease Pencil - Select mode Sculpt */
prop = RNA_def_property(srna, "use_gpencil_select_mask_point", PROP_BOOLEAN, PROP_NONE);
@@ -3337,7 +3363,7 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna)
prop, NULL, "rna_UnifiedPaintSettings_unprojected_radius_set", NULL);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_range(prop, 0.001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.001, 1, 0, -1);
+ RNA_def_property_ui_range(prop, 0.001, 1, 1, -1);
RNA_def_property_ui_text(prop, "Unprojected Radius", "Radius of brush in Blender units");
RNA_def_property_update(prop, 0, "rna_UnifiedPaintSettings_radius_update");
@@ -3535,7 +3561,6 @@ static void rna_def_statvis(BlenderRNA *brna)
/* overhang */
prop = RNA_def_property(srna, "overhang_min", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "overhang_min");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 10, 3);
RNA_def_property_ui_text(prop, "Overhang Min", "Minimum angle to display");
@@ -3544,7 +3569,6 @@ static void rna_def_statvis(BlenderRNA *brna)
prop = RNA_def_property(srna, "overhang_max", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "overhang_max");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 10, 3);
RNA_def_property_ui_text(prop, "Overhang Max", "Maximum angle to display");
@@ -3561,7 +3585,6 @@ static void rna_def_statvis(BlenderRNA *brna)
/* thickness */
prop = RNA_def_property(srna, "thickness_min", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "thickness_min");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, 1000.0);
RNA_def_property_ui_range(prop, 0.0f, 100.0, 0.001, 3);
RNA_def_property_ui_text(prop, "Thickness Min", "Minimum for measuring thickness");
@@ -3570,7 +3593,6 @@ static void rna_def_statvis(BlenderRNA *brna)
prop = RNA_def_property(srna, "thickness_max", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "thickness_max");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, 1000.0);
RNA_def_property_ui_range(prop, 0.0f, 100.0, 0.001, 3);
RNA_def_property_ui_text(prop, "Thickness Max", "Maximum for measuring thickness");
@@ -3587,7 +3609,6 @@ static void rna_def_statvis(BlenderRNA *brna)
/* distort */
prop = RNA_def_property(srna, "distort_min", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "distort_min");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 10, 3);
RNA_def_property_ui_text(prop, "Distort Min", "Minimum angle to display");
@@ -3596,7 +3617,6 @@ static void rna_def_statvis(BlenderRNA *brna)
prop = RNA_def_property(srna, "distort_max", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "distort_max");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 10, 3);
RNA_def_property_ui_text(prop, "Distort Max", "Maximum angle to display");
@@ -3606,7 +3626,6 @@ static void rna_def_statvis(BlenderRNA *brna)
/* sharp */
prop = RNA_def_property(srna, "sharp_min", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "sharp_min");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, -DEG2RADF(180.0f), DEG2RADF(180.0f));
RNA_def_property_ui_range(prop, -DEG2RADF(180.0f), DEG2RADF(180.0f), 10, 3);
RNA_def_property_ui_text(prop, "Distort Min", "Minimum angle to display");
@@ -3615,7 +3634,6 @@ static void rna_def_statvis(BlenderRNA *brna)
prop = RNA_def_property(srna, "sharp_max", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "sharp_max");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, -DEG2RADF(180.0f), DEG2RADF(180.0f));
RNA_def_property_ui_range(prop, -DEG2RADF(180.0f), DEG2RADF(180.0f), 10, 3);
RNA_def_property_ui_text(prop, "Distort Max", "Maximum angle to display");
@@ -5379,7 +5397,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 0, 500);
RNA_def_property_int_default(prop, 25);
RNA_def_property_ui_text(prop,
- "Keyframe interval",
+ "Keyframe Interval",
"Distance between key frames, also known as GOP size; "
"influences file size and seekability");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
@@ -5390,14 +5408,14 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 0, 16);
RNA_def_property_ui_text(
prop,
- "Max B-frames",
+ "Max B-Frames",
"Maximum number of B-frames between non-B-frames; influences file size and seekability");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_max_b_frames", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FFMPEG_USE_MAX_B_FRAMES);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Use max B-frames", "Set a maximum number of B-frames");
+ RNA_def_property_ui_text(prop, "Use Max B-Frames", "Set a maximum number of B-frames");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "buffersize", PROP_INT, PROP_NONE);
@@ -5421,7 +5439,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_enum_default(prop, FFM_CRF_MEDIUM);
RNA_def_property_ui_text(
prop,
- "Output quality",
+ "Output Quality",
"Constant Rate Factor (CRF); tradeoff between video quality and file size");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
@@ -5431,7 +5449,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_enum_items(prop, ffmpeg_preset_items);
RNA_def_property_enum_default(prop, FFM_PRESET_GOOD);
RNA_def_property_ui_text(
- prop, "Encoding speed", "Tradeoff between encoding speed and compression ratio");
+ prop, "Encoding Speed", "Tradeoff between encoding speed and compression ratio");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_autosplit", PROP_BOOLEAN, PROP_NONE);
@@ -5491,22 +5509,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem display_mode_items[] = {
- {R_OUTPUT_SCREEN,
- "SCREEN",
- 0,
- "Full Screen",
- "Images are rendered in a maximized Image Editor"},
- {R_OUTPUT_AREA, "AREA", 0, "Image Editor", "Images are rendered in an Image Editor"},
- {R_OUTPUT_WINDOW, "WINDOW", 0, "New Window", "Images are rendered in a new window"},
- {R_OUTPUT_NONE,
- "NONE",
- 0,
- "Keep User Interface",
- "Images are rendered without changing the user interface"},
- {0, NULL, 0, NULL, NULL},
- };
-
/* Bake */
static const EnumPropertyItem bake_mode_items[] = {
//{RE_BAKE_AO, "AO", 0, "Ambient Occlusion", "Bake ambient occlusion"},
@@ -5632,7 +5634,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "preview_start_resolution", PROP_INT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_range(prop, 8, 16384);
- RNA_def_property_int_default(prop, 64);
RNA_def_property_ui_text(prop,
"Start Resolution",
"Resolution to start rendering preview at, "
@@ -5904,13 +5905,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
"(this solves anti-aliasing issues with compositing)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
- prop = RNA_def_property(srna, "display_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "displaymode");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_enum_items(prop, display_mode_items);
- RNA_def_property_ui_text(prop, "Display", "Select where rendered images will be displayed");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
prop = RNA_def_property(srna, "use_lock_interface", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_lock_interface", 1);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -5986,14 +5980,13 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "bake_samples", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "bake_samples");
RNA_def_property_range(prop, 64, 1024);
- RNA_def_property_int_default(prop, 256);
RNA_def_property_ui_text(
prop, "Samples", "Number of samples used for ambient occlusion baking from multires");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_bake_user_scale", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "bake_flag", R_BAKE_USERSCALE);
- RNA_def_property_ui_text(prop, "User scale", "Use a user scale for the derivative map");
+ RNA_def_property_ui_text(prop, "User Scale", "Use a user scale for the derivative map");
prop = RNA_def_property(srna, "bake_user_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bake_user_scale");
@@ -6299,6 +6292,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Layers Blending", "Do not display blend layers");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ prop = RNA_def_property(srna, "simplify_gpencil_tint", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_TINT);
+ RNA_def_property_ui_text(prop, "Layers Tinting", "Do not display layer tint");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
/* persistent data */
prop = RNA_def_property(srna, "use_persistent_data", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_PERSISTENT_DATA);
@@ -6496,12 +6494,6 @@ static void rna_def_display_safe_areas(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static float default_title[2] = {0.1f, 0.05f};
- static float default_action[2] = {0.035f, 0.035f};
-
- static float default_title_center[2] = {0.175f, 0.05f};
- static float default_action_center[2] = {0.15f, 0.05f};
-
srna = RNA_def_struct(brna, "DisplaySafeAreas", NULL);
RNA_def_struct_ui_text(srna, "Safe Areas", "Safe areas used in 3D view and the sequencer");
RNA_def_struct_sdna(srna, "DisplaySafeAreas");
@@ -6511,14 +6503,12 @@ static void rna_def_display_safe_areas(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "title");
RNA_def_property_array(prop, 2);
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_float_array_default(prop, default_title);
RNA_def_property_ui_text(prop, "Title Safe Margins", "Safe area for text and graphics");
RNA_def_property_update(prop, NC_SCENE | ND_DRAW_RENDER_VIEWPORT, NULL);
prop = RNA_def_property(srna, "action", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "action");
RNA_def_property_array(prop, 2);
- RNA_def_property_float_array_default(prop, default_action);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Action Safe Margins", "Safe area for general elements");
RNA_def_property_update(prop, NC_SCENE | ND_DRAW_RENDER_VIEWPORT, NULL);
@@ -6526,7 +6516,6 @@ static void rna_def_display_safe_areas(BlenderRNA *brna)
prop = RNA_def_property(srna, "title_center", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "title_center");
RNA_def_property_array(prop, 2);
- RNA_def_property_float_array_default(prop, default_title_center);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop,
"Center Title Safe Margins",
@@ -6536,7 +6525,6 @@ static void rna_def_display_safe_areas(BlenderRNA *brna)
prop = RNA_def_property(srna, "action_center", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "action_center");
RNA_def_property_array(prop, 2);
- RNA_def_property_float_array_default(prop, default_action_center);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop,
"Center Action Safe Margins",
@@ -6549,8 +6537,6 @@ static void rna_def_scene_display(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static float default_light_direction[3] = {-M_SQRT1_3, -M_SQRT1_3, M_SQRT1_3};
-
srna = RNA_def_struct(brna, "SceneDisplay", NULL);
RNA_def_struct_ui_text(srna, "Scene Display", "Scene display settings for 3d viewport");
RNA_def_struct_sdna(srna, "SceneDisplay");
@@ -6559,13 +6545,11 @@ static void rna_def_scene_display(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "light_direction");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_array(prop, 3);
- RNA_def_property_float_array_default(prop, default_light_direction);
RNA_def_property_ui_text(
prop, "Light Direction", "Direction of the light for shadows and highlights");
RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_set_update");
prop = RNA_def_property(srna, "shadow_shift", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_default(prop, 0.1);
RNA_def_property_ui_text(prop, "Shadow Shift", "Shadow termination angle");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_range(prop, 0.00f, 1.0f, 1, 2);
@@ -6581,20 +6565,17 @@ static void rna_def_scene_display(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_set_update");
prop = RNA_def_property(srna, "matcap_ssao_distance", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_ui_text(
prop, "Distance", "Distance of object that contribute to the Cavity/Edge effect");
RNA_def_property_range(prop, 0.0f, 100000.0f);
RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3);
prop = RNA_def_property(srna, "matcap_ssao_attenuation", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Attenuation", "Attenuation constant");
RNA_def_property_range(prop, 1.0f, 100000.0f);
RNA_def_property_ui_range(prop, 1.0f, 100.0f, 1, 3);
prop = RNA_def_property(srna, "matcap_ssao_samples", PROP_INT, PROP_NONE);
- RNA_def_property_int_default(prop, 16);
RNA_def_property_ui_text(prop, "Samples", "Number of samples");
RNA_def_property_range(prop, 1, 500);
@@ -6620,12 +6601,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem eevee_shadow_method_items[] = {
- {SHADOW_ESM, "ESM", 0, "ESM", "Exponential Shadow Mapping"},
- {SHADOW_VSM, "VSM", 0, "VSM", "Variance Shadow Mapping"},
- {0, NULL, 0, NULL, NULL},
- };
-
static const EnumPropertyItem eevee_shadow_size_items[] = {
{64, "64", 0, "64px", ""},
{128, "128", 0, "128px", ""},
@@ -6653,15 +6628,12 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
- static float default_bloom_color[3] = {1.0f, 1.0f, 1.0f};
-
srna = RNA_def_struct(brna, "SceneEEVEE", NULL);
RNA_def_struct_path_func(srna, "rna_SceneEEVEE_path");
RNA_def_struct_ui_text(srna, "Scene Display", "Scene display settings for 3d viewport");
/* Indirect Lighting */
prop = RNA_def_property(srna, "gi_diffuse_bounces", PROP_INT, PROP_NONE);
- RNA_def_property_int_default(prop, 3);
RNA_def_property_ui_text(prop,
"Diffuse Bounces",
"Number of time the light is reinjected inside light grids, "
@@ -6671,13 +6643,11 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "gi_cubemap_resolution", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, eevee_shadow_size_items);
- RNA_def_property_enum_default(prop, 512);
RNA_def_property_ui_text(prop, "Cubemap Size", "Size of every cubemaps");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
prop = RNA_def_property(srna, "gi_visibility_resolution", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, eevee_gi_visibility_size_items);
- RNA_def_property_enum_default(prop, 32);
RNA_def_property_ui_text(prop,
"Irradiance Visibility Size",
"Size of the shadow map applied to each irradiance sample");
@@ -6686,7 +6656,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "gi_irradiance_smoothing", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 5, 2);
- RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_ui_text(prop,
"Irradiance Smoothing",
"Smoother irradiance interpolation but introduce light bleeding");
@@ -6694,7 +6663,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "gi_glossy_clamp", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_default(prop, 0.0f);
RNA_def_property_ui_text(prop,
"Clamp Glossy",
"Clamp pixel intensity to reduce noise inside glossy reflections "
@@ -6703,7 +6671,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
prop = RNA_def_property(srna, "gi_filter_quality", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_default(prop, 3.0f);
RNA_def_property_ui_text(
prop, "Filter Quality", "Take more samples during cubemap filtering to remove artifacts");
RNA_def_property_range(prop, 1.0f, 8.0f);
@@ -6711,7 +6678,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "gi_show_irradiance", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SHOW_IRRADIANCE);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_icon(prop, ICON_HIDE_ON, 1);
RNA_def_property_ui_text(
prop, "Show Irradiance Cache", "Display irradiance samples in the viewport");
@@ -6720,7 +6686,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "gi_show_cubemaps", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SHOW_CUBEMAPS);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_icon(prop, ICON_HIDE_ON, 1);
RNA_def_property_ui_text(
prop, "Show Cubemap Cache", "Display captured cubemaps in the viewport");
@@ -6730,7 +6695,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "gi_irradiance_display_size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "gi_irradiance_draw_size");
RNA_def_property_range(prop, 0.05f, 10.0f);
- RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_ui_text(prop,
"Irradiance Display Size",
"Size of the irradiance sample spheres to debug captured light");
@@ -6739,14 +6703,12 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "gi_cubemap_display_size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "gi_cubemap_draw_size");
RNA_def_property_range(prop, 0.05f, 10.0f);
- RNA_def_property_float_default(prop, 0.3f);
RNA_def_property_ui_text(
prop, "Cubemap Display Size", "Size of the cubemap spheres to debug captured light");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "gi_auto_bake", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_GI_AUTOBAKE);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "Auto Bake", "Auto bake indirect lighting when editing probes");
prop = RNA_def_property(srna, "gi_cache_info", PROP_STRING, PROP_NONE);
@@ -6756,14 +6718,12 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
/* Temporal Anti-Aliasing (super sampling) */
prop = RNA_def_property(srna, "taa_samples", PROP_INT, PROP_NONE);
- RNA_def_property_int_default(prop, 16);
RNA_def_property_ui_text(prop, "Viewport Samples", "Number of samples, unlimited if 0");
RNA_def_property_range(prop, 0, INT_MAX);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "taa_render_samples", PROP_INT, PROP_NONE);
- RNA_def_property_int_default(prop, 64);
RNA_def_property_ui_text(prop, "Render Samples", "Number of samples per pixels for rendering");
RNA_def_property_range(prop, 1, INT_MAX);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
@@ -6771,7 +6731,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_taa_reprojection", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_TAA_REPROJECTION);
- RNA_def_property_boolean_default(prop, 1);
RNA_def_property_ui_text(prop,
"Viewport Denoising",
"Denoise image using temporal reprojection "
@@ -6781,61 +6740,44 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
/* Screen Space Subsurface Scattering */
prop = RNA_def_property(srna, "sss_samples", PROP_INT, PROP_NONE);
- RNA_def_property_int_default(prop, 7);
RNA_def_property_ui_text(prop, "Samples", "Number of samples to compute the scattering effect");
RNA_def_property_range(prop, 1, 32);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "sss_jitter_threshold", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.3f);
RNA_def_property_ui_text(
prop, "Jitter Threshold", "Rotate samples that are below this threshold");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
- prop = RNA_def_property(srna, "use_sss_separate_albedo", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSS_SEPARATE_ALBEDO);
- RNA_def_property_boolean_default(prop, 0);
- RNA_def_property_ui_text(prop,
- "Separate Albedo",
- "Avoid albedo being blurred by the subsurface scattering "
- "but uses more video memory");
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
/* Screen Space Reflection */
prop = RNA_def_property(srna, "use_ssr", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSR_ENABLED);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "Screen Space Reflections", "Enable screen space reflection");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_ssr_refraction", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSR_REFRACTION);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "Screen Space Refractions", "Enable screen space Refractions");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_ssr_halfres", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSR_HALF_RESOLUTION);
- RNA_def_property_boolean_default(prop, 1);
RNA_def_property_ui_text(prop, "Half Res Trace", "Raytrace at a lower resolution");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "ssr_quality", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.25f);
RNA_def_property_ui_text(prop, "Trace Precision", "Precision of the screen space raytracing");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "ssr_max_roughness", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_ui_text(
prop, "Max Roughness", "Do not raytrace reflections for roughness above this value");
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -6843,7 +6785,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "ssr_thickness", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_ui_text(prop, "Thickness", "Pixel thickness used to detect intersection");
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 5, 3);
@@ -6851,14 +6792,12 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "ssr_border_fade", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.075f);
RNA_def_property_ui_text(prop, "Edge Fading", "Screen percentage used to fade the SSR");
RNA_def_property_range(prop, 0.0f, 0.5f);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "ssr_firefly_fac", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_default(prop, 10.0f);
RNA_def_property_ui_text(prop, "Clamp", "Clamp pixel intensity to remove noise (0 to disabled)");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
@@ -6866,7 +6805,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
/* Volumetrics */
prop = RNA_def_property(srna, "volumetric_start", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_ui_text(prop, "Start", "Start distance of the volumetric effect");
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
@@ -6874,7 +6812,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "volumetric_end", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_default(prop, 100.0f);
RNA_def_property_ui_text(prop, "End", "End distance of the volumetric effect");
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
@@ -6882,7 +6819,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "volumetric_tile_size", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_default(prop, 8);
RNA_def_property_enum_items(prop, eevee_volumetric_tile_size_items);
RNA_def_property_ui_text(prop,
"Tile Size",
@@ -6892,14 +6828,12 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "volumetric_samples", PROP_INT, PROP_NONE);
- RNA_def_property_int_default(prop, 64);
RNA_def_property_ui_text(prop, "Samples", "Number of samples to compute volumetric effects");
RNA_def_property_range(prop, 1, 256);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "volumetric_sample_distribution", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.8f);
RNA_def_property_ui_text(
prop, "Exponential Sampling", "Distribute more samples closer to the camera");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
@@ -6907,14 +6841,12 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_volumetric_lights", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_VOLUMETRIC_LIGHTS);
- RNA_def_property_boolean_default(prop, 1);
RNA_def_property_ui_text(
prop, "Volumetric Lighting", "Enable scene light interactions with volumetrics");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "volumetric_light_clamp", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_default(prop, 0.0f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_text(prop, "Clamp", "Maximum light contribution, reducing noise");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
@@ -6922,14 +6854,12 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_volumetric_shadows", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_VOLUMETRIC_SHADOWS);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(
prop, "Volumetric Shadows", "Generate shadows from volumetric material (Very expensive)");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "volumetric_shadow_samples", PROP_INT, PROP_NONE);
- RNA_def_property_int_default(prop, 16);
RNA_def_property_range(prop, 1, 128);
RNA_def_property_ui_text(
prop, "Volumetric Shadow Samples", "Number of samples to compute volumetric shadowing");
@@ -6939,7 +6869,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
/* Ambient Occlusion */
prop = RNA_def_property(srna, "use_gtao", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_GTAO_ENABLED);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop,
"Ambient Occlusion",
"Enable ambient occlusion to simulate medium scale indirect shadowing");
@@ -6948,7 +6877,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_gtao_bent_normals", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_GTAO_BENT_NORMALS);
- RNA_def_property_boolean_default(prop, 1);
RNA_def_property_ui_text(
prop, "Bent Normals", "Compute main non occluded direction to sample the environment");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
@@ -6956,7 +6884,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_gtao_bounce", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_GTAO_BOUNCE);
- RNA_def_property_boolean_default(prop, 1);
RNA_def_property_ui_text(prop,
"Bounces Approximation",
"An approximation to simulate light bounces "
@@ -6965,7 +6892,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "gtao_factor", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Factor", "Factor for ambient occlusion blending");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1f, 2);
@@ -6973,14 +6899,12 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "gtao_quality", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.25f);
RNA_def_property_ui_text(prop, "Trace Precision", "Precision of the horizon search");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "gtao_distance", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_ui_text(
prop, "Distance", "Distance of object that contribute to the ambient occlusion effect");
RNA_def_property_range(prop, 0.0f, 100000.0f);
@@ -6990,7 +6914,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
/* Depth of Field */
prop = RNA_def_property(srna, "bokeh_max_size", PROP_FLOAT, PROP_PIXEL);
- RNA_def_property_float_default(prop, 100.0f);
RNA_def_property_ui_text(
prop, "Max Size", "Max size of the bokeh shape for the depth of field (lower is faster)");
RNA_def_property_range(prop, 0.0f, 2000.0f);
@@ -6998,7 +6921,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
prop = RNA_def_property(srna, "bokeh_threshold", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(
prop, "Sprite Threshold", "Brightness threshold for using sprite base depth of field");
RNA_def_property_range(prop, 0.0f, 100000.0f);
@@ -7009,13 +6931,11 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
/* Bloom */
prop = RNA_def_property(srna, "use_bloom", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_BLOOM_ENABLED);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "Bloom", "High brightness pixels generate a glowing effect");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "bloom_threshold", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.8f);
RNA_def_property_ui_text(prop, "Threshold", "Filters out pixels under this level of brightness");
RNA_def_property_range(prop, 0.0f, 100000.0f);
RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
@@ -7023,21 +6943,18 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "bloom_color", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_float_array_default(prop, default_bloom_color);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Color", "Color applied to the bloom effect");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "bloom_knee", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_ui_text(prop, "Knee", "Makes transition between under/over-threshold gradual");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "bloom_radius", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 6.5f);
RNA_def_property_ui_text(prop, "Radius", "Bloom spread distance");
RNA_def_property_range(prop, 0.0f, 100.0f);
RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
@@ -7045,7 +6962,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "bloom_clamp", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.0f);
RNA_def_property_ui_text(
prop, "Clamp", "Maximum intensity a bloom pixel can have (0 to disabled)");
RNA_def_property_range(prop, 0.0f, 100000.0f);
@@ -7054,7 +6970,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "bloom_intensity", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 0.05f);
RNA_def_property_ui_text(prop, "Intensity", "Blend factor");
RNA_def_property_range(prop, 0.0f, 10000.0f);
RNA_def_property_ui_range(prop, 0.0f, 0.1f, 1, 3);
@@ -7064,20 +6979,17 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
/* Motion blur */
prop = RNA_def_property(srna, "use_motion_blur", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_MOTION_BLUR_ENABLED);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "Motion Blur", "Enable motion blur effect (only in camera view)");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "motion_blur_samples", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_default(prop, 8);
RNA_def_property_ui_text(prop, "Samples", "Number of samples to take with motion blur");
RNA_def_property_range(prop, 1, 64);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "motion_blur_shutter", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Shutter", "Time taken in frames between shutter open and close");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.01f, 1.0f, 1, 2);
@@ -7085,15 +6997,7 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
/* Shadows */
- prop = RNA_def_property(srna, "shadow_method", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_default(prop, SHADOW_ESM);
- RNA_def_property_enum_items(prop, eevee_shadow_method_items);
- RNA_def_property_ui_text(prop, "Method", "Technique use to compute the shadows");
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
prop = RNA_def_property(srna, "shadow_cube_size", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_default(prop, 512);
RNA_def_property_enum_items(prop, eevee_shadow_size_items);
RNA_def_property_ui_text(
prop, "Cube Shadows Resolution", "Size of point and area light shadow maps");
@@ -7101,7 +7005,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "shadow_cascade_size", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_default(prop, 1024);
RNA_def_property_enum_items(prop, eevee_shadow_size_items);
RNA_def_property_ui_text(
prop, "Directional Shadows Resolution", "Size of sun light shadow maps");
@@ -7110,21 +7013,18 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_shadow_high_bitdepth", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SHADOW_HIGH_BITDEPTH);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "High Bitdepth", "Use 32bit shadows");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_soft_shadows", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SHADOW_SOFT);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(
prop, "Soft Shadows", "Randomize shadowmaps origin to create soft shadows");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "light_threshold", PROP_FLOAT, PROP_UNSIGNED);
- RNA_def_property_float_default(prop, 0.01f);
RNA_def_property_ui_text(prop,
"Light Threshold",
"Minimum light intensity for a light to contribute to the lighting");
@@ -7136,7 +7036,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
/* Overscan */
prop = RNA_def_property(srna, "use_overscan", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_OVERSCAN);
- RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop,
"Overscan",
"Internally render past the image border to avoid "
@@ -7145,7 +7044,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
prop = RNA_def_property(srna, "overscan_size", PROP_FLOAT, PROP_PERCENTAGE);
RNA_def_property_float_sdna(prop, NULL, "overscan");
- RNA_def_property_float_default(prop, 3.0f);
RNA_def_property_ui_text(prop,
"Overscan Size",
"Percentage of render size to add as overscan to the "
@@ -7261,7 +7159,6 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "r.sfra");
RNA_def_property_int_funcs(prop, NULL, "rna_Scene_start_frame_set", NULL);
RNA_def_property_range(prop, MINFRAME, MAXFRAME);
- RNA_def_property_int_default(prop, 1);
RNA_def_property_ui_text(prop, "Start Frame", "First frame of the playback/rendering range");
RNA_def_property_update(prop, NC_SCENE | ND_FRAME_RANGE, NULL);
@@ -7270,7 +7167,6 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "r.efra");
RNA_def_property_int_funcs(prop, NULL, "rna_Scene_end_frame_set", NULL);
RNA_def_property_range(prop, MINFRAME, MAXFRAME);
- RNA_def_property_int_default(prop, 250);
RNA_def_property_ui_text(prop, "End Frame", "Final frame of the playback/rendering range");
RNA_def_property_update(prop, NC_SCENE | ND_FRAME_RANGE, NULL);
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index bea22d465a9..2b1b23a40f4 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -80,7 +80,7 @@ static void rna_Scene_frame_set(Scene *scene, Main *bmain, int frame, float subf
for (ViewLayer *view_layer = scene->view_layers.first; view_layer != NULL;
view_layer = view_layer->next) {
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
BKE_scene_graph_update_for_newframe(depsgraph, bmain);
}
@@ -156,7 +156,7 @@ static void rna_Scene_ray_cast(Scene *scene,
{
normalize_v3(direction);
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, depsgraph, 0);
bool ret = ED_transform_snap_object_project_ray_ex(sctx,
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 2e3f41d656b..1457bbfd3c3 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -162,24 +162,13 @@ const EnumPropertyItem rna_enum_symmetrize_direction_items[] = {
# include "DEG_depsgraph.h"
+# include "ED_gpencil.h"
# include "ED_particle.h"
static void rna_GPencil_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
/* mark all grease pencil datablocks of the scene */
- FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, ob) {
- if (ob->type == OB_GPENCIL) {
- bGPdata *gpd = (bGPdata *)ob->data;
- gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- }
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- }
- FOREACH_SCENE_COLLECTION_END;
-
- WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
+ ED_gpencil_tag_scene_gpencil(scene);
}
const EnumPropertyItem rna_enum_particle_edit_disconnected_hair_brush_items[] = {
@@ -215,10 +204,11 @@ static PointerRNA rna_ParticleBrush_curve_get(PointerRNA *ptr)
static void rna_ParticleEdit_redo(bContext *C, PointerRNA *UNUSED(ptr))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (!edit) {
return;
@@ -270,8 +260,9 @@ static const EnumPropertyItem *rna_ParticleEdit_tool_itemf(bContext *C,
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
# if 0
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys = edit ? edit->psys : NULL;
# else
/* use this rather than PE_get_current() - because the editing cache is
@@ -296,14 +287,14 @@ static bool rna_ParticleEdit_editable_get(PointerRNA *ptr)
{
ParticleEditSettings *pset = (ParticleEditSettings *)ptr->data;
- return (pset->object && pset->scene && PE_get_current(pset->scene, pset->object));
+ return (pset->object && pset->scene && PE_get_current(NULL, pset->scene, pset->object));
}
static bool rna_ParticleEdit_hair_get(PointerRNA *ptr)
{
ParticleEditSettings *pset = (ParticleEditSettings *)ptr->data;
if (pset->scene) {
- PTCacheEdit *edit = PE_get_current(pset->scene, pset->object);
+ PTCacheEdit *edit = PE_get_current(NULL, pset->scene, pset->object);
return (edit && edit->psys);
}
@@ -657,7 +648,7 @@ static void rna_def_paint(BlenderRNA *brna)
prop = RNA_def_property(srna, "input_samples", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "num_input_samples");
- RNA_def_property_ui_range(prop, 1, PAINT_MAX_INPUT_SAMPLES, 0, -1);
+ RNA_def_property_ui_range(prop, 1, PAINT_MAX_INPUT_SAMPLES, 1, -1);
RNA_def_property_ui_text(
prop, "Input Samples", "Average multiple input samples together to smooth the brush stroke");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
@@ -1032,7 +1023,7 @@ static void rna_def_image_paint(BlenderRNA *brna)
/* integers */
prop = RNA_def_property(srna, "seam_bleed", PROP_INT, PROP_PIXEL);
- RNA_def_property_ui_range(prop, 0, 8, 0, -1);
+ RNA_def_property_ui_range(prop, 0, 8, 1, -1);
RNA_def_property_ui_text(
prop, "Bleed", "Extend paint beyond the faces UVs to reduce seams (in pixels, slower)");
@@ -1047,11 +1038,12 @@ static void rna_def_image_paint(BlenderRNA *brna)
NULL,
0,
0,
- "screen_grab_size",
+ "Screen Grab Size",
"Size to capture the image for re-projecting",
0,
0);
RNA_def_property_range(prop, 512, 16384);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
@@ -1299,6 +1291,7 @@ static void rna_def_gpencil_guides(BlenderRNA *brna)
{GP_GUIDE_RADIAL, "RADIAL", 0, "Radial", "Use single point as direction"},
{GP_GUIDE_PARALLEL, "PARALLEL", 0, "Parallel", "Parallel lines"},
{GP_GUIDE_GRID, "GRID", 0, "Grid", "Grid allows horizontal and vertical lines"},
+ {GP_GUIDE_ISO, "ISO", 0, "Isometric", "Grid allows isometric and vertical lines"},
{0, NULL, 0, NULL, NULL},
};
@@ -1360,7 +1353,6 @@ static void rna_def_gpencil_guides(BlenderRNA *brna)
prop = RNA_def_property(srna, "spacing", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "spacing");
- RNA_def_property_float_default(prop, 0.01f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, 3);
RNA_def_property_ui_text(prop, "Spacing", "Guide spacing");
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 883468fa88e..dc0cc0482aa 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -1740,7 +1740,7 @@ static void rna_def_sequence(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3);
RNA_def_property_float_sdna(prop, NULL, "effect_fader");
- RNA_def_property_ui_text(prop, "Effect fader position", "Custom fade value");
+ RNA_def_property_ui_text(prop, "Effect Fader Position", "Custom fade value");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
@@ -1758,7 +1758,7 @@ static void rna_def_sequence(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "speed_fader");
RNA_def_property_ui_text(
prop,
- "Speed factor",
+ "Speed Factor",
"Multiply the current speed of the sequence with this number or remap current frame "
"to this frame");
RNA_def_property_update(
@@ -1932,12 +1932,19 @@ static void rna_def_editor(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_STORE_FINAL_OUT);
RNA_def_property_ui_text(prop, "Cache Final", "Cache final image for each frame");
+ prop = RNA_def_property(srna, "use_prefetch", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_PREFETCH_ENABLE);
+ RNA_def_property_ui_text(prop,
+ "Prefetch frames",
+ "Render frames ahead of playhead in background for faster playback");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
+
prop = RNA_def_property(srna, "recycle_max_cost", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0f, SEQ_CACHE_COST_MAX);
RNA_def_property_ui_range(prop, 0.0f, SEQ_CACHE_COST_MAX, 0.1f, 1);
RNA_def_property_float_sdna(prop, NULL, "recycle_max_cost");
RNA_def_property_ui_text(
- prop, "Recycle Up To Cost", "Only frames with cost lower than this value will be recycled");
+ prop, "Recycle Up to Cost", "Only frames with cost lower than this value will be recycled");
}
static void rna_def_filter_video(StructRNA *srna)
@@ -1958,12 +1965,6 @@ static void rna_def_filter_video(StructRNA *srna)
{0, NULL, 0, NULL, NULL},
};
- static const EnumPropertyItem playback_direction_items[] = {
- {0, "FORWARD", 0, "Forwards", "Play strip forwards"},
- {SEQ_REVERSE_FRAMES, "BACKWARD", 0, "Backwards", "Play strip backwards"},
- {0, NULL, 0, NULL, NULL},
- };
-
prop = RNA_def_property(srna, "use_deinterlace", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_FILTERY);
RNA_def_property_ui_text(prop, "Deinterlace", "Remove fields from video movies");
@@ -1990,10 +1991,9 @@ static void rna_def_filter_video(StructRNA *srna)
RNA_def_property_ui_text(prop, "Convert Float", "Convert input to float data");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
- prop = RNA_def_property(srna, "playback_direction", PROP_ENUM, PROP_NONE); /* as an enum */
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
- RNA_def_property_enum_items(prop, playback_direction_items);
- RNA_def_property_ui_text(prop, "Playback Direction", "Play strip forwards or backwards");
+ prop = RNA_def_property(srna, "use_reverse_frames", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_REVERSE_FRAMES);
+ RNA_def_property_ui_text(prop, "Reverse Frames", "Reverse frame order");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
prop = RNA_def_property(srna, "color_multiply", PROP_FLOAT, PROP_UNSIGNED);
@@ -2639,8 +2639,7 @@ static void rna_def_solid_color(StructRNA *srna)
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "col");
RNA_def_property_ui_text(prop, "Color", "Effect Strip color");
- RNA_def_property_update(
- prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
}
static void rna_def_speed_control(StructRNA *srna)
@@ -2661,14 +2660,14 @@ static void rna_def_speed_control(StructRNA *srna)
prop = RNA_def_property(srna, "use_as_speed", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_INTEGRATE);
RNA_def_property_ui_text(
- prop, "Use as speed", "Interpret the value as speed instead of a frame number");
+ prop, "Use as Speed", "Interpret the value as speed instead of a frame number");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
prop = RNA_def_property(srna, "use_scale_to_length", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_COMPRESS_IPO_Y);
RNA_def_property_ui_text(
- prop, "Scale to length", "Scale values from 0.0 to 1.0 to target sequence length");
+ prop, "Scale to Length", "Scale values from 0.0 to 1.0 to target sequence length");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
}
@@ -2758,14 +2757,16 @@ static void rna_def_text(StructRNA *srna)
prop = RNA_def_property(srna, "align_x", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "align");
RNA_def_property_enum_items(prop, text_align_x_items);
- RNA_def_property_ui_text(prop, "Align X", "Align the text along the X axis");
+ RNA_def_property_ui_text(
+ prop, "Align X", "Align the text along the X axis, relative to the text midpoint");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
prop = RNA_def_property(srna, "align_y", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "align_y");
RNA_def_property_enum_items(prop, text_align_y_items);
- RNA_def_property_ui_text(prop, "Align Y", "Align the image along the Y axis");
+ RNA_def_property_ui_text(
+ prop, "Align Y", "Align the image along the Y axis, relative to the text midpoint");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
@@ -3013,7 +3014,7 @@ static void rna_def_whitebalance_modifier(BlenderRNA *brna)
prop = RNA_def_property(srna, "white_value", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "white_value");
- RNA_def_property_ui_text(prop, "White value", "This color defines white in the strip");
+ RNA_def_property_ui_text(prop, "White Value", "This color defines white in the strip");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
}
diff --git a/source/blender/makesrna/intern/rna_shader_fx.c b/source/blender/makesrna/intern/rna_shader_fx.c
index acf525e1788..cd4e027ce7c 100644
--- a/source/blender/makesrna/intern/rna_shader_fx.c
+++ b/source/blender/makesrna/intern/rna_shader_fx.c
@@ -260,14 +260,14 @@ static void rna_def_shader_fx_colorize(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "low_color");
RNA_def_property_array(prop, 4);
- RNA_def_property_ui_text(prop, "Low color", "First color used for effect");
+ RNA_def_property_ui_text(prop, "Low Color", "First color used for effect");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "high_color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "high_color");
RNA_def_property_array(prop, 4);
- RNA_def_property_ui_text(prop, "Height color", "Second color used for effect");
+ RNA_def_property_ui_text(prop, "High Color", "Second color used for effect");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
index fa0297ac306..c00cc789eff 100644
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ b/source/blender/makesrna/intern/rna_smoke.c
@@ -588,7 +588,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_high_resolution", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_HIGHRES);
- RNA_def_property_ui_text(prop, "High res", "Enable high resolution (using amplification)");
+ RNA_def_property_ui_text(prop, "High Res", "Enable high resolution (using amplification)");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
@@ -668,7 +668,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_dissolve_smoke_log", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_DISSOLVE_LOG);
- RNA_def_property_ui_text(prop, "Logarithmic dissolve", "Using 1/x ");
+ RNA_def_property_ui_text(prop, "Logarithmic Dissolve", "Using 1/x ");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
@@ -1204,7 +1204,7 @@ static void rna_def_smoke_coll_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "collision_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, smoke_coll_type_items);
- RNA_def_property_ui_text(prop, "Collision type", "Collision type");
+ RNA_def_property_ui_text(prop, "Collision Type", "Collision type");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
}
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 8c855c9e870..56ba6403596 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -343,7 +343,11 @@ static const EnumPropertyItem autosnap_items[] = {
const EnumPropertyItem rna_enum_shading_type_items[] = {
{OB_WIRE, "WIREFRAME", ICON_SHADING_WIRE, "Wireframe", "Display the object as wire edges"},
{OB_SOLID, "SOLID", ICON_SHADING_SOLID, "Solid", "Display in solid mode"},
- {OB_MATERIAL, "MATERIAL", ICON_SHADING_TEXTURE, "Look Dev", "Display in Look Dev mode"},
+ {OB_MATERIAL,
+ "MATERIAL",
+ ICON_SHADING_TEXTURE,
+ "Material Preview",
+ "Display in Material Preview mode"},
{OB_RENDER, "RENDERED", ICON_SHADING_RENDERED, "Rendered", "Display render preview"},
{0, NULL, 0, NULL, NULL},
};
@@ -380,26 +384,30 @@ const EnumPropertyItem rna_enum_clip_editor_mode_items[] = {
* but helps for context-less access (e.g. doc, i18n...). */
static const EnumPropertyItem buttons_context_items[] = {
{BCONTEXT_TOOL, "TOOL", ICON_TOOL_SETTINGS, "Tool", "Active Tool and Workspace settings"},
- {BCONTEXT_SCENE, "SCENE", ICON_SCENE_DATA, "Scene", "Scene"},
- {BCONTEXT_RENDER, "RENDER", ICON_SCENE, "Render", "Render"},
- {BCONTEXT_OUTPUT, "OUTPUT", ICON_OUTPUT, "Output", "Output"},
- {BCONTEXT_VIEW_LAYER, "VIEW_LAYER", ICON_RENDER_RESULT, "View Layer", "View Layer"},
- {BCONTEXT_WORLD, "WORLD", ICON_WORLD, "World", "World"},
- {BCONTEXT_OBJECT, "OBJECT", ICON_OBJECT_DATA, "Object", "Object"},
- {BCONTEXT_CONSTRAINT, "CONSTRAINT", ICON_CONSTRAINT, "Constraints", "Object Constraints"},
- {BCONTEXT_MODIFIER, "MODIFIER", ICON_MODIFIER, "Modifiers", "Modifiers"},
- {BCONTEXT_DATA, "DATA", ICON_NONE, "Data", "Object Data"},
- {BCONTEXT_BONE, "BONE", ICON_BONE_DATA, "Bone", "Bone"},
+ {BCONTEXT_SCENE, "SCENE", ICON_SCENE_DATA, "Scene", "Scene Properties"},
+ {BCONTEXT_RENDER, "RENDER", ICON_SCENE, "Render", "Render Properties"},
+ {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_OBJECT, "OBJECT", ICON_OBJECT_DATA, "Object", "Object Properties"},
+ {BCONTEXT_CONSTRAINT,
+ "CONSTRAINT",
+ ICON_CONSTRAINT,
+ "Constraints",
+ "Object Constraint Properties"},
+ {BCONTEXT_MODIFIER, "MODIFIER", ICON_MODIFIER, "Modifiers", "Modifier Properties"},
+ {BCONTEXT_DATA, "DATA", ICON_NONE, "Data", "Object Data Properties"},
+ {BCONTEXT_BONE, "BONE", ICON_BONE_DATA, "Bone", "Bone Properties"},
{BCONTEXT_BONE_CONSTRAINT,
"BONE_CONSTRAINT",
ICON_CONSTRAINT_BONE,
"Bone Constraints",
- "Bone Constraints"},
- {BCONTEXT_MATERIAL, "MATERIAL", ICON_MATERIAL, "Material", "Material"},
- {BCONTEXT_TEXTURE, "TEXTURE", ICON_TEXTURE, "Texture", "Texture"},
- {BCONTEXT_PARTICLE, "PARTICLES", ICON_PARTICLES, "Particles", "Particles"},
- {BCONTEXT_PHYSICS, "PHYSICS", ICON_PHYSICS, "Physics", "Physics"},
- {BCONTEXT_SHADERFX, "SHADERFX", ICON_SHADERFX, "Effects", "Object visual effects"},
+ "Bone Constraint Properties"},
+ {BCONTEXT_MATERIAL, "MATERIAL", ICON_MATERIAL, "Material", "Material Properties"},
+ {BCONTEXT_TEXTURE, "TEXTURE", ICON_TEXTURE, "Texture", "Texture Properties"},
+ {BCONTEXT_PARTICLE, "PARTICLES", ICON_PARTICLES, "Particles", "Particle Properties"},
+ {BCONTEXT_PHYSICS, "PHYSICS", ICON_PHYSICS, "Physics", "Physics Properties"},
+ {BCONTEXT_SHADERFX, "SHADERFX", ICON_SHADERFX, "Effects", "Visual Effects Properties"},
{0, NULL, 0, NULL, NULL},
};
@@ -420,19 +428,19 @@ const EnumPropertyItem rna_enum_file_sort_items[] = {
{FILE_SORT_ALPHA,
"FILE_SORT_ALPHA",
ICON_SORTALPHA,
- "Sort alphabetically",
+ "Name",
"Sort the file list alphabetically"},
{FILE_SORT_EXTENSION,
"FILE_SORT_EXTENSION",
ICON_SORTBYEXT,
- "Sort by extension",
+ "Extension",
"Sort the file list by extension/type"},
{FILE_SORT_TIME,
"FILE_SORT_TIME",
ICON_SORTTIME,
- "Sort by time",
+ "Modified Date",
"Sort files by modification time"},
- {FILE_SORT_SIZE, "FILE_SORT_SIZE", ICON_SORTSIZE, "Sort by size", "Sort files by size"},
+ {FILE_SORT_SIZE, "FILE_SORT_SIZE", ICON_SORTSIZE, "Size", "Sort files by size"},
{0, NULL, 0, NULL, NULL},
};
@@ -450,6 +458,7 @@ const EnumPropertyItem rna_enum_file_sort_items[] = {
# include "BKE_brush.h"
# include "BKE_colortools.h"
# include "BKE_context.h"
+# include "BKE_idprop.h"
# include "BKE_layer.h"
# include "BKE_global.h"
# include "BKE_nla.h"
@@ -930,6 +939,18 @@ static bool rna_RegionView3D_is_orthographic_side_view_get(PointerRNA *ptr)
return RV3D_VIEW_IS_AXIS(rv3d->view);
}
+static IDProperty *rna_View3DShading_idprops(PointerRNA *ptr, bool create)
+{
+ View3DShading *shading = ptr->data;
+
+ if (create && !shading->prop) {
+ IDPropertyTemplate val = {0};
+ shading->prop = IDP_New(IDP_GROUP, &val, "View3DShading ID properties");
+ }
+
+ return shading->prop;
+}
+
static void rna_3DViewShading_type_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
ID *id = ptr->owner_id;
@@ -1054,6 +1075,7 @@ static PointerRNA rna_View3DShading_selected_studio_light_get(PointerRNA *ptr)
sl = BKE_studiolight_find(shading->studio_light, STUDIOLIGHT_FLAG_ALL);
}
else {
+ /* OB_MATERIAL and OB_RENDER */
sl = BKE_studiolight_find(shading->lookdev_light, STUDIOLIGHT_FLAG_ALL);
}
return rna_pointer_inherit_refine(ptr, &RNA_StudioLight, sl);
@@ -1088,21 +1110,32 @@ static const EnumPropertyItem *rna_View3DShading_color_type_itemf(bContext *UNUS
}
}
-/* Studio light */
-static int rna_View3DShading_studio_light_get(PointerRNA *ptr)
+static void rna_View3DShading_studio_light_get_storage(View3DShading *shading,
+ char **dna_storage,
+ int *flag)
{
- View3DShading *shading = (View3DShading *)ptr->data;
- char *dna_storage = shading->studio_light;
+ *dna_storage = shading->studio_light;
- int flag = STUDIOLIGHT_TYPE_STUDIO;
- if (shading->type == OB_SOLID && shading->light == V3D_LIGHTING_MATCAP) {
- flag = STUDIOLIGHT_TYPE_MATCAP;
- dna_storage = shading->matcap;
+ *flag = STUDIOLIGHT_TYPE_STUDIO;
+ if (shading->type == OB_SOLID) {
+ if (shading->light == V3D_LIGHTING_MATCAP) {
+ *flag = STUDIOLIGHT_TYPE_MATCAP;
+ *dna_storage = shading->matcap;
+ }
}
- else if (shading->type == OB_MATERIAL) {
- flag = STUDIOLIGHT_TYPE_WORLD;
- dna_storage = shading->lookdev_light;
+ else {
+ *flag = STUDIOLIGHT_TYPE_WORLD;
+ *dna_storage = shading->lookdev_light;
}
+}
+
+static int rna_View3DShading_studio_light_get(PointerRNA *ptr)
+{
+ View3DShading *shading = (View3DShading *)ptr->data;
+ char *dna_storage;
+ int flag;
+
+ rna_View3DShading_studio_light_get_storage(shading, &dna_storage, &flag);
StudioLight *sl = BKE_studiolight_find(dna_storage, flag);
if (sl) {
BLI_strncpy(dna_storage, sl->name, FILE_MAXFILE);
@@ -1116,17 +1149,10 @@ static int rna_View3DShading_studio_light_get(PointerRNA *ptr)
static void rna_View3DShading_studio_light_set(PointerRNA *ptr, int value)
{
View3DShading *shading = (View3DShading *)ptr->data;
- char *dna_storage = shading->studio_light;
+ char *dna_storage;
+ int flag;
- int flag = STUDIOLIGHT_TYPE_STUDIO;
- if (shading->type == OB_SOLID && shading->light == V3D_LIGHTING_MATCAP) {
- flag = STUDIOLIGHT_TYPE_MATCAP;
- dna_storage = shading->matcap;
- }
- else if (shading->type == OB_MATERIAL) {
- flag = STUDIOLIGHT_TYPE_WORLD;
- dna_storage = shading->lookdev_light;
- }
+ rna_View3DShading_studio_light_get_storage(shading, &dna_storage, &flag);
StudioLight *sl = BKE_studiolight_findindex(value, flag);
if (sl) {
BLI_strncpy(dna_storage, sl->name, FILE_MAXFILE);
@@ -1173,6 +1199,7 @@ static const EnumPropertyItem *rna_View3DShading_studio_light_itemf(bContext *UN
break;
case OB_MATERIAL:
+ case OB_RENDER:
show_studiolight = ((sl->flag & STUDIOLIGHT_TYPE_WORLD) != 0);
icon_id = sl->icon_id_radiance;
break;
@@ -1191,6 +1218,19 @@ static const EnumPropertyItem *rna_View3DShading_studio_light_itemf(bContext *UN
return item;
}
+static void rna_SpaceView3D_use_local_collections_update(bContext *C, PointerRNA *ptr)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = (View3D *)ptr->data;
+
+ if (ED_view3d_local_collections_set(bmain, v3d)) {
+ BKE_layer_collection_local_sync(view_layer, v3d);
+ DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
+ }
+}
+
static const EnumPropertyItem *rna_SpaceView3D_stereo3d_camera_itemf(bContext *C,
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
@@ -2142,6 +2182,18 @@ static void rna_SpaceClipEditor_view_type_update(Main *UNUSED(bmain),
/* File browser. */
+int rna_FileSelectParams_filename_editable(struct PointerRNA *ptr, const char **r_info)
+{
+ FileSelectParams *params = ptr->data;
+
+ if (params && (params->flag & FILE_DIRSEL_ONLY)) {
+ *r_info = "Only directories can be chosen for the current operation.";
+ return 0;
+ }
+
+ return params ? PROP_EDITABLE : 0;
+}
+
static bool rna_FileSelectParams_use_lib_get(PointerRNA *ptr)
{
FileSelectParams *params = ptr->data;
@@ -2711,11 +2763,6 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Display Faces", "Display faces over the image");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
- prop = RNA_def_property(srna, "show_edges", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SI_NO_DRAWEDGES);
- RNA_def_property_ui_text(prop, "Display Edges", "Display edges in vertex select mode");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
-
/* todo: move edge and face drawing options here from G.f */
prop = RNA_def_property(srna, "pixel_snap_mode", PROP_ENUM, PROP_NONE);
@@ -2929,7 +2976,7 @@ static void rna_def_space_outliner(BlenderRNA *brna)
/* Libraries filter. */
prop = RNA_def_property(srna, "use_filter_id_type", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filter", SO_FILTER_ID_TYPE);
- RNA_def_property_ui_text(prop, "Filter By Type", "Show only data-blocks of one type");
+ RNA_def_property_ui_text(prop, "Filter by Type", "Show only data-blocks of one type");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
prop = RNA_def_property(srna, "filter_id_type", PROP_ENUM, PROP_NONE);
@@ -2954,7 +3001,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
"Use a custom color limited to this viewport only"},
{0, NULL, 0, NULL, NULL},
};
- static const float default_background_color[] = {0.05f, 0.05f, 0.05f};
static const EnumPropertyItem cavity_type_items[] = {
{V3D_SHADING_CAVITY_SSAO,
@@ -2977,6 +3023,7 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
RNA_def_struct_path_func(srna, "rna_View3DShading_path");
RNA_def_struct_ui_text(
srna, "3D View Shading Settings", "Settings for shading in the 3D viewport");
+ RNA_def_struct_idprops_func(srna, "rna_View3DShading_idprops");
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_shading_type_items);
@@ -3036,7 +3083,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "curvature_ridge_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "curvature_ridge_factor");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Curvature Ridge", "Factor for the curvature ridges");
RNA_def_property_range(prop, 0.0f, 2.0f);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -3044,7 +3090,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "curvature_valley_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "curvature_valley_factor");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Curvature Valley", "Factor for the curvature valleys");
RNA_def_property_range(prop, 0.0f, 2.0f);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -3052,7 +3097,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "cavity_ridge_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "cavity_ridge_factor");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Cavity Ridge", "Factor for the cavity ridges");
RNA_def_property_range(prop, 0.0f, 250.0f);
RNA_def_property_ui_range(prop, 0.00f, 2.5f, 1, 3);
@@ -3061,7 +3105,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "cavity_valley_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "cavity_valley_factor");
- RNA_def_property_float_default(prop, 1.0);
RNA_def_property_ui_text(prop, "Cavity Valley", "Factor for the cavity valleys");
RNA_def_property_range(prop, 0.0f, 250.0f);
RNA_def_property_ui_range(prop, 0.00f, 2.5f, 1, 3);
@@ -3079,13 +3122,28 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "studiolight_rotate_z", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "studiolight_rot_z");
- RNA_def_property_float_default(prop, 0.0);
RNA_def_property_ui_text(
prop, "Studiolight Rotation", "Rotation of the studiolight around the Z-Axis");
RNA_def_property_range(prop, -M_PI, M_PI);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ prop = RNA_def_property(srna, "studiolight_intensity", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "studiolight_intensity");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Strength", "Strength of the studiolight");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 2.0f, 1, 3);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "studiolight_background_alpha", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "studiolight_background");
+ RNA_def_property_ui_text(prop, "Background", "Show the studiolight in the background");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0.00f, 1.0f, 1, 3);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
prop = RNA_def_property(srna, "color_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "color_type");
RNA_def_property_enum_items(prop, rna_enum_shading_color_type_items);
@@ -3115,7 +3173,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "background_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_array(prop, 3);
- RNA_def_property_float_array_default(prop, default_background_color);
RNA_def_property_ui_text(prop, "Background Color", "Color for custom background color");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -3140,7 +3197,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "xray_alpha", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "xray_alpha");
- RNA_def_property_float_default(prop, 0.5);
RNA_def_property_ui_text(prop, "X-Ray Alpha", "Amount of alpha to use");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -3148,7 +3204,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "xray_alpha_wireframe", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "xray_alpha_wire");
- RNA_def_property_float_default(prop, 0.5);
RNA_def_property_ui_text(prop, "X-Ray Alpha", "Amount of alpha to use");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -3165,12 +3220,26 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_scene_lights", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SCENE_LIGHTS);
+ RNA_def_property_boolean_default(prop, false);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Scene Lights", "Render lights and light probes of the scene");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "use_scene_world", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SCENE_WORLD);
+ RNA_def_property_boolean_default(prop, false);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Scene World", "Use scene world for lighting");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "use_scene_lights_render", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SCENE_LIGHTS_RENDER);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Scene Lights", "Render lights and light probes of the scene");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "use_scene_world_render", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SCENE_WORLD_RENDER);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Scene World", "Use scene world for lighting");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -3190,21 +3259,11 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "shadow_intensity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "shadow_intensity");
- RNA_def_property_float_default(prop, 0.5);
RNA_def_property_ui_text(prop, "Shadow Intensity", "Darkness of shadows");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_range(prop, 0.00f, 1.0f, 1, 3);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "studiolight_background_alpha", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "studiolight_background");
- RNA_def_property_float_default(prop, 0.0);
- RNA_def_property_ui_text(prop, "Background", "Show the studiolight in the background");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_range(prop, 0.00f, 1.0f, 1, 3);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
}
static void rna_def_space_view3d_overlay(BlenderRNA *brna)
@@ -3254,7 +3313,6 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Grid Scale", "Distance between 3D View grid lines");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, 1000.0f, 0.1f, 3);
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "grid_lines", PROP_INT, PROP_NONE);
@@ -3262,14 +3320,12 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Grid Lines", "Number of grid lines to display in perspective view");
RNA_def_property_range(prop, 0, 1024);
- RNA_def_property_int_default(prop, 16);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "grid_subdivisions", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "gridsubdiv");
RNA_def_property_ui_text(prop, "Grid Subdivisions", "Number of subdivisions between grid lines");
RNA_def_property_range(prop, 1, 1024);
- RNA_def_property_int_default(prop, 10);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "grid_scale_unit", PROP_FLOAT, PROP_NONE);
@@ -3342,7 +3398,6 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "xray_alpha_bone", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "overlay.xray_alpha_bone");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_ui_text(prop, "Opacity", "Opacity to use for bone selection");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -3364,7 +3419,7 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_look_dev", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_LOOK_DEV);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Look Dev Preview", "Show look development spheres and palette");
+ RNA_def_property_ui_text(prop, "Look Dev Preview", "Show look development spheres");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "show_wireframes", PROP_BOOLEAN, PROP_NONE);
@@ -3375,7 +3430,6 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "wireframe_threshold", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "overlay.wireframe_threshold");
- RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_ui_text(
prop, "Wireframe Threshold", "Adjust the number of wires displayed (1 for all wires)");
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -3542,7 +3596,6 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "texture_paint_mode_opacity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "overlay.texture_paint_mode_opacity");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(
prop, "Stencil Opacity", "Opacity of the texture paint mode stencil mask overlay");
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -3550,7 +3603,6 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "vertex_paint_mode_opacity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "overlay.vertex_paint_mode_opacity");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(
prop, "Vertex Paint Opacity", "Opacity of the vertex paint mode overlay");
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -3558,7 +3610,6 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "weight_paint_mode_opacity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "overlay.weight_paint_mode_opacity");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(
prop, "Weight Paint Opacity", "Opacity of the weight paint mode overlay");
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -3566,7 +3617,6 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "sculpt_mode_mask_opacity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "overlay.sculpt_mode_mask_opacity");
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Sculpt Mask Opacity", "");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -3579,10 +3629,10 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_gpencil_paper", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_PAPER);
- RNA_def_property_ui_text(prop,
- "Use Paper",
- "Cover all viewport with a full color layer to improve visibility "
- "while drawing over complex scenes");
+ RNA_def_property_ui_text(
+ prop,
+ "Fade Objects",
+ "Fade all viewport objects with a full color layer to improve visibility");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "use_gpencil_grid", PROP_BOOLEAN, PROP_NONE);
@@ -3596,10 +3646,15 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop, "Fade Layers", "Toggle fading of Grease Pencil layers except the active one");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+ prop = RNA_def_property(srna, "use_gpencil_fade_objects", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_FADE_NOACTIVE_GPENCIL);
+ RNA_def_property_ui_text(
+ prop, "Fade Grease Pencil Objects", "Fade Grease Pencil Objects, except the active one");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+
prop = RNA_def_property(srna, "gpencil_grid_opacity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "overlay.gpencil_grid_opacity");
RNA_def_property_range(prop, 0.1f, 1.0f);
- RNA_def_property_float_default(prop, 0.9f);
RNA_def_property_ui_text(prop, "Opacity", "Canvas grid opacity");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -3607,8 +3662,7 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "gpencil_paper_opacity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "overlay.gpencil_paper_opacity");
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_float_default(prop, 0.5f);
- RNA_def_property_ui_text(prop, "Opacity", "Paper opacity");
+ RNA_def_property_ui_text(prop, "Opacity", "Fade factor");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
/* Paper opacity factor */
@@ -3756,7 +3810,6 @@ static void rna_def_space_view3d(BlenderRNA *brna)
prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
- RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_ui_text(
prop, "Clip Start", "3D View near clipping distance (perspective view only)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -3764,7 +3817,6 @@ static void rna_def_space_view3d(BlenderRNA *brna)
prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
- RNA_def_property_float_default(prop, 1000.0f);
RNA_def_property_ui_text(prop, "Clip End", "3D View far clipping distance");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -3912,6 +3964,14 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "FX Options", "Options used for real time compositing");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ prop = RNA_def_property(srna, "use_local_collections", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_LOCAL_COLLECTIONS);
+ RNA_def_property_ui_text(
+ prop, "Local Collections", "Display a different set of collections in this viewport");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(
+ prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_use_local_collections_update");
+
/* Stereo Settings */
prop = RNA_def_property(srna, "stereo_3d_eye", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "multiview_eye");
@@ -4153,7 +4213,7 @@ static void rna_def_space_buttons(BlenderRNA *brna)
RNA_def_property_enum_items(prop, buttons_context_items);
RNA_def_property_enum_funcs(
prop, NULL, "rna_SpaceProperties_context_set", "rna_SpaceProperties_context_itemf");
- RNA_def_property_ui_text(prop, "Context", "");
+ RNA_def_property_ui_text(prop, "", "");
RNA_def_property_update(
prop, NC_SPACE | ND_SPACE_PROPERTIES, "rna_SpaceProperties_context_update");
@@ -4222,7 +4282,7 @@ static void rna_def_space_image(BlenderRNA *brna)
prop = RNA_def_property(srna, "sample_histogram", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "sample_line_hist");
RNA_def_property_struct_type(prop, "Histogram");
- RNA_def_property_ui_text(prop, "Line sample", "Sampled colors along line");
+ RNA_def_property_ui_text(prop, "Line Sample", "Sampled colors along line");
prop = RNA_def_property(srna, "zoom", PROP_FLOAT, PROP_NONE);
RNA_def_property_array(prop, 2);
@@ -4659,7 +4719,7 @@ static void rna_def_space_text(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_match_case", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", ST_MATCH_CASE);
RNA_def_property_ui_text(
- prop, "Match case", "Search string is sensitive to uppercase and lowercase letters");
+ prop, "Match Case", "Search string is sensitive to uppercase and lowercase letters");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL);
prop = RNA_def_property(srna, "find_text", PROP_STRING, PROP_NONE);
@@ -5138,25 +5198,25 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
PropertyRNA *prop;
static const EnumPropertyItem file_display_items[] = {
- {FILE_SHORTDISPLAY,
- "LIST_SHORT",
- ICON_SHORTDISPLAY,
- "Short List",
- "Display files as short list"},
- {FILE_LONGDISPLAY,
- "LIST_LONG",
+ {FILE_VERTICALDISPLAY,
+ "LIST_VERTICAL",
ICON_LONGDISPLAY,
- "Long List",
- "Display files as a detailed list"},
+ "Vertical List",
+ "Display files as a vertical list"},
+ {FILE_HORIZONTALDISPLAY,
+ "LIST_HORIZONTAL",
+ ICON_SHORTDISPLAY,
+ "Horizontal List",
+ "Display files as a horizontal list"},
{FILE_IMGDISPLAY, "THUMBNAIL", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem display_size_items[] = {
- {32, "TINY", 0, "Tiny", ""},
- {64, "SMALL", 0, "Small", ""},
+ {64, "TINY", 0, "Tiny", ""},
+ {96, "SMALL", 0, "Small", ""},
{128, "NORMAL", 0, "Regular", ""},
- {256, "LARGE", 0, "Large", ""},
+ {192, "LARGE", 0, "Large", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -5272,7 +5332,10 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Title", "Title for the file browser");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- prop = RNA_def_property(srna, "directory", PROP_STRING, PROP_DIRPATH);
+ /* Use BYTESTRING rather than DIRPATH as subtype so UI code doesn't add OT_directory_browse
+ * button when displaying this prop in the file browser (it would just open a file browser). That
+ * should be the only effective difference between the two. */
+ prop = RNA_def_property(srna, "directory", PROP_STRING, PROP_BYTESTRING);
RNA_def_property_string_sdna(prop, NULL, "dir");
RNA_def_property_ui_text(prop, "Directory", "Directory displayed in the file browser");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
@@ -5280,6 +5343,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
prop = RNA_def_property(srna, "filename", PROP_STRING, PROP_FILENAME);
RNA_def_property_string_sdna(prop, NULL, "file");
RNA_def_property_ui_text(prop, "File Name", "Active file in the file browser");
+ RNA_def_property_editable_func(prop, "rna_FileSelectParams_filename_editable");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
prop = RNA_def_property(srna, "use_library_browsing", PROP_BOOLEAN, PROP_NONE);
@@ -5300,6 +5364,19 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Recursion", "Numbers of dirtree levels to show simultaneously");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+ prop = RNA_def_property(srna, "show_details_size", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "details_flags", FILE_DETAILS_SIZE);
+ RNA_def_property_ui_text(prop, "File Size", "Draw a column listing the size of each file");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+
+ prop = RNA_def_property(srna, "show_details_datetime", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "details_flags", FILE_DETAILS_DATETIME);
+ RNA_def_property_ui_text(
+ prop,
+ "File Modification Date",
+ "Draw a column listing the date and time of modification for each file");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+
prop = RNA_def_property(srna, "use_filter", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FILE_FILTER);
RNA_def_property_ui_text(prop, "Filter Files", "Enable filtering of files");
@@ -5316,6 +5393,12 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Sort", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+ prop = RNA_def_property(srna, "use_sort_invert", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", FILE_SORT_INVERT);
+ RNA_def_property_ui_text(
+ prop, "Reverse Sorting", "Sort items descending, from highest value to lowest");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+
prop = RNA_def_property(srna, "use_filter_image", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filter", FILE_TYPE_IMAGE);
RNA_def_property_ui_text(prop, "Filter Images", "Show image files");
@@ -5331,7 +5414,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_filter_backup", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filter", FILE_TYPE_BLENDER_BACKUP);
RNA_def_property_ui_text(
- prop, "Filter BlenderBackup files", "Show .blend1, .blend2, etc. files");
+ prop, "Filter Blender Backup Files", "Show .blend1, .blend2, etc. files");
RNA_def_property_ui_icon(prop, ICON_FILE_BACKUP, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
@@ -5383,7 +5466,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_enum_items(prop, file_filter_idtypes_items);
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_ui_text(
- prop, "Filter ID types", "Which ID types to show/hide, when browsing a library");
+ prop, "Filter ID Types", "Which ID types to show/hide, when browsing a library");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
prop = RNA_def_property(srna, "filter_id_category", PROP_ENUM, PROP_NONE);
@@ -5391,7 +5474,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_enum_items(prop, file_filter_idcategories_items);
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_ui_text(
- prop, "Filter ID categories", "Which ID categories to show/hide, when browsing a library");
+ prop, "Filter ID Categories", "Which ID categories to show/hide, when browsing a library");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
prop = RNA_def_property(srna, "filter_glob", PROP_STRING, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c
index 52a197240da..cbaa407646f 100644
--- a/source/blender/makesrna/intern/rna_space_api.c
+++ b/source/blender/makesrna/intern/rna_space_api.c
@@ -40,6 +40,7 @@ static void rna_RegionView3D_update(ID *id, RegionView3D *rv3d, bContext *C)
area_region_from_regiondata(sc, rv3d, &sa, &ar);
if (sa && ar && sa->spacetype == SPACE_VIEW3D) {
+ Main *bmain = CTX_data_main(C);
View3D *v3d = sa->spacedata.first;
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win;
@@ -48,7 +49,7 @@ static void rna_RegionView3D_update(ID *id, RegionView3D *rv3d, bContext *C)
if (WM_window_get_active_screen(win) == sc) {
Scene *scene = WM_window_get_active_scene(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, NULL, NULL, NULL, false);
break;
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 2ab08c82b63..356ecd5b4db 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -465,18 +465,6 @@ static void rna_def_texmapping(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
- static const EnumPropertyItem prop_vect_type_items[] = {
- {TEXMAP_TYPE_TEXTURE,
- "TEXTURE",
- 0,
- "Texture",
- "Transform a texture by inverse mapping the texture coordinate"},
- {TEXMAP_TYPE_POINT, "POINT", 0, "Point", "Transform a point"},
- {TEXMAP_TYPE_VECTOR, "VECTOR", 0, "Vector", "Transform a direction vector"},
- {TEXMAP_TYPE_NORMAL, "NORMAL", 0, "Normal", "Transform a normal vector with unit length"},
- {0, NULL, 0, NULL, NULL},
- };
-
static const EnumPropertyItem prop_xyz_mapping_items[] = {
{0, "NONE", 0, "None", ""},
{1, "X", 0, "X", ""},
@@ -493,7 +481,7 @@ static void rna_def_texmapping(BlenderRNA *brna)
prop = RNA_def_property(srna, "vector_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_vect_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_mapping_type_items);
RNA_def_property_ui_text(prop, "Type", "Type of vector that the mapping transforms");
RNA_def_property_update(prop, 0, "rna_Texture_mapping_update");
@@ -581,16 +569,19 @@ static void rna_def_colormapping(BlenderRNA *brna)
prop = RNA_def_property(srna, "brightness", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bright");
RNA_def_property_range(prop, 0, 2);
+ RNA_def_property_ui_range(prop, 0, 2, 1, 3);
RNA_def_property_ui_text(prop, "Brightness", "Adjust the brightness of the texture");
RNA_def_property_update(prop, 0, "rna_Color_mapping_update");
prop = RNA_def_property(srna, "contrast", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 5);
+ RNA_def_property_ui_range(prop, 0, 5, 1, 3);
RNA_def_property_ui_text(prop, "Contrast", "Adjust the contrast of the texture");
RNA_def_property_update(prop, 0, "rna_Color_mapping_update");
prop = RNA_def_property(srna, "saturation", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0, 2);
+ RNA_def_property_ui_range(prop, 0, 2, 1, 3);
RNA_def_property_ui_text(prop, "Saturation", "Adjust the saturation of colors in the texture");
RNA_def_property_update(prop, 0, "rna_Color_mapping_update");
@@ -828,14 +819,14 @@ static void rna_def_texture_clouds(BlenderRNA *brna)
prop = RNA_def_property(srna, "noise_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "noisesize");
RNA_def_property_range(prop, 0.0001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0001, 2, 10, 2);
+ RNA_def_property_ui_range(prop, 0.0001, 2, 1, 2);
RNA_def_property_ui_text(prop, "Noise Size", "Scaling for noise input");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "noise_depth", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "noisedepth");
RNA_def_property_range(prop, 0, 30);
- RNA_def_property_ui_range(prop, 0, 24, 0, 2);
+ RNA_def_property_ui_range(prop, 0, 24, 1, 2);
RNA_def_property_ui_text(prop, "Noise Depth", "Depth of the cloud calculation");
RNA_def_property_update(prop, 0, "rna_Texture_nodes_update");
@@ -892,7 +883,7 @@ static void rna_def_texture_wood(BlenderRNA *brna)
prop = RNA_def_property(srna, "noise_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "noisesize");
RNA_def_property_range(prop, 0.0001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0001, 2, 10, 2);
+ RNA_def_property_ui_range(prop, 0.0001, 2, 1, 2);
RNA_def_property_ui_text(prop, "Noise Size", "Scaling for noise input");
RNA_def_property_update(prop, 0, "rna_Texture_update");
@@ -960,7 +951,7 @@ static void rna_def_texture_marble(BlenderRNA *brna)
prop = RNA_def_property(srna, "noise_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "noisesize");
RNA_def_property_range(prop, 0.0001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0001, 2, 10, 2);
+ RNA_def_property_ui_range(prop, 0.0001, 2, 1, 2);
RNA_def_property_ui_text(prop, "Noise Size", "Scaling for noise input");
RNA_def_property_update(prop, 0, "rna_Texture_update");
@@ -974,7 +965,7 @@ static void rna_def_texture_marble(BlenderRNA *brna)
prop = RNA_def_property(srna, "noise_depth", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "noisedepth");
RNA_def_property_range(prop, 0, 30);
- RNA_def_property_ui_range(prop, 0, 24, 0, 2);
+ RNA_def_property_ui_range(prop, 0, 24, 1, 2);
RNA_def_property_ui_text(prop, "Noise Depth", "Depth of the cloud calculation");
RNA_def_property_update(prop, 0, "rna_Texture_update");
@@ -1028,7 +1019,7 @@ static void rna_def_texture_magic(BlenderRNA *brna)
prop = RNA_def_property(srna, "noise_depth", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "noisedepth");
RNA_def_property_range(prop, 0, 30);
- RNA_def_property_ui_range(prop, 0, 24, 0, 2);
+ RNA_def_property_ui_range(prop, 0, 24, 1, 2);
RNA_def_property_ui_text(prop, "Noise Depth", "Depth of the noise");
RNA_def_property_update(prop, 0, "rna_Texture_update");
}
@@ -1108,7 +1099,7 @@ static void rna_def_texture_stucci(BlenderRNA *brna)
prop = RNA_def_property(srna, "noise_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "noisesize");
RNA_def_property_range(prop, 0.0001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0001, 2, 10, 2);
+ RNA_def_property_ui_range(prop, 0.0001, 2, 1, 2);
RNA_def_property_ui_text(prop, "Noise Size", "Scaling for noise input");
RNA_def_property_update(prop, 0, "rna_Texture_update");
@@ -1332,43 +1323,49 @@ static void rna_def_texture_musgrave(BlenderRNA *brna)
prop = RNA_def_property(srna, "dimension_max", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "mg_H");
RNA_def_property_range(prop, 0.0001, 2);
+ RNA_def_property_ui_range(prop, 0.0001, 2, 1, 2);
RNA_def_property_ui_text(prop, "Highest Dimension", "Highest fractal dimension");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "lacunarity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "mg_lacunarity");
RNA_def_property_range(prop, 0, 6);
+ RNA_def_property_ui_range(prop, 0, 6, 1, 2);
RNA_def_property_ui_text(prop, "Lacunarity", "Gap between successive frequencies");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "octaves", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "mg_octaves");
RNA_def_property_range(prop, 0, 8);
+ RNA_def_property_ui_range(prop, 0, 8, 1, 2);
RNA_def_property_ui_text(prop, "Octaves", "Number of frequencies used");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "mg_offset");
RNA_def_property_range(prop, 0, 6);
+ RNA_def_property_ui_range(prop, 0, 6, 1, 2);
RNA_def_property_ui_text(prop, "Offset", "The fractal offset");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "gain", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "mg_gain");
RNA_def_property_range(prop, 0, 6);
+ RNA_def_property_ui_range(prop, 0, 6, 1, 2);
RNA_def_property_ui_text(prop, "Gain", "The gain multiplier");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "noise_intensity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "ns_outscale");
RNA_def_property_range(prop, 0, 10);
+ RNA_def_property_ui_range(prop, 0, 10, 1, 2);
RNA_def_property_ui_text(prop, "Noise Intensity", "Intensity of the noise");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "noise_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "noisesize");
RNA_def_property_range(prop, 0.0001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0001, 2, 10, 2);
+ RNA_def_property_ui_range(prop, 0.0001, 2, 1, 2);
RNA_def_property_ui_text(prop, "Noise Size", "Scaling for noise input");
RNA_def_property_update(prop, 0, "rna_Texture_update");
@@ -1485,7 +1482,7 @@ static void rna_def_texture_voronoi(BlenderRNA *brna)
prop = RNA_def_property(srna, "noise_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "noisesize");
RNA_def_property_range(prop, 0.0001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0001, 2, 10, 2);
+ RNA_def_property_ui_range(prop, 0.0001, 2, 1, 2);
RNA_def_property_ui_text(prop, "Noise Size", "Scaling for noise input");
RNA_def_property_update(prop, 0, "rna_Texture_update");
@@ -1514,7 +1511,7 @@ static void rna_def_texture_distorted_noise(BlenderRNA *brna)
prop = RNA_def_property(srna, "noise_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "noisesize");
RNA_def_property_range(prop, 0.0001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0001, 2, 10, 2);
+ RNA_def_property_ui_range(prop, 0.0001, 2, 1, 2);
RNA_def_property_ui_text(prop, "Noise Size", "Scaling for noise input");
RNA_def_property_update(prop, 0, "rna_Texture_update");
@@ -1580,16 +1577,19 @@ static void rna_def_texture(BlenderRNA *brna)
prop = RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bright");
RNA_def_property_range(prop, 0, 2);
+ RNA_def_property_ui_range(prop, 0, 2, 1, 3);
RNA_def_property_ui_text(prop, "Brightness", "Adjust the brightness of the texture");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "contrast", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 5);
+ RNA_def_property_ui_range(prop, 0, 5, 1, 3);
RNA_def_property_ui_text(prop, "Contrast", "Adjust the contrast of the texture");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "saturation", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0, 2);
+ RNA_def_property_ui_range(prop, 0, 2, 1, 3);
RNA_def_property_ui_text(prop, "Saturation", "Adjust the saturation of colors in the texture");
RNA_def_property_update(prop, 0, "rna_Texture_update");
@@ -1597,18 +1597,21 @@ static void rna_def_texture(BlenderRNA *brna)
prop = RNA_def_property(srna, "factor_red", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "rfac");
RNA_def_property_range(prop, 0, 2);
+ RNA_def_property_ui_range(prop, 0, 2, 1, 3);
RNA_def_property_ui_text(prop, "Factor Red", "");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "factor_green", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "gfac");
RNA_def_property_range(prop, 0, 2);
+ RNA_def_property_ui_range(prop, 0, 2, 1, 3);
RNA_def_property_ui_text(prop, "Factor Green", "");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "factor_blue", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bfac");
RNA_def_property_range(prop, 0, 2);
+ RNA_def_property_ui_range(prop, 0, 2, 1, 3);
RNA_def_property_ui_text(prop, "Factor Blue", "");
RNA_def_property_update(prop, 0, "rna_Texture_update");
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index 0a824b3c67a..4b232251770 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -1037,7 +1037,7 @@ static void rna_def_trackingSettings(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_enum_items(prop, tracker_motion_model);
- RNA_def_property_ui_text(prop, "Motion model", "Default motion model to use for tracking");
+ RNA_def_property_ui_text(prop, "Motion Model", "Default motion model to use for tracking");
/* default_use_brute */
prop = RNA_def_property(srna, "use_default_brute", PROP_BOOLEAN, PROP_NONE);
@@ -1470,7 +1470,7 @@ static void rna_def_trackingTrack(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_enum_items(prop, tracker_motion_model);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Motion model", "Default motion model to use for tracking");
+ RNA_def_property_ui_text(prop, "Motion Model", "Default motion model to use for tracking");
/* minimum correlation */
prop = RNA_def_property(srna, "correlation_min", PROP_FLOAT, PROP_NONE);
@@ -1849,7 +1849,7 @@ static void rna_def_trackingStabilization(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_2d_stabilization", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", TRACKING_2D_STABILIZATION);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Use 2D stabilization", "Use 2D stabilization for footage");
+ RNA_def_property_ui_text(prop, "Use 2D Stabilization", "Use 2D stabilization for footage");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
/* use_stabilize_rotation */
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index c8b039bd2d6..74d1743dfc1 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -1519,6 +1519,13 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_int(func, "rows", 5, 1, INT_MAX, "", "Maximum number of items to show", 1, INT_MAX);
parm = RNA_def_int(func, "found", 0, 0, INT_MAX, "", "Number of items drawn", 0, INT_MAX);
RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "template_file_select_path", "uiTemplateFileSelectPath");
+ RNA_def_function_ui_description(func,
+ "Item. A text button to set the active file browser path.");
+ parm = RNA_def_pointer(func, "params", "FileSelectParams", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 72a3455b120..c9b6f46ab04 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -912,6 +912,13 @@ static bool rna_UserDef_studiolight_is_user_defined_get(PointerRNA *ptr)
return (sl->flag & STUDIOLIGHT_USER_DEFINED) != 0;
}
+/* StudioLight.is_user_defined */
+static bool rna_UserDef_studiolight_has_specular_highlight_pass_get(PointerRNA *ptr)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ return sl->flag & STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS;
+}
+
/* StudioLight.type */
static int rna_UserDef_studiolight_type_get(PointerRNA *ptr)
@@ -1497,6 +1504,12 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Shading", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+ prop = RNA_def_property(srna, "icon_folder", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "icon_folder");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "File Folders", "Color of folders in the file browser");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
prop = RNA_def_property(srna, "icon_border_intensity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "icon_border_intensity");
RNA_def_property_ui_text(
@@ -3384,6 +3397,16 @@ static void rna_def_userdef_theme_space_clip(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Path After", "Color of path after current frame");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+ prop = RNA_def_property(srna, "path_keyframe_before", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Path Before", "Color of path before current frame");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "path_keyframe_after", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Path After", "Color of path after current frame");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
prop = RNA_def_property(srna, "frame_current", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "cframe");
RNA_def_property_array(prop, 3);
@@ -3700,6 +3723,15 @@ static void rna_def_userdef_studiolight(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "User Defined", "");
+ prop = RNA_def_property(srna, "has_specular_highlight_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_UserDef_studiolight_has_specular_highlight_pass_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(
+ prop,
+ "Has Specular Highlight",
+ "Studio light image file has separate \"diffuse\" and \"specular\" passes");
+
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_studio_light_type_items);
RNA_def_property_enum_funcs(prop, "rna_UserDef_studiolight_type_get", NULL, NULL);
@@ -4022,6 +4054,43 @@ static void rna_def_userdef_view(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem render_display_types[] = {
+ {USER_RENDER_DISPLAY_NONE,
+ "NONE",
+ 0,
+ "Keep User Interface",
+ "Images are rendered without changing the user interface"},
+ {USER_RENDER_DISPLAY_SCREEN,
+ "SCREEN",
+ 0,
+ "Full Screen",
+ "Images are rendered in a maximized Image Editor"},
+ {USER_RENDER_DISPLAY_AREA,
+ "AREA",
+ 0,
+ "Image Editor",
+ "Images are rendered in an Image Editor"},
+ {USER_RENDER_DISPLAY_WINDOW,
+ "WINDOW",
+ 0,
+ "New Window",
+ "Images are rendered in a new window"},
+ {0, NULL, 0, NULL, NULL},
+ };
+ static const EnumPropertyItem temp_space_display_types[] = {
+ {USER_TEMP_SPACE_DISPLAY_FULLSCREEN,
+ "SCREEN", /* Could be FULLSCREEN, but keeping it consistent with render_display_types */
+ 0,
+ "Full Screen",
+ "Open the temporary editor in a maximized screen"},
+ {USER_TEMP_SPACE_DISPLAY_WINDOW,
+ "WINDOW",
+ 0,
+ "New Window",
+ "Open the temporary editor in a new window"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
PropertyRNA *prop;
StructRNA *srna;
@@ -4037,7 +4106,6 @@ static void rna_def_userdef_view(BlenderRNA *brna)
prop, "UI Scale", "Changes the size of the fonts and widgets in the interface");
RNA_def_property_range(prop, 0.25f, 4.0f);
RNA_def_property_ui_range(prop, 0.5f, 2.0f, 1, 2);
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
prop = RNA_def_property(srna, "ui_line_width", PROP_ENUM, PROP_NONE);
@@ -4096,7 +4164,8 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "show_addons_enabled_only", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_ADDONS_ENABLED_ONLY);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "space_data.flag", USER_SPACEDATA_ADDONS_SHOW_ONLY_ENABLED);
RNA_def_property_ui_text(prop,
"Enabled Add-ons Only",
"Only show enabled add-ons. Un-check to see all installed add-ons");
@@ -4150,7 +4219,7 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_MENUOPENAUTO);
RNA_def_property_ui_text(
prop,
- "Open On Mouse Over",
+ "Open on Mouse Over",
"Open menu buttons and pulldowns automatically when the mouse is hovering");
prop = RNA_def_property(srna, "open_toplevel_delay", PROP_INT, PROP_NONE);
@@ -4246,6 +4315,17 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Header Position", "Default header position for new space-types");
RNA_def_property_update(prop, 0, "rna_userdef_screen_update_header_default");
+ prop = RNA_def_property(srna, "render_display_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, render_display_types);
+ RNA_def_property_ui_text(
+ prop, "Render Display Type", "Default location where rendered images will be displayed in");
+
+ prop = RNA_def_property(srna, "filebrowser_display_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, temp_space_display_types);
+ RNA_def_property_ui_text(prop,
+ "File Browser Display Type",
+ "Default location where the File Editor will be displayed in");
+
static const EnumPropertyItem text_hinting_items[] = {
{0, "AUTO", 0, "Auto", ""},
{USER_TEXT_HINTING_NONE, "NONE", 0, "None", ""},
@@ -4302,7 +4382,6 @@ static void rna_def_userdef_view(BlenderRNA *brna)
prop = RNA_def_property(srna, "gizmo_size", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "gizmo_size");
RNA_def_property_range(prop, 10, 200);
- RNA_def_property_int_default(prop, 75);
RNA_def_property_ui_text(prop, "Gizmo Size", "Diameter of the gizmo");
RNA_def_property_update(prop, 0, "rna_userdef_update");
@@ -4310,7 +4389,6 @@ static void rna_def_userdef_view(BlenderRNA *brna)
prop = RNA_def_property(srna, "lookdev_sphere_size", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "lookdev_sphere_size");
RNA_def_property_range(prop, 50, 400);
- RNA_def_property_int_default(prop, 150);
RNA_def_property_ui_text(
prop, "Look Dev Spheres Size", "Maximum diameter of the look development sphere size");
RNA_def_property_update(prop, 0, "rna_userdef_update");
@@ -4340,7 +4418,7 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_enum_items(prop, zoom_frame_modes);
RNA_def_property_enum_sdna(prop, NULL, "view_frame_type");
RNA_def_property_ui_text(
- prop, "Zoom To Frame Type", "How zooming to frame focuses around current frame");
+ prop, "Zoom to Frame Type", "How zooming to frame focuses around current frame");
prop = RNA_def_property(srna, "view_frame_keyframes", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 1, 500);
@@ -5184,7 +5262,7 @@ static void rna_def_userdef_input(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_zoom_to_mouse", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_ZOOM_TO_MOUSEPOS);
RNA_def_property_ui_text(prop,
- "Zoom To Mouse Position",
+ "Zoom to Mouse Position",
"Zoom in towards the mouse pointer's position in the 3D view, "
"rather than the 2D window center");
@@ -5240,7 +5318,6 @@ static void rna_def_userdef_input(BlenderRNA *brna)
prop = RNA_def_property(srna, "view_rotate_sensitivity_turntable", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_range(prop, DEG2RADF(0.001f), DEG2RADF(15.0f));
- RNA_def_property_float_default(prop, DEG2RADF(0.4f));
RNA_def_property_ui_range(prop, DEG2RADF(0.001f), DEG2RADF(15.0f), 1.0f, 2);
RNA_def_property_ui_text(prop,
"Orbit Sensitivity",
@@ -5248,7 +5325,6 @@ static void rna_def_userdef_input(BlenderRNA *brna)
prop = RNA_def_property(srna, "view_rotate_sensitivity_trackball", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.1f, 10.0f);
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_range(prop, 0.1f, 2.0f, 0.01f, 2);
RNA_def_property_ui_text(prop, "Orbit Sensitivity", "Scale trackball orbit sensitivity");
@@ -5288,7 +5364,6 @@ static void rna_def_userdef_input(BlenderRNA *brna)
/* tablet pressure curve */
prop = RNA_def_property(srna, "pressure_threshold_max", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01f, 3);
RNA_def_property_ui_text(
prop, "Max Threshold", "Raw input pressure value that is interpreted as 100% by Blender");
@@ -5447,7 +5522,7 @@ static void rna_def_userdef_keymap(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_ui_keyconfig", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(
- prop, NULL, "userpref_flag", USER_SECTION_INPUT_HIDE_UI_KEYCONFIG);
+ prop, NULL, "space_data.flag", USER_SPACEDATA_INPUT_HIDE_UI_KEYCONFIG);
RNA_def_property_ui_text(prop, "Show UI Key-Config", "");
prop = RNA_def_property(srna, "active_keyconfig", PROP_STRING, PROP_DIRPATH);
@@ -5498,11 +5573,6 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Hide System Bookmarks", "Hide system bookmarks in the file selector");
- prop = RNA_def_property(srna, "show_thumbnails", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_SHOW_THUMBNAILS);
- RNA_def_property_ui_text(
- prop, "Show Thumbnails", "Open in thumbnail view for images and movies");
-
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(
@@ -5728,7 +5798,7 @@ void RNA_def_userdef(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Preferences", "Global preferences");
prop = RNA_def_property(srna, "active_section", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "userpref");
+ RNA_def_property_enum_sdna(prop, NULL, "space_data.section_active");
RNA_def_property_enum_items(prop, preference_section_items);
RNA_def_property_ui_text(
prop, "Active Section", "Active section of the preferences shown in the user interface");
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index c3ffeaf6f6f..5f60ecf449b 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -1420,6 +1420,39 @@ static void rna_operator_cancel_cb(bContext *C, wmOperator *op)
RNA_parameter_list_free(&list);
}
+static char *rna_operator_description_cb(bContext *C, wmOperatorType *ot, PointerRNA *prop_ptr)
+{
+ extern FunctionRNA rna_Operator_description_func;
+
+ PointerRNA ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ void *ret;
+ char *result;
+
+ RNA_pointer_create(NULL, ot->ext.srna, NULL, &ptr); /* dummy */
+ func = &rna_Operator_description_func; /* RNA_struct_find_function(&ptr, "description"); */
+
+ RNA_parameter_list_create(&list, &ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ RNA_parameter_set_lookup(&list, "properties", prop_ptr);
+ ot->ext.call(C, &ptr, func, &list);
+
+ RNA_parameter_get_lookup(&list, "result", &ret);
+ result = (char *)ret;
+
+ if (result && result[0]) {
+ result = BLI_strdup(result);
+ }
+ else {
+ result = NULL;
+ }
+
+ RNA_parameter_list_free(&list);
+
+ return result;
+}
+
static void rna_Operator_unregister(struct Main *bmain, StructRNA *type);
/* bpy_operator_wrap.c */
@@ -1437,7 +1470,7 @@ static StructRNA *rna_Operator_register(Main *bmain,
wmOperatorType dummyot = {NULL};
wmOperator dummyop = {NULL};
PointerRNA dummyotr;
- int have_function[7];
+ int have_function[8];
struct {
char idname[OP_MAX_TYPENAME];
@@ -1531,6 +1564,7 @@ static StructRNA *rna_Operator_register(Main *bmain,
dummyot.modal = (have_function[4]) ? rna_operator_modal_cb : NULL;
dummyot.ui = (have_function[5]) ? rna_operator_draw_cb : NULL;
dummyot.cancel = (have_function[6]) ? rna_operator_cancel_cb : NULL;
+ dummyot.get_description = (have_function[7]) ? rna_operator_description_cb : NULL;
WM_operatortype_append_ptr(BPY_RNA_operator_wrapper, (void *)&dummyot);
/* update while blender is running */
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index d9306ba7a65..886258ee45f 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -41,24 +41,27 @@
#include "rna_internal.h" /* own include */
-/* confusingm 2 enums mixed up here */
+/* confusing 2 enums mixed up here */
const EnumPropertyItem rna_enum_window_cursor_items[] = {
- {CURSOR_STD, "DEFAULT", 0, "Default", ""},
- {CURSOR_NONE, "NONE", 0, "None", ""},
- {CURSOR_WAIT, "WAIT", 0, "Wait", ""},
- {CURSOR_EDIT, "CROSSHAIR", 0, "Crosshair", ""},
- {CURSOR_X_MOVE, "MOVE_X", 0, "Move-X", ""},
- {CURSOR_Y_MOVE, "MOVE_Y", 0, "Move-Y", ""},
+ {WM_CURSOR_DEFAULT, "DEFAULT", 0, "Default", ""},
+ {WM_CURSOR_NONE, "NONE", 0, "None", ""},
+ {WM_CURSOR_WAIT, "WAIT", 0, "Wait", ""},
+ {WM_CURSOR_EDIT, "CROSSHAIR", 0, "Crosshair", ""},
+ {WM_CURSOR_X_MOVE, "MOVE_X", 0, "Move-X", ""},
+ {WM_CURSOR_Y_MOVE, "MOVE_Y", 0, "Move-Y", ""},
/* new */
- {BC_KNIFECURSOR, "KNIFE", 0, "Knife", ""},
- {BC_TEXTEDITCURSOR, "TEXT", 0, "Text", ""},
- {BC_PAINTBRUSHCURSOR, "PAINT_BRUSH", 0, "Paint Brush", ""},
- {BC_HANDCURSOR, "HAND", 0, "Hand", ""},
- {BC_EW_SCROLLCURSOR, "SCROLL_X", 0, "Scroll-X", ""},
- {BC_NS_SCROLLCURSOR, "SCROLL_Y", 0, "Scroll-Y", ""},
- {BC_NSEW_SCROLLCURSOR, "SCROLL_XY", 0, "Scroll-XY", ""},
- {BC_EYEDROPPER_CURSOR, "EYEDROPPER", 0, "Eyedropper", ""},
+ {WM_CURSOR_KNIFE, "KNIFE", 0, "Knife", ""},
+ {WM_CURSOR_TEXT_EDIT, "TEXT", 0, "Text", ""},
+ {WM_CURSOR_PAINT_BRUSH, "PAINT_BRUSH", 0, "Paint Brush", ""},
+ {WM_CURSOR_PAINT, "PAINT_CROSS", 0, "Paint Cross", ""},
+ {WM_CURSOR_DOT, "DOT", 0, "Dot Cursor", ""},
+ {WM_CURSOR_ERASER, "ERASER", 0, "Eraser", ""},
+ {WM_CURSOR_HAND, "HAND", 0, "Hand", ""},
+ {WM_CURSOR_EW_SCROLL, "SCROLL_X", 0, "Scroll-X", ""},
+ {WM_CURSOR_NS_SCROLL, "SCROLL_Y", 0, "Scroll-Y", ""},
+ {WM_CURSOR_NSEW_SCROLL, "SCROLL_XY", 0, "Scroll-XY", ""},
+ {WM_CURSOR_EYEDROPPER, "EYEDROPPER", 0, "Eyedropper", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -957,6 +960,19 @@ void RNA_api_operator(StructRNA *srna)
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "context", "Context", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ /* description */
+ func = RNA_def_function(srna, "description", NULL);
+ RNA_def_function_ui_description(func, "Compute a description string that depends on parameters");
+ RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL);
+ parm = RNA_def_string(func, "result", NULL, 4096, "result", "");
+ RNA_def_parameter_clear_flags(parm, PROP_NEVER_NULL, 0);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "properties", "OperatorProperties", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
}
void RNA_api_macro(StructRNA *srna)
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 5116fefde94..1ae1f891e6f 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -141,6 +141,10 @@ if(WITH_MOD_OCEANSIM)
add_definitions(-DWITH_OCEANSIM)
endif()
+if(WITH_OPENSUBDIV)
+ add_definitions(-DWITH_OPENSUBDIV)
+endif()
+
if(WITH_BULLET)
list(APPEND LIB
extern_bullet
diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c
index 522b387411b..9f3802a4fa1 100644
--- a/source/blender/modifiers/intern/MOD_armature.c
+++ b/source/blender/modifiers/intern/MOD_armature.c
@@ -82,7 +82,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the armature is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
return !amd->object || amd->object->type != OB_ARMATURE;
}
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 48718a47419..644ac3a10e8 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -268,9 +268,9 @@ static void dm_mvert_map_doubles(int *doubles_map,
static void mesh_merge_transform(Mesh *result,
Mesh *cap_mesh,
- float cap_offset[4][4],
- unsigned int cap_verts_index,
- unsigned int cap_edges_index,
+ const float cap_offset[4][4],
+ uint cap_verts_index,
+ uint cap_edges_index,
int cap_loops_index,
int cap_polys_index,
int cap_nverts,
@@ -775,7 +775,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the curve/mesh is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
if (amd->curve_ob && amd->curve_ob->type != OB_CURVE) {
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index a05b7023392..0c00bb572be 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -212,7 +212,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
spread,
mesh->smoothresh);
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
/* Make sure we never alloc'd these. */
BLI_assert(bm->vtoolflagpool == NULL && bm->etoolflagpool == NULL && bm->ftoolflagpool == NULL);
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index ea42ddb03f4..9868395c0e8 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -74,7 +74,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the mesh is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
return !bmd->object || bmd->object->type != OB_MESH;
}
@@ -316,7 +316,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
MEM_freeN(looptris);
}
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c
index 3d43c6de88e..56e84423db4 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -118,7 +118,7 @@ static void deformVerts(ModifierData *md,
if (mesh_src) {
float current_time = 0;
- unsigned int mvert_num = 0;
+ uint mvert_num = 0;
BKE_mesh_vert_coords_apply(mesh_src, vertexCos);
BKE_mesh_calc_normals(mesh_src);
diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c
index a234f468e45..ff241550bdc 100644
--- a/source/blender/modifiers/intern/MOD_correctivesmooth.c
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -70,7 +70,7 @@ static void initData(ModifierData *md)
csmd->defgrp_name[0] = '\0';
- csmd->delta_cache = NULL;
+ csmd->delta_cache.deltas = NULL;
}
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
@@ -84,14 +84,14 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
tcsmd->bind_coords = MEM_dupallocN(csmd->bind_coords);
}
- tcsmd->delta_cache = NULL;
- tcsmd->delta_cache_num = 0;
+ tcsmd->delta_cache.deltas = NULL;
+ tcsmd->delta_cache.totverts = 0;
}
static void freeBind(CorrectiveSmoothModifierData *csmd)
{
MEM_SAFE_FREE(csmd->bind_coords);
- MEM_SAFE_FREE(csmd->delta_cache);
+ MEM_SAFE_FREE(csmd->delta_cache.deltas);
csmd->bind_coords_num = 0;
}
@@ -117,11 +117,11 @@ static void requiredDataMask(Object *UNUSED(ob),
/* check individual weights for changes and cache values */
static void mesh_get_weights(MDeformVert *dvert,
const int defgrp_index,
- const unsigned int numVerts,
+ const uint numVerts,
const bool use_invert_vgroup,
float *smooth_weights)
{
- unsigned int i;
+ uint i;
for (i = 0; i < numVerts; i++, dvert++) {
const float w = defvert_find_weight(dvert, defgrp_index);
@@ -140,11 +140,11 @@ static void mesh_get_boundaries(Mesh *mesh, float *smooth_weights)
const MPoly *mpoly = mesh->mpoly;
const MLoop *mloop = mesh->mloop;
const MEdge *medge = mesh->medge;
- unsigned int mpoly_num, medge_num, i;
- unsigned short *boundaries;
+ uint mpoly_num, medge_num, i;
+ ushort *boundaries;
- mpoly_num = (unsigned int)mesh->totpoly;
- medge_num = (unsigned int)mesh->totedge;
+ mpoly_num = (uint)mesh->totpoly;
+ medge_num = (uint)mesh->totedge;
boundaries = MEM_calloc_arrayN(medge_num, sizeof(*boundaries), __func__);
@@ -176,14 +176,14 @@ static void mesh_get_boundaries(Mesh *mesh, float *smooth_weights)
static void smooth_iter__simple(CorrectiveSmoothModifierData *csmd,
Mesh *mesh,
float (*vertexCos)[3],
- unsigned int numVerts,
+ uint numVerts,
const float *smooth_weights,
- unsigned int iterations)
+ uint iterations)
{
const float lambda = csmd->lambda;
- unsigned int i;
+ uint i;
- const unsigned int numEdges = (unsigned int)mesh->totedge;
+ const uint numEdges = (uint)mesh->totedge;
const MEdge *edges = mesh->medge;
float *vertex_edge_count_div;
@@ -252,18 +252,18 @@ static void smooth_iter__simple(CorrectiveSmoothModifierData *csmd,
static void smooth_iter__length_weight(CorrectiveSmoothModifierData *csmd,
Mesh *mesh,
float (*vertexCos)[3],
- unsigned int numVerts,
+ uint numVerts,
const float *smooth_weights,
- unsigned int iterations)
+ uint iterations)
{
const float eps = FLT_EPSILON * 10.0f;
- const unsigned int numEdges = (unsigned int)mesh->totedge;
+ const uint numEdges = (uint)mesh->totedge;
/* note: the way this smoothing method works, its approx half as strong as the simple-smooth,
* and 2.0 rarely spikes, double the value for consistent behavior. */
const float lambda = csmd->lambda * 2.0f;
const MEdge *edges = mesh->medge;
float *vertex_edge_count;
- unsigned int i;
+ uint i;
struct SmoothingData_Weighted {
float delta[3];
@@ -346,9 +346,9 @@ static void smooth_iter__length_weight(CorrectiveSmoothModifierData *csmd,
static void smooth_iter(CorrectiveSmoothModifierData *csmd,
Mesh *mesh,
float (*vertexCos)[3],
- unsigned int numVerts,
+ uint numVerts,
const float *smooth_weights,
- unsigned int iterations)
+ uint iterations)
{
switch (csmd->smooth_type) {
case MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT:
@@ -367,7 +367,7 @@ static void smooth_verts(CorrectiveSmoothModifierData *csmd,
MDeformVert *dvert,
const int defgrp_index,
float (*vertexCos)[3],
- unsigned int numVerts)
+ uint numVerts)
{
float *smooth_weights = NULL;
@@ -391,7 +391,7 @@ static void smooth_verts(CorrectiveSmoothModifierData *csmd,
}
}
- smooth_iter(csmd, mesh, vertexCos, numVerts, smooth_weights, (unsigned int)csmd->repeat);
+ smooth_iter(csmd, mesh, vertexCos, numVerts, smooth_weights, (uint)csmd->repeat);
if (smooth_weights) {
MEM_freeN(smooth_weights);
@@ -454,13 +454,13 @@ static void calc_tangent_loop_accum(const float v_dir_prev[3],
static void calc_tangent_spaces(Mesh *mesh, float (*vertexCos)[3], float (*r_tangent_spaces)[3][3])
{
- const unsigned int mpoly_num = (unsigned int)mesh->totpoly;
+ const uint mpoly_num = (uint)mesh->totpoly;
#ifndef USE_TANGENT_CALC_INLINE
- const unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
+ const uint mvert_num = (uint)dm->getNumVerts(dm);
#endif
const MPoly *mpoly = mesh->mpoly;
const MLoop *mloop = mesh->mloop;
- unsigned int i;
+ uint i;
for (i = 0; i < mpoly_num; i++) {
const MPoly *mp = &mpoly[i];
@@ -502,6 +502,23 @@ static void calc_tangent_spaces(Mesh *mesh, float (*vertexCos)[3], float (*r_tan
#endif
}
+static void store_cache_settings(CorrectiveSmoothModifierData *csmd)
+{
+ csmd->delta_cache.lambda = csmd->lambda;
+ csmd->delta_cache.repeat = csmd->repeat;
+ csmd->delta_cache.flag = csmd->flag;
+ csmd->delta_cache.smooth_type = csmd->smooth_type;
+ csmd->delta_cache.rest_source = csmd->rest_source;
+}
+
+static bool cache_settings_equal(CorrectiveSmoothModifierData *csmd)
+{
+ return (csmd->delta_cache.lambda == csmd->lambda && csmd->delta_cache.repeat == csmd->repeat &&
+ csmd->delta_cache.flag == csmd->flag &&
+ csmd->delta_cache.smooth_type == csmd->smooth_type &&
+ csmd->delta_cache.rest_source == csmd->rest_source);
+}
+
/**
* This calculates #CorrectiveSmoothModifierData.delta_cache
* It's not run on every update (during animation for example).
@@ -511,22 +528,22 @@ static void calc_deltas(CorrectiveSmoothModifierData *csmd,
MDeformVert *dvert,
const int defgrp_index,
const float (*rest_coords)[3],
- unsigned int numVerts)
+ uint numVerts)
{
float(*smooth_vertex_coords)[3] = MEM_dupallocN(rest_coords);
float(*tangent_spaces)[3][3];
- unsigned int i;
+ uint i;
tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__);
- if (csmd->delta_cache_num != numVerts) {
- MEM_SAFE_FREE(csmd->delta_cache);
+ if (csmd->delta_cache.totverts != numVerts) {
+ MEM_SAFE_FREE(csmd->delta_cache.deltas);
}
/* allocate deltas if they have not yet been allocated, otherwise we will just write over them */
- if (!csmd->delta_cache) {
- csmd->delta_cache_num = numVerts;
- csmd->delta_cache = MEM_malloc_arrayN(numVerts, sizeof(float[3]), __func__);
+ if (!csmd->delta_cache.deltas) {
+ csmd->delta_cache.totverts = numVerts;
+ csmd->delta_cache.deltas = MEM_malloc_arrayN(numVerts, sizeof(float[3]), __func__);
}
smooth_verts(csmd, mesh, dvert, defgrp_index, smooth_vertex_coords, numVerts);
@@ -544,7 +561,7 @@ static void calc_deltas(CorrectiveSmoothModifierData *csmd,
if (UNLIKELY(!invert_m3_m3(imat, tangent_spaces[i]))) {
transpose_m3_m3(imat, tangent_spaces[i]);
}
- mul_v3_m3v3(csmd->delta_cache[i], imat, delta);
+ mul_v3_m3v3(csmd->delta_cache.deltas[i], imat, delta);
}
MEM_freeN(tangent_spaces);
@@ -556,13 +573,14 @@ static void correctivesmooth_modifier_do(ModifierData *md,
Object *ob,
Mesh *mesh,
float (*vertexCos)[3],
- unsigned int numVerts,
+ uint numVerts,
struct BMEditMesh *em)
{
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
const bool force_delta_cache_update =
/* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */
+ !cache_settings_equal(csmd) ||
((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) &&
(((ID *)ob->data)->recalc & ID_RECALC_ALL));
@@ -575,7 +593,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
/* if rest bind_coords not are defined, set them (only run during bind) */
if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) &&
/* signal to recalculate, whoever sets MUST also free bind coords */
- (csmd->bind_coords_num == (unsigned int)-1)) {
+ (csmd->bind_coords_num == (uint)-1)) {
if (DEG_is_active(depsgraph)) {
BLI_assert(csmd->bind_coords == NULL);
csmd->bind_coords = MEM_dupallocN(vertexCos);
@@ -617,8 +635,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
goto error;
}
else {
- unsigned int me_numVerts = (unsigned int)((em) ? em->bm->totvert :
- ((Mesh *)ob->data)->totvert);
+ uint me_numVerts = (uint)((em) ? em->bm->totvert : ((Mesh *)ob->data)->totvert);
if (me_numVerts != numVerts) {
modifier_setError(md, "Original vertex count mismatch: %u to %u", me_numVerts, numVerts);
@@ -628,10 +645,13 @@ static void correctivesmooth_modifier_do(ModifierData *md,
}
/* check to see if our deltas are still valid */
- if (!csmd->delta_cache || (csmd->delta_cache_num != numVerts) || force_delta_cache_update) {
+ if (!csmd->delta_cache.deltas || (csmd->delta_cache.totverts != numVerts) ||
+ force_delta_cache_update) {
const float(*rest_coords)[3];
bool is_rest_coords_alloc = false;
+ store_cache_settings(csmd);
+
if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
/* caller needs to do sanity check here */
csmd->bind_coords_num = numVerts;
@@ -642,7 +662,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
rest_coords = em ? BKE_editmesh_vert_coords_alloc_orco(em, &me_numVerts) :
BKE_mesh_vert_coords_alloc(ob->data, &me_numVerts);
- BLI_assert((unsigned int)me_numVerts == numVerts);
+ BLI_assert((uint)me_numVerts == numVerts);
is_rest_coords_alloc = true;
}
@@ -662,7 +682,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
/* this could be a check, but at this point it _must_ be valid */
- BLI_assert(csmd->bind_coords_num == numVerts && csmd->delta_cache);
+ BLI_assert(csmd->bind_coords_num == numVerts && csmd->delta_cache.deltas);
}
#ifdef DEBUG_TIME
@@ -673,7 +693,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, numVerts);
{
- unsigned int i;
+ uint i;
float(*tangent_spaces)[3][3];
@@ -689,7 +709,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
calc_tangent_ortho(tangent_spaces[i]);
#endif
- mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache[i]);
+ mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache.deltas[i]);
add_v3_v3(vertexCos[i], delta);
}
@@ -704,8 +724,8 @@ static void correctivesmooth_modifier_do(ModifierData *md,
/* when the modifier fails to execute */
error:
- MEM_SAFE_FREE(csmd->delta_cache);
- csmd->delta_cache_num = 0;
+ MEM_SAFE_FREE(csmd->delta_cache.deltas);
+ csmd->delta_cache.totverts = 0;
}
static void deformVerts(ModifierData *md,
@@ -717,7 +737,7 @@ static void deformVerts(ModifierData *md,
Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
correctivesmooth_modifier_do(
- md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (unsigned int)numVerts, NULL);
+ md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (uint)numVerts, NULL);
if (mesh_src != mesh) {
BKE_id_free(NULL, mesh_src);
@@ -735,7 +755,7 @@ static void deformVertsEM(ModifierData *md,
ctx->object, editData, mesh, NULL, numVerts, false, false);
correctivesmooth_modifier_do(
- md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (unsigned int)numVerts, editData);
+ md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (uint)numVerts, editData);
if (mesh_src != mesh) {
BKE_id_free(NULL, mesh_src);
diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index bedd6e519eb..f9137572d6f 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -69,7 +69,7 @@ static bool isDisabled(const Scene *UNUSED(scene), ModifierData *md, bool UNUSED
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the curve is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
return !cmd->object || cmd->object->type != OB_CURVE;
}
diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c
index fa60bd2a502..bb032f9725c 100644
--- a/source/blender/modifiers/intern/MOD_datatransfer.c
+++ b/source/blender/modifiers/intern/MOD_datatransfer.c
@@ -146,7 +146,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the mesh is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
return !dtmd->ob_source || dtmd->ob_source->type != OB_MESH;
}
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index cff700e8d45..c113a2767a0 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -140,8 +140,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
MOD_get_vgroup(ctx->object, mesh, dmd->defgrp_name, &dvert, &defgrp_index);
if (dvert) {
- const unsigned int vert_tot = mesh->totvert;
- unsigned int i;
+ const uint vert_tot = mesh->totvert;
+ uint i;
vweights = MEM_malloc_arrayN(vert_tot, sizeof(float), __func__);
@@ -199,7 +199,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
updateFaceCount(ctx, dmd, bm->totface);
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
/* make sure we never alloc'd these */
BLI_assert(bm->vtoolflagpool == NULL && bm->etoolflagpool == NULL && bm->ftoolflagpool == NULL);
BLI_assert(bm->vtable == NULL && bm->etable == NULL && bm->ftable == NULL);
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index ac0d72214c8..9cb694be88b 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -294,6 +294,11 @@ static void displaceModifier_do(DisplaceModifierData *dmd,
mvert = mesh->mvert;
MOD_get_vgroup(ob, mesh, dmd->defgrp_name, &dvert, &defgrp_index);
+ if (defgrp_index >= 0 && dvert == NULL) {
+ /* There is a vertex group, but it has no vertices. */
+ return;
+ }
+
Tex *tex_target = dmd->texture;
if (tex_target != NULL) {
tex_co = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tex_co), "displaceModifier_do tex_co");
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index 59d560b9a4a..69ba4aa2795 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -97,7 +97,7 @@ static Mesh *doEdgeSplit(Mesh *mesh, EdgeSplitModifierData *emd)
/* BM_mesh_validate(bm); */ /* for troubleshooting */
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index 4ed787810a8..5f0bbc8ecf1 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -201,7 +201,7 @@ static void createFacepa(ExplodeModifierData *emd, ParticleSystemModifierData *p
BLI_rng_free(rng);
}
-static int edgecut_get(EdgeHash *edgehash, unsigned int v1, unsigned int v2)
+static int edgecut_get(EdgeHash *edgehash, uint v1, uint v2)
{
return POINTER_AS_INT(BLI_edgehash_lookup(edgehash, v1, v2));
}
@@ -649,7 +649,7 @@ static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh)
int i, v1, v2, v3, v4, esplit, v[4] = {0, 0, 0, 0}, /* To quite gcc barking... */
uv[4] = {0, 0, 0, 0}; /* To quite gcc barking... */
int numlayer;
- unsigned int ed_v1, ed_v2;
+ uint ed_v1, ed_v2;
edgehash = BLI_edgehash_new(__func__);
@@ -906,7 +906,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
const int *facepa = emd->facepa;
int totdup = 0, totvert = 0, totface = 0, totpart = 0, delface = 0;
int i, v, u;
- unsigned int ed_v1, ed_v2, mindex = 0;
+ uint ed_v1, ed_v2, mindex = 0;
MTFace *mtface = NULL, *mtf;
totface = mesh->totface;
@@ -938,10 +938,13 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
continue;
}
}
+ else {
+ pa = NULL;
+ }
/* do mindex + totvert to ensure the vertex index to be the first
* with BLI_edgehashIterator_getKey */
- if (facepa[i] == totpart || cfra < (pars + facepa[i])->time) {
+ if (pa == NULL || cfra < pa->time) {
mindex = totvert + totpart;
}
else {
@@ -1022,6 +1025,9 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
mul_m4_v3(imat, vertco);
}
+ else {
+ pa = NULL;
+ }
}
BLI_edgehashIterator_free(ehi);
@@ -1043,13 +1049,17 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
continue;
}
}
+ else {
+ pa = NULL;
+ }
source = mesh->mface[i];
mf = &explode->mface[u];
orig_v4 = source.v4;
- if (facepa[i] != totpart && cfra < pa->time) {
+ /* Same as above in the first loop over mesh's faces. */
+ if (pa == NULL || cfra < pa->time) {
mindex = totvert + totpart;
}
else {
@@ -1069,7 +1079,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
/* override uv channel for particle age */
if (mtface) {
- float age = (cfra - pa->time) / pa->lifetime;
+ float age = (pa != NULL) ? (cfra - pa->time) / pa->lifetime : 0.0f;
/* Clamp to this range to avoid flipping to the other side of the coordinates. */
CLAMP(age, 0.001f, 0.999f);
diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.c b/source/blender/modifiers/intern/MOD_fluidsim_util.c
index 587aa108fd1..748bf4db4e2 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim_util.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim_util.c
@@ -513,6 +513,12 @@ static Mesh *fluidsim_read_cache(
return NULL;
}
+ BKE_mesh_copy_settings(newmesh, orgmesh);
+
+ /* Fluid simulation has a texture space that based on the bounds of the fluid mesh.
+ * This does not seem particularly useful, but it's backwards compatible. */
+ BKE_mesh_texspace_calc(newmesh);
+
/* load vertex velocities, if they exist...
* TODO? use generate flag as loading flag as well?
* warning, needs original .bobj.gz mesh loading filename */
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index 2f902db9340..1a62010abe7 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -136,8 +136,8 @@ struct HookData_cb {
float falloff_sq;
float fac_orig;
- unsigned int use_falloff : 1;
- unsigned int use_uniform : 1;
+ uint use_falloff : 1;
+ uint use_uniform : 1;
float cent[3];
diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c
index c9e0171c9f2..0fc2e0971da 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -66,7 +66,7 @@ typedef struct LaplacianSystem {
float (*co)[3]; /* Original vertex coordinates */
float (*no)[3]; /* Original vertex normal */
float (*delta)[3]; /* Differential Coordinates */
- unsigned int (*tris)[3]; /* Copy of MLoopTri (tessellation triangle) v1-v3 */
+ uint (*tris)[3]; /* Copy of MLoopTri (tessellation triangle) v1-v3 */
int *index_anchors; /* Static vertex index list */
int *unit_verts; /* Unit vectors of projected edges onto the plane orthogonal to n */
int *ringf_indices; /* Indices of faces per vertex */
@@ -153,7 +153,7 @@ static void createFaceRingMap(const int mvert_tot,
for (i = 0, mlt = mlooptri; i < mtri_tot; i++, mlt++) {
for (j = 0; j < 3; j++) {
- const unsigned int v_index = mloop[mlt->tri[j]].v;
+ const uint v_index = mloop[mlt->tri[j]].v;
map[v_index].count++;
totalr++;
}
@@ -167,7 +167,7 @@ static void createFaceRingMap(const int mvert_tot,
}
for (i = 0, mlt = mlooptri; i < mtri_tot; i++, mlt++) {
for (j = 0; j < 3; j++) {
- const unsigned int v_index = mloop[mlt->tri[j]].v;
+ const uint v_index = mloop[mlt->tri[j]].v;
map[v_index].indices[map[v_index].count] = i;
map[v_index].count++;
}
@@ -253,7 +253,7 @@ static void initLaplacianMatrix(LaplacianSystem *sys)
int idv[3];
for (ti = 0; ti < sys->total_tris; ti++) {
- const unsigned int *vidt = sys->tris[ti];
+ const uint *vidt = sys->tris[ti];
const float *co[3];
co[0] = sys->co[vidt[0]];
@@ -352,7 +352,7 @@ static void rotateDifferentialCoordinates(LaplacianSystem *sys)
zero_v3(ni);
num_fni = sys->ringf_map[i].count;
for (fi = 0; fi < num_fni; fi++) {
- const unsigned int *vin;
+ const uint *vin;
fidn = sys->ringf_map[i].indices;
vin = sys->tris[fidn[fi]];
for (j = 0; j < 3; j++) {
diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
index 4a86c26cdeb..86d4124e5db 100644
--- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c
+++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
@@ -199,7 +199,7 @@ static void init_laplacian_matrix(LaplacianSystem *sys)
float w1, w2, w3;
float areaf;
int i;
- unsigned int idv1, idv2;
+ uint idv1, idv2;
for (i = 0; i < sys->numEdges; i++) {
idv1 = sys->medges[i].v1;
@@ -233,7 +233,7 @@ static void init_laplacian_matrix(LaplacianSystem *sys)
const float *v_prev = sys->vertexCos[l_prev->v];
const float *v_curr = sys->vertexCos[l_curr->v];
const float *v_next = sys->vertexCos[l_next->v];
- const unsigned int l_curr_index = l_curr - sys->mloop;
+ const uint l_curr_index = l_curr - sys->mloop;
sys->numNeFa[l_curr->v] += 1;
@@ -274,7 +274,7 @@ static void init_laplacian_matrix(LaplacianSystem *sys)
static void fill_laplacian_matrix(LaplacianSystem *sys)
{
int i;
- unsigned int idv1, idv2;
+ uint idv1, idv2;
for (i = 0; i < sys->numPolys; i++) {
const MPoly *mp = &sys->mpoly[i];
@@ -284,7 +284,7 @@ static void fill_laplacian_matrix(LaplacianSystem *sys)
const MLoop *l_curr = l_term - 1;
for (; l_next != l_term; l_prev = l_curr, l_curr = l_next, l_next++) {
- const unsigned int l_curr_index = l_curr - sys->mloop;
+ const uint l_curr_index = l_curr - sys->mloop;
/* Is ring if number of faces == number of edges around vertice*/
if (sys->numNeEd[l_curr->v] == sys->numNeFa[l_curr->v] && sys->zerola[l_curr->v] == 0) {
diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c
index aca5b43a7d5..a73e96da975 100644
--- a/source/blender/modifiers/intern/MOD_lattice.c
+++ b/source/blender/modifiers/intern/MOD_lattice.c
@@ -67,7 +67,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the lattice is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
return !lmd->object || lmd->object->type != OB_LATTICE;
}
diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c
index bc218114432..cf7d227e898 100644
--- a/source/blender/modifiers/intern/MOD_mask.c
+++ b/source/blender/modifiers/intern/MOD_mask.c
@@ -160,7 +160,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
* (including selected matches only):
* key = oldindex, value = newindex
*/
- vertHash = BLI_ghash_int_new_ex("mask vert gh", (unsigned int)maxVerts);
+ vertHash = BLI_ghash_int_new_ex("mask vert gh", (uint)maxVerts);
/* add vertices which exist in vertexgroups into vertHash for filtering
* - dv = for each vertex, what vertexgroups does it belong to
@@ -204,7 +204,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
- vertHash = BLI_ghash_int_new_ex("mask vert2 bh", (unsigned int)maxVerts);
+ vertHash = BLI_ghash_int_new_ex("mask vert2 bh", (uint)maxVerts);
/* add vertices which exist in vertexgroup into ghash for filtering */
for (i = 0, dv = dvert; i < maxVerts; i++, dv++) {
@@ -220,8 +220,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
- edgeHash = BLI_ghash_int_new_ex("mask ed2 gh", (unsigned int)maxEdges);
- polyHash = BLI_ghash_int_new_ex("mask fa2 gh", (unsigned int)maxPolys);
+ edgeHash = BLI_ghash_int_new_ex("mask ed2 gh", (uint)maxEdges);
+ polyHash = BLI_ghash_int_new_ex("mask fa2 gh", (uint)maxPolys);
mvert_src = mesh->mvert;
medge_src = mesh->medge;
@@ -353,7 +353,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the armature is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
return mmd->ob_arm && mmd->ob_arm->type != OB_ARMATURE;
}
diff --git a/source/blender/modifiers/intern/MOD_meshcache_mdd.c b/source/blender/modifiers/intern/MOD_meshcache_mdd.c
index 16a118522c5..a3ab0120ff9 100644
--- a/source/blender/modifiers/intern/MOD_meshcache_mdd.c
+++ b/source/blender/modifiers/intern/MOD_meshcache_mdd.c
@@ -168,7 +168,7 @@ bool MOD_meshcache_read_mdd_index(FILE *fp,
if (factor >= 1.0f) {
#if 1
float *vco = *vertexCos;
- unsigned int i;
+ uint i;
for (i = mdd_head.verts_tot; i != 0; i--, vco += 3) {
fread(vco, sizeof(float) * 3, 1, fp);
@@ -192,7 +192,7 @@ bool MOD_meshcache_read_mdd_index(FILE *fp,
else {
const float ifactor = 1.0f - factor;
float *vco = *vertexCos;
- unsigned int i;
+ uint i;
for (i = mdd_head.verts_tot; i != 0; i--, vco += 3) {
float tvec[3];
fread(tvec, sizeof(float) * 3, 1, fp);
diff --git a/source/blender/modifiers/intern/MOD_meshcache_pc2.c b/source/blender/modifiers/intern/MOD_meshcache_pc2.c
index 97a8635ac9e..7b8ad0bd705 100644
--- a/source/blender/modifiers/intern/MOD_meshcache_pc2.c
+++ b/source/blender/modifiers/intern/MOD_meshcache_pc2.c
@@ -153,7 +153,7 @@ bool MOD_meshcache_read_pc2_index(FILE *fp,
if (factor >= 1.0f) {
float *vco = *vertexCos;
- unsigned int i;
+ uint i;
for (i = pc2_head.verts_tot; i != 0; i--, vco += 3) {
fread(vco, sizeof(float) * 3, 1, fp);
@@ -167,7 +167,7 @@ bool MOD_meshcache_read_pc2_index(FILE *fp,
else {
const float ifactor = 1.0f - factor;
float *vco = *vertexCos;
- unsigned int i;
+ uint i;
for (i = pc2_head.verts_tot; i != 0; i--, vco += 3) {
float tvec[3];
fread(tvec, sizeof(float) * 3, 1, fp);
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index 7ddce983c2a..408e38f43ab 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -142,7 +142,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the mesh is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
return !mmd->object || mmd->object->type != OB_MESH;
}
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index 11f001d7a85..47f8528ee94 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -30,6 +30,7 @@
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_mesh.h"
+#include "BKE_mirror.h"
#include "BKE_modifier.h"
#include "BKE_deform.h"
@@ -68,374 +69,6 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
}
}
-static Mesh *doBiscetOnMirrorPlane(
- MirrorModifierData *mmd, const Mesh *mesh, int axis, float plane_co[3], float plane_no[3])
-{
- bool do_bisect_flip_axis = ((axis == 0 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_X) ||
- (axis == 1 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Y) ||
- (axis == 2 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Z));
-
- const float bisect_distance = 0.001f;
-
- Mesh *result;
- BMesh *bm;
- BMIter viter;
- BMVert *v, *v_next;
-
- bm = BKE_mesh_to_bmesh_ex(mesh,
- &(struct BMeshCreateParams){0},
- &(struct BMeshFromMeshParams){
- .calc_face_normal = true,
- .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX,
- .emask = CD_MASK_ORIGINDEX,
- .pmask = CD_MASK_ORIGINDEX},
- });
-
- /* Define bisecting plane (aka mirror plane). */
- float plane[4];
- if (!do_bisect_flip_axis) {
- /* That reversed condition is a tad weird, but for some reason that's how you keep
- * the part of the mesh which is on the non-mirrored side when flip option is disabled,
- * think that that is the expected behavior. */
- negate_v3(plane_no);
- }
- plane_from_point_normal_v3(plane, plane_co, plane_no);
-
- BM_mesh_bisect_plane(bm, plane, false, false, 0, 0, bisect_distance);
-
- /* Plane definitions for vert killing. */
- float plane_offset[4];
- copy_v3_v3(plane_offset, plane);
- plane_offset[3] = plane[3] - bisect_distance;
-
- /* Delete verts across the mirror plane. */
- BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) {
- if (plane_point_side_v3(plane_offset, v->co) > 0.0f) {
- BM_vert_kill(bm, v);
- }
- }
-
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
- BM_mesh_free(bm);
-
- return result;
-}
-
-static Mesh *doMirrorOnAxis(MirrorModifierData *mmd,
- const ModifierEvalContext *UNUSED(ctx),
- Object *ob,
- const Mesh *mesh,
- int axis)
-{
- const float tolerance_sq = mmd->tolerance * mmd->tolerance;
- const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0;
- int tot_vtargetmap = 0; /* total merge vertices */
-
- const bool do_bisect = ((axis == 0 && mmd->flag & MOD_MIR_BISECT_AXIS_X) ||
- (axis == 1 && mmd->flag & MOD_MIR_BISECT_AXIS_Y) ||
- (axis == 2 && mmd->flag & MOD_MIR_BISECT_AXIS_Z));
-
- Mesh *result;
- MVert *mv, *mv_prev;
- MEdge *me;
- MLoop *ml;
- MPoly *mp;
- float mtx[4][4];
- float plane_co[3], plane_no[3];
- int i;
- int a, totshape;
- int *vtargetmap = NULL, *vtmap_a = NULL, *vtmap_b = NULL;
-
- /* mtx is the mirror transformation */
- unit_m4(mtx);
- mtx[axis][axis] = -1.0f;
-
- Object *mirror_ob = mmd->mirror_ob;
- if (mirror_ob != NULL) {
- float tmp[4][4];
- float itmp[4][4];
-
- /* tmp is a transform from coords relative to the object's own origin,
- * to coords relative to the mirror object origin */
- invert_m4_m4(tmp, mirror_ob->obmat);
- mul_m4_m4m4(tmp, tmp, ob->obmat);
-
- /* itmp is the reverse transform back to origin-relative coordinates */
- invert_m4_m4(itmp, tmp);
-
- /* combine matrices to get a single matrix that translates coordinates into
- * mirror-object-relative space, does the mirror, and translates back to
- * origin-relative space */
- mul_m4_series(mtx, itmp, mtx, tmp);
-
- if (do_bisect) {
- copy_v3_v3(plane_co, itmp[3]);
- copy_v3_v3(plane_no, itmp[axis]);
- }
- }
- else if (do_bisect) {
- copy_v3_v3(plane_co, mtx[3]);
- /* Need to negate here, since that axis is inverted (for mirror transform). */
- negate_v3_v3(plane_no, mtx[axis]);
- }
-
- Mesh *mesh_bisect = NULL;
- if (do_bisect) {
- mesh_bisect = doBiscetOnMirrorPlane(mmd, mesh, axis, plane_co, plane_no);
- mesh = mesh_bisect;
- }
-
- const int maxVerts = mesh->totvert;
- const int maxEdges = mesh->totedge;
- const int maxLoops = mesh->totloop;
- const int maxPolys = mesh->totpoly;
-
- result = BKE_mesh_new_nomain_from_template(
- mesh, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2);
-
- /*copy customdata to original geometry*/
- CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, maxVerts);
- CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, maxEdges);
- CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, maxLoops);
- CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, maxPolys);
-
- /* Subsurf for eg won't have mesh data in the custom data arrays.
- * now add mvert/medge/mpoly layers. */
- if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) {
- memcpy(result->mvert, mesh->mvert, sizeof(*result->mvert) * mesh->totvert);
- }
- if (!CustomData_has_layer(&mesh->edata, CD_MEDGE)) {
- memcpy(result->medge, mesh->medge, sizeof(*result->medge) * mesh->totedge);
- }
- if (!CustomData_has_layer(&mesh->pdata, CD_MPOLY)) {
- memcpy(result->mloop, mesh->mloop, sizeof(*result->mloop) * mesh->totloop);
- memcpy(result->mpoly, mesh->mpoly, sizeof(*result->mpoly) * mesh->totpoly);
- }
-
- /* copy customdata to new geometry,
- * copy from its self because this data may have been created in the checks above */
- CustomData_copy_data(&result->vdata, &result->vdata, 0, maxVerts, maxVerts);
- CustomData_copy_data(&result->edata, &result->edata, 0, maxEdges, maxEdges);
- /* loops are copied later */
- CustomData_copy_data(&result->pdata, &result->pdata, 0, maxPolys, maxPolys);
-
- if (do_vtargetmap) {
- /* second half is filled with -1 */
- vtargetmap = MEM_malloc_arrayN(maxVerts, 2 * sizeof(int), "MOD_mirror tarmap");
-
- vtmap_a = vtargetmap;
- vtmap_b = vtargetmap + maxVerts;
- }
-
- /* mirror vertex coordinates */
- mv_prev = result->mvert;
- mv = mv_prev + maxVerts;
- for (i = 0; i < maxVerts; i++, mv++, mv_prev++) {
- mul_m4_v3(mtx, mv->co);
-
- if (do_vtargetmap) {
- /* compare location of the original and mirrored vertex, to see if they
- * should be mapped for merging */
- if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
- *vtmap_a = maxVerts + i;
- tot_vtargetmap++;
-
- /* average location */
- mid_v3_v3v3(mv->co, mv_prev->co, mv->co);
- copy_v3_v3(mv_prev->co, mv->co);
- }
- else {
- *vtmap_a = -1;
- }
-
- *vtmap_b = -1; /* fill here to avoid 2x loops */
-
- vtmap_a++;
- vtmap_b++;
- }
- }
-
- /* handle shape keys */
- totshape = CustomData_number_of_layers(&result->vdata, CD_SHAPEKEY);
- for (a = 0; a < totshape; a++) {
- float(*cos)[3] = CustomData_get_layer_n(&result->vdata, CD_SHAPEKEY, a);
- for (i = maxVerts; i < result->totvert; i++) {
- mul_m4_v3(mtx, cos[i]);
- }
- }
-
- /* adjust mirrored edge vertex indices */
- me = result->medge + maxEdges;
- for (i = 0; i < maxEdges; i++, me++) {
- me->v1 += maxVerts;
- me->v2 += maxVerts;
- }
-
- /* adjust mirrored poly loopstart indices, and reverse loop order (normals) */
- mp = result->mpoly + maxPolys;
- ml = result->mloop;
- for (i = 0; i < maxPolys; i++, mp++) {
- MLoop *ml2;
- int j, e;
-
- /* reverse the loop, but we keep the first vertex in the face the same,
- * to ensure that quads are split the same way as on the other side */
- CustomData_copy_data(
- &result->ldata, &result->ldata, mp->loopstart, mp->loopstart + maxLoops, 1);
-
- for (j = 1; j < mp->totloop; j++) {
- CustomData_copy_data(&result->ldata,
- &result->ldata,
- mp->loopstart + j,
- mp->loopstart + maxLoops + mp->totloop - j,
- 1);
- }
-
- ml2 = ml + mp->loopstart + maxLoops;
- e = ml2[0].e;
- for (j = 0; j < mp->totloop - 1; j++) {
- ml2[j].e = ml2[j + 1].e;
- }
- ml2[mp->totloop - 1].e = e;
-
- mp->loopstart += maxLoops;
- }
-
- /* adjust mirrored loop vertex and edge indices */
- ml = result->mloop + maxLoops;
- for (i = 0; i < maxLoops; i++, ml++) {
- ml->v += maxVerts;
- ml->e += maxEdges;
- }
-
- /* handle uvs,
- * let tessface recalc handle updating the MTFace data */
- if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V) ||
- (is_zero_v2(mmd->uv_offset_copy) == false)) {
- const bool do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0;
- const bool do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0;
-
- const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV);
-
- for (a = 0; a < totuv; a++) {
- MLoopUV *dmloopuv = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, a);
- int j = maxLoops;
- dmloopuv += j; /* second set of loops only */
- for (; j-- > 0; dmloopuv++) {
- if (do_mirr_u) {
- dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0] + mmd->uv_offset[0];
- }
- if (do_mirr_v) {
- dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1] + mmd->uv_offset[1];
- }
- dmloopuv->uv[0] += mmd->uv_offset_copy[0];
- dmloopuv->uv[1] += mmd->uv_offset_copy[1];
- }
- }
- }
-
- /* handle custom split normals */
- if (ob->type == OB_MESH && (((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) &&
- CustomData_has_layer(&result->ldata, CD_CUSTOMLOOPNORMAL)) {
- const int totloop = result->totloop;
- const int totpoly = result->totpoly;
- float(*loop_normals)[3] = MEM_calloc_arrayN((size_t)totloop, sizeof(*loop_normals), __func__);
- CustomData *ldata = &result->ldata;
- short(*clnors)[2] = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
- MLoopNorSpaceArray lnors_spacearr = {NULL};
- float(*poly_normals)[3] = MEM_mallocN(sizeof(*poly_normals) * totpoly, __func__);
-
- /* calculate custom normals into loop_normals, then mirror first half into second half */
-
- BKE_mesh_calc_normals_poly(result->mvert,
- NULL,
- result->totvert,
- result->mloop,
- result->mpoly,
- totloop,
- totpoly,
- poly_normals,
- false);
-
- BKE_mesh_normals_loop_split(result->mvert,
- result->totvert,
- result->medge,
- result->totedge,
- result->mloop,
- loop_normals,
- totloop,
- result->mpoly,
- poly_normals,
- totpoly,
- true,
- mesh->smoothresh,
- &lnors_spacearr,
- clnors,
- NULL);
-
- /* mirroring has to account for loops being reversed in polys in second half */
- mp = result->mpoly;
- for (i = 0; i < maxPolys; i++, mp++) {
- MPoly *mpmirror = result->mpoly + maxPolys + i;
- int j;
-
- for (j = mp->loopstart; j < mp->loopstart + mp->totloop; j++) {
- int mirrorj = mpmirror->loopstart;
- if (j > mp->loopstart) {
- mirrorj += mpmirror->totloop - (j - mp->loopstart);
- }
- copy_v3_v3(loop_normals[mirrorj], loop_normals[j]);
- loop_normals[mirrorj][axis] = -loop_normals[j][axis];
- BKE_lnor_space_custom_normal_to_data(
- lnors_spacearr.lspacearr[mirrorj], loop_normals[mirrorj], clnors[mirrorj]);
- }
- }
-
- MEM_freeN(poly_normals);
- MEM_freeN(loop_normals);
- BKE_lnor_spacearr_free(&lnors_spacearr);
- }
-
- /* handle vgroup stuff */
- if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&result->vdata, CD_MDEFORMVERT)) {
- MDeformVert *dvert = (MDeformVert *)CustomData_get_layer(&result->vdata, CD_MDEFORMVERT) +
- maxVerts;
- int *flip_map = NULL, flip_map_len = 0;
-
- flip_map = defgroup_flip_map(ob, &flip_map_len, false);
-
- if (flip_map) {
- for (i = 0; i < maxVerts; dvert++, i++) {
- /* merged vertices get both groups, others get flipped */
- if (do_vtargetmap && (vtargetmap[i] != -1)) {
- defvert_flip_merged(dvert, flip_map, flip_map_len);
- }
- else {
- defvert_flip(dvert, flip_map, flip_map_len);
- }
- }
-
- MEM_freeN(flip_map);
- }
- }
-
- if (do_vtargetmap) {
- /* slow - so only call if one or more merge verts are found,
- * users may leave this on and not realize there is nothing to merge - campbell */
- if (tot_vtargetmap) {
- result = BKE_mesh_merge_verts(
- result, vtargetmap, tot_vtargetmap, MESH_MERGE_VERTS_DUMP_IF_MAPPED);
- }
- MEM_freeN(vtargetmap);
- }
-
- if (mesh_bisect != NULL) {
- BKE_id_free(NULL, mesh_bisect);
- }
-
- return result;
-}
-
static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
const ModifierEvalContext *ctx,
Object *ob,
@@ -445,11 +78,11 @@ static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
/* check which axes have been toggled and mirror accordingly */
if (mmd->flag & MOD_MIR_AXIS_X) {
- result = doMirrorOnAxis(mmd, ctx, ob, result, 0);
+ result = BKE_mirror_apply_mirror_on_axis(mmd, ctx, ob, result, 0);
}
if (mmd->flag & MOD_MIR_AXIS_Y) {
Mesh *tmp = result;
- result = doMirrorOnAxis(mmd, ctx, ob, result, 1);
+ result = BKE_mirror_apply_mirror_on_axis(mmd, ctx, ob, result, 1);
if (tmp != mesh) {
/* free intermediate results */
BKE_id_free(NULL, tmp);
@@ -457,7 +90,7 @@ static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
}
if (mmd->flag & MOD_MIR_AXIS_Z) {
Mesh *tmp = result;
- result = doMirrorOnAxis(mmd, ctx, ob, result, 2);
+ result = BKE_mirror_apply_mirror_on_axis(mmd, ctx, ob, result, 2);
if (tmp != mesh) {
/* free intermediate results */
BKE_id_free(NULL, tmp);
diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c
index c64d9be1158..53bb579128a 100644
--- a/source/blender/modifiers/intern/MOD_multires.c
+++ b/source/blender/modifiers/intern/MOD_multires.c
@@ -38,6 +38,7 @@
#include "BKE_paint.h"
#include "BKE_subdiv.h"
#include "BKE_subdiv_ccg.h"
+#include "BKE_subdiv_deform.h"
#include "BKE_subdiv_mesh.h"
#include "BKE_subsurf.h"
@@ -168,6 +169,10 @@ static Mesh *multires_as_ccg(MultiresModifierData *mmd,
static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result = mesh;
+#if !defined(WITH_OPENSUBDIV)
+ modifier_setError(md, "Disabled, built without OpenSubdiv");
+ return result;
+#endif
MultiresModifierData *mmd = (MultiresModifierData *)md;
SubdivSettings subdiv_settings;
BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
@@ -223,6 +228,36 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
return result;
}
+static void deformVerts(ModifierData *md,
+ const ModifierEvalContext *UNUSED(ctx),
+ Mesh *mesh,
+ float (*vertex_cos)[3],
+ int num_verts)
+{
+#if !defined(WITH_OPENSUBDIV)
+ modifier_setError(md, "Disabled, built without OpenSubdiv");
+ return;
+#endif
+ MultiresModifierData *mmd = (MultiresModifierData *)md;
+ SubdivSettings subdiv_settings;
+ BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
+ if (subdiv_settings.level == 0) {
+ return;
+ }
+ BKE_subdiv_settings_validate_for_mesh(&subdiv_settings, mesh);
+ MultiresRuntimeData *runtime_data = multires_ensure_runtime(mmd);
+ Subdiv *subdiv = subdiv_descriptor_ensure(mmd, &subdiv_settings, mesh);
+ if (subdiv == NULL) {
+ /* Happens on bad topology, ut also on empty input mesh. */
+ return;
+ }
+ BKE_subdiv_displacement_attach_from_multires(subdiv, mesh, mmd);
+ BKE_subdiv_deform_coarse_vertices(subdiv, mesh, vertex_cos, num_verts);
+ if (subdiv != runtime_data->subdiv) {
+ BKE_subdiv_free(subdiv);
+ }
+}
+
ModifierTypeInfo modifierType_Multires = {
/* name */ "Multires",
/* structName */ "MultiresModifierData",
@@ -233,7 +268,7 @@ ModifierTypeInfo modifierType_Multires = {
/* copyData */ copyData,
- /* deformVerts */ NULL,
+ /* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index aff5b8b071b..97be42367d4 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -268,7 +268,7 @@ static void generate_ocean_geometry_uvs(void *__restrict userdata,
}
}
-static Mesh *generate_ocean_geometry(OceanModifierData *omd)
+static Mesh *generate_ocean_geometry(OceanModifierData *omd, Mesh *mesh_orig)
{
Mesh *result;
@@ -296,6 +296,7 @@ static Mesh *generate_ocean_geometry(OceanModifierData *omd)
gogd.sy /= gogd.ry;
result = BKE_mesh_new_nomain(num_verts, 0, 0, num_polys * 4, num_polys);
+ BKE_mesh_copy_settings(result, mesh_orig);
gogd.mverts = result->mvert;
gogd.mpolys = result->mpoly;
@@ -377,7 +378,7 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes
}
if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) {
- result = generate_ocean_geometry(omd);
+ result = generate_ocean_geometry(omd, mesh);
BKE_mesh_ensure_normals(result);
}
else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) {
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index 01f1aeffdb2..49bb8691764 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -83,7 +83,7 @@ static bool isDisabled(const struct Scene *scene, ModifierData *md, bool useRend
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the mesh is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
if (!pimd->ob || pimd->ob->type != OB_MESH) {
return true;
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index a7c7c207cd6..67a64921bbc 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -168,7 +168,7 @@ static void deformVerts(ModifierData *md,
if (em) {
/* In edit mode get directly from the edit mesh. */
- psmd->mesh_original = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL);
+ psmd->mesh_original = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, mesh);
}
else {
/* Otherwise get regular mesh. */
diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c
index 631401d9d9e..df84f3db55c 100644
--- a/source/blender/modifiers/intern/MOD_remesh.c
+++ b/source/blender/modifiers/intern/MOD_remesh.c
@@ -185,6 +185,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *UNUSED(c
}
}
+ BKE_mesh_copy_settings(result, mesh);
BKE_mesh_calc_edges(result, true, false);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
return result;
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index ac47422fe2f..773cbf72d5b 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -46,18 +46,18 @@
/* used for gathering edge connectivity */
typedef struct ScrewVertConnect {
- float dist; /* distance from the center axis */
- float co[3]; /* location relative to the transformed axis */
- float no[3]; /* calc normal of the vertex */
- unsigned int v[2]; /* 2 verts on either side of this one */
- MEdge *e[2]; /* edges on either side, a bit of a waste since each edge ref's 2 edges */
+ float dist; /* distance from the center axis */
+ float co[3]; /* location relative to the transformed axis */
+ float no[3]; /* calc normal of the vertex */
+ uint v[2]; /* 2 verts on either side of this one */
+ MEdge *e[2]; /* edges on either side, a bit of a waste since each edge ref's 2 edges */
char flag;
} ScrewVertConnect;
typedef struct ScrewVertIter {
ScrewVertConnect *v_array;
ScrewVertConnect *v_poin;
- unsigned int v, v_other;
+ uint v, v_other;
MEdge *e;
} ScrewVertIter;
@@ -67,8 +67,8 @@ typedef struct ScrewVertIter {
static void screwvert_iter_init(ScrewVertIter *iter,
ScrewVertConnect *array,
- unsigned int v_init,
- unsigned int dir)
+ uint v_init,
+ uint dir)
{
iter->v_array = array;
iter->v = v_init;
@@ -187,10 +187,10 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
int *origindex;
int mpoly_index = 0;
- unsigned int step;
- unsigned int i, j;
- unsigned int i1, i2;
- unsigned int step_tot = use_render_params ? ltmd->render_steps : ltmd->steps;
+ uint step;
+ uint i, j;
+ uint i1, i2;
+ uint step_tot = use_render_params ? ltmd->render_steps : ltmd->steps;
const bool do_flip = (ltmd->flag & MOD_SCREW_NORMAL_FLIP) != 0;
const int quad_ord[4] = {
@@ -206,17 +206,16 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
3,
};
- unsigned int maxVerts = 0, maxEdges = 0, maxPolys = 0;
- const unsigned int totvert = (unsigned int)mesh->totvert;
- const unsigned int totedge = (unsigned int)mesh->totedge;
- const unsigned int totpoly = (unsigned int)mesh->totpoly;
+ uint maxVerts = 0, maxEdges = 0, maxPolys = 0;
+ const uint totvert = (uint)mesh->totvert;
+ const uint totedge = (uint)mesh->totedge;
+ const uint totpoly = (uint)mesh->totpoly;
- unsigned int *edge_poly_map = NULL; /* orig edge to orig poly */
- unsigned int *vert_loop_map = NULL; /* orig vert to orig loop */
+ uint *edge_poly_map = NULL; /* orig edge to orig poly */
+ uint *vert_loop_map = NULL; /* orig vert to orig loop */
/* UV Coords */
- const unsigned int mloopuv_layers_tot = (unsigned int)CustomData_number_of_layers(&mesh->ldata,
- CD_MLOOPUV);
+ const uint mloopuv_layers_tot = (uint)CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
MLoopUV **mloopuv_layers = BLI_array_alloca(mloopuv_layers, mloopuv_layers_tot);
float uv_u_scale;
float uv_v_minmax[2] = {FLT_MAX, -FLT_MAX};
@@ -235,11 +234,11 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
float mtx_tx_inv[4][4]; /* inverted */
float mtx_tmp_a[4][4];
- unsigned int vc_tot_linked = 0;
+ uint vc_tot_linked = 0;
short other_axis_1, other_axis_2;
const float *tmpf1, *tmpf2;
- unsigned int edge_offset;
+ uint edge_offset;
MPoly *mpoly_orig, *mpoly_new, *mp_new;
MLoop *mloop_orig, *mloop_new, *ml_new;
@@ -409,7 +408,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
if (mloopuv_layers_tot) {
- unsigned int uv_lay;
+ uint uv_lay;
for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) {
mloopuv_layers[uv_lay] = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, (int)uv_lay);
}
@@ -460,18 +459,18 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
memset(vert_loop_map, 0xff, sizeof(*vert_loop_map) * totvert);
for (i = 0, mp_orig = mpoly_orig; i < totpoly; i++, mp_orig++) {
- unsigned int loopstart = (unsigned int)mp_orig->loopstart;
- unsigned int loopend = loopstart + (unsigned int)mp_orig->totloop;
+ uint loopstart = (uint)mp_orig->loopstart;
+ uint loopend = loopstart + (uint)mp_orig->totloop;
MLoop *ml_orig = &mloop_orig[loopstart];
- unsigned int k;
+ uint k;
for (k = loopstart; k < loopend; k++, ml_orig++) {
edge_poly_map[ml_orig->e] = i;
vert_loop_map[ml_orig->v] = k;
/* also order edges based on faces */
if (medge_new[ml_orig->e].v1 != ml_orig->v) {
- SWAP(unsigned int, medge_new[ml_orig->e].v1, medge_new[ml_orig->e].v2);
+ SWAP(uint, medge_new[ml_orig->e].v1, medge_new[ml_orig->e].v2);
}
}
}
@@ -596,7 +595,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
* so resulting faces are flipped the right way */
vc_tot_linked = 0; /* count the number of linked verts for this loop */
if (vc->flag == 0) {
- unsigned int v_best = SV_UNUSED, ed_loop_closed = 0; /* vert and vert new */
+ uint v_best = SV_UNUSED, ed_loop_closed = 0; /* vert and vert new */
ScrewVertIter lt_iter;
float fl = -1.0f;
@@ -731,7 +730,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
if (lt_iter.v == lt_iter.e->v1) {
if (ed_loop_flip == 0) {
/*printf("\t\t\tFlipping 0\n");*/
- SWAP(unsigned int, lt_iter.e->v1, lt_iter.e->v2);
+ SWAP(uint, lt_iter.e->v1, lt_iter.e->v2);
}
#if 0
else {
@@ -742,7 +741,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
else if (lt_iter.v == lt_iter.e->v2) {
if (ed_loop_flip == 1) {
/*printf("\t\t\tFlipping 1\n");*/
- SWAP(unsigned int, lt_iter.e->v1, lt_iter.e->v2);
+ SWAP(uint, lt_iter.e->v1, lt_iter.e->v2);
}
#if 0
else {
@@ -851,7 +850,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
/* Add Faces */
for (step = 1; step < step_tot; step++) {
- const unsigned int varray_stride = totvert * step;
+ const uint varray_stride = totvert * step;
float step_angle;
float nor_tx[3];
float mat[4][4];
@@ -921,7 +920,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
if (close) {
/* last loop of edges, previous loop doesn't account for the last set of edges */
- const unsigned int varray_stride = (step_tot - 1) * totvert;
+ const uint varray_stride = (step_tot - 1) * totvert;
for (i = 0; i < totvert; i++) {
med_new->v1 = i;
@@ -942,12 +941,12 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
edge_offset = totedge + (totvert * (step_tot - (close ? 0 : 1)));
for (i = 0; i < totedge; i++, med_new_firstloop++) {
- const unsigned int step_last = step_tot - (close ? 1 : 2);
- const unsigned int mpoly_index_orig = totpoly ? edge_poly_map[i] : UINT_MAX;
+ const uint step_last = step_tot - (close ? 1 : 2);
+ const uint mpoly_index_orig = totpoly ? edge_poly_map[i] : UINT_MAX;
const bool has_mpoly_orig = (mpoly_index_orig != UINT_MAX);
float uv_v_offset_a, uv_v_offset_b;
- const unsigned int mloop_index_orig[2] = {
+ const uint mloop_index_orig[2] = {
vert_loop_map ? vert_loop_map[medge_new[i].v1] : UINT_MAX,
vert_loop_map ? vert_loop_map[medge_new[i].v2] : UINT_MAX,
};
@@ -1006,7 +1005,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
&mesh->ldata, &result->ldata, (int)mloop_index_orig[0], l_index + 3, 1);
if (mloopuv_layers_tot) {
- unsigned int uv_lay;
+ uint uv_lay;
const float uv_u_offset_a = (float)(step)*uv_u_scale;
const float uv_u_offset_b = (float)(step + 1) * uv_u_scale;
for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) {
@@ -1023,7 +1022,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
if (mloopuv_layers_tot) {
int l_index = (int)(ml_new - mloop_new);
- unsigned int uv_lay;
+ uint uv_lay;
const float uv_u_offset_a = (float)(step)*uv_u_scale;
const float uv_u_offset_b = (float)(step + 1) * uv_u_scale;
for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) {
@@ -1094,7 +1093,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
unsigned i = 0;
printf("\n");
for (; i < maxPolys * 4; i += 4) {
- unsigned int ii;
+ uint ii;
ml_new = mloop_new + i;
ii = findEd(medge_new, maxEdges, ml_new[0].v, ml_new[1].v);
printf("%d %d -- ", ii, ml_new[0].e);
diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c
index 408ec06a49c..b8d0b19b7bf 100644
--- a/source/blender/modifiers/intern/MOD_shrinkwrap.c
+++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c
@@ -65,8 +65,8 @@ static void requiredDataMask(Object *UNUSED(ob),
if ((smd->shrinkType == MOD_SHRINKWRAP_PROJECT) &&
(smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL)) {
- r_cddata_masks->vmask |=
- CD_MASK_MVERT; /* XXX Really? These should always be present, always... */
+ /* XXX Really? These should always be present, always... */
+ r_cddata_masks->vmask |= CD_MASK_MVERT;
}
}
@@ -79,7 +79,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the mesh is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
if (!smd->target || smd->target->type != OB_MESH) {
return true;
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index 1a541f9fc5a..6e7a0b0dbae 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -103,7 +103,7 @@ typedef struct Frame {
int corner;
/* checked to avoid chaining.
* (merging when we're already been referenced), see T39775 */
- unsigned int is_target : 1;
+ uint is_target : 1;
} merge[4];
/* For hull frames, whether each vertex is detached or not */
@@ -1518,7 +1518,7 @@ static void skin_update_merged_vertices(SkinNode *skin_nodes, int totvert)
{
int v;
- for (v = 0; v < totvert; ++v) {
+ for (v = 0; v < totvert; v++) {
SkinNode *sn = &skin_nodes[v];
int i, j;
@@ -1566,7 +1566,7 @@ static void skin_output_end_nodes(SkinOutput *so, SkinNode *skin_nodes, int totv
{
int v;
- for (v = 0; v < totvert; ++v) {
+ for (v = 0; v < totvert; v++) {
SkinNode *sn = &skin_nodes[v];
/* Assuming here just two frames */
if (sn->flag & SEAM_FRAME) {
@@ -1769,7 +1769,7 @@ static BMesh *build_skin(SkinNode *skin_nodes,
skin_merge_close_frame_verts(skin_nodes, totvert, emap, medge);
/* Write out all frame vertices to the mesh */
- for (v = 0; v < totvert; ++v) {
+ for (v = 0; v < totvert; v++) {
if (skin_nodes[v].totframe) {
output_frames(so.bm, &skin_nodes[v], input_dvert ? &input_dvert[v] : NULL);
}
@@ -1871,7 +1871,7 @@ static Mesh *base_skin(Mesh *origmesh, SkinModifierData *smd)
return NULL;
}
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, origmesh);
BM_mesh_free(bm);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c
index 59d5b2ccbd2..c8bc3aaa484 100644
--- a/source/blender/modifiers/intern/MOD_smooth.c
+++ b/source/blender/modifiers/intern/MOD_smooth.c
@@ -54,16 +54,15 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
bool UNUSED(useRenderParams))
{
SmoothModifierData *smd = (SmoothModifierData *)md;
- short flag;
- flag = smd->flag & (MOD_SMOOTH_X | MOD_SMOOTH_Y | MOD_SMOOTH_Z);
+ const short flag = smd->flag & (MOD_SMOOTH_X | MOD_SMOOTH_Y | MOD_SMOOTH_Z);
/* disable if modifier is off for X, Y and Z or if factor is 0 */
- if ((smd->fac == 0.0f) || flag == 0) {
- return 1;
+ if (smd->fac == 0.0f || flag == 0) {
+ return true;
}
- return 0;
+ return false;
}
static void requiredDataMask(Object *UNUSED(ob),
@@ -81,134 +80,105 @@ static void requiredDataMask(Object *UNUSED(ob),
static void smoothModifier_do(
SmoothModifierData *smd, Object *ob, Mesh *mesh, float (*vertexCos)[3], int numVerts)
{
- MDeformVert *dvert = NULL;
- MEdge *medges = NULL;
-
- int i, j, numDMEdges, defgrp_index;
- unsigned char *uctmp;
- float *ftmp, fac, facm;
+ if (mesh == NULL) {
+ return;
+ }
- ftmp = (float *)MEM_calloc_arrayN(numVerts, 3 * sizeof(float), "smoothmodifier_f");
- if (!ftmp) {
+ float(*accumulated_vecs)[3] = MEM_calloc_arrayN(
+ (size_t)numVerts, sizeof(*accumulated_vecs), __func__);
+ if (!accumulated_vecs) {
return;
}
- uctmp = (unsigned char *)MEM_calloc_arrayN(numVerts, sizeof(unsigned char), "smoothmodifier_uc");
- if (!uctmp) {
- if (ftmp) {
- MEM_freeN(ftmp);
+
+ uint *num_accumulated_vecs = MEM_calloc_arrayN(
+ (size_t)numVerts, sizeof(*num_accumulated_vecs), __func__);
+ if (!num_accumulated_vecs) {
+ if (accumulated_vecs) {
+ MEM_freeN(accumulated_vecs);
}
return;
}
- fac = smd->fac;
- facm = 1 - fac;
+ const float fac_new = smd->fac;
+ const float fac_orig = 1.0f - fac_new;
- if (mesh != NULL) {
- medges = mesh->medge;
- numDMEdges = mesh->totedge;
- }
- else {
- medges = NULL;
- numDMEdges = 0;
- }
+ MEdge *medges = mesh->medge;
+ const int num_edges = mesh->totedge;
+ MDeformVert *dvert;
+ int defgrp_index;
MOD_get_vgroup(ob, mesh, smd->defgrp_name, &dvert, &defgrp_index);
- /* NOTICE: this can be optimized a little bit by moving the
- * if (dvert) out of the loop, if needed */
- for (j = 0; j < smd->repeat; j++) {
- for (i = 0; i < numDMEdges; i++) {
- float fvec[3];
- float *v1, *v2;
- unsigned int idx1, idx2;
-
- idx1 = medges[i].v1;
- idx2 = medges[i].v2;
+ for (int j = 0; j < smd->repeat; j++) {
+ if (j != 0) {
+ memset(accumulated_vecs, 0, sizeof(*accumulated_vecs) * (size_t)numVerts);
+ memset(num_accumulated_vecs, 0, sizeof(*num_accumulated_vecs) * (size_t)numVerts);
+ }
- v1 = vertexCos[idx1];
- v2 = vertexCos[idx2];
+ for (int i = 0; i < num_edges; i++) {
+ float fvec[3];
+ const uint idx1 = medges[i].v1;
+ const uint idx2 = medges[i].v2;
- mid_v3_v3v3(fvec, v1, v2);
+ mid_v3_v3v3(fvec, vertexCos[idx1], vertexCos[idx2]);
- v1 = &ftmp[idx1 * 3];
- v2 = &ftmp[idx2 * 3];
+ num_accumulated_vecs[idx1]++;
+ add_v3_v3(accumulated_vecs[idx1], fvec);
- if (uctmp[idx1] < 255) {
- uctmp[idx1]++;
- add_v3_v3(v1, fvec);
- }
- if (uctmp[idx2] < 255) {
- uctmp[idx2]++;
- add_v3_v3(v2, fvec);
- }
+ num_accumulated_vecs[idx2]++;
+ add_v3_v3(accumulated_vecs[idx2], fvec);
}
+ const short flag = smd->flag;
if (dvert) {
MDeformVert *dv = dvert;
- for (i = 0; i < numVerts; i++, dv++) {
- float f, fm, facw, *fp, *v;
- short flag = smd->flag;
-
- v = vertexCos[i];
- fp = &ftmp[i * 3];
-
- f = defvert_find_weight(dv, defgrp_index);
- if (f <= 0.0f) {
- continue;
+ for (int i = 0; i < numVerts; i++, dv++) {
+ float *vco_orig = vertexCos[i];
+ if (num_accumulated_vecs[0] > 0) {
+ mul_v3_fl(accumulated_vecs[i], 1.0f / (float)num_accumulated_vecs[i]);
}
+ float *vco_new = accumulated_vecs[i];
- f *= fac;
- fm = 1.0f - f;
-
- /* fp is the sum of uctmp[i] verts, so must be averaged */
- facw = 0.0f;
- if (uctmp[i]) {
- facw = f / (float)uctmp[i];
+ const float f_new = defvert_find_weight(dv, defgrp_index) * fac_new;
+ if (f_new <= 0.0f) {
+ continue;
}
+ const float f_orig = 1.0f - f_new;
if (flag & MOD_SMOOTH_X) {
- v[0] = fm * v[0] + facw * fp[0];
+ vco_orig[0] = f_orig * vco_orig[0] + f_new * vco_new[0];
}
if (flag & MOD_SMOOTH_Y) {
- v[1] = fm * v[1] + facw * fp[1];
+ vco_orig[1] = f_orig * vco_orig[1] + f_new * vco_new[1];
}
if (flag & MOD_SMOOTH_Z) {
- v[2] = fm * v[2] + facw * fp[2];
+ vco_orig[2] = f_orig * vco_orig[2] + f_new * vco_new[2];
}
}
}
else { /* no vertex group */
- for (i = 0; i < numVerts; i++) {
- float facw, *fp, *v;
- short flag = smd->flag;
-
- v = vertexCos[i];
- fp = &ftmp[i * 3];
-
- /* fp is the sum of uctmp[i] verts, so must be averaged */
- facw = 0.0f;
- if (uctmp[i]) {
- facw = fac / (float)uctmp[i];
+ for (int i = 0; i < numVerts; i++) {
+ float *vco_orig = vertexCos[i];
+ if (num_accumulated_vecs[0] > 0) {
+ mul_v3_fl(accumulated_vecs[i], 1.0f / (float)num_accumulated_vecs[i]);
}
+ float *vco_new = accumulated_vecs[i];
if (flag & MOD_SMOOTH_X) {
- v[0] = facm * v[0] + facw * fp[0];
+ vco_orig[0] = fac_orig * vco_orig[0] + fac_new * vco_new[0];
}
if (flag & MOD_SMOOTH_Y) {
- v[1] = facm * v[1] + facw * fp[1];
+ vco_orig[1] = fac_orig * vco_orig[1] + fac_new * vco_new[1];
}
if (flag & MOD_SMOOTH_Z) {
- v[2] = facm * v[2] + facw * fp[2];
+ vco_orig[2] = fac_orig * vco_orig[2] + fac_new * vco_new[2];
}
}
}
-
- memset(ftmp, 0, 3 * sizeof(float) * numVerts);
- memset(uctmp, 0, sizeof(unsigned char) * numVerts);
}
- MEM_freeN(ftmp);
- MEM_freeN(uctmp);
+ MEM_freeN(accumulated_vecs);
+ MEM_freeN(num_accumulated_vecs);
}
static void deformVerts(ModifierData *md,
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index 05bcc7f695d..292e659fe03 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -198,11 +198,11 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
MEdge *ed, *medge, *orig_medge;
MLoop *ml, *mloop, *orig_mloop;
MPoly *mp, *mpoly, *orig_mpoly;
- const unsigned int numVerts = (unsigned int)mesh->totvert;
- const unsigned int numEdges = (unsigned int)mesh->totedge;
- const unsigned int numPolys = (unsigned int)mesh->totpoly;
- const unsigned int numLoops = (unsigned int)mesh->totloop;
- unsigned int newLoops = 0, newPolys = 0, newEdges = 0, newVerts = 0, rimVerts = 0;
+ const uint numVerts = (uint)mesh->totvert;
+ const uint numEdges = (uint)mesh->totedge;
+ const uint numPolys = (uint)mesh->totpoly;
+ const uint numLoops = (uint)mesh->totloop;
+ uint newLoops = 0, newPolys = 0, newEdges = 0, newVerts = 0, rimVerts = 0;
/* only use material offsets if we have 2 or more materials */
const short mat_nr_max = ctx->object->totcol > 1 ? ctx->object->totcol - 1 : 0;
@@ -211,16 +211,16 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
/* use for edges */
/* over-alloc new_vert_arr, old_vert_arr */
- unsigned int *new_vert_arr = NULL;
+ uint *new_vert_arr = NULL;
STACK_DECLARE(new_vert_arr);
- unsigned int *new_edge_arr = NULL;
+ uint *new_edge_arr = NULL;
STACK_DECLARE(new_edge_arr);
- unsigned int *old_vert_arr = MEM_calloc_arrayN(
+ uint *old_vert_arr = MEM_calloc_arrayN(
numVerts, sizeof(*old_vert_arr), "old_vert_arr in solidify");
- unsigned int *edge_users = NULL;
+ uint *edge_users = NULL;
char *edge_order = NULL;
float(*vert_nors)[3] = NULL;
@@ -244,7 +244,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
int defgrp_index;
/* array size is doubled in case of using a shell */
- const unsigned int stride = do_shell ? 2 : 1;
+ const uint stride = do_shell ? 2 : 1;
MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index);
@@ -272,11 +272,11 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
if (smd->flag & MOD_SOLIDIFY_RIM) {
BLI_bitmap *orig_mvert_tag = BLI_BITMAP_NEW(numVerts, __func__);
- unsigned int eidx;
- unsigned int i;
+ uint eidx;
+ uint i;
-#define INVALID_UNUSED ((unsigned int)-1)
-#define INVALID_PAIR ((unsigned int)-2)
+#define INVALID_UNUSED ((uint)-1)
+#define INVALID_PAIR ((uint)-2)
new_vert_arr = MEM_malloc_arrayN(numVerts, 2 * sizeof(*new_vert_arr), __func__);
new_edge_arr = MEM_malloc_arrayN(((numEdges * 2) + numVerts), sizeof(*new_edge_arr), __func__);
@@ -442,13 +442,13 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
/* flip normals */
if (do_shell) {
- unsigned int i;
+ uint i;
mp = mpoly + numPolys;
for (i = 0; i < mesh->totpoly; i++, mp++) {
const int loop_end = mp->totloop - 1;
MLoop *ml2;
- unsigned int e;
+ uint e;
int j;
/* reverses the loop direction (MLoop.v as well as custom-data)
@@ -512,7 +512,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
const float offset_sq = offset * offset;
if (do_clamp) {
- unsigned int i;
+ uint i;
vert_lens = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_lens");
copy_vn_fl(vert_lens, (int)numVerts, FLT_MAX);
@@ -524,7 +524,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
if (ofs_new != 0.0f) {
- unsigned int i_orig, i_end;
+ uint i_orig, i_end;
bool do_shell_align;
scalar_short = scalar_short_vgroup = ofs_new / 32767.0f;
@@ -532,7 +532,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
INIT_VERT_ARRAY_OFFSETS(false);
for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
- const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig];
+ const uint i = do_shell_align ? i_orig : new_vert_arr[i_orig];
if (dvert) {
MDeformVert *dv = &dvert[i];
if (defgrp_invert) {
@@ -559,7 +559,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
if (ofs_orig != 0.0f) {
- unsigned int i_orig, i_end;
+ uint i_orig, i_end;
bool do_shell_align;
scalar_short = scalar_short_vgroup = ofs_orig / 32767.0f;
@@ -568,7 +568,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
INIT_VERT_ARRAY_OFFSETS(true);
for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
- const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig];
+ const uint i = do_shell_align ? i_orig : new_vert_arr[i_orig];
if (dvert) {
MDeformVert *dv = &dvert[i];
if (defgrp_invert) {
@@ -606,8 +606,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
float *vert_angles = MEM_calloc_arrayN(
numVerts, 2 * sizeof(float), "mod_solid_pair"); /* 2 in 1 */
float *vert_accum = vert_angles + numVerts;
- unsigned int vidx;
- unsigned int i;
+ uint vidx;
+ uint i;
if (vert_nors == NULL) {
vert_nors = MEM_malloc_arrayN(numVerts, 3 * sizeof(float), "mod_solid_vno");
@@ -707,13 +707,13 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
if (ofs_new != 0.0f) {
- unsigned int i_orig, i_end;
+ uint i_orig, i_end;
bool do_shell_align;
INIT_VERT_ARRAY_OFFSETS(false);
for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
- const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
+ const uint i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
if (vert_accum[i_other]) { /* zero if unselected */
madd_v3_v3fl(
mv->co, vert_nors[i_other], ofs_new * (vert_angles[i_other] / vert_accum[i_other]));
@@ -722,14 +722,14 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
if (ofs_orig != 0.0f) {
- unsigned int i_orig, i_end;
+ uint i_orig, i_end;
bool do_shell_align;
/* same as above but swapped, intentional use of 'ofs_new' */
INIT_VERT_ARRAY_OFFSETS(true);
for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
- const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
+ const uint i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
if (vert_accum[i_other]) { /* zero if unselected */
madd_v3_v3fl(
mv->co, vert_nors[i_other], ofs_orig * (vert_angles[i_other] / vert_accum[i_other]));
@@ -749,7 +749,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
else if (do_shell) {
- unsigned int i;
+ uint i;
/* flip vertex normals for copied verts */
mv = mvert + numVerts;
for (i = 0; i < numVerts; i++, mv++) {
@@ -758,7 +758,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
if (smd->flag & MOD_SOLIDIFY_RIM) {
- unsigned int i;
+ uint i;
/* bugger, need to re-calculate the normals for the new edge faces.
* This could be done in many ways, but probably the quickest way
@@ -781,13 +781,13 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
NULL;
float nor[3];
#endif
- const unsigned char crease_rim = smd->crease_rim * 255.0f;
- const unsigned char crease_outer = smd->crease_outer * 255.0f;
- const unsigned char crease_inner = smd->crease_inner * 255.0f;
+ const uchar crease_rim = smd->crease_rim * 255.0f;
+ const uchar crease_outer = smd->crease_outer * 255.0f;
+ const uchar crease_inner = smd->crease_inner * 255.0f;
int *origindex_edge;
int *orig_ed;
- unsigned int j;
+ uint j;
if (crease_rim || crease_outer || crease_inner) {
result->cd_flag |= ME_CDFLAG_EDGE_CREASE;
@@ -817,8 +817,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
ml = mloop + (numLoops * stride);
j = 0;
for (i = 0; i < newPolys; i++, mp++) {
- unsigned int eidx = new_edge_arr[i];
- unsigned int pidx = edge_users[eidx];
+ uint eidx = new_edge_arr[i];
+ uint pidx = edge_users[eidx];
int k1, k2;
bool flip;
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index 0b1249e263c..55df1b5ddda 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -35,6 +35,7 @@
#include "BKE_scene.h"
#include "BKE_subdiv.h"
#include "BKE_subdiv_ccg.h"
+#include "BKE_subdiv_deform.h"
#include "BKE_subdiv_mesh.h"
#include "BKE_subsurf.h"
@@ -208,6 +209,10 @@ static SubsurfRuntimeData *subsurf_ensure_runtime(SubsurfModifierData *smd)
static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result = mesh;
+#if !defined(WITH_OPENSUBDIV)
+ modifier_setError(md, "Disabled, built without OpenSubdiv");
+ return result;
+#endif
SubsurfModifierData *smd = (SubsurfModifierData *)md;
SubdivSettings subdiv_settings;
subdiv_settings_init(&subdiv_settings, smd);
@@ -236,6 +241,35 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
return result;
}
+static void deformVerts(ModifierData *md,
+ const ModifierEvalContext *UNUSED(ctx),
+ Mesh *mesh,
+ float (*vertex_cos)[3],
+ int num_verts)
+{
+#if !defined(WITH_OPENSUBDIV)
+ modifier_setError(md, "Disabled, built without OpenSubdiv");
+ return;
+#endif
+ SubsurfModifierData *smd = (SubsurfModifierData *)md;
+ SubdivSettings subdiv_settings;
+ subdiv_settings_init(&subdiv_settings, smd);
+ if (subdiv_settings.level == 0) {
+ return;
+ }
+ BKE_subdiv_settings_validate_for_mesh(&subdiv_settings, mesh);
+ SubsurfRuntimeData *runtime_data = subsurf_ensure_runtime(smd);
+ Subdiv *subdiv = subdiv_descriptor_ensure(smd, &subdiv_settings, mesh);
+ if (subdiv == NULL) {
+ /* Happens on bad topology, but also on empty input mesh. */
+ return;
+ }
+ BKE_subdiv_deform_coarse_vertices(subdiv, mesh, vertex_cos, num_verts);
+ if (subdiv != runtime_data->subdiv) {
+ BKE_subdiv_free(subdiv);
+ }
+}
+
ModifierTypeInfo modifierType_Subsurf = {
/* name */ "Subdivision",
/* structName */ "SubsurfModifierData",
@@ -247,7 +281,7 @@ ModifierTypeInfo modifierType_Subsurf = {
/* copyData */ copyData,
- /* deformVerts */ NULL,
+ /* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c
index 840914aa313..97e6bb9e804 100644
--- a/source/blender/modifiers/intern/MOD_surface.c
+++ b/source/blender/modifiers/intern/MOD_surface.c
@@ -125,7 +125,7 @@ static void deformVerts(ModifierData *md,
}
if (surmd->mesh) {
- unsigned int numverts = 0, i = 0;
+ uint numverts = 0, i = 0;
int init = 0;
float *vec;
MVert *x, *v;
diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c
index 93196ea21fb..de32b90a5e3 100644
--- a/source/blender/modifiers/intern/MOD_surfacedeform.c
+++ b/source/blender/modifiers/intern/MOD_surfacedeform.c
@@ -45,16 +45,16 @@
typedef struct SDefAdjacency {
struct SDefAdjacency *next;
- unsigned int index;
+ uint index;
} SDefAdjacency;
typedef struct SDefAdjacencyArray {
SDefAdjacency *first;
- unsigned int num; /* Careful, this is twice the number of polygons (avoids an extra loop) */
+ uint num; /* Careful, this is twice the number of polygons (avoids an extra loop) */
} SDefAdjacencyArray;
typedef struct SDefEdgePolys {
- unsigned int polys[2], num;
+ uint polys[2], num;
} SDefEdgePolys;
typedef struct SDefBindCalcData {
@@ -90,20 +90,20 @@ typedef struct SDefBindPoly {
float point_edgemid_angles[2];
float corner_edgemid_angles[2];
float dominant_angle_weight;
- unsigned int index;
- unsigned int numverts;
- unsigned int loopstart;
- unsigned int edge_inds[2];
- unsigned int edge_vert_inds[2];
- unsigned int corner_ind;
- unsigned int dominant_edge;
+ uint index;
+ uint numverts;
+ uint loopstart;
+ uint edge_inds[2];
+ uint edge_vert_inds[2];
+ uint corner_ind;
+ uint dominant_edge;
bool inside;
} SDefBindPoly;
typedef struct SDefBindWeightData {
SDefBindPoly *bind_polys;
- unsigned int numpoly;
- unsigned int numbinds;
+ uint numpoly;
+ uint numbinds;
} SDefBindWeightData;
typedef struct SDefDeformData {
@@ -217,8 +217,8 @@ static void freeAdjacencyMap(SDefAdjacencyArray *const vert_edges,
static int buildAdjacencyMap(const MPoly *poly,
const MEdge *edge,
const MLoop *const mloop,
- const unsigned int numpoly,
- const unsigned int numedges,
+ const uint numpoly,
+ const uint numedges,
SDefAdjacencyArray *const vert_edges,
SDefAdjacency *adj,
SDefEdgePolys *const edge_polys)
@@ -263,10 +263,10 @@ static int buildAdjacencyMap(const MPoly *poly,
return MOD_SDEF_BIND_RESULT_SUCCESS;
}
-BLI_INLINE void sortPolyVertsEdge(unsigned int *indices,
+BLI_INLINE void sortPolyVertsEdge(uint *indices,
const MLoop *const mloop,
- const unsigned int edge,
- const unsigned int num)
+ const uint edge,
+ const uint num)
{
bool found = false;
@@ -287,10 +287,10 @@ BLI_INLINE void sortPolyVertsEdge(unsigned int *indices,
}
}
-BLI_INLINE void sortPolyVertsTri(unsigned int *indices,
+BLI_INLINE void sortPolyVertsTri(uint *indices,
const MLoop *const mloop,
- const unsigned int loopstart,
- const unsigned int num)
+ const uint loopstart,
+ const uint num)
{
for (int i = loopstart; i < num; i++) {
*indices = mloop[i].v;
@@ -303,7 +303,7 @@ BLI_INLINE void sortPolyVertsTri(unsigned int *indices,
}
}
-BLI_INLINE unsigned int nearestVert(SDefBindCalcData *const data, const float point_co[3])
+BLI_INLINE uint nearestVert(SDefBindCalcData *const data, const float point_co[3])
{
BVHTreeNearest nearest = {
.dist_sq = FLT_MAX,
@@ -315,7 +315,7 @@ BLI_INLINE unsigned int nearestVert(SDefBindCalcData *const data, const float po
float t_point[3];
float max_dist = FLT_MAX;
float dist;
- unsigned int index = 0;
+ uint index = 0;
mul_v3_m4v3(t_point, data->imat, point_co);
@@ -346,7 +346,7 @@ BLI_INLINE unsigned int nearestVert(SDefBindCalcData *const data, const float po
}
}
-BLI_INLINE int isPolyValid(const float coords[][2], const unsigned int nr)
+BLI_INLINE int isPolyValid(const float coords[][2], const uint nr)
{
float prev_co[2];
float curr_vec[2], prev_vec[2];
@@ -408,7 +408,7 @@ BLI_INLINE float computeAngularWeight(const float point_angle, const float edgem
BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data,
const float point_co[3])
{
- const unsigned int nearest = nearestVert(data, point_co);
+ const uint nearest = nearestVert(data, point_co);
const SDefAdjacency *const vert_edges = data->vert_edges[nearest].first;
const SDefEdgePolys *const edge_polys = data->edge_polys;
@@ -444,7 +444,7 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data,
/* Loop over all adjacent edges,
* and build the SDefBindPoly data for each poly adjacent to those. */
for (vedge = vert_edges; vedge; vedge = vedge->next) {
- unsigned int edge_ind = vedge->index;
+ uint edge_ind = vedge->index;
for (int i = 0; i < edge_polys[edge_ind].num; i++) {
{
@@ -603,8 +603,8 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data,
SDefBindPoly *bpolys[2];
const SDefEdgePolys *epolys;
float ang_weights[2];
- unsigned int edge_ind = vedge->index;
- unsigned int edge_on_poly[2];
+ uint edge_ind = vedge->index;
+ uint edge_on_poly[2];
epolys = &edge_polys[edge_ind];
@@ -981,9 +981,9 @@ static void bindVert(void *__restrict userdata,
static bool surfacedeformBind(SurfaceDeformModifierData *smd,
float (*vertexCos)[3],
- unsigned int numverts,
- unsigned int tnumpoly,
- unsigned int tnumverts,
+ uint numverts,
+ uint tnumpoly,
+ uint tnumverts,
Mesh *target)
{
BVHTreeFromMesh treeData = {NULL};
@@ -991,7 +991,7 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd,
const MPoly *mpoly = target->mpoly;
const MEdge *medge = target->medge;
const MLoop *mloop = target->mloop;
- unsigned int tnumedges = target->totedge;
+ uint tnumedges = target->totedge;
int adj_result;
SDefAdjacencyArray *vert_edges;
SDefAdjacency *adj_array;
@@ -1173,12 +1173,12 @@ static void deformVert(void *__restrict userdata,
static void surfacedeformModifier_do(ModifierData *md,
const ModifierEvalContext *ctx,
float (*vertexCos)[3],
- unsigned int numverts,
+ uint numverts,
Object *ob)
{
SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
Mesh *target;
- unsigned int tnumverts, tnumpoly;
+ uint tnumverts, tnumpoly;
/* Exit function if bind flag is not set (free bind data if any). */
if (!(smd->flags & MOD_SDEF_BIND)) {
@@ -1282,7 +1282,7 @@ static bool isDisabled(const Scene *UNUSED(scene), ModifierData *md, bool UNUSED
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the mesh is missing).
*
- * In other cases it should be impossible to have a type missmatch.
+ * In other cases it should be impossible to have a type mismatch.
*/
return (smd->target == NULL || smd->target->type != OB_MESH) &&
!(smd->verts != NULL && !(smd->flags & MOD_SDEF_BIND));
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index 1582c27960e..7fba7e864ae 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -65,7 +65,7 @@ static Mesh *triangulate_mesh(Mesh *mesh,
BM_mesh_triangulate(bm, quad_method, ngon_method, min_vertices, false, NULL, NULL, NULL);
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cddata_masks);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cddata_masks, mesh);
BM_mesh_free(bm);
if (keep_clnors) {
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index e7acbd3e32e..1e3c747022c 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -108,12 +108,12 @@ void MOD_get_texture_coords(MappingInfoModifierData *dmd,
mloop_uv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
/* verts are given the UV from the first face that uses them */
- for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp) {
- unsigned int fidx = mp->totloop - 1;
+ for (i = 0, mp = mpoly; i < numPolys; i++, mp++) {
+ uint fidx = mp->totloop - 1;
do {
- unsigned int lidx = mp->loopstart + fidx;
- unsigned int vidx = mloop[lidx].v;
+ uint lidx = mp->loopstart + fidx;
+ uint vidx = mloop[lidx].v;
if (!BLI_BITMAP_TEST(done, vidx)) {
/* remap UVs from [0, 1] to [-1, 1] */
@@ -135,7 +135,7 @@ void MOD_get_texture_coords(MappingInfoModifierData *dmd,
}
MVert *mv = mesh->mvert;
- for (i = 0; i < numVerts; ++i, ++mv, ++r_texco) {
+ for (i = 0; i < numVerts; i++, mv++, r_texco++) {
switch (texmapping) {
case MOD_DISP_MAP_LOCAL:
copy_v3_v3(*r_texco, cos != NULL ? *cos : mv->co);
@@ -182,7 +182,7 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
}
else if (ob->type == OB_MESH) {
if (em) {
- mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL);
+ mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, ob->data);
}
else {
/* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index 5f1eae0297a..9698e150850 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -68,7 +68,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
UVProjectModifierData *umd = (UVProjectModifierData *)md;
int i;
- for (i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i) {
+ for (i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; i++) {
walk(userData, ob, &umd->projectors[i], IDWALK_CB_NOP);
}
}
@@ -86,7 +86,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
{
UVProjectModifierData *umd = (UVProjectModifierData *)md;
bool do_add_own_transform = false;
- for (int i = 0; i < umd->num_projectors; ++i) {
+ for (int i = 0; i < umd->num_projectors; i++) {
if (umd->projectors[i] != NULL) {
DEG_add_object_relation(
ctx->node, umd->projectors[i], DEG_OB_COMP_TRANSFORM, "UV Project Modifier");
@@ -124,7 +124,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
float scay = umd->scaley ? umd->scaley : 1.0f;
int free_uci = 0;
- for (i = 0; i < umd->num_projectors; ++i) {
+ for (i = 0; i < umd->num_projectors; i++) {
if (umd->projectors[i] != NULL) {
projectors[num_projectors++].ob = umd->projectors[i];
}
@@ -144,7 +144,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, umd->uvlayer_name, uvname);
/* calculate a projection matrix and normal for each projector */
- for (i = 0; i < num_projectors; ++i) {
+ for (i = 0; i < num_projectors; i++) {
float tmpmat[4][4];
float offsetmat[4][4];
Camera *cam = NULL;
@@ -207,13 +207,13 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
coords = BKE_mesh_vert_coords_alloc(mesh, &numVerts);
/* convert coords to world space */
- for (i = 0, co = coords; i < numVerts; ++i, ++co) {
+ for (i = 0, co = coords; i < numVerts; i++, co++) {
mul_m4_v3(ob->obmat, *co);
}
/* if only one projector, project coords to UVs */
if (num_projectors == 1 && projectors[0].uci == NULL) {
- for (i = 0, co = coords; i < numVerts; ++i, ++co) {
+ for (i = 0, co = coords; i < numVerts; i++, co++) {
mul_project_m4_v3(projectors[0].projmat, *co);
}
}
@@ -222,22 +222,22 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
mloop = mesh->mloop;
/* apply coords as UVs */
- for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp) {
+ for (i = 0, mp = mpoly; i < numPolys; i++, mp++) {
if (num_projectors == 1) {
if (projectors[0].uci) {
- unsigned int fidx = mp->totloop - 1;
+ uint fidx = mp->totloop - 1;
do {
- unsigned int lidx = mp->loopstart + fidx;
- unsigned int vidx = mloop[lidx].v;
+ uint lidx = mp->loopstart + fidx;
+ uint vidx = mloop[lidx].v;
BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], projectors[0].uci);
} while (fidx--);
}
else {
/* apply transformed coords as UVs */
- unsigned int fidx = mp->totloop - 1;
+ uint fidx = mp->totloop - 1;
do {
- unsigned int lidx = mp->loopstart + fidx;
- unsigned int vidx = mloop[lidx].v;
+ uint lidx = mp->loopstart + fidx;
+ uint vidx = mloop[lidx].v;
copy_v2_v2(mloop_uv[lidx].uv, coords[vidx]);
} while (fidx--);
}
@@ -259,7 +259,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
best_dot = dot_v3v3(projectors[0].normal, face_no);
best_projector = &projectors[0];
- for (j = 1; j < num_projectors; ++j) {
+ for (j = 1; j < num_projectors; j++) {
float tmp_dot = dot_v3v3(projectors[j].normal, face_no);
if (tmp_dot > best_dot) {
best_dot = tmp_dot;
@@ -268,18 +268,18 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
}
if (best_projector->uci) {
- unsigned int fidx = mp->totloop - 1;
+ uint fidx = mp->totloop - 1;
do {
- unsigned int lidx = mp->loopstart + fidx;
- unsigned int vidx = mloop[lidx].v;
+ uint lidx = mp->loopstart + fidx;
+ uint vidx = mloop[lidx].v;
BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], best_projector->uci);
} while (fidx--);
}
else {
- unsigned int fidx = mp->totloop - 1;
+ uint fidx = mp->totloop - 1;
do {
- unsigned int lidx = mp->loopstart + fidx;
- unsigned int vidx = mloop[lidx].v;
+ uint lidx = mp->loopstart + fidx;
+ uint vidx = mloop[lidx].v;
mul_v2_project_m4_v3(mloop_uv[lidx].uv, best_projector->projmat, coords[vidx]);
} while (fidx--);
}
@@ -290,7 +290,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
if (free_uci) {
int j;
- for (j = 0; j < num_projectors; ++j) {
+ for (j = 0; j < num_projectors; j++) {
if (projectors[j].uci) {
MEM_freeN(projectors[j].uci);
}
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c
index 486d5c90bef..4ff07b21ef4 100644
--- a/source/blender/modifiers/intern/MOD_weightvg_util.c
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.c
@@ -76,7 +76,7 @@ void weightvg_do_map(int num, float *new_w, short falloff_type, CurveMapping *cm
}
/* Map each weight (vertex) to its new value, accordingly to the chosen mode. */
- for (i = 0; i < num; ++i) {
+ for (i = 0; i < num; i++) {
float fac = new_w[i];
/* Code borrowed from the warp modifier. */
@@ -164,7 +164,7 @@ void weightvg_do_mask(const ModifierEvalContext *ctx,
MOD_init_texture(&t_map, ctx);
/* For each weight (vertex), make the mix between org and new weights. */
- for (i = 0; i < num; ++i) {
+ for (i = 0; i < num; i++) {
int idx = indices ? indices[i] : i;
TexResult texres;
float hsv[3]; /* For HSV color space. */
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index 95b15b4a924..7e23289433f 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -215,7 +215,7 @@ static void get_vert2ob_distance(
{
/* Vertex and ref object coordinates. */
float v_wco[3];
- unsigned int i = numVerts;
+ uint i = numVerts;
while (i-- > 0) {
/* Get world-coordinates of the vertex (constraints and anim included). */
@@ -241,7 +241,7 @@ static void do_map(
Object *ob, float *weights, const int nidx, const float min_d, const float max_d, short mode)
{
const float range_inv = 1.0f / (max_d - min_d); /* invert since multiplication is faster */
- unsigned int i = nidx;
+ uint i = nidx;
if (max_d == min_d) {
while (i-- > 0) {
weights[i] = (weights[i] >= max_d) ? 1.0f : 0.0f; /* "Step" behavior... */
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index 7af9ef6f5b6..3dd6e00c3a5 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -91,7 +91,7 @@ static Mesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, Mesh *
MAX2(ob->totcol - 1, 0),
false);
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 5cf5e1ac6d3..f618f964b22 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -205,9 +205,10 @@ set(SRC
shader/nodes/node_shader_uvmap.c
shader/nodes/node_shader_valToRgb.c
shader/nodes/node_shader_value.c
- shader/nodes/node_shader_vector_math.c
shader/nodes/node_shader_vectTransform.c
shader/nodes/node_shader_vector_displacement.c
+ shader/nodes/node_shader_vector_math.c
+ shader/nodes/node_shader_vertex_color.c
shader/nodes/node_shader_volume_absorption.c
shader/nodes/node_shader_volume_info.c
shader/nodes/node_shader_volume_principled.c
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index 30673e7cd31..a004090d03d 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -86,6 +86,7 @@ void register_node_type_sh_script(void);
void register_node_type_sh_normal_map(void);
void register_node_type_sh_tangent(void);
void register_node_type_sh_vect_transform(void);
+void register_node_type_sh_vertex_color(void);
void register_node_type_sh_ambient_occlusion(void);
void register_node_type_sh_background(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index d14511504f0..f3bc5a0cafa 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -121,6 +121,7 @@ DefNode(ShaderNode, SH_NODE_VECT_TRANSFORM, def_sh_vect_transform, "VEC
DefNode(ShaderNode, SH_NODE_SEPHSV, 0, "SEPHSV", SeparateHSV, "Separate HSV", "" )
DefNode(ShaderNode, SH_NODE_COMBHSV, 0, "COMBHSV", CombineHSV, "Combine HSV", "" )
DefNode(ShaderNode, SH_NODE_UVMAP, def_sh_uvmap, "UVMAP", UVMap, "UV Map", "" )
+DefNode(ShaderNode, SH_NODE_VERTEX_COLOR, def_sh_vertex_color, "VERTEX_COLOR", VertexColor, "Vertex Color", "" )
DefNode(ShaderNode, SH_NODE_UVALONGSTROKE, def_sh_uvalongstroke, "UVALONGSTROKE", UVAlongStroke, "UV Along Stroke", "" )
DefNode(ShaderNode, SH_NODE_SEPXYZ, 0, "SEPXYZ", SeparateXYZ, "Separate XYZ", "" )
DefNode(ShaderNode, SH_NODE_COMBXYZ, 0, "COMBXYZ", CombineXYZ, "Combine XYZ", "" )
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorbalance.c b/source/blender/nodes/composite/nodes/node_composite_colorbalance.c
index db0689df775..27cf050c658 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorbalance.c
+++ b/source/blender/nodes/composite/nodes/node_composite_colorbalance.c
@@ -46,7 +46,7 @@ void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *UNUSED(ntree), bNode *node)
NodeColorBalance *n = node->storage;
int c;
- for (c = 0; c < 3; ++c) {
+ for (c = 0; c < 3; c++) {
n->slope[c] = (2.0f - n->lift[c]) * n->gain[c];
n->offset[c] = (n->lift[c] - 1.0f) * n->gain[c];
n->power[c] = (n->gamma[c] != 0.0f) ? 1.0f / n->gamma[c] : 1000000.0f;
@@ -58,7 +58,7 @@ void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *UNUSED(ntree), bNode *node)
NodeColorBalance *n = node->storage;
int c;
- for (c = 0; c < 3; ++c) {
+ for (c = 0; c < 3; c++) {
float d = n->slope[c] + n->offset[c];
n->lift[c] = (d != 0.0f ? n->slope[c] + 2.0f * n->offset[c] / d : 0.0f);
n->gain[c] = d;
diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c
index dcd8589cfdd..cbae2c412ea 100644
--- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c
+++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c
@@ -60,7 +60,7 @@ static void cryptomatte_add(NodeCryptomatte *n, float f)
while (start < end) {
/* Ignore leading whitespace. */
while (start < end && n->matte_id[start] == ' ') {
- ++start;
+ start++;
}
/* Find the next separator. */
@@ -139,7 +139,7 @@ static void cryptomatte_remove(NodeCryptomatte *n, float f)
bool skip = false;
/* Ignore leading whitespace or commas. */
while (start < end && ((n->matte_id[start] == ' ') || (n->matte_id[start] == ','))) {
- ++start;
+ start++;
}
/* Find the next separator. */
diff --git a/source/blender/nodes/composite/nodes/node_composite_denoise.c b/source/blender/nodes/composite/nodes/node_composite_denoise.c
index e2fdb08816a..bb62869f470 100644
--- a/source/blender/nodes/composite/nodes/node_composite_denoise.c
+++ b/source/blender/nodes/composite/nodes/node_composite_denoise.c
@@ -33,8 +33,8 @@
static bNodeSocketTemplate cmp_node_denoise_in[] = {
{SOCK_RGBA, 1, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_RGBA, 1, N_("Albedo"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
{SOCK_VECTOR, 0, N_("Normal"), 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f},
+ {SOCK_RGBA, 1, N_("Albedo"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
{-1, 0, ""}};
static bNodeSocketTemplate cmp_node_denoise_out[] = {{SOCK_RGBA, 0, N_("Image")}, {-1, 0, ""}};
diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c
index 24376e39f3d..85c408c40bb 100644
--- a/source/blender/nodes/intern/node_exec.c
+++ b/source/blender/nodes/intern/node_exec.c
@@ -183,7 +183,7 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context,
/* set stack indices */
index = 0;
- for (n = 0; n < totnodes; ++n) {
+ for (n = 0; n < totnodes; n++) {
node = nodelist[n];
node->stack_index = index;
@@ -213,12 +213,12 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context,
exec->stack = MEM_callocN(exec->stacksize * sizeof(bNodeStack), "bNodeStack");
/* all non-const results are considered inputs */
- for (n = 0; n < exec->stacksize; ++n) {
+ for (n = 0; n < exec->stacksize; n++) {
exec->stack[n].hasinput = 1;
}
/* prepare all nodes for execution */
- for (n = 0, nodeexec = exec->nodeexec; n < totnodes; ++n, ++nodeexec) {
+ for (n = 0, nodeexec = exec->nodeexec; n < totnodes; n++, nodeexec++) {
node = nodeexec->node = nodelist[n];
nodeexec->freeexecfunc = node->typeinfo->freeexecfunc;
@@ -265,7 +265,7 @@ void ntree_exec_end(bNodeTreeExec *exec)
MEM_freeN(exec->stack);
}
- for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
+ for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; n++, nodeexec++) {
if (nodeexec->freeexecfunc) {
nodeexec->freeexecfunc(nodeexec->data.data);
}
@@ -317,7 +317,7 @@ bool ntreeExecThreadNodes(bNodeTreeExec *exec, bNodeThreadStack *nts, void *call
/* nodes are presorted, so exec is in order of list */
- for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
+ for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; n++, nodeexec++) {
node = nodeexec->node;
if (node->need_exec) {
node_get_stack(node, nts->stack, nsin, nsout);
diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c
index 0d7f19fb67a..455da4b3881 100644
--- a/source/blender/nodes/intern/node_util.c
+++ b/source/blender/nodes/intern/node_util.c
@@ -130,7 +130,7 @@ static bool node_link_socket_match(bNodeSocket *a, bNodeSocket *b)
*/
int prefix_len = 0;
char *ca = a->name, *cb = b->name;
- for (; *ca != '\0' && *cb != '\0'; ++ca, ++cb) {
+ for (; *ca != '\0' && *cb != '\0'; ca++, cb++) {
/* end of common prefix? */
if (*ca != *cb) {
/* prefix delimited by non-alphabetic char */
@@ -139,7 +139,7 @@ static bool node_link_socket_match(bNodeSocket *a, bNodeSocket *b)
}
break;
}
- ++prefix_len;
+ prefix_len++;
}
return prefix_len > 0;
}
@@ -150,10 +150,10 @@ static int node_count_links(bNodeTree *ntree, bNodeSocket *sock)
int count = 0;
for (link = ntree->links.first; link; link = link->next) {
if (link->fromsock == sock) {
- ++count;
+ count++;
}
if (link->tosock == sock) {
- ++count;
+ count++;
}
}
return count;
@@ -321,7 +321,7 @@ static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output)
int sel_priority = -1;
bool sel_is_linked = false;
- for (input = node->inputs.first, i = 0; input; input = input->next, ++i) {
+ for (input = node->inputs.first, i = 0; input; input = input->next, i++) {
int priority = node_datatype_priority(input->type, output->type);
bool is_linked = (input->link != NULL);
bool preferred;
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index 60a6cc91630..92266600612 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -32,6 +32,7 @@
#include "DNA_linestyle_types.h"
#include "DNA_workspace_types.h"
+#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -212,115 +213,6 @@ void register_node_tree_type_sh(void)
/* GPU material from shader nodes */
-static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
- bNode *node_from,
- bNodeSocket *socket_from,
- bNode *displacement_node,
- bNodeSocket *displacement_socket);
-
-static bNodeSocket *ntree_shader_node_find_input(bNode *node, const char *identifier);
-
-static bNode *ntree_group_output_node(bNodeTree *ntree);
-
-static bNode *ntree_shader_relink_output_from_group(bNodeTree *ntree,
- bNode *group_node,
- bNode *sh_output_node,
- int target)
-{
- int i;
- bNodeTree *group_ntree = (bNodeTree *)group_node->id;
-
- int sock_len = BLI_listbase_count(&sh_output_node->inputs);
- bNodeSocket **group_surface_sockets = BLI_array_alloca(group_surface_sockets, sock_len);
-
- /* Create output sockets to plug output connection to. */
- i = 0;
- for (bNodeSocket *sock = sh_output_node->inputs.first; sock; sock = sock->next, ++i) {
- group_surface_sockets[i] = ntreeAddSocketInterface(
- group_ntree, SOCK_OUT, sock->typeinfo->idname, sock->name);
- }
-
- bNode *group_output_node = ntree_group_output_node(group_ntree);
-
- /* If no group output node is present, we need to create one. */
- if (group_output_node == NULL) {
- group_output_node = nodeAddStaticNode(NULL, group_ntree, NODE_GROUP_OUTPUT);
- }
-
- /* Need to update tree so all node instances nodes gets proper sockets. */
- node_group_update(ntree, group_node);
- node_group_output_update(group_ntree, group_output_node);
- ntreeUpdateTree(G.main, group_ntree);
-
- /* Remove other shader output nodes so that only the new one can be selected as active. */
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
- if (ELEM(node->type, SH_NODE_OUTPUT_MATERIAL, SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LIGHT)) {
- ntreeFreeLocalNode(ntree, node);
- }
- }
-
- /* Create new shader output node outside the group. */
- bNode *new_output_node = nodeAddStaticNode(NULL, ntree, sh_output_node->type);
- new_output_node->custom1 = target;
-
- i = 0;
- for (bNodeSocket *sock = sh_output_node->inputs.first; sock; sock = sock->next, ++i) {
- if (sock->link != NULL) {
- /* Link the shader output node incoming link to the group output sockets */
- bNodeSocket *group_output_node_surface_input_sock = nodeFindSocket(
- group_output_node, SOCK_IN, group_surface_sockets[i]->identifier);
- nodeAddLink(group_ntree,
- sock->link->fromnode,
- sock->link->fromsock,
- group_output_node,
- group_output_node_surface_input_sock);
-
- /* Link the group output sockets to the new shader output node. */
- bNodeSocket *group_node_surface_output = nodeFindSocket(
- group_node, SOCK_OUT, group_surface_sockets[i]->identifier);
- bNodeSocket *output_node_surface_input = ntree_shader_node_find_input(new_output_node,
- sock->name);
-
- nodeAddLink(ntree,
- group_node,
- group_node_surface_output,
- new_output_node,
- output_node_surface_input);
- }
- }
-
- ntreeUpdateTree(G.main, group_ntree);
- ntreeUpdateTree(G.main, ntree);
-
- return new_output_node;
-}
-
-static bNode *ntree_shader_output_node_from_group(bNodeTree *ntree, int target)
-{
- bNode *output_node = NULL;
-
- /* Search if node groups do not contain valid output nodes (recursively). */
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
- if (!ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
- continue;
- }
- if (node->id != NULL) {
- output_node = ntree_shader_output_node_from_group((bNodeTree *)node->id, target);
-
- if (output_node == NULL) {
- output_node = ntreeShaderOutputNode((bNodeTree *)node->id, target);
- }
-
- if (output_node != NULL) {
- /* Output is inside this group node. Create relink to make the output outside the group. */
- output_node = ntree_shader_relink_output_from_group(ntree, node, output_node, target);
- break;
- }
- }
- }
- return output_node;
-}
-
/* Find an output node of the shader tree.
*
* NOTE: it will only return output which is NOT in the group, which isn't how
@@ -368,28 +260,6 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target)
return output_node;
}
-/* Find the active output node of a group nodetree.
- *
- * Does not return the shading output node but the group output node.
- */
-static bNode *ntree_group_output_node(bNodeTree *ntree)
-{
- /* Make sure we only have single node tagged as output. */
- ntreeSetOutput(ntree);
-
- /* Find output node that matches type and target. If there are
- * multiple, we prefer exact target match and active nodes. */
- bNode *output_node = NULL;
-
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
- if ((node->type == NODE_GROUP_OUTPUT) && (node->flag & NODE_DO_OUTPUT)) {
- output_node = node;
- }
- }
-
- return output_node;
-}
-
/* Find socket with a specified identifier. */
static bNodeSocket *ntree_shader_node_find_socket(ListBase *sockets, const char *identifier)
{
@@ -520,6 +390,106 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree)
}
}
+static void flatten_group_do(bNodeTree *ntree, bNode *gnode)
+{
+ bNodeLink *link, *linkn, *tlink;
+ bNode *node, *nextnode;
+ bNodeTree *ngroup;
+ LinkNode *group_interface_nodes = NULL;
+
+ ngroup = (bNodeTree *)gnode->id;
+
+ /* Add the nodes into the ntree */
+ for (node = ngroup->nodes.first; node; node = nextnode) {
+ nextnode = node->next;
+ /* Remove interface nodes.
+ * This also removes remaining links to and from interface nodes.
+ * We must delay removal since sockets will reference this node. see: T52092 */
+ if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
+ BLI_linklist_prepend(&group_interface_nodes, node);
+ }
+ /* migrate node */
+ BLI_remlink(&ngroup->nodes, node);
+ BLI_addtail(&ntree->nodes, node);
+ /* ensure unique node name in the node tree */
+ nodeUniqueName(ntree, node);
+ }
+
+ /* Save first and last link to iterate over flattened group links. */
+ bNodeLink *glinks_first = ntree->links.last;
+
+ /* Add internal links to the ntree */
+ for (link = ngroup->links.first; link; link = linkn) {
+ linkn = link->next;
+ BLI_remlink(&ngroup->links, link);
+ BLI_addtail(&ntree->links, link);
+ }
+
+ bNodeLink *glinks_last = ntree->links.last;
+
+ /* restore external links to and from the gnode */
+ if (glinks_first != NULL) {
+ /* input links */
+ for (link = glinks_first->next; link != glinks_last->next; link = link->next) {
+ if (link->fromnode->type == NODE_GROUP_INPUT) {
+ const char *identifier = link->fromsock->identifier;
+ /* find external links to this input */
+ for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) {
+ if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) {
+ nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode, link->tosock);
+ }
+ }
+ }
+ }
+ /* output links */
+ for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) {
+ if (tlink->fromnode == gnode) {
+ const char *identifier = tlink->fromsock->identifier;
+ /* find internal links to this output */
+ for (link = glinks_first->next; link != glinks_last->next; link = link->next) {
+ /* only use active output node */
+ if (link->tonode->type == NODE_GROUP_OUTPUT && (link->tonode->flag & NODE_DO_OUTPUT)) {
+ if (STREQ(link->tosock->identifier, identifier)) {
+ nodeAddLink(ntree, link->fromnode, link->fromsock, tlink->tonode, tlink->tosock);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ while (group_interface_nodes) {
+ node = BLI_linklist_pop(&group_interface_nodes);
+ ntreeFreeLocalNode(ntree, node);
+ }
+
+ ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+}
+
+/* Flatten group to only have a simple single tree */
+static void ntree_shader_groups_flatten(bNodeTree *localtree)
+{
+ /* This is effectively recursive as the flattened groups will add
+ * nodes at the end of the list, which will also get evaluated. */
+ for (bNode *node = localtree->nodes.first, *node_next; node; node = node_next) {
+ if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id != NULL) {
+ flatten_group_do(localtree, node);
+ /* Continue even on new flattened nodes. */
+ node_next = node->next;
+ /* delete the group instance and its localtree. */
+ bNodeTree *ngroup = (bNodeTree *)node->id;
+ ntreeFreeLocalNode(localtree, node);
+ ntreeFreeTree(ngroup);
+ MEM_freeN(ngroup);
+ }
+ else {
+ node_next = node->next;
+ }
+ }
+
+ ntreeUpdateTree(G.main, localtree);
+}
+
/* Check whether shader has a displacement.
*
* Will also return a node and it's socket which is connected to a displacement
@@ -576,53 +546,10 @@ static void ntree_shader_relink_node_normal(bNodeTree *ntree,
}
}
-static void ntree_shader_link_builtin_group_normal(bNodeTree *ntree,
- bNode *group_node,
- bNode *node_from,
- bNodeSocket *socket_from,
- bNode *displacement_node,
- bNodeSocket *displacement_socket)
-{
- bNodeTree *group_ntree = (bNodeTree *)group_node->id;
- /* Create input socket to plug displacement connection to. */
- bNodeSocket *group_normal_socket = ntreeAddSocketInterface(
- group_ntree, SOCK_IN, "NodeSocketVector", "Normal");
- /* Need to update tree so all node instances nodes gets proper sockets. */
- bNode *group_input_node = ntreeFindType(group_ntree, NODE_GROUP_INPUT);
- node_group_update(ntree, group_node);
- if (group_input_node) {
- node_group_input_update(group_ntree, group_input_node);
- }
- ntreeUpdateTree(G.main, group_ntree);
- /* Assumes sockets are always added at the end. */
- bNodeSocket *group_node_normal_socket = group_node->inputs.last;
- if (displacement_node == group_node) {
- /* This should never happen as all displacement nodes are duplicated and tagged. */
- BLI_assert(0);
- }
- else if (group_input_node) {
- /* Connect group node normal input. */
- nodeAddLink(ntree, node_from, socket_from, group_node, group_node_normal_socket);
- BLI_assert(group_input_node != NULL);
- bNodeSocket *group_input_node_normal_socket = nodeFindSocket(
- group_input_node, SOCK_OUT, group_normal_socket->identifier);
- BLI_assert(group_input_node_normal_socket != NULL);
- /* Relink normals inside of the instanced tree. */
- ntree_shader_link_builtin_normal(group_ntree,
- group_input_node,
- group_input_node_normal_socket,
- displacement_node,
- displacement_socket);
- ntreeUpdateTree(G.main, group_ntree);
- }
-}
-
/* Use specified node and socket as an input for unconnected normal sockets. */
static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
bNode *node_from,
- bNodeSocket *socket_from,
- bNode *displacement_node,
- bNodeSocket *displacement_socket)
+ bNodeSocket *socket_from)
{
for (bNode *node = ntree->nodes.first; node != NULL; node = node->next) {
if (node == node_from) {
@@ -633,16 +560,6 @@ static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
/* This node is used inside the displacement tree. Skip to avoid cycles. */
continue;
}
- if ((ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) && node->id) {
- /* Special re-linking for group nodes. */
- ntree_shader_link_builtin_group_normal(
- ntree, node, node_from, socket_from, displacement_node, displacement_socket);
- continue;
- }
- if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
- /* Group inputs and outputs needs nothing special. */
- continue;
- }
ntree_shader_relink_node_normal(ntree, node, node_from, socket_from);
}
}
@@ -670,36 +587,17 @@ static void ntree_shader_bypass_bump_link(bNodeTree *ntree, bNode *bump_node, bN
static void ntree_shader_bypass_tagged_bump_nodes(bNodeTree *ntree)
{
/* Bypass bump links inside copied nodes */
- bNodeLink *link, *link_next;
- for (link = ntree->links.first; link; link = link_next) {
- /* link might be freed by ntree_shader_bypass_bump_link. */
- link_next = link->next;
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
bNode *node = link->fromnode;
/* If node is a copy. */
if (node->tmp_flag == -2 && node->type == SH_NODE_BUMP) {
ntree_shader_bypass_bump_link(ntree, node, link);
}
}
- /* Do the same inside nodegroups. */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- /* If node is a copy. */
- if (node->tmp_flag == -2 && ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) {
- bNodeTree *group_ntree = (bNodeTree *)node->id;
- /* Tag all nodes inside this group as copies. */
- LISTBASE_FOREACH (bNode *, group_node, &group_ntree->nodes) {
- group_node->tmp_flag = -2;
- }
- /* Recursive. */
- ntree_shader_bypass_tagged_bump_nodes(group_ntree);
- }
- }
ntreeUpdateTree(G.main, ntree);
}
-static bool ntree_branch_count_and_tag_nodes(bNode *fromnode,
- bNode *tonode,
- void *userdata,
- const bool UNUSED(reversed))
+static bool ntree_branch_count_and_tag_nodes(bNode *fromnode, bNode *tonode, void *userdata)
{
int *node_count = (int *)userdata;
if (fromnode->tmp_flag == -1) {
@@ -713,19 +611,22 @@ static bool ntree_branch_count_and_tag_nodes(bNode *fromnode,
return true;
}
-static void ntree_shader_copy_branch_displacement(bNodeTree *ntree,
- bNode *displacement_node,
- bNodeSocket *displacement_socket,
- bNodeLink *displacement_link)
+/* Create a copy of a branch starting from a given node.
+ * callback is executed once for every copied node.
+ * Returns input node copy. */
+static bNode *ntree_shader_copy_branch(bNodeTree *ntree,
+ bNode *start_node,
+ void (*callback)(bNode *node, int user_data),
+ int user_data)
{
/* Init tmp flag. */
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
node->tmp_flag = -1;
}
/* Count and tag all nodes inside the displacement branch of the tree. */
- displacement_node->tmp_flag = 0;
+ start_node->tmp_flag = 0;
int node_count = 1;
- nodeChainIter(ntree, displacement_node, ntree_branch_count_and_tag_nodes, &node_count, true);
+ nodeChainIterBackwards(ntree, start_node, ntree_branch_count_and_tag_nodes, &node_count);
/* Make a full copy of the branch */
bNode **nodes_copy = MEM_mallocN(sizeof(bNode *) * node_count, __func__);
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
@@ -733,9 +634,6 @@ static void ntree_shader_copy_branch_displacement(bNodeTree *ntree,
int id = node->tmp_flag;
nodes_copy[id] = BKE_node_copy_ex(ntree, node, LIB_ID_CREATE_NO_USER_REFCOUNT);
nodes_copy[id]->tmp_flag = -2; /* Copy */
- if (ELEM(nodes_copy[id]->type, NODE_GROUP, NODE_CUSTOM_GROUP) && nodes_copy[id]->id) {
- nodes_copy[id]->id = (ID *)ntreeLocalize((bNodeTree *)nodes_copy[id]->id);
- }
/* Make sure to clear all sockets links as they are invalid. */
LISTBASE_FOREACH (bNodeSocket *, sock, &nodes_copy[id]->inputs) {
sock->link = NULL;
@@ -755,15 +653,30 @@ static void ntree_shader_copy_branch_displacement(bNodeTree *ntree,
nodeAddLink(ntree, fromnode, fromsock, tonode, tosock);
}
}
+ /* Per node callback. */
+ if (callback) {
+ for (int i = 0; i < node_count; i++) {
+ callback(nodes_copy[i], user_data);
+ }
+ }
+ bNode *start_node_copy = nodes_copy[start_node->tmp_flag];
+ MEM_freeN(nodes_copy);
+ return start_node_copy;
+}
+
+static void ntree_shader_copy_branch_displacement(bNodeTree *ntree,
+ bNode *displacement_node,
+ bNodeSocket *displacement_socket,
+ bNodeLink *displacement_link)
+{
/* Replace displacement socket/node/link. */
bNode *tonode = displacement_link->tonode;
bNodeSocket *tosock = displacement_link->tosock;
- displacement_node = nodes_copy[displacement_node->tmp_flag];
+ displacement_node = ntree_shader_copy_branch(ntree, displacement_node, NULL, 0);
displacement_socket = ntree_shader_node_find_output(displacement_node,
displacement_socket->identifier);
nodeRemLink(ntree, displacement_link);
nodeAddLink(ntree, displacement_node, displacement_socket, tonode, tosock);
- MEM_freeN(nodes_copy);
ntreeUpdateTree(G.main, ntree);
}
@@ -802,10 +715,12 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod
bNode *dot_node = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
bNode *geo_node = nodeAddStaticNode(NULL, ntree, SH_NODE_NEW_GEOMETRY);
bNodeSocket *normal_socket = ntree_shader_node_find_output(geo_node, "Normal");
- dot_node->custom1 = 3; /* dot product */
+ bNodeSocket *dot_input1 = dot_node->inputs.first;
+ bNodeSocket *dot_input2 = dot_input1->next;
+ dot_node->custom1 = NODE_VECTOR_MATH_DOT_PRODUCT;
- nodeAddLink(ntree, displacement_node, displacement_socket, dot_node, dot_node->inputs.first);
- nodeAddLink(ntree, geo_node, normal_socket, dot_node, dot_node->inputs.last);
+ nodeAddLink(ntree, displacement_node, displacement_socket, dot_node, dot_input1);
+ nodeAddLink(ntree, geo_node, normal_socket, dot_node, dot_input2);
displacement_node = dot_node;
displacement_socket = ntree_shader_node_find_output(dot_node, "Value");
@@ -830,33 +745,52 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod
ntreeUpdateTree(G.main, ntree);
/* Connect all free-standing Normal inputs and relink geometry/coordinate nodes. */
- ntree_shader_link_builtin_normal(
- ntree, bump_node, bump_output_socket, displacement_node, displacement_socket);
+ ntree_shader_link_builtin_normal(ntree, bump_node, bump_output_socket);
/* We modified the tree, it needs to be updated now. */
ntreeUpdateTree(G.main, ntree);
}
-static bool ntree_tag_bsdf_cb(bNode *fromnode,
- bNode *UNUSED(tonode),
- void *userdata,
- const bool UNUSED(reversed))
+static void node_tag_branch_as_derivative(bNode *node, int dx)
{
- /* Don't evaluate nodes more than once. */
- if (fromnode->tmp_flag) {
- return true;
+ if (dx) {
+ node->branch_tag = 1;
+ }
+ else {
+ node->branch_tag = 2;
}
- fromnode->tmp_flag = 1;
+}
+
+static bool ntree_shader_bump_branches(bNode *UNUSED(fromnode), bNode *tonode, void *userdata)
+{
+ bNodeTree *ntree = (bNodeTree *)userdata;
+ if (tonode->type == SH_NODE_BUMP) {
+ bNodeSocket *height_dx_sock, *height_dy_sock, *bump_socket, *bump_dx_socket, *bump_dy_socket;
+ bNode *bump = tonode;
+ bump_socket = ntree_shader_node_find_input(bump, "Height");
+ bump_dx_socket = ntree_shader_node_find_input(bump, "Height_dx");
+ bump_dy_socket = ntree_shader_node_find_input(bump, "Height_dy");
+ if (bump_dx_socket->link) {
+ /* Avoid reconnecting the same bump twice. */
+ }
+ else if (bump_socket && bump_socket->link) {
+ bNodeLink *link = bump_socket->link;
+ bNode *height = link->fromnode;
+ bNode *height_dx = ntree_shader_copy_branch(ntree, height, node_tag_branch_as_derivative, 1);
+ bNode *height_dy = ntree_shader_copy_branch(ntree, height, node_tag_branch_as_derivative, 0);
+ height_dx_sock = ntree_shader_node_find_output(height_dx, link->fromsock->identifier);
+ height_dy_sock = ntree_shader_node_find_output(height_dy, link->fromsock->identifier);
+ nodeAddLink(ntree, height_dx, height_dx_sock, bump, bump_dx_socket);
+ nodeAddLink(ntree, height_dy, height_dy_sock, bump, bump_dy_socket);
+ /* We could end iter here, but other bump node could be plugged into other input sockets. */
+ }
+ }
+ return true;
+}
+
+static bool ntree_tag_bsdf_cb(bNode *fromnode, bNode *UNUSED(tonode), void *userdata)
+{
switch (fromnode->type) {
- case NODE_GROUP:
- case NODE_CUSTOM_GROUP:
- /* Recursive */
- if (fromnode->id != NULL) {
- bNodeTree *ntree = (bNodeTree *)fromnode->id;
- bNode *group_output = ntree_group_output_node(ntree);
- ntree_shader_tag_nodes(ntree, group_output, (nTreeTags *)userdata);
- }
- break;
case SH_NODE_BSDF_ANISOTROPIC:
case SH_NODE_EEVEE_SPECULAR:
case SH_NODE_BSDF_GLOSSY:
@@ -895,12 +829,7 @@ void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tag
/* Make sure sockets links pointers are correct. */
ntreeUpdateTree(G.main, ntree);
- /* Reset visit flag. */
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
- node->tmp_flag = 0;
- }
-
- nodeChainIter(ntree, output_node, ntree_tag_bsdf_cb, tags, true);
+ nodeChainIterBackwards(ntree, output_node, ntree_tag_bsdf_cb, tags);
}
/* This one needs to work on a local tree. */
@@ -911,18 +840,26 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree,
{
bNodeTreeExec *exec;
- /* Extract output nodes from inside nodegroups. */
- ntree_shader_output_node_from_group(localtree, SHD_OUTPUT_EEVEE);
-
bNode *output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE);
ntree_shader_groups_expand_inputs(localtree);
+ ntree_shader_groups_flatten(localtree);
+
+ if (output == NULL) {
+ /* Search again, now including flattened nodes. */
+ output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE);
+ }
+
/* Perform all needed modifications on the tree in order to support
* displacement/bump mapping.
*/
ntree_shader_relink_displacement(localtree, output);
+ /* Duplicate bump height branches for manual derivatives.
+ */
+ nodeChainIterBackwards(localtree, output, ntree_shader_bump_branches, localtree);
+
/* TODO(fclem): consider moving this to the gpu shader tree evaluation. */
nTreeTags tags = {
.ssr_id = 1.0,
diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c
index 2e8f81979a8..9615c6f01e0 100644
--- a/source/blender/nodes/shader/node_shader_util.c
+++ b/source/blender/nodes/shader/node_shader_util.c
@@ -231,7 +231,7 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node
stack = exec->stack;
- for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
+ for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; n++, nodeexec++) {
node = nodeexec->node;
do_it = false;
@@ -258,6 +258,30 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node
}
}
+void node_shader_gpu_bump_tex_coord(GPUMaterial *mat, bNode *node, GPUNodeLink **link)
+{
+ if (node->branch_tag == 1) {
+ /* Add one time the value fo derivative to the input vector. */
+ GPU_link(mat, "dfdx_v3", *link, link);
+ }
+ else if (node->branch_tag == 2) {
+ /* Add one time the value fo derivative to the input vector. */
+ GPU_link(mat, "dfdy_v3", *link, link);
+ }
+ else {
+ /* nothing to do, reference center value. */
+ }
+}
+
+void node_shader_gpu_default_tex_coord(GPUMaterial *mat, bNode *node, GPUNodeLink **link)
+{
+ if (!*link) {
+ *link = GPU_attribute(CD_ORCO, "");
+ GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), *link, link);
+ node_shader_gpu_bump_tex_coord(mat, node, link);
+ }
+}
+
void node_shader_gpu_tex_mapping(GPUMaterial *mat,
bNode *node,
GPUNodeStack *in,
@@ -280,10 +304,10 @@ void node_shader_gpu_tex_mapping(GPUMaterial *mat,
tmat2 = GPU_uniform((float *)texmap->mat[2]);
tmat3 = GPU_uniform((float *)texmap->mat[3]);
- GPU_link(mat, "mapping", in[0].link, tmat0, tmat1, tmat2, tmat3, tmin, tmax, &in[0].link);
+ GPU_link(mat, "mapping_mat4", in[0].link, tmat0, tmat1, tmat2, tmat3, tmin, tmax, &in[0].link);
if (texmap->type == TEXMAP_TYPE_NORMAL) {
- GPU_link(mat, "texco_norm", in[0].link, &in[0].link);
+ GPU_link(mat, "vector_normalize", in[0].link, &in[0].link);
}
}
}
diff --git a/source/blender/nodes/shader/node_shader_util.h b/source/blender/nodes/shader/node_shader_util.h
index a3c553b983b..9719d0b36f5 100644
--- a/source/blender/nodes/shader/node_shader_util.h
+++ b/source/blender/nodes/shader/node_shader_util.h
@@ -84,6 +84,12 @@ void nodestack_get_vec(float *in, short type_in, bNodeStack *ns);
void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, struct bNodeStack *ns);
void node_data_from_gpu_stack(struct bNodeStack *ns, struct GPUNodeStack *gs);
+void node_shader_gpu_bump_tex_coord(struct GPUMaterial *mat,
+ struct bNode *node,
+ struct GPUNodeLink **link);
+void node_shader_gpu_default_tex_coord(struct GPUMaterial *mat,
+ struct bNode *node,
+ struct GPUNodeLink **link);
void node_shader_gpu_tex_mapping(struct GPUMaterial *mat,
struct bNode *node,
struct GPUNodeStack *in,
diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.c b/source/blender/nodes/shader/nodes/node_shader_attribute.c
index c92ae28f2e6..ecb8c53c312 100644
--- a/source/blender/nodes/shader/nodes/node_shader_attribute.c
+++ b/source/blender/nodes/shader/nodes/node_shader_attribute.c
@@ -67,7 +67,14 @@ static int node_shader_gpu_attribute(GPUMaterial *mat,
}
else {
GPUNodeLink *cd_attr = GPU_attribute(CD_AUTO_FROM_NAME, attr->name);
- return GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr);
+ GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr);
+
+ /* for each output. */
+ for (int i = 0; sh_node_attribute_out[i].type != -1; i++) {
+ node_shader_gpu_bump_tex_coord(mat, node, &out[i].link);
+ }
+
+ return 1;
}
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
index 595ddf27d0a..3340054396d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
@@ -120,6 +120,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
GPU_link(mat, "world_normals_get", &in[20].link);
}
+#if 0 /* Not used at the moment. */
/* Tangents */
if (!in[21].link) {
GPUNodeLink *orco = GPU_attribute(CD_ORCO, "");
@@ -131,6 +132,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
GPU_builtin(GPU_OBJECT_MATRIX),
&in[21].link);
}
+#endif
bool use_diffuse = socket_not_one(4) && socket_not_one(15);
bool use_subsurf = socket_not_zero(1) && use_diffuse && node->sss_id > 0;
diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.c
index d17edae35df..384701d2ddf 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bump.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bump.c
@@ -24,32 +24,17 @@
#include "node_shader_util.h"
/* **************** BUMP ******************** */
+/* clang-format off */
static bNodeSocketTemplate sh_node_bump_in[] = {
{SOCK_FLOAT, 1, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{SOCK_FLOAT, 1, N_("Distance"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_FLOAT,
- 1,
- N_("Height"),
- 1.0f,
- 1.0f,
- 1.0f,
- 1.0f,
- -1000.0f,
- 1000.0f,
- PROP_NONE,
- SOCK_HIDE_VALUE},
- {SOCK_VECTOR,
- 1,
- N_("Normal"),
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- -1.0f,
- 1.0f,
- PROP_NONE,
- SOCK_HIDE_VALUE},
- {-1, 0, ""}};
+ {SOCK_FLOAT, 1, N_("Height"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ {SOCK_FLOAT, 1, N_("Height_dx"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_UNAVAIL},
+ {SOCK_FLOAT, 1, N_("Height_dy"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_UNAVAIL},
+ {SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ {-1, 0, ""}
+};
+/* clang-format on */
static bNodeSocketTemplate sh_node_bump_out[] = {{SOCK_VECTOR, 0, "Normal"}, {-1, 0, ""}};
@@ -59,8 +44,8 @@ static int gpu_shader_bump(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- if (!in[3].link) {
- GPU_link(mat, "world_normals_get", &in[3].link);
+ if (!in[5].link) {
+ GPU_link(mat, "world_normals_get", &in[5].link);
}
float invert = (node->custom1) ? -1.0 : 1.0;
diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.c
index 10f6aadbc5f..257caabcabf 100644
--- a/source/blender/nodes/shader/nodes/node_shader_common.c
+++ b/source/blender/nodes/shader/nodes/node_shader_common.c
@@ -98,7 +98,7 @@ static void group_copy_inputs(bNode *gnode, bNodeStack **in, bNodeStack *gstack)
for (node = ngroup->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP_INPUT) {
- for (sock = node->outputs.first, a = 0; sock; sock = sock->next, ++a) {
+ for (sock = node->outputs.first, a = 0; sock; sock = sock->next, a++) {
ns = node_get_socket_stack(gstack, sock);
if (ns) {
copy_stack(ns, in[a]);
@@ -120,7 +120,7 @@ static void group_move_outputs(bNode *gnode, bNodeStack **out, bNodeStack *gstac
for (node = ngroup->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) {
- for (sock = node->inputs.first, a = 0; sock; sock = sock->next, ++a) {
+ for (sock = node->inputs.first, a = 0; sock; sock = sock->next, a++) {
ns = node_get_socket_stack(gstack, sock);
if (ns) {
move_stack(out[a], ns);
@@ -174,7 +174,7 @@ static void group_gpu_copy_inputs(bNode *gnode, GPUNodeStack *in, bNodeStack *gs
for (node = ngroup->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP_INPUT) {
- for (sock = node->outputs.first, a = 0; sock; sock = sock->next, ++a) {
+ for (sock = node->outputs.first, a = 0; sock; sock = sock->next, a++) {
ns = node_get_socket_stack(gstack, sock);
if (ns) {
/* convert the external gpu stack back to internal node stack data */
@@ -197,7 +197,7 @@ static void group_gpu_move_outputs(bNode *gnode, GPUNodeStack *out, bNodeStack *
for (node = ngroup->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) {
- for (sock = node->inputs.first, a = 0; sock; sock = sock->next, ++a) {
+ for (sock = node->inputs.first, a = 0; sock; sock = sock->next, a++) {
ns = node_get_socket_stack(gstack, sock);
if (ns) {
/* convert the node stack data result back to gpu stack */
diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.c b/source/blender/nodes/shader/nodes/node_shader_curves.c
index baf86951fe0..f5c89e6ba41 100644
--- a/source/blender/nodes/shader/nodes/node_shader_curves.c
+++ b/source/blender/nodes/shader/nodes/node_shader_curves.c
@@ -141,7 +141,7 @@ static int gpu_shader_curve_rgb(GPUMaterial *mat,
float ext_rgba[4][4];
float range_rgba[4];
- for (int a = 0; a < CM_TOT; ++a) {
+ for (int a = 0; a < CM_TOT; a++) {
const CurveMap *cm = &cumap->cm[a];
ext_rgba[a][0] = cm->mintable;
ext_rgba[a][2] = cm->maxtable;
diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.c b/source/blender/nodes/shader/nodes/node_shader_geometry.c
index df9a8ac8318..d94141c3699 100644
--- a/source/blender/nodes/shader/nodes/node_shader_geometry.c
+++ b/source/blender/nodes/shader/nodes/node_shader_geometry.c
@@ -41,9 +41,11 @@ static int node_shader_gpu_geometry(GPUMaterial *mat,
{
/* HACK: Don't request GPU_BARYCENTRIC_TEXCO if not used because it will
* trigger the use of geometry shader (and the performance penalty it implies). */
- float val[2] = {0.0f, 0.0f};
+ float val[4] = {0.0f, 0.0f, 0.0f, 0.0f};
GPUNodeLink *bary_link = (!out[5].hasoutput) ? GPU_constant(val) :
GPU_builtin(GPU_BARYCENTRIC_TEXCO);
+ /* Opti: don't request orco if not needed. */
+ GPUNodeLink *orco_link = (!out[2].hasoutput) ? GPU_constant(val) : GPU_attribute(CD_ORCO, "");
return GPU_stack_link(mat,
node,
@@ -52,7 +54,7 @@ static int node_shader_gpu_geometry(GPUMaterial *mat,
out,
GPU_builtin(GPU_VIEW_POSITION),
GPU_builtin(GPU_WORLD_NORMAL),
- GPU_attribute(CD_ORCO, ""),
+ orco_link,
GPU_builtin(GPU_OBJECT_MATRIX),
GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
bary_link);
diff --git a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
index ea916d25ffd..21d2cdcb3b5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
+++ b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
@@ -39,7 +39,7 @@ static bNodeSocketTemplate sh_node_hue_sat_out[] = {
/* note: it would be possible to use CMP version for both nodes */
static void do_hue_sat_fac(
- bNode *UNUSED(node), float *out, float hue, float sat, float val, float in[4], float fac)
+ bNode *UNUSED(node), float *out, float hue, float sat, float val, const float in[4], float fac)
{
if (fac != 0.0f && (hue != 0.5f || sat != 1.0f || val != 1.0f)) {
float col[3], hsv[3], mfac = 1.0f - fac;
diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.c
index eca0d96f2c8..d607fcdc7a1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mapping.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mapping.c
@@ -25,7 +25,10 @@
/* **************** MAPPING ******************** */
static bNodeSocketTemplate sh_node_mapping_in[] = {
- {SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE},
+ {SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_NONE},
+ {SOCK_VECTOR, 1, N_("Location"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
+ {SOCK_VECTOR, 1, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
+ {SOCK_VECTOR, 1, N_("Scale"), 1.0f, 1.0f, 1.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_XYZ},
{-1, 0, ""},
};
@@ -34,91 +37,27 @@ static bNodeSocketTemplate sh_node_mapping_out[] = {
{-1, 0, ""},
};
-static void *node_shader_initexec_mapping(bNodeExecContext *UNUSED(context),
- bNode *node,
- bNodeInstanceKey UNUSED(key))
-{
- TexMapping *texmap = node->storage;
- BKE_texture_mapping_init(texmap);
- return NULL;
-}
-
-/* do the regular mapping options for blender textures */
-static void node_shader_exec_mapping(void *UNUSED(data),
- int UNUSED(thread),
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- TexMapping *texmap = node->storage;
- float *vec = out[0]->vec;
-
- /* stack order input: vector */
- /* stack order output: vector */
- nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
- mul_m4_v3(texmap->mat, vec);
-
- if (texmap->flag & TEXMAP_CLIP_MIN) {
- if (vec[0] < texmap->min[0]) {
- vec[0] = texmap->min[0];
- }
- if (vec[1] < texmap->min[1]) {
- vec[1] = texmap->min[1];
- }
- if (vec[2] < texmap->min[2]) {
- vec[2] = texmap->min[2];
- }
- }
- if (texmap->flag & TEXMAP_CLIP_MAX) {
- if (vec[0] > texmap->max[0]) {
- vec[0] = texmap->max[0];
- }
- if (vec[1] > texmap->max[1]) {
- vec[1] = texmap->max[1];
- }
- if (vec[2] > texmap->max[2]) {
- vec[2] = texmap->max[2];
- }
- }
-
- if (texmap->type == TEXMAP_TYPE_NORMAL) {
- normalize_v3(vec);
- }
-}
-
-static void node_shader_init_mapping(bNodeTree *UNUSED(ntree), bNode *node)
-{
- node->storage = BKE_texture_mapping_add(TEXMAP_TYPE_POINT);
-}
-
static int gpu_shader_mapping(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
GPUNodeStack *in,
GPUNodeStack *out)
{
- TexMapping *texmap = node->storage;
- float domin = (texmap->flag & TEXMAP_CLIP_MIN) != 0;
- float domax = (texmap->flag & TEXMAP_CLIP_MAX) != 0;
- static float max[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
- static float min[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
- GPUNodeLink *tmin, *tmax, *tmat0, *tmat1, *tmat2, *tmat3;
-
- tmin = GPU_uniform((domin) ? texmap->min : min);
- tmax = GPU_uniform((domax) ? texmap->max : max);
- tmat0 = GPU_uniform((float *)texmap->mat[0]);
- tmat1 = GPU_uniform((float *)texmap->mat[1]);
- tmat2 = GPU_uniform((float *)texmap->mat[2]);
- tmat3 = GPU_uniform((float *)texmap->mat[3]);
-
- GPU_stack_link(mat, node, "mapping", in, out, tmat0, tmat1, tmat2, tmat3, tmin, tmax);
-
- if (texmap->type == TEXMAP_TYPE_NORMAL) {
- GPU_link(mat, "texco_norm", out[0].link, &out[0].link);
- }
+ static const char *names[] = {
+ [NODE_MAPPING_TYPE_POINT] = "mapping_point",
+ [NODE_MAPPING_TYPE_TEXTURE] = "mapping_texture",
+ [NODE_MAPPING_TYPE_VECTOR] = "mapping_vector",
+ [NODE_MAPPING_TYPE_NORMAL] = "mapping_normal",
+ };
+
+ return GPU_stack_link(mat, node, names[node->custom1], in, out);
+}
- return true;
+static void node_shader_update_mapping(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sock = nodeFindSocket(node, SOCK_IN, "Location");
+ nodeSetSocketAvailability(
+ sock, ELEM(node->custom1, NODE_MAPPING_TYPE_POINT, NODE_MAPPING_TYPE_TEXTURE));
}
void register_node_type_sh_mapping(void)
@@ -127,11 +66,8 @@ void register_node_type_sh_mapping(void)
sh_node_type_base(&ntype, SH_NODE_MAPPING, "Mapping", NODE_CLASS_OP_VECTOR, 0);
node_type_socket_templates(&ntype, sh_node_mapping_in, sh_node_mapping_out);
- node_type_size(&ntype, 320, 160, 360);
- node_type_init(&ntype, node_shader_init_mapping);
- node_type_storage(&ntype, "TexMapping", node_free_standard_storage, node_copy_standard_storage);
- node_type_exec(&ntype, node_shader_initexec_mapping, NULL, node_shader_exec_mapping);
node_type_gpu(&ntype, gpu_shader_mapping);
+ node_type_update(&ntype, node_shader_update_mapping);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_mixRgb.c b/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
index 872f4f9da9c..ae2184d8237 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
@@ -92,7 +92,7 @@ static int gpu_shader_mix_rgb(GPUMaterial *mat,
if (ret && node->custom2 & SHD_MIXRGB_CLAMP) {
float min[3] = {0.0f, 0.0f, 0.0f};
float max[3] = {1.0f, 1.0f, 1.0f};
- GPU_link(mat, "clamp_vec3", out[0].link, GPU_constant(min), GPU_constant(max), &out[0].link);
+ GPU_link(mat, "clamp_color", out[0].link, GPU_constant(min), GPU_constant(max), &out[0].link);
}
return ret;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
index 712c64084cc..18015d94f03 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
@@ -114,8 +114,8 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
break;
}
- GPU_link(mat, "vector_math_mix", strength, realnorm, negnorm, &out[0].link);
- GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
+ GPU_link(mat, "vector_mix", strength, realnorm, negnorm, &out[0].link);
+ GPU_link(mat, "vector_normalize", out[0].link, &out[0].link);
return true;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
index 9a0a132b311..9f93dfd837b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
+++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
@@ -61,8 +61,6 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat,
GPU_link(mat, "world_normals_get", &in[5].link);
}
- GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS);
-
if (node->sss_id > 0) {
bNodeSocket *socket = BLI_findlink(&node->original->inputs, 2);
bNodeSocketValueRGBA *socket_data = socket->default_value;
@@ -71,6 +69,10 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat,
/* For some reason it seems that the socket value is in ARGB format. */
GPU_material_sss_profile_create(
mat, &socket_data->value[1], &node->original->custom1, &socket_data_sharp->value);
+
+ /* sss_id is 0 only the node is not connected to any output.
+ * In this case flagging the material would trigger a bug (see T68736). */
+ GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS);
}
return GPU_stack_link(
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
index 92ade999650..9c86e78c3cd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
@@ -157,11 +157,7 @@ static int node_shader_gpu_tex_brick(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- if (!in[0].link) {
- in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
- }
-
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
NodeTexBrick *tex = (NodeTexBrick *)node->storage;
float offset_freq = tex->offset_freq;
@@ -171,9 +167,9 @@ static int node_shader_gpu_tex_brick(GPUMaterial *mat,
"node_tex_brick",
in,
out,
- GPU_constant(&tex->offset),
+ GPU_uniform(&tex->offset),
GPU_constant(&offset_freq),
- GPU_constant(&tex->squash),
+ GPU_uniform(&tex->squash),
GPU_constant(&squash_freq));
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_checker.c b/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
index 9dcb6057589..9b9138802fa 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
@@ -70,11 +70,7 @@ static int node_shader_gpu_tex_checker(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- if (!in[0].link) {
- in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
- }
-
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
return GPU_stack_link(mat, node, "node_tex_checker", in, out);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
index 0e34f2ca9b1..068458b7e1f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
@@ -45,22 +45,27 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat,
GPUNodeLink *inv_obmat = (ob != NULL) ? GPU_uniform(&ob->imat[0][0]) :
GPU_builtin(GPU_INVERSE_OBJECT_MATRIX);
- GPUNodeLink *orco = GPU_attribute(CD_ORCO, "");
+ /* Opti: don't request orco if not needed. */
+ GPUNodeLink *orco = (!out[0].hasoutput) ? GPU_constant((float[4]){0.0f, 0.0f, 0.0f, 0.0f}) :
+ GPU_attribute(CD_ORCO, "");
GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, "");
+ GPUNodeLink *viewpos = GPU_builtin(GPU_VIEW_POSITION);
+ GPUNodeLink *worldnor = GPU_builtin(GPU_WORLD_NORMAL);
+ GPUNodeLink *texcofacs = GPU_builtin(GPU_CAMERA_TEXCO_FACTORS);
- GPU_link(mat, "generated_from_orco", orco, &orco);
+ if (out[0].hasoutput) {
+ GPU_link(mat, "generated_from_orco", orco, &orco);
+ }
- return GPU_stack_link(mat,
- node,
- "node_tex_coord",
- in,
- out,
- GPU_builtin(GPU_VIEW_POSITION),
- GPU_builtin(GPU_WORLD_NORMAL),
- inv_obmat,
- GPU_builtin(GPU_CAMERA_TEXCO_FACTORS),
- orco,
- mtface);
+ GPU_stack_link(
+ mat, node, "node_tex_coord", in, out, viewpos, worldnor, inv_obmat, texcofacs, orco, mtface);
+
+ /* for each output. */
+ for (int i = 0; sh_node_tex_coord_out[i].type != -1; i++) {
+ node_shader_gpu_bump_tex_coord(mat, node, &out[i].link);
+ }
+
+ return 1;
}
/* node type definition */
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 bd8355ec885..6c380efe0b2 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
@@ -75,6 +75,7 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
if (!in[0].link) {
GPU_link(mat, "node_tex_environment_texco", GPU_builtin(GPU_VIEW_POSITION), &in[0].link);
+ node_shader_gpu_bump_tex_coord(mat, node, &in[0].link);
}
node_shader_gpu_tex_mapping(mat, node, in, out);
@@ -124,15 +125,15 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
if (ELEM(ima->alpha_mode, IMA_ALPHA_IGNORE, IMA_ALPHA_CHANNEL_PACKED) ||
IMB_colormanagement_space_name_is_data(ima->colorspace_settings.name)) {
/* Don't let alpha affect color output in these cases. */
- GPU_link(mat, "tex_color_alpha_clear", out[0].link, &out[0].link);
+ GPU_link(mat, "color_alpha_clear", out[0].link, &out[0].link);
}
else {
/* Always output with premultiplied alpha. */
if (ima->alpha_mode == IMA_ALPHA_PREMUL) {
- GPU_link(mat, "tex_color_alpha_clear", out[0].link, &out[0].link);
+ GPU_link(mat, "color_alpha_clear", out[0].link, &out[0].link);
}
else {
- GPU_link(mat, "tex_color_alpha_premultiply", out[0].link, &out[0].link);
+ GPU_link(mat, "color_alpha_premultiply", out[0].link, &out[0].link);
}
}
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
index 9271ba72a05..7f266c06a1b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
@@ -68,11 +68,7 @@ static int node_shader_gpu_tex_gradient(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- if (!in[0].link) {
- in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
- }
-
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
NodeTexGradient *tex = (NodeTexGradient *)node->storage;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
index 6f3614e357d..a6dfb2636fc 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
@@ -118,6 +118,7 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
if (!*texco) {
*texco = GPU_attribute(CD_MTFACE, "");
+ node_shader_gpu_bump_tex_coord(mat, node, texco);
}
node_shader_gpu_tex_mapping(mat, node, in, out);
@@ -183,7 +184,7 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
if (ELEM(ima->alpha_mode, IMA_ALPHA_IGNORE, IMA_ALPHA_CHANNEL_PACKED) ||
IMB_colormanagement_space_name_is_data(ima->colorspace_settings.name)) {
/* Don't let alpha affect color output in these cases. */
- GPU_link(mat, "tex_color_alpha_clear", out[0].link, &out[0].link);
+ GPU_link(mat, "color_alpha_clear", out[0].link, &out[0].link);
}
else {
/* Output premultiplied alpha depending on alpha socket usage. This makes
@@ -192,18 +193,18 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
* not, then there will be no artifacts from zero alpha areas. */
if (ima->alpha_mode == IMA_ALPHA_PREMUL) {
if (out[1].hasoutput) {
- GPU_link(mat, "tex_color_alpha_unpremultiply", out[0].link, &out[0].link);
+ GPU_link(mat, "color_alpha_unpremultiply", out[0].link, &out[0].link);
}
else {
- GPU_link(mat, "tex_color_alpha_clear", out[0].link, &out[0].link);
+ GPU_link(mat, "color_alpha_clear", out[0].link, &out[0].link);
}
}
else {
if (out[1].hasoutput) {
- GPU_link(mat, "tex_color_alpha_clear", out[0].link, &out[0].link);
+ GPU_link(mat, "color_alpha_clear", out[0].link, &out[0].link);
}
else {
- GPU_link(mat, "tex_color_alpha_premultiply", out[0].link, &out[0].link);
+ GPU_link(mat, "color_alpha_premultiply", out[0].link, &out[0].link);
}
}
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_magic.c b/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
index f5dc0435f27..d51594e549d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
@@ -73,11 +73,7 @@ static int node_shader_gpu_tex_magic(GPUMaterial *mat,
NodeTexMagic *tex = (NodeTexMagic *)node->storage;
float depth = tex->depth;
- if (!in[0].link) {
- in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
- }
-
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
return GPU_stack_link(mat, node, "node_tex_magic", in, out, GPU_constant(&depth));
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
index 250a1da3c23..daf4053f182 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
@@ -23,6 +23,7 @@
static bNodeSocketTemplate sh_node_tex_musgrave_in[] = {
{SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ {SOCK_FLOAT, 1, N_("W"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{SOCK_FLOAT, 1, N_("Scale"), 5.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{SOCK_FLOAT, 1, N_("Detail"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 16.0f},
{SOCK_FLOAT, 1, N_("Dimension"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
@@ -33,17 +34,6 @@ static bNodeSocketTemplate sh_node_tex_musgrave_in[] = {
};
static bNodeSocketTemplate sh_node_tex_musgrave_out[] = {
- {SOCK_RGBA,
- 0,
- N_("Color"),
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- PROP_NONE,
- SOCK_NO_INTERNAL_LINK},
{SOCK_FLOAT,
0,
N_("Fac"),
@@ -64,6 +54,7 @@ static void node_shader_init_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *node)
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->musgrave_type = SHD_MUSGRAVE_FBM;
+ tex->dimensions = 3;
node->storage = tex;
}
@@ -74,20 +65,81 @@ static int node_shader_gpu_tex_musgrave(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- if (!in[0].link) {
- in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
- }
-
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
NodeTexMusgrave *tex = (NodeTexMusgrave *)node->storage;
- float type = tex->musgrave_type;
+ int dimensions = tex->dimensions;
+ int type = tex->musgrave_type;
+
+ static const char *names[][5] = {
+ [SHD_MUSGRAVE_MULTIFRACTAL] =
+ {
+ "",
+ "node_tex_musgrave_multi_fractal_1d",
+ "node_tex_musgrave_multi_fractal_2d",
+ "node_tex_musgrave_multi_fractal_3d",
+ "node_tex_musgrave_multi_fractal_4d",
+ },
+ [SHD_MUSGRAVE_FBM] =
+ {
+ "",
+ "node_tex_musgrave_fBm_1d",
+ "node_tex_musgrave_fBm_2d",
+ "node_tex_musgrave_fBm_3d",
+ "node_tex_musgrave_fBm_4d",
+ },
+ [SHD_MUSGRAVE_HYBRID_MULTIFRACTAL] =
+ {
+ "",
+ "node_tex_musgrave_hybrid_multi_fractal_1d",
+ "node_tex_musgrave_hybrid_multi_fractal_2d",
+ "node_tex_musgrave_hybrid_multi_fractal_3d",
+ "node_tex_musgrave_hybrid_multi_fractal_4d",
+ },
+ [SHD_MUSGRAVE_RIDGED_MULTIFRACTAL] =
+ {
+ "",
+ "node_tex_musgrave_ridged_multi_fractal_1d",
+ "node_tex_musgrave_ridged_multi_fractal_2d",
+ "node_tex_musgrave_ridged_multi_fractal_3d",
+ "node_tex_musgrave_ridged_multi_fractal_4d",
+ },
+ [SHD_MUSGRAVE_HETERO_TERRAIN] =
+ {
+ "",
+ "node_tex_musgrave_hetero_terrain_1d",
+ "node_tex_musgrave_hetero_terrain_2d",
+ "node_tex_musgrave_hetero_terrain_3d",
+ "node_tex_musgrave_hetero_terrain_4d",
+ },
+ };
+
+ BLI_assert(type >= 0 && type < 5);
+ BLI_assert(dimensions > 0 && dimensions < 5);
+
+ return GPU_stack_link(mat, node, names[type][dimensions], in, out);
+}
+
+static void node_shader_update_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeTexMusgrave *tex = (NodeTexMusgrave *)node->storage;
+
+ bNodeSocket *inVectorSock = nodeFindSocket(node, SOCK_IN, "Vector");
+ bNodeSocket *inWSock = nodeFindSocket(node, SOCK_IN, "W");
+ bNodeSocket *inOffsetSock = nodeFindSocket(node, SOCK_IN, "Offset");
+ bNodeSocket *inGainSock = nodeFindSocket(node, SOCK_IN, "Gain");
- return GPU_stack_link(mat, node, "node_tex_musgrave", in, out, GPU_constant(&type));
+ nodeSetSocketAvailability(inVectorSock, tex->dimensions != 1);
+ nodeSetSocketAvailability(inWSock, tex->dimensions == 1 || tex->dimensions == 4);
+ nodeSetSocketAvailability(inOffsetSock,
+ tex->musgrave_type != SHD_MUSGRAVE_MULTIFRACTAL &&
+ tex->musgrave_type != SHD_MUSGRAVE_FBM);
+ nodeSetSocketAvailability(inGainSock,
+ tex->musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL &&
+ tex->musgrave_type != SHD_MUSGRAVE_RIDGED_MULTIFRACTAL);
}
-/* node type definition */
void register_node_type_sh_tex_musgrave(void)
{
static bNodeType ntype;
@@ -99,6 +151,7 @@ void register_node_type_sh_tex_musgrave(void)
node_type_storage(
&ntype, "NodeTexMusgrave", node_free_standard_storage, node_copy_standard_storage);
node_type_gpu(&ntype, node_shader_gpu_tex_musgrave);
+ node_type_update(&ntype, node_shader_update_tex_musgrave);
nodeRegisterType(&ntype);
}
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 34c4b17f255..0b3b249c3d9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
@@ -23,6 +23,7 @@
static bNodeSocketTemplate sh_node_tex_noise_in[] = {
{SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ {SOCK_FLOAT, 1, N_("W"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{SOCK_FLOAT, 1, N_("Scale"), 5.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{SOCK_FLOAT, 1, N_("Detail"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 16.0f},
{SOCK_FLOAT, 1, N_("Distortion"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
@@ -30,27 +31,27 @@ static bNodeSocketTemplate sh_node_tex_noise_in[] = {
};
static bNodeSocketTemplate sh_node_tex_noise_out[] = {
- {SOCK_RGBA,
+ {SOCK_FLOAT,
0,
- N_("Color"),
+ N_("Fac"),
0.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
- PROP_NONE,
+ PROP_FACTOR,
SOCK_NO_INTERNAL_LINK},
- {SOCK_FLOAT,
+ {SOCK_RGBA,
0,
- N_("Fac"),
+ N_("Color"),
0.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
- PROP_FACTOR,
+ PROP_NONE,
SOCK_NO_INTERNAL_LINK},
{-1, 0, ""},
};
@@ -60,6 +61,7 @@ static void node_shader_init_tex_noise(bNodeTree *UNUSED(ntree), bNode *node)
NodeTexNoise *tex = MEM_callocN(sizeof(NodeTexNoise), "NodeTexNoise");
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
+ tex->dimensions = 3;
node->storage = tex;
}
@@ -70,14 +72,28 @@ static int node_shader_gpu_tex_noise(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- if (!in[0].link) {
- in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
- }
-
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
- return GPU_stack_link(mat, node, "node_tex_noise", in, out);
+ NodeTexNoise *tex = (NodeTexNoise *)node->storage;
+ static const char *names[] = {
+ "",
+ "node_noise_texture_1d",
+ "node_noise_texture_2d",
+ "node_noise_texture_3d",
+ "node_noise_texture_4d",
+ };
+ return GPU_stack_link(mat, node, names[tex->dimensions], in, out);
+}
+
+static void node_shader_update_tex_noise(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector");
+ bNodeSocket *sockW = nodeFindSocket(node, SOCK_IN, "W");
+
+ NodeTexNoise *tex = (NodeTexNoise *)node->storage;
+ nodeSetSocketAvailability(sockVector, tex->dimensions != 1);
+ nodeSetSocketAvailability(sockW, tex->dimensions == 1 || tex->dimensions == 4);
}
/* node type definition */
@@ -91,6 +107,7 @@ void register_node_type_sh_tex_noise(void)
node_type_storage(
&ntype, "NodeTexNoise", node_free_standard_storage, node_copy_standard_storage);
node_type_gpu(&ntype, node_shader_gpu_tex_noise);
+ node_type_update(&ntype, node_shader_update_tex_noise);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
index e0b4de985d8..adcb93d7775 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
@@ -23,12 +23,26 @@
static bNodeSocketTemplate sh_node_tex_voronoi_in[] = {
{SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ {SOCK_FLOAT, 1, N_("W"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{SOCK_FLOAT, 1, N_("Scale"), 5.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
+ {SOCK_FLOAT, 1, N_("Smoothness"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{SOCK_FLOAT, 1, N_("Exponent"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 32.0f},
+ {SOCK_FLOAT, 1, N_("Randomness"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{-1, 0, ""},
};
static bNodeSocketTemplate sh_node_tex_voronoi_out[] = {
+ {SOCK_FLOAT,
+ 0,
+ N_("Distance"),
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ PROP_NONE,
+ SOCK_NO_INTERNAL_LINK},
{SOCK_RGBA,
0,
N_("Color"),
@@ -40,16 +54,28 @@ static bNodeSocketTemplate sh_node_tex_voronoi_out[] = {
1.0f,
PROP_NONE,
SOCK_NO_INTERNAL_LINK},
+ {SOCK_VECTOR,
+ 0,
+ N_("Position"),
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ PROP_NONE,
+ SOCK_NO_INTERNAL_LINK},
+ {SOCK_FLOAT, 0, N_("W"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
{SOCK_FLOAT,
0,
- N_("Fac"),
+ N_("Radius"),
0.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
- PROP_FACTOR,
+ PROP_NONE,
SOCK_NO_INTERNAL_LINK},
{-1, 0, ""},
};
@@ -59,8 +85,8 @@ static void node_shader_init_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node)
NodeTexVoronoi *tex = MEM_callocN(sizeof(NodeTexVoronoi), "NodeTexVoronoi");
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
- tex->coloring = SHD_VORONOI_INTENSITY;
- tex->distance = SHD_VORONOI_DISTANCE;
+ tex->dimensions = 3;
+ tex->distance = SHD_VORONOI_EUCLIDEAN;
tex->feature = SHD_VORONOI_F1;
node->storage = tex;
@@ -72,46 +98,99 @@ static int node_shader_gpu_tex_voronoi(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- if (!in[0].link) {
- in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
- }
-
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
+ static const char *names[][5] = {
+ [SHD_VORONOI_F1] =
+ {
+ "",
+ "node_tex_voronoi_f1_1d",
+ "node_tex_voronoi_f1_2d",
+ "node_tex_voronoi_f1_3d",
+ "node_tex_voronoi_f1_4d",
+ },
+ [SHD_VORONOI_F2] =
+ {
+ "",
+ "node_tex_voronoi_f2_1d",
+ "node_tex_voronoi_f2_2d",
+ "node_tex_voronoi_f2_3d",
+ "node_tex_voronoi_f2_4d",
+ },
+ [SHD_VORONOI_SMOOTH_F1] =
+ {
+ "",
+ "node_tex_voronoi_smooth_f1_1d",
+ "node_tex_voronoi_smooth_f1_2d",
+ "node_tex_voronoi_smooth_f1_3d",
+ "node_tex_voronoi_smooth_f1_4d",
+ },
+ [SHD_VORONOI_DISTANCE_TO_EDGE] =
+ {
+ "",
+ "node_tex_voronoi_distance_to_edge_1d",
+ "node_tex_voronoi_distance_to_edge_2d",
+ "node_tex_voronoi_distance_to_edge_3d",
+ "node_tex_voronoi_distance_to_edge_4d",
+ },
+ [SHD_VORONOI_N_SPHERE_RADIUS] =
+ {
+ "",
+ "node_tex_voronoi_n_sphere_radius_1d",
+ "node_tex_voronoi_n_sphere_radius_2d",
+ "node_tex_voronoi_n_sphere_radius_3d",
+ "node_tex_voronoi_n_sphere_radius_4d",
+ },
+ };
+
NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
- float coloring = tex->coloring;
float metric = tex->distance;
- float feature = tex->feature;
-
- return GPU_stack_link(mat,
- node,
- "node_tex_voronoi",
- in,
- out,
- GPU_constant(&coloring),
- GPU_constant(&metric),
- GPU_constant(&feature));
+
+ BLI_assert(tex->feature >= 0 && tex->feature < 5);
+ BLI_assert(tex->dimensions > 0 && tex->dimensions < 5);
+
+ return GPU_stack_link(
+ mat, node, names[tex->feature][tex->dimensions], in, out, GPU_constant(&metric));
}
static void node_shader_update_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node)
{
+ bNodeSocket *inVectorSock = nodeFindSocket(node, SOCK_IN, "Vector");
+ bNodeSocket *inWSock = nodeFindSocket(node, SOCK_IN, "W");
+ bNodeSocket *inSmoothnessSock = nodeFindSocket(node, SOCK_IN, "Smoothness");
+ bNodeSocket *inExponentSock = nodeFindSocket(node, SOCK_IN, "Exponent");
+
+ bNodeSocket *outDistanceSock = nodeFindSocket(node, SOCK_OUT, "Distance");
+ bNodeSocket *outColorSock = nodeFindSocket(node, SOCK_OUT, "Color");
+ bNodeSocket *outPositionSock = nodeFindSocket(node, SOCK_OUT, "Position");
+ bNodeSocket *outWSock = nodeFindSocket(node, SOCK_OUT, "W");
+ bNodeSocket *outRadiusSock = nodeFindSocket(node, SOCK_OUT, "Radius");
+
NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
- bNodeSocket *sock;
-
- for (sock = node->inputs.first; sock; sock = sock->next) {
- if (STREQ(sock->name, "Exponent")) {
- if (tex->distance == SHD_VORONOI_MINKOWSKI) {
- sock->flag &= ~SOCK_UNAVAIL;
- }
- else {
- sock->flag |= SOCK_UNAVAIL;
- }
- }
- }
+
+ nodeSetSocketAvailability(inWSock, tex->dimensions == 1 || tex->dimensions == 4);
+ nodeSetSocketAvailability(inVectorSock, tex->dimensions != 1);
+ nodeSetSocketAvailability(
+ inExponentSock,
+ tex->distance == SHD_VORONOI_MINKOWSKI && tex->dimensions != 1 &&
+ !ELEM(tex->feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS));
+ nodeSetSocketAvailability(inSmoothnessSock, tex->feature == SHD_VORONOI_SMOOTH_F1);
+ nodeSetSocketAvailability(outDistanceSock, tex->feature != SHD_VORONOI_N_SPHERE_RADIUS);
+ nodeSetSocketAvailability(outColorSock,
+ tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
+ tex->feature != SHD_VORONOI_N_SPHERE_RADIUS);
+ nodeSetSocketAvailability(outPositionSock,
+ tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
+ tex->feature != SHD_VORONOI_N_SPHERE_RADIUS &&
+ tex->dimensions != 1);
+ nodeSetSocketAvailability(outWSock,
+ tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
+ tex->feature != SHD_VORONOI_N_SPHERE_RADIUS &&
+ (tex->dimensions == 1 || tex->dimensions == 4));
+ nodeSetSocketAvailability(outRadiusSock, tex->feature == SHD_VORONOI_N_SPHERE_RADIUS);
}
-/* node type definition */
void register_node_type_sh_tex_voronoi(void)
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c b/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
index 65b78f2923d..b525f4897a9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
@@ -72,11 +72,7 @@ static int node_shader_gpu_tex_wave(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- if (!in[0].link) {
- in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
- }
-
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
NodeTexWave *tex = (NodeTexWave *)node->storage;
diff --git a/source/blender/nodes/shader/nodes/node_shader_uvmap.c b/source/blender/nodes/shader/nodes/node_shader_uvmap.c
index 73fb022e476..a2e47735490 100644
--- a/source/blender/nodes/shader/nodes/node_shader_uvmap.c
+++ b/source/blender/nodes/shader/nodes/node_shader_uvmap.c
@@ -43,7 +43,11 @@ static int node_shader_gpu_uvmap(GPUMaterial *mat,
NodeShaderUVMap *attr = node->storage;
GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, attr->uv_map);
- return GPU_stack_link(mat, node, "node_uvmap", in, out, mtface);
+ GPU_stack_link(mat, node, "node_uvmap", in, out, mtface);
+
+ node_shader_gpu_bump_tex_coord(mat, node, &out[0].link);
+
+ return 1;
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c b/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
index fe0e7b1d638..563ef89162b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
@@ -132,7 +132,7 @@ static int gpu_shader_vect_transform(GPUMaterial *mat,
}
if (nodeprop->type == SHD_VECT_TRANSFORM_TYPE_NORMAL) {
- GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
+ GPU_link(mat, "vector_normalize", out[0].link, &out[0].link);
}
return true;
diff --git a/source/blender/nodes/shader/nodes/node_shader_vertex_color.c b/source/blender/nodes/shader/nodes/node_shader_vertex_color.c
new file mode 100644
index 00000000000..8848fc37c66
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_vertex_color.c
@@ -0,0 +1,58 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "../node_shader_util.h"
+
+static bNodeSocketTemplate sh_node_vertex_color_out[] = {
+ {SOCK_RGBA, 0, N_("Color")},
+ {SOCK_FLOAT, 0, N_("Alpha")},
+ {-1, 0, ""},
+};
+
+static void node_shader_init_vertex_color(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeShaderVertexColor *vertexColor = MEM_callocN(sizeof(NodeShaderVertexColor),
+ "NodeShaderVertexColor");
+ node->storage = vertexColor;
+}
+
+static int node_shader_gpu_vertex_color(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ NodeShaderVertexColor *vertexColor = (NodeShaderVertexColor *)node->storage;
+ GPUNodeLink *vertexColorLink = GPU_attribute(CD_MCOL, vertexColor->layer_name);
+ return GPU_stack_link(mat, node, "node_vertex_color", in, out, vertexColorLink);
+}
+
+void register_node_type_sh_vertex_color(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_VERTEX_COLOR, "Vertex Color", NODE_CLASS_INPUT, 0);
+ node_type_socket_templates(&ntype, NULL, sh_node_vertex_color_out);
+ node_type_init(&ntype, node_shader_init_vertex_color);
+ node_type_storage(
+ &ntype, "NodeShaderVertexColor", node_free_standard_storage, node_copy_standard_storage);
+ node_type_gpu(&ntype, node_shader_gpu_vertex_color);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c
index b8435d3a352..a505bed2458 100644
--- a/source/blender/nodes/texture/nodes/node_texture_common.c
+++ b/source/blender/nodes/texture/nodes/node_texture_common.c
@@ -84,7 +84,7 @@ static void group_copy_inputs(bNode *gnode, bNodeStack **in, bNodeStack *gstack)
for (node = ngroup->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP_INPUT) {
- for (sock = node->outputs.first, a = 0; sock; sock = sock->next, ++a) {
+ for (sock = node->outputs.first, a = 0; sock; sock = sock->next, a++) {
if (in[a]) { /* shouldn't need to check this [#36694] */
ns = node_get_socket_stack(gstack, sock);
if (ns) {
@@ -108,7 +108,7 @@ static void group_copy_outputs(bNode *gnode, bNodeStack **out, bNodeStack *gstac
for (node = ngroup->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) {
- for (sock = node->inputs.first, a = 0; sock; sock = sock->next, ++a) {
+ for (sock = node->inputs.first, a = 0; sock; sock = sock->next, a++) {
if (out[a]) { /* shouldn't need to check this [#36694] */
ns = node_get_socket_stack(gstack, sock);
if (ns) {
diff --git a/source/blender/nodes/texture/nodes/node_texture_proc.c b/source/blender/nodes/texture/nodes/node_texture_proc.c
index b0b646dfd16..5c3b0dc7f55 100644
--- a/source/blender/nodes/texture/nodes/node_texture_proc.c
+++ b/source/blender/nodes/texture/nodes/node_texture_proc.c
@@ -165,83 +165,84 @@ static void voronoi_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short th
tex->ns_outscale = tex_input_value(in[I + 4], p, thread);
tex->noisesize = tex_input_value(in[I + 5], p, thread);
}
-ProcDef(voronoi)
+ProcDef(voronoi);
- /* --- BLEND -- */
- static bNodeSocketTemplate blend_inputs[] = {COMMON_INPUTS, {-1, 0, ""}};
-ProcNoInputs(blend) ProcDef(blend)
+/* --- BLEND -- */
+static bNodeSocketTemplate blend_inputs[] = {COMMON_INPUTS, {-1, 0, ""}};
+ProcNoInputs(blend);
+ProcDef(blend);
- /* -- MAGIC -- */
- static bNodeSocketTemplate magic_inputs[] = {
- COMMON_INPUTS,
- {SOCK_FLOAT, 1, N_("Turbulence"), 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 200.0f, PROP_UNSIGNED},
- {-1, 0, ""}};
+/* -- MAGIC -- */
+static bNodeSocketTemplate magic_inputs[] = {
+ COMMON_INPUTS,
+ {SOCK_FLOAT, 1, N_("Turbulence"), 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 200.0f, PROP_UNSIGNED},
+ {-1, 0, ""}};
static void magic_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short thread)
{
tex->turbul = tex_input_value(in[I + 0], p, thread);
}
-ProcDef(magic)
-
- /* --- MARBLE --- */
- static bNodeSocketTemplate marble_inputs[] = {
- COMMON_INPUTS,
- {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
- {SOCK_FLOAT, 1, N_("Turbulence"), 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 200.0f, PROP_UNSIGNED},
- {-1, 0, ""}};
+ProcDef(magic);
+
+/* --- MARBLE --- */
+static bNodeSocketTemplate marble_inputs[] = {
+ COMMON_INPUTS,
+ {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
+ {SOCK_FLOAT, 1, N_("Turbulence"), 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 200.0f, PROP_UNSIGNED},
+ {-1, 0, ""}};
static void marble_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short thread)
{
tex->noisesize = tex_input_value(in[I + 0], p, thread);
tex->turbul = tex_input_value(in[I + 1], p, thread);
}
-ProcDef(marble)
+ProcDef(marble);
- /* --- CLOUDS --- */
- static bNodeSocketTemplate clouds_inputs[] = {
- COMMON_INPUTS,
- {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
- {-1, 0, ""}};
+/* --- CLOUDS --- */
+static bNodeSocketTemplate clouds_inputs[] = {
+ COMMON_INPUTS,
+ {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
+ {-1, 0, ""}};
static void clouds_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short thread)
{
tex->noisesize = tex_input_value(in[I + 0], p, thread);
}
-ProcDef(clouds)
-
- /* --- DISTORTED NOISE --- */
- static bNodeSocketTemplate distnoise_inputs[] = {
- COMMON_INPUTS,
- {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
- {SOCK_FLOAT, 1, N_("Distortion"), 1.00f, 0.0f, 0.0f, 0.0f, 0.0000f, 10.0f, PROP_UNSIGNED},
- {-1, 0, ""}};
+ProcDef(clouds);
+
+/* --- DISTORTED NOISE --- */
+static bNodeSocketTemplate distnoise_inputs[] = {
+ COMMON_INPUTS,
+ {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
+ {SOCK_FLOAT, 1, N_("Distortion"), 1.00f, 0.0f, 0.0f, 0.0f, 0.0000f, 10.0f, PROP_UNSIGNED},
+ {-1, 0, ""}};
static void distnoise_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short thread)
{
tex->noisesize = tex_input_value(in[I + 0], p, thread);
tex->dist_amount = tex_input_value(in[I + 1], p, thread);
}
-ProcDef(distnoise)
-
- /* --- WOOD --- */
- static bNodeSocketTemplate wood_inputs[] = {
- COMMON_INPUTS,
- {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
- {SOCK_FLOAT, 1, N_("Turbulence"), 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 200.0f, PROP_UNSIGNED},
- {-1, 0, ""}};
+ProcDef(distnoise);
+
+/* --- WOOD --- */
+static bNodeSocketTemplate wood_inputs[] = {
+ COMMON_INPUTS,
+ {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
+ {SOCK_FLOAT, 1, N_("Turbulence"), 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 200.0f, PROP_UNSIGNED},
+ {-1, 0, ""}};
static void wood_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short thread)
{
tex->noisesize = tex_input_value(in[I + 0], p, thread);
tex->turbul = tex_input_value(in[I + 1], p, thread);
}
-ProcDef(wood)
-
- /* --- MUSGRAVE --- */
- static bNodeSocketTemplate musgrave_inputs[] = {
- COMMON_INPUTS,
- {SOCK_FLOAT, 1, N_("H"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
- {SOCK_FLOAT, 1, N_("Lacunarity"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 6.0f, PROP_UNSIGNED},
- {SOCK_FLOAT, 1, N_("Octaves"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 8.0f, PROP_UNSIGNED},
-
- {SOCK_FLOAT, 1, N_("iScale"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 10.0f, PROP_UNSIGNED},
- {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
- {-1, 0, ""}};
+ProcDef(wood);
+
+/* --- MUSGRAVE --- */
+static bNodeSocketTemplate musgrave_inputs[] = {
+ COMMON_INPUTS,
+ {SOCK_FLOAT, 1, N_("H"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
+ {SOCK_FLOAT, 1, N_("Lacunarity"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 6.0f, PROP_UNSIGNED},
+ {SOCK_FLOAT, 1, N_("Octaves"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 8.0f, PROP_UNSIGNED},
+
+ {SOCK_FLOAT, 1, N_("iScale"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 10.0f, PROP_UNSIGNED},
+ {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
+ {-1, 0, ""}};
static void musgrave_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short thread)
{
tex->mg_H = tex_input_value(in[I + 0], p, thread);
@@ -250,28 +251,29 @@ static void musgrave_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short t
tex->ns_outscale = tex_input_value(in[I + 3], p, thread);
tex->noisesize = tex_input_value(in[I + 4], p, thread);
}
-ProcDef(musgrave)
-
- /* --- NOISE --- */
- static bNodeSocketTemplate noise_inputs[] = {COMMON_INPUTS, {-1, 0, ""}};
-ProcNoInputs(noise) ProcDef(noise)
-
- /* --- STUCCI --- */
- static bNodeSocketTemplate stucci_inputs[] = {
- COMMON_INPUTS,
- {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
- {SOCK_FLOAT, 1, N_("Turbulence"), 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 200.0f, PROP_UNSIGNED},
- {-1, 0, ""}};
+ProcDef(musgrave);
+
+/* --- NOISE --- */
+static bNodeSocketTemplate noise_inputs[] = {COMMON_INPUTS, {-1, 0, ""}};
+ProcNoInputs(noise);
+ProcDef(noise);
+
+/* --- STUCCI --- */
+static bNodeSocketTemplate stucci_inputs[] = {
+ COMMON_INPUTS,
+ {SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED},
+ {SOCK_FLOAT, 1, N_("Turbulence"), 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 200.0f, PROP_UNSIGNED},
+ {-1, 0, ""}};
static void stucci_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short thread)
{
tex->noisesize = tex_input_value(in[I + 0], p, thread);
tex->turbul = tex_input_value(in[I + 1], p, thread);
}
-ProcDef(stucci)
+ProcDef(stucci);
- /* --- */
+/* --- */
- static void init(bNodeTree *UNUSED(ntree), bNode *node)
+static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
Tex *tex = MEM_callocN(sizeof(Tex), "Tex");
node->storage = tex;
@@ -303,9 +305,9 @@ ProcDef(stucci)
#define C outputs_color_only
#define CV outputs_both
-TexDef(TEX_VORONOI, CV, voronoi, "Voronoi") TexDef(TEX_BLEND, C, blend, "Blend")
- TexDef(TEX_MAGIC, C, magic, "Magic") TexDef(TEX_MARBLE, CV, marble, "Marble")
- TexDef(TEX_CLOUDS, CV, clouds, "Clouds") TexDef(TEX_WOOD, CV, wood, "Wood")
- TexDef(TEX_MUSGRAVE, CV, musgrave, "Musgrave") TexDef(TEX_NOISE, C, noise, "Noise")
- TexDef(TEX_STUCCI, CV, stucci, "Stucci")
- TexDef(TEX_DISTNOISE, CV, distnoise, "Distorted Noise")
+TexDef(TEX_VORONOI, CV, voronoi, "Voronoi") TexDef(TEX_BLEND, C, blend, "Blend");
+TexDef(TEX_MAGIC, C, magic, "Magic") TexDef(TEX_MARBLE, CV, marble, "Marble");
+TexDef(TEX_CLOUDS, CV, clouds, "Clouds") TexDef(TEX_WOOD, CV, wood, "Wood");
+TexDef(TEX_MUSGRAVE, CV, musgrave, "Musgrave") TexDef(TEX_NOISE, C, noise, "Noise");
+TexDef(TEX_STUCCI, CV, stucci, "Stucci");
+TexDef(TEX_DISTNOISE, CV, distnoise, "Distorted Noise");
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index 07cb3370eec..c057e74b72b 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -231,9 +231,9 @@ static void cloth_setup_constraints(ClothModifierData *clmd,
verts[v].impulse_count = 0;
}
- for (i = 0; i < totcolliders; ++i) {
+ for (i = 0; i < totcolliders; i++) {
ColliderContacts *ct = &contacts[i];
- for (j = 0; j < ct->totcollisions; ++j) {
+ for (j = 0; j < ct->totcollisions; j++) {
CollPair *collpair = &ct->collisions[j];
// float restitution = (1.0f - clmd->coll_parms->damping) * (1.0f - ct->ob->pd->pdef_sbdamp);
float restitution = 0.0f;
@@ -867,8 +867,8 @@ static void cloth_continuum_step(ClothModifierData *clmd, float dt)
clmd->hair_grid_min[(axis + 2) % 3];
BKE_sim_debug_data_clear_category(clmd->debug_data, "grid velocity");
- for (j = 0; j < size; ++j) {
- for (i = 0; i < size; ++i) {
+ for (j = 0; j < size; j++) {
+ for (i = 0; i < size; i++) {
float x[3], v[3], gvel[3], gvel_smooth[3], gdensity;
madd_v3_v3v3fl(x, offset, a, (float)i / (float)(size - 1));
@@ -1111,6 +1111,12 @@ int BPH_cloth_solve(
ImplicitSolverResult result;
if (is_hair) {
+ /* copy velocities for collision */
+ for (i = 0; i < mvert_num; i++) {
+ BPH_mass_spring_get_motion_state(id, i, NULL, verts[i].tv);
+ copy_v3_v3(verts[i].v, verts[i].tv);
+ }
+
/* determine contact points */
if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
cloth_find_point_contacts(depsgraph, ob, clmd, 0.0f, tf, &contacts, &totcolliders);
diff --git a/source/blender/physics/intern/ConstrainedConjugateGradient.h b/source/blender/physics/intern/ConstrainedConjugateGradient.h
index 56151b714a6..c924490f97d 100644
--- a/source/blender/physics/intern/ConstrainedConjugateGradient.h
+++ b/source/blender/physics/intern/ConstrainedConjugateGradient.h
@@ -283,7 +283,7 @@ class ConstrainedConjugateGradient
m_iterations = Base::maxIterations();
m_error = Base::m_tolerance;
- for (int j = 0; j < b.cols(); ++j) {
+ for (int j = 0; j < b.cols(); j++) {
m_iterations = Base::maxIterations();
m_error = Base::m_tolerance;
diff --git a/source/blender/physics/intern/eigen_utils.h b/source/blender/physics/intern/eigen_utils.h
index 273b13e096a..2b50da0d190 100644
--- a/source/blender/physics/intern/eigen_utils.h
+++ b/source/blender/physics/intern/eigen_utils.h
@@ -54,14 +54,14 @@ class Vector3 : public Eigen::Vector3f {
Vector3(const ctype &v)
{
- for (int k = 0; k < 3; ++k) {
+ for (int k = 0; k < 3; k++) {
coeffRef(k) = v[k];
}
}
Vector3 &operator=(const ctype &v)
{
- for (int k = 0; k < 3; ++k) {
+ for (int k = 0; k < 3; k++) {
coeffRef(k) = v[k];
}
return *this;
@@ -86,8 +86,8 @@ class Matrix3 : public Eigen::Matrix3f {
Matrix3(const ctype &v)
{
- for (int k = 0; k < 3; ++k) {
- for (int l = 0; l < 3; ++l) {
+ for (int k = 0; k < 3; k++) {
+ for (int l = 0; l < 3; l++) {
coeffRef(l, k) = v[k][l];
}
}
@@ -95,8 +95,8 @@ class Matrix3 : public Eigen::Matrix3f {
Matrix3 &operator=(const ctype &v)
{
- for (int k = 0; k < 3; ++k) {
- for (int l = 0; l < 3; ++l) {
+ for (int k = 0; k < 3; k++) {
+ for (int l = 0; l < 3; l++) {
coeffRef(l, k) = v[k][l];
}
}
@@ -170,8 +170,8 @@ struct lMatrix3fCtor {
{
i *= 3;
j *= 3;
- for (int k = 0; k < 3; ++k) {
- for (int l = 0; l < 3; ++l) {
+ for (int k = 0; k < 3; k++) {
+ for (int l = 0; l < 3; l++) {
m_trips.push_back(Triplet(i + k, j + l, m.coeff(l, k)));
}
}
@@ -181,8 +181,8 @@ struct lMatrix3fCtor {
{
i *= 3;
j *= 3;
- for (int k = 0; k < 3; ++k) {
- for (int l = 0; l < 3; ++l) {
+ for (int k = 0; k < 3; k++) {
+ for (int l = 0; l < 3; l++) {
m_trips.push_back(Triplet(i + k, j + l, -m.coeff(l, k)));
}
}
@@ -205,7 +205,7 @@ using Eigen::ComputationInfo;
BLI_INLINE void print_lvector(const lVector3f &v)
{
- for (int i = 0; i < v.rows(); ++i) {
+ for (int i = 0; i < v.rows(); i++) {
if (i > 0 && i % 3 == 0) {
printf("\n");
}
@@ -216,12 +216,12 @@ BLI_INLINE void print_lvector(const lVector3f &v)
BLI_INLINE void print_lmatrix(const lMatrix &m)
{
- for (int j = 0; j < m.rows(); ++j) {
+ for (int j = 0; j < m.rows(); j++) {
if (j > 0 && j % 3 == 0) {
printf("\n");
}
- for (int i = 0; i < m.cols(); ++i) {
+ for (int i = 0; i < m.cols(); i++) {
if (i > 0 && i % 3 == 0) {
printf(" ");
}
diff --git a/source/blender/physics/intern/hair_volume.cpp b/source/blender/physics/intern/hair_volume.cpp
index 33c65a0cf95..88913eef7df 100644
--- a/source/blender/physics/intern/hair_volume.cpp
+++ b/source/blender/physics/intern/hair_volume.cpp
@@ -160,7 +160,7 @@ BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid,
if (velocity) {
int k;
- for (k = 0; k < 3; ++k) {
+ for (k = 0; k < 3; k++) {
velocity[k] = muvw[2] *
(muvw[1] * (muvw[0] * data[0].velocity[k] + uvw[0] * data[1].velocity[k]) +
uvw[1] * (muvw[0] * data[2].velocity[k] + uvw[0] * data[3].velocity[k])) +
@@ -172,7 +172,7 @@ BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid,
if (vel_smooth) {
int k;
- for (k = 0; k < 3; ++k) {
+ for (k = 0; k < 3; k++) {
vel_smooth[k] = muvw[2] * (muvw[1] * (muvw[0] * data[0].velocity_smooth[k] +
uvw[0] * data[1].velocity_smooth[k]) +
uvw[1] * (muvw[0] * data[2].velocity_smooth[k] +
@@ -297,7 +297,7 @@ void BPH_hair_volume_grid_clear(HairGrid *grid)
{
const int size = hair_grid_size(grid->res);
int i;
- for (i = 0; i < size; ++i) {
+ for (i = 0; i < size; i++) {
zero_v3(grid->verts[i].velocity);
zero_v3(grid->verts[i].velocity_smooth);
grid->verts[i].density = 0.0f;
@@ -321,7 +321,7 @@ BLI_INLINE float weights_sum(const float weights[8])
{
float totweight = 0.0f;
int i;
- for (i = 0; i < 8; ++i) {
+ for (i = 0; i < 8; i++) {
totweight += weights[i];
}
return totweight;
@@ -377,9 +377,9 @@ void BPH_hair_volume_add_vertex(HairGrid *grid, const float x[3], const float v[
offset = hair_grid_weights(res, grid->gmin, grid->inv_cellsize, x, weights);
- for (di = 0; di < 2; ++di) {
- for (dj = 0; dj < 2; ++dj) {
- for (dk = 0; dk < 2; ++dk) {
+ for (di = 0; di < 2; di++) {
+ for (dj = 0; dj < 2; dj++) {
+ for (dk = 0; dk < 2; dk++) {
int voffset = offset + di + (dj + dk * res[1]) * res[0];
int iw = di + dj * 2 + dk * 4;
@@ -465,12 +465,12 @@ BLI_INLINE void hair_volume_add_segment_2D(HairGrid *grid,
HairGridVert *vert_j = vert + jmin * stride_j;
float loc_j[3] = {loc[0], loc[1], loc[2]};
loc_j[axis_j] += (float)jmin;
- for (j = jmin; j <= jmax; ++j, vert_j += stride_j, loc_j[axis_j] += 1.0f) {
+ for (j = jmin; j <= jmax; j++, vert_j += stride_j, loc_j[axis_j] += 1.0f) {
HairGridVert *vert_k = vert_j + kmin * stride_k;
float loc_k[3] = {loc_j[0], loc_j[1], loc_j[2]};
loc_k[axis_k] += (float)kmin;
- for (k = kmin; k <= kmax; ++k, vert_k += stride_k, loc_k[axis_k] += 1.0f) {
+ for (k = kmin; k <= kmax; k++, vert_k += stride_k, loc_k[axis_k] += 1.0f) {
hair_volume_eval_grid_vertex(vert_k, loc_k, radius, dist_scale, x2, v2, x3, v3);
@@ -553,7 +553,7 @@ void BPH_hair_volume_add_segment(HairGrid *grid,
int j0, k0, j0_prev, k0_prev;
int i;
- for (i = imin; i <= imax; ++i) {
+ for (i = imin; i <= imax; i++) {
float shift1, shift2; /* fraction of a full cell shift [0.0, 1.0) */
int jmin, jmax, kmin, kmax;
@@ -657,7 +657,7 @@ void BPH_hair_volume_add_segment(HairGrid *grid,
int s;
- for (s = 0; s < num_samples; ++s) {
+ for (s = 0; s < num_samples; s++) {
float x[3], v[3];
int i, j, k;
@@ -672,9 +672,9 @@ void BPH_hair_volume_add_segment(HairGrid *grid,
int kmin = max_ii(floor_int(x[2]) - 2, 0);
int kmax = min_ii(floor_int(x[2]) + 2, res[2] - 1);
- for (k = kmin; k <= kmax; ++k) {
- for (j = jmin; j <= jmax; ++j) {
- for (i = imin; i <= imax; ++i) {
+ for (k = kmin; k <= kmax; k++) {
+ for (j = jmin; j <= jmax; j++) {
+ for (i = imin; i <= imax; i++) {
float loc[3] = {(float)i, (float)j, (float)k};
HairGridVert *vert = grid->verts + i * stride[0] + j * stride[1] + k * stride[2];
@@ -761,9 +761,9 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid,
/* Calculate divergence */
lVector B(num_cellsA);
- for (k = 0; k < resA[2]; ++k) {
- for (j = 0; j < resA[1]; ++j) {
- for (i = 0; i < resA[0]; ++i) {
+ for (k = 0; k < resA[2]; k++) {
+ for (j = 0; j < resA[1]; j++) {
+ for (i = 0; i < resA[0]; i++) {
int u = i * strideA0 + j * strideA1 + k * strideA2;
bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 ||
MARGIN_k1;
@@ -855,9 +855,9 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid,
*/
A.reserve(Eigen::VectorXi::Constant(num_cellsA, 7));
- for (k = 0; k < resA[2]; ++k) {
- for (j = 0; j < resA[1]; ++j) {
- for (i = 0; i < resA[0]; ++i) {
+ for (k = 0; k < resA[2]; k++) {
+ for (j = 0; j < resA[1]; j++) {
+ for (i = 0; i < resA[0]; i++) {
int u = i * strideA0 + j * strideA1 + k * strideA2;
bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 ||
MARGIN_k1;
@@ -897,11 +897,11 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid,
/*int liquid_neighbors = neighbors_lo + neighbors_hi;*/
non_solid_neighbors = 6;
- for (n = 0; n < neighbors_lo; ++n) {
+ for (n = 0; n < neighbors_lo; n++) {
A.insert(neighbor_lo_index[n], u) = -1.0f;
}
A.insert(u, u) = (float)non_solid_neighbors;
- for (n = 0; n < neighbors_hi; ++n) {
+ for (n = 0; n < neighbors_hi; n++) {
A.insert(neighbor_hi_index[n], u) = -1.0f;
}
}
@@ -922,9 +922,9 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid,
if (cg.info() == Eigen::Success) {
/* Calculate velocity = grad(p) */
- for (k = 0; k < resA[2]; ++k) {
- for (j = 0; j < resA[1]; ++j) {
- for (i = 0; i < resA[0]; ++i) {
+ for (k = 0; k < resA[2]; k++) {
+ for (j = 0; j < resA[1]; j++) {
+ for (i = 0; i < resA[0]; i++) {
int u = i * strideA0 + j * strideA1 + k * strideA2;
bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 ||
MARGIN_k1;
@@ -965,9 +965,9 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid,
int slice = (offset - grid->gmin[axis]) / grid->cellsize;
- for (k = 0; k < resA[2]; ++k) {
- for (j = 0; j < resA[1]; ++j) {
- for (i = 0; i < resA[0]; ++i) {
+ for (k = 0; k < resA[2]; k++) {
+ for (j = 0; j < resA[1]; j++) {
+ for (i = 0; i < resA[0]; i++) {
int u = i * strideA0 + j * strideA1 + k * strideA2;
bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 ||
MARGIN_k1;
@@ -1034,7 +1034,7 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid,
}
else {
/* Clear result in case of error */
- for (i = 0, vert = grid->verts; i < num_cells; ++i, ++vert) {
+ for (i = 0, vert = grid->verts; i < num_cells; i++, vert++) {
zero_v3(vert->velocity_smooth);
}
@@ -1066,9 +1066,9 @@ BLI_INLINE void hair_volume_filter_box_convolute(
kernel_offset = minp + (minq + minr * res) * res;
kernel_dq = res;
kernel_dr = res * res;
- for (r = minr; r <= maxr; ++r) {
- for (q = minq; q <= maxq; ++q) {
- for (p = minp; p <= maxp; ++p) {
+ for (r = minr; r <= maxr; r++) {
+ for (q = minq; q <= maxq; q++) {
+ for (p = minp; p <= maxp; p++) {
madd_v3_v3fl(vel_smooth, verts[kernel_offset].velocity, invD);
@@ -1096,20 +1096,20 @@ void BPH_hair_volume_vertex_grid_filter_box(HairVertexGrid *grid, int kernel_siz
invD = 1.0f / (float)(tot * tot * tot);
/* clear values for convolution */
- for (i = 0; i < size; ++i) {
+ for (i = 0; i < size; i++) {
zero_v3(grid->verts[i].velocity_smooth);
}
- for (i = 0; i < grid->res; ++i) {
- for (j = 0; j < grid->res; ++j) {
- for (k = 0; k < grid->res; ++k) {
+ for (i = 0; i < grid->res; i++) {
+ for (j = 0; j < grid->res; j++) {
+ for (k = 0; k < grid->res; k++) {
hair_volume_filter_box_convolute(grid, invD, kernel_sizev, i, j, k);
}
}
}
/* apply as new velocity */
- for (i = 0; i < size; ++i) {
+ for (i = 0; i < size; i++) {
copy_v3_v3(grid->verts[i].velocity, grid->verts[i].velocity_smooth);
}
}
@@ -1134,7 +1134,7 @@ HairGrid *BPH_hair_volume_create_vertex_grid(float cellsize,
scale = 1.0f / cellsize;
sub_v3_v3v3(extent, gmax, gmin);
- for (i = 0; i < 3; ++i) {
+ for (i = 0; i < 3; i++) {
resmin[i] = floor_int(gmin[i] * scale);
resmax[i] = floor_int(gmax[i] * scale) + 1;
@@ -1221,7 +1221,7 @@ static HairGridVert *hair_volume_create_collision_grid(ClothModifierData *clmd,
collgrid = MEM_mallocN(sizeof(HairGridVert) * size, "hair collider voxel data");
/* initialize grid */
- for (i = 0; i < size; ++i) {
+ for (i = 0; i < size; i++) {
zero_v3(collgrid[i].velocity);
collgrid[i].density = 0.0f;
}
@@ -1247,9 +1247,9 @@ static HairGridVert *hair_volume_create_collision_grid(ClothModifierData *clmd,
sub_v3_v3v3(vel, loc1->co, loc0->co);
- for (di = 0; di < 2; ++di) {
- for (dj = 0; dj < 2; ++dj) {
- for (dk = 0; dk < 2; ++dk) {
+ for (di = 0; di < 2; di++) {
+ for (dj = 0; dj < 2; dj++) {
+ for (dk = 0; dk < 2; dk++) {
int voffset = offset + di + (dj + dk * res) * res;
int iw = di + dj * 2 + dk * 4;
diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c
index c2eb7b465e1..d8b3f647591 100644
--- a/source/blender/physics/intern/implicit_blender.c
+++ b/source/blender/physics/intern/implicit_blender.c
@@ -300,7 +300,7 @@ static void print_sparse_matrix(fmatrix3x3 *m)
static void print_lvector(lfVector *v, int numverts)
{
int i;
- for (i = 0; i < numverts; ++i) {
+ for (i = 0; i < numverts; i++) {
if (i > 0) {
printf("\n");
}
@@ -320,12 +320,12 @@ static void print_bfmatrix(fmatrix3x3 *m)
float *t = MEM_callocN(sizeof(float) * size * size, "bfmatrix");
int q, i, j;
- for (q = 0; q < tot; ++q) {
+ for (q = 0; q < tot; q++) {
int k = 3 * m[q].r;
int l = 3 * m[q].c;
- for (j = 0; j < 3; ++j) {
- for (i = 0; i < 3; ++i) {
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++) {
// if (t[k + i + (l + j) * size] != 0.0f) {
// printf("warning: overwriting value at %d, %d\n", m[q].r, m[q].c);
// }
@@ -340,12 +340,12 @@ static void print_bfmatrix(fmatrix3x3 *m)
}
}
- for (j = 0; j < size; ++j) {
+ for (j = 0; j < size; j++) {
if (j > 0 && j % 3 == 0) {
printf("\n");
}
- for (i = 0; i < size; ++i) {
+ for (i = 0; i < size; i++) {
if (i > 0 && i % 3 == 0) {
printf(" ");
}
@@ -560,7 +560,7 @@ DO_INLINE fmatrix3x3 *create_bfmatrix(unsigned int verts, unsigned int springs)
temp[0].scount = springs;
/* vertex part of the matrix is diagonal blocks */
- for (i = 0; i < verts; ++i) {
+ for (i = 0; i < verts; i++) {
init_fmatrix(temp + i, i, i);
}
@@ -1289,7 +1289,7 @@ static int BPH_mass_spring_add_block(Implicit_Data *data, int v1, int v2)
void BPH_mass_spring_clear_constraints(Implicit_Data *data)
{
int i, numverts = data->S[0].vcount;
- for (i = 0; i < numverts; ++i) {
+ for (i = 0; i < numverts; i++) {
unit_m3(data->S[i].m);
zero_v3(data->z[i]);
}
@@ -2001,7 +2001,7 @@ BLI_INLINE void spring_hairbend_estimate_dfdx(Implicit_Data *data,
/* XXX TODO offset targets to account for position dependency */
- for (a = 0; a < 3; ++a) {
+ for (a = 0; a < 3; a++) {
spring_hairbend_forces(
data, i, j, k, goal, stiffness, damping, q, dvec_pos[a], dvec_null[a], f);
copy_v3_v3(dfdx[a], f);
@@ -2010,7 +2010,7 @@ BLI_INLINE void spring_hairbend_estimate_dfdx(Implicit_Data *data,
data, i, j, k, goal, stiffness, damping, q, dvec_neg[a], dvec_null[a], f);
sub_v3_v3(dfdx[a], f);
- for (b = 0; b < 3; ++b) {
+ for (b = 0; b < 3; b++) {
dfdx[a][b] /= delta;
}
}
@@ -2040,7 +2040,7 @@ BLI_INLINE void spring_hairbend_estimate_dfdv(Implicit_Data *data,
/* XXX TODO offset targets to account for position dependency */
- for (a = 0; a < 3; ++a) {
+ for (a = 0; a < 3; a++) {
spring_hairbend_forces(
data, i, j, k, goal, stiffness, damping, q, dvec_null[a], dvec_pos[a], f);
copy_v3_v3(dfdv[a], f);
@@ -2049,7 +2049,7 @@ BLI_INLINE void spring_hairbend_estimate_dfdv(Implicit_Data *data,
data, i, j, k, goal, stiffness, damping, q, dvec_null[a], dvec_neg[a], f);
sub_v3_v3(dfdv[a], f);
- for (b = 0; b < 3; ++b) {
+ for (b = 0; b < 3; b++) {
dfdv[a][b] /= delta;
}
}
diff --git a/source/blender/physics/intern/implicit_eigen.cpp b/source/blender/physics/intern/implicit_eigen.cpp
index 277b62fba7c..9e1c03638d7 100644
--- a/source/blender/physics/intern/implicit_eigen.cpp
+++ b/source/blender/physics/intern/implicit_eigen.cpp
@@ -98,14 +98,14 @@ class fVector : public Eigen::Vector3f {
fVector(const ctype &v)
{
- for (int k = 0; k < 3; ++k) {
+ for (int k = 0; k < 3; k++) {
coeffRef(k) = v[k];
}
}
fVector &operator=(const ctype &v)
{
- for (int k = 0; k < 3; ++k) {
+ for (int k = 0; k < 3; k++) {
coeffRef(k) = v[k];
}
return *this;
@@ -130,8 +130,8 @@ class fMatrix : public Eigen::Matrix3f {
fMatrix(const ctype &v)
{
- for (int k = 0; k < 3; ++k) {
- for (int l = 0; l < 3; ++l) {
+ for (int k = 0; k < 3; k++) {
+ for (int l = 0; l < 3; l++) {
coeffRef(l, k) = v[k][l];
}
}
@@ -139,8 +139,8 @@ class fMatrix : public Eigen::Matrix3f {
fMatrix &operator=(const ctype &v)
{
- for (int k = 0; k < 3; ++k) {
- for (int l = 0; l < 3; ++l) {
+ for (int k = 0; k < 3; k++) {
+ for (int l = 0; l < 3; l++) {
coeffRef(l, k) = v[k][l];
}
}
@@ -212,8 +212,8 @@ struct lMatrixCtor {
{
i *= 3;
j *= 3;
- for (int k = 0; k < 3; ++k) {
- for (int l = 0; l < 3; ++l) {
+ for (int k = 0; k < 3; k++) {
+ for (int l = 0; l < 3; l++) {
m_trips.push_back(Triplet(i + k, j + l, m.coeff(l, k)));
}
}
@@ -223,8 +223,8 @@ struct lMatrixCtor {
{
i *= 3;
j *= 3;
- for (int k = 0; k < 3; ++k) {
- for (int l = 0; l < 3; ++l) {
+ for (int k = 0; k < 3; k++) {
+ for (int l = 0; l < 3; l++) {
m_trips.push_back(Triplet(i + k, j + l, -m.coeff(l, k)));
}
}
@@ -255,7 +255,7 @@ using Eigen::ComputationInfo;
static void print_lvector(const lVector &v)
{
- for (int i = 0; i < v.rows(); ++i) {
+ for (int i = 0; i < v.rows(); i++) {
if (i > 0 && i % 3 == 0) {
printf("\n");
}
@@ -266,12 +266,12 @@ static void print_lvector(const lVector &v)
static void print_lmatrix(const lMatrix &m)
{
- for (int j = 0; j < m.rows(); ++j) {
+ for (int j = 0; j < m.rows(); j++) {
if (j > 0 && j % 3 == 0) {
printf("\n");
}
- for (int i = 0; i < m.cols(); ++i) {
+ for (int i = 0; i < m.cols(); i++) {
if (i > 0 && i % 3 == 0) {
printf(" ");
}
@@ -302,8 +302,8 @@ BLI_INLINE void triplets_m3(TripletList &tlist, float m[3][3], int i, int j)
{
i *= 3;
j *= 3;
- for (int l = 0; l < 3; ++l) {
- for (int k = 0; k < 3; ++k) {
+ for (int l = 0; l < 3; l++) {
+ for (int k = 0; k < 3; k++) {
tlist.push_back(Triplet(i + k, j + l, m[k][l]));
}
}
@@ -313,8 +313,8 @@ BLI_INLINE void triplets_m3fl(TripletList &tlist, float m[3][3], int i, int j, f
{
i *= 3;
j *= 3;
- for (int l = 0; l < 3; ++l) {
- for (int k = 0; k < 3; ++k) {
+ for (int l = 0; l < 3; l++) {
+ for (int k = 0; k < 3; k++) {
tlist.push_back(Triplet(i + k, j + l, m[k][l] * factor));
}
}
@@ -667,7 +667,7 @@ void BPH_mass_spring_set_new_velocity(Implicit_Data *data, int index, const floa
void BPH_mass_spring_clear_constraints(Implicit_Data *data)
{
int numverts = data->numverts;
- for (int i = 0; i < numverts; ++i) {
+ for (int i = 0; i < numverts; i++) {
data->iS.add(i, i, I);
zero_v3(data->z.v3(i));
}
@@ -1236,7 +1236,7 @@ BLI_INLINE void spring_angbend_estimate_dfdx(Implicit_Data *data,
/* XXX TODO offset targets to account for position dependency */
- for (a = 0; a < 3; ++a) {
+ for (a = 0; a < 3; a++) {
spring_angbend_forces(
data, i, j, k, goal, stiffness, damping, q, dvec_pos[a], dvec_null[a], f);
copy_v3_v3(dfdx[a], f);
@@ -1245,7 +1245,7 @@ BLI_INLINE void spring_angbend_estimate_dfdx(Implicit_Data *data,
data, i, j, k, goal, stiffness, damping, q, dvec_neg[a], dvec_null[a], f);
sub_v3_v3(dfdx[a], f);
- for (b = 0; b < 3; ++b) {
+ for (b = 0; b < 3; b++) {
dfdx[a][b] /= delta;
}
}
@@ -1275,7 +1275,7 @@ BLI_INLINE void spring_angbend_estimate_dfdv(Implicit_Data *data,
/* XXX TODO offset targets to account for position dependency */
- for (a = 0; a < 3; ++a) {
+ for (a = 0; a < 3; a++) {
spring_angbend_forces(
data, i, j, k, goal, stiffness, damping, q, dvec_null[a], dvec_pos[a], f);
copy_v3_v3(dfdv[a], f);
@@ -1284,7 +1284,7 @@ BLI_INLINE void spring_angbend_estimate_dfdv(Implicit_Data *data,
data, i, j, k, goal, stiffness, damping, q, dvec_null[a], dvec_neg[a], f);
sub_v3_v3(dfdv[a], f);
- for (b = 0; b < 3; ++b) {
+ for (b = 0; b < 3; b++) {
dfdv[a][b] /= delta;
}
}
diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c
index 23be0d68fb0..1b6466dee68 100644
--- a/source/blender/python/generic/bgl.c
+++ b/source/blender/python/generic/bgl.c
@@ -1366,6 +1366,7 @@ BGL_Wrap(GenVertexArrays, void, (GLsizei, GLuintP));
BGL_Wrap(GetStringi, GLstring, (GLenum, GLuint));
BGL_Wrap(IsVertexArray, GLboolean, (GLuint));
BGL_Wrap(RenderbufferStorage, void, (GLenum, GLenum, GLsizei, GLsizei));
+BGL_Wrap(VertexAttribIPointer, void, (GLuint, GLint, GLenum, GLsizei, GLvoidP));
/* GL_VERSION_3_1 */
BGL_Wrap(BindBufferBase, void, (GLenum, GLuint, GLuint));
@@ -1709,6 +1710,7 @@ PyObject *BPyInit_bgl(void)
PY_MOD_ADD_METHOD(GetStringi);
PY_MOD_ADD_METHOD(IsVertexArray);
PY_MOD_ADD_METHOD(RenderbufferStorage);
+ PY_MOD_ADD_METHOD(VertexAttribIPointer);
}
/* GL_VERSION_3_1 */
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index d10d281c1f9..335dea0a2b6 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -688,6 +688,7 @@ bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group,
/* Preserve prev/next links!!! See T42593. */
prop->prev = prop_exist->prev;
prop->next = prop_exist->next;
+ prop->flag = prop_exist->flag;
IDP_FreePropertyContent(prop_exist);
*prop_exist = *prop;
@@ -896,7 +897,7 @@ static PyObject *BPy_IDGroup_pop(BPy_IDProperty *self, PyObject *args)
pyform = BPy_IDGroup_MapDataToPy(idprop);
if (pyform == NULL) {
- /* ok something bad happened with the pyobject,
+ /* ok something bad happened with the #PyObject,
* so don't remove the prop from the group. if pyform is
* NULL, then it already should have raised an exception.*/
return NULL;
diff --git a/source/blender/python/generic/imbuf_py_api.c b/source/blender/python/generic/imbuf_py_api.c
index 22be0429ea5..6a7f899488b 100644
--- a/source/blender/python/generic/imbuf_py_api.c
+++ b/source/blender/python/generic/imbuf_py_api.c
@@ -88,21 +88,37 @@ PyDoc_STRVAR(py_imbuf_resize_doc,
"\n"
" :arg size: New size.\n"
" :type size: pair of ints\n"
- " :arg method: Method of resizing (TODO)\n"
+ " :arg method: Method of resizing ('FAST', 'BILINEAR')\n"
" :type method: str\n");
static PyObject *py_imbuf_resize(Py_ImBuf *self, PyObject *args, PyObject *kw)
{
PY_IMBUF_CHECK_OBJ(self);
uint size[2];
- char *method = NULL;
+
+ enum { FAST, BILINEAR };
+ const struct PyC_StringEnumItems method_items[] = {
+ {FAST, "FAST"},
+ {BILINEAR, "BILINEAR"},
+ {0, NULL},
+ };
+ struct PyC_StringEnum method = {method_items, FAST};
static const char *_keywords[] = {"size", "method", NULL};
- static _PyArg_Parser _parser = {"(II)|s:resize", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &size[0], &size[1], &method)) {
+ static _PyArg_Parser _parser = {"(II)|O&:resize", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser, &size[0], &size[1], PyC_ParseStringEnum, &method)) {
return NULL;
}
- IMB_scaleImBuf(self->ibuf, UNPACK2(size));
+ if (method.value_found == FAST) {
+ IMB_scalefastImBuf(self->ibuf, UNPACK2(size));
+ }
+ else if (method.value_found == BILINEAR) {
+ IMB_scaleImBuf(self->ibuf, UNPACK2(size));
+ }
+ else {
+ BLI_assert(0);
+ }
Py_RETURN_NONE;
}
@@ -227,6 +243,51 @@ static int py_imbuf_ppm_set(Py_ImBuf *self, PyObject *value, void *UNUSED(closur
return 0;
}
+PyDoc_STRVAR(py_imbuf_filepath_doc, "filepath associated with this image.\n\n:type: string");
+static PyObject *py_imbuf_filepath_get(Py_ImBuf *self, void *UNUSED(closure))
+{
+ PY_IMBUF_CHECK_OBJ(self);
+ ImBuf *ibuf = self->ibuf;
+ return PyC_UnicodeFromByte(ibuf->name);
+}
+
+static int py_imbuf_filepath_set(Py_ImBuf *self, PyObject *value, void *UNUSED(closure))
+{
+ PY_IMBUF_CHECK_INT(self);
+
+ if (!PyUnicode_Check(value)) {
+ PyErr_SetString(PyExc_TypeError, "expected a string!");
+ return -1;
+ }
+
+ ImBuf *ibuf = self->ibuf;
+ Py_ssize_t value_str_len_max = sizeof(ibuf->name);
+ Py_ssize_t value_str_len;
+ const char *value_str = _PyUnicode_AsStringAndSize(value, &value_str_len);
+ if (value_str_len >= value_str_len_max) {
+ PyErr_Format(PyExc_TypeError, "filepath length over %zd", value_str_len_max - 1);
+ return -1;
+ }
+ memcpy(ibuf->name, value_str, value_str_len + 1);
+ return 0;
+}
+
+PyDoc_STRVAR(py_imbuf_planes_doc, "Number of bits associated with this image.\n\n:type: int");
+static PyObject *py_imbuf_planes_get(Py_ImBuf *self, void *UNUSED(closure))
+{
+ PY_IMBUF_CHECK_OBJ(self);
+ ImBuf *imbuf = self->ibuf;
+ return PyLong_FromLong(imbuf->planes);
+}
+
+PyDoc_STRVAR(py_imbuf_channels_doc, "Number of bit-planes.\n\n:type: int");
+static PyObject *py_imbuf_channels_get(Py_ImBuf *self, void *UNUSED(closure))
+{
+ PY_IMBUF_CHECK_OBJ(self);
+ ImBuf *imbuf = self->ibuf;
+ return PyLong_FromLong(imbuf->channels);
+}
+
static PyGetSetDef Py_ImBuf_getseters[] = {
{(char *)"size", (getter)py_imbuf_size_get, (setter)NULL, (char *)py_imbuf_size_doc, NULL},
{(char *)"ppm",
@@ -234,6 +295,13 @@ static PyGetSetDef Py_ImBuf_getseters[] = {
(setter)py_imbuf_ppm_set,
(char *)py_imbuf_ppm_doc,
NULL},
+ {(char *)"filepath",
+ (getter)py_imbuf_filepath_get,
+ (setter)py_imbuf_filepath_set,
+ (char *)py_imbuf_filepath_doc,
+ NULL},
+ {(char *)"planes", (getter)py_imbuf_planes_get, NULL, (char *)py_imbuf_planes_doc, NULL},
+ {(char *)"channels", (getter)py_imbuf_channels_get, NULL, (char *)py_imbuf_channels_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
@@ -258,7 +326,7 @@ static PyObject *py_imbuf_repr(Py_ImBuf *self)
const ImBuf *ibuf = self->ibuf;
if (ibuf != NULL) {
return PyUnicode_FromFormat(
- "<imbuf: address=%p, filename='%s', size=(%d, %d)>", ibuf, ibuf->name, ibuf->x, ibuf->y);
+ "<imbuf: address=%p, filepath='%s', size=(%d, %d)>", ibuf, ibuf->name, ibuf->x, ibuf->y);
}
else {
return PyUnicode_FromString("<imbuf: address=0x0>");
@@ -375,73 +443,73 @@ static PyObject *M_imbuf_new(PyObject *UNUSED(self), PyObject *args, PyObject *k
}
PyDoc_STRVAR(M_imbuf_load_doc,
- ".. function:: load(filename)\n"
+ ".. function:: load(filepath)\n"
"\n"
" Load an image from a file.\n"
"\n"
- " :arg filename: the filename of the image.\n"
- " :type filename: string\n"
+ " :arg filepath: the filepath of the image.\n"
+ " :type filepath: string\n"
" :return: the newly loaded image.\n"
" :rtype: :class:`ImBuf`\n");
static PyObject *M_imbuf_load(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- const char *filename;
+ const char *filepath;
- static const char *_keywords[] = {"filename", NULL};
+ static const char *_keywords[] = {"filepath", NULL};
static _PyArg_Parser _parser = {"s:load", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &filename)) {
+ if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &filepath)) {
return NULL;
}
- const int file = BLI_open(filename, O_BINARY | O_RDONLY, 0);
+ const int file = BLI_open(filepath, O_BINARY | O_RDONLY, 0);
if (file == -1) {
- PyErr_Format(PyExc_IOError, "load: %s, failed to open file '%s'", strerror(errno));
+ PyErr_Format(PyExc_IOError, "load: %s, failed to open file '%s'", strerror(errno), filepath);
return NULL;
}
- ImBuf *ibuf = IMB_loadifffile(file, filename, IB_rect, NULL, filename);
+ ImBuf *ibuf = IMB_loadifffile(file, filepath, IB_rect, NULL, filepath);
close(file);
if (ibuf == NULL) {
PyErr_Format(
- PyExc_ValueError, "load: Unable to recognize image format for file '%s'", filename);
+ PyExc_ValueError, "load: Unable to recognize image format for file '%s'", filepath);
return NULL;
}
- BLI_strncpy(ibuf->name, filename, sizeof(ibuf->name));
+ BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
return Py_ImBuf_CreatePyObject(ibuf);
}
PyDoc_STRVAR(M_imbuf_write_doc,
- ".. function:: write(image, filename)\n"
+ ".. function:: write(image, filepath)\n"
"\n"
" Write an image.\n"
"\n"
" :arg image: the image to write.\n"
" :type image: :class:`ImBuf`\n"
- " :arg filename: the filename of the image.\n"
- " :type filename: string\n");
+ " :arg filepath: the filepath of the image.\n"
+ " :type filepath: string\n");
static PyObject *M_imbuf_write(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
Py_ImBuf *py_imb;
- const char *filename = NULL;
+ const char *filepath = NULL;
- static const char *_keywords[] = {"image", "filename", NULL};
+ static const char *_keywords[] = {"image", "filepath", NULL};
static _PyArg_Parser _parser = {"O!|s:write", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &Py_ImBuf_Type, &py_imb, &filename)) {
+ if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &Py_ImBuf_Type, &py_imb, &filepath)) {
return NULL;
}
- if (filename == NULL) {
- filename = py_imb->ibuf->name;
+ if (filepath == NULL) {
+ filepath = py_imb->ibuf->name;
}
- bool ok = IMB_saveiff(py_imb->ibuf, filename, IB_rect);
+ bool ok = IMB_saveiff(py_imb->ibuf, filepath, IB_rect);
if (ok == false) {
PyErr_Format(
- PyExc_IOError, "write: Unable to write image file (%s) '%s'", strerror(errno), filename);
+ PyExc_IOError, "write: Unable to write image file (%s) '%s'", strerror(errno), filepath);
return NULL;
}
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index ca9f15ed01a..a6983c38f0e 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -231,6 +231,37 @@ int PyC_ParseBool(PyObject *o, void *p)
return 1;
}
+/**
+ * Use with PyArg_ParseTuple's "O&" formatting.
+ */
+int PyC_ParseStringEnum(PyObject *o, void *p)
+{
+ struct PyC_StringEnum *e = p;
+ const char *value = _PyUnicode_AsString(o);
+ if (value == NULL) {
+ PyErr_Format(PyExc_ValueError, "expected a string, got %s", Py_TYPE(o)->tp_name);
+ return 0;
+ }
+ int i;
+ for (i = 0; e->items[i].id; i++) {
+ if (STREQ(e->items[i].id, value)) {
+ e->value_found = e->items[i].value;
+ return 1;
+ }
+ }
+
+ /* Set as a precaution. */
+ e->value_found = -1;
+
+ PyObject *enum_items = PyTuple_New(i);
+ for (i = 0; e->items[i].id; i++) {
+ PyTuple_SET_ITEM(enum_items, i, PyUnicode_FromString(e->items[i].id));
+ }
+ PyErr_Format(PyExc_ValueError, "expected a string in %S, got '%s'", enum_items, value);
+ Py_DECREF(enum_items);
+ return 0;
+}
+
/* silly function, we dont use arg. just check its compatible with __deepcopy__ */
int PyC_CheckArgs_DeepCopy(PyObject *args)
{
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index 4454aa11d77..1f552c3d78d 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -126,6 +126,17 @@ bool PyC_RunString_AsString(const char **imports,
int PyC_ParseBool(PyObject *o, void *p);
+struct PyC_StringEnumItems {
+ int value;
+ const char *id;
+};
+struct PyC_StringEnum {
+ const struct PyC_StringEnumItems *items;
+ int value_found;
+};
+
+int PyC_ParseStringEnum(PyObject *o, void *p);
+
int PyC_CheckArgs_DeepCopy(PyObject *args);
/* Integer parsing (with overflow checks), -1 on error. */
diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c
index b5f4d26220a..70f76896898 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.c
+++ b/source/blender/python/gpu/gpu_py_offscreen.c
@@ -32,6 +32,7 @@
#include "BLI_utildefines.h"
+#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_scene.h"
@@ -238,7 +239,7 @@ static PyObject *bpygpu_offscreen_draw_view3d(BPyGPUOffScreen *self,
BLI_assert(BKE_id_is_in_global_main(&scene->id));
- depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ depsgraph = BKE_scene_get_depsgraph(G_MAIN, scene, view_layer, true);
rv3d_mats = ED_view3d_mats_rv3d_backup(ar->regiondata);
diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c
index cccf75513f9..87091e311f3 100644
--- a/source/blender/python/gpu/gpu_py_shader.c
+++ b/source/blender/python/gpu/gpu_py_shader.c
@@ -26,7 +26,6 @@
#include "BLI_utildefines.h"
#include "GPU_shader.h"
-#include "GPU_shader_interface.h"
#include "../generic/py_capi_utils.h"
#include "../generic/python_utildefines.h"
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index fc945562c98..a5f71e92438 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -231,6 +231,10 @@ if(WITH_OPENAL)
add_definitions(-DWITH_OPENAL)
endif()
+if(WITH_OPENSUBDIV)
+ add_definitions(-DWITH_OPENSUBDIV)
+endif()
+
if(WITH_SDL)
list(APPEND INC_SYS
${SDL_INCLUDE_DIR}
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 8c34699b598..52b35478dd0 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -147,39 +147,28 @@ static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObjec
// PyDoc_STRVAR(bpy_user_resource_doc[] = // now in bpy/utils.py
static PyObject *bpy_user_resource(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- const char *type;
+ const struct PyC_StringEnumItems type_items[] = {
+ {BLENDER_USER_DATAFILES, "DATAFILES"},
+ {BLENDER_USER_CONFIG, "CONFIG"},
+ {BLENDER_USER_SCRIPTS, "SCRIPTS"},
+ {BLENDER_USER_AUTOSAVE, "AUTOSAVE"},
+ {0, NULL},
+ };
+ struct PyC_StringEnum type = {type_items};
+
const char *subdir = NULL;
- int folder_id;
const char *path;
static const char *_keywords[] = {"type", "subdir", NULL};
- static _PyArg_Parser _parser = {"s|s:user_resource", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &type, &subdir)) {
- return NULL;
- }
-
- /* stupid string compare */
- if (STREQ(type, "DATAFILES")) {
- folder_id = BLENDER_USER_DATAFILES;
- }
- else if (STREQ(type, "CONFIG")) {
- folder_id = BLENDER_USER_CONFIG;
- }
- else if (STREQ(type, "SCRIPTS")) {
- folder_id = BLENDER_USER_SCRIPTS;
- }
- else if (STREQ(type, "AUTOSAVE")) {
- folder_id = BLENDER_USER_AUTOSAVE;
- }
- else {
- PyErr_SetString(PyExc_ValueError, "invalid resource argument");
+ static _PyArg_Parser _parser = {"O&|s:user_resource", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, PyC_ParseStringEnum, &type, &subdir)) {
return NULL;
}
/* same logic as BKE_appdir_folder_id_create(),
* but best leave it up to the script author to create */
- path = BKE_appdir_folder_id_user_notest(folder_id, subdir);
+ path = BKE_appdir_folder_id_user_notest(type.value_found, subdir);
return PyC_UnicodeFromByte(path ? path : "");
}
@@ -195,34 +184,25 @@ PyDoc_STRVAR(bpy_system_resource_doc,
" :type path: string\n");
static PyObject *bpy_system_resource(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- const char *type;
+ const struct PyC_StringEnumItems type_items[] = {
+ {BLENDER_SYSTEM_DATAFILES, "DATAFILES"},
+ {BLENDER_SYSTEM_SCRIPTS, "SCRIPTS"},
+ {BLENDER_SYSTEM_PYTHON, "PYTHON"},
+ {0, NULL},
+ };
+ struct PyC_StringEnum type = {type_items};
+
const char *subdir = NULL;
- int folder_id;
const char *path;
static const char *_keywords[] = {"type", "path", NULL};
- static _PyArg_Parser _parser = {"s|s:system_resource", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &type, &subdir)) {
+ static _PyArg_Parser _parser = {"O&|s:system_resource", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, PyC_ParseStringEnum, &type, &subdir)) {
return NULL;
}
- /* stupid string compare */
- if (STREQ(type, "DATAFILES")) {
- folder_id = BLENDER_SYSTEM_DATAFILES;
- }
- else if (STREQ(type, "SCRIPTS")) {
- folder_id = BLENDER_SYSTEM_SCRIPTS;
- }
- else if (STREQ(type, "PYTHON")) {
- folder_id = BLENDER_SYSTEM_PYTHON;
- }
- else {
- PyErr_SetString(PyExc_ValueError, "invalid resource argument");
- return NULL;
- }
-
- path = BKE_appdir_folder_id(folder_id, subdir);
+ path = BKE_appdir_folder_id(type.value_found, subdir);
return PyC_UnicodeFromByte(path ? path : "");
}
@@ -243,33 +223,25 @@ PyDoc_STRVAR(
" :rtype: string\n");
static PyObject *bpy_resource_path(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- const char *type;
+ const struct PyC_StringEnumItems type_items[] = {
+ {BLENDER_RESOURCE_PATH_USER, "USER"},
+ {BLENDER_RESOURCE_PATH_LOCAL, "LOCAL"},
+ {BLENDER_RESOURCE_PATH_SYSTEM, "SYSTEM"},
+ {0, NULL},
+ };
+ struct PyC_StringEnum type = {type_items};
+
int major = BLENDER_VERSION / 100, minor = BLENDER_VERSION % 100;
- int folder_id;
const char *path;
static const char *_keywords[] = {"type", "major", "minor", NULL};
- static _PyArg_Parser _parser = {"s|ii:resource_path", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &type, &major, &minor)) {
- return NULL;
- }
-
- /* stupid string compare */
- if (STREQ(type, "USER")) {
- folder_id = BLENDER_RESOURCE_PATH_USER;
- }
- else if (STREQ(type, "LOCAL")) {
- folder_id = BLENDER_RESOURCE_PATH_LOCAL;
- }
- else if (STREQ(type, "SYSTEM")) {
- folder_id = BLENDER_RESOURCE_PATH_SYSTEM;
- }
- else {
- PyErr_SetString(PyExc_ValueError, "invalid resource argument");
+ static _PyArg_Parser _parser = {"O&|ii:resource_path", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser, PyC_ParseStringEnum, &type, &major, &minor)) {
return NULL;
}
- path = BKE_appdir_folder_id_version(folder_id, (major * 100) + minor, false);
+ path = BKE_appdir_folder_id_version(type.value_found, (major * 100) + minor, false);
return PyC_UnicodeFromByte(path ? path : "");
}
diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c
index a841e974e85..afb2f6b3636 100644
--- a/source/blender/python/intern/bpy_app_build_options.c
+++ b/source/blender/python/intern/bpy_app_build_options.c
@@ -46,6 +46,7 @@ static PyStructSequence_Field app_builtopts_info_fields[] = {
{(char *)"audaspace", NULL},
{(char *)"international", NULL},
{(char *)"openal", NULL},
+ {(char *)"opensubdiv", NULL},
{(char *)"sdl", NULL},
{(char *)"sdl_dynload", NULL},
{(char *)"jack", NULL},
@@ -190,6 +191,12 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
+#ifdef WITH_OPENSUBDIV
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
#ifdef WITH_SDL
SetObjIncref(Py_True);
#else
diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c
index dde3d026d47..2fbefe3be74 100644
--- a/source/blender/python/intern/bpy_app_handlers.c
+++ b/source/blender/python/intern/bpy_app_handlers.c
@@ -24,7 +24,8 @@
#include <Python.h>
#include "BLI_utildefines.h"
-#include "BLI_callbacks.h"
+
+#include "BKE_callbacks.h"
#include "RNA_types.h"
#include "RNA_access.h"
@@ -35,7 +36,10 @@
#include "BPY_extern.h"
-void bpy_app_generic_callback(struct Main *main, struct ID *id, void *arg);
+void bpy_app_generic_callback(struct Main *main,
+ struct PointerRNA **pointers,
+ const int num_pointers,
+ void *arg);
static PyTypeObject BlenderAppCbType;
@@ -80,7 +84,7 @@ static PyStructSequence_Desc app_cb_info_desc = {
};
#if 0
-# if (BLI_CB_EVT_TOT != ARRAY_SIZE(app_cb_info_fields))
+# if (BKE_CB_EVT_TOT != ARRAY_SIZE(app_cb_info_fields))
# error "Callbacks are out of sync"
# endif
#endif
@@ -175,7 +179,7 @@ static PyTypeObject BPyPersistent_Type = {
0, /* tp_free */
};
-static PyObject *py_cb_array[BLI_CB_EVT_TOT] = {NULL};
+static PyObject *py_cb_array[BKE_CB_EVT_TOT] = {NULL};
static PyObject *make_app_cb_info(void)
{
@@ -187,7 +191,7 @@ static PyObject *make_app_cb_info(void)
return NULL;
}
- for (pos = 0; pos < BLI_CB_EVT_TOT; pos++) {
+ for (pos = 0; pos < BKE_CB_EVT_TOT; pos++) {
if (app_cb_info_fields[pos].name == NULL) {
Py_FatalError("invalid callback slots 1");
}
@@ -227,16 +231,16 @@ PyObject *BPY_app_handlers_struct(void)
/* assign the C callbacks */
if (ret) {
- static bCallbackFuncStore funcstore_array[BLI_CB_EVT_TOT] = {{NULL}};
+ static bCallbackFuncStore funcstore_array[BKE_CB_EVT_TOT] = {{NULL}};
bCallbackFuncStore *funcstore;
int pos = 0;
- for (pos = 0; pos < BLI_CB_EVT_TOT; pos++) {
+ for (pos = 0; pos < BKE_CB_EVT_TOT; pos++) {
funcstore = &funcstore_array[pos];
funcstore->func = bpy_app_generic_callback;
funcstore->alloc = 0;
funcstore->arg = POINTER_FROM_INT(pos);
- BLI_callback_add(funcstore, pos);
+ BKE_callback_add(funcstore, pos);
}
}
@@ -251,7 +255,7 @@ void BPY_app_handlers_reset(const short do_all)
gilstate = PyGILState_Ensure();
if (do_all) {
- for (pos = 0; pos < BLI_CB_EVT_TOT; pos++) {
+ for (pos = 0; pos < BKE_CB_EVT_TOT; pos++) {
/* clear list */
PyList_SetSlice(py_cb_array[pos], 0, PY_SSIZE_T_MAX, NULL);
}
@@ -260,7 +264,7 @@ void BPY_app_handlers_reset(const short do_all)
/* save string conversion thrashing */
PyObject *perm_id_str = PyUnicode_FromString(PERMINENT_CB_ID);
- for (pos = 0; pos < BLI_CB_EVT_TOT; pos++) {
+ for (pos = 0; pos < BKE_CB_EVT_TOT; pos++) {
/* clear only items without PERMINENT_CB_ID */
PyObject *ls = py_cb_array[pos];
Py_ssize_t i;
@@ -289,32 +293,55 @@ void BPY_app_handlers_reset(const short do_all)
PyGILState_Release(gilstate);
}
+static PyObject *choose_arguments(PyObject *func, PyObject *args_all, PyObject *args_single)
+{
+ if (!PyFunction_Check(func)) {
+ return args_all;
+ }
+ PyCodeObject *code = (PyCodeObject *)PyFunction_GetCode(func);
+ if (code->co_argcount == 1) {
+ return args_single;
+ }
+ return args_all;
+}
+
/* the actual callback - not necessarily called from py */
-void bpy_app_generic_callback(struct Main *UNUSED(main), struct ID *id, void *arg)
+void bpy_app_generic_callback(struct Main *UNUSED(main),
+ struct PointerRNA **pointers,
+ const int num_pointers,
+ void *arg)
{
PyObject *cb_list = py_cb_array[POINTER_AS_INT(arg)];
if (PyList_GET_SIZE(cb_list) > 0) {
PyGILState_STATE gilstate = PyGILState_Ensure();
- PyObject *args = PyTuple_New(1); /* save python creating each call */
+ const int num_arguments = 2;
+ PyObject *args_all = PyTuple_New(num_arguments); /* save python creating each call */
+ PyObject *args_single = PyTuple_New(1);
PyObject *func;
PyObject *ret;
Py_ssize_t pos;
/* setup arguments */
- if (id) {
- PointerRNA id_ptr;
- RNA_id_pointer_create(id, &id_ptr);
- PyTuple_SET_ITEM(args, 0, pyrna_struct_CreatePyObject(&id_ptr));
+ for (int i = 0; i < num_pointers; ++i) {
+ PyTuple_SET_ITEM(args_all, i, pyrna_struct_CreatePyObject(pointers[i]));
+ }
+ for (int i = num_pointers; i < num_arguments; ++i) {
+ PyTuple_SET_ITEM(args_all, i, Py_INCREF_RET(Py_None));
+ }
+
+ if (num_pointers == 0) {
+ PyTuple_SET_ITEM(args_single, 0, Py_INCREF_RET(Py_None));
}
else {
- PyTuple_SET_ITEM(args, 0, Py_INCREF_RET(Py_None));
+ PyTuple_SET_ITEM(args_single, 0, pyrna_struct_CreatePyObject(pointers[0]));
}
/* Iterate the list and run the callbacks
* note: don't store the list size since the scripts may remove themselves */
for (pos = 0; pos < PyList_GET_SIZE(cb_list); pos++) {
func = PyList_GET_ITEM(cb_list, pos);
+ PyObject *args = choose_arguments(func, args_all, args_single);
ret = PyObject_Call(func, args, NULL);
if (ret == NULL) {
/* Don't set last system variables because they might cause some
@@ -331,7 +358,8 @@ void bpy_app_generic_callback(struct Main *UNUSED(main), struct ID *id, void *ar
}
}
- Py_DECREF(args);
+ Py_DECREF(args_all);
+ Py_DECREF(args_single);
PyGILState_Release(gilstate);
}
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 9e734123caa..6b63d1ef2c3 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -480,7 +480,7 @@ static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr,
if (ret == NULL) {
PyC_Err_PrintWithFunc(py_func);
- for (i = 0; i < len; ++i) {
+ for (i = 0; i < len; i++) {
values[i] = false;
}
}
@@ -488,7 +488,7 @@ static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr,
if (PyC_AsArray(values, ret, len, &PyBool_Type, false, "BoolVectorProperty get") == -1) {
PyC_Err_PrintWithFunc(py_func);
- for (i = 0; i < len; ++i) {
+ for (i = 0; i < len; i++) {
values[i] = false;
}
@@ -724,7 +724,7 @@ static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr,
if (ret == NULL) {
PyC_Err_PrintWithFunc(py_func);
- for (i = 0; i < len; ++i) {
+ for (i = 0; i < len; i++) {
values[i] = 0;
}
}
@@ -732,7 +732,7 @@ static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr,
if (PyC_AsArray(values, ret, len, &PyLong_Type, false, "IntVectorProperty get") == -1) {
PyC_Err_PrintWithFunc(py_func);
- for (i = 0; i < len; ++i) {
+ for (i = 0; i < len; i++) {
values[i] = 0;
}
@@ -968,7 +968,7 @@ static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr,
if (ret == NULL) {
PyC_Err_PrintWithFunc(py_func);
- for (i = 0; i < len; ++i) {
+ for (i = 0; i < len; i++) {
values[i] = 0.0f;
}
}
@@ -976,7 +976,7 @@ static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr,
if (PyC_AsArray(values, ret, len, &PyFloat_Type, false, "FloatVectorProperty get") == -1) {
PyC_Err_PrintWithFunc(py_func);
- for (i = 0; i < len; ++i) {
+ for (i = 0; i < len; i++) {
values[i] = 0.0f;
}
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index b85d48b67da..45a7d2dacd1 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -918,21 +918,21 @@ static PyObject *pyrna_struct_repr(BPy_StructRNA *self)
tmp_str = PyUnicode_FromString(id->name + 2);
- if (RNA_struct_is_ID(self->ptr.type)) {
+ if (RNA_struct_is_ID(self->ptr.type) && (id->flag & LIB_PRIVATE_DATA) == 0) {
ret = PyUnicode_FromFormat(
"bpy.data.%s[%R]", BKE_idcode_to_name_plural(GS(id->name)), tmp_str);
}
else {
const char *path;
- path = RNA_path_from_ID_to_struct(&self->ptr);
+ ID *real_id = NULL;
+ path = RNA_path_from_real_ID_to_struct(G_MAIN, &self->ptr, &real_id);
if (path) {
- if (GS(id->name) == ID_NT) { /* Nodetree paths are not accurate. */
- ret = PyUnicode_FromFormat("bpy.data...%s", path);
- }
- else {
- ret = PyUnicode_FromFormat(
- "bpy.data.%s[%R].%s", BKE_idcode_to_name_plural(GS(id->name)), tmp_str, path);
+ if (real_id != id) {
+ Py_DECREF(tmp_str);
+ tmp_str = PyUnicode_FromString(real_id->name + 2);
}
+ ret = PyUnicode_FromFormat(
+ "bpy.data.%s[%R].%s", BKE_idcode_to_name_plural(GS(real_id->name)), tmp_str, path);
MEM_freeN((void *)path);
}
@@ -1033,20 +1033,23 @@ static PyObject *pyrna_prop_repr_ex(BPy_PropertyRNA *self, const int index_dim,
tmp_str = PyUnicode_FromString(id->name + 2);
- path = RNA_path_from_ID_to_property_index(&self->ptr, self->prop, index_dim, index);
+ /* Note that using G_MAIN is absolutely not ideal, but we have no access to actual Main DB from
+ * here. */
+ ID *real_id = NULL;
+ path = RNA_path_from_real_ID_to_property_index(
+ G_MAIN, &self->ptr, self->prop, index_dim, index, &real_id);
if (path) {
- const char *data_delim = (path[0] == '[') ? "" : ".";
- if (GS(id->name) == ID_NT) { /* Nodetree paths are not accurate. */
- ret = PyUnicode_FromFormat("bpy.data...%s", path);
- }
- else {
- ret = PyUnicode_FromFormat("bpy.data.%s[%R]%s%s",
- BKE_idcode_to_name_plural(GS(id->name)),
- tmp_str,
- data_delim,
- path);
+ if (real_id != id) {
+ Py_DECREF(tmp_str);
+ tmp_str = PyUnicode_FromString(real_id->name + 2);
}
+ const char *data_delim = (path[0] == '[') ? "" : ".";
+ ret = PyUnicode_FromFormat("bpy.data.%s[%R]%s%s",
+ BKE_idcode_to_name_plural(GS(real_id->name)),
+ tmp_str,
+ data_delim,
+ path);
MEM_freeN((void *)path);
}
@@ -1765,7 +1768,12 @@ static int pyrna_py_to_prop(
if (value == Py_None) {
if ((RNA_property_flag(prop) & PROP_NEVER_NULL) == 0) {
if (data) {
- *((char **)data) = (char *)NULL;
+ if (RNA_property_flag(prop) & PROP_THICK_WRAP) {
+ *(char *)data = 0;
+ }
+ else {
+ *((char **)data) = (char *)NULL;
+ }
}
else {
RNA_property_string_set(ptr, prop, NULL);
@@ -1810,7 +1818,12 @@ static int pyrna_py_to_prop(
}
else {
if (data) {
- *((char **)data) = (char *)param;
+ if (RNA_property_flag(prop) & PROP_THICK_WRAP) {
+ BLI_strncpy((char *)data, (char *)param, RNA_property_string_maxlength(prop));
+ }
+ else {
+ *((char **)data) = (char *)param;
+ }
}
else {
RNA_property_string_set_bytes(ptr, prop, param, PyBytes_Size(value));
@@ -1859,7 +1872,12 @@ static int pyrna_py_to_prop(
/* XXX, this is suspect, but needed for function calls,
* need to see if there's a better way. */
if (data) {
- *((char **)data) = (char *)param;
+ if (RNA_property_flag(prop) & PROP_THICK_WRAP) {
+ BLI_strncpy((char *)data, (char *)param, RNA_property_string_maxlength(prop));
+ }
+ else {
+ *((char **)data) = (char *)param;
+ }
}
else {
RNA_property_string_set(ptr, prop, param);
@@ -1910,7 +1928,7 @@ static int pyrna_py_to_prop(
* layout.prop(self.properties, "filepath")
*
* we need to do this trick.
- * if the prop is not an operator type and the pyobject is an operator,
+ * if the prop is not an operator type and the PyObject is an operator,
* use its properties in place of itself.
*
* This is so bad that it is almost a good reason to do away with fake
@@ -3692,9 +3710,9 @@ static PyObject *pyrna_struct_is_property_readonly(BPy_StructRNA *self, PyObject
PyDoc_STRVAR(pyrna_struct_is_property_overridable_library_doc,
".. method:: is_property_overridable_library(property)\n"
"\n"
- " Check if a property is statically overridable.\n"
+ " Check if a property is overridable.\n"
"\n"
- " :return: True when the property is statically overridable.\n"
+ " :return: True when the property is overridable.\n"
" :rtype: boolean\n");
static PyObject *pyrna_struct_is_property_overridable_library(BPy_StructRNA *self, PyObject *args)
{
@@ -3718,14 +3736,13 @@ static PyObject *pyrna_struct_is_property_overridable_library(BPy_StructRNA *sel
return PyBool_FromLong((long)RNA_property_overridable_get(&self->ptr, prop));
}
-PyDoc_STRVAR(
- pyrna_struct_property_overridable_library_set_doc,
- ".. method:: property_overridable_library_set(property)\n"
- "\n"
- " Define a property as statically overridable or not (only for custom properties!).\n"
- "\n"
- " :return: True when the overridable status of the property was successfully set.\n"
- " :rtype: boolean\n");
+PyDoc_STRVAR(pyrna_struct_property_overridable_library_set_doc,
+ ".. method:: property_overridable_library_set(property, overridable)\n"
+ "\n"
+ " Define a property as overridable or not (only for custom properties!).\n"
+ "\n"
+ " :return: True when the overridable status of the property was successfully set.\n"
+ " :rtype: boolean\n");
static PyObject *pyrna_struct_property_overridable_library_set(BPy_StructRNA *self, PyObject *args)
{
PropertyRNA *prop;
@@ -3968,7 +3985,7 @@ static PyObject *pyrna_struct_type_recast(BPy_StructRNA *self)
}
/**
- * \note Return value is borrowed, caller must incref.
+ * \note Return value is borrowed, caller must #Py_INCREF.
*/
static PyObject *pyrna_struct_bl_rna_find_subclass_recursive(PyObject *cls, const char *id)
{
@@ -7175,7 +7192,7 @@ static PyObject *pyrna_srna_Subtype(StructRNA *srna)
#endif
/* Newclass will now have 2 ref's, ???,
- * probably 1 is internal since decrefing here segfaults. */
+ * probably 1 is internal since #Py_DECREF here segfaults. */
/* PyC_ObSpit("new class ref", newclass); */
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index 5e535d0e3ce..8aa6aa91fcf 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -277,7 +277,7 @@ static int pyrna_struct_keyframe_parse(PointerRNA *ptr,
char pyrna_struct_keyframe_insert_doc[] =
".. method:: keyframe_insert(data_path, index=-1, frame=bpy.context.scene.frame_current, "
- "group=\"\")\n"
+ "group=\"\", options=set())\n"
"\n"
" Insert a keyframe on the property given, adding fcurves and animation data when "
"necessary.\n"
@@ -294,7 +294,7 @@ char pyrna_struct_keyframe_insert_doc[] =
" :arg group: The name of the group the F-Curve should be added to if it doesn't exist "
"yet.\n"
" :type group: str\n"
- " :arg options: Optional flags:\n"
+ " :arg options: Optional set of flags:\n"
"\n"
" - ``INSERTKEY_NEEDED`` Only insert keyframes where they're needed in the relevant "
"F-Curves.\n"
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
index 267971408bf..2b3aa29a366 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.c
+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
@@ -176,6 +176,50 @@ static PyObject *Quaternion_to_axis_angle(QuaternionObject *self)
return ret;
}
+PyDoc_STRVAR(Quaternion_to_swing_twist_doc,
+ ".. method:: to_swing_twist(axis)\n"
+ "\n"
+ " Split the rotation into a swing quaternion with the specified\n"
+ "axis fixed at zero, and the remaining twist rotation angle.\n"
+ "\n"
+ " :arg axis: twist axis as a string in ['X', 'Y', 'Z']\n"
+ " :return: swing, twist angle.\n"
+ " :rtype: (:class:`Quaternion`, float) pair\n");
+static PyObject *Quaternion_to_swing_twist(QuaternionObject *self, PyObject *axis_arg)
+{
+ PyObject *ret;
+
+ const char *axis_str = NULL;
+ float swing[4], twist;
+ int axis;
+
+ if (axis_arg && PyUnicode_Check(axis_arg)) {
+ axis_str = _PyUnicode_AsString(axis_arg);
+ }
+
+ if (axis_str && axis_str[0] >= 'X' && axis_str[0] <= 'Z' && axis_str[1] == 0) {
+ axis = axis_str[0] - 'X';
+ }
+ else {
+ PyErr_SetString(PyExc_ValueError,
+ "Quaternion.to_swing_twist(): "
+ "the axis agrument must be "
+ "a string in 'X', 'Y', 'Z'");
+ return NULL;
+ }
+
+ if (BaseMath_ReadCallback(self) == -1) {
+ return NULL;
+ }
+
+ twist = quat_split_swing_and_twist(self->quat, axis, swing, NULL);
+
+ ret = PyTuple_New(2);
+ PyTuple_SET_ITEMS(
+ ret, Quaternion_CreatePyObject(swing, Py_TYPE(self)), PyFloat_FromDouble(twist));
+ return ret;
+}
+
PyDoc_STRVAR(
Quaternion_to_exponential_map_doc,
".. method:: to_exponential_map()\n"
@@ -1368,6 +1412,10 @@ static struct PyMethodDef Quaternion_methods[] = {
(PyCFunction)Quaternion_to_axis_angle,
METH_NOARGS,
Quaternion_to_axis_angle_doc},
+ {"to_swing_twist",
+ (PyCFunction)Quaternion_to_swing_twist,
+ METH_O,
+ Quaternion_to_swing_twist_doc},
{"to_exponential_map",
(PyCFunction)Quaternion_to_exponential_map,
METH_NOARGS,
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index aa7cbadde14..0555c707ed3 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -691,7 +691,8 @@ PyDoc_STRVAR(Vector_to_track_quat_doc,
static PyObject *Vector_to_track_quat(VectorObject *self, PyObject *args)
{
float vec[3], quat[4];
- const char *strack, *sup;
+ const char *strack = NULL;
+ const char *sup = NULL;
short track = 2, up = 1;
if (!PyArg_ParseTuple(args, "|ss:to_track_quat", &strack, &sup)) {
@@ -2350,26 +2351,26 @@ static PyObject *Vector_length_squared_get(VectorObject *self, void *UNUSED(clos
*
* axis_dict = {}
* axis_pos = {'x': 0, 'y': 1, 'z': 2, 'w': 3}
- * axises = 'xyzw'
- * while len(axises) >= 2:
- * for axis_0 in axises:
+ * axis_chars = 'xyzw'
+ * while len(axis_chars) >= 2:
+ * for axis_0 in axis_chars:
* axis_0_pos = axis_pos[axis_0]
- * for axis_1 in axises:
+ * for axis_1 in axis_chars:
* axis_1_pos = axis_pos[axis_1]
* axis_dict[axis_0 + axis_1] = (
* '((%s | SWIZZLE_VALID_AXIS) | '
* '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS))' %
* (axis_0_pos, axis_1_pos))
- * if len(axises) > 2:
- * for axis_2 in axises:
+ * if len(axis_chars) > 2:
+ * for axis_2 in axis_chars:
* axis_2_pos = axis_pos[axis_2]
* axis_dict[axis_0 + axis_1 + axis_2] = (
* '((%s | SWIZZLE_VALID_AXIS) | '
* '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | '
* '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)))' %
* (axis_0_pos, axis_1_pos, axis_2_pos))
- * if len(axises) > 3:
- * for axis_3 in axises:
+ * if len(axis_chars) > 3:
+ * for axis_3 in axis_chars:
* axis_3_pos = axis_pos[axis_3]
* axis_dict[axis_0 + axis_1 + axis_2 + axis_3] = (
* '((%s | SWIZZLE_VALID_AXIS) | '
@@ -2379,7 +2380,7 @@ static PyObject *Vector_length_squared_get(VectorObject *self, void *UNUSED(clos
* %
* (axis_0_pos, axis_1_pos, axis_2_pos, axis_3_pos))
*
- * axises = axises[:-1]
+ * axis_chars = axis_chars[:-1]
* items = list(axis_dict.items())
* items.sort(
* key=lambda a: a[0].replace('x', '0').replace('y', '1').replace('z', '2').replace('w', '3')
diff --git a/source/blender/python/mathutils/mathutils_noise.c b/source/blender/python/mathutils/mathutils_noise.c
index b890295d32f..1b438072329 100644
--- a/source/blender/python/mathutils/mathutils_noise.c
+++ b/source/blender/python/mathutils/mathutils_noise.c
@@ -140,11 +140,11 @@ static void next_state(void)
left = N;
next = state;
- for (j = N - M + 1; --j; p++) {
+ for (j = N - M + 1; j--; p++) {
*p = p[M] ^ TWIST(p[0], p[1]);
}
- for (j = M; --j; p++) {
+ for (j = M; j--; p++) {
*p = p[M - N] ^ TWIST(p[0], p[1]);
}
diff --git a/source/blender/python/rna_dump.py b/source/blender/python/rna_dump.py
index c2ede5664f2..7d469d20110 100644
--- a/source/blender/python/rna_dump.py
+++ b/source/blender/python/rna_dump.py
@@ -133,8 +133,10 @@ seek(bpy.data, 'bpy.data', 0)
'''
for d in dir(bpy.types):
t = getattr(bpy.types, d)
- try: r = t.bl_rna
- except: r = None
+ try:
+ r = t.bl_rna
+ except:
+ r = None
if r:
seek(r, 'bpy.types.' + d + '.bl_rna', 0)
'''
diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c
index 4e5a83555eb..e8c349f6c85 100644
--- a/source/blender/render/intern/source/bake_api.c
+++ b/source/blender/render/intern/source/bake_api.c
@@ -172,8 +172,8 @@ void RE_bake_margin(ImBuf *ibuf, char *mask, const int margin)
*/
static void calc_point_from_barycentric_cage(TriTessFace *triangles_low,
TriTessFace *triangles_cage,
- float mat_low[4][4],
- float mat_cage[4][4],
+ const float mat_low[4][4],
+ const float mat_cage[4][4],
int primitive_id,
float u,
float v,
@@ -214,8 +214,8 @@ static void calc_point_from_barycentric_cage(TriTessFace *triangles_low,
* The returned coordinate is extruded along the normal by cage_extrusion
*/
static void calc_point_from_barycentric_extrusion(TriTessFace *triangles,
- float mat[4][4],
- float imat[4][4],
+ const float mat[4][4],
+ const float imat[4][4],
int primitive_id,
float u,
float v,
@@ -316,7 +316,7 @@ static bool cast_ray_highpoly(BVHTreeFromMesh *treeData,
TriTessFace *triangles[],
BakePixel *pixel_array_low,
BakePixel *pixel_array,
- float mat_low[4][4],
+ const float mat_low[4][4],
BakeHighPolyData *highpoly,
const float co[3],
const float dir[3],
diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c
index 0db1a4b81ae..d3080ebe3ed 100644
--- a/source/blender/render/intern/source/external_engine.c
+++ b/source/blender/render/intern/source/external_engine.c
@@ -509,7 +509,7 @@ static void engine_depsgraph_init(RenderEngine *engine, ViewLayer *view_layer)
Main *bmain = engine->re->main;
Scene *scene = engine->re->scene;
- engine->depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
+ engine->depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
DEG_debug_name_set(engine->depsgraph, "RENDER");
if (engine->re->r.scemode & R_BUTS_PREVIEW) {
diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c
index 9672184cec8..dc7288234b3 100644
--- a/source/blender/render/intern/source/imagetexture.c
+++ b/source/blender/render/intern/source/imagetexture.c
@@ -842,8 +842,8 @@ static void area_sample(TexResult *texr, ImBuf *ibuf, float fx, float fy, afdata
xsd = 1.f / xsam;
ysd = 1.f / ysam;
texr->tr = texr->tg = texr->tb = texr->ta = 0.f;
- for (ys = 0; ys < ysam; ++ys) {
- for (xs = 0; xs < xsam; ++xs) {
+ for (ys = 0; ys < ysam; ys++) {
+ for (xs = 0; xs < xsam; xs++) {
const float su = (xs + ((ys & 1) + 0.5f) * 0.5f) * xsd - 0.5f;
const float sv = (ys + ((xs & 1) + 0.5f) * 0.5f) * ysd - 0.5f;
const float pu = fx + su * AFD->dxt[0] + sv * AFD->dyt[0];
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index b4d0c2147f2..c3125cb72a1 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -48,11 +48,11 @@
#include "BLI_timecode.h"
#include "BLI_fileops.h"
#include "BLI_threads.h"
-#include "BLI_callbacks.h"
#include "BLT_translation.h"
#include "BKE_animsys.h" /* <------ should this be here?, needed for sequencer update */
+#include "BKE_callbacks.h"
#include "BKE_camera.h"
#include "BKE_colortools.h"
#include "BKE_context.h" /* XXX needed by wm_window.h */
@@ -134,6 +134,24 @@ static struct {
ListBase renderlist;
} RenderGlobal = {{NULL, NULL}};
+/* ********* callbacks ******** */
+
+static void render_callback_exec_null(Render *re, Main *bmain, eCbEvent evt)
+{
+ if (re->r.scemode & R_BUTS_PREVIEW) {
+ return;
+ }
+ BKE_callback_exec_null(bmain, evt);
+}
+
+static void render_callback_exec_id(Render *re, Main *bmain, ID *id, eCbEvent evt)
+{
+ if (re->r.scemode & R_BUTS_PREVIEW) {
+ return;
+ }
+ BKE_callback_exec_id(bmain, id, evt);
+}
+
/* ********* alloc and free ******** */
static int do_write_image_or_movie(Render *re,
@@ -226,7 +244,7 @@ static void stats_background(void *UNUSED(arg), RenderStats *rs)
/* NOTE: using G_MAIN seems valid here???
* Not sure it's actually even used anyway, we could as well pass NULL? */
- BLI_callback_exec(G_MAIN, NULL, BLI_CB_EVT_RENDER_STATS);
+ BKE_callback_exec_null(G_MAIN, BKE_CB_EVT_RENDER_STATS);
fputc('\n', stdout);
fflush(stdout);
@@ -926,8 +944,8 @@ static void render_result_rescale(Render *re)
scale_x = (float)result->rectx / re->result->rectx;
scale_y = (float)result->recty / re->result->recty;
- for (x = 0; x < re->result->rectx; ++x) {
- for (y = 0; y < re->result->recty; ++y) {
+ for (x = 0; x < re->result->rectx; x++) {
+ for (y = 0; y < re->result->recty; y++) {
int src_x = x * scale_x;
int src_y = y * scale_y;
int dst_index = y * re->result->rectx + x;
@@ -1637,7 +1655,7 @@ static void do_render_seq(Render *re)
BKE_stamp_info_from_imbuf(rr, ibuf_arr[view_id]);
}
- if (recurs_depth == 0) { /* with nested scenes, only free on toplevel... */
+ if (recurs_depth == 0) { /* With nested scenes, only free on top-level. */
Editing *ed = re->pipeline_scene_eval->ed;
if (ed) {
BKE_sequencer_free_imbuf(re->pipeline_scene_eval, &ed->seqbase, true);
@@ -1953,7 +1971,7 @@ static void update_physics_cache(Render *re,
baker.bmain = re->main;
baker.scene = scene;
baker.view_layer = view_layer;
- baker.depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ baker.depsgraph = BKE_scene_get_depsgraph(re->main, scene, view_layer, true);
baker.bake = 0;
baker.render = 1;
baker.anim_init = 1;
@@ -2069,7 +2087,7 @@ static void render_init_depsgraph(Render *re)
Scene *scene = re->scene;
ViewLayer *view_layer = BKE_view_layer_default_render(re->scene);
- re->pipeline_depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
+ re->pipeline_depsgraph = DEG_graph_new(re->main, scene, view_layer, DAG_EVAL_RENDER);
DEG_debug_name_set(re->pipeline_depsgraph, "RENDER PIPELINE");
/* Make sure there is a correct evaluated scene pointer. */
@@ -2090,7 +2108,7 @@ void RE_RenderFrame(Render *re,
int frame,
const bool write_still)
{
- BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_INIT);
+ render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_INIT);
/* Ugly global still...
* is to prevent preview events and signal subsurfs etc to make full resol. */
@@ -2103,9 +2121,9 @@ void RE_RenderFrame(Render *re,
const RenderData rd = scene->r;
MEM_reset_peak_memory();
- render_init_depsgraph(re);
+ render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_PRE);
- BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_PRE);
+ render_init_depsgraph(re);
do_render_all_options(re);
@@ -2131,14 +2149,16 @@ void RE_RenderFrame(Render *re,
}
/* keep after file save */
- BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_POST);
+ render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_POST);
if (write_still) {
- BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_WRITE);
+ render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_WRITE);
}
}
- BLI_callback_exec(
- re->main, (ID *)scene, G.is_break ? BLI_CB_EVT_RENDER_CANCEL : BLI_CB_EVT_RENDER_COMPLETE);
+ render_callback_exec_id(re,
+ re->main,
+ &scene->id,
+ G.is_break ? BKE_CB_EVT_RENDER_CANCEL : BKE_CB_EVT_RENDER_COMPLETE);
RE_CleanAfterRender(re);
@@ -2429,7 +2449,7 @@ static int do_write_image_or_movie(Render *re,
/* NOTE: using G_MAIN seems valid here???
* Not sure it's actually even used anyway, we could as well pass NULL? */
- BLI_callback_exec(G_MAIN, NULL, BLI_CB_EVT_RENDER_STATS);
+ render_callback_exec_null(re, G_MAIN, BKE_CB_EVT_RENDER_STATS);
BLI_timecode_string_from_time_simple(name, sizeof(name), re->i.lastframetime - render_time);
printf(" (Saving: %s)\n", name);
@@ -2486,6 +2506,10 @@ void RE_RenderAnim(Render *re,
int efra,
int tfra)
{
+ /* Call hooks before taking a copy of scene->r, so user can alter the render settings prior to
+ * copying (e.g. alter the output path). */
+ render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_INIT);
+
const RenderData rd = scene->r;
bMovieHandle *mh = NULL;
const int cfrao = rd.cfra;
@@ -2495,8 +2519,6 @@ void RE_RenderAnim(Render *re,
const bool is_multiview_name = ((rd.scemode & R_MULTIVIEW) != 0 &&
(rd.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL));
- BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_INIT);
-
/* do not fully call for each frame, it initializes & pops output window */
if (!render_initialize_from_main(re, &rd, bmain, scene, single_layer, camera_override, 0, 1)) {
return;
@@ -2660,8 +2682,8 @@ void RE_RenderAnim(Render *re,
re->r.cfra = scene->r.cfra; /* weak.... */
- /* run callbacs before rendering, before the scene is updated */
- BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_PRE);
+ /* run callbacks before rendering, before the scene is updated */
+ render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_PRE);
do_render_all_options(re);
totrendered++;
@@ -2712,8 +2734,8 @@ void RE_RenderAnim(Render *re,
if (G.is_break == false) {
/* keep after file save */
- BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_POST);
- BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_WRITE);
+ render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_POST);
+ render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_WRITE);
}
}
}
@@ -2731,8 +2753,10 @@ void RE_RenderAnim(Render *re,
re->flag &= ~R_ANIMATION;
- BLI_callback_exec(
- re->main, (ID *)scene, G.is_break ? BLI_CB_EVT_RENDER_CANCEL : BLI_CB_EVT_RENDER_COMPLETE);
+ render_callback_exec_id(re,
+ re->main,
+ &scene->id,
+ G.is_break ? BKE_CB_EVT_RENDER_CANCEL : BKE_CB_EVT_RENDER_COMPLETE);
BKE_sound_reset_scene_specs(re->pipeline_scene_eval);
RE_CleanAfterRender(re);
diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c
index 3ede55434b9..c99f5d4075f 100644
--- a/source/blender/render/intern/source/pointdensity.c
+++ b/source/blender/render/intern/source/pointdensity.c
@@ -355,11 +355,11 @@ static void pointdensity_cache_vertex_weight(PointDensity *pd,
return;
}
- for (i = 0, dv = mdef; i < totvert; ++i, ++dv, data_color += 3) {
+ for (i = 0, dv = mdef; i < totvert; i++, dv++, data_color += 3) {
MDeformWeight *dw;
int j;
- for (j = 0, dw = dv->dw; j < dv->totweight; ++j, ++dw) {
+ for (j = 0, dw = dv->dw; j < dv->totweight; j++, dw++) {
if (dw->def_nr == mdef_index) {
copy_v3_fl(data_color, dw->weight);
break;
@@ -832,7 +832,7 @@ void RE_point_density_cache(struct Depsgraph *depsgraph, PointDensity *pd)
{
Scene *scene = DEG_get_evaluated_scene(depsgraph);
- /* Same matricies/resolution as dupli_render_particle_set(). */
+ /* Same matrices/resolution as dupli_render_particle_set(). */
BLI_mutex_lock(&sample_mutex);
cache_pointdensity(depsgraph, scene, pd);
BLI_mutex_unlock(&sample_mutex);
@@ -910,8 +910,8 @@ static void point_density_sample_func(void *__restrict data_v,
}
size_t z = (size_t)iter;
- for (size_t y = 0; y < resolution; ++y) {
- for (size_t x = 0; x < resolution; ++x) {
+ for (size_t y = 0; y < resolution; y++) {
+ for (size_t x = 0; x < resolution; x++) {
size_t index = z * resolution2 + y * resolution + x;
float texvec[3];
float age, vec[3], col[3];
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 13be8701c27..2d9fa9e5ab6 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -102,6 +102,8 @@ void WM_init_opengl(struct Main *bmain);
void WM_check(struct bContext *C);
void WM_reinit_gizmomap_all(struct Main *bmain);
+void WM_script_tag_reload(void);
+
uint *WM_window_pixels_read(struct wmWindowManager *wm, struct wmWindow *win, int r_size[2]);
int WM_window_pixels_x(const struct wmWindow *win);
@@ -153,18 +155,9 @@ void WM_opengl_context_dispose(void *context);
void WM_opengl_context_activate(void *context);
void WM_opengl_context_release(void *context);
-/* defines for 'type' WM_window_open_temp */
-enum {
- WM_WINDOW_RENDER = 1,
- WM_WINDOW_USERPREFS,
- WM_WINDOW_DRIVERS,
- WM_WINDOW_INFO,
- // WM_WINDOW_FILESEL // UNUSED
-};
-
struct wmWindow *WM_window_open(struct bContext *C, const struct rcti *rect);
struct wmWindow *WM_window_open_temp(
- struct bContext *C, int x, int y, int sizex, int sizey, int type);
+ struct bContext *C, const char *title, int x, int y, int sizex, int sizey, int space_type);
void WM_window_set_dpi(wmWindow *win);
bool WM_stereo3d_enabled(struct wmWindow *win, bool only_fullscreen_test);
@@ -493,6 +486,8 @@ bool WM_operator_properties_checker_interval_test(const struct CheckerIntervalPa
#define WM_FILESEL_FILENAME (1 << 2)
#define WM_FILESEL_FILEPATH (1 << 3)
#define WM_FILESEL_FILES (1 << 4)
+/* Show the properties sidebar by default. */
+#define WM_FILESEL_SHOW_PROPS (1 << 5)
/* operator as a python command (resultuing string must be freed) */
char *WM_operator_pystring_ex(struct bContext *C,
@@ -545,6 +540,9 @@ struct wmOperatorTypeMacro *WM_operatortype_macro_define(struct wmOperatorType *
const char *idname);
const char *WM_operatortype_name(struct wmOperatorType *ot, struct PointerRNA *properties);
+char *WM_operatortype_description(struct bContext *C,
+ struct wmOperatorType *ot,
+ struct PointerRNA *properties);
/* wm_uilist_type.c */
void WM_uilisttype_init(void);
@@ -681,6 +679,7 @@ enum {
WM_JOB_TYPE_STUDIOLIGHT,
WM_JOB_TYPE_LIGHT_BAKE,
WM_JOB_TYPE_FSMENU_BOOKMARK_VALIDATE,
+ WM_JOB_TYPE_QUADRIFLOW_REMESH,
/* 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 7fdbf79248b..15ad8cbedc4 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -737,6 +737,12 @@ typedef struct wmOperatorType {
*/
const char *(*get_name)(struct wmOperatorType *, struct PointerRNA *);
+ /**
+ * Return a different description to use in the user interface, based on property values.
+ * The returned string must be freed by the caller, unless NULL.
+ */
+ char *(*get_description)(struct bContext *C, struct wmOperatorType *, struct PointerRNA *);
+
/** rna for properties */
struct StructRNA *srna;
@@ -769,6 +775,16 @@ typedef struct wmOperatorType {
} wmOperatorType;
+/**
+ * Wrapper to reference a #wmOperatorType together with some set properties and other relevant
+ * information to invoke the operator in a customizable way.
+ */
+typedef struct wmOperatorCallParams {
+ struct wmOperatorType *optype;
+ struct PointerRNA *opptr;
+ short opcontext;
+} wmOperatorCallParams;
+
#ifdef WITH_INPUT_IME
/* *********** Input Method Editor (IME) *********** */
/**
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
index 8eefea84ff8..dd568d7baf1 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
@@ -30,7 +30,6 @@
#include "GPU_batch.h"
#include "GPU_glew.h"
-#include "GPU_immediate.h"
#include "RNA_access.h"
#include "RNA_define.h"
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
index 50c98630a16..77950c11c63 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
@@ -34,7 +34,6 @@
#include "BLI_buffer.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
-#include "BLI_math.h"
#include "BKE_context.h"
#include "BKE_main.h"
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index cd140eba55a..4b1abeceebb 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -45,48 +45,106 @@
#include "wm_cursors.h"
#include "wm_window.h"
-/* XXX this still is mess from old code */
+/* Blender custom cursor. */
+typedef struct BCursor {
+ char *small_bm;
+ char *small_mask;
-/* Some simple ghost <-> blender conversions */
-static GHOST_TStandardCursor convert_cursor(int curs)
+ char small_sizex;
+ char small_sizey;
+ char small_hotx;
+ char small_hoty;
+
+ char *big_bm;
+ char *big_mask;
+
+ char big_sizex;
+ char big_sizey;
+ char big_hotx;
+ char big_hoty;
+
+ bool can_invert_color;
+} BCursor;
+
+static BCursor *BlenderCursor[WM_CURSOR_NUM] = {0};
+
+/* Blender cursor to GHOST standard cursor conversion. */
+static GHOST_TStandardCursor convert_to_ghost_standard_cursor(WMCursorType curs)
{
switch (curs) {
- default:
- case CURSOR_STD:
+ case WM_CURSOR_DEFAULT:
return GHOST_kStandardCursorDefault;
- case CURSOR_FACESEL:
- return GHOST_kStandardCursorRightArrow;
- case CURSOR_WAIT:
+ case WM_CURSOR_WAIT:
return GHOST_kStandardCursorWait;
- case CURSOR_EDIT:
+ case WM_CURSOR_EDIT:
+ case WM_CURSOR_CROSS:
return GHOST_kStandardCursorCrosshair;
- case CURSOR_HELP:
-#ifdef __APPLE__
- return GHOST_kStandardCursorLeftRight;
-#else
- return GHOST_kStandardCursorHelp;
-#endif
- case CURSOR_X_MOVE:
+ case WM_CURSOR_X_MOVE:
return GHOST_kStandardCursorLeftRight;
- case CURSOR_Y_MOVE:
+ case WM_CURSOR_Y_MOVE:
return GHOST_kStandardCursorUpDown;
- case CURSOR_PENCIL:
- return GHOST_kStandardCursorPencil;
- case CURSOR_COPY:
+ case WM_CURSOR_COPY:
return GHOST_kStandardCursorCopy;
+ case WM_CURSOR_HAND:
+ return GHOST_kStandardCursorMove;
+ case WM_CURSOR_H_SPLIT:
+ return GHOST_kStandardCursorHorizontalSplit;
+ case WM_CURSOR_V_SPLIT:
+ return GHOST_kStandardCursorVerticalSplit;
+ case WM_CURSOR_STOP:
+ return GHOST_kStandardCursorStop;
+ case WM_CURSOR_KNIFE:
+ return GHOST_kStandardCursorKnife;
+ case WM_CURSOR_NSEW_SCROLL:
+ return GHOST_kStandardCursorNSEWScroll;
+ case WM_CURSOR_NS_SCROLL:
+ return GHOST_kStandardCursorNSScroll;
+ case WM_CURSOR_EW_SCROLL:
+ return GHOST_kStandardCursorEWScroll;
+ case WM_CURSOR_EYEDROPPER:
+ return GHOST_kStandardCursorEyedropper;
+ case WM_CURSOR_N_ARROW:
+ return GHOST_kStandardCursorUpArrow;
+ case WM_CURSOR_S_ARROW:
+ return GHOST_kStandardCursorDownArrow;
+ case WM_CURSOR_PAINT:
+ return GHOST_kStandardCursorCrosshairA;
+ case WM_CURSOR_DOT:
+ return GHOST_kStandardCursorCrosshairB;
+ case WM_CURSOR_CROSSC:
+ return GHOST_kStandardCursorCrosshairC;
+ case WM_CURSOR_ERASER:
+ return GHOST_kStandardCursorEraser;
+ case WM_CURSOR_ZOOM_IN:
+ return GHOST_kStandardCursorZoomIn;
+ case WM_CURSOR_ZOOM_OUT:
+ return GHOST_kStandardCursorZoomOut;
+ case WM_CURSOR_TEXT_EDIT:
+ return GHOST_kStandardCursorText;
+ case WM_CURSOR_PAINT_BRUSH:
+ return GHOST_kStandardCursorPencil;
+ case WM_CURSOR_E_ARROW:
+ return GHOST_kStandardCursorRightArrow;
+ case WM_CURSOR_W_ARROW:
+ return GHOST_kStandardCursorLeftArrow;
+ default:
+ return GHOST_kStandardCursorCustom;
}
}
-static void window_set_custom_cursor(
- wmWindow *win, unsigned char mask[16][2], unsigned char bitmap[16][2], int hotx, int hoty)
+static void window_set_custom_cursor(wmWindow *win,
+ unsigned const char mask[16][2],
+ unsigned char bitmap[16][2],
+ int hotx,
+ int hoty)
{
GHOST_SetCustomCursorShape(
win->ghostwin, (GHOST_TUns8 *)bitmap, (GHOST_TUns8 *)mask, 16, 16, hotx, hoty, true);
}
-static void window_set_custom_cursor_ex(wmWindow *win, BCursor *cursor, int useBig)
+static void window_set_custom_cursor_ex(wmWindow *win, BCursor *cursor)
{
- if (useBig) {
+ if (U.curssize && cursor->big_bm) {
GHOST_SetCustomCursorShape(win->ghostwin,
(GHOST_TUns8 *)cursor->big_bm,
(GHOST_TUns8 *)cursor->big_mask,
@@ -108,60 +166,46 @@ static void window_set_custom_cursor_ex(wmWindow *win, BCursor *cursor, int useB
}
}
-/* Cursor Globals */
-static BCursor *BlenderCursor[BC_NUMCURSORS]; /*Points to static BCursor Structs */
-
void WM_cursor_set(wmWindow *win, int curs)
{
-
if (win == NULL || G.background) {
return; /* Can't set custom cursor before Window init */
}
- if (curs == CURSOR_NONE) {
+ if (curs == WM_CURSOR_NONE) {
GHOST_SetCursorVisibility(win->ghostwin, 0);
return;
}
-#ifdef _WIN32
- /* the default win32 cross cursor is barely visible,
- * only 1 pixel thick, use another one instead */
- if (curs == CURSOR_EDIT) {
- curs = BC_CROSSCURSOR;
- }
-#else
- /* in case of large cursor, also use custom cursor because
- * large cursors don't work for system cursors */
- if (U.curssize && curs == CURSOR_EDIT) {
- curs = BC_CROSSCURSOR;
- }
-#endif
-
GHOST_SetCursorVisibility(win->ghostwin, 1);
- if (curs == CURSOR_STD && win->modalcursor) {
+ if (curs == WM_CURSOR_DEFAULT && win->modalcursor) {
curs = win->modalcursor;
}
win->cursor = curs;
- /* detect if we use system cursor or Blender cursor */
- if (curs >= BC_GHOST_CURSORS) {
- GHOST_SetCursorShape(win->ghostwin, convert_cursor(curs));
+ if (curs < 0 || curs >= WM_CURSOR_NUM) {
+ BLI_assert(!"Invalid cursor number");
+ return;
}
- else {
- if ((curs < SYSCURSOR) || (curs >= BC_NUMCURSORS)) {
- return;
- }
- if (curs == SYSCURSOR) { /* System default Cursor */
- GHOST_SetCursorShape(win->ghostwin, convert_cursor(CURSOR_STD));
- }
- else if ((U.curssize == 0) || (BlenderCursor[curs]->big_bm == NULL)) {
- window_set_custom_cursor_ex(win, BlenderCursor[curs], 0);
+ GHOST_TStandardCursor ghost_cursor = convert_to_ghost_standard_cursor(curs);
+
+ if (ghost_cursor != GHOST_kStandardCursorCustom &&
+ GHOST_HasCursorShape(win->ghostwin, ghost_cursor)) {
+ /* Use native GHOST cursor when available. */
+ GHOST_SetCursorShape(win->ghostwin, ghost_cursor);
+ }
+ else {
+ BCursor *bcursor = BlenderCursor[curs];
+ if (bcursor) {
+ /* Use custom bitmap cursor. */
+ window_set_custom_cursor_ex(win, bcursor);
}
else {
- window_set_custom_cursor_ex(win, BlenderCursor[curs], 1);
+ /* Fallback to default cursor if no bitmap found. */
+ GHOST_SetCursorShape(win->ghostwin, GHOST_kStandardCursorDefault);
}
}
}
@@ -173,7 +217,7 @@ bool WM_cursor_set_from_tool(struct wmWindow *win, const ScrArea *sa, const AReg
}
bToolRef_Runtime *tref_rt = (sa && sa->runtime.tool) ? sa->runtime.tool->runtime : NULL;
- if (tref_rt && tref_rt->cursor != CURSOR_STD) {
+ if (tref_rt && tref_rt->cursor != WM_CURSOR_DEFAULT) {
if (win->modalcursor == 0) {
WM_cursor_set(win, tref_rt->cursor);
win->cursor = tref_rt->cursor;
@@ -210,7 +254,7 @@ void WM_cursor_wait(bool val)
for (; win; win = win->next) {
if (val) {
- WM_cursor_modal_set(win, BC_WAITCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_WAIT);
}
else {
WM_cursor_modal_restore(win);
@@ -407,15 +451,39 @@ void wm_init_cursor_data(void)
/********************** NW_ARROW Cursor **************************/
BEGIN_CURSOR_BLOCK;
static char nw_sbm[] = {
- 0x03, 0x00, 0x05, 0x00, 0x09, 0x00, 0x11, 0x00, 0x21, 0x00, 0x41,
- 0x00, 0x81, 0x00, 0x01, 0x01, 0x01, 0x02, 0xc1, 0x03, 0x49, 0x00,
- 0x8d, 0x00, 0x8b, 0x00, 0x10, 0x01, 0x90, 0x01, 0x60, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x1e, 0x00, 0x3e,
+ 0x00, 0x7e, 0x00, 0xfe, 0x00, 0xfe, 0x01, 0xfe, 0x03, 0xfe, 0x07,
+ 0x7e, 0x00, 0x6e, 0x00, 0xc6, 0x00, 0xc2, 0x00, 0x00, 0x00,
};
static char nw_smsk[] = {
0x03, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x3f, 0x00, 0x7f,
- 0x00, 0xff, 0x00, 0xff, 0x01, 0xff, 0x03, 0xff, 0x03, 0x7f, 0x00,
- 0xff, 0x00, 0xfb, 0x00, 0xf0, 0x01, 0xf0, 0x01, 0x60, 0x00,
+ 0x00, 0xff, 0x00, 0xff, 0x01, 0xff, 0x03, 0xff, 0x07, 0xff, 0x0f,
+ 0xff, 0x0f, 0xff, 0x00, 0xef, 0x01, 0xe7, 0x01, 0xc3, 0x00,
+ };
+
+ static char nw_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
+ 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00,
+ 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xfe,
+ 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00,
+ 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x07,
+ 0x00, 0xfe, 0xff, 0x0f, 0x00, 0xfe, 0xff, 0x1f, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xfe, 0x3f,
+ 0x00, 0x00, 0xfe, 0x3e, 0x00, 0x00, 0x7e, 0x7c, 0x00, 0x00, 0x3e, 0x7c, 0x00, 0x00, 0x1e,
+ 0xf8, 0x00, 0x00, 0x0e, 0xf8, 0x00, 0x00, 0x06, 0xf0, 0x01, 0x00, 0x02, 0xf0, 0x01, 0x00,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char nw_lmsk[] = {
+ 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00,
+ 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01,
+ 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff,
+ 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x0f,
+ 0x00, 0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0x3f, 0x00, 0xff, 0xff, 0x7f, 0x00, 0xff, 0x7f,
+ 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x3f,
+ 0xfc, 0x01, 0x00, 0x1f, 0xfc, 0x01, 0x00, 0x0f, 0xf8, 0x03, 0x00, 0x07, 0xf8, 0x03, 0x00,
+ 0x03, 0xf0, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00,
};
static BCursor NWArrowCursor = {
@@ -424,34 +492,60 @@ void wm_init_cursor_data(void)
nw_smsk,
16,
16,
- 6,
- 7,
+ 0,
+ 0,
/* big */
- NULL,
- NULL,
+ nw_lbm,
+ nw_lmsk,
32,
32,
- 15,
- 15,
+ 0,
+ 0,
/* can invert color */
true,
};
- BlenderCursor[BC_NW_ARROWCURSOR] = &NWArrowCursor;
+ BlenderCursor[WM_CURSOR_DEFAULT] = &NWArrowCursor;
+ BlenderCursor[WM_CURSOR_COPY] = &NWArrowCursor;
+ BlenderCursor[WM_CURSOR_NW_ARROW] = &NWArrowCursor;
END_CURSOR_BLOCK;
///********************** NS_ARROW Cursor *************************/
BEGIN_CURSOR_BLOCK;
static char ns_sbm[] = {
- 0x40, 0x01, 0x20, 0x02, 0x10, 0x04, 0x08, 0x08, 0x04, 0x10, 0x3c,
- 0x1e, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x3c, 0x1e,
- 0x04, 0x10, 0x08, 0x08, 0x10, 0x04, 0x20, 0x02, 0x40, 0x01,
+ 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0x80,
+ 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
+ 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00,
};
static char ns_smsk[] = {
- 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc, 0x1f, 0xfc,
- 0x1f, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xfc, 0x1f,
- 0xfc, 0x1f, 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01,
+ 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc,
+ 0x1f, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xfc, 0x1f,
+ 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00,
+ };
+
+ static char ns_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03,
+ 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff,
+ 0x3f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00,
+ 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0,
+ 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
+ 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char ns_lmsk[] = {
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xf8, 0x07,
+ 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff,
+ 0x7f, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x01, 0x00, 0xe0, 0x01, 0x00, 0x00,
+ 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00,
+ 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01,
+ 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0xe0, 0xff,
+ 0xff, 0x01, 0xc0, 0xff, 0xff, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00,
+ 0xfe, 0x1f, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00,
+ 0x00, 0xe0, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00,
};
static BCursor NSArrowCursor = {
@@ -460,11 +554,11 @@ void wm_init_cursor_data(void)
ns_smsk,
16,
16,
- 6,
+ 7,
7,
/* big */
- NULL,
- NULL,
+ ns_lbm,
+ ns_lmsk,
32,
32,
15,
@@ -473,21 +567,46 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_NS_ARROWCURSOR] = &NSArrowCursor;
+ BlenderCursor[WM_CURSOR_Y_MOVE] = &NSArrowCursor;
+ BlenderCursor[WM_CURSOR_NS_ARROW] = &NSArrowCursor;
END_CURSOR_BLOCK;
/********************** EW_ARROW Cursor *************************/
BEGIN_CURSOR_BLOCK;
static char ew_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x38, 0x1c, 0x2c, 0x34, 0xe6,
- 0x67, 0x03, 0xc0, 0x01, 0x80, 0x03, 0xc0, 0xe6, 0x67, 0x2c, 0x34,
- 0x38, 0x1c, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x18,
+ 0x18, 0x1c, 0x38, 0xfe, 0x7f, 0x1c, 0x38, 0x18, 0x18, 0x10, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char ew_smsk[] = {
- 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x38, 0x1c, 0x3c, 0x3c, 0xfe,
- 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0x3c, 0x3c,
- 0x38, 0x1c, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x20, 0x04, 0x30, 0x0c, 0x38, 0x1c, 0x3c,
+ 0x3c, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0x3c, 0x3c, 0x38, 0x1c,
+ 0x30, 0x0c, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char ew_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x80, 0x00, 0x80, 0x01, 0x80, 0x01, 0xc0, 0x01, 0x80, 0x03, 0xe0, 0x01, 0x80, 0x07, 0xf0,
+ 0x01, 0x80, 0x0f, 0xf8, 0x01, 0x80, 0x1f, 0xfc, 0x01, 0x80, 0x3f, 0xfe, 0xff, 0xff, 0x7f,
+ 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0x01, 0x80, 0x3f, 0xf8, 0x01, 0x80, 0x1f, 0xf0, 0x01, 0x80,
+ 0x0f, 0xe0, 0x01, 0x80, 0x07, 0xc0, 0x01, 0x80, 0x03, 0x80, 0x01, 0x80, 0x01, 0x00, 0x01,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char ew_lmsk[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x80, 0x03,
+ 0xc0, 0x01, 0xc0, 0x03, 0xc0, 0x03, 0xe0, 0x03, 0xc0, 0x07, 0xf0, 0x03, 0xc0, 0x0f, 0xf8,
+ 0x03, 0xc0, 0x1f, 0xfc, 0x03, 0xc0, 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0x03, 0xc0, 0x3f, 0xf8, 0x03, 0xc0,
+ 0x1f, 0xf0, 0x03, 0xc0, 0x0f, 0xe0, 0x03, 0xc0, 0x07, 0xc0, 0x03, 0xc0, 0x03, 0x80, 0x03,
+ 0xc0, 0x01, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static BCursor EWArrowCursor = {
@@ -497,10 +616,10 @@ void wm_init_cursor_data(void)
16,
16,
7,
- 6,
+ 7,
/* big */
- NULL,
- NULL,
+ ew_lbm,
+ ew_lmsk,
32,
32,
15,
@@ -509,45 +628,46 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_EW_ARROWCURSOR] = &EWArrowCursor;
+ BlenderCursor[WM_CURSOR_X_MOVE] = &EWArrowCursor;
+ BlenderCursor[WM_CURSOR_EW_ARROW] = &EWArrowCursor;
END_CURSOR_BLOCK;
/********************** Wait Cursor *****************************/
BEGIN_CURSOR_BLOCK;
static char wait_sbm[] = {
- 0xfe, 0x7f, 0x02, 0x40, 0x02, 0x40, 0x84, 0x21, 0xc8, 0x13, 0xd0,
- 0x0b, 0xa0, 0x04, 0x20, 0x05, 0xa0, 0x04, 0x10, 0x09, 0x88, 0x11,
- 0xc4, 0x23, 0xe2, 0x47, 0xfa, 0x5f, 0x02, 0x40, 0xfe, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0xf0, 0x07, 0xb0, 0x06, 0x60,
+ 0x03, 0xc0, 0x01, 0x80, 0x00, 0x80, 0x00, 0xc0, 0x01, 0x60, 0x03,
+ 0x30, 0x06, 0x10, 0x04, 0xf0, 0x07, 0x00, 0x00, 0x00, 0x00,
};
static char wait_smsk[] = {
- 0xfe, 0x7f, 0xfe, 0x7f, 0x06, 0x60, 0x8c, 0x31, 0xd8, 0x1b, 0xf0,
- 0x0f, 0xe0, 0x06, 0x60, 0x07, 0xe0, 0x06, 0x30, 0x0d, 0x98, 0x19,
- 0xcc, 0x33, 0xe6, 0x67, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f,
+ 0xfc, 0x1f, 0xfc, 0x1f, 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f, 0xf0,
+ 0x07, 0xe0, 0x03, 0xc0, 0x01, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07,
+ 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f, 0xfc, 0x1f, 0xfc, 0x1f,
};
static char wait_lbm[] = {
- 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0x0c, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00,
- 0x30, 0x0c, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00, 0x18, 0x18, 0xc0, 0x03, 0x0c, 0x30, 0x20,
- 0x07, 0x06, 0x60, 0xf0, 0x0f, 0x03, 0xc0, 0xd0, 0x8d, 0x01, 0x80, 0x79, 0xcf, 0x00, 0x00,
- 0xf3, 0x67, 0x00, 0x00, 0x66, 0x37, 0x00, 0x00, 0x8c, 0x33, 0x00, 0x00, 0x0c, 0x32, 0x00,
- 0x00, 0xcc, 0x33, 0x00, 0x00, 0x8c, 0x30, 0x00, 0x00, 0x46, 0x61, 0x00, 0x00, 0x03, 0xc3,
- 0x00, 0x80, 0x01, 0x83, 0x01, 0xc0, 0xc0, 0x03, 0x03, 0x60, 0xa0, 0x05, 0x06, 0x30, 0xf0,
- 0x0f, 0x0c, 0x18, 0xf8, 0x1d, 0x18, 0x0c, 0x5c, 0x3f, 0x30, 0x0c, 0xff, 0x5f, 0x30, 0x0c,
- 0xf7, 0xfe, 0x31, 0xcc, 0xfb, 0x9f, 0x33, 0x0c, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00, 0x30,
- 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f,
+ 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff,
+ 0x7f, 0x00, 0x80, 0x07, 0x78, 0x00, 0x00, 0x0f, 0x3c, 0x00, 0x00, 0x1e, 0x1e, 0x00, 0x00,
+ 0x3c, 0x0f, 0x00, 0x00, 0x38, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x30, 0x03,
+ 0x00, 0x00, 0x38, 0x07, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x3e, 0x1f, 0x00, 0x00, 0x1f,
+ 0x3e, 0x00, 0x80, 0x0f, 0x7c, 0x00, 0x80, 0x07, 0x78, 0x00, 0x80, 0x03, 0x70, 0x00, 0x80,
+ 0x01, 0x60, 0x00, 0x80, 0x01, 0x60, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char wait_lmsk[] = {
- 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff,
- 0x3f, 0x3c, 0x00, 0x00, 0x3c, 0x3c, 0x00, 0x00, 0x1e, 0x78, 0xc0, 0x03, 0x0f, 0xf0, 0xa0,
- 0x87, 0x07, 0xe0, 0xf1, 0xcf, 0x03, 0xc0, 0xf3, 0xef, 0x01, 0x80, 0xff, 0xff, 0x00, 0x00,
- 0xff, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0x3c, 0x3f, 0x00,
- 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xbc, 0x3c, 0x00, 0x00, 0xde, 0x79, 0x00, 0x00, 0x0f, 0xf3,
- 0x00, 0x80, 0x07, 0xe3, 0x01, 0xc0, 0xc3, 0xc3, 0x03, 0xe0, 0xe1, 0x87, 0x07, 0xf0, 0xf0,
- 0x0f, 0x0f, 0x78, 0xf8, 0x1f, 0x1e, 0x3c, 0x7c, 0x3f, 0x3c, 0x3c, 0xff, 0x7f, 0x3c, 0xbc,
- 0xff, 0xff, 0x3d, 0xfc, 0xfb, 0xbf, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
- 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
+ 0xf0, 0xff, 0xff, 0x03, 0xf0, 0xff, 0xff, 0x03, 0xf0, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xff,
+ 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff,
+ 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00,
+ 0xfe, 0x1f, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00,
+ 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xf8, 0x07,
+ 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff,
+ 0x7f, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0,
+ 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xf0, 0xff, 0xff, 0x03,
+ 0xf0, 0xff, 0xff, 0x03, 0xf0, 0xff, 0xff, 0x03,
};
static BCursor WaitCursor = {
@@ -565,25 +685,25 @@ void wm_init_cursor_data(void)
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_WAITCURSOR] = &WaitCursor;
+ BlenderCursor[WM_CURSOR_WAIT] = &WaitCursor;
END_CURSOR_BLOCK;
- /********************** Cross Cursor ***************************/
+ /****************** Normal Cross Cursor ************************/
BEGIN_CURSOR_BLOCK;
static char cross_sbm[] = {
- 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
- 0x01, 0x80, 0x01, 0x7e, 0x7e, 0x7e, 0x7e, 0x80, 0x01, 0x80, 0x01,
- 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x00, 0x00,
+ 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
+ 0x01, 0x00, 0x00, 0x3f, 0xfc, 0x3f, 0xfc, 0x00, 0x00, 0x80, 0x01,
+ 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
};
static char cross_smsk[] = {
- 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
- 0x01, 0xc0, 0x03, 0x7f, 0xfe, 0x7f, 0xfe, 0xc0, 0x03, 0x80, 0x01,
- 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
+ 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0,
+ 0x03, 0x7f, 0xfe, 0x3f, 0xfc, 0x3f, 0xfc, 0x7f, 0xfe, 0xc0, 0x03,
+ 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03,
};
static char cross_lbm[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
@@ -601,9 +721,9 @@ void wm_init_cursor_data(void)
0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
- 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x78, 0x1e, 0x00,
- 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x1f, 0xf8, 0xff, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x70, 0x0e,
- 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
+ 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
@@ -624,121 +744,227 @@ void wm_init_cursor_data(void)
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_CROSSCURSOR] = &CrossCursor;
+ BlenderCursor[WM_CURSOR_EDIT] = &CrossCursor;
+ BlenderCursor[WM_CURSOR_CROSS] = &CrossCursor;
END_CURSOR_BLOCK;
- /********************** EditCross Cursor ***********************/
+ /****************** Painting Cursor ************************/
BEGIN_CURSOR_BLOCK;
- static char editcross_sbm[] = {
- 0x0e, 0x00, 0x11, 0x00, 0x1d, 0x00, 0x19, 0x03, 0x1d, 0x03, 0x11,
- 0x03, 0x0e, 0x03, 0x00, 0x03, 0xf8, 0x7c, 0xf8, 0x7c, 0x00, 0x03,
- 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00,
+ static char paint_sbm[] = {
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x8f, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00,
+ };
+
+ static char paint_smsk[] = {
+ 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x8f, 0x78, 0xcf, 0x79, 0x8f, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0x00, 0x00,
+ };
+ static char paint_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
+ 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0x80, 0x01, 0x7f, 0xfe, 0x80, 0x01, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
};
- static char editcross_smsk[] = {
- 0x0e, 0x00, 0x1f, 0x00, 0x1f, 0x03, 0x1f, 0x03, 0x1f, 0x03, 0x1f,
- 0x03, 0x0e, 0x03, 0x80, 0x07, 0xfc, 0xfc, 0xfc, 0xfc, 0x80, 0x07,
- 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
+ static char paint_lmsk[] = {
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03,
+ 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0,
+ 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x01, 0x7f,
+ 0xff, 0xc1, 0x83, 0xff, 0xff, 0xc1, 0x83, 0xff, 0xfe, 0x80, 0x01, 0x7f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00,
+ 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00,
+ 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00,
};
- static BCursor EditCrossCursor = {
+ static BCursor PaintCursor = {
/* small */
- editcross_sbm,
- editcross_smsk,
+ paint_sbm,
+ paint_smsk,
16,
16,
- 9,
- 8,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ paint_lbm,
+ paint_lmsk,
32,
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_EDITCROSSCURSOR] = &EditCrossCursor;
+ BlenderCursor[WM_CURSOR_PAINT] = &PaintCursor;
END_CURSOR_BLOCK;
- /********************** Box Select *************************/
+ /********************** Dot Cursor ***********************/
BEGIN_CURSOR_BLOCK;
- static char box_sbm[32] = {
- 0x7f, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x06, 0x41, 0x06, 0x41,
- 0x06, 0x7f, 0x06, 0x00, 0x06, 0xe0, 0x79, 0xe0, 0x79, 0x00, 0x06,
- 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00,
+ static char dot_sbm[] = {
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x8f, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00,
};
- static char box_smsk[32] = {
- 0x7f, 0x00, 0x7f, 0x00, 0x63, 0x06, 0x63, 0x06, 0x63, 0x06, 0x7f,
- 0x06, 0x7f, 0x06, 0x00, 0x0f, 0xf0, 0xf9, 0xf0, 0xf9, 0x00, 0x0f,
- 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06,
+ static char dot_smsk[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ static char dot_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
- static BCursor BoxSelCursor = {
+ static char dot_lmsk[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00,
+ 0x00, 0xe0, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static BCursor DotCursor = {
/* small */
- box_sbm,
- box_smsk,
+ dot_sbm,
+ dot_smsk,
16,
16,
- 9,
- 8,
+ 7,
+ 7,
+ /* big */
+ dot_lbm,
+ dot_lmsk,
+ 32,
+ 32,
+ 14,
+ 14,
+ /* don't invert color */
+ false,
+ };
+
+ BlenderCursor[WM_CURSOR_DOT] = &DotCursor;
+ END_CURSOR_BLOCK;
+
+ /************* Minimal Crosshair Cursor ***************/
+ BEGIN_CURSOR_BLOCK;
+ static char crossc_sbm[] = {
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0x55, 0x55, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ };
+
+ static char crossc_smsk[] = {
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+ 0x00, 0x80, 0x00, 0x7f, 0x7f, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00,
+ };
+ static char crossc_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char crossc_lmsk[] = {
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
+ 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
+ 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+ 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x78, 0x1e, 0x00,
+ 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x1f, 0xf8, 0xff, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x70, 0x0e,
+ 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
+ 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ };
+
+ static BCursor CrossCursorC = {
+ /* small */
+ crossc_sbm,
+ crossc_smsk,
+ 16,
+ 16,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ crossc_lbm,
+ crossc_lmsk,
32,
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_BOXSELCURSOR] = &BoxSelCursor;
-
+ BlenderCursor[WM_CURSOR_CROSSC] = &CrossCursorC;
END_CURSOR_BLOCK;
+
/********************** Knife Cursor ***********************/
BEGIN_CURSOR_BLOCK;
static char knife_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x2c, 0x00, 0x5a, 0x00,
- 0x34, 0x00, 0x2a, 0x00, 0x17, 0x80, 0x06, 0x40, 0x03, 0xa0, 0x03,
- 0xd0, 0x01, 0x68, 0x00, 0x1c, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00,
+ 0x0c, 0x00, 0x06, 0x00, 0x0f, 0x80, 0x07, 0xc0, 0x03, 0xe0, 0x01,
+ 0xf0, 0x00, 0x78, 0x00, 0x3c, 0x00, 0x0e, 0x00, 0x00, 0x00,
};
static char knife_smsk[] = {
- 0x00, 0x60, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0xfe, 0x00, 0xfe, 0x00,
- 0x7e, 0x00, 0x7f, 0x80, 0x3f, 0xc0, 0x0e, 0x60, 0x07, 0xb0, 0x07,
- 0xd8, 0x03, 0xec, 0x01, 0x7e, 0x00, 0x1f, 0x00, 0x07, 0x00,
+ 0x00, 0x40, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0x78, 0x00, 0x3c, 0x00,
+ 0x1e, 0x00, 0x0f, 0x80, 0x1f, 0xc0, 0x0f, 0xe0, 0x07, 0xf0, 0x03,
+ 0xf8, 0x01, 0xfc, 0x00, 0x7e, 0x00, 0x3f, 0x00, 0x0f, 0x00,
};
static char knife_lbm[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00,
- 0x00, 0x7f, 0x00, 0x00, 0x80, 0xbf, 0x00, 0x00, 0xc0, 0x5f, 0x00, 0x00, 0xc0, 0x6f, 0x00,
- 0x00, 0xc0, 0x37, 0x00, 0x00, 0xa8, 0x1b, 0x00, 0x00, 0x54, 0x0d, 0x00, 0x00, 0xa8, 0x00,
- 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0xc0, 0x07,
- 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xd0, 0x0f, 0x00, 0x00, 0xe8, 0x07, 0x00, 0x00, 0xf4,
- 0x07, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x80, 0x0e, 0x00, 0x00, 0xc0,
- 0x03, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
+ 0x00, 0x07, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x00, 0x00,
+ 0x00, 0x70, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xfe, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0xe0, 0x1f,
+ 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xfe,
+ 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0xe0,
+ 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char knife_lmsk[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
- 0x80, 0xff, 0x00, 0x00, 0xc0, 0xbf, 0x00, 0x00, 0xe0, 0xdf, 0x00, 0x00, 0xe0, 0xef, 0x00,
- 0x00, 0xf8, 0x77, 0x00, 0x00, 0xfc, 0x3b, 0x00, 0x00, 0xfe, 0x1d, 0x00, 0x00, 0xfe, 0x0f,
- 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0xc0, 0xff, 0x00, 0x00, 0xe0, 0x7f,
- 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xd8, 0x1f, 0x00, 0x00, 0xec, 0x0f, 0x00, 0x00, 0xf6,
- 0x0f, 0x00, 0x00, 0xfb, 0x06, 0x00, 0x80, 0xbd, 0x01, 0x00, 0xc0, 0x6e, 0x00, 0x00, 0xe0,
- 0x1b, 0x00, 0x00, 0xf0, 0x06, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
- 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
+ 0x7c, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
+ 0xc0, 0x1f, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xf8, 0x03, 0x00,
+ 0x00, 0xfc, 0x01, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x80, 0xff, 0x01,
+ 0x00, 0xc0, 0xff, 0x03, 0x00, 0xe0, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf8, 0x7f,
+ 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x80, 0xff,
+ 0x07, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xe0, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf8,
+ 0x7f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x03, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
};
static BCursor KnifeCursor = {
@@ -756,11 +982,11 @@ void wm_init_cursor_data(void)
32,
0,
31,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_KNIFECURSOR] = &KnifeCursor;
+ BlenderCursor[WM_CURSOR_KNIFE] = &KnifeCursor;
END_CURSOR_BLOCK;
@@ -768,9 +994,9 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char vloop_sbm[] = {
- 0x00, 0x00, 0x7e, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x66,
- 0x60, 0x62, 0x6f, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x00, 0x00, 0x60, 0x60, 0x60, 0x6f, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0xfe, 0xf0, 0x96,
+ 0x9f, 0x92, 0x90, 0xf0, 0xf0, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40,
+ 0x20, 0x40, 0xf0, 0xf0, 0x90, 0x90, 0x90, 0x9f, 0xf0, 0xf0,
};
static char vloop_smsk[] = {
@@ -780,27 +1006,27 @@ void wm_init_cursor_data(void)
};
static char vloop_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfc, 0x3f, 0x00,
- 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xfc, 0x03,
- 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x3c, 0x3c, 0x00, 0x3c, 0x3c,
- 0x3c, 0x00, 0x3c, 0x0c, 0x3c, 0xff, 0x3c, 0x0c, 0x3c, 0xff, 0x3c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00,
- 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c,
- 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0xff, 0x3c, 0x00, 0x3c, 0xff, 0x3c,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00,
+ 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xfe, 0x01,
+ 0x00, 0x00, 0xfe, 0x7e, 0x00, 0x7e, 0x7e, 0xff, 0x00, 0xff, 0x3e, 0xc3, 0x00, 0xc3, 0x1e,
+ 0xc3, 0xff, 0xc3, 0x0e, 0xc3, 0xff, 0xc3, 0x06, 0xc3, 0x00, 0xc3, 0x02, 0xff, 0x00, 0xff,
+ 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00,
+ 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18,
+ 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0xc3, 0x00, 0xc3, 0x00, 0xc3, 0xff, 0xc3, 0x00, 0xc3, 0xff, 0xc3, 0x00, 0xc3, 0x00, 0xc3,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x7e, 0x00, 0x7e,
};
static char vloop_lmsk[] = {
- 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
- 0x00, 0xff, 0x3f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f,
- 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0x00, 0xff,
- 0x0f, 0xff, 0x00, 0xff, 0x03, 0x3c, 0x00, 0x3c, 0x03, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00,
- 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c,
- 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
- 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
- 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+ 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x7f, 0x00,
+ 0x00, 0xff, 0x3f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x07,
+ 0x00, 0x00, 0xff, 0x7f, 0x00, 0x7e, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x7f,
+ 0xe7, 0xff, 0xe7, 0x3f, 0xe7, 0xff, 0xe7, 0x1f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0x00, 0xff,
+ 0x07, 0x7e, 0x00, 0x7e, 0x03, 0x38, 0x00, 0x38, 0x01, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00,
+ 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38,
+ 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0xe7, 0xff, 0xe7, 0x00, 0xe7, 0xff, 0xe7, 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x7e, 0x00, 0x7e,
};
static BCursor VLoopCursor = {
@@ -818,26 +1044,50 @@ void wm_init_cursor_data(void)
32,
0,
0,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_VLOOPCURSOR] = &VLoopCursor;
+ BlenderCursor[WM_CURSOR_VERTEX_LOOP] = &VLoopCursor;
END_CURSOR_BLOCK;
/********************** TextEdit Cursor ***********************/
BEGIN_CURSOR_BLOCK;
static char textedit_sbm[] = {
- 0xe0, 0x03, 0x10, 0x04, 0x60, 0x03, 0x40, 0x01, 0x40, 0x01, 0x40,
- 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01,
- 0x40, 0x01, 0x40, 0x01, 0x60, 0x03, 0x10, 0x04, 0xe0, 0x03,
+ 0x00, 0x00, 0x70, 0x07, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+ 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x70, 0x07, 0x00, 0x00,
};
static char textedit_smsk[] = {
- 0xe0, 0x03, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0xc0, 0x01, 0xc0,
+ 0x70, 0x07, 0xf8, 0x0f, 0xf0, 0x07, 0xc0, 0x01, 0xc0, 0x01, 0xc0,
0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01,
- 0xc0, 0x01, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xe0, 0x03,
+ 0xc0, 0x01, 0xc0, 0x01, 0xf0, 0x07, 0xf8, 0x0f, 0x70, 0x07,
+ };
+
+ static char textedit_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xe0, 0x01,
+ 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0,
+ 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00,
+ 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0,
+ 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xff, 0x3f, 0x00,
+ 0x00, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char textedit_lmsk[] = {
+ 0x00, 0x3f, 0x3f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f,
+ 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0,
+ 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00,
+ 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00,
+ 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01,
+ 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0,
+ 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00,
+ 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff, 0x7f, 0x00,
+ 0x80, 0xff, 0x7f, 0x00, 0x00, 0x3f, 0x3f, 0x00,
};
static BCursor TextEditCursor = {
@@ -846,35 +1096,58 @@ void wm_init_cursor_data(void)
textedit_smsk,
16,
16,
- 9,
- 8,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ textedit_lbm,
+ textedit_lmsk,
32,
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_TEXTEDITCURSOR] = &TextEditCursor;
+ BlenderCursor[WM_CURSOR_TEXT_EDIT] = &TextEditCursor;
END_CURSOR_BLOCK;
/********************** Paintbrush Cursor ***********************/
BEGIN_CURSOR_BLOCK;
static char paintbrush_sbm[] = {
-
- 0x00, 0xe0, 0x00, 0x98, 0x00, 0x44, 0x00, 0x42, 0x00, 0x21, 0x80,
- 0x20, 0x40, 0x13, 0x40, 0x17, 0xa0, 0x0b, 0x98, 0x05, 0x04, 0x02,
- 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x81, 0x00, 0x7f, 0x00,
+ 0x00, 0x00, 0x00, 0x30, 0x00, 0x78, 0x00, 0x74, 0x00, 0x2e, 0x00,
+ 0x1f, 0x80, 0x0f, 0xc0, 0x07, 0xe0, 0x03, 0xf0, 0x01, 0xf8, 0x00,
+ 0x7c, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x00, 0x00,
};
static char paintbrush_smsk[] = {
- 0x00, 0xe0, 0x00, 0xf8, 0x00, 0x7c, 0x00, 0x7e, 0x00, 0x3f, 0x80,
- 0x3f, 0xc0, 0x1f, 0xc0, 0x1f, 0xe0, 0x0f, 0xf8, 0x07, 0xfc, 0x03,
- 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xff, 0x00, 0x7f, 0x00,
+ 0x00, 0x30, 0x00, 0x78, 0x00, 0xfc, 0x00, 0xfe, 0x00, 0x7f, 0x80,
+ 0x3f, 0xc0, 0x1f, 0xe0, 0x0f, 0xf0, 0x07, 0xf8, 0x03, 0xfc, 0x01,
+ 0xfe, 0x00, 0x7f, 0x00, 0x3f, 0x00, 0x1f, 0x00, 0x0f, 0x00,
+ };
+
+ static char paintbrush_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x0f, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
+ 0x10, 0x1f, 0x00, 0x00, 0x38, 0x0e, 0x00, 0x00, 0x7c, 0x04, 0x00, 0x00, 0xfe, 0x00, 0x00,
+ 0x00, 0xff, 0x01, 0x00, 0x80, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f, 0x00,
+ 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe, 0x03,
+ 0x00, 0x00, 0xff, 0x01, 0x00, 0x80, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f,
+ 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe,
+ 0x03, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char paintbrush_lmsk[] = {
+ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0xc0,
+ 0x3f, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00,
+ 0xfc, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x80, 0xff, 0x0f, 0x00,
+ 0xc0, 0xff, 0x07, 0x00, 0xe0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x00,
+ 0x00, 0xfc, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x80, 0xff, 0x0f,
+ 0x00, 0xc0, 0xff, 0x07, 0x00, 0xe0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf8, 0xff,
+ 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0xff,
+ 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
};
static BCursor PaintBrushCursor = {
@@ -886,32 +1159,116 @@ void wm_init_cursor_data(void)
0,
15,
/* big */
- NULL,
- NULL,
+ paintbrush_lbm,
+ paintbrush_lmsk,
32,
32,
- 15,
- 15,
- /* can invert color */
- true,
+ 0,
+ 31,
+ /* don't invert color */
+ false,
+ };
+
+ BlenderCursor[WM_CURSOR_PAINT_BRUSH] = &PaintBrushCursor;
+ END_CURSOR_BLOCK;
+
+ /********************** Eraser Cursor ***********************/
+ BEGIN_CURSOR_BLOCK;
+ static char eraser_sbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc, 0x07,
+ 0xfe, 0x03, 0xfe, 0x01, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char eraser_smsk[] = {
+ 0x00, 0x00, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x1f, 0x80, 0x3f, 0xc0,
+ 0x7f, 0xe0, 0xff, 0xf0, 0x7f, 0xf8, 0x3f, 0xfc, 0x1f, 0xfe, 0x0f,
+ 0xff, 0x07, 0xff, 0x03, 0xff, 0x01, 0xff, 0x00, 0x00, 0x00,
+ };
+
+ static char eraser_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x78,
+ 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x86, 0x01, 0x00, 0x00, 0x03, 0x03, 0x00, 0x80,
+ 0x01, 0x06, 0x00, 0xc0, 0x00, 0x0c, 0x00, 0x60, 0x00, 0x18, 0x00, 0x30, 0x00, 0x30, 0x00,
+ 0x18, 0x00, 0x60, 0x00, 0x4c, 0x00, 0xc0, 0x00, 0xe6, 0x00, 0xc0, 0x00, 0xf3, 0x01, 0x60,
+ 0x80, 0xf9, 0x03, 0x30, 0xc0, 0xfc, 0x07, 0x18, 0x60, 0xfe, 0x0f, 0x0c, 0x30, 0xff, 0x1f,
+ 0x06, 0x98, 0xff, 0x3f, 0x03, 0xcc, 0xff, 0x9f, 0x01, 0xe6, 0xff, 0xcf, 0x00, 0xf3, 0xff,
+ 0x67, 0x00, 0xf9, 0xff, 0x33, 0x00, 0xfd, 0xff, 0x19, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfd,
+ 0x7f, 0x06, 0x00, 0xfd, 0x3f, 0x03, 0x00, 0x01, 0x80, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char eraser_lmsk[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x78,
+ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x80,
+ 0xff, 0x07, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0x1f, 0x00, 0xf0, 0xff, 0x3f, 0x00,
+ 0xf8, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0xff, 0x00, 0xfe, 0xff, 0xff, 0x00, 0xff, 0xff, 0x7f,
+ 0x80, 0xff, 0xff, 0x3f, 0xc0, 0xff, 0xff, 0x1f, 0xe0, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0xff,
+ 0x07, 0xf8, 0xff, 0xff, 0x03, 0xfc, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0x00, 0xff, 0xff,
+ 0x7f, 0x00, 0xff, 0xff, 0x3f, 0x00, 0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0x0f, 0x00, 0xff,
+ 0xff, 0x07, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static BCursor EraserCursor = {
+ /* small */
+ eraser_sbm,
+ eraser_smsk,
+ 16,
+ 16,
+ 0,
+ 14,
+ /* big */
+ eraser_lbm,
+ eraser_lmsk,
+ 32,
+ 32,
+ 0,
+ 28,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_PAINTBRUSHCURSOR] = &PaintBrushCursor;
+ BlenderCursor[WM_CURSOR_ERASER] = &EraserCursor;
END_CURSOR_BLOCK;
/********************** Hand Cursor ***********************/
BEGIN_CURSOR_BLOCK;
static char hand_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x80, 0x0d, 0x98, 0x6d, 0x98,
- 0x6d, 0xb0, 0x6d, 0xb0, 0x6d, 0xe0, 0x6f, 0xe6, 0x7f, 0xee, 0x7f,
- 0xfc, 0x3f, 0xf8, 0x3f, 0xf0, 0x1f, 0xc0, 0x1f, 0xc0, 0x1f,
+ 0x00, 0x00, 0x80, 0x01, 0x80, 0x0d, 0x98, 0x6d, 0xb8, 0x6d, 0xb0,
+ 0x6d, 0xb0, 0x6d, 0xe0, 0x6f, 0xe6, 0x7f, 0xee, 0x7f, 0x7c, 0x35,
+ 0x78, 0x35, 0x70, 0x15, 0x60, 0x15, 0xc0, 0x1f, 0xc0, 0x1f,
};
static char hand_smsk[] = {
- 0x00, 0x00, 0x80, 0x01, 0xc0, 0x0f, 0xd8, 0x7f, 0xfc, 0xff, 0xfc,
- 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xfe, 0x7f, 0xfc, 0x7f, 0xf8, 0x3f, 0xf0, 0x3f, 0xe0, 0x3f,
+ 0x80, 0x01, 0xc0, 0x0f, 0xd8, 0x7f, 0xfc, 0xff, 0xfc, 0xff, 0xf8,
+ 0xff, 0xf8, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f,
+ 0xfc, 0x7f, 0xf8, 0x3f, 0xf0, 0x3f, 0xe0, 0x3f, 0xe0, 0x3f,
+ };
+
+ static char hand_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x30, 0x0f,
+ 0x00, 0x00, 0x78, 0xcf, 0x00, 0x00, 0x78, 0xef, 0x01, 0x00, 0x78, 0xef, 0x01, 0x00, 0x78,
+ 0xef, 0x01, 0x00, 0x78, 0xef, 0x1d, 0x00, 0x78, 0xef, 0x3d, 0x00, 0x78, 0xef, 0x3d, 0x00,
+ 0x78, 0xef, 0x3d, 0x00, 0x78, 0xef, 0x3d, 0x00, 0x78, 0xef, 0x3d, 0x70, 0x78, 0xef, 0x3d,
+ 0xf0, 0x78, 0xef, 0x3d, 0xf0, 0xf8, 0xff, 0x3d, 0xf0, 0xf8, 0xff, 0x3d, 0xf0, 0xf8, 0xff,
+ 0x3f, 0xf0, 0xb9, 0xf7, 0x3f, 0xe0, 0xbb, 0xf7, 0x3f, 0xe0, 0xbf, 0xf7, 0x3e, 0xe0, 0xbf,
+ 0xf7, 0x3e, 0xc0, 0xbf, 0xf7, 0x3e, 0x80, 0xbf, 0xf7, 0x3e, 0x80, 0xbf, 0xf7, 0x3e, 0x00,
+ 0xbf, 0xf7, 0x1e, 0x00, 0xbe, 0xf7, 0x1e, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x0f,
+ 0x00, 0xf8, 0xff, 0x07, 0x00, 0xf8, 0xff, 0x07,
+ };
+
+ static char hand_lmsk[] = {
+ 0x00, 0x00, 0x0f, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc, 0xff,
+ 0x01, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc,
+ 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x7f, 0x00,
+ 0xfc, 0xff, 0x7f, 0x60, 0xfc, 0xff, 0x7f, 0xf8, 0xfc, 0xff, 0x7f, 0xf8, 0xfd, 0xff, 0x7f,
+ 0xfc, 0xfd, 0xff, 0x7f, 0xfc, 0xfd, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x7f, 0xf8, 0xff, 0xff,
+ 0x7f, 0xf8, 0xff, 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x7f, 0xf0, 0xff,
+ 0xff, 0x7f, 0xe0, 0xff, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0x7f, 0xc0, 0xff, 0xff, 0x7f, 0x80,
+ 0xff, 0xff, 0x7f, 0x80, 0xff, 0xff, 0x3f, 0x00, 0xff, 0xff, 0x3f, 0x00, 0xfe, 0xff, 0x1f,
+ 0x00, 0xfe, 0xff, 0x1f, 0x00, 0xfc, 0xff, 0x1f,
};
static BCursor HandCursor = {
@@ -923,17 +1280,17 @@ void wm_init_cursor_data(void)
8,
8,
/* big */
- NULL,
- NULL,
+ hand_lbm,
+ hand_lmsk,
32,
32,
- 15,
- 15,
- /* can invert color */
- true,
+ 17,
+ 17,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_HANDCURSOR] = &HandCursor;
+ BlenderCursor[WM_CURSOR_HAND] = &HandCursor;
END_CURSOR_BLOCK;
@@ -941,15 +1298,39 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char nsewscroll_sbm[] = {
- 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xc0, 0x03, 0x00, 0x00, 0x00,
- 0x00, 0x0c, 0x30, 0x0e, 0x70, 0x0e, 0x70, 0x0c, 0x30, 0x00, 0x00,
- 0x00, 0x00, 0xc0, 0x03, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0x40, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x30, 0x06, 0x60, 0x06, 0x60, 0x0c, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x02, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00,
};
static char nsewscroll_smsk[] = {
- 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x0c,
- 0x30, 0x1e, 0x78, 0x1f, 0xf8, 0x1f, 0xf8, 0x1e, 0x78, 0x0c, 0x30,
- 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01,
+ 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0x40, 0x02, 0x0c,
+ 0x30, 0x1e, 0x78, 0x0f, 0xf0, 0x0f, 0xf8, 0x1e, 0x78, 0x0c, 0x30,
+ 0x40, 0x02, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01,
+ };
+
+ static char nsewscroll_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07,
+ 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0x38,
+ 0x1c, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x02, 0xe0,
+ 0x00, 0x00, 0x07, 0xf0, 0x01, 0x80, 0x0f, 0xf8, 0x00, 0x00, 0x1f, 0x7c, 0x00, 0x00, 0x3e,
+ 0x3e, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x3e, 0xf8, 0x00, 0x00,
+ 0x1f, 0xf0, 0x01, 0x80, 0x0f, 0xe0, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00,
+ 0xf8, 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xc0, 0x03, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char nsewscroll_lmsk[] = {
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xf0, 0x0f,
+ 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x7c,
+ 0x3e, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x40, 0x10, 0x08, 0x02, 0xe0, 0x00, 0x00, 0x07, 0xf0,
+ 0x01, 0x80, 0x0f, 0xf8, 0x03, 0xc0, 0x1f, 0xfc, 0x01, 0x80, 0x3f, 0xfe, 0x00, 0x00, 0x7f,
+ 0x7f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0x7f, 0xfc, 0x01, 0x80,
+ 0x3f, 0xf8, 0x03, 0xc0, 0x1f, 0xf0, 0x01, 0x80, 0x0f, 0xe0, 0x00, 0x00, 0x07, 0x40, 0x10,
+ 0x08, 0x02, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00,
+ 0xfc, 0x3f, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xe0, 0x07, 0x00,
+ 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00,
};
static BCursor NSEWScrollCursor = {
@@ -958,11 +1339,11 @@ void wm_init_cursor_data(void)
nsewscroll_smsk,
16,
16,
- 8,
- 8,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ nsewscroll_lbm,
+ nsewscroll_lmsk,
32,
32,
15,
@@ -971,7 +1352,7 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_NSEW_SCROLLCURSOR] = &NSEWScrollCursor;
+ BlenderCursor[WM_CURSOR_NSEW_SCROLL] = &NSEWScrollCursor;
END_CURSOR_BLOCK;
@@ -979,15 +1360,39 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char nsscroll_sbm[] = {
- 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xc0, 0x03, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xc0, 0x03, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0x70, 0x07, 0x20,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02,
+ 0x70, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00,
};
static char nsscroll_smsk[] = {
- 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01,
+ 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0x70,
+ 0x07, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x70, 0x07,
+ 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00,
+ };
+
+ static char nsscroll_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03,
+ 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff,
+ 0x3f, 0x00, 0x00, 0x3e, 0x1f, 0x00, 0x00, 0x1c, 0x0e, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x1c,
+ 0x0e, 0x00, 0x00, 0x3e, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
+ 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char nsscroll_lmsk[] = {
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xf8, 0x07,
+ 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff,
+ 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x3e, 0x1f, 0x00, 0x00, 0x1c, 0x0e, 0x00, 0x00,
+ 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x1c, 0x0e, 0x00, 0x00, 0x3e,
+ 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00,
+ 0xfe, 0x1f, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00,
+ 0x00, 0xe0, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00,
};
static BCursor NSScrollCursor = {
@@ -996,11 +1401,11 @@ void wm_init_cursor_data(void)
nsscroll_smsk,
16,
16,
- 8,
- 8,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ nsscroll_lbm,
+ nsscroll_lmsk,
32,
32,
15,
@@ -1009,7 +1414,7 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_NS_SCROLLCURSOR] = &NSScrollCursor;
+ BlenderCursor[WM_CURSOR_NS_SCROLL] = &NSScrollCursor;
END_CURSOR_BLOCK;
@@ -1017,15 +1422,39 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char ewscroll_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x0c, 0x30, 0x0e, 0x70, 0x0e, 0x70, 0x0c, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x38,
+ 0x1c, 0x1c, 0x38, 0x0e, 0x70, 0x1c, 0x38, 0x38, 0x1c, 0x10, 0x08,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char ewscroll_smsk[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c,
- 0x30, 0x1e, 0x78, 0x1f, 0xf8, 0x1f, 0xf8, 0x1e, 0x78, 0x0c, 0x30,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x38, 0x1c, 0x7c,
+ 0x3e, 0x3e, 0x7c, 0x1f, 0xf8, 0x3e, 0x7c, 0x7c, 0x3e, 0x38, 0x1c,
+ 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char ewscroll_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0xc0, 0x01, 0x80, 0x03, 0xe0, 0x03, 0xc0, 0x07, 0xf0,
+ 0x07, 0xe0, 0x0f, 0xf8, 0x03, 0xc0, 0x1f, 0xfc, 0x01, 0x80, 0x3f, 0xfe, 0x00, 0x00, 0x7f,
+ 0xfe, 0x00, 0x00, 0x7f, 0xfc, 0x01, 0x80, 0x3f, 0xf8, 0x03, 0xc0, 0x1f, 0xf0, 0x07, 0xe0,
+ 0x0f, 0xe0, 0x03, 0xc0, 0x07, 0xc0, 0x01, 0x80, 0x03, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char ewscroll_lmsk[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
+ 0x00, 0x01, 0xc0, 0x01, 0x80, 0x03, 0xe0, 0x03, 0xc0, 0x07, 0xf0, 0x07, 0xe0, 0x0f, 0xf8,
+ 0x0f, 0xf0, 0x1f, 0xfc, 0x07, 0xe0, 0x3f, 0xfe, 0x03, 0xc0, 0x7f, 0xff, 0x01, 0x80, 0xff,
+ 0xff, 0x01, 0x80, 0xff, 0xfe, 0x03, 0xc0, 0x7f, 0xfc, 0x07, 0xe0, 0x3f, 0xf8, 0x0f, 0xf0,
+ 0x1f, 0xf0, 0x07, 0xe0, 0x0f, 0xe0, 0x03, 0xc0, 0x07, 0xc0, 0x01, 0x80, 0x03, 0x80, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static BCursor EWScrollCursor = {
@@ -1034,11 +1463,11 @@ void wm_init_cursor_data(void)
ewscroll_smsk,
16,
16,
- 8,
- 8,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ ewscroll_lbm,
+ ewscroll_lmsk,
32,
32,
15,
@@ -1047,7 +1476,7 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_EW_SCROLLCURSOR] = &EWScrollCursor;
+ BlenderCursor[WM_CURSOR_EW_SCROLL] = &EWScrollCursor;
END_CURSOR_BLOCK;
@@ -1055,15 +1484,39 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char eyedropper_sbm[] = {
- 0x00, 0x30, 0x00, 0x48, 0x00, 0x85, 0x80, 0x82, 0x40, 0x40, 0x80,
- 0x20, 0x40, 0x11, 0xa0, 0x23, 0xd0, 0x15, 0xe8, 0x0a, 0x74, 0x01,
- 0xb4, 0x00, 0x4a, 0x00, 0x35, 0x00, 0x08, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x60, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x17, 0x00,
+ 0x0e, 0x00, 0x1d, 0x80, 0x0b, 0xc0, 0x01, 0xe0, 0x00, 0x70, 0x00,
+ 0x38, 0x00, 0x1c, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x00, 0x00,
};
static char eyedropper_smsk[] = {
- 0x00, 0x30, 0x00, 0x78, 0x00, 0xfd, 0x80, 0xff, 0xc0, 0x7f, 0x80,
- 0x3f, 0xc0, 0x1f, 0xe0, 0x3f, 0xf0, 0x1f, 0xf8, 0x0b, 0xfc, 0x01,
- 0xfc, 0x00, 0x7e, 0x00, 0x3f, 0x00, 0x0c, 0x00, 0x04, 0x00,
+ 0x00, 0x60, 0x00, 0xf0, 0x00, 0xfa, 0x00, 0x7f, 0x80, 0x3f, 0x00,
+ 0x1f, 0x80, 0x3f, 0xc0, 0x1f, 0xe0, 0x0b, 0xf0, 0x01, 0xf8, 0x00,
+ 0x7c, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0x0f, 0x00, 0x03, 0x00,
+ };
+
+ static char eyedropper_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x7f, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe4, 0x3f, 0x00, 0x00,
+ 0xee, 0x1f, 0x00, 0x00, 0xdf, 0x0f, 0x00, 0x00, 0xbf, 0x07, 0x00, 0x00, 0x7e, 0x03, 0x00,
+ 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfb, 0x01, 0x00, 0x80, 0xf7, 0x03, 0x00, 0xc0, 0xef, 0x01,
+ 0x00, 0xe0, 0xcf, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xb8, 0x03, 0x00, 0x00, 0xdc, 0x01,
+ 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x80, 0x3b, 0x00, 0x00, 0xc0, 0x1d,
+ 0x00, 0x00, 0xe0, 0x0e, 0x00, 0x00, 0x70, 0x07, 0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, 0xf8,
+ 0x01, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char eyedropper_lmsk[] = {
+ 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x80,
+ 0xff, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0xe4, 0xff, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00,
+ 0xff, 0x3f, 0x00, 0x80, 0xff, 0x1f, 0x00, 0x80, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00,
+ 0x00, 0xff, 0x03, 0x00, 0x80, 0xff, 0x03, 0x00, 0xc0, 0xff, 0x07, 0x00, 0xe0, 0xff, 0x03,
+ 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf8, 0xcf, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe, 0x03,
+ 0x00, 0x00, 0xff, 0x01, 0x00, 0x80, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f,
+ 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfc,
+ 0x03, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
};
static BCursor EyedropperCursor = {
@@ -1072,108 +1525,134 @@ void wm_init_cursor_data(void)
eyedropper_smsk,
16,
16,
- 1,
+ 0,
15,
/* big */
- NULL,
- NULL,
+ eyedropper_lbm,
+ eyedropper_lmsk,
32,
32,
- 15,
- 15,
- /* can invert color */
- true,
+ 1,
+ 30,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_EYEDROPPER_CURSOR] = &EyedropperCursor;
+ BlenderCursor[WM_CURSOR_EYEDROPPER] = &EyedropperCursor;
END_CURSOR_BLOCK;
/********************** Swap Area Cursor ***********************/
BEGIN_CURSOR_BLOCK;
static char swap_sbm[] = {
- 0xc0, 0xff, 0x40, 0x80, 0x40, 0x80, 0x40, 0x9c, 0x40, 0x98, 0x40,
- 0x94, 0x00, 0x82, 0xfe, 0x80, 0x7e, 0xfd, 0xbe, 0x01, 0xda, 0x01,
+ 0xc0, 0xff, 0x40, 0x80, 0x40, 0xbc, 0x40, 0xb8, 0x40, 0xb8, 0x40,
+ 0xa4, 0x00, 0x82, 0xfe, 0x81, 0x7e, 0x81, 0xbe, 0xfd, 0xda, 0x01,
0xe2, 0x01, 0xe2, 0x01, 0xc2, 0x01, 0xfe, 0x01, 0x00, 0x00,
};
static char swap_smsk[] = {
0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0x03,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03,
};
+ static char swap_lbm[] = {
+ 0x00, 0xe0, 0xff, 0xff, 0x00, 0x20, 0x00, 0x80, 0x00, 0x20, 0x00, 0x80, 0x00, 0x20, 0xf8,
+ 0x9f, 0x00, 0x20, 0xf0, 0x9f, 0x00, 0x20, 0xe0, 0x9f, 0x00, 0x20, 0xc0, 0x9f, 0x00, 0x20,
+ 0x80, 0x9f, 0x00, 0x20, 0xc0, 0x9f, 0x00, 0x20, 0xe0, 0x9e, 0x00, 0x20, 0x70, 0x9c, 0x00,
+ 0x20, 0x38, 0x98, 0x00, 0x20, 0x1c, 0x90, 0x00, 0x00, 0x0e, 0x80, 0xfe, 0xff, 0x07, 0x80,
+ 0xfe, 0x7f, 0x03, 0x80, 0xfe, 0x3f, 0x02, 0x80, 0xfe, 0x1f, 0x03, 0x80, 0xfe, 0x8f, 0xfb,
+ 0xff, 0xf6, 0xc7, 0x03, 0x00, 0xe6, 0xe3, 0x03, 0x00, 0xc6, 0xf1, 0x03, 0x00, 0x86, 0xf8,
+ 0x03, 0x00, 0x06, 0xfc, 0x03, 0x00, 0x06, 0xfe, 0x03, 0x00, 0x06, 0xfc, 0x03, 0x00, 0x06,
+ 0xf8, 0x03, 0x00, 0x06, 0xf0, 0x03, 0x00, 0x06, 0xe0, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00,
+ 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char swap_lmsk[] = {
+ 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff,
+ 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0,
+ 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00,
+ 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff,
+ 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff,
+ 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00,
+ 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00,
+ };
+
static BCursor SwapCursor = {
/* small */
swap_sbm,
swap_smsk,
16,
16,
- 8,
- 8,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ swap_lbm,
+ swap_lmsk,
32,
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_SWAPAREA_CURSOR] = &SwapCursor;
+ BlenderCursor[WM_CURSOR_SWAP_AREA] = &SwapCursor;
END_CURSOR_BLOCK;
- /********************** Horizontal Split Cursor ***********************/
+ /********************** Vertical Split Cursor ***********************/
BEGIN_CURSOR_BLOCK;
- static char hsplit_sbm[] = {
- 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x88,
- 0x08, 0x8C, 0x18, 0x8E, 0x38, 0x8C, 0x18, 0x88, 0x08, 0x80, 0x00,
- 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ static char vsplit_sbm[] = {
+ 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x88,
+ 0x11, 0x8c, 0x31, 0x86, 0x61, 0x86, 0x61, 0x8c, 0x31, 0x88, 0x11,
+ 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
};
- static char hsplit_smsk[] = {
- 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0xD0, 0x05, 0xD8, 0x0D, 0xDC,
- 0x1D, 0xDE, 0x3D, 0xDF, 0x7D, 0xDE, 0x3D, 0xDC, 0x1D, 0xD8, 0x0D,
- 0xD0, 0x05, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x00,
+ static char vsplit_smsk[] = {
+ 0xe0, 0x07, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc8, 0x13, 0xdc,
+ 0x3b, 0xde, 0x7b, 0xcf, 0xf3, 0xcf, 0xf3, 0xde, 0x7b, 0xdc, 0x3b,
+ 0xc8, 0x13, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xe0, 0x07,
};
- static char hsplit_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
- 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
- 0x01, 0x00, 0x00, 0x84, 0x21, 0x00, 0x00, 0x86, 0x61, 0x00, 0x00, 0x87, 0xE1, 0x00, 0x80,
- 0x87, 0xE1, 0x01, 0xC0, 0x87, 0xE1, 0x03, 0xE0, 0x87, 0xE1, 0x07, 0xF0, 0x87, 0xE1, 0x0F,
- 0xF8, 0x87, 0xE1, 0x1F, 0xF0, 0x87, 0xE1, 0x0F, 0xE0, 0x87, 0xE1, 0x07, 0xC0, 0x87, 0xE1,
- 0x03, 0x80, 0x87, 0xE1, 0x01, 0x00, 0x87, 0xE1, 0x00, 0x00, 0x86, 0x61, 0x00, 0x00, 0x84,
- 0x21, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
- 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ static char vsplit_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c,
+ 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38,
+ 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x80, 0x38, 0x1c, 0x01, 0xc0, 0x39, 0x9c, 0x03, 0xe0,
+ 0x3b, 0xdc, 0x07, 0xf0, 0x39, 0x9c, 0x0f, 0xf8, 0x38, 0x1c, 0x1f, 0x7c, 0x38, 0x1c, 0x3e,
+ 0x3e, 0x38, 0x1c, 0x7c, 0x3e, 0x38, 0x1c, 0x7c, 0x7c, 0x38, 0x1c, 0x3e, 0xf8, 0x38, 0x1c,
+ 0x1f, 0xf0, 0x39, 0x9c, 0x0f, 0xe0, 0x3b, 0xdc, 0x07, 0xc0, 0x39, 0x9c, 0x03, 0x80, 0x38,
+ 0x1c, 0x01, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00,
+ 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00,
+ 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
- static char hsplit_lmsk[] = {
- 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03,
- 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC8, 0x13, 0x00, 0x00, 0xCC, 0x33, 0x00, 0x00, 0xCE,
- 0x73, 0x00, 0x00, 0xCF, 0xF3, 0x00, 0x80, 0xCF, 0xF3, 0x01, 0xC0, 0xCF, 0xF3, 0x03, 0xE0,
- 0xCF, 0xF3, 0x07, 0xF0, 0xCF, 0xF3, 0x0F, 0xF8, 0xCF, 0xF3, 0x1F, 0xFC, 0xCF, 0xF3, 0x3F,
- 0xFE, 0xCF, 0xF3, 0x7F, 0xFC, 0xCF, 0xF3, 0x3F, 0xF8, 0xCF, 0xF3, 0x1F, 0xF0, 0xCF, 0xF3,
- 0x0F, 0xE0, 0xCF, 0xF3, 0x07, 0xC0, 0xCF, 0xF3, 0x03, 0x80, 0xCF, 0xF3, 0x01, 0x00, 0xCF,
- 0xF3, 0x00, 0x00, 0xCE, 0x73, 0x00, 0x00, 0xCC, 0x33, 0x00, 0x00, 0xC8, 0x13, 0x00, 0x00,
- 0xC8, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00,
- 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00};
+ static char vsplit_lmsk[] = {
+ 0x00, 0x18, 0x18, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e,
+ 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78,
+ 0x1e, 0x00, 0x80, 0x78, 0x1e, 0x01, 0xc0, 0x79, 0x9e, 0x03, 0xe0, 0x7b, 0xde, 0x07, 0xf0,
+ 0x7f, 0xfe, 0x0f, 0xf8, 0x7b, 0xde, 0x1f, 0xfc, 0x79, 0x9e, 0x3f, 0xfe, 0x78, 0x1e, 0x7f,
+ 0x7f, 0x78, 0x1e, 0xfe, 0x7f, 0x78, 0x1e, 0xfe, 0xfe, 0x78, 0x1e, 0x7f, 0xfc, 0x79, 0x9e,
+ 0x3f, 0xf8, 0x7b, 0xde, 0x1f, 0xf0, 0x7f, 0xfe, 0x0f, 0xe0, 0x7b, 0xde, 0x07, 0xc0, 0x79,
+ 0x9e, 0x03, 0x80, 0x78, 0x1e, 0x01, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00,
+ 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00,
+ 0x00, 0x38, 0x1c, 0x00, 0x00, 0x18, 0x18, 0x00,
+ };
- static BCursor HSplitCursor = {
+ static BCursor VSplitCursor = {
/* small */
- hsplit_sbm,
- hsplit_smsk,
+ vsplit_sbm,
+ vsplit_smsk,
16,
16,
7,
7,
/* big */
- hsplit_lbm,
- hsplit_lmsk,
+ vsplit_lbm,
+ vsplit_lmsk,
32,
32,
15,
@@ -1182,58 +1661,60 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_H_SPLITCURSOR] = &HSplitCursor;
+ BlenderCursor[WM_CURSOR_V_SPLIT] = &VSplitCursor;
END_CURSOR_BLOCK;
- /********************** Vertical Split Cursor ***********************/
+ /********************** Horizontal Split Cursor ***********************/
BEGIN_CURSOR_BLOCK;
- static char vsplit_sbm[] = {
- 0x00, 0x00, 0x80, 0x00, 0xC0, 0x01, 0xE0, 0x03, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ static char hsplit_sbm[] = {
+ 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0x60, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x06, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00,
};
- static char vsplit_smsk[] = {
- 0x80, 0x00, 0xC0, 0x01, 0xE0, 0x03, 0xF0, 0x07, 0xF8, 0x0F, 0x00,
- 0x00, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0x00, 0x00, 0xF8, 0x0F,
- 0xF0, 0x07, 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x00,
+ static char hsplit_smsk[] = {
+ 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f, 0x60, 0x06, 0x01,
+ 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x80,
+ 0x60, 0x06, 0xf0, 0x0f, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01,
};
- static char vsplit_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
- 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8,
- 0x0F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xFE, 0xFF, 0xFF, 0x3F, 0xFE, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, 0xFE,
- 0x3F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00,
- 0xE0, 0x03, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ static char hsplit_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07,
+ 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0x3e,
+ 0x7c, 0x00, 0x00, 0x1c, 0x38, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+ 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff,
+ 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x10, 0x00, 0x00, 0x1c, 0x38, 0x00, 0x00, 0x3e, 0x7c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00,
+ 0xf8, 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xc0, 0x03, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
- static char vsplit_lmsk[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x03,
- 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFE,
- 0x3F, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xC0, 0xFF, 0xFF, 0x01, 0xE0,
- 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x7F,
- 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0x01, 0x80, 0xFF,
- 0xFF, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00,
- 0xF8, 0x0F, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xC0, 0x01, 0x00,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ static char hsplit_lmsk[] = {
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xf0, 0x0f,
+ 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x7f,
+ 0xfe, 0x00, 0x00, 0x3e, 0x7c, 0x00, 0x00, 0x1c, 0x38, 0x00, 0x00, 0x08, 0x10, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff,
+ 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x08, 0x10, 0x00, 0x00, 0x1c,
+ 0x38, 0x00, 0x00, 0x3e, 0x7c, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00,
+ 0xfc, 0x3f, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xe0, 0x07, 0x00,
+ 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00,
+ };
- static BCursor VSplitCursor = {
+ static BCursor HSplitCursor = {
/* small */
- vsplit_sbm,
- vsplit_smsk,
+ hsplit_sbm,
+ hsplit_smsk,
16,
16,
7,
7,
/* big */
- vsplit_lbm,
- vsplit_lmsk,
+ hsplit_lbm,
+ hsplit_lmsk,
32,
32,
15,
@@ -1242,7 +1723,7 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_V_SPLITCURSOR] = &VSplitCursor;
+ BlenderCursor[WM_CURSOR_H_SPLIT] = &HSplitCursor;
END_CURSOR_BLOCK;
@@ -1250,38 +1731,40 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char narrow_sbm[] = {
- 0x00, 0x00, 0x80, 0x00, 0xC0, 0x01, 0xE0, 0x03, 0xF0, 0x07, 0xF8,
- 0x0F, 0xFC, 0x1F, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03,
+ 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8,
+ 0x0f, 0x7c, 0x1f, 0x3e, 0x3e, 0x1c, 0x1c, 0x08, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char narrow_smsk[] = {
- 0x80, 0x00, 0xC0, 0x01, 0xE0, 0x03, 0xF0, 0x07, 0xF8, 0x0F, 0xFC,
- 0x1F, 0xFE, 0x3F, 0xFF, 0x7F, 0xF0, 0x07, 0xF0, 0x07, 0xF0, 0x07,
- 0xF0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc,
+ 0x1f, 0xfe, 0x3f, 0x7f, 0x7f, 0x3e, 0x3e, 0x1c, 0x1c, 0x08, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char narrow_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x01,
- 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xFC,
- 0x1F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xC0,
- 0xFF, 0xFF, 0x01, 0xE0, 0xFF, 0xFF, 0x03, 0xF0, 0xFF, 0xFF, 0x07, 0xF8, 0xFF, 0xFF, 0x0F,
- 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F,
- 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC,
- 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x07,
+ 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc,
+ 0x7f, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x80, 0xff, 0xfe, 0x03, 0xc0,
+ 0x7f, 0xfc, 0x07, 0xe0, 0x3f, 0xf8, 0x0f, 0xf0, 0x1f, 0xf0, 0x1f, 0xf8, 0x0f, 0xe0, 0x3f,
+ 0xfc, 0x07, 0xc0, 0x7f, 0xf8, 0x03, 0x80, 0x3f, 0xf0, 0x01, 0x00, 0x1f, 0xe0, 0x00, 0x00,
+ 0x0e, 0x40, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static char narrow_lmsk[] = {
- 0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF0, 0x07,
- 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFF,
- 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xC0, 0xFF, 0xFF, 0x01, 0xE0, 0xFF, 0xFF, 0x03, 0xF0,
- 0xFF, 0xFF, 0x07, 0xF8, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFE, 0xFF, 0xFF, 0x3F,
- 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F,
- 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE,
- 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xe0, 0x0f,
+ 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0xfe,
+ 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xff, 0x07, 0xe0,
+ 0xff, 0xfe, 0x0f, 0xf0, 0x7f, 0xfc, 0x1f, 0xf8, 0x3f, 0xf8, 0x3f, 0xfc, 0x1f, 0xf0, 0x7f,
+ 0xfe, 0x0f, 0xe0, 0xff, 0xfc, 0x07, 0xc0, 0x7f, 0xf8, 0x03, 0x80, 0x3f, 0xf0, 0x01, 0x00,
+ 0x1f, 0xe0, 0x00, 0x00, 0x0e, 0x40, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static BCursor NArrowCursor = {
/* small */
@@ -1290,19 +1773,19 @@ void wm_init_cursor_data(void)
16,
16,
7,
- 4,
+ 5,
/* big */
narrow_lbm,
narrow_lmsk,
32,
32,
- 15,
- 10,
+ 16,
+ 12,
/* can invert color */
true,
};
- BlenderCursor[BC_N_ARROWCURSOR] = &NArrowCursor;
+ BlenderCursor[WM_CURSOR_N_ARROW] = &NArrowCursor;
END_CURSOR_BLOCK;
@@ -1310,38 +1793,40 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char sarrow_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0,
- 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xFC, 0x1F, 0xF8, 0x0F,
- 0xF0, 0x07, 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x08, 0x1c, 0x1c, 0x3e, 0x3e, 0x7c, 0x1f, 0xf8, 0x0f,
+ 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00,
};
static char sarrow_smsk[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0xF0,
- 0x07, 0xF0, 0x07, 0xF0, 0x07, 0xFF, 0x7F, 0xFE, 0x3F, 0xFC, 0x1F,
- 0xF8, 0x0F, 0xF0, 0x07, 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x08, 0x1c, 0x1c, 0x3e, 0x3e, 0x7f, 0x7f, 0xfe, 0x3f, 0xfc, 0x1f,
+ 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00,
};
static char sarrow_lbm[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00,
- 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00,
- 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0xF8, 0xFF, 0xFF, 0x0F, 0xF0, 0xFF, 0xFF,
- 0x07, 0xE0, 0xFF, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
- 0x7F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00,
- 0xF0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x02, 0x70, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x80, 0x0f,
+ 0xfc, 0x01, 0xc0, 0x1f, 0xfe, 0x03, 0xe0, 0x3f, 0xfc, 0x07, 0xf0, 0x1f, 0xf8, 0x0f, 0xf8,
+ 0x0f, 0xf0, 0x1f, 0xfc, 0x07, 0xe0, 0x3f, 0xfe, 0x03, 0xc0, 0x7f, 0xff, 0x01, 0x80, 0xff,
+ 0xff, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00,
+ 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static char sarrow_lmsk[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE,
- 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00,
- 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00,
- 0x00, 0xFE, 0x3F, 0x00, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF,
- 0x1F, 0xF8, 0xFF, 0xFF, 0x0F, 0xF0, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0x03, 0xC0, 0xFF,
- 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00,
- 0xFC, 0x1F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0x00,
- 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
+ 0x00, 0x00, 0x02, 0x70, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x80, 0x0f, 0xfc, 0x01, 0xc0, 0x1f,
+ 0xfe, 0x03, 0xe0, 0x3f, 0xff, 0x07, 0xf0, 0x7f, 0xfe, 0x0f, 0xf8, 0x3f, 0xfc, 0x1f, 0xfc,
+ 0x1f, 0xf8, 0x3f, 0xfe, 0x0f, 0xf0, 0x7f, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x03, 0xc0, 0xff,
+ 0xff, 0x01, 0x80, 0xff, 0xff, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00,
+ 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
+ };
static BCursor SArrowCursor = {
/* small */
@@ -1350,19 +1835,19 @@ void wm_init_cursor_data(void)
16,
16,
7,
- 11,
+ 10,
/* big */
sarrow_lbm,
sarrow_lmsk,
32,
32,
15,
- 21,
+ 18,
/* can invert color */
true,
};
- BlenderCursor[BC_S_ARROWCURSOR] = &SArrowCursor;
+ BlenderCursor[WM_CURSOR_S_ARROW] = &SArrowCursor;
END_CURSOR_BLOCK;
@@ -1370,38 +1855,40 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char earrow_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0E, 0xE0,
- 0x1F, 0xE0, 0x3F, 0xE0, 0x7F, 0xE0, 0x3F, 0xE0, 0x1F, 0x00, 0x0E,
- 0x00, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x0f, 0x00,
+ 0x1f, 0x00, 0x3e, 0x00, 0x7c, 0x00, 0x3e, 0x00, 0x1f, 0x80, 0x0f,
+ 0xc0, 0x07, 0x80, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
};
static char earrow_smsk[] = {
- 0x00, 0x01, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0F, 0xF0, 0x1F, 0xF0,
- 0x3F, 0xF0, 0x7F, 0xF0, 0xFF, 0xF0, 0x7F, 0xF0, 0x3F, 0xF0, 0x1F,
- 0x00, 0x0F, 0x00, 0x07, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xc0, 0x1f, 0x80,
+ 0x3f, 0x00, 0x7f, 0x00, 0xfe, 0x00, 0x7f, 0x80, 0x3f, 0xc0, 0x1f,
+ 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x03, 0x00, 0x01, 0x00, 0x00,
};
static char earrow_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
- 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
- 0x3E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00,
- 0xFF, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xFF, 0x1F,
- 0x00, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0xFF, 0x1F, 0x00, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xFF,
- 0x07, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00,
- 0x7E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00,
- 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x07,
+ 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xc0,
+ 0x7f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00,
+ 0x00, 0xfc, 0x07, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x3f,
+ 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8,
+ 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xff, 0x01, 0x00, 0x80,
+ 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00,
+ 0xe0, 0x0f, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static char earrow_lmsk[] = {
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0F,
- 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00,
- 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0x03, 0x80, 0xFF, 0xFF, 0x07, 0x80,
- 0xFF, 0xFF, 0x0F, 0x80, 0xFF, 0xFF, 0x1F, 0x80, 0xFF, 0xFF, 0x3F, 0x80, 0xFF, 0xFF, 0x7F,
- 0x80, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0x7F, 0x80, 0xFF, 0xFF, 0x3F, 0x80, 0xFF, 0xFF,
- 0x1F, 0x80, 0xFF, 0xFF, 0x0F, 0x80, 0xFF, 0xFF, 0x07, 0x80, 0xFF, 0xFF, 0x03, 0x00, 0x00,
- 0xFF, 0x01, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00,
- 0x00, 0x1F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xe0, 0x0f,
+ 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xe0,
+ 0xff, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x80, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00,
+ 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf0, 0x7f,
+ 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc,
+ 0x1f, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x80, 0xff, 0x03, 0x00, 0xc0,
+ 0xff, 0x01, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00,
+ 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x80, 0x03, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static BCursor EArrowCursor = {
/* small */
@@ -1409,20 +1896,20 @@ void wm_init_cursor_data(void)
earrow_smsk,
16,
16,
- 11,
+ 10,
7,
/* big */
earrow_lbm,
earrow_lmsk,
32,
32,
+ 18,
15,
- 22,
/* can invert color */
true,
};
- BlenderCursor[BC_E_ARROWCURSOR] = &EArrowCursor;
+ BlenderCursor[WM_CURSOR_E_ARROW] = &EArrowCursor;
END_CURSOR_BLOCK;
@@ -1430,38 +1917,40 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char warrow_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x00, 0x70, 0x00, 0xF8,
- 0x07, 0xFC, 0x07, 0xFE, 0x07, 0xFC, 0x07, 0xF8, 0x07, 0x70, 0x00,
- 0x60, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x01, 0xf8,
+ 0x00, 0x7c, 0x00, 0x3e, 0x00, 0x7c, 0x00, 0xf8, 0x00, 0xf0, 0x01,
+ 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char warrow_smsk[] = {
- 0x80, 0x00, 0xC0, 0x00, 0xE0, 0x00, 0xF0, 0x00, 0xF8, 0x0F, 0xFC,
- 0x0F, 0xFE, 0x0F, 0xFF, 0x0F, 0xFE, 0x0F, 0xFC, 0x0F, 0xF8, 0x0F,
- 0xF0, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x03, 0xfc,
+ 0x01, 0xfe, 0x00, 0x7f, 0x00, 0xfe, 0x00, 0xfc, 0x01, 0xf8, 0x03,
+ 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00,
};
static char warrow_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
- 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x7C,
- 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xC0,
- 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x00, 0xF8, 0xFF, 0xFF, 0x00,
- 0xFC, 0xFF, 0xFF, 0x00, 0xF8, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0xFF,
- 0x00, 0xC0, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x7E,
- 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00,
- 0x60, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03,
+ 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe,
+ 0x03, 0x00, 0x00, 0xff, 0x01, 0x00, 0x80, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0,
+ 0x3f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00,
+ 0xfe, 0x03, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00,
+ 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00,
+ 0xf0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static char warrow_lmsk[] = {
- 0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xF0, 0x00,
- 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0xFF,
- 0x00, 0x00, 0x80, 0xFF, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x01, 0xE0, 0xFF, 0xFF, 0x01, 0xF0,
- 0xFF, 0xFF, 0x01, 0xF8, 0xFF, 0xFF, 0x01, 0xFC, 0xFF, 0xFF, 0x01, 0xFE, 0xFF, 0xFF, 0x01,
- 0xFF, 0xFF, 0xFF, 0x01, 0xFE, 0xFF, 0xFF, 0x01, 0xFC, 0xFF, 0xFF, 0x01, 0xF8, 0xFF, 0xFF,
- 0x01, 0xF0, 0xFF, 0xFF, 0x01, 0xE0, 0xFF, 0xFF, 0x01, 0xC0, 0xFF, 0xFF, 0x01, 0x80, 0xFF,
- 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00,
- 0xF8, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x07,
+ 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xff,
+ 0x07, 0x00, 0x80, 0xff, 0x03, 0x00, 0xc0, 0xff, 0x01, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xf0,
+ 0x7f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00,
+ 0xff, 0x07, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00,
+ 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x80, 0xff,
+ 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00,
+ 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static BCursor WArrowCursor = {
/* small */
@@ -1469,20 +1958,20 @@ void wm_init_cursor_data(void)
warrow_smsk,
16,
16,
- 4,
+ 5,
7,
/* big */
warrow_lbm,
warrow_lmsk,
32,
32,
- 15,
+ 18,
15,
/* can invert color */
true,
};
- BlenderCursor[BC_W_ARROWCURSOR] = &WArrowCursor;
+ BlenderCursor[WM_CURSOR_W_ARROW] = &WArrowCursor;
END_CURSOR_BLOCK;
@@ -1490,38 +1979,40 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char stop_sbm[] = {
- 0x00, 0x00, 0xE0, 0x07, 0x38, 0x1C, 0x1C, 0x30, 0x3C, 0x20, 0x76,
- 0x60, 0xE2, 0x40, 0xC2, 0x41, 0x82, 0x43, 0x02, 0x47, 0x06, 0x6E,
- 0x04, 0x3C, 0x0C, 0x38, 0x38, 0x1C, 0xE0, 0x07, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x07, 0xf8, 0x1f, 0x1c, 0x3c, 0x3c, 0x30, 0x76,
+ 0x70, 0xe6, 0x60, 0xc6, 0x61, 0x86, 0x63, 0x06, 0x67, 0x0e, 0x6e,
+ 0x0c, 0x3c, 0x3c, 0x38, 0xf8, 0x1f, 0xe0, 0x07, 0x00, 0x00,
};
static char stop_smsk[] = {
- 0xE0, 0x07, 0xF8, 0x1F, 0xFC, 0x3F, 0x3E, 0x7C, 0x7E, 0x70, 0xFF,
- 0xF0, 0xF7, 0xE1, 0xE7, 0xE3, 0xC7, 0xE7, 0x87, 0xEF, 0x0F, 0xFF,
- 0x0E, 0x7E, 0x3E, 0x7C, 0xFC, 0x3F, 0xF8, 0x1F, 0xE0, 0x07,
+ 0xe0, 0x07, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f, 0x7e, 0x7c, 0xff,
+ 0xf8, 0xff, 0xf1, 0xef, 0xf3, 0xcf, 0xf7, 0x8f, 0xff, 0x1f, 0xff,
+ 0x3e, 0x7e, 0xfe, 0x7f, 0xfc, 0x3f, 0xf8, 0x1f, 0xe0, 0x07,
};
static char stop_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x00, 0x0F, 0xF0,
- 0x00, 0xC0, 0x03, 0xC0, 0x03, 0xE0, 0x01, 0x00, 0x07, 0xF0, 0x01, 0x00, 0x0E, 0xF0, 0x01,
- 0x00, 0x0C, 0xF8, 0x03, 0x00, 0x18, 0x1C, 0x07, 0x00, 0x38, 0x0C, 0x0E, 0x00, 0x30, 0x0C,
- 0x1C, 0x00, 0x30, 0x06, 0x38, 0x00, 0x60, 0x06, 0x70, 0x00, 0x60, 0x06, 0xE0, 0x00, 0x60,
- 0x06, 0xC0, 0x01, 0x60, 0x06, 0x80, 0x03, 0x60, 0x06, 0x00, 0x07, 0x60, 0x06, 0x00, 0x0E,
- 0x60, 0x06, 0x00, 0x1C, 0x60, 0x0C, 0x00, 0x38, 0x30, 0x0C, 0x00, 0x70, 0x30, 0x1C, 0x00,
- 0xE0, 0x38, 0x18, 0x00, 0xC0, 0x1F, 0x30, 0x00, 0x80, 0x0F, 0x70, 0x00, 0x80, 0x0F, 0xE0,
- 0x00, 0x80, 0x07, 0xC0, 0x03, 0xC0, 0x03, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0xFE, 0x7F, 0x00,
- 0x00, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0xc0, 0x1f, 0xf8, 0x03, 0xe0, 0x03, 0xc0, 0x07, 0xf0, 0x01, 0x80, 0x0f, 0xf0, 0x03,
+ 0x00, 0x0f, 0xf8, 0x07, 0x00, 0x1e, 0xbc, 0x0f, 0x00, 0x3c, 0x1c, 0x1f, 0x00, 0x38, 0x1c,
+ 0x3e, 0x00, 0x38, 0x1e, 0x7c, 0x00, 0x78, 0x0e, 0xf8, 0x00, 0x70, 0x0e, 0xf0, 0x01, 0x70,
+ 0x0e, 0xe0, 0x03, 0x70, 0x0e, 0xc0, 0x07, 0x70, 0x0e, 0x80, 0x0f, 0x70, 0x0e, 0x00, 0x1f,
+ 0x70, 0x1e, 0x00, 0x3e, 0x78, 0x1c, 0x00, 0x7c, 0x38, 0x1c, 0x00, 0xf8, 0x38, 0x3c, 0x00,
+ 0xf0, 0x3d, 0x78, 0x00, 0xe0, 0x1f, 0xf0, 0x00, 0xc0, 0x0f, 0xf0, 0x01, 0x80, 0x0f, 0xe0,
+ 0x03, 0xc0, 0x07, 0xc0, 0x1f, 0xf8, 0x03, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0x7f, 0x00,
+ 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static char stop_lmsk[] = {
- 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x01, 0xC0, 0xFF, 0xFF,
- 0x03, 0xE0, 0x1F, 0xF8, 0x07, 0xF0, 0x03, 0xC0, 0x0F, 0xF8, 0x03, 0x80, 0x1F, 0xFC, 0x07,
- 0x00, 0x3F, 0xFC, 0x0F, 0x00, 0x3E, 0xFE, 0x1F, 0x00, 0x7C, 0x9E, 0x3F, 0x00, 0x78, 0x1E,
- 0x7F, 0x00, 0x78, 0x1F, 0xFE, 0x00, 0xF8, 0x0F, 0xFC, 0x01, 0xF0, 0x0F, 0xF8, 0x03, 0xF0,
- 0x0F, 0xF0, 0x07, 0xF0, 0x0F, 0xE0, 0x0F, 0xF0, 0x0F, 0xC0, 0x1F, 0xF0, 0x0F, 0x80, 0x3F,
- 0xF0, 0x1F, 0x00, 0x7F, 0xF8, 0x1E, 0x00, 0xFE, 0x78, 0x1E, 0x00, 0xFC, 0x79, 0x3E, 0x00,
- 0xF8, 0x7F, 0x7C, 0x00, 0xF0, 0x3F, 0xFC, 0x00, 0xE0, 0x3F, 0xF8, 0x01, 0xC0, 0x1F, 0xF0,
- 0x03, 0xC0, 0x0F, 0xE0, 0x1F, 0xF8, 0x07, 0xC0, 0xFF, 0xFF, 0x03, 0x80, 0xFF, 0xFF, 0x01,
- 0x00, 0xFE, 0x7F, 0x00, 0x00, 0xF0, 0x0F, 0x00};
+ 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x01, 0xe0, 0xff, 0xff,
+ 0x07, 0xf0, 0xff, 0xff, 0x0f, 0xf8, 0x3f, 0xfc, 0x1f, 0xf8, 0x07, 0xe0, 0x1f, 0xfc, 0x0f,
+ 0xc0, 0x3f, 0xfe, 0x1f, 0x80, 0x7f, 0xfe, 0x3f, 0x00, 0x7f, 0xfe, 0x7f, 0x00, 0x7e, 0xbf,
+ 0xff, 0x00, 0xfc, 0x3f, 0xff, 0x01, 0xfc, 0x3f, 0xfe, 0x03, 0xfc, 0x1f, 0xfc, 0x07, 0xf8,
+ 0x1f, 0xf8, 0x0f, 0xf8, 0x1f, 0xf0, 0x1f, 0xf8, 0x1f, 0xe0, 0x3f, 0xf8, 0x3f, 0xc0, 0x7f,
+ 0xfc, 0x3f, 0x80, 0xff, 0xfc, 0x3f, 0x00, 0xff, 0xfd, 0x7e, 0x00, 0xfe, 0x7f, 0xfe, 0x00,
+ 0xfc, 0x7f, 0xfe, 0x01, 0xf8, 0x7f, 0xfc, 0x03, 0xf0, 0x3f, 0xf8, 0x07, 0xe0, 0x1f, 0xf8,
+ 0x3f, 0xfc, 0x1f, 0xf0, 0xff, 0xff, 0x0f, 0xe0, 0xff, 0xff, 0x07, 0x80, 0xff, 0xff, 0x01,
+ 0x00, 0xff, 0xff, 0x00, 0x00, 0xf8, 0x1f, 0x00,
+ };
static BCursor StopCursor = {
/* small */
@@ -1538,11 +2029,135 @@ void wm_init_cursor_data(void)
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
+ };
+
+ BlenderCursor[WM_CURSOR_STOP] = &StopCursor;
+
+ END_CURSOR_BLOCK;
+
+ /********************** Zoom In Cursor ***********************/
+ BEGIN_CURSOR_BLOCK;
+
+ static char zoomin_sbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xf8, 0x03, 0xb8, 0x03, 0xbc,
+ 0x07, 0x0c, 0x06, 0xbc, 0x07, 0xb8, 0x03, 0xf8, 0x0b, 0xe0, 0x14,
+ 0x00, 0x22, 0x00, 0x44, 0x00, 0x88, 0x00, 0x90, 0x00, 0x60,
+ };
+
+ static char zoomin_smsk[] = {
+ 0x00, 0x00, 0xe0, 0x00, 0xf8, 0x03, 0xfc, 0x07, 0xfc, 0x07, 0xfe,
+ 0x0f, 0xfe, 0x0f, 0xfe, 0x0f, 0xfc, 0x07, 0xfc, 0x0f, 0xf8, 0x1f,
+ 0xe0, 0x3e, 0x00, 0x7c, 0x00, 0xf8, 0x00, 0xf0, 0x00, 0x60,
+ };
+
+ static char zoomin_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x0f,
+ 0x00, 0xf8, 0xff, 0x1f, 0x00, 0xf8, 0xff, 0x1f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xe7,
+ 0x3f, 0x00, 0xfc, 0xe7, 0x3f, 0x00, 0xfe, 0xe7, 0x7f, 0x00, 0xfe, 0xe7, 0x7f, 0x00, 0x7e,
+ 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0xfe, 0xe7, 0x7f, 0x00, 0xfe, 0xe7, 0x7f, 0x00,
+ 0xfc, 0xe7, 0x3f, 0x00, 0xfc, 0xe7, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0x5f,
+ 0x00, 0xf8, 0xff, 0x9f, 0x00, 0xf0, 0xff, 0x0f, 0x01, 0xc0, 0xff, 0x03, 0x02, 0x00, 0x7e,
+ 0x04, 0x04, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00,
+ 0x00, 0x40, 0x40, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x82,
+ 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x38,
+ };
+
+ static char zoomin_lmsk[] = {
+ 0x00, 0x7e, 0x00, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0xf8, 0xff, 0x1f,
+ 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff,
+ 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x7f,
+ 0x00, 0xfc, 0xff, 0xff, 0x00, 0xf8, 0xff, 0xff, 0x01, 0xf0, 0xff, 0xff, 0x03, 0xc0, 0xff,
+ 0xff, 0x07, 0x00, 0x7e, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x3f, 0x00,
+ 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xfe,
+ 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x38,
+ };
+
+ static BCursor ZoomInCursor = {
+ /* small */
+ zoomin_sbm,
+ zoomin_smsk,
+ 16,
+ 16,
+ 6,
+ 6,
+ /* big */
+ zoomin_lbm,
+ zoomin_lmsk,
+ 32,
+ 32,
+ 11,
+ 11,
+ /* don't invert color */
+ false,
+ };
+
+ BlenderCursor[WM_CURSOR_ZOOM_IN] = &ZoomInCursor;
+
+ END_CURSOR_BLOCK;
+
+ /********************** Zoom Out Cursor ***********************/
+ BEGIN_CURSOR_BLOCK;
+
+ static char zoomout_sbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xf8, 0x03, 0xf8, 0x03, 0xfc,
+ 0x07, 0x0c, 0x06, 0xfc, 0x07, 0xf8, 0x03, 0xf8, 0x0b, 0xe0, 0x14,
+ 0x00, 0x22, 0x00, 0x44, 0x00, 0x88, 0x00, 0x90, 0x00, 0x60,
+ };
+
+ static char zoomout_smsk[] = {
+ 0x00, 0x00, 0xe0, 0x00, 0xf8, 0x03, 0xfc, 0x07, 0xfc, 0x07, 0xfe,
+ 0x0f, 0xfe, 0x0f, 0xfe, 0x0f, 0xfc, 0x07, 0xfc, 0x0f, 0xf8, 0x1f,
+ 0xe0, 0x3e, 0x00, 0x7c, 0x00, 0xf8, 0x00, 0xf0, 0x00, 0x60,
+ };
+
+ static char zoomout_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x0f,
+ 0x00, 0xf8, 0xff, 0x1f, 0x00, 0xf8, 0xff, 0x1f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff,
+ 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0x7e,
+ 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00,
+ 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0x5f,
+ 0x00, 0xf8, 0xff, 0x9f, 0x00, 0xf0, 0xff, 0x0f, 0x01, 0xc0, 0xff, 0x03, 0x02, 0x00, 0x7e,
+ 0x04, 0x04, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00,
+ 0x00, 0x40, 0x40, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x82,
+ 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x38,
+ };
+
+ static char zoomout_lmsk[] = {
+ 0x00, 0x7e, 0x00, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0xf8, 0xff, 0x1f,
+ 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff,
+ 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x7f,
+ 0x00, 0xfc, 0xff, 0xff, 0x00, 0xf8, 0xff, 0xff, 0x01, 0xf0, 0xff, 0xff, 0x03, 0xc0, 0xff,
+ 0xff, 0x07, 0x00, 0x7e, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x3f, 0x00,
+ 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xfe,
+ 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x38,
+ };
+
+ static BCursor ZoomOutCursor = {
+ /* small */
+ zoomout_sbm,
+ zoomout_smsk,
+ 16,
+ 16,
+ 6,
+ 6,
+ /* big */
+ zoomout_lbm,
+ zoomout_lmsk,
+ 32,
+ 32,
+ 11,
+ 11,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_STOPCURSOR] = &StopCursor;
+ BlenderCursor[WM_CURSOR_ZOOM_OUT] = &ZoomOutCursor;
END_CURSOR_BLOCK;
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index ba6a0c4ebe1..901594850dd 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -265,7 +265,7 @@ static void wm_drop_operator_options(bContext *C, wmDrag *drag, const wmEvent *e
if (opname) {
BLI_strncpy(drag->opname, opname, sizeof(drag->opname));
- // WM_cursor_modal_set(win, CURSOR_COPY);
+ // WM_cursor_modal_set(win, WM_CURSOR_COPY);
}
// else
// WM_cursor_modal_restore(win);
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 3bcb955c2b2..2f538a19ba2 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -46,7 +46,6 @@
#include "BKE_main.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
-#include "BKE_workspace.h"
#include "GHOST_C-api.h"
@@ -55,10 +54,8 @@
#include "ED_screen.h"
#include "GPU_draw.h"
-#include "GPU_extensions.h"
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
-#include "GPU_matrix.h"
#include "GPU_state.h"
#include "GPU_texture.h"
#include "GPU_viewport.h"
@@ -436,6 +433,17 @@ static void wm_draw_region_blit(ARegion *ar, int view)
return;
}
+ if (view == -1) {
+ /* Non-stereo drawing. */
+ view = 0;
+ }
+ else if (view > 0) {
+ if (ar->draw_buffer->viewport[view] == NULL && ar->draw_buffer->offscreen[view] == NULL) {
+ /* Region does not need stereo or failed to allocate stereo buffers. */
+ view = 0;
+ }
+ }
+
if (ar->draw_buffer->viewport[view]) {
GPU_viewport_draw_to_screen(ar->draw_buffer->viewport[view], &ar->winrct);
}
@@ -688,7 +696,7 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
}
else {
/* Blit from offscreen buffer. */
- wm_draw_region_blit(ar, 0);
+ wm_draw_region_blit(ar, view);
}
}
}
@@ -820,11 +828,11 @@ static void wm_draw_window(bContext *C, wmWindow *win)
/****************** main update call **********************/
/* quick test to prevent changing window drawable */
-static bool wm_draw_update_test_window(wmWindow *win)
+static bool wm_draw_update_test_window(Main *bmain, wmWindow *win)
{
Scene *scene = WM_window_get_active_scene(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- struct Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ struct Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
bScreen *screen = WM_window_get_active_screen(win);
ARegion *ar;
bool do_draw = false;
@@ -925,7 +933,7 @@ void wm_draw_update(bContext *C)
}
#endif
- if (wm_draw_update_test_window(win)) {
+ if (wm_draw_update_test_window(bmain, win)) {
bScreen *screen = WM_window_get_active_screen(win);
CTX_wm_window_set(C, win);
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 51191b45439..6b4327d5f44 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -50,7 +50,6 @@
#include "BKE_customdata.h"
#include "BKE_idprop.h"
#include "BKE_global.h"
-#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -59,6 +58,8 @@
#include "BKE_sound.h"
+#include "BLT_translation.h"
+
#include "ED_fileselect.h"
#include "ED_info.h"
#include "ED_screen.h"
@@ -360,7 +361,7 @@ void wm_event_do_depsgraph(bContext *C, bool is_after_open_file)
* and for until then we have to accept ambiguities when object is shared
* across visible view layers and has overrides on it.
*/
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
if (is_after_open_file) {
DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
DEG_graph_on_visible_update(bmain, depsgraph, true);
@@ -1804,8 +1805,11 @@ void wm_event_free_handler(wmEventHandler *handler)
/* only set context when area/region is part of screen */
static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const wmEvent *event)
{
- wmWindow *win = CTX_wm_window(C);
- bScreen *screen = CTX_wm_screen(C);
+ wmWindow *win = handler->context.win ? handler->context.win : CTX_wm_window(C);
+ /* It's probably fine to always use WM_window_get_active_screen() to get the screen. But this
+ * code has been getting it through context since forever, so play safe and stick to that when
+ * possible. */
+ bScreen *screen = handler->context.win ? WM_window_get_active_screen(win) : CTX_wm_screen(C);
if (screen && handler->op) {
if (handler->context.area == NULL) {
@@ -2334,50 +2338,39 @@ static int wm_handler_fileselect_do(bContext *C,
int val)
{
wmWindowManager *wm = CTX_wm_manager(C);
- SpaceFile *sfile;
int action = WM_HANDLER_CONTINUE;
switch (val) {
case EVT_FILESELECT_FULL_OPEN: {
- ScrArea *sa;
+ wmWindow *win = CTX_wm_window(C);
+ ScrArea *area;
- /* sa can be null when window A is active, but mouse is over window B
- * in this case, open file select in original window A. Also don't
- * use global areas. */
- if (handler->context.area == NULL || ED_area_is_global(handler->context.area)) {
- bScreen *screen = CTX_wm_screen(C);
- sa = (ScrArea *)screen->areabase.first;
- }
- else {
- sa = handler->context.area;
- }
+ if ((area = ED_screen_temp_space_open(C,
+ IFACE_("Blender File View"),
+ WM_window_pixels_x(win) / 2,
+ WM_window_pixels_y(win) / 2,
+ U.file_space_data.temp_win_sizex * UI_DPI_FAC,
+ U.file_space_data.temp_win_sizey * UI_DPI_FAC,
+ SPACE_FILE,
+ U.filebrowser_display_type))) {
+ ARegion *region_header = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
- if (sa->full) {
- /* ensure the first area becomes the file browser, because the second one is the small
- * top (info-)area which might be too small (in fullscreens we have max two areas) */
- if (sa->prev) {
- sa = sa->prev;
- }
- ED_area_newspace(C, sa, SPACE_FILE, true); /* 'sa' is modified in-place */
- /* we already had a fullscreen here -> mark new space as a stacked fullscreen */
- sa->flag |= (AREA_FLAG_STACKED_FULLSCREEN | AREA_FLAG_TEMP_TYPE);
- }
- else if (sa->spacetype == SPACE_FILE) {
- sa = ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENMAXIMIZED);
- }
- else {
- sa = ED_screen_full_newspace(C, sa, SPACE_FILE); /* sets context */
- }
+ BLI_assert(area->spacetype == SPACE_FILE);
- /* note, getting the 'sa' back from the context causes a nasty bug where the newly created
- * 'sa' != CTX_wm_area(C). removed the line below and set 'sa' in the 'if' above */
- /* sa = CTX_wm_area(C); */
+ region_header->flag |= RGN_FLAG_HIDDEN;
+ /* Header on bottom, AZone triangle to toggle header looks misplaced at the top */
+ region_header->alignment = RGN_ALIGN_BOTTOM;
- /* settings for filebrowser, sfile is not operator owner but sends events */
- sfile = (SpaceFile *)sa->spacedata.first;
- sfile->op = handler->op;
+ /* settings for filebrowser, sfile is not operator owner but sends events */
+ SpaceFile *sfile = (SpaceFile *)area->spacedata.first;
+ sfile->op = handler->op;
- ED_fileselect_set_params(sfile);
+ ED_fileselect_set_params_from_userdef(sfile);
+ }
+ else {
+ BKE_report(&wm->reports, RPT_ERROR, "Failed to open window!");
+ return OPERATOR_CANCELLED;
+ }
action = WM_HANDLER_BREAK;
break;
@@ -2386,22 +2379,69 @@ static int wm_handler_fileselect_do(bContext *C,
case EVT_FILESELECT_EXEC:
case EVT_FILESELECT_CANCEL:
case EVT_FILESELECT_EXTERNAL_CANCEL: {
+ wmWindow *ctx_win = CTX_wm_window(C);
+
/* remlink now, for load file case before removing*/
BLI_remlink(handlers, handler);
- if (val != EVT_FILESELECT_EXTERNAL_CANCEL) {
- ScrArea *sa = CTX_wm_area(C);
+ if (val == EVT_FILESELECT_EXTERNAL_CANCEL) {
+ /* The window might have been freed already. */
+ if (BLI_findindex(&wm->windows, handler->context.win) == -1) {
+ handler->context.win = NULL;
+ }
+ }
+ else {
+ wmWindow *temp_win;
+ ScrArea *ctx_sa = CTX_wm_area(C);
+
+ for (temp_win = wm->windows.first; temp_win; temp_win = temp_win->next) {
+ bScreen *screen = WM_window_get_active_screen(temp_win);
+ ScrArea *file_sa = screen->areabase.first;
+
+ if (screen->temp && (file_sa->spacetype == SPACE_FILE)) {
+ int win_size[2];
+
+ /* Get DPI/pixelsize independent size to be stored in preferences. */
+ WM_window_set_dpi(temp_win); /* Ensure the DPI is taken from the right window. */
+ win_size[0] = WM_window_pixels_x(temp_win) / UI_DPI_FAC;
+ win_size[1] = WM_window_pixels_y(temp_win) / UI_DPI_FAC;
+
+ ED_fileselect_params_to_userdef(file_sa->spacedata.first, win_size);
+
+ if (BLI_listbase_is_single(&file_sa->spacedata)) {
+ BLI_assert(ctx_win != temp_win);
+
+ wm_window_close(C, wm, temp_win);
+
+ CTX_wm_window_set(C, ctx_win); // wm_window_close() NULLs.
+ /* Some operators expect a drawable context (for EVT_FILESELECT_EXEC) */
+ 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->winactive = ctx_win; /* Reports use this... */
+ if (handler->context.win == temp_win) {
+ handler->context.win = NULL;
+ }
+ }
+ else if (file_sa->full) {
+ ED_screen_full_prevspace(C, file_sa);
+ }
+ else {
+ ED_area_prevspace(C, file_sa);
+ }
- if (sa->full) {
- ED_screen_full_prevspace(C, sa);
+ break;
+ }
}
- /* user may have left fullscreen */
- else {
- ED_area_prevspace(C, sa);
+
+ if (!temp_win && ctx_sa->full) {
+ ED_fileselect_params_to_userdef(ctx_sa->spacedata.first, NULL);
+ ED_screen_full_prevspace(C, ctx_sa);
}
}
- wm_handler_op_context(C, handler, CTX_wm_window(C)->eventstate);
+ wm_handler_op_context(C, handler, ctx_win->eventstate);
/* needed for UI_popup_menu_reports */
@@ -3235,9 +3275,10 @@ void wm_event_do_handlers(bContext *C)
wm_event_free_all(win);
}
else {
+ Main *bmain = CTX_data_main(C);
Scene *scene = WM_window_get_active_scene(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, false);
Scene *scene_eval = (depsgraph != NULL) ? DEG_get_evaluated_scene(depsgraph) : NULL;
if (scene_eval != NULL) {
@@ -3511,38 +3552,48 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
+ const bool is_temp_screen = WM_window_is_temp_screen(win);
+ const bool opens_window = (U.filebrowser_display_type == USER_TEMP_SPACE_DISPLAY_WINDOW);
+ /* Don't add the file handler to the temporary window if one is opened, or else it owns the
+ * handlers for itself, causing dangling pointers once it's destructed through a handler. It has
+ * a parent which should hold the handlers itself. */
+ ListBase *modalhandlers = (is_temp_screen && opens_window) ? &win->parent->modalhandlers :
+ &win->modalhandlers;
/* Close any popups, like when opening a file browser from the splash. */
- UI_popup_handlers_remove_all(C, &win->modalhandlers);
+ UI_popup_handlers_remove_all(C, modalhandlers);
- /* only allow 1 file selector open per window */
- LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, &win->modalhandlers) {
- if (handler_base->type == WM_HANDLER_TYPE_OP) {
- wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
- if (handler->is_fileselect == false) {
- continue;
- }
- bScreen *screen = CTX_wm_screen(C);
- bool cancel_handler = true;
+ if (!is_temp_screen) {
+ /* only allow 1 file selector open per window */
+ LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, modalhandlers) {
+ if (handler_base->type == WM_HANDLER_TYPE_OP) {
+ wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
+ if (handler->is_fileselect == false) {
+ continue;
+ }
+ bScreen *screen = CTX_wm_screen(C);
+ bool cancel_handler = true;
- /* find the area with the file selector for this handler */
- ED_screen_areas_iter(win, screen, sa)
- {
- if (sa->spacetype == SPACE_FILE) {
- SpaceFile *sfile = sa->spacedata.first;
+ /* find the area with the file selector for this handler */
+ ED_screen_areas_iter(win, screen, sa)
+ {
+ if (sa->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = sa->spacedata.first;
- if (sfile->op == handler->op) {
- CTX_wm_area_set(C, sa);
- wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_CANCEL);
- cancel_handler = false;
- break;
+ if (sfile->op == handler->op) {
+ CTX_wm_area_set(C, sa);
+ wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_CANCEL);
+ cancel_handler = false;
+ break;
+ }
}
}
- }
- /* if not found we stop the handler without changing the screen */
- if (cancel_handler) {
- wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL);
+ /* if not found we stop the handler without changing the screen */
+ if (cancel_handler) {
+ wm_handler_fileselect_do(
+ C, &win->modalhandlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL);
+ }
}
}
}
@@ -3552,10 +3603,11 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
handler->is_fileselect = true;
handler->op = op;
+ handler->context.win = CTX_wm_window(C);
handler->context.area = CTX_wm_area(C);
handler->context.region = CTX_wm_region(C);
- BLI_addhead(&win->modalhandlers, handler);
+ BLI_addhead(modalhandlers, handler);
/* check props once before invoking if check is available
* ensures initial properties are valid */
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 8546290d281..f96a8c3d7fd 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -52,8 +52,8 @@
#include "BLI_blenlib.h"
#include "BLI_linklist.h"
#include "BLI_utildefines.h"
+#include "BLI_timer.h"
#include "BLI_threads.h"
-#include "BLI_callbacks.h"
#include "BLI_system.h"
#include BLI_SYSTEM_PID_H
@@ -73,7 +73,7 @@
#include "BKE_autoexec.h"
#include "BKE_blender.h"
#include "BKE_blendfile.h"
-#include "BKE_blender_undo.h"
+#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
@@ -101,6 +101,7 @@
#include "ED_datafiles.h"
#include "ED_fileselect.h"
#include "ED_image.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "ED_util.h"
@@ -113,8 +114,6 @@
#include "UI_resources.h"
#include "UI_view2d.h"
-#include "GPU_draw.h"
-
/* only to report a missing engine */
#include "RE_engine.h"
@@ -535,16 +534,16 @@ static void wm_file_read_post(bContext *C,
if (use_userdef) {
if (is_factory_startup) {
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_FACTORY_USERDEF_POST);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_LOAD_FACTORY_USERDEF_POST);
}
}
if (use_data) {
/* important to do before NULL'ing the context */
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_VERSION_UPDATE);
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_POST);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_VERSION_UPDATE);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_LOAD_POST);
if (is_factory_startup) {
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_FACTORY_STARTUP_POST);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_LOAD_FACTORY_STARTUP_POST);
}
}
@@ -607,7 +606,8 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
WM_cursor_wait(1);
- BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_PRE);
+ BKE_callback_exec_null(CTX_data_main(C), BKE_CB_EVT_LOAD_PRE);
+ BLI_timer_on_file_load();
UI_view2d_zoom_cache_reset();
@@ -804,7 +804,8 @@ void wm_homefile_read(bContext *C,
}
if (use_data) {
- BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_PRE);
+ BKE_callback_exec_null(CTX_data_main(C), BKE_CB_EVT_LOAD_PRE);
+ BLI_timer_on_file_load();
G.relbase_valid = 0;
@@ -1204,6 +1205,8 @@ static ImBuf *blend_file_thumb(const bContext *C,
/* will be scaled down, but gives some nice oversampling */
ImBuf *ibuf;
BlendThumbnail *thumb;
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *windrawable_old = wm->windrawable;
char err_out[256] = "unknown";
/* screen if no camera found */
@@ -1269,6 +1272,14 @@ static ImBuf *blend_file_thumb(const bContext *C,
err_out);
}
+ /* Reset to old drawable. */
+ if (windrawable_old) {
+ wm_window_make_drawable(wm, windrawable_old);
+ }
+ else {
+ wm_window_clear_drawable(wm);
+ }
+
if (ibuf) {
float aspect = (scene->r.xsch * scene->r.xasp) / (scene->r.ysch * scene->r.yasp);
@@ -1354,7 +1365,7 @@ static bool wm_file_write(bContext *C, const char *filepath, int fileflags, Repo
/* Call pre-save callbacks before writing preview,
* that way you can generate custom file thumbnail. */
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_SAVE_PRE);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_PRE);
/* Enforce full override check/generation on file save. */
BKE_main_override_library_operations_create(bmain, true);
@@ -1407,7 +1418,7 @@ static bool wm_file_write(bContext *C, const char *filepath, int fileflags, Repo
wm_history_file_update();
}
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_SAVE_POST);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_POST);
/* run this function after because the file cant be written before the blend is */
if (ibuf_thumb) {
@@ -1632,7 +1643,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_SAVE_PRE);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_PRE);
/* check current window and close it if temp */
if (win && WM_window_is_temp_screen(win)) {
@@ -1660,7 +1671,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
G.save_over = 0;
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_SAVE_POST);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_POST);
return OPERATOR_FINISHED;
}
@@ -1753,7 +1764,7 @@ static void wm_userpref_read_exceptions(UserDef *userdef_curr, const UserDef *us
((void)0)
/* Current visible preferences category. */
- USERDEF_RESTORE(userpref);
+ USERDEF_RESTORE(space_data.section_active);
#undef USERDEF_RESTORE
}
@@ -1971,6 +1982,10 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op)
}
}
+ if (G.fileflags & G_FILE_NO_UI) {
+ ED_outliner_select_sync_from_all_tag(C);
+ }
+
return OPERATOR_FINISHED;
}
@@ -2226,6 +2241,10 @@ static int wm_open_mainfile__open(bContext *C, wmOperator *op)
BKE_report_print_level_set(op->reports, RPT_WARNING);
if (success) {
+ if (G.fileflags & G_FILE_NO_UI) {
+ ED_outliner_select_sync_from_all_tag(C);
+ }
+ ED_view3d_local_collections_reset(C, (G.fileflags & G_FILE_NO_UI) != 0);
return OPERATOR_FINISHED;
}
else {
@@ -2314,7 +2333,7 @@ static void wm_open_mainfile_ui(bContext *UNUSED(C), wmOperator *op)
void WM_OT_open_mainfile(wmOperatorType *ot)
{
- ot->name = "Open Blender File";
+ ot->name = "Open";
ot->idname = "WM_OT_open_mainfile";
ot->description = "Open a Blender file";
@@ -2390,7 +2409,10 @@ void WM_OT_revert_mainfile(wmOperatorType *ot)
ot->name = "Revert";
ot->idname = "WM_OT_revert_mainfile";
ot->description = "Reload the saved file";
+
ot->invoke = WM_operator_confirm;
+ ot->exec = wm_revert_mainfile_exec;
+ ot->poll = wm_revert_mainfile_poll;
RNA_def_boolean(ot->srna,
"use_scripts",
@@ -2398,9 +2420,6 @@ void WM_OT_revert_mainfile(wmOperatorType *ot)
"Trusted Source",
"Allow .blend file to execute scripts automatically, default available from "
"system preferences");
-
- ot->exec = wm_revert_mainfile_exec;
- ot->poll = wm_revert_mainfile_poll;
}
/** \} */
@@ -2445,8 +2464,8 @@ void WM_OT_recover_last_session(wmOperatorType *ot)
ot->name = "Recover Last Session";
ot->idname = "WM_OT_recover_last_session";
ot->description = "Open the last closed file (\"" BLENDER_QUIT_FILE "\")";
- ot->invoke = WM_operator_confirm;
+ ot->invoke = WM_operator_confirm;
ot->exec = wm_recover_last_session_exec;
}
@@ -2488,15 +2507,15 @@ void WM_OT_recover_auto_save(wmOperatorType *ot)
ot->idname = "WM_OT_recover_auto_save";
ot->description = "Open an automatically saved file to recover it";
- ot->exec = wm_recover_auto_save_exec;
ot->invoke = wm_recover_auto_save_invoke;
+ ot->exec = wm_recover_auto_save_exec;
WM_operator_properties_filesel(ot,
FILE_TYPE_BLENDER,
FILE_BLENDER,
FILE_OPENFILE,
WM_FILESEL_FILEPATH,
- FILE_LONGDISPLAY,
+ FILE_VERTICALDISPLAY,
FILE_SORT_TIME);
}
@@ -2630,7 +2649,7 @@ void WM_OT_save_as_mainfile(wmOperatorType *ot)
{
PropertyRNA *prop;
- ot->name = "Save As Blender File";
+ ot->name = "Save As";
ot->idname = "WM_OT_save_as_mainfile";
ot->description = "Save the current file in the desired location";
@@ -3038,7 +3057,7 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C, struct ARegi
BLI_path_extension_replace(filename, sizeof(filename), "");
}
else {
- BLI_snprintf(filename, sizeof(filename), IFACE_("Untitled"));
+ STRNCPY(filename, IFACE_("Untitled"));
}
/* Title */
@@ -3074,6 +3093,12 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C, struct ARegi
BKE_reports_init(&reports, RPT_STORE);
uint modified_images_count = ED_image_save_all_modified_info(C, &reports);
+ LISTBASE_FOREACH (Report *, report, &reports.list) {
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiLayoutSetRedAlert(row, true);
+ uiItemL(row, report->message, ICON_CANCEL);
+ }
+
if (modified_images_count > 0) {
char message[64];
BLI_snprintf(message,
@@ -3099,13 +3124,9 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C, struct ARegi
"");
}
- LISTBASE_FOREACH (Report *, report, &reports.list) {
- uiItemL(layout, report->message, ICON_ERROR);
- }
-
BKE_reports_clear(&reports);
- uiItemL(layout, "", ICON_NONE);
+ uiItemS_ex(layout, 3.0f);
/* Buttons */
#ifdef _WIN32
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 5a6606984ba..3374d17cbfd 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -55,7 +55,6 @@
#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_report.h"
-#include "BKE_scene.h"
#include "BKE_idcode.h"
@@ -561,7 +560,7 @@ static void wm_link_append_properties_common(wmOperatorType *ot, bool is_link)
void WM_OT_link(wmOperatorType *ot)
{
- ot->name = "Link from Library";
+ ot->name = "Link";
ot->idname = "WM_OT_link";
ot->description = "Link from a Library .blend file";
@@ -576,7 +575,7 @@ void WM_OT_link(wmOperatorType *ot)
FILE_LOADLIB,
FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME |
- WM_FILESEL_RELPATH | WM_FILESEL_FILES,
+ WM_FILESEL_RELPATH | WM_FILESEL_FILES | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
@@ -585,7 +584,7 @@ void WM_OT_link(wmOperatorType *ot)
void WM_OT_append(wmOperatorType *ot)
{
- ot->name = "Append from Library";
+ ot->name = "Append";
ot->idname = "WM_OT_append";
ot->description = "Append from a Library .blend file";
@@ -600,7 +599,7 @@ void WM_OT_append(wmOperatorType *ot)
FILE_LOADLIB,
FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME |
- WM_FILESEL_FILES,
+ WM_FILESEL_FILES | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 29cb02888ac..70d83153840 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -41,7 +41,6 @@
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
-#include "BLI_callbacks.h"
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
@@ -54,7 +53,7 @@
#include "BKE_blendfile.h"
#include "BKE_blender.h"
-#include "BKE_blender_undo.h"
+#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_font.h"
#include "BKE_global.h"
@@ -120,7 +119,6 @@
#include "GPU_material.h"
#include "GPU_draw.h"
-#include "GPU_immediate.h"
#include "GPU_init_exit.h"
#include "BKE_sound.h"
@@ -215,7 +213,7 @@ static void sound_jack_sync_callback(Main *bmain, int mode, float time)
continue;
}
ViewLayer *view_layer = WM_window_get_active_view_layer(window);
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, false);
if (depsgraph == NULL) {
continue;
}
@@ -288,6 +286,10 @@ void WM_init(bContext *C, int argc, const char **argv)
const bool use_data = true;
const bool use_userdef = true;
+ /* Studio-lights needs to be init before we read the home-file,
+ * otherwise the versioning cannot find the default studio-light. */
+ BKE_studiolight_init();
+
wm_homefile_read(C,
NULL,
G.factory_startup,
@@ -315,8 +317,6 @@ void WM_init(bContext *C, int argc, const char **argv)
UI_init();
}
- BKE_studiolight_init();
-
ED_spacemacros_init();
/* note: there is a bug where python needs initializing before loading the
@@ -376,10 +376,10 @@ void WM_init(bContext *C, int argc, const char **argv)
* note that recovering the last session does its own callbacks. */
CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_VERSION_UPDATE);
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_POST);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_VERSION_UPDATE);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_LOAD_POST);
if (is_factory_startup) {
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_FACTORY_STARTUP_POST);
+ BKE_callback_exec_null(bmain, BKE_CB_EVT_LOAD_FACTORY_STARTUP_POST);
}
wm_file_read_report(C, bmain);
@@ -524,6 +524,7 @@ void WM_exit_ex(bContext *C, const bool do_python)
BKE_addon_pref_type_free();
BKE_keyconfig_pref_type_free();
+ BKE_material_gpencil_default_free();
wm_operatortype_free();
wm_dropbox_free();
@@ -680,3 +681,12 @@ void WM_exit(bContext *C)
exit(G.is_break == true);
}
+
+/**
+ * Needed for cases when operators are re-registered
+ * (when operator type pointers are stored).
+ */
+void WM_script_tag_reload(void)
+{
+ UI_interface_tag_script_reload();
+}
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index fcb55d3f801..a8feb22cbf8 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -65,14 +65,14 @@ void WM_operator_properties_filesel(wmOperatorType *ot,
0,
"Default",
"Automatically determine display type for files"},
- {FILE_SHORTDISPLAY,
- "LIST_SHORT",
- ICON_SHORTDISPLAY,
+ {FILE_VERTICALDISPLAY,
+ "LIST_VERTICAL",
+ ICON_SHORTDISPLAY, /* Name of deprecated short list */
"Short List",
"Display files as short list"},
- {FILE_LONGDISPLAY,
- "LIST_LONG",
- ICON_LONGDISPLAY,
+ {FILE_HORIZONTALDISPLAY,
+ "LIST_HORIZONTAL",
+ ICON_LONGDISPLAY, /* Name of deprecated long list */
"Long List",
"Display files as a detailed list"},
{FILE_IMGDISPLAY, "THUMBNAIL", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"},
@@ -99,6 +99,15 @@ void WM_operator_properties_filesel(wmOperatorType *ot,
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
+ if ((flag & WM_FILESEL_SHOW_PROPS) == 0) {
+ prop = RNA_def_boolean(ot->srna,
+ "hide_props_region",
+ true,
+ "Hide Operator Properties",
+ "Collapse the region displaying the operator settings");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ }
+
if (action == FILE_SAVE) {
/* note, this is only used to check if we should highlight the filename area red when the
* filepath is an existing file. */
@@ -138,6 +147,9 @@ void WM_operator_properties_filesel(wmOperatorType *ot,
ot->srna, "filter_text", (filter & FILE_TYPE_TEXT) != 0, "Filter text files", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(
+ ot->srna, "filter_archive", (filter & FILE_TYPE_ARCHIVE) != 0, "Filter archive files", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(
ot->srna, "filter_btx", (filter & FILE_TYPE_BTX) != 0, "Filter btx files", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(
@@ -479,19 +491,26 @@ void WM_operator_properties_mouse_select(wmOperatorType *ot)
*/
void WM_operator_properties_checker_interval(wmOperatorType *ot, bool nth_can_disable)
{
- const int nth_default = nth_can_disable ? 1 : 2;
- const int nth_min = min_ii(nth_default, 2);
+ const int nth_default = nth_can_disable ? 0 : 1;
+ const int nth_min = min_ii(nth_default, 1);
RNA_def_int(ot->srna,
- "nth",
+ "skip",
nth_default,
nth_min,
INT_MAX,
- "Nth Element",
- "Skip every Nth element",
+ "Deselected",
+ "Number of deselected elements in the repetitive sequence",
nth_min,
100);
- RNA_def_int(
- ot->srna, "skip", 1, 1, INT_MAX, "Skip", "Number of elements to skip at once", 1, 100);
+ RNA_def_int(ot->srna,
+ "nth",
+ 1,
+ 1,
+ INT_MAX,
+ "Selected",
+ "Number of selected elements in the repetitive sequence",
+ 1,
+ 100);
RNA_def_int(ot->srna,
"offset",
0,
@@ -506,7 +525,7 @@ void WM_operator_properties_checker_interval(wmOperatorType *ot, bool nth_can_di
void WM_operator_properties_checker_interval_from_op(struct wmOperator *op,
struct CheckerIntervalParams *op_params)
{
- const int nth = RNA_int_get(op->ptr, "nth") - 1;
+ const int nth = RNA_int_get(op->ptr, "nth");
const int skip = RNA_int_get(op->ptr, "skip");
int offset = RNA_int_get(op->ptr, "offset");
@@ -520,6 +539,6 @@ void WM_operator_properties_checker_interval_from_op(struct wmOperator *op,
bool WM_operator_properties_checker_interval_test(const struct CheckerIntervalParams *op_params,
int depth)
{
- return ((op_params->nth == 0) ||
+ return ((op_params->skip == 0) ||
((op_params->offset + depth) % (op_params->skip + op_params->nth) >= op_params->skip));
}
diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c
index 8f3052ace5e..e3fe8892515 100644
--- a/source/blender/windowmanager/intern/wm_operator_type.c
+++ b/source/blender/windowmanager/intern/wm_operator_type.c
@@ -227,8 +227,8 @@ void wm_operatortype_free(void)
*/
void WM_operatortype_props_advanced_begin(wmOperatorType *ot)
{
- if (ot_prop_basic_count ==
- -1) { /* Don't do anything if _begin was called before, but not _end */
+ if (ot_prop_basic_count == -1) {
+ /* Don't do anything if _begin was called before, but not _end */
ot_prop_basic_count = RNA_struct_count_properties(ot->srna);
}
}
@@ -595,4 +595,35 @@ const char *WM_operatortype_name(struct wmOperatorType *ot, struct PointerRNA *p
return (name && name[0]) ? name : RNA_struct_ui_name(ot->srna);
}
+char *WM_operatortype_description(struct bContext *C,
+ struct wmOperatorType *ot,
+ struct PointerRNA *properties)
+{
+ if (ot->get_description && properties) {
+ char *description = ot->get_description(C, ot, properties);
+
+ if (description) {
+ if (description[0]) {
+ return description;
+ }
+ else {
+ MEM_freeN(description);
+ }
+ }
+ }
+
+ const char *info = RNA_struct_ui_description(ot->srna);
+
+ if (!(info && info[0])) {
+ info = RNA_struct_ui_name(ot->srna);
+ }
+
+ if (info && info[0]) {
+ return BLI_strdup(info);
+ }
+ else {
+ return NULL;
+ }
+}
+
/** \} */
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index b10a4ce6794..285379e90c6 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -41,6 +41,7 @@
#include "CLG_log.h"
#include "DNA_ID.h"
+#include "DNA_brush_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_scene_types.h"
@@ -58,6 +59,7 @@
#include "BLI_utildefines.h"
#include "BKE_brush.h"
+#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_icons.h"
@@ -140,13 +142,13 @@ void WM_operator_bl_idname(char *to, const char *from)
if (from) {
const char *sep = strchr(from, '.');
- if (sep) {
- int ofs = (sep - from);
-
+ int from_len;
+ if (sep && (from_len = strlen(from)) < OP_MAX_TYPENAME - 3) {
+ const int ofs = (sep - from);
memcpy(to, from, sizeof(char) * ofs);
BLI_str_toupper_ascii(to, ofs);
- strcpy(to + ofs, "_OT_");
- strcpy(to + (ofs + 4), sep + 1);
+ memcpy(to + ofs, "_OT_", 4);
+ memcpy(to + (ofs + 4), sep + 1, (from_len - ofs));
}
else {
/* should not happen but support just in case */
@@ -539,7 +541,7 @@ char *WM_prop_pystring_assign(bContext *C, PointerRNA *ptr, PropertyRNA *prop, i
if (lhs == NULL) {
/* fallback to bpy.data.foo[id] if we dont find in the context */
- lhs = RNA_path_full_property_py(ptr, prop, index);
+ lhs = RNA_path_full_property_py(CTX_data_main(C), ptr, prop, index);
}
if (!lhs) {
@@ -850,7 +852,7 @@ static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg)
NULL);
/* Move it downwards, mouse over button. */
- UI_block_bounds_set_popup(block, 6, (const int[2]){0, -UI_UNIT_Y});
+ UI_block_bounds_set_popup(block, 0.3f * U.widget_unit, (const int[2]){0, -UI_UNIT_Y});
UI_but_focus_on_enter_event(win, but);
@@ -1126,18 +1128,15 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op)
if (op->type->flag & OPTYPE_MACRO) {
for (op = op->macro.first; op; op = op->next) {
uiTemplateOperatorPropertyButs(
- C, layout, op, UI_BUT_LABEL_ALIGN_SPLIT_COLUMN, UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
- if (op->next) {
- uiItemS(layout);
- }
+ C, layout, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
}
}
else {
uiTemplateOperatorPropertyButs(
- C, layout, op, UI_BUT_LABEL_ALIGN_SPLIT_COLUMN, UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
+ C, layout, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
}
- UI_block_bounds_set_popup(block, 4, NULL);
+ UI_block_bounds_set_popup(block, 6 * U.dpi_fac, NULL);
return block;
}
@@ -1217,7 +1216,8 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData)
}
/* center around the mouse */
- UI_block_bounds_set_popup(block, 4, (const int[2]){data->width / -2, data->height / 2});
+ UI_block_bounds_set_popup(
+ block, 6 * U.dpi_fac, (const int[2]){data->width / -2, data->height / 2});
UI_block_active_only_flagged_buttons(C, ar, block);
@@ -1245,7 +1245,7 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *ar, void *userData)
UI_block_func_set(block, NULL, NULL, NULL);
- UI_block_bounds_set_popup(block, 4, NULL);
+ UI_block_bounds_set_popup(block, 6 * U.dpi_fac, NULL);
UI_block_active_only_flagged_buttons(C, ar, block);
@@ -1516,7 +1516,7 @@ static uiBlock *wm_block_search_menu(bContext *C, ARegion *ar, void *userdata)
NULL);
/* Move it downwards, mouse over button. */
- UI_block_bounds_set_popup(block, 6, (const int[2]){0, -UI_UNIT_Y});
+ UI_block_bounds_set_popup(block, 0.3f * U.widget_unit, (const int[2]){0, -UI_UNIT_Y});
return block;
}
@@ -1864,6 +1864,7 @@ typedef struct {
StructRNA *image_id_srna;
float initial_value, current_value, min_value, max_value;
int initial_mouse[2];
+ int initial_co[2];
int slow_mouse[2];
bool slow_mode;
Dial *dial;
@@ -1926,6 +1927,9 @@ static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *e
rc->initial_mouse[0] = event->x;
rc->initial_mouse[1] = event->y;
+ rc->initial_co[0] = event->x;
+ rc->initial_co[1] = event->y;
+
switch (rc->subtype) {
case PROP_NONE:
case PROP_DISTANCE:
@@ -1937,7 +1941,7 @@ static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *e
WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
break;
case PROP_FACTOR:
- d[0] = (1 - rc->initial_value) * WM_RADIAL_CONTROL_DISPLAY_WIDTH +
+ d[0] = rc->initial_value * WM_RADIAL_CONTROL_DISPLAY_WIDTH +
WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
break;
case PROP_ANGLE:
@@ -1964,8 +1968,10 @@ static void radial_control_set_tex(RadialControl *rc)
switch (RNA_type_to_ID_code(rc->image_id_ptr.type)) {
case ID_BR:
- if ((ibuf = BKE_brush_gen_radial_control_imbuf(rc->image_id_ptr.data,
- rc->use_secondary_tex))) {
+ if ((ibuf = BKE_brush_gen_radial_control_imbuf(
+ rc->image_id_ptr.data,
+ rc->use_secondary_tex,
+ !ELEM(rc->subtype, PROP_NONE, PROP_PIXEL, PROP_DISTANCE)))) {
glGenTextures(1, &rc->gltex);
glBindTexture(GL_TEXTURE_2D, rc->gltex);
glTexImage2D(
@@ -2063,6 +2069,22 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph
immUnbindProgram();
}
+static void radial_control_paint_curve(uint pos, Brush *br, float radius, int line_segments)
+{
+ GPU_line_width(2.0f);
+ immUniformColor4f(0.8f, 0.8f, 0.8f, 0.85f);
+ float step = (radius * 2.0f) / (float)line_segments;
+ BKE_curvemapping_initialize(br->curve);
+ immBegin(GPU_PRIM_LINES, line_segments * 2);
+ for (int i = 0; i < line_segments; i++) {
+ float h1 = BKE_brush_curve_strength_clamped(br, fabsf((i * step) - radius), radius);
+ immVertex2f(pos, -radius + (i * step), h1 * radius);
+ float h2 = BKE_brush_curve_strength_clamped(br, fabsf(((i + 1) * step) - radius), radius);
+ immVertex2f(pos, -radius + ((i + 1) * step), h2 * radius);
+ }
+ immEnd();
+}
+
static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void *customdata)
{
RadialControl *rc = customdata;
@@ -2096,7 +2118,7 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void
alpha = 0.75;
break;
case PROP_FACTOR:
- r1 = (1 - rc->current_value) * WM_RADIAL_CONTROL_DISPLAY_WIDTH +
+ r1 = rc->current_value * WM_RADIAL_CONTROL_DISPLAY_WIDTH +
WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
r2 = tex_radius = WM_RADIAL_CONTROL_DISPLAY_SIZE;
rmin = WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
@@ -2117,9 +2139,17 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void
break;
}
- /* Keep cursor in the original place */
- x = rc->initial_mouse[0];
- y = rc->initial_mouse[1];
+ if (rc->subtype == PROP_ANGLE) {
+ /* Use the initial mouse position to draw the rotation preview. This avoids starting the
+ * rotation in a random direction */
+ x = rc->initial_mouse[0];
+ y = rc->initial_mouse[1];
+ }
+ else {
+ /* Keep cursor in the original place */
+ x = rc->initial_co[0];
+ y = rc->initial_co[1];
+ }
GPU_matrix_translate_2f((float)x, (float)y);
GPU_blend(true);
@@ -2143,7 +2173,6 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor3fvAlpha(col, 0.5f);
if (rc->subtype == PROP_ANGLE) {
GPU_matrix_push();
@@ -2166,25 +2195,40 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void
}
/* draw circles on top */
- imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r1, 40);
- imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r2, 40);
+ GPU_line_width(2.0f);
+ immUniformColor3fvAlpha(col, 0.8f);
+ imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r1, 80);
+
+ GPU_line_width(1.0f);
+ immUniformColor3fvAlpha(col, 0.5f);
+ imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r2, 80);
if (rmin > 0.0f) {
- imm_draw_circle_wire_2d(pos, 0.0, 0.0f, rmin, 40);
+ /* Inner fill circle to increase the contrast of the value */
+ float black[3] = {0.0f};
+ immUniformColor3fvAlpha(black, 0.2f);
+ imm_draw_circle_fill_2d(pos, 0.0, 0.0f, rmin, 80);
+
+ immUniformColor3fvAlpha(col, 0.5f);
+ imm_draw_circle_wire_2d(pos, 0.0, 0.0f, rmin, 80);
}
+
+ /* draw curve falloff preview */
+ if (RNA_type_to_ID_code(rc->image_id_ptr.type) == ID_BR && rc->subtype == PROP_FACTOR) {
+ Brush *br = rc->image_id_ptr.data;
+ if (br) {
+ radial_control_paint_curve(pos, br, r2, 120);
+ }
+ }
+
immUnbindProgram();
- BLF_size(fontid, 1.5 * fstyle_points * U.pixelsize, U.dpi);
- BLF_enable(fontid, BLF_SHADOW);
- BLF_shadow(fontid, 3, (const float[4]){0.0f, 0.0f, 0.0f, 0.5f});
- BLF_shadow_offset(fontid, 1, -1);
+ BLF_size(fontid, 1.75f * fstyle_points * U.pixelsize, U.dpi);
/* draw value */
BLF_width_and_height(fontid, str, strdrawlen, &strwidth, &strheight);
BLF_position(fontid, -0.5f * strwidth, -0.5f * strheight, 0.0f);
BLF_draw(fontid, str, strdrawlen);
- BLF_disable(fontid, BLF_SHADOW);
-
GPU_blend(false);
GPU_line_smooth(false);
}
@@ -2635,6 +2679,8 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
if (snap) {
new_value = ((int)ceil(new_value * 10.f) * 10.0f) / 100.f;
}
+ /* Invert new value to increase the factor moving the mouse to the right */
+ new_value = 1 - new_value;
break;
case PROP_ANGLE:
new_value = atan2f(delta[1], delta[0]) + (float)M_PI + angle_precision;
diff --git a/source/blender/windowmanager/intern/wm_splash_screen.c b/source/blender/windowmanager/intern/wm_splash_screen.c
index 8629997030f..d3f7661a008 100644
--- a/source/blender/windowmanager/intern/wm_splash_screen.c
+++ b/source/blender/windowmanager/intern/wm_splash_screen.c
@@ -113,31 +113,37 @@ static void wm_block_splash_add_label(uiBlock *block, const char *label, int x,
static void wm_block_splash_add_labels(uiBlock *block, int x, int y)
{
/* Version number. */
- const char *version_suffix = NULL;
+ const char *version_cycle = NULL;
bool show_build_info = true;
if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "alpha")) {
- version_suffix = " Alpha";
+ version_cycle = " Alpha";
}
else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "beta")) {
- version_suffix = " Beta";
+ version_cycle = " Beta";
}
else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "rc")) {
- version_suffix = " Release Candidate";
+ version_cycle = " Release Candidate";
show_build_info = false;
}
else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) {
- version_suffix = STRINGIFY(BLENDER_VERSION_CHAR);
+ version_cycle = STRINGIFY(BLENDER_VERSION_CHAR);
show_build_info = false;
}
+ const char *version_cycle_number = "";
+ if (strlen(STRINGIFY(BLENDER_VERSION_CYCLE_NUMBER))) {
+ version_cycle_number = " " STRINGIFY(BLENDER_VERSION_CYCLE_NUMBER);
+ }
+
char version_buf[256] = "\0";
BLI_snprintf(version_buf,
sizeof(version_buf),
- "v %d.%d%s",
+ "v %d.%d%s%s",
BLENDER_VERSION / 100,
BLENDER_VERSION % 100,
- version_suffix);
+ version_cycle,
+ version_cycle_number);
wm_block_splash_add_label(block, version_buf, x, &y);
diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c
index 874f8516caa..9b62e532132 100644
--- a/source/blender/windowmanager/intern/wm_stereo.c
+++ b/source/blender/windowmanager/intern/wm_stereo.c
@@ -43,7 +43,6 @@
#include "ED_screen.h"
#include "GPU_immediate.h"
-#include "GPU_framebuffer.h"
#include "GPU_texture.h"
#include "WM_api.h"
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 47491813f70..2c26a15dce0 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -44,7 +44,6 @@
#include "BLT_translation.h"
-#include "BKE_blender.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_icons.h"
@@ -83,8 +82,6 @@
#include "GPU_framebuffer.h"
#include "GPU_init_exit.h"
#include "GPU_immediate.h"
-#include "GPU_material.h"
-#include "GPU_texture.h"
#include "GPU_context.h"
#include "BLF_api.h"
@@ -709,7 +706,7 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm)
/* without this, cursor restore may fail, T45456 */
if (win->cursor == 0) {
- win->cursor = CURSOR_STD;
+ win->cursor = WM_CURSOR_DEFAULT;
}
wm_window_ghostwindow_add(wm, "Blender", win);
@@ -795,10 +792,11 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect)
* Uses `screen->temp` tag to define what to do, currently it limits
* to only one "temp" window for render out, preferences, filewindow, etc...
*
- * \param type: WM_WINDOW_RENDER, WM_WINDOW_USERPREFS...
- * \return the window or NULL.
+ * \param space_type: SPACE_VIEW3D, SPACE_INFO, ... (eSpace_Type)
+ * \return the window or NULL in case of failure.
*/
-wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, int type)
+wmWindow *WM_window_open_temp(
+ bContext *C, const char *title, int x, int y, int sizex, int sizey, int space_type)
{
Main *bmain = CTX_data_main(C);
wmWindow *win_prev = CTX_wm_window(C);
@@ -807,7 +805,6 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
ScrArea *sa;
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- const char *title;
/* convert to native OS window coordinates */
const float native_pixel_size = GHOST_GetNativePixelSize(win_prev->ghostwin);
@@ -887,46 +884,11 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
sa = screen->areabase.first;
CTX_wm_area_set(C, sa);
- if (type == WM_WINDOW_RENDER) {
- ED_area_newspace(C, sa, SPACE_IMAGE, false);
- }
- else if (type == WM_WINDOW_DRIVERS) {
- ED_area_newspace(C, sa, SPACE_GRAPH, false);
- }
- else if (type == WM_WINDOW_INFO) {
- ED_area_newspace(C, sa, SPACE_INFO, false);
- }
- else {
- ED_area_newspace(C, sa, SPACE_USERPREF, false);
- }
+ ED_area_newspace(C, sa, space_type, false);
ED_screen_change(C, screen);
ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */
- /* do additional setup for specific editor type */
- if (type == WM_WINDOW_DRIVERS) {
- ED_drivers_editor_init(C, sa);
- }
-
- if (sa->spacetype == SPACE_IMAGE) {
- title = IFACE_("Blender Render");
- }
- else if (ELEM(sa->spacetype, SPACE_OUTLINER, SPACE_USERPREF)) {
- title = IFACE_("Blender Preferences");
- }
- else if (sa->spacetype == SPACE_FILE) {
- title = IFACE_("Blender File View");
- }
- else if (sa->spacetype == SPACE_GRAPH) {
- title = IFACE_("Blender Drivers Editor");
- }
- else if (sa->spacetype == SPACE_INFO) {
- title = IFACE_("Blender Info Log");
- }
- else {
- title = "Blender";
- }
-
if (win->ghostwin) {
GHOST_SetTitle(win->ghostwin, title);
return win;
diff --git a/source/blender/windowmanager/wm_cursors.h b/source/blender/windowmanager/wm_cursors.h
index 6793937c413..7a28aeb3c70 100644
--- a/source/blender/windowmanager/wm_cursors.h
+++ b/source/blender/windowmanager/wm_cursors.h
@@ -24,80 +24,57 @@
#ifndef __WM_CURSORS_H__
#define __WM_CURSORS_H__
-void wm_init_cursor_data(void);
-
-#define BC_GHOST_CURSORS 1000
-
-/* old cursors */
-enum {
- CURSOR_FACESEL = BC_GHOST_CURSORS,
- CURSOR_WAIT,
- CURSOR_EDIT,
- CURSOR_X_MOVE,
- CURSOR_Y_MOVE,
- CURSOR_HELP,
- CURSOR_STD,
- CURSOR_NONE,
- CURSOR_PENCIL,
- CURSOR_COPY,
-};
-
-// typedef struct BCursor_s BCursor;
-typedef struct BCursor {
-
- char *small_bm;
- char *small_mask;
-
- char small_sizex;
- char small_sizey;
- char small_hotx;
- char small_hoty;
-
- char *big_bm;
- char *big_mask;
-
- char big_sizex;
- char big_sizey;
- char big_hotx;
- char big_hoty;
-
- bool can_invert_color;
+struct wmEvent;
+struct wmWindow;
-} BCursor;
+typedef enum WMCursorType {
+ WM_CURSOR_DEFAULT = 1,
+ WM_CURSOR_TEXT_EDIT,
+ WM_CURSOR_WAIT,
+ WM_CURSOR_STOP,
+ WM_CURSOR_EDIT,
+ WM_CURSOR_COPY,
+ WM_CURSOR_HAND,
+
+ WM_CURSOR_CROSS,
+ WM_CURSOR_PAINT,
+ WM_CURSOR_DOT,
+ WM_CURSOR_CROSSC,
+
+ WM_CURSOR_KNIFE,
+ WM_CURSOR_VERTEX_LOOP,
+ WM_CURSOR_PAINT_BRUSH,
+ WM_CURSOR_ERASER,
+ WM_CURSOR_EYEDROPPER,
+
+ WM_CURSOR_SWAP_AREA,
+ WM_CURSOR_X_MOVE,
+ WM_CURSOR_Y_MOVE,
+ WM_CURSOR_H_SPLIT,
+ WM_CURSOR_V_SPLIT,
+
+ WM_CURSOR_NW_ARROW,
+ WM_CURSOR_NS_ARROW,
+ WM_CURSOR_EW_ARROW,
+ WM_CURSOR_N_ARROW,
+ WM_CURSOR_S_ARROW,
+ WM_CURSOR_E_ARROW,
+ WM_CURSOR_W_ARROW,
+
+ WM_CURSOR_NSEW_SCROLL,
+ WM_CURSOR_NS_SCROLL,
+ WM_CURSOR_EW_SCROLL,
+
+ WM_CURSOR_ZOOM_IN,
+ WM_CURSOR_ZOOM_OUT,
+
+ WM_CURSOR_NONE,
-#define SYSCURSOR 1
-enum {
- BC_NW_ARROWCURSOR = 2,
- BC_NS_ARROWCURSOR,
- BC_EW_ARROWCURSOR,
- BC_WAITCURSOR,
- BC_CROSSCURSOR,
- BC_EDITCROSSCURSOR,
- BC_BOXSELCURSOR,
- BC_KNIFECURSOR,
- BC_VLOOPCURSOR,
- BC_TEXTEDITCURSOR,
- BC_PAINTBRUSHCURSOR,
- BC_HANDCURSOR,
- BC_NSEW_SCROLLCURSOR,
- BC_NS_SCROLLCURSOR,
- BC_EW_SCROLLCURSOR,
- BC_EYEDROPPER_CURSOR,
- BC_SWAPAREA_CURSOR,
- BC_H_SPLITCURSOR,
- BC_V_SPLITCURSOR,
- BC_N_ARROWCURSOR,
- BC_S_ARROWCURSOR,
- BC_E_ARROWCURSOR,
- BC_W_ARROWCURSOR,
- BC_STOPCURSOR,
/* --- ALWAYS LAST ----- */
- BC_NUMCURSORS,
-};
-
-struct wmEvent;
-struct wmWindow;
+ WM_CURSOR_NUM,
+} WMCursorType;
+void wm_init_cursor_data(void);
bool wm_cursor_arrow_move(struct wmWindow *win, const struct wmEvent *event);
#endif /* __WM_CURSORS_H__ */
diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h
index 53b25a80dce..c53ccda170a 100644
--- a/source/blender/windowmanager/wm_event_system.h
+++ b/source/blender/windowmanager/wm_event_system.h
@@ -116,6 +116,10 @@ typedef struct wmEventHandler_Op {
/** Store context for this handler for derived/modal handlers. */
struct {
+ /* To override the window, and hence the screen. Set for few cases only, usually window/screen
+ * can be taken from current context. */
+ struct wmWindow *win;
+
struct ScrArea *area;
struct ARegion *region;
short region_type;