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
path: root/source
diff options
context:
space:
mode:
authorJulian Eisel <eiseljulian@gmail.com>2019-08-18 14:24:15 +0300
committerJulian Eisel <eiseljulian@gmail.com>2019-08-18 14:24:15 +0300
commit8209f25c3b08f726a221cbcbcfa48dbea597c772 (patch)
tree0e02482c8b6e87a75e02098c69cee051596da42e /source
parent4befee9e620f3c0b17711b56cc19bdebd7d401f5 (diff)
parent454b120f48201abe2e1a9ca7e5d25c28cb04013a (diff)
Merge branch 'master' into filebrowser_redesign
Diffstat (limited to 'source')
-rw-r--r--source/blender/alembic/ABC_alembic.h6
-rw-r--r--source/blender/alembic/intern/abc_customdata.h2
-rw-r--r--source/blender/alembic/intern/abc_exporter.cc6
-rw-r--r--source/blender/alembic/intern/abc_mesh.cc32
-rw-r--r--source/blender/alembic/intern/abc_mesh.h2
-rw-r--r--source/blender/alembic/intern/abc_object.cc8
-rw-r--r--source/blender/alembic/intern/abc_object.h2
-rw-r--r--source/blender/alembic/intern/alembic_capi.cc41
-rw-r--r--source/blender/blenfont/intern/blf_font.c4
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c8
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_context.h4
-rw-r--r--source/blender/blenkernel/BKE_mask.h1
-rw-r--r--source/blender/blenkernel/BKE_material.h8
-rw-r--r--source/blender/blenkernel/BKE_mesh.h1
-rw-r--r--source/blender/blenkernel/BKE_mesh_remesh_voxel.h46
-rw-r--r--source/blender/blenkernel/BKE_node.h9
-rw-r--r--source/blender/blenkernel/BKE_paint.h2
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h3
-rw-r--r--source/blender/blenkernel/BKE_writeavi.h8
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/action.c4
-rw-r--r--source/blender/blenkernel/intern/armature.c5
-rw-r--r--source/blender/blenkernel/intern/armature_update.c2
-rw-r--r--source/blender/blenkernel/intern/collection.c5
-rw-r--r--source/blender/blenkernel/intern/context.c7
-rw-r--r--source/blender/blenkernel/intern/curve.c6
-rw-r--r--source/blender/blenkernel/intern/customdata.c28
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c12
-rw-r--r--source/blender/blenkernel/intern/editmesh.c15
-rw-r--r--source/blender/blenkernel/intern/effect.c5
-rw-r--r--source/blender/blenkernel/intern/fcurve.c6
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c6
-rw-r--r--source/blender/blenkernel/intern/font.c4
-rw-r--r--source/blender/blenkernel/intern/gpencil.c125
-rw-r--r--source/blender/blenkernel/intern/image.c4
-rw-r--r--source/blender/blenkernel/intern/layer.c38
-rw-r--r--source/blender/blenkernel/intern/library.c4
-rw-r--r--source/blender/blenkernel/intern/library_override.c6
-rw-r--r--source/blender/blenkernel/intern/library_query.c9
-rw-r--r--source/blender/blenkernel/intern/main.c26
-rw-r--r--source/blender/blenkernel/intern/mask.c23
-rw-r--r--source/blender/blenkernel/intern/material.c16
-rw-r--r--source/blender/blenkernel/intern/mball.c5
-rw-r--r--source/blender/blenkernel/intern/mesh.c1
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.c4
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c22
-rw-r--r--source/blender/blenkernel/intern/mesh_remesh_voxel.c204
-rw-r--r--source/blender/blenkernel/intern/nla.c17
-rw-r--r--source/blender/blenkernel/intern/node.c13
-rw-r--r--source/blender/blenkernel/intern/object.c2
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c4
-rw-r--r--source/blender/blenkernel/intern/object_update.c2
-rw-r--r--source/blender/blenkernel/intern/ocean.c2
-rw-r--r--source/blender/blenkernel/intern/particle.c5
-rw-r--r--source/blender/blenkernel/intern/pointcache.c45
-rw-r--r--source/blender/blenkernel/intern/softbody.c24
-rw-r--r--source/blender/blenkernel/intern/text.c17
-rw-r--r--source/blender/blenkernel/intern/unit.c10
-rw-r--r--source/blender/blenlib/BLI_delaunay_2d.h199
-rw-r--r--source/blender/blenlib/BLI_math_geom.h8
-rw-r--r--source/blender/blenlib/BLI_path_util.h2
-rw-r--r--source/blender/blenlib/BLI_string_utils.h1
-rw-r--r--source/blender/blenlib/CMakeLists.txt2
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c4
-rw-r--r--source/blender/blenlib/intern/boxpack_2d.c4
-rw-r--r--source/blender/blenlib/intern/delaunay_2d.c2913
-rw-r--r--source/blender/blenlib/intern/freetypefont.c2
-rw-r--r--source/blender/blenlib/intern/math_geom.c232
-rw-r--r--source/blender/blenlib/intern/math_statistics.c2
-rw-r--r--source/blender/blenlib/intern/path_util.c18
-rw-r--r--source/blender/blenlib/intern/string_utils.c15
-rw-r--r--source/blender/blenlib/intern/task.c2
-rw-r--r--source/blender/blenloader/BLO_blend_defs.h2
-rw-r--r--source/blender/blenloader/intern/readfile.c166
-rw-r--r--source/blender/blenloader/intern/readfile.h2
-rw-r--r--source/blender/blenloader/intern/versioning_280.c136
-rw-r--r--source/blender/blenloader/intern/versioning_cycles.c52
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c5
-rw-r--r--source/blender/blenloader/intern/writefile.c9
-rw-r--r--source/blender/blentranslation/msgfmt/msgfmt.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c6
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c6
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_query.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers_impl.c2
-rw-r--r--source/blender/bmesh/operators/bmo_primitive.c7
-rw-r--r--source/blender/bmesh/operators/bmo_removedoubles.c10
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c1
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_collapse.c6
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_region_match.c2
-rw-r--r--source/blender/collada/MeshImporter.cpp5
-rw-r--r--source/blender/compositor/CMakeLists.txt13
-rw-r--r--source/blender/compositor/intern/COM_CompositorContext.h2
-rw-r--r--source/blender/compositor/intern/COM_Converter.cpp6
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.h2
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.h2
-rw-r--r--source/blender/compositor/intern/COM_OpenCLDevice.cpp2
-rw-r--r--source/blender/compositor/intern/COM_OpenCLDevice.h4
-rw-r--r--source/blender/compositor/nodes/COM_DenoiseNode.cpp47
-rw-r--r--source/blender/compositor/nodes/COM_DenoiseNode.h37
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_MathNode.cpp36
-rw-r--r--source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_CompositorOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_DenoiseOperation.cpp155
-rw-r--r--source/blender/compositor/operations/COM_DenoiseOperation.h71
-rw-r--r--source/blender/compositor/operations/COM_GlareGhostOperation.cpp12
-rw-r--r--source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_GlareStreaksOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_MaskOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_ViewerOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_WriteBufferOperation.cpp6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc3
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc5
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc2
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc2
-rw-r--r--source/blender/draw/CMakeLists.txt6
-rw-r--r--source/blender/draw/DRW_engine.h8
-rw-r--r--source/blender/draw/DRW_select_buffer.h108
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c4
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c6
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.c14
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_lights.c7
-rw-r--r--source/blender/draw/engines/eevee/eevee_lookdev.c13
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c62
-rw-r--r--source/blender/draw/engines/eevee/eevee_mist.c5
-rw-r--r--source/blender/draw/engines/eevee/eevee_occlusion.c4
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h1
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c4
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl228
-rw-r--r--source/blender/draw/engines/eevee/shaders/default_frag.glsl10
-rw-r--r--source/blender/draw/engines/eevee/shaders/lights_lib.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/prepass_frag.glsl6
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c6
-rw-r--r--source/blender/draw/engines/select/select_draw_utils.c59
-rw-r--r--source/blender/draw/engines/select/select_engine.c141
-rw-r--r--source/blender/draw/engines/select/select_private.h39
-rw-r--r--source/blender/draw/engines/workbench/workbench_studiolight.c5
-rw-r--r--source/blender/draw/intern/DRW_render.h1
-rw-r--r--source/blender/draw/intern/draw_cache.c8
-rw-r--r--source/blender/draw/intern/draw_cache.h13
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h250
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.c4313
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h3
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c4899
-rw-r--r--source/blender/draw/intern/draw_hair.c2
-rw-r--r--source/blender/draw/intern/draw_instance_data.c2
-rw-r--r--source/blender/draw/intern/draw_manager.c55
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c25
-rw-r--r--source/blender/draw/intern/draw_manager_profiling.c6
-rw-r--r--source/blender/draw/intern/draw_manager_profiling.h2
-rw-r--r--source/blender/draw/intern/draw_manager_shader.c2
-rw-r--r--source/blender/draw/intern/draw_select_buffer.c (renamed from source/blender/draw/engines/select/select_buffer.c)244
-rw-r--r--source/blender/draw/modes/edit_mesh_mode.c35
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_frag.glsl6
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl25
-rw-r--r--source/blender/editors/animation/anim_filter.c12
-rw-r--r--source/blender/editors/animation/anim_motion_paths.c5
-rw-r--r--source/blender/editors/animation/drivers.c2
-rw-r--r--source/blender/editors/animation/keyframing.c10
-rw-r--r--source/blender/editors/animation/keyingsets.c6
-rw-r--r--source/blender/editors/armature/armature_add.c2
-rw-r--r--source/blender/editors/armature/armature_select.c16
-rw-r--r--source/blender/editors/armature/pose_select.c15
-rw-r--r--source/blender/editors/curve/editcurve.c8
-rw-r--r--source/blender/editors/curve/editcurve_paint.c4
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c4
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c2
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c7
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c19
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c9
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c47
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h4
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c39
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c56
-rw-r--r--source/blender/editors/include/ED_anim_api.h2
-rw-r--r--source/blender/editors/include/ED_outliner.h13
-rw-r--r--source/blender/editors/include/ED_screen.h3
-rw-r--r--source/blender/editors/include/ED_sculpt.h3
-rw-r--r--source/blender/editors/include/ED_text.h5
-rw-r--r--source/blender/editors/include/UI_resources.h1
-rw-r--r--source/blender/editors/interface/interface.c4
-rw-r--r--source/blender/editors/interface/interface_context_menu.c44
-rw-r--r--source/blender/editors/interface/interface_eyedropper_datablock.c49
-rw-r--r--source/blender/editors/interface/interface_handlers.c70
-rw-r--r--source/blender/editors/interface/interface_layout.c6
-rw-r--r--source/blender/editors/interface/interface_ops.c5
-rw-r--r--source/blender/editors/interface/interface_templates.c29
-rw-r--r--source/blender/editors/interface/interface_utils.c5
-rw-r--r--source/blender/editors/interface/resources.c4
-rw-r--r--source/blender/editors/interface/view2d_gizmo_navigate.c13
-rw-r--r--source/blender/editors/interface/view2d_ops.c2
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c13
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c2
-rw-r--r--source/blender/editors/mesh/editmesh_select.c14
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c8
-rw-r--r--source/blender/editors/mesh/meshtools.c10
-rw-r--r--source/blender/editors/object/CMakeLists.txt1
-rw-r--r--source/blender/editors/object/object_add.c3
-rw-r--r--source/blender/editors/object/object_intern.h3
-rw-r--r--source/blender/editors/object/object_ops.c2
-rw-r--r--source/blender/editors/object/object_relations.c2
-rw-r--r--source/blender/editors/object/object_remesh.c158
-rw-r--r--source/blender/editors/object/object_select.c19
-rw-r--r--source/blender/editors/object/object_shader_fx.c5
-rw-r--r--source/blender/editors/object/object_vgroup.c6
-rw-r--r--source/blender/editors/render/render_view.c4
-rw-r--r--source/blender/editors/screen/area.c91
-rw-r--r--source/blender/editors/screen/screen_edit.c2
-rw-r--r--source/blender/editors/screen/screen_ops.c53
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_undo.c12
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c21
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c270
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h19
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c131
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c4
-rw-r--r--source/blender/editors/space_image/image_draw.c5
-rw-r--r--source/blender/editors/space_image/space_image.c9
-rw-r--r--source/blender/editors/space_info/info_stats.c2
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_node/drawnode.c34
-rw-r--r--source/blender/editors/space_outliner/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.c187
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c254
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c253
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h34
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c1
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c433
-rw-r--r--source/blender/editors/space_outliner/outliner_sync.c548
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c124
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c15
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.c140
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c21
-rw-r--r--source/blender/editors/space_sequencer/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c5
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c23
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c7
-rw-r--r--source/blender/editors/space_text/space_text.c2
-rw-r--r--source/blender/editors/space_text/text_draw.c14
-rw-r--r--source/blender/editors/space_text/text_format.c38
-rw-r--r--source/blender/editors/space_text/text_ops.c42
-rw-r--r--source/blender/editors/space_text/text_undo.c1
-rw-r--r--source/blender/editors/space_view3d/drawobject.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_camera_control.c3
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c9
-rw-r--r--source/blender/editors/space_view3d/view3d_draw_legacy.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c16
-rw-r--r--source/blender/editors/space_view3d/view3d_fly.c50
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate.c17
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c208
-rw-r--r--source/blender/editors/space_view3d/view3d_utils.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c60
-rw-r--r--source/blender/editors/transform/transform.c9
-rw-r--r--source/blender/editors/transform/transform_constraints.c2
-rw-r--r--source/blender/editors/transform/transform_conversions.c140
-rw-r--r--source/blender/editors/transform/transform_input.c2
-rw-r--r--source/blender/editors/transform/transform_snap.c9
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c48
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c6
-rw-r--r--source/blender/freestyle/intern/scene_graph/FrsMaterial.h16
-rw-r--r--source/blender/freestyle/intern/scene_graph/IndexedFaceSet.h2
-rw-r--r--source/blender/freestyle/intern/scene_graph/NodeTransform.h6
-rw-r--r--source/blender/freestyle/intern/stroke/AdvancedFunctions1D.h2
-rw-r--r--source/blender/freestyle/intern/stroke/Curve.h2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c43
-rw-r--r--source/blender/gpu/CMakeLists.txt1
-rw-r--r--source/blender/gpu/GPU_batch.h8
-rw-r--r--source/blender/gpu/GPU_element.h19
-rw-r--r--source/blender/gpu/GPU_matrix.h12
-rw-r--r--source/blender/gpu/GPU_shader.h4
-rw-r--r--source/blender/gpu/GPU_vertex_buffer.h7
-rw-r--r--source/blender/gpu/GPU_vertex_format.h74
-rw-r--r--source/blender/gpu/intern/gpu_batch.c44
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c25
-rw-r--r--source/blender/gpu/intern/gpu_context.cpp18
-rw-r--r--source/blender/gpu/intern/gpu_context_private.h2
-rw-r--r--source/blender/gpu/intern/gpu_element.c100
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c1
-rw-r--r--source/blender/gpu/intern/gpu_immediate.c6
-rw-r--r--source/blender/gpu/intern/gpu_matrix.c91
-rw-r--r--source/blender/gpu/intern/gpu_matrix_private.h35
-rw-r--r--source/blender/gpu/intern/gpu_texture.c2
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format.c144
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format_private.h1
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl11
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl352
-rw-r--r--source/blender/imbuf/IMB_imbuf.h3
-rw-r--r--source/blender/imbuf/intern/imageprocess.c12
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp6
-rw-r--r--source/blender/imbuf/intern/scaling.c4
-rw-r--r--source/blender/makesdna/DNA_documentation.h2
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h5
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h2
-rw-r--r--source/blender/makesdna/DNA_material_types.h12
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h5
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h4
-rw-r--r--source/blender/makesdna/DNA_node_types.h45
-rw-r--r--source/blender/makesdna/DNA_object_force_types.h4
-rw-r--r--source/blender/makesdna/DNA_outliner_types.h4
-rw-r--r--source/blender/makesdna/DNA_scene_types.h18
-rw-r--r--source/blender/makesdna/DNA_screen_types.h7
-rw-r--r--source/blender/makesdna/DNA_space_types.h29
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h1
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h17
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c2
-rw-r--r--source/blender/makesrna/RNA_access.h6
-rw-r--r--source/blender/makesrna/RNA_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_ID.c13
-rw-r--r--source/blender/makesrna/intern/rna_access.c272
-rw-r--r--source/blender/makesrna/intern/rna_armature.c4
-rw-r--r--source/blender/makesrna/intern/rna_collection.c5
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c3
-rw-r--r--source/blender/makesrna/intern/rna_curve.c4
-rw-r--r--source/blender/makesrna/intern/rna_define.c6
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c17
-rw-r--r--source/blender/makesrna/intern/rna_material.c10
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c24
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c76
-rw-r--r--source/blender/makesrna/intern/rna_object.c49
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c25
-rw-r--r--source/blender/makesrna/intern/rna_particle.c6
-rw-r--r--source/blender/makesrna/intern/rna_rna.c135
-rw-r--r--source/blender/makesrna/intern/rna_scene.c68
-rw-r--r--source/blender/makesrna/intern/rna_screen.c11
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c7
-rw-r--r--source/blender/makesrna/intern/rna_space.c24
-rw-r--r--source/blender/makesrna/intern/rna_text.c2
-rw-r--r--source/blender/makesrna/intern/rna_text_api.c10
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c3
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c16
-rw-r--r--source/blender/makesrna/intern/rna_wm.c6
-rw-r--r--source/blender/makesrna/intern/rna_wm_gizmo.c7
-rw-r--r--source/blender/makesrna/intern/rna_wm_gizmo_api.c2
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c5
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c5
-rw-r--r--source/blender/modifiers/intern/MOD_mask.c6
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.c10
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c6
-rw-r--r--source/blender/nodes/CMakeLists.txt3
-rw-r--r--source/blender/nodes/NOD_composite.h1
-rw-r--r--source/blender/nodes/NOD_shader.h2
-rw-r--r--source/blender/nodes/NOD_static_types.h3
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_denoise.c58
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c24
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_clamp.c56
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_holdout.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_map_range.c68
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.c370
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tangent.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_math.c36
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp2
-rw-r--r--source/blender/physics/intern/implicit_blender.c9
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.h4
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_customdata.c6
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_meshdata.c8
-rw-r--r--source/blender/python/generic/idprop_py_api.c5
-rw-r--r--source/blender/python/intern/bpy_app_translations.c2
-rw-r--r--source/blender/python/intern/bpy_operator.c5
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.c2
-rw-r--r--source/blender/python/intern/bpy_props.c4
-rw-r--r--source/blender/python/intern/bpy_rna.c7
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c4
-rw-r--r--source/blender/python/intern/bpy_rna_array.c5
-rw-r--r--source/blender/python/mathutils/mathutils.c148
-rw-r--r--source/blender/python/mathutils/mathutils.h30
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c2
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c6
-rw-r--r--source/blender/python/mathutils/mathutils_geometry.c229
-rw-r--r--source/blender/render/extern/include/RE_pipeline.h2
-rw-r--r--source/blender/render/intern/source/imagetexture.c2
-rw-r--r--source/blender/render/intern/source/pipeline.c15
-rw-r--r--source/blender/windowmanager/CMakeLists.txt1
-rw-r--r--source/blender/windowmanager/WM_api.h10
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c6
-rw-r--r--source/blender/windowmanager/intern/wm_files.c8
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c5
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c389
-rw-r--r--source/blender/windowmanager/intern/wm_splash_screen.c314
-rw-r--r--source/blender/windowmanager/intern/wm_window.c12
-rw-r--r--source/blender/windowmanager/wm.h3
-rw-r--r--source/creator/CMakeLists.txt84
-rw-r--r--source/creator/creator.c6
393 files changed, 16266 insertions, 7770 deletions
diff --git a/source/blender/alembic/ABC_alembic.h b/source/blender/alembic/ABC_alembic.h
index 653382017d6..696e0ff1810 100644
--- a/source/blender/alembic/ABC_alembic.h
+++ b/source/blender/alembic/ABC_alembic.h
@@ -117,6 +117,12 @@ struct Mesh *ABC_read_mesh(struct CacheReader *reader,
const char **err_str,
int flags);
+bool ABC_mesh_topology_changed(struct CacheReader *reader,
+ struct Object *ob,
+ struct Mesh *existing_mesh,
+ const float time,
+ const char **err_str);
+
void CacheReader_incref(struct CacheReader *reader);
void CacheReader_free(struct CacheReader *reader);
diff --git a/source/blender/alembic/intern/abc_customdata.h b/source/blender/alembic/intern/abc_customdata.h
index 0ffafa8848e..52f55a41628 100644
--- a/source/blender/alembic/intern/abc_customdata.h
+++ b/source/blender/alembic/intern/abc_customdata.h
@@ -28,11 +28,11 @@
#include <Alembic/AbcGeom/All.h>
struct CustomData;
-struct Mesh;
struct MLoop;
struct MLoopUV;
struct MPoly;
struct MVert;
+struct Mesh;
using Alembic::Abc::ICompoundProperty;
using Alembic::Abc::OCompoundProperty;
diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc
index 56fb5a68402..f19e0257b1b 100644
--- a/source/blender/alembic/intern/abc_exporter.cc
+++ b/source/blender/alembic/intern/abc_exporter.cc
@@ -241,9 +241,9 @@ Alembic::Abc::TimeSamplingPtr AbcExporter::createTimeSampling(double step)
getShutterSamples(step, true, samples);
- Alembic::Abc::TimeSamplingType ts(
- static_cast<uint32_t>(samples.size()),
- 1.0 / m_settings.scene->r.frs_sec); /* TODO(Sybren): shouldn't we use the FPS macro here? */
+ /* TODO(Sybren): shouldn't we use the FPS macro here? */
+ Alembic::Abc::TimeSamplingType ts(static_cast<uint32_t>(samples.size()),
+ 1.0 / m_settings.scene->r.frs_sec);
return TimeSamplingPtr(new Alembic::Abc::TimeSampling(ts, samples));
}
diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc
index 6647ca83bd6..8728303923a 100644
--- a/source/blender/alembic/intern/abc_mesh.cc
+++ b/source/blender/alembic/intern/abc_mesh.cc
@@ -1131,6 +1131,31 @@ bool AbcMeshReader::accepts_object_type(
return true;
}
+bool AbcMeshReader::topology_changed(Mesh *existing_mesh, const ISampleSelector &sample_sel)
+{
+ IPolyMeshSchema::Sample sample;
+ try {
+ sample = m_schema.getValue(sample_sel);
+ }
+ catch (Alembic::Util::Exception &ex) {
+ printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n",
+ m_iobject.getFullName().c_str(),
+ m_schema.getName().c_str(),
+ sample_sel.getRequestedTime(),
+ ex.what());
+ // A similar error in read_mesh() would just return existing_mesh.
+ return false;
+ }
+
+ const P3fArraySamplePtr &positions = sample.getPositions();
+ const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
+ const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
+
+ return positions->size() != existing_mesh->totvert ||
+ face_counts->size() != existing_mesh->totpoly ||
+ face_indices->size() != existing_mesh->totloop;
+}
+
Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
const ISampleSelector &sample_sel,
int read_flag,
@@ -1162,10 +1187,7 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
ImportSettings settings;
settings.read_flag |= read_flag;
- bool topology_changed = positions->size() != existing_mesh->totvert ||
- face_counts->size() != existing_mesh->totpoly ||
- face_indices->size() != existing_mesh->totloop;
- if (topology_changed) {
+ if (topology_changed(existing_mesh, sample_sel)) {
new_mesh = BKE_mesh_new_nomain_from_template(
existing_mesh, positions->size(), 0, 0, face_indices->size(), face_counts->size());
@@ -1314,7 +1336,7 @@ static void read_subd_sample(const std::string &iobject_full_name,
if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
/* Alembic's 'SubD' scheme is used to store subdivision surfaces, i.e. the pre-subdivision
- * mesh. Currently we don't add a subdivison modifier when we load such data. This code is
+ * mesh. Currently we don't add a subdivision modifier when we load such data. This code is
* assuming that the subdivided surface should be smooth, and sets a flag that will eventually
* mark all polygons as such. */
abc_mesh_data.poly_flag_smooth = true;
diff --git a/source/blender/alembic/intern/abc_mesh.h b/source/blender/alembic/intern/abc_mesh.h
index 859ab121eb6..77686a0204e 100644
--- a/source/blender/alembic/intern/abc_mesh.h
+++ b/source/blender/alembic/intern/abc_mesh.h
@@ -110,6 +110,8 @@ class AbcMeshReader : public AbcObjectReader {
const Alembic::Abc::ISampleSelector &sample_sel,
int read_flag,
const char **err_str);
+ bool topology_changed(Mesh *existing_mesh,
+ const Alembic::Abc::ISampleSelector &sample_sel) override;
private:
void readFaceSetsSample(Main *bmain,
diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_object.cc
index f863fe4fee7..ebebbc0da1e 100644
--- a/source/blender/alembic/intern/abc_object.cc
+++ b/source/blender/alembic/intern/abc_object.cc
@@ -246,6 +246,14 @@ struct Mesh *AbcObjectReader::read_mesh(struct Mesh *existing_mesh,
return existing_mesh;
}
+bool AbcObjectReader::topology_changed(Mesh * /*existing_mesh*/,
+ const Alembic::Abc::ISampleSelector & /*sample_sel*/)
+{
+ /* The default implementation of read_mesh() just returns the original mesh, so never changes the
+ * topology. */
+ return false;
+}
+
void AbcObjectReader::setupObjectTransform(const float time)
{
bool is_constant = false;
diff --git a/source/blender/alembic/intern/abc_object.h b/source/blender/alembic/intern/abc_object.h
index 537f24ab7d6..efe78b9017c 100644
--- a/source/blender/alembic/intern/abc_object.h
+++ b/source/blender/alembic/intern/abc_object.h
@@ -190,6 +190,8 @@ class AbcObjectReader {
const Alembic::Abc::ISampleSelector &sample_sel,
int read_flag,
const char **err_str);
+ virtual bool topology_changed(Mesh *existing_mesh,
+ const Alembic::Abc::ISampleSelector &sample_sel);
/** Reads the object matrix and sets up an object transform if animated. */
void setupObjectTransform(const float time);
diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc
index d63b310fef7..f7ba925530b 100644
--- a/source/blender/alembic/intern/alembic_capi.cc
+++ b/source/blender/alembic/intern/alembic_capi.cc
@@ -937,12 +937,7 @@ void ABC_get_transform(CacheReader *reader, float r_mat[4][4], float time, float
/* ************************************************************************** */
-Mesh *ABC_read_mesh(CacheReader *reader,
- Object *ob,
- Mesh *existing_mesh,
- const float time,
- const char **err_str,
- int read_flag)
+static AbcObjectReader *get_abc_reader(CacheReader *reader, Object *ob, const char **err_str)
{
AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
IObject iobject = abc_reader->iobject();
@@ -958,12 +953,44 @@ Mesh *ABC_read_mesh(CacheReader *reader,
return NULL;
}
+ return abc_reader;
+}
+
+static ISampleSelector sample_selector_for_time(float time)
+{
/* kFloorIndex is used to be compatible with non-interpolating
* properties; they use the floor. */
- ISampleSelector sample_sel(time, ISampleSelector::kFloorIndex);
+ return ISampleSelector(time, ISampleSelector::kFloorIndex);
+}
+
+Mesh *ABC_read_mesh(CacheReader *reader,
+ Object *ob,
+ Mesh *existing_mesh,
+ const float time,
+ const char **err_str,
+ int read_flag)
+{
+ AbcObjectReader *abc_reader = get_abc_reader(reader, ob, err_str);
+ if (abc_reader == NULL) {
+ return NULL;
+ }
+
+ ISampleSelector sample_sel = sample_selector_for_time(time);
return abc_reader->read_mesh(existing_mesh, sample_sel, read_flag, err_str);
}
+bool ABC_mesh_topology_changed(
+ CacheReader *reader, Object *ob, Mesh *existing_mesh, const float time, const char **err_str)
+{
+ AbcObjectReader *abc_reader = get_abc_reader(reader, ob, err_str);
+ if (abc_reader == NULL) {
+ return NULL;
+ }
+
+ ISampleSelector sample_sel = sample_selector_for_time(time);
+ return abc_reader->topology_changed(existing_mesh, sample_sel);
+}
+
/* ************************************************************************** */
void CacheReader_free(CacheReader *reader)
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index 7283ade3ae5..6748a5324ac 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -619,8 +619,8 @@ static void blf_font_draw_buffer_ex(
cbuf[0] = (unsigned char)((b_col_char[0] * a) + (cbuf[0] * (1.0f - a)));
cbuf[1] = (unsigned char)((b_col_char[1] * a) + (cbuf[1] * (1.0f - a)));
cbuf[2] = (unsigned char)((b_col_char[2] * a) + (cbuf[2] * (1.0f - a)));
- cbuf[3] = (unsigned char)MIN2((int)cbuf[3] + (int)(a * 255),
- 255); /* clamp to 255 */
+ /* clamp to 255 */
+ cbuf[3] = (unsigned char)MIN2((int)cbuf[3] + (int)(a * 255), 255);
}
}
}
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index 66be94aaa06..c0a53cbf282 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -329,10 +329,10 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
/* Convert result from 1 bit per pixel to 8 bit per pixel */
/* Accum errors for later, fine if not interested beyond "ok vs any error" */
FT_Bitmap_New(&tempbitmap);
- err += FT_Bitmap_Convert(font->ft_lib,
- &slot->bitmap,
- &tempbitmap,
- 1); /* Does Blender use Pitch 1 always? It works so far */
+
+ /* Does Blender use Pitch 1 always? It works so far */
+ err += FT_Bitmap_Convert(font->ft_lib, &slot->bitmap, &tempbitmap, 1);
+
err += FT_Bitmap_Copy(font->ft_lib, &tempbitmap, &slot->bitmap);
err += FT_Bitmap_Done(font->ft_lib, &tempbitmap);
}
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index ced9f4a3153..0c55ae8ee83 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 1
+#define BLENDER_SUBVERSION 2
/** Several breakages with 280, e.g. collections vs layers. */
#define BLENDER_MINVERSION 280
#define BLENDER_MINSUBVERSION 0
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index 53976b4c1ad..755a155653b 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -137,8 +137,8 @@ void CTX_store_free(bContextStore *store);
void CTX_store_free_list(ListBase *contexts);
/* need to store if python is initialized or not */
-int CTX_py_init_get(bContext *C);
-void CTX_py_init_set(bContext *C, int value);
+bool CTX_py_init_get(bContext *C);
+void CTX_py_init_set(bContext *C, bool value);
void *CTX_py_dict_get(const bContext *C);
void CTX_py_dict_set(bContext *C, void *value);
diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h
index bfdeadc7f60..f87c73e35a2 100644
--- a/source/blender/blenkernel/BKE_mask.h
+++ b/source/blender/blenkernel/BKE_mask.h
@@ -171,7 +171,6 @@ void BKE_mask_coord_to_image(struct Image *image,
/* parenting */
-void BKE_mask_evaluate_all_masks(struct Main *bmain, float ctime, const bool do_newframe);
void BKE_mask_evaluate(struct Mask *mask, const float ctime, const bool do_newframe);
void BKE_mask_layer_evaluate(struct MaskLayer *masklay, const float ctime, const bool do_newframe);
void BKE_mask_parent_init(struct MaskParent *parent);
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index b1200c7e608..44a8f98e994 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -28,12 +28,12 @@
extern "C" {
#endif
-struct bNode;
struct ID;
struct Main;
struct Material;
struct Object;
struct Scene;
+struct bNode;
/* materials */
@@ -103,9 +103,9 @@ void BKE_material_resize_id(struct Main *bmain, struct ID *id, short totcol, boo
void BKE_material_append_id(struct Main *bmain, struct ID *id, struct Material *ma);
struct Material *BKE_material_pop_id(struct Main *bmain,
struct ID *id,
- int index,
- bool update_data); /* index is an int because of RNA */
-void BKE_material_clear_id(struct Main *bmain, struct ID *id, bool update_data);
+ /* index is an int because of RNA. */
+ int index);
+void BKE_material_clear_id(struct Main *bmain, struct ID *id);
/* rendering */
void ramp_blend(int type, float r_col[3], const float fac, const float col[3]);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 924cfad37d6..94d118bde36 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -486,6 +486,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_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,
const struct MVert *mvarray,
diff --git a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h
new file mode 100644
index 00000000000..089e4de4709
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mesh_remesh_voxel.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) 2019 by Blender Foundation
+ * All rights reserved.
+ */
+#ifndef __BKE_REMESH_H__
+#define __BKE_REMESH_H__
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifdef WITH_OPENVDB
+# include "openvdb_capi.h"
+#endif
+
+struct Mesh;
+
+/* OpenVDB Voxel Remesher */
+#ifdef WITH_OPENVDB
+struct OpenVDBLevelSet *BKE_mesh_remesh_voxel_ovdb_mesh_to_level_set_create(
+ struct Mesh *mesh, struct OpenVDBTransform *transform);
+struct Mesh *BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(struct OpenVDBLevelSet *level_set,
+ double isovalue,
+ double adaptivity,
+ bool relax_disoriented_triangles);
+#endif
+struct Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(struct Mesh *mesh, float voxel_size);
+
+/* Data reprojection functions */
+void BKE_remesh_reproject_paint_mask(struct Mesh *target, struct Mesh *source);
+
+#endif /* __BKE_REMESH_H__ */
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 8a107aac538..7d427cb7799 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -310,9 +310,8 @@ typedef struct bNodeTreeType {
/* callbacks */
void (*free_cache)(struct bNodeTree *ntree);
void (*free_node_cache)(struct bNodeTree *ntree, struct bNode *node);
- void (*foreach_nodeclass)(struct Scene *scene,
- void *calldata,
- bNodeClassCallback func); /* iteration over all node classes */
+ /* Iteration over all node classes. */
+ void (*foreach_nodeclass)(struct Scene *scene, void *calldata, bNodeClassCallback func);
/* Check visibility in the node editor */
bool (*poll)(const struct bContext *C, struct bNodeTreeType *ntreetype);
/* Select a node tree from the context */
@@ -616,6 +615,7 @@ void nodeUpdateInternalLinks(struct bNodeTree *ntree, struct bNode *node);
int nodeSocketIsHidden(struct bNodeSocket *sock);
void ntreeTagUsedSockets(struct bNodeTree *ntree);
+void nodeSetSocketAvailability(struct bNodeSocket *sock, bool is_available);
/* Node Clipboard */
void BKE_node_clipboard_init(struct bNodeTree *ntree);
@@ -976,6 +976,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
#define SH_NODE_VOLUME_PRINCIPLED 200
/* 201..700 occupied by other node types, continue from 701 */
#define SH_NODE_BSDF_HAIR_PRINCIPLED 701
+#define SH_NODE_MAP_RANGE 702
+#define SH_NODE_CLAMP 703
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1
@@ -1128,6 +1130,7 @@ void ntreeGPUMaterialNodes(struct bNodeTree *localtree,
#define CMP_NODE_CORNERPIN 321
#define CMP_NODE_SWITCH_VIEW 322
#define CMP_NODE_CRYPTOMATTE 323
+#define CMP_NODE_DENOISE 324
/* channel toggles */
#define CMP_CHAN_RGB 1
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index cbe250d0ac8..37667599488 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -259,6 +259,8 @@ typedef struct SculptSession {
struct StrokeCache *cache;
+ int active_vertex_index;
+
union {
struct {
struct SculptVertexPaintGeomMap gmap;
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 3806868e060..62544efad2c 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -301,6 +301,7 @@ typedef struct PBVHVertexIter {
int gx;
int gy;
int i;
+ int index;
/* grid */
struct CCGElem **grids;
@@ -369,6 +370,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo
continue; \
vi.co = vi.mvert->co; \
vi.no = vi.mvert->no; \
+ vi.index = vi.vert_indices[vi.i]; \
if (vi.vmask) \
vi.mask = &vi.vmask[vi.vert_indices[vi.gx]]; \
} \
@@ -385,6 +387,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo
continue; \
vi.co = vi.bm_vert->co; \
vi.fno = vi.bm_vert->no; \
+ vi.index = BM_elem_index_get(vi.bm_vert); \
vi.mask = BM_ELEM_CD_GET_VOID_P(vi.bm_vert, vi.cd_vert_mask_offset); \
}
diff --git a/source/blender/blenkernel/BKE_writeavi.h b/source/blender/blenkernel/BKE_writeavi.h
index 3212bad75cb..7fc740a4a9b 100644
--- a/source/blender/blenkernel/BKE_writeavi.h
+++ b/source/blender/blenkernel/BKE_writeavi.h
@@ -53,10 +53,10 @@ typedef struct bMovieHandle {
const char *suffix,
struct ReportList *reports);
void (*end_movie)(void *context_v);
- void (*get_movie_path)(char *string,
- struct RenderData *rd,
- bool preview,
- const char *suffix); /* optional */
+
+ /* Optional function. */
+ void (*get_movie_path)(char *string, struct RenderData *rd, bool preview, const char *suffix);
+
void *(*context_create)(void);
void (*context_free)(void *context_v);
} bMovieHandle;
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index d9bd87d97b5..669abff6599 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -151,6 +151,7 @@ set(SRC
intern/mesh_mapping.c
intern/mesh_merge.c
intern/mesh_remap.c
+ intern/mesh_remesh_voxel.c
intern/mesh_runtime.c
intern/mesh_tangent.c
intern/mesh_validate.c
@@ -300,6 +301,7 @@ set(SRC
BKE_mesh_iterators.h
BKE_mesh_mapping.h
BKE_mesh_remap.h
+ BKE_mesh_remesh_voxel.h
BKE_mesh_runtime.h
BKE_mesh_tangent.h
BKE_modifier.h
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 57a7379eeae..d072a0aa599 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -1420,9 +1420,7 @@ short action_get_item_transforms(bAction *act, Object *ob, bPoseChannel *pchan,
if ((curves) || (flags & ACT_TRANS_PROP) == 0) {
/* custom properties only */
- pPtr = strstr(
- bPtr,
- "[\""); /* extra '"' comment here to keep my texteditor functionlist working :) */
+ pPtr = strstr(bPtr, "[\"");
if (pPtr) {
flags |= ACT_TRANS_PROP;
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 742e3634bf1..ea927ca9333 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -2707,8 +2707,9 @@ void BKE_pose_where_is_bone(struct Depsgraph *depsgraph,
cob = BKE_constraints_make_evalob(depsgraph, scene, ob, pchan, CONSTRAINT_OBTYPE_BONE);
/* Solve PoseChannel's Constraints */
- BKE_constraints_solve(
- depsgraph, &pchan->constraints, cob, ctime); /* ctime doesn't alter objects */
+
+ /* ctime doesn't alter objects. */
+ BKE_constraints_solve(depsgraph, &pchan->constraints, cob, ctime);
/* cleanup after Constraint Solving
* - applies matrix back to pchan, and frees temporary struct used
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index bf7d81e5d63..cd1cdce91e0 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -889,7 +889,7 @@ void BKE_pose_eval_proxy_copy_bone(struct Depsgraph *depsgraph, Object *object,
bPoseChannel *pchan = pose_pchan_get_indexed(object, pchan_index);
DEG_debug_print_eval_subdata(
depsgraph, __func__, object->id.name, object, "pchan", pchan->name, pchan);
- /* TODO(sergey): Use indexec lookup, once it's guaranteed to be kept
+ /* TODO(sergey): Use indexed lookup, once it's guaranteed to be kept
* around for the time while proxies are evaluating.
*/
#if 0
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 25f2797915a..2031576190e 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -239,8 +239,9 @@ static Collection *collection_duplicate_recursive(Main *bmain,
if (!do_hierarchy || collection_old->id.newid == NULL) {
BKE_id_copy(bmain, &collection_old->id, (ID **)&collection_new);
- id_us_min(
- &collection_new->id); /* Copying add one user by default, need to get rid of that one. */
+
+ /* Copying add one user by default, need to get rid of that one. */
+ id_us_min(&collection_new->id);
if (do_hierarchy) {
ID_NEW_SET(collection_old, collection_new);
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 2cb98d8d90b..f536f21c3e5 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -89,7 +89,8 @@ struct bContext {
struct Scene *scene;
int recursion;
- int py_init; /* true if python is initialized */
+ /** True if python is initialized. */
+ bool py_init;
void *py_context;
} data;
};
@@ -212,11 +213,11 @@ void CTX_store_free_list(ListBase *contexts)
/* is python initialized? */
-int CTX_py_init_get(bContext *C)
+bool CTX_py_init_get(bContext *C)
{
return C->data.py_init;
}
-void CTX_py_init_set(bContext *C, int value)
+void CTX_py_init_set(bContext *C, bool value)
{
C->data.py_init = value;
}
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index efdfa2c19bb..980e8043a42 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -2737,8 +2737,10 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
/* check if we will calculate tilt data */
do_tilt = CU_DO_TILT(cu, nu);
- do_radius = CU_DO_RADIUS(
- cu, nu); /* normal display uses the radius, better just to calculate them */
+
+ /* Normal display uses the radius, better just to calculate them. */
+ do_radius = CU_DO_RADIUS(cu, nu);
+
do_weight = true;
/* check we are a single point? also check we are not a surface and that the orderu is sane,
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 3c7ac5d8d2e..db0ed0dc0fb 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -294,7 +294,7 @@ static void layerInterp_mdeformvert(const void **sources,
}
}
- /* delay writing to the destination incase dest is in sources */
+ /* Delay writing to the destination in case dest is in sources. */
/* now we know how many unique deform weights there are, so realloc */
if (dvert->dw && (dvert->totweight == totweight)) {
@@ -441,7 +441,7 @@ static void layerInterp_tface(
}
}
- /* delay writing to the destination incase dest is in sources */
+ /* Delay writing to the destination in case dest is in sources. */
*tf = *(MTFace *)(*sources);
memcpy(tf->uv, uv, sizeof(tf->uv));
}
@@ -548,7 +548,7 @@ static void layerInterp_origspace_face(
}
}
- /* delay writing to the destination in case dest is in sources */
+ /* Delay writing to the destination in case dest is in sources. */
memcpy(osf->uv, uv, sizeof(osf->uv));
}
@@ -908,7 +908,7 @@ static void layerInterp_mloopcol(
/* Subdivide smooth or fractal can cause problems without clamping
* although weights should also not cause this situation */
- /* also delay writing to the destination incase dest is in sources */
+ /* Also delay writing to the destination in case dest is in sources. */
mc->r = round_fl_to_uchar_clamp(col.r);
mc->g = round_fl_to_uchar_clamp(col.g);
mc->b = round_fl_to_uchar_clamp(col.b);
@@ -1008,7 +1008,7 @@ static void layerInterp_mloopuv(
}
}
- /* delay writing to the destination incase dest is in sources */
+ /* Delay writing to the destination in case dest is in sources. */
copy_v2_v2(((MLoopUV *)dest)->uv, uv);
((MLoopUV *)dest)->flag = flag;
}
@@ -1104,7 +1104,7 @@ static void layerInterp_mloop_origspace(
}
}
- /* delay writing to the destination incase dest is in sources */
+ /* Delay writing to the destination in case dest is in sources. */
copy_v2_v2(((OrigSpaceLoop *)dest)->uv, uv);
}
/* --- end copy */
@@ -1152,7 +1152,7 @@ static void layerInterp_mcol(
}
}
- /* delay writing to the destination incase dest is in sources */
+ /* Delay writing to the destination in case dest is in sources. */
for (j = 0; j < 4; ++j) {
/* Subdivide smooth or fractal can cause problems without clamping
@@ -1220,7 +1220,7 @@ static void layerInterp_bweight(const void **sources,
}
}
- /* delay writing to the destination incase dest is in sources */
+ /* Delay writing to the destination in case dest is in sources. */
*((float *)dest) = f;
}
@@ -1251,7 +1251,7 @@ static void layerInterp_shapekey(const void **sources,
}
}
- /* delay writing to the destination incase dest is in sources */
+ /* Delay writing to the destination in case dest is in sources. */
copy_v3_v3((float *)dest, co);
}
@@ -1289,7 +1289,7 @@ static void layerInterp_mvert_skin(const void **sources,
madd_v3_v3fl(radius, vs_src->radius, w);
}
- /* delay writing to the destination incase dest is in sources */
+ /* Delay writing to the destination in case dest is in sources. */
vs_dst = dest;
copy_v3_v3(vs_dst->radius, radius);
vs_dst->flag &= ~MVERT_SKIN_ROOT;
@@ -2828,9 +2828,7 @@ void CustomData_interp(const CustomData *source,
const void *source_buf[SOURCE_BUF_SIZE];
const void **sources = source_buf;
- /* slow fallback in case we're interpolating a ridiculous number of
- * elements
- */
+ /* Slow fallback in case we're interpolating a ridiculous number of elements. */
if (count > SOURCE_BUF_SIZE) {
sources = MEM_malloc_arrayN(count, sizeof(*sources), __func__);
}
@@ -3828,9 +3826,7 @@ void CustomData_bmesh_interp(CustomData *data,
void *source_buf[SOURCE_BUF_SIZE];
const void **sources = (const void **)source_buf;
- /* slow fallback in case we're interpolating a ridiculous number of
- * elements
- */
+ /* Slow fallback in case we're interpolating a ridiculous number of elements. */
if (count > SOURCE_BUF_SIZE) {
sources = MEM_malloc_arrayN(count, sizeof(*sources), __func__);
}
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 1fb25375159..04cbdbb6bcd 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -4061,8 +4061,10 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
hit_found = HIT_VOLUME;
/* Mark hit info */
- madd_v3_v3v3fl(
- hitCoord, ray_start, ray_dir, hit.dist); /* Calculate final hit coordinates */
+
+ /* Calculate final hit coordinates */
+ madd_v3_v3v3fl(hitCoord, ray_start, ray_dir, hit.dist);
+
depth += dist * sample_factor;
hitTri = f_index;
}
@@ -4113,8 +4115,10 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
treeData->tree, ray_start, proj_ray, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
if (hit.index != -1) {
proxDist = hit.dist;
- madd_v3_v3v3fl(
- hitCo, ray_start, proj_ray, hit.dist); /* Calculate final hit coordinates */
+
+ /* Calculate final hit coordinates */
+ madd_v3_v3v3fl(hitCo, ray_start, proj_ray, hit.dist);
+
tri = hit.index;
}
}
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index b8234ccc5bb..1c3f6a56629 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -61,11 +61,10 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
/* The tessellation is NOT calculated on the copy here,
* because currently all the callers of this function use
- * it to make a backup copy of the BMEditMesh to restore
- * it in the case of errors in an operation. For perf
- * reasons, in that case it makes more sense to do the
- * tessellation only when/if that copy ends up getting
- * used.*/
+ * it to make a backup copy of the #BMEditMesh to restore
+ * it in the case of errors in an operation. For performance reasons,
+ * in that case it makes more sense to do the
+ * tessellation only when/if that copy ends up getting used. */
em_copy->looptris = NULL;
return em_copy;
@@ -97,8 +96,8 @@ static void editmesh_tessface_calc_intern(BMEditMesh *em)
BMesh *bm = em->bm;
- /* this assumes all faces can be scan-filled, which isn't always true,
- * worst case we over alloc a little which is acceptable */
+ /* This assumes all faces can be scan-filled, which isn't always true,
+ * worst case we over allocate a little which is acceptable. */
const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
const int looptris_tot_prev_alloc = em->looptris ?
(MEM_allocN_len(em->looptris) / sizeof(*em->looptris)) :
@@ -109,7 +108,7 @@ static void editmesh_tessface_calc_intern(BMEditMesh *em)
/* this means no reallocs for quad dominant models, for */
if ((em->looptris != NULL) &&
/* (*em->tottri >= looptris_tot)) */
- /* check against alloc'd size incase we over alloc'd a little */
+ /* Check against allocated size in case we over allocated a little. */
((looptris_tot_prev_alloc >= looptris_tot) &&
(looptris_tot_prev_alloc <= looptris_tot * 2))) {
looptris = em->looptris;
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 7cbd5b6b050..ffab82b75af 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -1338,8 +1338,9 @@ void BKE_sim_debug_data_clear_category(const char *category)
BLI_ghashIterator_init(&iter, _sim_debug_data->gh);
while (!BLI_ghashIterator_done(&iter)) {
const SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
- BLI_ghashIterator_step(
- &iter); /* removing invalidates the current iterator, so step before removing */
+
+ /* Removing invalidates the current iterator, so step before removing. */
+ BLI_ghashIterator_step(&iter);
if (elem->category_hash == category_hash) {
BLI_ghash_remove(_sim_debug_data->gh, elem, NULL, debug_element_free);
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 140d1f0d26c..9580ea763fb 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -506,8 +506,10 @@ static int binarysearch_bezt_index_ex(
*/
for (loopbreaker = 0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
/* compute and get midpoint */
- int mid = start + ((end - start) /
- 2); /* we calculate the midpoint this way to avoid int overflows... */
+
+ /* We calculate the midpoint this way to avoid int overflows... */
+ int mid = start + ((end - start) / 2);
+
float midfra = array[mid].vec[1][0];
/* check if exactly equal to midpoint */
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
index 4295a44098c..48c0258bf47 100644
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -555,8 +555,10 @@ int BKE_fcm_envelope_find_index(FCM_EnvelopeData array[],
*/
for (loopbreaker = 0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
/* compute and get midpoint */
- int mid = start + ((end - start) /
- 2); /* we calculate the midpoint this way to avoid int overflows... */
+
+ /* we calculate the midpoint this way to avoid int overflows... */
+ int mid = start + ((end - start) / 2);
+
float midfra = array[mid].time;
/* check if exactly equal to midpoint */
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index 78117a4f615..b55635560be 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -955,7 +955,7 @@ static bool vfont_to_curve(Object *ob,
}
}
- current_line_length += xof;
+ current_line_length += xof - MARGIN_X_MIN;
if (ct->dobreak) {
current_line_length += twidth;
}
@@ -1026,7 +1026,7 @@ static bool vfont_to_curve(Object *ob,
}
ct++;
}
- current_line_length += xof + twidth;
+ current_line_length += xof + twidth - MARGIN_X_MIN;
longest_line_length = MAX2(current_line_length, longest_line_length);
cu->lines = 1;
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index ed4c6848751..0354aeaf0ca 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -642,8 +642,10 @@ void BKE_gpencil_copy_data(bGPdata *gpd_dst, const bGPdata *gpd_src, const int U
BLI_listbase_clear(&gpd_dst->layers);
for (const bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
/* make a copy of source layer and its data */
- bGPDlayer *gpl_dst = BKE_gpencil_layer_duplicate(
- gpl_src); /* TODO here too could add unused flags... */
+
+ /* TODO here too could add unused flags... */
+ bGPDlayer *gpl_dst = BKE_gpencil_layer_duplicate(gpl_src);
+
BLI_addtail(&gpd_dst->layers, gpl_dst);
}
}
@@ -1782,33 +1784,55 @@ bool BKE_gpencil_smooth_stroke_strength(bGPDstroke *gps, int point_index, float
bGPDspoint *ptb = &gps->points[point_index];
/* Do nothing if not enough points */
- if (gps->totpoints <= 2) {
+ if ((gps->totpoints <= 2) || (point_index < 1)) {
return false;
}
+ /* Only affect endpoints by a fraction of the normal influence */
+ float inf = influence;
+ if ((point_index == 0) || (point_index == gps->totpoints - 1)) {
+ inf *= 0.01f;
+ }
+ /* Limit max influence to reduce pop effect. */
+ CLAMP_MAX(inf, 0.98f);
- /* Compute theoretical optimal value using distances */
- bGPDspoint *pta, *ptc;
- int before = point_index - 1;
- int after = point_index + 1;
+ float total = 0.0f;
+ float max_strength = 0.0f;
+ const int steps = 4;
+ const float average_fac = 1.0f / (float)(steps * 2 + 1);
+ int step;
- CLAMP_MIN(before, 0);
- CLAMP_MAX(after, gps->totpoints - 1);
+ /* add the point itself */
+ total += ptb->strength * average_fac;
+ max_strength = ptb->strength;
- pta = &gps->points[before];
- ptc = &gps->points[after];
+ /* n-steps before/after current point */
+ for (step = 1; step <= steps; step++) {
+ bGPDspoint *pt1, *pt2;
+ int before = point_index - step;
+ int after = point_index + step;
- /* the optimal value is the corresponding to the interpolation of the strength
- * at the distance of point b
- */
- float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
- /* sometimes the factor can be wrong due stroke geometry, so use middle point */
- if ((fac < 0.0f) || (fac > 1.0f)) {
- fac = 0.5f;
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pt1 = &gps->points[before];
+ pt2 = &gps->points[after];
+
+ /* add both these points to the average-sum (s += p[i]/n) */
+ total += pt1->strength * average_fac;
+ total += pt2->strength * average_fac;
+ /* Save max value. */
+ if (max_strength < pt1->strength) {
+ max_strength = pt1->strength;
+ }
+ if (max_strength < pt2->strength) {
+ max_strength = pt2->strength;
+ }
}
- const float optimal = (1.0f - fac) * pta->strength + fac * ptc->strength;
- /* Based on influence factor, blend between original and optimal */
- ptb->strength = (1.0f - influence) * ptb->strength + influence * optimal;
+ /* Based on influence factor, blend between original and optimal smoothed value. */
+ ptb->strength = interpf(ptb->strength, total, inf);
+ /* Clamp to maximum stroke strength to avoid weird results. */
+ CLAMP_MAX(ptb->strength, max_strength);
return true;
}
@@ -1823,31 +1847,52 @@ bool BKE_gpencil_smooth_stroke_thickness(bGPDstroke *gps, int point_index, float
if ((gps->totpoints <= 2) || (point_index < 1)) {
return false;
}
+ /* Only affect endpoints by a fraction of the normal influence */
+ float inf = influence;
+ if ((point_index == 0) || (point_index == gps->totpoints - 1)) {
+ inf *= 0.01f;
+ }
+ /* Limit max influence to reduce pop effect. */
+ CLAMP_MAX(inf, 0.98f);
- /* Compute theoretical optimal value using distances */
- bGPDspoint *pta, *ptc;
- int before = point_index - 1;
- int after = point_index + 1;
+ float total = 0.0f;
+ float max_pressure = 0.0f;
+ const int steps = 4;
+ const float average_fac = 1.0f / (float)(steps * 2 + 1);
+ int step;
- CLAMP_MIN(before, 0);
- CLAMP_MAX(after, gps->totpoints - 1);
+ /* add the point itself */
+ total += ptb->pressure * average_fac;
+ max_pressure = ptb->pressure;
- pta = &gps->points[before];
- ptc = &gps->points[after];
+ /* n-steps before/after current point */
+ for (step = 1; step <= steps; step++) {
+ bGPDspoint *pt1, *pt2;
+ int before = point_index - step;
+ int after = point_index + step;
- /* the optimal value is the corresponding to the interpolation of the pressure
- * at the distance of point b
- */
- float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
- /* sometimes the factor can be wrong due stroke geometry, so use middle point */
- if ((fac < 0.0f) || (fac > 1.0f)) {
- fac = 0.5f;
- }
- float optimal = interpf(ptc->pressure, pta->pressure, fac);
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
- /* Based on influence factor, blend between original and optimal */
- ptb->pressure = interpf(optimal, ptb->pressure, influence);
+ pt1 = &gps->points[before];
+ pt2 = &gps->points[after];
+
+ /* add both these points to the average-sum (s += p[i]/n) */
+ total += pt1->pressure * average_fac;
+ total += pt2->pressure * average_fac;
+ /* Save max value. */
+ if (max_pressure < pt1->pressure) {
+ max_pressure = pt1->pressure;
+ }
+ if (max_pressure < pt2->pressure) {
+ max_pressure = pt2->pressure;
+ }
+ }
+ /* Based on influence factor, blend between original and optimal smoothed value. */
+ ptb->pressure = interpf(ptb->pressure, total, inf);
+ /* Clamp to maximum stroke thickness to avoid weird results. */
+ CLAMP_MAX(ptb->pressure, max_pressure);
return true;
}
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 8e04ef2d3ca..a99407b9bf9 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -2766,8 +2766,8 @@ static void do_makepicstring(char *string,
int frame,
const char imtype,
const ImageFormatData *im_format,
- const short use_ext,
- const short use_frames,
+ const bool use_ext,
+ const bool use_frames,
const char *suffix)
{
if (string == NULL) {
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index 40608285785..de105b9b62a 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -494,6 +494,36 @@ static LayerCollection *collection_from_index(ListBase *lb, const int number, in
}
/**
+ * Determine if a collection is hidden, viewport visibility restricted, or excluded
+ */
+static bool layer_collection_hidden(ViewLayer *view_layer, LayerCollection *lc)
+{
+ if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
+ return true;
+ }
+
+ /* Check visiblilty restriction flags */
+ if (lc->flag & LAYER_COLLECTION_HIDE || lc->collection->flag & COLLECTION_RESTRICT_VIEWPORT) {
+ return true;
+ }
+ else {
+ /* Restriction flags stay set, so we need to check parents */
+ CollectionParent *parent = lc->collection->parents.first;
+
+ if (parent) {
+ lc = BKE_layer_collection_first_from_scene_collection(view_layer, parent->collection);
+
+ return lc && layer_collection_hidden(view_layer, lc);
+ }
+ else {
+ return false;
+ }
+ }
+
+ return false;
+}
+
+/**
* Get the collection for a given index
*/
LayerCollection *BKE_layer_collection_from_index(ViewLayer *view_layer, const int index)
@@ -537,8 +567,9 @@ LayerCollection *BKE_layer_collection_activate_parent(ViewLayer *view_layer, Lay
lc = NULL;
}
- if (lc && (lc->flag & LAYER_COLLECTION_EXCLUDE)) {
- /* Don't activate excluded collections. */
+ /* Don't activate excluded or hidden collections to prevent creating objects in a hidden
+ * collection from the UI */
+ if (lc && layer_collection_hidden(view_layer, lc)) {
return BKE_layer_collection_activate_parent(view_layer, lc);
}
@@ -817,8 +848,7 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
/* Always set a valid active collection. */
LayerCollection *active = view_layer->active_collection;
-
- if (active && (active->flag & LAYER_COLLECTION_EXCLUDE)) {
+ if (active && layer_collection_hidden(view_layer, active)) {
BKE_layer_collection_activate_parent(view_layer, active);
}
else if (active == NULL) {
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index de6f5142a19..2dbca3b4db1 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -1727,8 +1727,8 @@ bool BKE_id_new_name_validate(ListBase *lb, ID *id, const char *tname)
/* This was in 2.43 and previous releases
* however all data in blender should be sorted, not just duplicate names
- * sorting should not hurt, but noting just incase it alters the way other
- * functions work, so sort every time */
+ * sorting should not hurt, but noting just in case it alters the way other
+ * functions work, so sort every time. */
#if 0
if (result) {
id_sort_by_name(lb, id);
diff --git a/source/blender/blenkernel/intern/library_override.c b/source/blender/blenkernel/intern/library_override.c
index fed90ad8982..e435f07e38d 100644
--- a/source/blender/blenkernel/intern/library_override.c
+++ b/source/blender/blenkernel/intern/library_override.c
@@ -703,9 +703,9 @@ void BKE_override_library_update(Main *bmain, ID *local)
local->tag |= LIB_TAG_OVERRIDE_LIBRARY_REFOK;
/* Full rebuild of Depsgraph! */
- DEG_on_visible_update(
- bmain,
- true); /* XXX Is this actual valid replacement for old DAG_relations_tag_update(bmain) ? */
+
+ /* XXX Is this actual valid replacement for old DAG_relations_tag_update(bmain) ? */
+ DEG_on_visible_update(bmain, true);
}
/** Update all overrides from given \a bmain. */
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index bf77c1417ea..ca3da0d89c7 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -1168,10 +1168,8 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
case ID_CA:
return ELEM(id_type_used, ID_OB);
case ID_KE:
- return ELEM(id_type_used,
- ID_ME,
- ID_CU,
- ID_LT); /* Warning! key->from, could be more types in future? */
+ /* Warning! key->from, could be more types in future? */
+ return ELEM(id_type_used, ID_ME, ID_CU, ID_LT);
case ID_SCR:
return ELEM(id_type_used, ID_SCE);
case ID_WO:
@@ -1190,7 +1188,8 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
case ID_MC:
return ELEM(id_type_used, ID_GD, ID_IM);
case ID_MSK:
- return ELEM(id_type_used, ID_MC); /* WARNING! mask->parent.id, not typed. */
+ /* WARNING! mask->parent.id, not typed. */
+ return ELEM(id_type_used, ID_MC);
case ID_LS:
return (ELEM(id_type_used, ID_TE, ID_OB));
case ID_LP:
diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c
index 170b8d0ab93..8e2c3a11ac0 100644
--- a/source/blender/blenkernel/intern/main.c
+++ b/source/blender/blenkernel/intern/main.c
@@ -485,16 +485,23 @@ int set_listbasepointers(Main *bmain, ListBase **lb)
/* BACKWARDS! also watch order of free-ing! (mesh<->mat), first items freed last.
* This is important because freeing data decreases user-counts of other data-blocks,
* if this data is its self freed it can crash. */
- lb[INDEX_ID_LI] = &(
- bmain->libraries); /* Libraries may be accessed from pretty much any other ID... */
+
+ /* Libraries may be accessed from pretty much any other ID. */
+ lb[INDEX_ID_LI] = &(bmain->libraries);
+
lb[INDEX_ID_IP] = &(bmain->ipo);
- lb[INDEX_ID_AC] = &(
- bmain->actions); /* moved here to avoid problems when freeing with animato (aligorith) */
+
+ /* Moved here to avoid problems when freeing with animato (aligorith). */
+ lb[INDEX_ID_AC] = &(bmain->actions);
+
lb[INDEX_ID_KE] = &(bmain->shapekeys);
- lb[INDEX_ID_PAL] = &(
- bmain->palettes); /* referenced by gpencil, so needs to be before that to avoid crashes */
- lb[INDEX_ID_GD] = &(
- bmain->gpencils); /* referenced by nodes, objects, view, scene etc, before to free after. */
+
+ /* Referenced by gpencil, so needs to be before that to avoid crashes. */
+ lb[INDEX_ID_PAL] = &(bmain->palettes);
+
+ /* Referenced by nodes, objects, view, scene etc, before to free after. */
+ lb[INDEX_ID_GD] = &(bmain->gpencils);
+
lb[INDEX_ID_NT] = &(bmain->nodetrees);
lb[INDEX_ID_IM] = &(bmain->images);
lb[INDEX_ID_TE] = &(bmain->textures);
@@ -502,8 +509,7 @@ int set_listbasepointers(Main *bmain, ListBase **lb)
lb[INDEX_ID_VF] = &(bmain->fonts);
/* Important!: When adding a new object type,
- * the specific data should be inserted here
- */
+ * the specific data should be inserted here. */
lb[INDEX_ID_AR] = &(bmain->armatures);
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index bb93d068bef..fc087ff91b2 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -892,8 +892,8 @@ void BKE_mask_copy_data(Main *UNUSED(bmain),
{
BLI_listbase_clear(&mask_dst->masklayers);
- BKE_mask_layer_copy_list(&mask_dst->masklayers,
- &mask_src->masklayers); /* TODO add unused flag to those as well. */
+ /* TODO add unused flag to those as well. */
+ BKE_mask_layer_copy_list(&mask_dst->masklayers, &mask_src->masklayers);
/* enable fake user by default */
id_fake_user_set(&mask_dst->id);
@@ -1469,15 +1469,6 @@ void BKE_mask_evaluate(Mask *mask, const float ctime, const bool do_newframe)
}
}
-void BKE_mask_evaluate_all_masks(Main *bmain, float ctime, const bool do_newframe)
-{
- Mask *mask;
-
- for (mask = bmain->masks.first; mask; mask = mask->id.next) {
- BKE_mask_evaluate(mask, ctime, do_newframe);
- }
-}
-
void BKE_mask_parent_init(MaskParent *parent)
{
parent->id_type = ID_MC;
@@ -1637,7 +1628,9 @@ MaskLayerShape *BKE_mask_layer_shape_find_frame(MaskLayer *masklay, const int fr
return NULL;
}
-/* when returning 2 - the frame isnt found but before/after frames are */
+/**
+ * When returning 2 - the frame isn't found but before/after frames are.
+ */
int BKE_mask_layer_shape_find_frame_range(MaskLayer *masklay,
const float frame,
MaskLayerShape **r_masklay_shape_a,
@@ -1775,10 +1768,10 @@ static void interp_weights_uv_v2_calc(float r_uv[2],
{
float pt_on_line[2];
r_uv[0] = closest_to_line_v2(pt_on_line, pt, pt_a, pt_b);
+
r_uv[1] = (len_v2v2(pt_on_line, pt) / len_v2v2(pt_a, pt_b)) *
- ((line_point_side_v2(pt_a, pt_b, pt) < 0.0f) ?
- -1.0f :
- 1.0f); /* this line only sets the sign */
+ /* This line only sets the sign. */
+ ((line_point_side_v2(pt_a, pt_b, pt) < 0.0f) ? -1.0f : 1.0f);
}
static void interp_weights_uv_v2_apply(const float uv[2],
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index b01c1189fd1..1545ae4f48f 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -461,7 +461,7 @@ void BKE_material_append_id(Main *bmain, ID *id, Material *ma)
}
}
-Material *BKE_material_pop_id(Main *bmain, ID *id, int index_i, bool update_data)
+Material *BKE_material_pop_id(Main *bmain, ID *id, int index_i)
{
short index = (short)index_i;
Material *ret = NULL;
@@ -489,10 +489,7 @@ Material *BKE_material_pop_id(Main *bmain, ID *id, int index_i, bool update_data
test_all_objects_materials(bmain, id);
}
- if (update_data) {
- /* decrease mat_nr index */
- material_data_index_remove_id(id, index);
- }
+ material_data_index_remove_id(id, index);
DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
@@ -502,7 +499,7 @@ Material *BKE_material_pop_id(Main *bmain, ID *id, int index_i, bool update_data
return ret;
}
-void BKE_material_clear_id(Main *bmain, ID *id, bool update_data)
+void BKE_material_clear_id(Main *bmain, ID *id)
{
Material ***matar;
if ((matar = give_matarar_id(id))) {
@@ -516,12 +513,9 @@ void BKE_material_clear_id(Main *bmain, ID *id, bool update_data)
MEM_freeN(*matar);
*matar = NULL;
}
- test_all_objects_materials(bmain, id);
- if (update_data) {
- /* decrease mat_nr index */
- material_data_index_clear_id(id);
- }
+ test_all_objects_materials(bmain, id);
+ material_data_index_clear_id(id);
DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index d6fa071009e..0820f0ebbb1 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -364,12 +364,13 @@ bool BKE_mball_is_any_unselected(const MetaBall *mb)
return false;
}
-/* \brief copy some properties from object to other metaball object with same base name
+/**
+ * \brief copy some properties from object to other metaball object with same base name
*
* When some properties (wiresize, threshold, update flags) of metaball are changed, then this
* properties are copied to all metaballs in same "group" (metaballs with same base name: MBall,
* MBall.001, MBall.002, etc). The most important is to copy properties to the base metaball,
- * because this metaball influence polygonisation of metaballs. */
+ * because this metaball influence polygonization of metaballs. */
void BKE_mball_properties_copy(Scene *scene, Object *active_object)
{
Scene *sce_iter = scene;
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 7e755e54eaa..4f39d34574e 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -536,6 +536,7 @@ void BKE_mesh_init(Mesh *me)
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;
CustomData_reset(&me->vdata);
CustomData_reset(&me->edata);
diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c
index ee060a117dc..3a2ba078dce 100644
--- a/source/blender/blenkernel/intern/mesh_convert.c
+++ b/source/blender/blenkernel/intern/mesh_convert.c
@@ -978,7 +978,7 @@ static void curve_to_mesh_eval_ensure(Object *object)
*
* So we create temporary copy of the object which will use same data as the original bevel, but
* will have no modifiers. */
- Object bevel_object = {NULL};
+ Object bevel_object = {{NULL}};
if (remapped_curve.bevobj != NULL) {
bevel_object = *remapped_curve.bevobj;
BLI_listbase_clear(&bevel_object.modifiers);
@@ -986,7 +986,7 @@ static void curve_to_mesh_eval_ensure(Object *object)
}
/* Same thing for taper. */
- Object taper_object = {NULL};
+ Object taper_object = {{NULL}};
if (remapped_curve.taperobj != NULL) {
taper_object = *remapped_curve.taperobj;
BLI_listbase_clear(&taper_object.modifiers);
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index e28d50cbde4..ad06f4b7da1 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -1320,7 +1320,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
}
// print_v2("new clnors", clnors_avg);
}
- /* Extra bonus: since smallstack is local to this func,
+ /* Extra bonus: since small-stack is local to this function,
* no more need to empty it at all cost! */
BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor);
@@ -1336,7 +1336,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
copy_v3_v3(nor, lnor);
}
}
- /* Extra bonus: since smallstack is local to this func,
+ /* Extra bonus: since small-stack is local to this funcion,
* no more need to empty it at all cost! */
}
}
@@ -2378,6 +2378,24 @@ float BKE_mesh_calc_poly_area(const MPoly *mpoly, const MLoop *loopstart, const
}
}
+float BKE_mesh_calc_poly_uv_area(const MPoly *mpoly, const MLoopUV *uv_array)
+{
+
+ int i, l_iter = mpoly->loopstart;
+ float area;
+ float(*vertexcos)[2] = BLI_array_alloca(vertexcos, (size_t)mpoly->totloop);
+
+ /* pack vertex cos into an array for area_poly_v2 */
+ for (i = 0; i < mpoly->totloop; i++, l_iter++) {
+ copy_v2_v2(vertexcos[i], uv_array[l_iter].uv);
+ }
+
+ /* finally calculate the area */
+ area = area_poly_v2((const float(*)[2])vertexcos, (unsigned int)mpoly->totloop);
+
+ return area;
+}
+
/**
* Calculate the volume and volume-weighted centroid of the volume
* formed by the polygon and the origin.
diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.c b/source/blender/blenkernel/intern/mesh_remesh_voxel.c
new file mode 100644
index 00000000000..a5136311a22
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.c
@@ -0,0 +1,204 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+#include <float.h>
+#include <ctype.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_library.h"
+#include "BKE_customdata.h"
+#include "BKE_bvhutils.h"
+#include "BKE_mesh_remesh_voxel.h" /* own include */
+
+#ifdef WITH_OPENVDB
+# include "openvdb_capi.h"
+#endif
+
+#ifdef WITH_OPENVDB
+struct OpenVDBLevelSet *BKE_mesh_remesh_voxel_ovdb_mesh_to_level_set_create(
+ Mesh *mesh, struct OpenVDBTransform *transform)
+{
+ BKE_mesh_runtime_looptri_recalc(mesh);
+ const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ MVertTri *verttri = MEM_callocN(sizeof(*verttri) * BKE_mesh_runtime_looptri_len(mesh),
+ "remesh_looptri");
+ BKE_mesh_runtime_verttri_from_looptri(
+ verttri, mesh->mloop, looptri, BKE_mesh_runtime_looptri_len(mesh));
+
+ unsigned int totfaces = BKE_mesh_runtime_looptri_len(mesh);
+ unsigned int totverts = 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 = &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];
+ }
+
+ struct OpenVDBLevelSet *level_set = OpenVDBLevelSet_create(false, NULL);
+ OpenVDBLevelSet_mesh_to_level_set(level_set, verts, faces, totverts, totfaces, transform);
+
+ MEM_freeN(verts);
+ MEM_freeN(faces);
+ MEM_freeN(verttri);
+
+ return level_set;
+}
+
+Mesh *BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(struct OpenVDBLevelSet *level_set,
+ double isovalue,
+ double adaptivity,
+ bool relax_disoriented_triangles)
+{
+# ifdef WITH_OPENVDB
+ struct OpenVDBVolumeToMeshData output_mesh;
+ OpenVDBLevelSet_volume_to_mesh(
+ level_set, &output_mesh, isovalue, adaptivity, relax_disoriented_triangles);
+# endif
+
+ Mesh *mesh = BKE_mesh_new_nomain(output_mesh.totvertices,
+ 0,
+ 0,
+ (output_mesh.totquads * 4) + (output_mesh.tottriangles * 3),
+ output_mesh.totquads + output_mesh.tottriangles);
+
+ for (int i = 0; i < output_mesh.totvertices; i++) {
+ copy_v3_v3(mesh->mvert[i].co, &output_mesh.vertices[i * 3]);
+ }
+
+ MPoly *mp = mesh->mpoly;
+ MLoop *ml = mesh->mloop;
+ for (int i = 0; i < output_mesh.totquads; i++, mp++, ml += 4) {
+ mp->loopstart = (int)(ml - mesh->mloop);
+ mp->totloop = 4;
+
+ ml[0].v = output_mesh.quads[i * 4 + 3];
+ ml[1].v = output_mesh.quads[i * 4 + 2];
+ ml[2].v = output_mesh.quads[i * 4 + 1];
+ ml[3].v = output_mesh.quads[i * 4];
+ }
+
+ for (int i = 0; i < output_mesh.tottriangles; i++, mp++, ml += 3) {
+ mp->loopstart = (int)(ml - mesh->mloop);
+ mp->totloop = 3;
+
+ ml[0].v = output_mesh.triangles[i * 3 + 2];
+ ml[1].v = output_mesh.triangles[i * 3 + 1];
+ ml[2].v = output_mesh.triangles[i * 3];
+ }
+
+ BKE_mesh_calc_edges(mesh, false, false);
+ BKE_mesh_calc_normals(mesh);
+
+ MEM_freeN(output_mesh.quads);
+ MEM_freeN(output_mesh.vertices);
+
+ if (output_mesh.tottriangles > 0) {
+ MEM_freeN(output_mesh.triangles);
+ }
+
+ return mesh;
+}
+#endif
+
+Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(Mesh *mesh, float voxel_size)
+{
+ Mesh *new_mesh = NULL;
+#ifdef WITH_OPENVDB
+ struct OpenVDBLevelSet *level_set;
+ 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);
+ OpenVDBLevelSet_free(level_set);
+ OpenVDBTransform_free(xform);
+#else
+ UNUSED_VARS(mesh, voxel_size);
+#endif
+ return new_mesh;
+}
+
+void BKE_remesh_reproject_paint_mask(Mesh *target, Mesh *source)
+{
+ BVHTreeFromMesh bvhtree = {
+ .nearest_callback = NULL,
+ };
+ BKE_bvhtree_from_mesh_get(&bvhtree, source, BVHTREE_FROM_VERTS, 2);
+ MVert *target_verts = CustomData_get_layer(&target->vdata, CD_MVERT);
+
+ float *target_mask;
+ if (CustomData_has_layer(&target->vdata, CD_PAINT_MASK)) {
+ target_mask = CustomData_get_layer(&target->vdata, CD_PAINT_MASK);
+ }
+ else {
+ target_mask = CustomData_add_layer(
+ &target->vdata, CD_PAINT_MASK, CD_CALLOC, NULL, target->totvert);
+ }
+
+ float *source_mask;
+ if (CustomData_has_layer(&source->vdata, CD_PAINT_MASK)) {
+ source_mask = CustomData_get_layer(&source->vdata, CD_PAINT_MASK);
+ }
+ else {
+ source_mask = CustomData_add_layer(
+ &source->vdata, CD_PAINT_MASK, CD_CALLOC, NULL, source->totvert);
+ }
+
+ for (int i = 0; i < target->totvert; i++) {
+ float from_co[3];
+ BVHTreeNearest nearest;
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+ copy_v3_v3(from_co, target_verts[i].co);
+ BLI_bvhtree_find_nearest(bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree);
+ if (nearest.index != -1) {
+ target_mask[i] = source_mask[nearest.index];
+ }
+ }
+ free_bvhtree_from_mesh(&bvhtree);
+}
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 0b06bfab2ab..2cc1083aba3 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -448,8 +448,9 @@ static float nlastrip_get_frame_actionclip(NlaStrip *strip, float cframe, short
if (IS_EQF(strip->scale, 0.0f)) {
strip->scale = 1.0f;
}
- scale = fabsf(
- strip->scale); /* scale must be positive - we've got a special flag for reversing */
+
+ /* Scale must be positive - we've got a special flag for reversing. */
+ scale = fabsf(strip->scale);
/* length of referenced action */
actlength = strip->actend - strip->actstart;
@@ -1280,9 +1281,9 @@ static void nlastrip_fix_resize_overlaps(NlaStrip *strip)
* then offset everything else by the remaining defict to give the strip room
*/
nls->start = nls->end - 1.0f;
- offset = ceilf(
- strip->end -
- nls->start); /* XXX: review whether preventing fractionals is good here... */
+
+ /* XXX: review whether preventing fractionals is good here... */
+ offset = ceilf(strip->end - nls->start);
/* apply necessary offset to ensure that the strip has enough space */
for (; nls; nls = nls->next) {
@@ -1329,9 +1330,9 @@ static void nlastrip_fix_resize_overlaps(NlaStrip *strip)
* then offset everything else by the remaining defict to give the strip room
*/
nls->end = nls->start + 1.0f;
- offset = ceilf(
- nls->end -
- strip->start); /* XXX: review whether preventing fractionals is good here... */
+
+ /* XXX: review whether preventing fractionals is good here... */
+ offset = ceilf(nls->end - strip->start);
/* apply necessary offset to ensure that the strip has enough space */
for (; nls; nls = nls->next) {
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 775f6eb37a7..d64a5a33ef1 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -2799,6 +2799,16 @@ int nodeSocketIsHidden(bNodeSocket *sock)
return ((sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) != 0);
}
+void nodeSetSocketAvailability(bNodeSocket *sock, bool is_available)
+{
+ if (is_available) {
+ sock->flag &= ~SOCK_UNAVAIL;
+ }
+ else {
+ sock->flag |= SOCK_UNAVAIL;
+ }
+}
+
/* ************** Node Clipboard *********** */
#define USE_NODE_CB_VALIDATE
@@ -3779,6 +3789,7 @@ static void registerCompositNodes(void)
register_node_type_cmp_despeckle();
register_node_type_cmp_defocus();
register_node_type_cmp_sunbeams();
+ register_node_type_cmp_denoise();
register_node_type_cmp_valtorgb();
register_node_type_cmp_rgbtobw();
@@ -3856,6 +3867,8 @@ static void registerShaderNodes(void)
register_node_type_sh_mapping();
register_node_type_sh_curve_vec();
register_node_type_sh_curve_rgb();
+ register_node_type_sh_map_range();
+ register_node_type_sh_clamp();
register_node_type_sh_math();
register_node_type_sh_vect_math();
register_node_type_sh_vect_transform();
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index d95c02cdf7f..ae091f32fbf 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -3587,7 +3587,7 @@ bool BKE_object_shapekey_free(Main *bmain, Object *ob)
BKE_id_free_us(bmain, key);
- return false;
+ return true;
}
bool BKE_object_shapekey_remove(Main *bmain, Object *ob, KeyBlock *kb)
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 0dedbb7e934..7983fe54be5 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -762,8 +762,8 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
no_draw_flag |= PARS_NO_DISP;
}
- ctime = DEG_get_ctime(
- ctx->depsgraph); /* NOTE: in old animsys, used parent object's timeoffset... */
+ /* NOTE: in old animsys, used parent object's timeoffset... */
+ ctime = DEG_get_ctime(ctx->depsgraph);
totpart = psys->totpart;
totchild = psys->totchild;
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 202eadaa35a..49f5aa35f93 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -432,7 +432,7 @@ void BKE_object_eval_eval_base_flags(Depsgraph *depsgraph,
BKE_base_eval_flags(base);
/* For render, compute base visibility again since BKE_base_eval_flags
- * assumed viewport visibility. Selectability does not matter here. */
+ * assumed viewport visibility. Select-ability does not matter here. */
if (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER) {
if (base->flag & BASE_ENABLED_RENDER) {
base->flag |= BASE_VISIBLE;
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 39fb668c873..fcceebc3913 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -519,7 +519,7 @@ static void ocean_compute_htilda(void *__restrict userdata,
int j;
- /* note the <= _N/2 here, see the fftw doco
+ /* 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) {
fftw_complex exp_param1;
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index da00a044009..ffeba0148a2 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -1764,8 +1764,9 @@ void psys_particle_on_dm(Mesh *mesh_final,
copy_v3_v3(nor, tmpnor);
}
- normalize_v3(
- tmpnor); /* XXX Why not normalize tmpnor before copying it into nor??? -- mont29 */
+ /* XXX Why not normalize tmpnor before copying it into nor??? -- mont29 */
+ normalize_v3(tmpnor);
+
mul_v3_fl(tmpnor, -foffset);
add_v3_v3(vec, tmpnor);
}
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 90ae512074d..13d0f1adb84 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -2073,10 +2073,9 @@ static int ptcache_path(PTCacheID *pid, char *filename)
file[i - 6] = '\0';
}
- BLI_snprintf(filename,
- MAX_PTCACHE_PATH,
- "//" PTCACHE_PATH "%s",
- file); /* add blend file name to pointcache dir */
+ /* Add blend file name to pointcache dir. */
+ BLI_snprintf(filename, MAX_PTCACHE_PATH, "//" PTCACHE_PATH "%s", file);
+
BLI_path_abs(filename, blendfilename);
return BLI_add_slash(filename); /* new strlen() */
}
@@ -2130,24 +2129,17 @@ static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_p
if (pid->cache->flag & PTCACHE_EXTERNAL) {
if (pid->cache->index >= 0) {
- BLI_snprintf(newname,
- MAX_PTCACHE_FILE,
- "_%06d_%02u%s",
- cfra,
- pid->stack_index,
- ext); /* always 6 chars */
+ /* Always 6 chars. */
+ BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u%s", cfra, pid->stack_index, ext);
}
else {
- BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d%s", cfra, ext); /* always 6 chars */
+ /* Always 6 chars. */
+ BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d%s", cfra, ext);
}
}
else {
- BLI_snprintf(newname,
- MAX_PTCACHE_FILE,
- "_%06d_%02u%s",
- cfra,
- pid->stack_index,
- ext); /* always 6 chars */
+ /* Always 6 chars. */
+ BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u%s", cfra, pid->stack_index, ext);
}
len += 16;
}
@@ -2178,8 +2170,9 @@ static PTCacheFile *ptcache_file_open(PTCacheID *pid, int mode, int cfra)
fp = BLI_fopen(filename, "rb");
}
else if (mode == PTCACHE_FILE_WRITE) {
- BLI_make_existing_file(
- filename); /* will create the dir if needs be, same as //textures is created */
+ /* Will create the dir if needs be, same as "//textures" is created. */
+ BLI_make_existing_file(filename);
+
fp = BLI_fopen(filename, "wb");
}
else if (mode == PTCACHE_FILE_UPDATE) {
@@ -3337,7 +3330,7 @@ int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra)
cache->cached_frames[cfra - cache->startframe] = 1;
}
- BKE_ptcache_update_info(pid);
+ cache->flag |= PTCACHE_FLAG_INFO_DIRTY;
return !error;
}
@@ -3500,8 +3493,9 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
break;
}
- BKE_ptcache_update_info(pid);
+ pid->cache->flag |= PTCACHE_FLAG_INFO_DIRTY;
}
+
int BKE_ptcache_id_exist(PTCacheID *pid, int cfra)
{
if (!pid->cache) {
@@ -4288,7 +4282,7 @@ void BKE_ptcache_toggle_disk_cache(PTCacheID *pid)
BKE_ptcache_id_time(pid, NULL, 0.0f, NULL, NULL, NULL);
- BKE_ptcache_update_info(pid);
+ cache->flag |= PTCACHE_FLAG_INFO_DIRTY;
if ((cache->flag & PTCACHE_DISK_CACHE) == 0) {
if (cache->index) {
@@ -4461,7 +4455,8 @@ void BKE_ptcache_load_external(PTCacheID *pid)
cache->cached_frames = NULL;
cache->cached_frames_len = 0;
}
- BKE_ptcache_update_info(pid);
+
+ cache->flag |= PTCACHE_FLAG_INFO_DIRTY;
}
void BKE_ptcache_update_info(PTCacheID *pid)
@@ -4469,7 +4464,9 @@ void BKE_ptcache_update_info(PTCacheID *pid)
PointCache *cache = pid->cache;
PTCacheExtra *extra = NULL;
int totframes = 0;
- char mem_info[64];
+ char mem_info[sizeof(((PointCache *)0)->info) / sizeof(*(((PointCache *)0)->info))];
+
+ cache->flag &= ~PTCACHE_FLAG_INFO_DIRTY;
if (cache->flag & PTCACHE_EXTERNAL) {
int cfra = cache->startframe;
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index 2024a507ebb..d3b72fb295d 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -1731,8 +1731,8 @@ static int sb_detect_vertex_collisionCached(float opco[3],
/* switch origin to be nv2*/
sub_v3_v3v3(edge1, nv1, nv2);
sub_v3_v3v3(edge2, nv3, nv2);
- sub_v3_v3v3(
- dv1, opco, nv2); /* abuse dv1 to have vertex in question at *origin* of triangle */
+ /* Abuse dv1 to have vertex in question at *origin* of triangle. */
+ sub_v3_v3v3(dv1, opco, nv2);
cross_v3_v3v3(d_nvect, edge2, edge1);
/* n_mag = */ /* UNUSED */ normalize_v3(d_nvect);
@@ -2087,9 +2087,12 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene,
if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
float gravity[3];
copy_v3_v3(gravity, scene->physics_settings.gravity);
+
+ /* Individual mass of node here. */
mul_v3_fl(gravity,
sb_grav_force_scale(ob) * _final_mass(ob, bp) *
- sb->effector_weights->global_gravity); /* individual mass of node here */
+ sb->effector_weights->global_gravity);
+
add_v3_v3(bp->force, gravity);
}
@@ -2099,8 +2102,10 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene,
float kd;
float force[3] = {0.0f, 0.0f, 0.0f};
float speed[3] = {0.0f, 0.0f, 0.0f};
- float eval_sb_fric_force_scale = sb_fric_force_scale(
- ob); /* just for calling function once */
+
+ /* just for calling function once */
+ float eval_sb_fric_force_scale = sb_fric_force_scale(ob);
+
pd_point_from_soft(scene, bp->pos, bp->vec, sb->bpoint - bp, &epoint);
BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed);
@@ -2700,7 +2705,7 @@ static void mesh_to_softbody(Scene *scene, Object *ob)
for (a = 0; a < me->totvert; a++, bp++) {
/* get scalar values needed *per vertex* from vertex group functions,
- * so we can *paint* them nicly ..
+ * so we can *paint* them nicely ..
* they are normalized [0.0..1.0] so may be we need amplitude for scale
* which can be done by caller but still .. i'd like it to go this way
*/
@@ -2743,9 +2748,10 @@ static void mesh_to_softbody(Scene *scene, Object *ob)
build_bps_springlist(ob); /* scan for springs attached to bodypoints ONCE */
/* insert *other second order* springs if desired */
if (sb->secondspring > 0.0000001f) {
- add_2nd_order_springs(
- ob, sb->secondspring); /* exploits the first run of build_bps_springlist(ob);*/
- build_bps_springlist(ob); /* yes we need to do it again*/
+ /* exploits the first run of build_bps_springlist(ob); */
+ add_2nd_order_springs(ob, sb->secondspring);
+ /* yes we need to do it again. */
+ build_bps_springlist(ob);
}
springs_from_mesh(ob); /* write the 'rest'-length of the springs */
if (ob->softflag & OB_SB_SELF) {
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 1a3e42a7da2..83be64e84c9 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -1931,7 +1931,7 @@ bool txt_replace_char(Text *text, unsigned int add)
*
* \note caller must handle undo.
*/
-static void txt_select_prefix(Text *text, const char *add)
+static void txt_select_prefix(Text *text, const char *add, bool skip_blank_lines)
{
int len, num, curc_old, selc_old;
char *tmp;
@@ -1947,7 +1947,7 @@ static void txt_select_prefix(Text *text, const char *add)
while (true) {
/* don't indent blank lines */
- if (text->curl->len != 0) {
+ if ((text->curl->len != 0) || (skip_blank_lines == 0)) {
tmp = MEM_mallocN(text->curl->len + indentlen + 1, "textline_string");
text->curc = 0;
@@ -1971,7 +1971,9 @@ static void txt_select_prefix(Text *text, const char *add)
}
if (text->curl == text->sell) {
- text->selc += indentlen;
+ if (text->curl->len != 0) {
+ text->selc += indentlen;
+ }
break;
}
else {
@@ -1995,7 +1997,9 @@ static void txt_select_prefix(Text *text, const char *add)
text->curc = 0;
}
else {
- text->curc = curc_old + indentlen;
+ if (text->curl->len != 0) {
+ text->curc = curc_old + indentlen;
+ }
}
}
@@ -2089,7 +2093,8 @@ void txt_comment(Text *text)
return;
}
- txt_select_prefix(text, prefix);
+ const bool skip_blank_lines = txt_has_sel(text);
+ txt_select_prefix(text, prefix, skip_blank_lines);
}
bool txt_uncomment(Text *text)
@@ -2111,7 +2116,7 @@ void txt_indent(Text *text)
return;
}
- txt_select_prefix(text, prefix);
+ txt_select_prefix(text, prefix, true);
}
bool txt_unindent(Text *text)
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 375721057c3..e30ea687b13 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -734,8 +734,9 @@ static int unit_scale_str(char *str,
len_name = strlen(replace_str);
len_move = (len - (found_ofs + len_name)) + 1; /* 1+ to copy the string terminator */
- len_num = BLI_snprintf(
- str_tmp, TEMP_STR_SIZE, "*%.9g" SEP_STR, unit->scalar / scale_pref); /* # removed later */
+
+ /* # removed later */
+ len_num = BLI_snprintf(str_tmp, TEMP_STR_SIZE, "*%.9g" SEP_STR, unit->scalar / scale_pref);
if (len_num > len_max) {
len_num = len_max;
@@ -748,8 +749,9 @@ static int unit_scale_str(char *str,
if (len_move > 0) {
/* resize the last part of the string */
- memmove(
- str_found + len_num, str_found + len_name, len_move); /* may grow or shrink the string */
+
+ /* May grow or shrink the string. */
+ memmove(str_found + len_num, str_found + len_name, len_move);
}
if (found_ofs + len_num > len_max) {
diff --git a/source/blender/blenlib/BLI_delaunay_2d.h b/source/blender/blenlib/BLI_delaunay_2d.h
new file mode 100644
index 00000000000..fe81de5fc5e
--- /dev/null
+++ b/source/blender/blenlib/BLI_delaunay_2d.h
@@ -0,0 +1,199 @@
+/*
+ * 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_DELAUNAY_2D_H__
+#define __BLI_DELAUNAY_2D_H__
+
+/** \file
+ * \ingroup bli
+ */
+
+/**
+ * Interface for Constrained Delaunay Triangulation (CDT) in 2D.
+ *
+ * The input is a set of vertices, edges between those vertices,
+ * and faces using those vertices.
+ * Those inputs are called "constraints". The output must contain
+ * those constraints, or at least edges, points, and vertices that
+ * may be pieced together to form the constraints. Part of the
+ * work of doing the CDT is to detect intersections and mergers
+ * among the input elements, so these routines are also useful
+ * for doing 2D intersection.
+ *
+ * The output is a triangulation of the plane that includes the
+ * constraints in the above sense, and also satisfies the
+ * "Delaunay condition" as modified to take into account that
+ * the constraints must be there: for every non-constrained edge
+ * in the output, there is a circle through the endpoints that
+ * does not contain any of the vertices directly connected to
+ * those endpoints. What this means in practice is that as
+ * much as possible the triangles look "nice" -- not too long
+ * and skinny.
+ *
+ * Optionally, the output can be a subset of the triangulation
+ * (but still containing all of the constraints), to get the
+ * effect of 2D intersection.
+ *
+ * The underlying method is incremental, but we need to know
+ * beforehand a bounding box for all of the constraints.
+ * This code can be extended in the future to allow for
+ * deletion of constraints, if there is a use in Blender
+ * for dynamically maintaining a triangulation.
+ */
+
+/**
+ * Input to Constrained Delaunay Triangulation.
+ * There are verts_len vertices, whose coordinates
+ * are given by vert_coords. For the rest of the input,
+ * vertices are referred to by indices into that array.
+ * Edges and Faces are optional. If provided, they will
+ * appear in the output triangulation ("constraints").
+ * One can provide faces and not edges -- the edges
+ * implied by the faces will be inferred.
+ *
+ * The edges are given by pairs of vertex indices.
+ * The faces are given in a triple `(faces, faces_start_table, faces_len_table)`
+ * to represent a list-of-lists as follows:
+ * the vertex indices for a counterclockwise traversal of
+ * face number `i` starts at `faces_start_table[i]` and has `faces_len_table[i]`
+ * elements.
+ *
+ * The edges implied by the faces are automatically added
+ * and need not be put in the edges array, which is intended
+ * as a way to specify edges that are not part of any face.
+ *
+ * Some notes about some special cases and how they are handled:
+ * - Input faces can have any number of vertices greater than 2. Depending
+ * on the output option, ngons may be triangulated or they may remain
+ * as ngons.
+ * - Input faces may have repeated vertices. Output faces will not,
+ * except when the CDT_CONSTRAINTS output option is used.
+ * - Input faces may have edges that self-intersect, but currently the labeling
+ * of which output faces have which input faces may not be done correctly,
+ * since the labeling relies on the inside being on the left of edges
+ * as one traverses the face. Output faces will not self-intersect.
+ * - Input edges, including those implied by the input faces, may have
+ * zero-length or near-zero-length edges (nearness as determined by epsilon),
+ * but those edges will not be in the output.
+ * - Input edges (including face edges) can overlap or nearly overlap each other.
+ * The output edges will not overlap, but instead be divided into as many
+ * edges as necessary to represent each overlap regime.
+ * - Input vertices may be coincide with, or nearly coincide with (as determined
+ * by epsilon) other input vertices. Only one representative will survive
+ * in the output. If an input vertex is within epsilon of an edge (including
+ * an added triangulation edge), it will be snapped to that edge, so the
+ * output coordinates may not exactly match the input coordinates in all cases.
+ * - Wire edges (those not part of faces) and isolated vertices are allowed in
+ * the input. If they are inside faces, they will be incorporated into the
+ * triangulation of those faces.
+ *
+ * Epsilon is used for "is it near enough" distance calculations.
+ * If zero is supplied for epsilon, an internal value of 1e-8 used
+ * instead, since this code will not work correctly if it is not allowed
+ * to merge "too near" vertices.
+ */
+typedef struct CDT_input {
+ int verts_len;
+ int edges_len;
+ int faces_len;
+ float (*vert_coords)[2];
+ int (*edges)[2];
+ int *faces;
+ int *faces_start_table;
+ int *faces_len_table;
+ float epsilon;
+} CDT_input;
+
+/**
+ * A representation of the triangulation for output.
+ * See #CDT_input for the representation of the output
+ * vertices, edges, and faces, all represented in
+ * a similar way to the input.
+ *
+ * The output may have merged some input vertices together,
+ * if they were closer than some epsilon distance.
+ * The output edges may be overlapping sub-segments of some
+ * input edges; or they may be new edges for the triangulation.
+ * The output faces may be pieces of some input faces, or they
+ * may be new.
+ *
+ * In the same way that faces lists-of-lists were represented by
+ * a run-together array and a "start" and "len" extra array,
+ * similar triples are used to represent the output to input
+ * mapping of vertices, edges, and faces.
+ *
+ * Those triples are:
+ * - verts_orig, verts_orig_start_table, verts_orig_len_table
+ * - edges_orig, edges_orig_start_table, edges_orig_len_table
+ * - faces_orig, faces_orig_start_table, faces_orig_len_table
+ *
+ * For edges, the edges_orig triple can also say which original face
+ * edge is part of a given output edge. If an index in edges_orig
+ * is greater than the input's edges_len, then subtract input's edges_len
+ * from it to some number i: then the face edge that starts from the
+ * input vertex at input's faces[i] is the corresponding face edge.
+ * for convenience, face_edge_offset in the result will be the input's
+ * edges_len, so that this conversion can be easily done by the caller.
+ */
+typedef struct CDT_result {
+ int verts_len;
+ int edges_len;
+ int faces_len;
+ int face_edge_offset;
+ float (*vert_coords)[2];
+ int (*edges)[2];
+ int *faces;
+ int *faces_start_table;
+ int *faces_len_table;
+ int *verts_orig;
+ int *verts_orig_start_table;
+ int *verts_orig_len_table;
+ int *edges_orig;
+ int *edges_orig_start_table;
+ int *edges_orig_len_table;
+ int *faces_orig;
+ int *faces_orig_start_table;
+ int *faces_orig_len_table;
+} CDT_result;
+
+/** What triangles and edges of CDT are desired when getting output? */
+typedef enum CDT_output_type {
+ /** All triangles, outer boundary is convex hull. */
+ CDT_FULL,
+ /** All triangles fully enclosed by constraint edges or faces. */
+ CDT_INSIDE,
+ /** Only point, edge, and face constraints, and their intersections. */
+ CDT_CONSTRAINTS,
+ /**
+ * Like CDT_CONSTRAINTS, but keep enough
+ * edges so that any output faces that came from input faces can be made as valid
+ * #BMesh faces in Blender: that is,
+ * no vertex appears more than once and no isolated holes in faces.
+ */
+ CDT_CONSTRAINTS_VALID_BMESH
+} CDT_output_type;
+
+/**
+ * API interface to CDT.
+ * This returns a pointer to an allocated CDT_result.
+ * When the caller is finished with it, the caller
+ * should use #BLI_delaunay_2d_cdt_free() to free it.
+ */
+CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_type output_type);
+
+void BLI_delaunay_2d_cdt_free(CDT_result *result);
+
+#endif /* __BLI_DELAUNAY_2D_H__ */
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 5ac4ce8be0b..39b1b96d009 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -92,6 +92,7 @@ float volume_tetrahedron_signed_v3(const float v1[3],
const float v3[3],
const float v4[3]);
+bool is_edge_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
bool is_poly_convex_v2(const float verts[][2], unsigned int nr);
@@ -390,6 +391,13 @@ bool isect_tri_tri_epsilon_v3(const float t_a0[3],
float r_i2[3],
const float epsilon);
+bool isect_tri_tri_v2(const float p1[2],
+ const float q1[2],
+ const float r1[2],
+ const float p2[2],
+ const float q2[2],
+ const float r2[2]);
+
/* water-tight raycast (requires pre-calculation) */
struct IsectRayPrecalc {
/* Maximal dimension kz, and orthogonal dimensions. */
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index 31b68204c51..99e86615e50 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -42,6 +42,8 @@ void BLI_split_dirfile(
const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen);
void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen);
void BLI_split_file_part(const char *string, char *file, const size_t filelen);
+const char *BLI_path_extension(const char *filepath) ATTR_NONNULL();
+
void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file)
ATTR_NONNULL();
void BLI_join_dirfile(char *__restrict string,
diff --git a/source/blender/blenlib/BLI_string_utils.h b/source/blender/blenlib/BLI_string_utils.h
index 9740629276d..13dbb2de659 100644
--- a/source/blender/blenlib/BLI_string_utils.h
+++ b/source/blender/blenlib/BLI_string_utils.h
@@ -38,6 +38,7 @@ struct ListBase;
typedef bool (*UniquenameCheckCallback)(void *arg, const char *name);
size_t BLI_split_name_num(char *left, int *nr, const char *name, const char delim);
+bool BLI_string_is_decimal(const char *string) ATTR_NONNULL();
void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len);
void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len);
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 0ec6e7ee4fc..7f6e9d49b17 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -63,6 +63,7 @@ set(SRC
intern/buffer.c
intern/callbacks.c
intern/convexhull_2d.c
+ intern/delaunay_2d.c
intern/dynlib.c
intern/easing.c
intern/edgehash.c
@@ -150,6 +151,7 @@ set(SRC
BLI_compiler_typecheck.h
BLI_console.h
BLI_convexhull_2d.h
+ BLI_delaunay_2d.h
BLI_dial_2d.h
BLI_dlrbTree.h
BLI_dynlib.h
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index 769bb02e2b9..05ffb02597d 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -886,7 +886,7 @@ bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_
const bool haskey = (e != NULL);
if (!haskey) {
- /* pass 'key' incase we resize */
+ /* Pass 'key' in case we resize. */
e = BLI_mempool_alloc(gh->entrypool);
ghash_insert_ex_keyonly_entry(gh, (void *)key, bucket_index, (Entry *)e);
e->e.key = NULL; /* caller must re-assign */
@@ -1189,7 +1189,7 @@ bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key)
const bool haskey = (e != NULL);
if (!haskey) {
- /* pass 'key' incase we resize */
+ /* Pass 'key' in case we resize */
e = BLI_mempool_alloc(((GHash *)gs)->entrypool);
ghash_insert_ex_keyonly_entry((GHash *)gs, (void *)key, bucket_index, (Entry *)e);
e->key = NULL; /* caller must re-assign */
diff --git a/source/blender/blenlib/intern/boxpack_2d.c b/source/blender/blenlib/intern/boxpack_2d.c
index 196d45967be..ddc7f9ee4c7 100644
--- a/source/blender/blenlib/intern/boxpack_2d.c
+++ b/source/blender/blenlib/intern/boxpack_2d.c
@@ -273,12 +273,12 @@ static int vertex_sort(const void *p1, const void *p2, void *vs_ctx_p)
/** \} */
/**
- * Main boxpacking function accessed from other functions
+ * Main box-packing function accessed from other functions
* This sets boxes x,y to positive values, sorting from 0,0 outwards.
* There is no limit to the space boxes may take, only that they will be packed
* tightly into the lower left hand corner (0,0)
*
- * \param boxarray: a pre allocated array of boxes.
+ * \param boxarray: a pre-allocated array of boxes.
* only the 'box->x' and 'box->y' are set, 'box->w' and 'box->h' are used,
* 'box->index' is not used at all, the only reason its there
* is that the box array is sorted by area and programs need to be able
diff --git a/source/blender/blenlib/intern/delaunay_2d.c b/source/blender/blenlib/intern/delaunay_2d.c
new file mode 100644
index 00000000000..23f560c5463
--- /dev/null
+++ b/source/blender/blenlib/intern/delaunay_2d.c
@@ -0,0 +1,2913 @@
+/*
+ * 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
+ *
+ * Dynamic Constrained Delaunay Triangulation.
+ * See paper by Marcelo Kallmann, Hanspeter Bieri, and Daniel Thalmann
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_array.h"
+#include "BLI_bitmap.h"
+#include "BLI_linklist.h"
+#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_mempool.h"
+#include "BLI_rand.h"
+
+#include "BLI_delaunay_2d.h"
+
+/* Uncomment this define to get helpful debugging functions etc. defined. */
+// #define DEBUG_CDT
+
+struct CDTEdge;
+struct CDTFace;
+struct CDTVert;
+
+typedef struct SymEdge {
+ struct SymEdge *next; /* In face, doing CCW traversal of face. */
+ struct SymEdge *rot; /* CCW around vert. */
+ struct CDTVert *vert; /* Vert at origin. */
+ struct CDTEdge *edge; /* Undirected edge this is for. */
+ struct CDTFace *face; /* Face on left side. */
+} SymEdge;
+
+typedef struct CDTVert {
+ double co[2]; /* Coordinate. */
+ SymEdge *symedge; /* Some edge attached to it. */
+ LinkNode *input_ids; /* List of corresponding vertex input ids. */
+ int index; /* Index into array that cdt keeps. */
+} CDTVert;
+
+typedef struct CDTEdge {
+ LinkNode *input_ids; /* List of input edge ids that this is part of. */
+ SymEdge symedges[2]; /* The directed edges for this edge. */
+} CDTEdge;
+
+typedef struct CDTFace {
+ double centroid[2]; /* Average of vertex coords. */
+ SymEdge *symedge; /* A symedge in face; only used during output. */
+ LinkNode *input_ids; /* List of input face ids that this is part of. */
+ int visit_index; /* Which visit epoch has this been seen. */
+ bool deleted; /* Marks this face no longer used. */
+} CDTFace;
+
+typedef struct CDT_state {
+ LinkNode *edges;
+ LinkNode *faces;
+ CDTFace *outer_face;
+ CDTVert **vert_array;
+ int vert_array_len;
+ int vert_array_len_alloc;
+ double minx;
+ double miny;
+ double maxx;
+ double maxy;
+ double margin;
+ int visit_count;
+ int face_edge_offset;
+ RNG *rng;
+ MemArena *arena;
+ BLI_mempool *listpool;
+ double epsilon;
+ bool output_prepared;
+} CDT_state;
+
+typedef struct LocateResult {
+ enum { OnVert, OnEdge, InFace } loc_kind;
+ SymEdge *se;
+ double edge_lambda;
+} LocateResult;
+
+#define DLNY_ARENASIZE 1 << 14
+
+/**
+ * This margin means that will only be a 1 degree possible
+ * concavity on outside if remove all border touching triangles.
+ */
+#define DLNY_MARGIN_PCT 2000.0
+
+#ifdef DEBUG_CDT
+# define F2(p) p[0], p[1]
+static void dump_se(const SymEdge *se, const char *lab);
+static void dump_v(const CDTVert *v, const char *lab);
+static void dump_se_cycle(const SymEdge *se, const char *lab, const int limit);
+static void dump_id_list(const LinkNode *id_list, const char *lab);
+static void dump_cdt(const CDT_state *cdt, const char *lab);
+static void cdt_draw(CDT_state *cdt, const char *lab);
+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])
+{
+ double det;
+ double ab;
+
+ /* 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) {
+ return 0;
+ }
+ det /= ab;
+ if (det > DBL_EPSILON) {
+ return 1;
+ }
+ else if (det < -DBL_EPSILON) {
+ return -1;
+ }
+ return 0;
+}
+
+/** return true if a -- b -- c are in that order, assuming they are on a straight line. */
+static bool in_line(const double a[2], const double b[2], const double c[2])
+{
+ double dir_ab[2], dir_ac[2];
+
+ sub_v2_v2v2_db(dir_ab, a, b);
+ sub_v2_v2v2_db(dir_ac, a, c);
+ return dot_v2v2_db(dir_ab, dir_ac) >= 0.0;
+}
+
+#ifndef NDEBUG
+/** Is s2 reachable from s1 by next pointers with < limit hops? */
+static bool reachable(SymEdge *s1, SymEdge *s2, int limit)
+{
+ int count = 0;
+ for (SymEdge *s = s1; s && count < limit; s = s->next) {
+ if (s == s2) {
+ return true;
+ }
+ count++;
+ }
+ return false;
+}
+#endif
+
+static void calc_face_centroid(SymEdge *se)
+{
+ SymEdge *senext;
+ double *centroidp = se->face->centroid;
+ int count;
+ copy_v2_v2_db(centroidp, se->vert->co);
+ count = 1;
+ for (senext = se->next; senext != se; senext = senext->next) {
+ add_v2_v2_db(centroidp, senext->vert->co);
+ count++;
+ }
+ centroidp[0] /= count;
+ centroidp[1] /= count;
+}
+
+/** Using array to store these instead of linked list so can make a random selection from them. */
+static CDTVert *add_cdtvert(CDT_state *cdt, double x, double y)
+{
+ CDTVert *v = BLI_memarena_alloc(cdt->arena, sizeof(*v));
+ v->co[0] = x;
+ v->co[1] = y;
+ v->input_ids = NULL;
+ v->symedge = NULL;
+ if (cdt->vert_array_len == cdt->vert_array_len_alloc) {
+ CDTVert **old_array = cdt->vert_array;
+ cdt->vert_array_len_alloc *= 4;
+ cdt->vert_array = BLI_memarena_alloc(cdt->arena,
+ cdt->vert_array_len_alloc * sizeof(cdt->vert_array[0]));
+ memmove(cdt->vert_array, old_array, cdt->vert_array_len * sizeof(cdt->vert_array[0]));
+ }
+ BLI_assert(cdt->vert_array_len < cdt->vert_array_len_alloc);
+ v->index = cdt->vert_array_len;
+ cdt->vert_array[cdt->vert_array_len++] = v;
+ return v;
+}
+
+static CDTEdge *add_cdtedge(
+ CDT_state *cdt, CDTVert *v1, CDTVert *v2, CDTFace *fleft, CDTFace *fright)
+{
+ CDTEdge *e = BLI_memarena_alloc(cdt->arena, sizeof(*e));
+ SymEdge *se = &e->symedges[0];
+ SymEdge *sesym = &e->symedges[1];
+ e->input_ids = NULL;
+ BLI_linklist_prepend_arena(&cdt->edges, (void *)e, cdt->arena);
+ se->edge = sesym->edge = e;
+ se->face = fleft;
+ sesym->face = fright;
+ se->vert = v1;
+ if (v1->symedge == NULL) {
+ v1->symedge = se;
+ }
+ sesym->vert = v2;
+ if (v2->symedge == NULL) {
+ v2->symedge = sesym;
+ }
+ se->next = sesym->next = se->rot = sesym->rot = NULL;
+ return e;
+}
+
+static CDTFace *add_cdtface(CDT_state *cdt)
+{
+ CDTFace *f = BLI_memarena_alloc(cdt->arena, sizeof(*f));
+ f->visit_index = 0;
+ f->deleted = false;
+ f->symedge = NULL;
+ f->input_ids = NULL;
+ BLI_linklist_prepend_arena(&cdt->faces, (void *)f, cdt->arena);
+ return f;
+}
+
+static bool id_in_list(const LinkNode *id_list, int id)
+{
+ const LinkNode *ln;
+
+ for (ln = id_list; ln; ln = ln->next) {
+ if (POINTER_AS_INT(ln->link) == id) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/** is any id in (range_start, range_start+1, ... , range_end) in id_list? */
+static bool id_range_in_list(const LinkNode *id_list, int range_start, int range_end)
+{
+ const LinkNode *ln;
+ int id;
+
+ for (ln = id_list; ln; ln = ln->next) {
+ id = POINTER_AS_INT(ln->link);
+ if (id >= range_start && id <= range_end) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void add_to_input_ids(LinkNode **dst, int input_id, CDT_state *cdt)
+{
+ if (!id_in_list(*dst, input_id)) {
+ BLI_linklist_prepend_arena(dst, POINTER_FROM_INT(input_id), cdt->arena);
+ }
+}
+
+static void add_list_to_input_ids(LinkNode **dst, const LinkNode *src, CDT_state *cdt)
+{
+ const LinkNode *ln;
+
+ for (ln = src; ln; ln = ln->next) {
+ add_to_input_ids(dst, POINTER_AS_INT(ln->link), cdt);
+ }
+}
+
+/** Return other #SymEdge for same #CDTEdge as se. */
+static inline SymEdge *sym(const SymEdge *se)
+{
+ return se->next->rot;
+}
+
+/** Return SymEdge whose next is se. */
+static inline SymEdge *prev(const SymEdge *se)
+{
+ return se->rot->next->rot;
+}
+
+static inline bool is_border_edge(const CDTEdge *e, const CDT_state *cdt)
+{
+ return e->symedges[0].face == cdt->outer_face || e->symedges[1].face == cdt->outer_face;
+}
+
+/** Does one edge of this edge touch the frame? */
+static bool edge_touches_frame(const CDTEdge *e)
+{
+ return e->symedges[0].vert->index < 4 || e->symedges[1].vert->index < 4;
+}
+
+static inline bool is_constrained_edge(const CDTEdge *e)
+{
+ return e->input_ids != NULL;
+}
+
+static inline bool is_deleted_edge(const CDTEdge *e)
+{
+ return e->symedges[0].next == NULL;
+}
+
+/** Is there already an edge between a and b? */
+static bool exists_edge(const CDTVert *a, const CDTVert *b)
+{
+ SymEdge *se, *ss;
+ se = a->symedge;
+ if (se->next->vert == b) {
+ return true;
+ }
+ for (ss = se->rot; ss != se; ss = ss->rot) {
+ if (ss->next->vert == b) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Assume s1 and s2 are both SymEdges in a face with > 3 sides,
+ * and one is not the next of the other.
+ * Add an edge from s1->v to s2->v, splitting the face in two.
+ * The original face will continue to be associated with the subface
+ * that has s1, and a new face will be made for s2's new face.
+ * The centroids of both faces are recalculated.
+ * Return the new diagonal's CDTEdge *.
+ */
+static CDTEdge *add_diagonal(CDT_state *cdt, SymEdge *s1, SymEdge *s2)
+{
+ CDTEdge *ediag;
+ CDTFace *fold, *fnew;
+ SymEdge *sdiag, *sdiagsym;
+ SymEdge *s1prev, *s1prevsym, *s2prev, *s2prevsym, *se;
+ BLI_assert(reachable(s1, s2, 20));
+ BLI_assert(reachable(s2, s1, 20));
+ fold = s1->face;
+ fnew = add_cdtface(cdt);
+ s1prev = prev(s1);
+ s1prevsym = sym(s1prev);
+ s2prev = prev(s2);
+ s2prevsym = sym(s2prev);
+ ediag = add_cdtedge(cdt, s1->vert, s2->vert, fnew, fold);
+ sdiag = &ediag->symedges[0];
+ sdiagsym = &ediag->symedges[1];
+ sdiag->next = s2;
+ sdiagsym->next = s1;
+ s2prev->next = sdiagsym;
+ s1prev->next = sdiag;
+ s1->rot = sdiag;
+ sdiag->rot = s1prevsym;
+ s2->rot = sdiagsym;
+ sdiagsym->rot = s2prevsym;
+#ifdef DEBUG_CDT
+ BLI_assert(reachable(s2, sdiag, 20));
+#endif
+ for (se = s2; se != sdiag; se = se->next) {
+ se->face = fnew;
+ }
+ add_list_to_input_ids(&fnew->input_ids, fold->input_ids, cdt);
+ calc_face_centroid(sdiag);
+ calc_face_centroid(sdiagsym);
+ return ediag;
+}
+
+/**
+ * Split \a se at fraction \a lambda,
+ * and return the new #CDTEdge that is the new second half.
+ * Copy the edge input_ids into the new one.
+ */
+static CDTEdge *split_edge(CDT_state *cdt, SymEdge *se, double lambda)
+{
+ const double *a, *b;
+ double p[2];
+ CDTVert *v;
+ CDTEdge *e;
+ SymEdge *sesym, *newse, *newsesym, *senext, *sesymprev, *sesymprevsym;
+ /* Split e at lambda. */
+ a = se->vert->co;
+ b = se->next->vert->co;
+ sesym = sym(se);
+ sesymprev = prev(sesym);
+ sesymprevsym = sym(sesymprev);
+ senext = se->next;
+ p[0] = (1.0 - lambda) * a[0] + lambda * b[0];
+ p[1] = (1.0 - lambda) * a[1] + lambda * b[1];
+ v = add_cdtvert(cdt, p[0], p[1]);
+ e = add_cdtedge(cdt, v, se->next->vert, se->face, sesym->face);
+ sesym->vert = v;
+ newse = &e->symedges[0];
+ newsesym = &e->symedges[1];
+ se->next = newse;
+ newsesym->next = sesym;
+ newse->next = senext;
+ newse->rot = sesym;
+ sesym->rot = newse;
+ senext->rot = newsesym;
+ newsesym->rot = sesymprevsym;
+ sesymprev->next = newsesym;
+ if (newsesym->vert->symedge == sesym) {
+ newsesym->vert->symedge = newsesym;
+ }
+ add_list_to_input_ids(&e->input_ids, se->edge->input_ids, cdt);
+ calc_face_centroid(se);
+ calc_face_centroid(sesym);
+ return e;
+}
+
+/**
+ * Delete an edge from the structure. The new combined face on either side of
+ * the deleted edge will be the one that was e's face; the centroid is updated.
+ * There will be now an unused face, marked by setting its deleted flag,
+ * and an unused #CDTEdge, marked by setting the next and rot pointers of
+ * its SymEdges to NULL.
+ * <pre>
+ * . v2 .
+ * / \ / \
+ * /f|j\ / \
+ * / | \ / \
+ * |
+ * A | B A
+ * \ e| / \ /
+ * \ | / \ /
+ * \h|i/ \ /
+ * . v1 .
+ * </pre>
+ * Also handle variant cases where one or both ends
+ * are attached only to e.
+ */
+static void delete_edge(CDT_state *cdt, SymEdge *e)
+{
+ SymEdge *esym, *f, *h, *i, *j, *k, *jsym, *hsym;
+ CDTFace *aface, *bface;
+ CDTVert *v1, *v2;
+ bool v1_isolated, v2_isolated;
+
+ esym = sym(e);
+ v1 = e->vert;
+ v2 = esym->vert;
+ aface = e->face;
+ bface = esym->face;
+ f = e->next;
+ h = prev(e);
+ i = esym->next;
+ j = prev(esym);
+ jsym = sym(j);
+ hsym = sym(h);
+ v1_isolated = (i == e);
+ v2_isolated = (f == esym);
+
+ if (!v1_isolated) {
+ h->next = i;
+ i->rot = hsym;
+ }
+ if (!v2_isolated) {
+ j->next = f;
+ f->rot = jsym;
+ }
+ if (!v1_isolated && !v2_isolated && aface != bface) {
+ for (k = i; k != f; k = k->next) {
+ k->face = aface;
+ }
+ }
+
+ /* If e was representative symedge for v1 or v2, fix that. */
+ if (v1_isolated) {
+ v1->symedge = NULL;
+ }
+ else if (v1->symedge == e) {
+ v1->symedge = i;
+ }
+ if (v2_isolated) {
+ v2->symedge = NULL;
+ }
+ else if (v2->symedge == esym) {
+ v2->symedge = f;
+ }
+
+ /* Mark SymEdge as deleted by setting all its pointers to NULL. */
+ e->next = e->rot = NULL;
+ esym->next = esym->rot = NULL;
+ if (!v1_isolated && !v2_isolated && aface != bface) {
+ bface->deleted = true;
+ if (cdt->outer_face == bface) {
+ cdt->outer_face = aface;
+ }
+ }
+ if (aface != cdt->outer_face) {
+ calc_face_centroid(f);
+ }
+}
+
+/**
+ * The initial structure will be the rectangle with opposite corners (minx,miny)
+ * and (maxx,maxy), and a diagonal going between those two corners.
+ * We keep track of the outer face (surrounding the entire structure; its boundary
+ * is the clockwise traversal of the bounding box rectangle initially) in cdt->outer_face.
+ *
+ * The vertices are kept as pointers in an array (which may need to be reallocated from
+ * time to time); the edges and faces are kept in lists. Sometimes edges and faces are deleted,
+ * marked by setting all pointers to NULL (for edges), or setting the deleted flag to true (for
+ * faces).
+ *
+ * A #MemArena is allocated to do all allocations from except for link list nodes; a listpool
+ * is created for link list node allocations.
+ *
+ * The epsilon argument is stored and used in "near enough" distance calculations.
+ *
+ * When done, caller must call BLI_constrained_delaunay_free to free
+ * the memory used by the returned #CDT_state.
+ */
+static CDT_state *cdt_init(double minx, double maxx, double miny, double maxy, double epsilon)
+{
+ double x0, x1, y0, y1;
+ double margin;
+ CDTVert *v[4];
+ CDTEdge *e[4];
+ CDTFace *f0, *fouter;
+ int i, inext, iprev;
+ MemArena *arena = BLI_memarena_new(DLNY_ARENASIZE, __func__);
+ CDT_state *cdt = BLI_memarena_alloc(arena, sizeof(CDT_state));
+ cdt->edges = NULL;
+ cdt->faces = NULL;
+ cdt->vert_array_len = 0;
+ cdt->vert_array_len_alloc = 32;
+ cdt->vert_array = BLI_memarena_alloc(arena,
+ cdt->vert_array_len_alloc * sizeof(*cdt->vert_array));
+ cdt->minx = minx;
+ cdt->miny = miny;
+ cdt->maxx = maxx;
+ cdt->maxy = maxy;
+ cdt->arena = arena;
+ cdt->listpool = BLI_mempool_create(sizeof(LinkNode), 128, 128, 0);
+ cdt->rng = BLI_rng_new(0);
+ cdt->epsilon = epsilon;
+
+ /* Expand bounding box a bit and make initial CDT from it. */
+ margin = DLNY_MARGIN_PCT * max_dd(maxx - minx, maxy - miny) / 100.0;
+ if (margin <= 0.0) {
+ margin = 1.0;
+ }
+ if (margin < epsilon) {
+ margin = 4 * epsilon; /* Make sure constraint verts don't merge with border verts. */
+ }
+ cdt->margin = margin;
+ x0 = minx - margin;
+ y0 = miny - margin;
+ x1 = maxx + margin;
+ y1 = maxy + margin;
+
+ /* Make a quad, then split it with a diagonal. */
+ v[0] = add_cdtvert(cdt, x0, y0);
+ v[1] = add_cdtvert(cdt, x1, y0);
+ v[2] = add_cdtvert(cdt, x1, y1);
+ v[3] = add_cdtvert(cdt, x0, y1);
+ cdt->outer_face = fouter = add_cdtface(cdt);
+ f0 = add_cdtface(cdt);
+ for (i = 0; i < 4; i++) {
+ e[i] = add_cdtedge(cdt, v[i], v[(i + 1) % 4], f0, fouter);
+ }
+ for (i = 0; i < 4; i++) {
+ inext = (i + 1) % 4;
+ iprev = (i + 3) % 4;
+ e[i]->symedges[0].next = &e[inext]->symedges[0];
+ e[inext]->symedges[1].next = &e[i]->symedges[1];
+ e[i]->symedges[0].rot = &e[iprev]->symedges[1];
+ e[iprev]->symedges[1].rot = &e[i]->symedges[0];
+ }
+ calc_face_centroid(&e[0]->symedges[0]);
+ add_diagonal(cdt, &e[0]->symedges[0], &e[2]->symedges[0]);
+ fouter->centroid[0] = fouter->centroid[1] = 0.0;
+
+ cdt->visit_count = 0;
+ cdt->output_prepared = false;
+ cdt->face_edge_offset = 0;
+ return cdt;
+}
+
+static void cdt_free(CDT_state *cdt)
+{
+ BLI_rng_free(cdt->rng);
+ BLI_mempool_destroy(cdt->listpool);
+ BLI_memarena_free(cdt->arena);
+}
+
+static bool locate_point_final(const double p[2],
+ SymEdge *tri_se,
+ bool try_neighbors,
+ const double epsilon,
+ LocateResult *r_lr)
+{
+ /* 'p' should be in or on our just outside of 'cur_tri'. */
+ double dist_inside[3];
+ int i;
+ SymEdge *se;
+ const double *a, *b;
+ double lambda, close[2];
+ bool done = false;
+#ifdef DEBUG_CDT
+ int dbglevel = 0;
+ if (dbglevel > 0) {
+ fprintf(stderr, "locate_point_final %d\n", try_neighbors);
+ dump_se(tri_se, "tri_se");
+ fprintf(stderr, "\n");
+ }
+#endif
+ se = tri_se;
+ i = 0;
+ do {
+#ifdef DEBUG_CDT
+ if (dbglevel > 1) {
+ fprintf(stderr, "%d: ", i);
+ dump_se(se, "search se");
+ }
+#endif
+ a = se->vert->co;
+ b = se->next->vert->co;
+ lambda = closest_to_line_v2_db(close, p, a, b);
+ double len_close_p = len_v2v2_db(close, p);
+ if (len_close_p < epsilon) {
+ if (len_v2v2_db(p, a) < epsilon) {
+#ifdef DEBUG_CDT
+ if (dbglevel > 0) {
+ fprintf(stderr, "OnVert case a (%.2f,%.2f)\n", F2(a));
+ }
+#endif
+ r_lr->loc_kind = OnVert;
+ r_lr->se = se;
+ r_lr->edge_lambda = 0.0;
+ done = true;
+ }
+ else if (len_v2v2_db(p, b) < epsilon) {
+#ifdef DEBUG_CDT
+ if (dbglevel > 0) {
+ fprintf(stderr, "OnVert case b (%.2f,%.2f)\n", F2(b));
+ }
+#endif
+ r_lr->loc_kind = OnVert;
+ r_lr->se = se->next;
+ r_lr->edge_lambda = 0.0;
+ done = true;
+ }
+ else if (lambda > 0.0 && lambda < 1.0) {
+#ifdef DEBUG_CDT
+ if (dbglevel > 0) {
+ fprintf(stderr, "OnEdge case, lambda=%f\n", lambda);
+ dump_se(se, "se");
+ }
+#endif
+ r_lr->loc_kind = OnEdge;
+ r_lr->se = se;
+ r_lr->edge_lambda = lambda;
+ done = true;
+ }
+ }
+ else {
+ dist_inside[i] = len_close_p;
+ dist_inside[i] = CCW_test(a, b, p) >= 0 ? len_close_p : -len_close_p;
+ }
+ i++;
+ se = se->next;
+ } while (se != tri_se && !done);
+ if (!done) {
+#ifdef DEBUG_CDT
+ if (dbglevel > 1) {
+ fprintf(stderr,
+ "not done, dist_inside=%f %f %f\n",
+ dist_inside[0],
+ dist_inside[1],
+ dist_inside[2]);
+ }
+#endif
+ if (dist_inside[0] >= 0.0 && dist_inside[1] >= 0.0 && dist_inside[2] >= 0.0) {
+#ifdef DEBUG_CDT
+ if (dbglevel > 0) {
+ fprintf(stderr, "InFace case\n");
+ dump_se_cycle(tri_se, "tri", 10);
+ }
+#endif
+ r_lr->loc_kind = InFace;
+ r_lr->se = tri_se;
+ r_lr->edge_lambda = 0.0;
+ done = true;
+ }
+ else if (try_neighbors) {
+ for (se = tri_se->next; se != tri_se; se = se->next) {
+ if (locate_point_final(p, se, false, epsilon, r_lr)) {
+ done = true;
+ break;
+ }
+ }
+ if (!done) {
+ /* Shouldn't happen desperation mode: pick something. */
+ se = NULL;
+ if (dist_inside[0] > 0) {
+ se = tri_se;
+ }
+ if (dist_inside[1] > 0 && (se == NULL || dist_inside[1] < dist_inside[i])) {
+ se = tri_se->next;
+ }
+ if (se == NULL) {
+ se = tri_se->next->next;
+ }
+ a = se->vert->co;
+ b = se->next->vert->co;
+ lambda = closest_to_line_v2_db(close, p, a, b);
+ if (lambda <= 0.0) {
+ r_lr->loc_kind = OnVert;
+ r_lr->se = se;
+ r_lr->edge_lambda = 0.0;
+ }
+ else if (lambda >= 1.0) {
+ r_lr->loc_kind = OnVert;
+ r_lr->se = se->next;
+ r_lr->edge_lambda = 0.0;
+ }
+ else {
+ r_lr->loc_kind = OnEdge;
+ r_lr->se = se->next;
+ r_lr->edge_lambda = lambda;
+ }
+#ifdef DEBUG_CDT
+ if (dbglevel > 0) {
+ fprintf(
+ stderr, "desperation case kind=%u lambda=%f\n", r_lr->loc_kind, r_lr->edge_lambda);
+ dump_se(r_lr->se, "se");
+ BLI_assert(0); /* While developing, catch these "should not happens" */
+ }
+#endif
+ fprintf(stderr, "desperation!\n"); // TODO: remove
+ return true;
+ }
+ }
+ }
+ return done;
+}
+
+static LocateResult locate_point(CDT_state *cdt, const double p[2])
+{
+ LocateResult lr;
+ SymEdge *cur_se, *next_se, *next_se_sym;
+ CDTFace *cur_tri;
+ bool done;
+ int sample_n, i, k;
+ CDTVert *v, *best_start_vert;
+ double dist_squared, best_dist_squared;
+ double *a, *b, *c;
+ const double epsilon = cdt->epsilon;
+ int visit = ++cdt->visit_count;
+ int loop_count = 0;
+#ifdef DEBUG_CDT
+ int dbglevel = 0;
+
+ if (dbglevel > 0) {
+ fprintf(stderr, "locate_point (%.2f,%.2f), visit_index=%d\n", F2(p), visit);
+ }
+#endif
+ /* Starting point determined by closest to p in an n ** (1/3) sized sample of current points. */
+ BLI_assert(cdt->vert_array_len > 0);
+ sample_n = (int)round(pow((double)cdt->vert_array_len, 0.33333));
+ if (sample_n < 1) {
+ sample_n = 1;
+ }
+ best_start_vert = NULL;
+ best_dist_squared = DBL_MAX;
+ for (k = 0; k < sample_n; k++) {
+ /* Yes, this may try some i's more than once,
+ * but will still get about an n ** (1/3) size sample. */
+ i = (int)(BLI_rng_get_uint(cdt->rng) % cdt->vert_array_len);
+ v = cdt->vert_array[i];
+ dist_squared = len_squared_v2v2_db(p, v->co);
+#ifdef DEBUG_CDT
+ if (dbglevel > 0) {
+ fprintf(stderr, "try start vert %d, dist_squared=%f\n", i, dist_squared);
+ dump_v(v, "v");
+ }
+#endif
+ if (dist_squared < best_dist_squared) {
+ best_dist_squared = dist_squared;
+ best_start_vert = v;
+ }
+ }
+ cur_se = &best_start_vert->symedge[0];
+ if (cur_se->face == cdt->outer_face) {
+ cur_se = cur_se->rot;
+ BLI_assert(cur_se->face != cdt->outer_face);
+ }
+#ifdef DEBUG_CDT
+ if (dbglevel > 0) {
+ dump_se(cur_se, "start vert edge");
+ }
+#endif
+ done = false;
+ while (!done) {
+ /* Find edge of cur_tri that separates p and t's centroid,
+ * and where other tri over the edge is unvisited. */
+#ifdef DEBUG_CDT
+ if (dbglevel > 0) {
+ dump_se_cycle(cur_se, "cur search face", 5);
+ }
+#endif
+ cur_tri = cur_se->face;
+ BLI_assert(cur_tri != cdt->outer_face);
+ cur_tri->visit_index = visit;
+ /* Is p in or on current triangle? */
+ 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) {
+#ifdef DEBUG_CDT
+ if (dbglevel > 1) {
+ fprintf(stderr, "p in current triangle\n");
+ }
+#endif
+ done = locate_point_final(p, cur_se, false, epsilon, &lr);
+ BLI_assert(done == true);
+ break;
+ }
+ bool found_next = false;
+ next_se = cur_se;
+ do {
+ a = next_se->vert->co;
+ b = next_se->next->vert->co;
+ c = next_se->next->next->vert->co;
+#ifdef DEBUG_CDT
+ if (dbglevel > 1) {
+ dump_se(next_se, "search edge");
+ fprintf(stderr, "tri centroid=(%.2f,%.2f)\n", F2(cur_tri->centroid));
+ validate_face_centroid(next_se);
+ }
+#endif
+ next_se_sym = sym(next_se);
+ if (CCW_test(a, b, p) <= 0 && next_se->face != cdt->outer_face) {
+#ifdef DEBUG_CDT
+ if (dbglevel > 1) {
+ fprintf(stderr, "CCW_test(a, b, p) <= 0\n");
+ }
+#endif
+#ifdef DEBUG_CDT
+ if (dbglevel > 0) {
+ dump_se(next_se_sym, "next_se_sym");
+ fprintf(stderr, "next_se_sym face visit=%d\n", next_se_sym->face->visit_index);
+ }
+#endif
+ if (next_se_sym->face->visit_index != visit) {
+#ifdef DEBUG_CDT
+ if (dbglevel > 0) {
+ fprintf(stderr, "found edge to cross\n");
+ }
+#endif
+ found_next = true;
+ cur_se = next_se_sym;
+ break;
+ }
+ }
+ next_se = next_se->next;
+ } while (next_se != cur_se);
+ if (!found_next) {
+ done = locate_point_final(p, cur_se, true, epsilon, &lr);
+ BLI_assert(done = true);
+ done = true;
+ }
+ if (++loop_count > 1000000) {
+ fprintf(stderr, "infinite search loop?\n");
+ done = locate_point_final(p, cur_se, true, epsilon, &lr);
+ }
+ }
+
+ return lr;
+}
+
+/** return true if circumcircle(v1, v2, v3) does not contain p. */
+static bool delaunay_check(CDTVert *v1, CDTVert *v2, CDTVert *v3, CDTVert *p, const double epsilon)
+{
+ double a, b, c, d, z1, z2, z3;
+ const double *p1, *p2, *p3;
+ double cen[2], r, len_pc;
+ /* To do epislon test, need center and radius of circumcircle. */
+ p1 = v1->co;
+ p2 = v2->co;
+ p3 = v3->co;
+ z1 = dot_v2v2_db(p1, p1);
+ z2 = dot_v2v2_db(p2, p2);
+ z3 = dot_v2v2_db(p3, p3);
+ a = p1[0] * (p2[1] - p3[1]) - p1[1] * (p2[0] - p3[0]) + p2[0] * p3[1] - p3[0] * p2[1];
+ b = z1 * (p3[1] - p2[1]) + z2 * (p1[1] - p3[1]) + z3 * (p2[1] - p1[1]);
+ c = z1 * (p2[0] - p3[0]) + z2 * (p3[0] - p1[0]) + z3 * (p1[0] - p2[0]);
+ d = z1 * (p3[0] * p2[1] - p2[0] * p3[1]) + z2 * (p1[0] * p3[1] - p3[0] * p1[1]) +
+ z3 * (p2[0] * p1[1] - p1[0] * p2[1]);
+ if (a == 0.0) {
+ return true; /* Not really, but this shouldn't happen. */
+ }
+ cen[0] = -b / (2 * a);
+ cen[1] = -c / (2 * a);
+ r = sqrt((b * b + c * c - 4 * a * d) / (4 * a * a));
+ len_pc = len_v2v2_db(p->co, cen);
+ return (len_pc >= (r - epsilon));
+}
+
+/** Use LinkNode linked list as stack of SymEdges, allocating from cdt->listpool. */
+typedef LinkNode *Stack;
+
+static inline void push(Stack *stack, SymEdge *se, CDT_state *cdt)
+{
+ BLI_linklist_prepend_pool(stack, se, cdt->listpool);
+}
+
+static inline SymEdge *pop(Stack *stack, CDT_state *cdt)
+{
+ return (SymEdge *)BLI_linklist_pop_pool(stack, cdt->listpool);
+}
+
+static inline bool is_empty(Stack *stack)
+{
+ return *stack == NULL;
+}
+
+/**
+ * <pre>
+ * /\ /\
+ * /a|\ / \
+ * / | sesym / \
+ * / | \ / \
+ * . b | d . -> . se______
+ * \ se| / \ /
+ * \ |c/ \ /
+ * \ |/ \ /
+ * </pre>
+ */
+static void flip(SymEdge *se, CDT_state *cdt)
+{
+ SymEdge *a, *b, *c, *d;
+ SymEdge *sesym, *asym, *bsym, *csym, *dsym;
+ CDTFace *t1, *t2;
+ CDTVert *v1, *v2;
+#ifdef DEBUG_CDT
+ const int dbglevel = 0;
+#endif
+
+ sesym = sym(se);
+#ifdef DEBUG_CDT
+ if (dbglevel > 0) {
+ fprintf(stderr, "flip\n");
+ dump_se(se, "se");
+ dump_se(sesym, "sesym");
+ }
+#endif
+ a = se->next;
+ b = a->next;
+ c = sesym->next;
+ d = c->next;
+ asym = sym(a);
+ bsym = sym(b);
+ csym = sym(c);
+ dsym = sym(d);
+#ifdef DEBUG_CDT
+ if (dbglevel > 1) {
+ dump_se(a, "a");
+ dump_se(b, "b");
+ dump_se(c, "c");
+ dump_se(d, "d");
+ }
+#endif
+ v1 = se->vert;
+ v2 = sesym->vert;
+ t1 = a->face;
+ t2 = c->face;
+
+ se->vert = b->vert;
+ sesym->vert = d->vert;
+
+ a->next = se;
+ se->next = d;
+ d->next = a;
+
+ sesym->next = b;
+ b->next = c;
+ c->next = sesym;
+
+ a->rot = dsym;
+ b->rot = se;
+ se->rot = asym;
+
+ c->rot = bsym;
+ d->rot = sesym;
+ sesym->rot = csym;
+
+ a->face = se->face = d->face = t1;
+ sesym->face = b->face = c->face = t2;
+
+ if (v1->symedge == se) {
+ v1->symedge = c;
+ }
+ if (v2->symedge == sesym) {
+ v2->symedge = a;
+ }
+
+ calc_face_centroid(a);
+ calc_face_centroid(sesym);
+
+#ifdef DEBUG_CDT
+ if (dbglevel > 0) {
+ fprintf(stderr, "after flip\n");
+ dump_se_cycle(a, "a cycle", 5);
+ dump_se_cycle(sesym, "sesym cycle", 5);
+ }
+#endif
+ if (cdt) {
+ /* Pass. */
+ }
+}
+
+static void flip_edges(CDTVert *v, Stack *stack, CDT_state *cdt)
+{
+ SymEdge *se, *sesym;
+ CDTVert *a, *b, *c, *d;
+ SymEdge *tri_without_p;
+ bool is_delaunay;
+ const double epsilon = cdt->epsilon;
+ int count = 0;
+#ifdef DEBUG_CDT
+ const int dbglevel = 0;
+ if (dbglevel > 0) {
+ fprintf(stderr, "flip_edges, v=(%.2f,%.2f)\n", F2(v->co));
+ }
+#endif
+ while (!is_empty(stack)) {
+ if (++count > 10000) {
+ fprintf(stderr, "infinite flip loop?\n");
+ return;
+ }
+ se = pop(stack, cdt);
+#ifdef DEBUG_CDT
+ if (dbglevel > 0) {
+ dump_se(se, "flip_edges popped");
+ }
+#endif
+ if (!is_constrained_edge(se->edge)) {
+ /* Edge is not constrained; is it Delaunay? */
+#ifdef DEBUG_CDT
+ if (dbglevel > 1) {
+ dump_se_cycle(se, "unconstrained edge", 5);
+ }
+ else if (dbglevel > 0) {
+ fprintf(stderr, "unconstrained edge\n");
+ }
+#endif
+ a = se->vert;
+ b = se->next->vert;
+ c = se->next->next->vert;
+ sesym = sym(se);
+ d = sesym->next->next->vert;
+#ifdef DEBUG_CDT
+ if (dbglevel > 1) {
+ fprintf(stderr, "a=(%.2f,%.2f) b=(%.2f,%.2f)\n", F2(a->co), F2(b->co));
+ fprintf(stderr, "c=(%.2f,%.2f) d=(%.2f,%.2f)\n", F2(c->co), F2(d->co));
+ }
+#endif
+ if (v == c) {
+ tri_without_p = sesym;
+ is_delaunay = delaunay_check(a, b, c, d, epsilon);
+#ifdef DEBUG_CDT
+ if (dbglevel > 1) {
+ fprintf(stderr, "v==c, delaunay(a,b,c,d)=%d\n", is_delaunay);
+ }
+#endif
+ }
+ else {
+ tri_without_p = se;
+ BLI_assert(d == v);
+ is_delaunay = delaunay_check(b, a, d, c, epsilon);
+#ifdef DEBUG_CDT
+ if (dbglevel > 1) {
+ fprintf(stderr, "v!=c, delaunay(b,a,d,c)=%d\n", is_delaunay);
+ }
+#endif
+ }
+ if (!is_delaunay) {
+ /* Push two edges of tri without p that aren't se. */
+#ifdef DEBUG_CDT
+ if (dbglevel > 0) {
+ fprintf(stderr, "maybe pushing more edges\n");
+ }
+#endif
+ if (!is_border_edge(tri_without_p->next->edge, cdt)) {
+#ifdef DEBUG_CDT
+ if (dbglevel > 0) {
+ dump_se(tri_without_p->next, "push1");
+ }
+#endif
+ push(stack, tri_without_p->next, cdt);
+ }
+ if (!is_border_edge(tri_without_p->next->next->edge, cdt)) {
+#ifdef DEBUG_CDT
+ if (dbglevel > 0) {
+ dump_se(tri_without_p->next->next, "\npush2");
+ }
+#endif
+ push(stack, tri_without_p->next->next, cdt);
+ }
+ flip(se, cdt);
+ }
+ }
+ }
+}
+
+/**
+ * Splits e at lambda and returns a #SymEdge with new vert as its vert.
+ * The two opposite triangle vertices to e are connect to new point.
+ * <pre>
+ * /\ /\
+ * /f|\ / |\
+ * / |j\ / | \
+ * / | i\ / k| \
+ * . | . -> . l_ p m_.
+ * \g | / \ | /
+ * \ |h/ \ | /
+ * \e|/ \ e|/
+ *
+ * t1 = {e, f, g}; t2 = {h, i, j};
+ * t1' = {e, l.sym, g}; t2' = {h, m.sym, e'.sym}
+ * t3 = {k, f, l}; t4 = {m, i, j}
+ * </pre>
+ */
+static CDTVert *insert_point_in_edge(CDT_state *cdt, SymEdge *e, double lambda)
+{
+ SymEdge *f, *g, *h, *i, *j, *k;
+ CDTEdge *ke;
+ CDTVert *p;
+ Stack stack;
+ /* Split e at lambda. */
+
+ f = e->next;
+ g = f->next;
+ BLI_assert(g->next == e);
+ j = sym(e);
+ h = j->next;
+ i = h->next;
+ BLI_assert(i->next == j);
+
+ ke = split_edge(cdt, e, lambda);
+ k = &ke->symedges[0];
+ p = k->vert;
+
+ add_diagonal(cdt, g, k);
+ add_diagonal(cdt, sym(e), i);
+
+ stack = NULL;
+ if (!is_border_edge(f->edge, cdt)) {
+ push(&stack, f, cdt);
+ }
+ if (!is_border_edge(g->edge, cdt)) {
+ push(&stack, g, cdt);
+ }
+ if (!is_border_edge(h->edge, cdt)) {
+ push(&stack, h, cdt);
+ }
+ if (!is_border_edge(i->edge, cdt)) {
+ push(&stack, i, cdt);
+ }
+ flip_edges(k->vert, &stack, cdt);
+ return p;
+}
+
+/**
+ * Inserts p inside e's triangle and connects the three cornders
+ * of the triangle to the new point. Returns a SymEdge that has
+ * new point as its point.
+ * <pre>
+ * * *
+ * *g * * .j*
+ * * * * . *
+ * * p * -> * 1. p . 3*
+ * * * * . . *
+ * * e f* * . h 2 i . *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * </pre>
+ */
+static CDTVert *insert_point_in_face(CDT_state *cdt, SymEdge *e, const double p[2])
+{
+ SymEdge *f, *g, *h, *i, *j;
+ SymEdge *esym, *fsym, *gsym, *hsym, *isym, *jsym;
+ CDTVert *v;
+ CDTEdge *he, *ie, *je;
+ CDTFace *t1, *t2, *t3;
+ Stack stack;
+
+ f = e->next;
+ g = f->next;
+ esym = sym(e);
+ fsym = sym(f);
+ gsym = sym(g);
+ t1 = e->face;
+ t2 = add_cdtface(cdt);
+ t3 = add_cdtface(cdt);
+
+ v = add_cdtvert(cdt, p[0], p[1]);
+ he = add_cdtedge(cdt, e->vert, v, t1, t2);
+ h = &he->symedges[0];
+ hsym = &he->symedges[1];
+ ie = add_cdtedge(cdt, f->vert, v, t2, t3);
+ i = &ie->symedges[0];
+ isym = &ie->symedges[1];
+ je = add_cdtedge(cdt, g->vert, v, t3, t1);
+ j = &je->symedges[0];
+ jsym = &je->symedges[1];
+
+ e->next = i;
+ i->next = hsym;
+ hsym->next = e;
+ e->face = t2;
+
+ f->next = j;
+ j->next = isym;
+ isym->next = f;
+ f->face = t3;
+
+ g->next = h;
+ h->next = jsym;
+ jsym->next = g;
+ g->face = t1;
+
+ e->rot = h;
+ i->rot = esym;
+ hsym->rot = isym;
+
+ f->rot = i;
+ j->rot = fsym;
+ isym->rot = jsym;
+
+ g->rot = j;
+ h->rot = gsym;
+ jsym->rot = hsym;
+
+ calc_face_centroid(e);
+ calc_face_centroid(f);
+ calc_face_centroid(g);
+
+ stack = NULL;
+ if (!is_border_edge(e->edge, cdt)) {
+ push(&stack, e, cdt);
+ }
+ if (!is_border_edge(f->edge, cdt)) {
+ push(&stack, f, cdt);
+ }
+ if (!is_border_edge(g->edge, cdt)) {
+ push(&stack, g, cdt);
+ }
+ flip_edges(v, &stack, cdt);
+
+ return v;
+}
+
+/**
+ * Re-triangulates, assuring constrained delaunay condition,
+ * the pseudo-polygon that cycles from se.
+ * "pseudo" because a vertex may be repeated.
+ * See Anglada paper, "An Improved incremental algorithm
+ * for constructing restricted Delaunay triangulations".
+ */
+static void re_delaunay_triangulate(CDT_state *cdt, SymEdge *se)
+{
+ SymEdge *ss, *first, *cse;
+ CDTVert *a, *b, *c, *v;
+ CDTEdge *ebc, *eca;
+ const double epsilon = cdt->epsilon;
+ int count;
+#ifdef DEBUG_CDT
+ SymEdge *last;
+ const int dbg_level = 0;
+
+ if (dbg_level > 0) {
+ fprintf(stderr, "retriangulate");
+ dump_se_cycle(se, "poly ", 1000);
+ }
+#endif
+ /* 'se' is a diagonal just added, and it is base of area to retriangulate (face on its left) */
+ count = 1;
+ for (ss = se->next; ss != se; ss = ss->next) {
+ count++;
+ }
+ if (count <= 3) {
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "nothing to do\n");
+ }
+#endif
+ return;
+ }
+ /* First and last are the SymEdges whose verts are first and last off of base,
+ * continuing from 'se'. */
+ first = se->next->next;
+ /* We want to make a triangle with 'se' as base and some other c as 3rd vertex. */
+ a = se->vert;
+ b = se->next->vert;
+ c = first->vert;
+ cse = first;
+#ifdef DEBUG_CDT
+ last = prev(se);
+ if (dbg_level > 1) {
+ dump_se(first, "first");
+ dump_se(last, "last");
+ dump_v(a, "a");
+ dump_v(b, "b");
+ dump_v(c, "c");
+ }
+#endif
+ for (ss = first->next; ss != se; ss = ss->next) {
+ v = ss->vert;
+ if (!delaunay_check(a, b, c, v, epsilon)) {
+ c = v;
+ cse = ss;
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ dump_v(c, "new c ");
+ }
+#endif
+ }
+ }
+ /* Add diagonals necessary to make abc a triangle. */
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "make triangle abc exist where\n");
+ dump_v(a, " a");
+ dump_v(b, " b");
+ dump_v(c, " c");
+ }
+#endif
+ ebc = NULL;
+ eca = NULL;
+ if (!exists_edge(b, c)) {
+ ebc = add_diagonal(cdt, se->next, cse);
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(stderr, "added edge ebc\n");
+ dump_se(&ebc->symedges[0], " ebc");
+ }
+#endif
+ }
+ if (!exists_edge(c, a)) {
+ eca = add_diagonal(cdt, cse, se);
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(stderr, "added edge eca\n");
+ dump_se(&eca->symedges[0], " eca");
+ }
+#endif
+ }
+ /* Now recurse. */
+ if (ebc) {
+ re_delaunay_triangulate(cdt, &ebc->symedges[1]);
+ }
+ if (eca) {
+ re_delaunay_triangulate(cdt, &eca->symedges[1]);
+ }
+}
+
+/**
+ * Add a constrained point to cdt structure, and return the corresponding CDTVert*.
+ * May not be at exact coords given, because it can be merged with an existing vertex
+ * or moved to an existing edge (which could be a triangulation edge, not just a constraint one)
+ * if the point is within cdt->epsilon of those other elements.
+ *
+ * input_id will be added to the list of input_ids for the returned CDTVert (don't use -1 for id).
+ *
+ * Assumes cdt has been initialized, with min/max bounds that contain coords.
+ * Assumes that #BLI_constrained_delaunay_get_output has not been called yet.
+ */
+static CDTVert *add_point_constraint(CDT_state *cdt, const double coords[2], int input_id)
+{
+ LocateResult lr;
+ CDTVert *v;
+#ifdef DEBUG_CDT
+ const int dbg_level = 0;
+#endif
+
+ BLI_assert(!cdt->output_prepared);
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "add point constraint (%.3f,%.3f), id=%d\n", F2(coords), input_id);
+ }
+#endif
+ lr = locate_point(cdt, coords);
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, " locate result has loc_kind %u\n", lr.loc_kind);
+ }
+#endif
+ if (lr.loc_kind == OnVert) {
+ v = lr.se->vert;
+ }
+ else if (lr.loc_kind == OnEdge) {
+ v = insert_point_in_edge(cdt, lr.se, lr.edge_lambda);
+ }
+ else {
+ v = insert_point_in_face(cdt, lr.se, coords);
+ }
+ add_to_input_ids(&v->input_ids, input_id, cdt);
+ return v;
+}
+
+/**
+ * Add a constrained edge between v1 and v2 to cdt structure.
+ * This may result in a number of #CDTEdges created, due to intersections
+ * and partial overlaps with existing cdt vertices and edges.
+ * Each created #CDTEdge will have input_id added to its input_ids list.
+ *
+ * If \a r_edges is not NULL, the #CDTEdges generated or found that go from
+ * v1 to v2 are put into that linked list, in order.
+ *
+ * Assumes that #BLI_constrained_delaunay_get_output has not been called yet.
+ */
+static void add_edge_constraint(
+ CDT_state *cdt, CDTVert *v1, CDTVert *v2, int input_id, LinkNode **r_edges)
+{
+ CDTVert *va, *vb, *vc;
+ SymEdge *vse1;
+#ifdef DEBUG_CDT
+ SymEdge *vse2;
+#endif
+ SymEdge *t, *tstart, *tout, *tnext;
+ SymEdge *se;
+ CDTEdge *edge;
+ int ccw1, ccw2, isect;
+ int i, search_count;
+ double lambda;
+ bool done, state_through_vert;
+ LinkNodePair edge_list = {NULL, NULL};
+ typedef struct CrossData {
+ double lambda;
+ CDTVert *vert;
+ SymEdge *in;
+ SymEdge *out;
+ } CrossData;
+ CrossData cdata;
+ CrossData *crossings = NULL;
+ CrossData *cd;
+ BLI_array_staticdeclare(crossings, 128);
+#ifdef DEBUG_CDT
+ const int dbg_level = 0;
+#endif
+
+ /* Find path through structure from v1 to v2 and record how we got there in crossings.
+ * In crossings array, each CrossData is populated as follows:
+ *
+ * If ray from previous node goes through a face, not along an edge:
+ *
+ * _ B
+ * / |\
+ * - - | \
+ * prev........X \
+ * \ d | \C
+ * -- | /
+ * \ a| b/
+ * - - | /
+ * \ A
+ *
+ * lambda = fraction of way along AB where X is.
+ * vert = NULL initially, will later get new node that splits AB
+ * in = a (SymEdge from A->B, whose face the ray goes through)
+ * out = b (SymEdge from A->C, whose face the ray goes through next
+ *
+ * If the ray from the previous node goes directly to an existing vertex, say A
+ * in the previous diagram, maybe along an existing edge like d in that diagram
+ * but if prev had lambda !=0 then there may be no such edge d, then:
+ *
+ * lambda = 0
+ * vert = A
+ * in = a
+ * out = b
+ *
+ * crossings[0] will have in = NULL, and crossings[last] will have out = NULL
+ */
+ if (r_edges) {
+ *r_edges = NULL;
+ }
+ vse1 = v1->symedge;
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ vse2 = v2->symedge;
+ fprintf(stderr, "\ninsert_segment %d\n", input_id);
+ dump_v(v1, " 1");
+ dump_v(v2, " 2");
+ if (dbg_level > 1) {
+ dump_se(vse1, " se1");
+ dump_se(vse2, " se2");
+ }
+ }
+#endif
+ if (v1 == v2) {
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "segment between same vertices, ignored\n");
+ }
+#endif
+ return;
+ }
+ state_through_vert = true;
+ done = false;
+ t = vse1;
+ search_count = 0;
+ while (!done) {
+ /* Invariant: crossings[0 .. BLI_array_len(crossings)] has crossing info for path up to
+ * but not including the crossing of edge t, which will either be through a vert
+ * (if state_through_vert is true) or through edge t not at either end.
+ * In the latter case, t->face is the face that ray v1--v2 goes through after path-so-far.
+ */
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(
+ stderr, "top of insert_segment main loop, state_through_vert=%d\n", state_through_vert);
+ dump_se_cycle(t, "current t ", 4);
+ }
+#endif
+ if (state_through_vert) {
+ /* Invariant: ray v1--v2 contains t->vert. */
+ cdata.in = (BLI_array_len(crossings) == 0) ? NULL : t;
+ cdata.out = NULL; /* To be filled in if this isn't final. */
+ cdata.lambda = 0.0;
+ cdata.vert = t->vert;
+ BLI_array_append(crossings, cdata);
+ if (t->vert == v2) {
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "found v2, so done\n");
+ }
+#endif
+ done = true;
+ }
+ else {
+ /* Do ccw scan of triangles around t->vert to find exit triangle for ray v1--v2. */
+ tstart = t;
+ tout = NULL;
+ 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);
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(stderr, "non-final through vert case\n");
+ dump_v(va, " va");
+ dump_v(vb, " vb");
+ fprintf(stderr, "ccw1=%d, ccw2=%d\n", ccw1, ccw2);
+ }
+#endif
+ if (ccw1 == 0 && in_line(t->vert->co, va->co, v2->co)) {
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "ray goes through va\n");
+ }
+#endif
+ state_through_vert = true;
+ tout = t;
+ t = t->next;
+ break;
+ }
+ else if (ccw2 == 0 && in_line(t->vert->co, vb->co, v2->co)) {
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "ray goes through vb\n");
+ }
+#endif
+ state_through_vert = true;
+ t = t->next->next;
+ tout = sym(t);
+ break;
+ }
+ else if (ccw1 > 0 && ccw2 < 0) {
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "segment intersects\n");
+ }
+#endif
+ state_through_vert = false;
+ tout = t;
+ t = t->next;
+ break;
+ }
+ t = t->rot;
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ dump_se_cycle(t, "next rot tri", 4);
+ }
+#endif
+ } while (t != tstart);
+ BLI_assert(tout != NULL); /* TODO: something sensivle for "this can't happen" */
+ crossings[BLI_array_len(crossings) - 1].out = tout;
+ }
+ }
+ else { /* State is "through edge", not "through vert" */
+ /* Invariant: ray v1--v2 intersects segment t->edge, not at either end.
+ * and t->face is the face we have just passed through. */
+ va = t->vert;
+ vb = t->next->vert;
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(stderr, "through edge case\n");
+ dump_v(va, " va");
+ dump_v(vb, " vb");
+ }
+#endif
+ isect = isect_seg_seg_v2_lambda_mu_db(va->co, vb->co, v1->co, v2->co, &lambda, NULL);
+ /* TODO: something sensible for "this can't happen" */
+ BLI_assert(isect == ISECT_LINE_LINE_CROSS);
+ UNUSED_VARS_NDEBUG(isect);
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "intersect point at %f along va--vb\n", lambda);
+ if (dbg_level == 1) {
+ dump_v(va, " va");
+ dump_v(vb, " vb");
+ }
+ }
+#endif
+ tout = sym(t)->next;
+ cdata.in = t;
+ cdata.out = tout;
+ cdata.lambda = lambda;
+ cdata.vert = NULL; /* To be filled in with edge split vertex later. */
+ BLI_array_append(crossings, cdata);
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ dump_se_cycle(tout, "next search tri", 4);
+ }
+#endif
+ /* '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);
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(stderr, "now searching with third vertex ");
+ dump_v(vc, "vc");
+ fprintf(stderr, "ccw(v1, v2, vc) = %d\n", ccw1);
+ }
+#endif
+ if (ccw1 == -1) {
+ /* v1--v2 should intersect vb--vc. */
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(stderr, "v1--v2 intersects vb--vc\n");
+ }
+#endif
+ t = tout->next;
+ state_through_vert = false;
+ }
+ else if (ccw1 == 1) {
+ /* v1--v2 should intersect va--vc. */
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(stderr, "v1--v2 intersects va--vc\n");
+ }
+#endif
+ t = tout;
+ state_through_vert = false;
+ }
+ else {
+ /* ccw1 == 0. */
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(stderr, "ccw==0 case, so going through or to vc\n");
+ }
+#endif
+ t = tout->next;
+ state_through_vert = true;
+ }
+ }
+ if (++search_count > 10000) {
+ fprintf(stderr, "infinite loop? bailing out\n");
+ BLI_assert(0); /* Catch these while developing. */
+ break;
+ }
+ }
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "Crossing info gathered:\n");
+ for (i = 0; i < BLI_array_len(crossings); i++) {
+ cd = &crossings[i];
+ fprintf(stderr, "%d:\n", i);
+ if (cd->vert != NULL) {
+ dump_v(cd->vert, " vert: ");
+ }
+ else {
+ fprintf(stderr, " lambda=%f along in\n", cd->lambda);
+ }
+ if (cd->in) {
+ dump_se(cd->in, " in: ");
+ }
+ if (cd->out) {
+ dump_se(cd->out, " out: ");
+ }
+ }
+ }
+#endif
+
+ if (BLI_array_len(crossings) == 2) {
+ /* For speed, handle special case of segment must have already been there. */
+ se = crossings[1].in;
+ if (se->next->vert != v1) {
+ se = prev(se);
+ }
+ BLI_assert(se->vert == v1 || se->next->vert == v1);
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "segment already there: ");
+ dump_se(se, "");
+ }
+#endif
+ add_to_input_ids(&se->edge->input_ids, input_id, cdt);
+ if (r_edges != NULL) {
+ BLI_linklist_append_pool(&edge_list, se->edge, cdt->listpool);
+ }
+ }
+ else {
+ /* Insert all intersection points. */
+ for (i = 0; i < BLI_array_len(crossings); i++) {
+ cd = &crossings[i];
+ if (cd->lambda != 0.0 && is_constrained_edge(cd->in->edge)) {
+ edge = split_edge(cdt, cd->in, cd->lambda);
+ cd->vert = edge->symedges[0].vert;
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(stderr, "insert vert for crossing %d: ", i);
+ dump_v(cd->vert, "inserted");
+ }
+#endif
+ }
+ }
+
+ /* Remove any crossed, non-intersected edges. */
+ for (i = 0; i < BLI_array_len(crossings); i++) {
+ cd = &crossings[i];
+ if (cd->lambda != 0.0 && !is_constrained_edge(cd->in->edge)) {
+ delete_edge(cdt, cd->in);
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(stderr, "delete edge for crossing %d\n", i);
+ }
+#endif
+ }
+ }
+
+ /* Insert segments for v1->v2. */
+ tstart = crossings[0].out;
+ for (i = 1; i < BLI_array_len(crossings); i++) {
+ cd = &crossings[i];
+ t = tnext = NULL;
+ if (cd->lambda != 0.0) {
+ if (is_constrained_edge(cd->in->edge)) {
+ t = cd->vert->symedge;
+ tnext = sym(t)->next;
+ }
+ }
+ else if (cd->lambda == 0.0) {
+ t = cd->in;
+ tnext = cd->out;
+ }
+ if (t) {
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(stderr, "insert diagonal between\n");
+ dump_se(tstart, " ");
+ dump_se(t, " ");
+ dump_se_cycle(tstart, "tstart", 100);
+ dump_se_cycle(t, "t", 100);
+ }
+#endif
+ if (tstart->next->vert == t->vert) {
+ edge = tstart->edge;
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(stderr, "already there\n");
+ }
+#endif
+ }
+ else {
+ edge = add_diagonal(cdt, tstart, t);
+ }
+ add_to_input_ids(&edge->input_ids, input_id, cdt);
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(stderr, "added\n");
+ }
+#endif
+ if (r_edges != NULL) {
+ BLI_linklist_append_pool(&edge_list, edge, cdt->listpool);
+ }
+ /* Now retriangulate upper and lower gaps. */
+ re_delaunay_triangulate(cdt, &edge->symedges[0]);
+ re_delaunay_triangulate(cdt, &edge->symedges[1]);
+ }
+ if (i < BLI_array_len(crossings) - 1) {
+ if (tnext != NULL) {
+ tstart = tnext;
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(stderr, "now tstart = ");
+ dump_se(tstart, "");
+ }
+#endif
+ }
+ }
+ }
+ }
+ if (r_edges) {
+ *r_edges = edge_list.list;
+ }
+ BLI_array_free(crossings);
+}
+
+/**
+ * Add face_id to the input_ids lists of all #CDTFace's on the interior of the input face with that
+ * id. face_symedge is on edge of the boundary of the input face, with assumption that interior is
+ * on the left of that SymEdge.
+ *
+ * The algorithm is: starting from the #CDTFace for face_symedge, add the face_id and then
+ * process all adjacent faces where the adjacency isn't across an edge that was a constraint added
+ * for the boundary of the input face.
+ * fedge_start..fedge_end is the inclusive range of edge input ids that are for the given face.
+ *
+ * Note: if the input face is not CCW oriented, we'll be labeling the outside, not the inside.
+ * Note 2: if the boundary has self-crossings, this method will arbitrarily pick one of the
+ * contiguous set of faces enclosed by parts of the boundary, leaving the other such untagged. This
+ * may be a feature instead of a bug if the first contiguous section is most of the face and the
+ * others are tiny self-crossing triangles at some parts of the boundary. On the other hand, if
+ * decide we want to handle these in full generality, then will need a more complicated algorithm
+ * (using "inside" tests and a parity rule) to decide on the interior.
+ */
+static void add_face_ids(
+ CDT_state *cdt, SymEdge *face_symedge, int face_id, int fedge_start, int fedge_end)
+{
+ Stack stack;
+ SymEdge *se, *se_start, *se_sym;
+ CDTFace *face, *face_other;
+ int visit;
+
+ /* Can't loop forever since eventually would visit every face. */
+ cdt->visit_count++;
+ visit = cdt->visit_count;
+ stack = NULL;
+ push(&stack, face_symedge, cdt);
+ while (!is_empty(&stack)) {
+ se = pop(&stack, cdt);
+ face = se->face;
+ if (face->visit_index == visit) {
+ continue;
+ }
+ face->visit_index = visit;
+ add_to_input_ids(&face->input_ids, face_id, cdt);
+ se_start = se;
+ for (se = se->next; se != se_start; se = se->next) {
+ if (!id_range_in_list(se->edge->input_ids, fedge_start, fedge_end)) {
+ se_sym = sym(se);
+ face_other = se_sym->face;
+ if (face_other->visit_index != visit) {
+ push(&stack, se_sym, cdt);
+ }
+ }
+ }
+ }
+}
+
+/* Delete_edge but try not to mess up outer face.
+ * Also faces have symedges now, so make sure not
+ * to mess those up either. */
+static void dissolve_symedge(CDT_state *cdt, SymEdge *se)
+{
+ SymEdge *symse = sym(se);
+ if (symse->face == cdt->outer_face) {
+ se = sym(se);
+ symse = sym(se);
+ }
+ if (cdt->outer_face->symedge == se || cdt->outer_face->symedge == symse) {
+ /* Advancing by 2 to get past possible 'sym(se)'. */
+ if (se->next->next == se) {
+ cdt->outer_face->symedge = NULL;
+ }
+ else {
+ cdt->outer_face->symedge = se->next->next;
+ }
+ }
+ else {
+ if (se->face->symedge == se) {
+ se->face->symedge = se->next;
+ }
+ if (symse->face->symedge == se) {
+ symse->face->symedge = symse->next;
+ }
+ }
+ delete_edge(cdt, se);
+}
+
+static void remove_non_constraint_edges(CDT_state *cdt, const bool valid_bmesh)
+{
+ LinkNode *ln;
+ CDTEdge *e;
+ SymEdge *se, *se2;
+ CDTFace *fleft, *fright;
+ bool dissolve;
+
+ for (ln = cdt->edges; ln; ln = ln->next) {
+ e = (CDTEdge *)ln->link;
+ dissolve = !is_deleted_edge(e) && !is_constrained_edge(e);
+ if (dissolve) {
+ se = &e->symedges[0];
+ if (valid_bmesh) {
+ fleft = se->face;
+ fright = sym(se)->face;
+ if (fleft != cdt->outer_face && fright != cdt->outer_face &&
+ (fleft->input_ids != NULL || fright->input_ids != NULL)) {
+ /* Is there another symedge with same left and right faces? */
+ for (se2 = se->next; dissolve && se2 != se; se2 = se2->next) {
+ if (sym(se2)->face == fright) {
+ dissolve = false;
+ }
+ }
+ }
+ }
+ if (dissolve) {
+ dissolve_symedge(cdt, se);
+ }
+ }
+ }
+}
+
+static void remove_outer_edges(CDT_state *cdt, const bool remove_until_constraints)
+{
+ LinkNode *fstack = NULL;
+ SymEdge *se, *se_start;
+ CDTFace *f, *fsym;
+ int visit = ++cdt->visit_count;
+#ifdef DEBUG_CDT
+ int dbg_level = 0;
+
+ if (dbg_level > 0) {
+ fprintf(stderr, "remove_outer_edges, until_constraints=%d\n", remove_until_constraints);
+ }
+#endif
+
+ cdt->outer_face->visit_index = visit;
+
+ /* Find an f, not outer face, but touching outer face. */
+ f = NULL;
+ se_start = se = cdt->vert_array[0]->symedge;
+ do {
+ if (se->face != cdt->outer_face) {
+ f = se->face;
+ break;
+ }
+ se = se->rot;
+ } while (se != se_start);
+ BLI_assert(f != NULL && f->symedge != NULL);
+ if (f == NULL) {
+ return;
+ }
+ BLI_linklist_prepend_pool(&fstack, f, cdt->listpool);
+ while (fstack != NULL) {
+ LinkNode *to_dissolve = NULL;
+ bool dissolvable;
+ f = (CDTFace *)BLI_linklist_pop_pool(&fstack, cdt->listpool);
+ if (f->visit_index == visit) {
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "skipping f=%p, already visited\n", f);
+ }
+#endif
+ continue;
+ }
+ BLI_assert(f != cdt->outer_face);
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "top of loop, f=%p\n", f);
+ dump_se_cycle(f->symedge, "visit", 10000);
+ dump_cdt(cdt, "cdt at top of loop");
+ }
+#endif
+ f->visit_index = visit;
+ se_start = se = f->symedge;
+ do {
+ if (remove_until_constraints) {
+ dissolvable = !is_constrained_edge(se->edge);
+ }
+ else {
+ dissolvable = edge_touches_frame(se->edge);
+ }
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ dump_se(se, "edge in f");
+ fprintf(stderr, " dissolvable=%d\n", dissolvable);
+ }
+#endif
+ if (dissolvable) {
+ fsym = sym(se)->face;
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ dump_se_cycle(fsym->symedge, "fsym", 10000);
+ fprintf(stderr, " visited=%d\n", fsym->visit_index == visit);
+ }
+#endif
+ if (fsym->visit_index != visit) {
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "pushing face %p\n", fsym);
+ dump_se_cycle(fsym->symedge, "pushed", 10000);
+ }
+#endif
+ BLI_linklist_prepend_pool(&fstack, fsym, cdt->listpool);
+ }
+ else {
+ BLI_linklist_prepend_pool(&to_dissolve, se, cdt->listpool);
+ }
+ }
+ se = se->next;
+ } while (se != se_start);
+ while (to_dissolve != NULL) {
+ se = (SymEdge *)BLI_linklist_pop_pool(&to_dissolve, cdt->listpool);
+ if (se->next != NULL) {
+ dissolve_symedge(cdt, se);
+ }
+ }
+ }
+}
+
+/**
+ * Remove edges and merge faces to get desired output, as per options.
+ * \note the cdt cannot be further changed after this.
+ */
+static void prepare_cdt_for_output(CDT_state *cdt, const CDT_output_type output_type)
+{
+ CDTFace *f;
+ CDTEdge *e;
+ LinkNode *ln;
+
+ cdt->output_prepared = true;
+
+ /* Make sure all non-deleted faces have a symedge. */
+ for (ln = cdt->edges; ln; ln = ln->next) {
+ e = (CDTEdge *)ln->link;
+ if (e->symedges[0].face->symedge == NULL) {
+ e->symedges[0].face->symedge = &e->symedges[0];
+ }
+ if (e->symedges[1].face->symedge == NULL) {
+ e->symedges[1].face->symedge = &e->symedges[1];
+ }
+ }
+#ifdef DEBUG_CDT
+ /* All non-deleted faces should have a symedge now. */
+ for (ln = cdt->faces; ln; ln = ln->next) {
+ f = (CDTFace *)ln->link;
+ if (!f->deleted) {
+ BLI_assert(f->symedge != NULL);
+ }
+ }
+#else
+ UNUSED_VARS(f);
+#endif
+
+ if (output_type == CDT_CONSTRAINTS || output_type == CDT_CONSTRAINTS_VALID_BMESH) {
+ remove_non_constraint_edges(cdt, output_type == CDT_CONSTRAINTS_VALID_BMESH);
+ }
+ else if (output_type == CDT_FULL || output_type == CDT_INSIDE) {
+ remove_outer_edges(cdt, output_type == CDT_INSIDE);
+ }
+}
+
+#define NUM_BOUND_VERTS 4
+#define VERT_OUT_INDEX(v) ((v)->index - NUM_BOUND_VERTS)
+
+static CDT_result *cdt_get_output(CDT_state *cdt, const CDT_output_type output_type)
+{
+ int i, j, nv, ne, nf, faces_len_total;
+ int orig_map_size, orig_map_index;
+ CDT_result *result;
+ LinkNode *lne, *lnf, *ln;
+ SymEdge *se, *se_start;
+ CDTEdge *e;
+ CDTFace *f;
+
+ prepare_cdt_for_output(cdt, output_type);
+
+ result = (CDT_result *)MEM_callocN(sizeof(*result), __func__);
+
+ /* All verts except first NUM_BOUND_VERTS will be output. */
+ nv = cdt->vert_array_len - NUM_BOUND_VERTS;
+ if (nv <= 0) {
+ return result;
+ }
+
+ result->verts_len = nv;
+ result->vert_coords = MEM_malloc_arrayN(nv, sizeof(result->vert_coords[0]), __func__);
+
+ /* Make the vertex "orig" map arrays, mapping output verts to lists of input ones. */
+ orig_map_size = 0;
+ for (i = 0; i < nv; i++) {
+ orig_map_size += BLI_linklist_count(cdt->vert_array[i + 4]->input_ids);
+ }
+ result->verts_orig_len_table = MEM_malloc_arrayN(nv, sizeof(int), __func__);
+ result->verts_orig_start_table = MEM_malloc_arrayN(nv, sizeof(int), __func__);
+ result->verts_orig = MEM_malloc_arrayN(orig_map_size, sizeof(int), __func__);
+
+ orig_map_index = 0;
+ for (i = 0; i < nv; i++) {
+ j = i + NUM_BOUND_VERTS;
+ result->vert_coords[i][0] = (float)cdt->vert_array[j]->co[0];
+ result->vert_coords[i][1] = (float)cdt->vert_array[j]->co[1];
+ result->verts_orig_start_table[i] = orig_map_index;
+ for (ln = cdt->vert_array[j]->input_ids; ln; ln = ln->next) {
+ result->verts_orig[orig_map_index++] = POINTER_AS_INT(ln->link);
+ }
+ result->verts_orig_len_table[i] = orig_map_index - result->verts_orig_start_table[i];
+ }
+
+ ne = 0;
+ orig_map_size = 0;
+ for (ln = cdt->edges; ln; ln = ln->next) {
+ e = (CDTEdge *)ln->link;
+ if (!is_deleted_edge(e)) {
+ ne++;
+ if (e->input_ids) {
+ orig_map_size += BLI_linklist_count(e->input_ids);
+ }
+ }
+ }
+ if (ne != 0) {
+ result->edges_len = ne;
+ result->face_edge_offset = cdt->face_edge_offset;
+ result->edges = MEM_malloc_arrayN(ne, sizeof(result->edges[0]), __func__);
+ result->edges_orig_len_table = MEM_malloc_arrayN(ne, sizeof(int), __func__);
+ result->edges_orig_start_table = MEM_malloc_arrayN(ne, sizeof(int), __func__);
+ if (orig_map_size > 0) {
+ result->edges_orig = MEM_malloc_arrayN(orig_map_size, sizeof(int), __func__);
+ }
+ orig_map_index = 0;
+ i = 0;
+ for (lne = cdt->edges; lne; lne = lne->next) {
+ e = (CDTEdge *)lne->link;
+ if (!is_deleted_edge(e)) {
+ result->edges[i][0] = VERT_OUT_INDEX(e->symedges[0].vert);
+ result->edges[i][1] = VERT_OUT_INDEX(e->symedges[1].vert);
+ result->edges_orig_start_table[i] = orig_map_index;
+ for (ln = e->input_ids; ln; ln = ln->next) {
+ result->edges_orig[orig_map_index++] = POINTER_AS_INT(ln->link);
+ }
+ result->edges_orig_len_table[i] = orig_map_index - result->edges_orig_start_table[i];
+ i++;
+ }
+ }
+ }
+
+ nf = 0;
+ faces_len_total = 0;
+ orig_map_size = 0;
+ for (ln = cdt->faces; ln; ln = ln->next) {
+ f = (CDTFace *)ln->link;
+ if (!f->deleted && f != cdt->outer_face) {
+ nf++;
+ se = se_start = f->symedge;
+ BLI_assert(se != NULL);
+ do {
+ faces_len_total++;
+ se = se->next;
+ } while (se != se_start);
+ if (f->input_ids) {
+ orig_map_size += BLI_linklist_count(f->input_ids);
+ }
+ }
+ }
+
+ if (nf != 0) {
+ result->faces_len = nf;
+ result->faces_len_table = MEM_malloc_arrayN(nf, sizeof(int), __func__);
+ result->faces_start_table = MEM_malloc_arrayN(nf, sizeof(int), __func__);
+ result->faces = MEM_malloc_arrayN(faces_len_total, sizeof(int), __func__);
+ result->faces_orig_len_table = MEM_malloc_arrayN(nf, sizeof(int), __func__);
+ result->faces_orig_start_table = MEM_malloc_arrayN(nf, sizeof(int), __func__);
+ if (orig_map_size > 0) {
+ result->faces_orig = MEM_malloc_arrayN(orig_map_size, sizeof(int), __func__);
+ }
+ orig_map_index = 0;
+ i = 0;
+ j = 0;
+ for (lnf = cdt->faces; lnf; lnf = lnf->next) {
+ f = (CDTFace *)lnf->link;
+ if (!f->deleted && f != cdt->outer_face) {
+ result->faces_start_table[i] = j;
+ se = se_start = f->symedge;
+ do {
+ result->faces[j++] = VERT_OUT_INDEX(se->vert);
+ se = se->next;
+ } while (se != se_start);
+ result->faces_len_table[i] = j - result->faces_start_table[i];
+ result->faces_orig_start_table[i] = orig_map_index;
+ for (ln = f->input_ids; ln; ln = ln->next) {
+ result->faces_orig[orig_map_index++] = POINTER_AS_INT(ln->link);
+ }
+ result->faces_orig_len_table[i] = orig_map_index - result->faces_orig_start_table[i];
+ i++;
+ }
+ }
+ }
+ return result;
+}
+
+CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_type output_type)
+{
+ int nv = input->verts_len;
+ int ne = input->edges_len;
+ int nf = input->faces_len;
+ double epsilon = (double)input->epsilon;
+ int i, f, v1, v2;
+ int fedge_start, fedge_end;
+ double minx, maxx, miny, maxy;
+ float *xy;
+ double vert_co[2];
+ CDT_state *cdt;
+ CDT_result *result;
+ CDTVert **verts;
+ LinkNode *edge_list;
+ CDTEdge *face_edge;
+ SymEdge *face_symedge;
+#ifdef DEBUG_CDT
+ int dbg_level = 1;
+#endif
+
+ if ((nv > 0 && input->vert_coords == NULL) || (ne > 0 && input->edges == NULL) ||
+ (nf > 0 && (input->faces == NULL || input->faces_start_table == NULL ||
+ input->faces_len_table == NULL))) {
+#ifdef DEBUG_CDT
+ fprintf(stderr, "invalid input: unexpected NULL array(s)\n");
+#endif
+ return NULL;
+ }
+
+ if (nv > 0) {
+ minx = miny = DBL_MAX;
+ maxx = maxy = -DBL_MAX;
+ for (i = 0; i < nv; i++) {
+ xy = input->vert_coords[i];
+ if (xy[0] < minx) {
+ minx = xy[0];
+ }
+ if (xy[0] > maxx) {
+ maxx = xy[0];
+ }
+ if (xy[1] < miny) {
+ miny = xy[1];
+ }
+ if (xy[1] > maxy) {
+ maxy = xy[1];
+ }
+ }
+ verts = (CDTVert **)MEM_mallocN(nv * sizeof(CDTVert *), "constrained delaunay");
+ }
+ else {
+ minx = miny = maxx = maxy = 0;
+ verts = NULL;
+ }
+
+ if (epsilon == 0.0) {
+ epsilon = 1e-8;
+ }
+ cdt = cdt_init(minx, maxx, miny, maxy, epsilon);
+ /* TODO: use a random permutation for order of adding the vertices. */
+ for (i = 0; i < nv; i++) {
+ vert_co[0] = (double)input->vert_coords[i][0];
+ vert_co[1] = (double)input->vert_coords[i][1];
+ verts[i] = add_point_constraint(cdt, vert_co, i);
+ }
+ for (i = 0; i < ne; i++) {
+ v1 = input->edges[i][0];
+ v2 = input->edges[i][1];
+ if (v1 < 0 || v1 >= nv || v2 < 0 || v2 >= nv) {
+#ifdef DEBUG_CDT
+ fprintf(stderr, "edge indices not valid: v1=%d, v2=%d, nv=%d\n", v1, v2, nv);
+#endif
+ continue;
+ }
+ add_edge_constraint(cdt, verts[v1], verts[v2], i, NULL);
+ }
+ cdt->face_edge_offset = ne;
+ for (f = 0; f < nf; f++) {
+ int flen = input->faces_len_table[f];
+ int fstart = input->faces_start_table[f];
+ if (flen <= 2) {
+#ifdef DEBUG_CDT
+ fprintf(stderr, "face %d has length %d; ignored\n", f, flen);
+#endif
+ continue;
+ }
+ for (i = 0; i < flen; i++) {
+ int face_edge_id = cdt->face_edge_offset + fstart + i;
+ v1 = input->faces[fstart + i];
+ v2 = input->faces[fstart + ((i + 1) % flen)];
+ if (v1 < 0 || v1 >= nv || v2 < 0 || v2 >= nv) {
+#ifdef DEBUG_CDT
+ fprintf(stderr, "face indices not valid: f=%d, v1=%d, v2=%d, nv=%d\n", f, v1, v2, nv);
+#endif
+ continue;
+ }
+ add_edge_constraint(cdt, verts[v1], verts[v2], face_edge_id, &edge_list);
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(stderr, "edges for edge %d:\n", i);
+ for (LinkNode *ln = edge_list; ln; ln = ln->next) {
+ CDTEdge *cdt_e = (CDTEdge *)ln->link;
+ fprintf(stderr,
+ " (%.2f,%.2f)->(%.2f,%.2f)\n",
+ F2(cdt_e->symedges[0].vert->co),
+ F2(cdt_e->symedges[1].vert->co));
+ }
+ }
+#endif
+ if (i == 0) {
+ face_edge = (CDTEdge *)edge_list->link;
+ face_symedge = &face_edge->symedges[0];
+ if (face_symedge->vert != verts[v1]) {
+ face_symedge = &face_edge->symedges[1];
+ BLI_assert(face_symedge->vert == verts[v1]);
+ }
+ }
+ BLI_linklist_free_pool(edge_list, NULL, cdt->listpool);
+ }
+ fedge_start = cdt->face_edge_offset + fstart;
+ fedge_end = fedge_start + flen - 1;
+ add_face_ids(cdt, face_symedge, f, fedge_start, fedge_end);
+ }
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ validate_cdt(cdt, true);
+ }
+ if (dbg_level > 1) {
+ cdt_draw(cdt, "before cdt_get_output");
+ }
+#endif
+ result = cdt_get_output(cdt, output_type);
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ cdt_draw(cdt, "final");
+ }
+#endif
+ if (verts) {
+ MEM_freeN(verts);
+ }
+ cdt_free(cdt);
+ return result;
+}
+
+void BLI_delaunay_2d_cdt_free(CDT_result *result)
+{
+ if (result == NULL) {
+ return;
+ }
+ if (result->vert_coords) {
+ MEM_freeN(result->vert_coords);
+ }
+ if (result->edges) {
+ MEM_freeN(result->edges);
+ }
+ if (result->faces) {
+ MEM_freeN(result->faces);
+ }
+ if (result->faces_start_table) {
+ MEM_freeN(result->faces_start_table);
+ }
+ if (result->faces_len_table) {
+ MEM_freeN(result->faces_len_table);
+ }
+ if (result->verts_orig) {
+ MEM_freeN(result->verts_orig);
+ }
+ if (result->verts_orig_start_table) {
+ MEM_freeN(result->verts_orig_start_table);
+ }
+ if (result->verts_orig_len_table) {
+ MEM_freeN(result->verts_orig_len_table);
+ }
+ if (result->edges_orig) {
+ MEM_freeN(result->edges_orig);
+ }
+ if (result->edges_orig_start_table) {
+ MEM_freeN(result->edges_orig_start_table);
+ }
+ if (result->edges_orig_len_table) {
+ MEM_freeN(result->edges_orig_len_table);
+ }
+ if (result->faces_orig) {
+ MEM_freeN(result->faces_orig);
+ }
+ if (result->faces_orig_start_table) {
+ MEM_freeN(result->faces_orig_start_table);
+ }
+ if (result->faces_orig_len_table) {
+ MEM_freeN(result->faces_orig_len_table);
+ }
+ MEM_freeN(result);
+}
+
+#ifdef DEBUG_CDT
+
+static void dump_se(const SymEdge *se, const char *lab)
+{
+ if (se->next) {
+ fprintf(
+ stderr, "%s((%.2f,%.2f)->(%.2f,%.2f))\n", lab, F2(se->vert->co), F2(se->next->vert->co));
+ }
+ else {
+ fprintf(stderr, "%s((%.2f,%.2f)->NULL)\n", lab, F2(se->vert->co));
+ }
+}
+
+static void dump_v(const CDTVert *v, const char *lab)
+{
+ fprintf(stderr, "%s(%.2f,%.2f)\n", lab, F2(v->co));
+}
+
+static void dump_se_cycle(const SymEdge *se, const char *lab, const int limit)
+{
+ int count = 0;
+ const SymEdge *s = se;
+ fprintf(stderr, "%s:\n", lab);
+ do {
+ dump_se(s, " ");
+ s = s->next;
+ count++;
+ } while (s != se && count < limit);
+ if (count == limit) {
+ fprintf(stderr, " limit hit without cycle!\n");
+ }
+}
+
+static void dump_id_list(const LinkNode *id_list, const char *lab)
+{
+ const LinkNode *ln;
+ if (!id_list) {
+ return;
+ }
+ fprintf(stderr, "%s", lab);
+ for (ln = id_list; ln; ln = ln->next) {
+ fprintf(stderr, "%d%c", POINTER_AS_INT(ln->link), ln->next ? ' ' : '\n');
+ }
+}
+
+# define PL(p) (POINTER_AS_UINT(p) & 0xFFFF)
+static void dump_cdt(const CDT_state *cdt, const char *lab)
+{
+ LinkNode *ln;
+ CDTVert *v;
+ CDTEdge *e;
+ CDTFace *f;
+ SymEdge *se;
+ int i;
+
+ fprintf(stderr, "\nCDT %s\n", lab);
+ fprintf(stderr, "\nVERTS\n");
+ for (i = 0; i < cdt->vert_array_len; i++) {
+ v = cdt->vert_array[i];
+ fprintf(stderr, "%x: (%f,%f) symedge=%x\n", PL(v), F2(v->co), PL(v->symedge));
+ dump_id_list(v->input_ids, " ");
+ }
+ fprintf(stderr, "\nEDGES\n");
+ for (ln = cdt->edges; ln; ln = ln->next) {
+ e = (CDTEdge *)ln->link;
+ if (e->symedges[0].next == NULL) {
+ continue;
+ }
+ fprintf(stderr, "%x:\n", PL(e));
+ for (i = 0; i < 2; i++) {
+ se = &e->symedges[i];
+ fprintf(stderr,
+ " se[%d] @%x: next=%x, rot=%x, vert=%x (%.2f,%.2f), edge=%x, face=%x\n",
+ i,
+ PL(se),
+ PL(se->next),
+ PL(se->rot),
+ PL(se->vert),
+ F2(se->vert->co),
+ PL(se->edge),
+ PL(se->face));
+ }
+ dump_id_list(e->input_ids, " ");
+ }
+ fprintf(stderr, "\nFACES\n");
+ for (ln = cdt->faces; ln; ln = ln->next) {
+ f = (CDTFace *)ln->link;
+ if (f->deleted) {
+ continue;
+ }
+ if (f == cdt->outer_face) {
+ fprintf(stderr, "outer");
+ }
+ else {
+ fprintf(stderr, "%x: centroid (%f,%f)", PL(f), F2(f->centroid));
+ }
+ fprintf(stderr, " symedge=%x\n", PL(f->symedge));
+ dump_id_list(f->input_ids, " ");
+ }
+ fprintf(stderr, "\nOTHER\n");
+ fprintf(
+ stderr, "minx=%f, maxx=%f, miny=%f, maxy=%f\n", cdt->minx, cdt->maxx, cdt->miny, cdt->maxy);
+ fprintf(stderr, "margin=%f\n", cdt->margin);
+}
+# undef PL
+
+/**
+ * Make an html file with svg in it to display the argument cdt.
+ * Mouse-overs will reveal the coordinates of vertices and edges.
+ * Constraint edges are drawn thicker than non-constraint edges.
+ * The first call creates DRAWFILE; subsequent calls append to it.
+ */
+# define DRAWFILE "/tmp/debug_draw.html"
+# define MAX_DRAW_WIDTH 1000
+# define MAX_DRAW_HEIGHT 700
+static void cdt_draw(CDT_state *cdt, const char *lab)
+{
+ static bool append = false;
+ FILE *f = fopen(DRAWFILE, append ? "a" : "w");
+ double draw_margin = (cdt->maxx - cdt->minx + cdt->maxy - cdt->miny + 1) * 0.05;
+ double minx = cdt->minx - draw_margin;
+ double maxx = cdt->maxx + draw_margin;
+ double miny = cdt->miny - draw_margin;
+ double maxy = cdt->maxy + draw_margin;
+ double width = maxx - minx;
+ double height = maxy - miny;
+ double aspect = height / width;
+ int view_width, view_height;
+ double scale;
+ LinkNode *ln;
+ CDTVert *v, *u;
+ CDTEdge *e;
+ int i, strokew;
+
+ view_width = MAX_DRAW_WIDTH;
+ view_height = (int)(view_width * aspect);
+ if (view_height > MAX_DRAW_HEIGHT) {
+ view_height = MAX_DRAW_HEIGHT;
+ view_width = (int)(view_height / aspect);
+ }
+ scale = view_width / width;
+
+# define SX(x) ((x - minx) * scale)
+# define SY(y) ((maxy - y) * scale)
+
+ if (!f) {
+ printf("couldn't open file %s\n", DRAWFILE);
+ return;
+ }
+ fprintf(f, "<div>%s</div>\n<div>\n", lab);
+ fprintf(f,
+ "<svg version=\"1.1\" "
+ "xmlns=\"http://www.w3.org/2000/svg\" "
+ "xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
+ "xml:space=\"preserve\"\n");
+ fprintf(f, "width=\"%d\" height=\"%d\">/n", view_width, view_height);
+
+ for (ln = cdt->edges; ln; ln = ln->next) {
+ e = (CDTEdge *)ln->link;
+ if (is_deleted_edge(e)) {
+ continue;
+ }
+ u = e->symedges[0].vert;
+ v = e->symedges[1].vert;
+ strokew = is_constrained_edge(e) ? 5 : 2;
+ fprintf(f,
+ "<line fill=\"none\" stroke=\"black\" stroke-width=\"%d\" "
+ "x1=\"%.1f\" y1=\"%.1f\" x2=\"%.1f\" y2=\"%.1f\">\n",
+ strokew,
+ SX(u->co[0]),
+ SY(u->co[1]),
+ SX(v->co[0]),
+ SY(v->co[1]));
+ fprintf(
+ f, " <title>(%.3f,%.3f)(%.3f,%.3f)</title>\n", u->co[0], u->co[1], v->co[0], v->co[1]);
+ fprintf(f, "</line>\n");
+ }
+ i = cdt->output_prepared ? NUM_BOUND_VERTS : 0;
+ for (; i < cdt->vert_array_len; i++) {
+ v = cdt->vert_array[i];
+ fprintf(f,
+ "<circle fill=\"black\" cx=\"%.1f\" cy=\"%.1f\" r=\"5\">\n",
+ SX(v->co[0]),
+ SY(v->co[1]));
+ fprintf(f, " <title>(%.3f,%.3f)</title>\n", v->co[0], v->co[1]);
+ fprintf(f, "</circle>\n");
+ }
+
+ fprintf(f, "</svg>\n</div>\n");
+ fclose(f);
+ append = true;
+# undef SX
+# undef SY
+}
+
+# ifndef NDEBUG /* Only used in assert. */
+/**
+ * Is a visible from b: i.e., ab crosses no edge of cdt?
+ * If constrained is true, consider only constrained edges as possible crossers.
+ * In any case, don't count an edge ab itself.
+ */
+static bool is_visible(const CDTVert *a, const CDTVert *b, bool constrained, const CDT_state *cdt)
+{
+ const LinkNode *ln;
+ const CDTEdge *e;
+ const SymEdge *se, *senext;
+ int ikind;
+
+ for (ln = cdt->edges; ln; ln = ln->next) {
+ e = (const CDTEdge *)ln->link;
+ if (is_deleted_edge(e) || is_border_edge(e, cdt)) {
+ continue;
+ }
+ if (constrained && !is_constrained_edge(e)) {
+ continue;
+ }
+ se = (const SymEdge *)&e->symedges[0];
+ senext = se->next;
+ if ((a == se->vert || a == senext->vert) || b == se->vert || b == se->next->vert) {
+ continue;
+ }
+ ikind = isect_seg_seg_v2_lambda_mu_db(
+ a->co, b->co, se->vert->co, senext->vert->co, NULL, NULL);
+ if (ikind != ISECT_LINE_LINE_NONE) {
+ if (ikind == ISECT_LINE_LINE_COLINEAR) {
+ /* TODO: special test here for overlap. */
+ continue;
+ }
+ return false;
+ }
+ }
+ return true;
+}
+# endif
+
+# ifndef NDEBUG /* Only used in assert. */
+/**
+ * Check that edge ab satisfies constrained delaunay condition:
+ * That is, for all non-constraint, non-border edges ab,
+ * (1) ab is visible in the constraint graph; and
+ * (2) there is a circle through a and b such that any vertex v connected by an edge to a or b
+ * is not inside that circle.
+ * The argument 'se' specifies ab by: a is se's vert and b is se->next's vert.
+ * Return true if check is OK.
+ */
+static bool is_delaunay_edge(const SymEdge *se, const double epsilon)
+{
+ int i;
+ CDTVert *a, *b, *c;
+ const SymEdge *sesym, *curse, *ss;
+ bool ok[2];
+
+ if (!is_constrained_edge(se->edge)) {
+ return true;
+ }
+ sesym = sym(se);
+ a = se->vert;
+ b = se->next->vert;
+ /* Try both the triangles adjacent to se's edge for circle. */
+ for (i = 0; i < 2; i++) {
+ ok[i] = true;
+ curse = (i == 0) ? se : sesym;
+ a = curse->vert;
+ b = curse->next->vert;
+ c = curse->next->next->vert;
+ for (ss = curse->rot; ss != curse; ss = ss->rot) {
+ ok[i] |= delaunay_check(a, b, c, ss->next->vert, epsilon);
+ }
+ }
+ return ok[0] || ok[1];
+}
+# endif
+
+# ifndef NDEBUG
+static bool plausible_non_null_ptr(void *p)
+{
+ return p > (void *)0x1000;
+}
+# endif
+
+static void validate_face_centroid(SymEdge *se)
+{
+ SymEdge *senext;
+# ifndef NDEBUG
+ double *centroidp = se->face->centroid;
+# endif
+ double c[2];
+ int count;
+ copy_v2_v2_db(c, se->vert->co);
+ BLI_assert(reachable(se->next, se, 100));
+ count = 1;
+ for (senext = se->next; senext != se; senext = senext->next) {
+ add_v2_v2_db(c, senext->vert->co);
+ count++;
+ }
+ c[0] /= count;
+ c[1] /= count;
+ BLI_assert(fabs(c[0] - centroidp[0]) < 1e-8 && fabs(c[1] - centroidp[1]) < 1e-8);
+}
+
+static void validate_cdt(CDT_state *cdt, bool check_all_tris)
+{
+ LinkNode *ln, *lne;
+ int totedges, totfaces, totverts, totborderedges;
+ CDTEdge *e;
+ SymEdge *se, *sesym, *s;
+ CDTVert *v;
+ CDTFace *f;
+ double *p;
+ double margin;
+ int i, limit;
+ bool isborder;
+
+ if (cdt->output_prepared) {
+ return;
+ }
+
+ BLI_assert(cdt != NULL);
+ BLI_assert(cdt->maxx >= cdt->minx);
+ BLI_assert(cdt->maxy >= cdt->miny);
+ totedges = 0;
+ totborderedges = 0;
+ for (ln = cdt->edges; ln; ln = ln->next) {
+ e = (CDTEdge *)ln->link;
+ se = &e->symedges[0];
+ sesym = &e->symedges[1];
+ if (is_deleted_edge(e)) {
+ BLI_assert(se->rot == NULL && sesym->next == NULL && sesym->rot == NULL);
+ continue;
+ }
+ totedges++;
+ isborder = is_border_edge(e, cdt);
+ if (isborder) {
+ totborderedges++;
+ BLI_assert((se->face == cdt->outer_face && sesym->face != cdt->outer_face) ||
+ (se->face != cdt->outer_face && sesym->face == cdt->outer_face));
+ }
+ /* BLI_assert(se->face != sesym->face);
+ * Not required because faces can have intruding wire edges. */
+ BLI_assert(se->vert != sesym->vert);
+ BLI_assert(se->edge == sesym->edge && se->edge == e);
+ BLI_assert(sym(se) == sesym && sym(sesym) == se);
+ for (i = 0; i < 2; i++) {
+ se = &e->symedges[i];
+ v = se->vert;
+ f = se->face;
+ p = v->co;
+ UNUSED_VARS_NDEBUG(p);
+ BLI_assert(plausible_non_null_ptr(v));
+ if (f != NULL) {
+ BLI_assert(plausible_non_null_ptr(f));
+ }
+ BLI_assert(plausible_non_null_ptr(se->next));
+ BLI_assert(plausible_non_null_ptr(se->rot));
+ if (check_all_tris && se->face != cdt->outer_face) {
+ limit = 3;
+ }
+ else {
+ limit = 10000;
+ }
+ BLI_assert(reachable(se->next, se, limit));
+ UNUSED_VARS_NDEBUG(limit);
+ BLI_assert(se->next->next != se);
+ s = se;
+ do {
+ BLI_assert(prev(s)->next == s);
+ BLI_assert(s->rot == sym(prev(s)));
+ s = s->next;
+ } while (s != se);
+ }
+ BLI_assert(isborder || is_visible(se->vert, se->next->vert, false, cdt));
+ BLI_assert(isborder || is_delaunay_edge(se, cdt->epsilon));
+ }
+ totverts = 0;
+ margin = cdt->margin;
+ for (i = 0; i < cdt->vert_array_len; i++) {
+ totverts++;
+ v = cdt->vert_array[i];
+ BLI_assert(plausible_non_null_ptr(v));
+ p = v->co;
+ BLI_assert(p[0] >= cdt->minx - margin && p[0] <= cdt->maxx + margin);
+ UNUSED_VARS_NDEBUG(margin);
+ BLI_assert(v->symedge->vert == v);
+ }
+ totfaces = 0;
+ for (ln = cdt->faces; ln; ln = ln->next) {
+ f = (CDTFace *)ln->link;
+ BLI_assert(plausible_non_null_ptr(f));
+ if (f->deleted) {
+ continue;
+ }
+ totfaces++;
+ if (f == cdt->outer_face) {
+ continue;
+ }
+ for (lne = cdt->edges; lne; lne = lne->next) {
+ e = (CDTEdge *)lne->link;
+ if (!is_deleted_edge(e)) {
+ for (i = 0; i < 2; i++) {
+ if (e->symedges[i].face == f) {
+ validate_face_centroid(&e->symedges[i]);
+ }
+ }
+ }
+ }
+ p = f->centroid;
+ BLI_assert(p[0] >= cdt->minx - margin && p[0] <= cdt->maxx + margin);
+ BLI_assert(p[1] >= cdt->miny - margin && p[1] <= cdt->maxy + margin);
+ }
+ /* Euler's formula for planar graphs. */
+ if (check_all_tris) {
+ BLI_assert(totverts - totedges + totfaces == 2);
+ }
+}
+#endif
diff --git a/source/blender/blenlib/intern/freetypefont.c b/source/blender/blenlib/intern/freetypefont.c
index 7be7674069c..b5a950d6851 100644
--- a/source/blender/blenlib/intern/freetypefont.c
+++ b/source/blender/blenlib/intern/freetypefont.c
@@ -565,7 +565,7 @@ VChar *BLI_vfontchar_copy(const VChar *vchar_src, const int UNUSED(flag))
* between them
* </pre>
*
- * Each glyph's original outline points are located on a grid of indivisible units.
+ * Each glyphs original outline points are located on a grid of indivisible units.
* The points are stored in the font file as 16-bit integer grid coordinates,
* with the grid origin's being at (0, 0); they thus range from -16384 to 16383.
*
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index b4a96ff316a..c4bdc73e0e3 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -2346,6 +2346,213 @@ bool isect_tri_tri_epsilon_v3(const float t_a0[3],
return false;
}
+/* -------------------------------------------------------------------- */
+/** \name Tri-Tri Intersect 2D
+ *
+ * "Fast and Robust Triangle-Triangle Overlap Test
+ * Using Orientation Predicates" P. Guigue - O. Devillers
+ * Journal of Graphics Tools, 8(1), 2003.
+ *
+ * \{ */
+
+static bool isect_tri_tri_v2_impl_vert(const float t_a0[2],
+ const float t_a1[2],
+ const float t_a2[2],
+ const float t_b0[2],
+ const float t_b1[2],
+ const float t_b2[2])
+{
+ if (line_point_side_v2(t_b2, t_b0, t_a1) >= 0.0f) {
+ if (line_point_side_v2(t_b2, t_b1, t_a1) <= 0.0f) {
+ if (line_point_side_v2(t_a0, t_b0, t_a1) > 0.0f) {
+ if (line_point_side_v2(t_a0, t_b1, t_a1) <= 0.0f) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ }
+ else {
+ if (line_point_side_v2(t_a0, t_b0, t_a2) >= 0.0f) {
+ if (line_point_side_v2(t_a1, t_a2, t_b0) >= 0.0f) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ }
+ else {
+ return 0;
+ }
+ }
+ }
+ else if (line_point_side_v2(t_a0, t_b1, t_a1) <= 0.0f) {
+ if (line_point_side_v2(t_b2, t_b1, t_a2) <= 0.0f) {
+ if (line_point_side_v2(t_a1, t_a2, t_b1) >= 0.0f) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ }
+ else {
+ return 0;
+ }
+ }
+ else {
+ return 0;
+ }
+ }
+ else if (line_point_side_v2(t_b2, t_b0, t_a2) >= 0.0f) {
+ if (line_point_side_v2(t_a1, t_a2, t_b2) >= 0.0f) {
+ if (line_point_side_v2(t_a0, t_b0, t_a2) >= 0.0f) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ }
+ else if (line_point_side_v2(t_a1, t_a2, t_b1) >= 0.0f) {
+ if (line_point_side_v2(t_b2, t_a2, t_b1) >= 0.0f) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ }
+ else {
+ return 0;
+ }
+ }
+ else {
+ return 0;
+ }
+}
+
+static bool isect_tri_tri_v2_impl_edge(const float t_a0[2],
+ const float t_a1[2],
+ const float t_a2[2],
+ const float t_b0[2],
+ const float t_b1[2],
+ const float t_b2[2])
+{
+ UNUSED_VARS(t_b1);
+
+ if (line_point_side_v2(t_b2, t_b0, t_a1) >= 0.0f) {
+ if (line_point_side_v2(t_a0, t_b0, t_a1) >= 0.0f) {
+ if (line_point_side_v2(t_a0, t_a1, t_b2) >= 0.0f) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ }
+ else {
+ if (line_point_side_v2(t_a1, t_a2, t_b0) >= 0.0f) {
+ if (line_point_side_v2(t_a2, t_a0, t_b0) >= 0.0f) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ }
+ else {
+ return 0;
+ }
+ }
+ }
+ else {
+ if (line_point_side_v2(t_b2, t_b0, t_a2) >= 0.0f) {
+ if (line_point_side_v2(t_a0, t_b0, t_a2) >= 0.0f) {
+ if (line_point_side_v2(t_a0, t_a2, t_b2) >= 0.0f) {
+ return 1;
+ }
+ else {
+ if (line_point_side_v2(t_a1, t_a2, t_b2) >= 0.0f) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ }
+ }
+ else {
+ return 0;
+ }
+ }
+ else {
+ return 0;
+ }
+ }
+}
+
+static int isect_tri_tri_impl_ccw_v2(const float t_a0[2],
+ const float t_a1[2],
+ const float t_a2[2],
+ const float t_b0[2],
+ const float t_b1[2],
+ const float t_b2[2])
+{
+ if (line_point_side_v2(t_b0, t_b1, t_a0) >= 0.0f) {
+ if (line_point_side_v2(t_b1, t_b2, t_a0) >= 0.0f) {
+ if (line_point_side_v2(t_b2, t_b0, t_a0) >= 0.0f) {
+ return 1;
+ }
+ else {
+ return isect_tri_tri_v2_impl_edge(t_a0, t_a1, t_a2, t_b0, t_b1, t_b2);
+ }
+ }
+ else {
+ if (line_point_side_v2(t_b2, t_b0, t_a0) >= 0.0f) {
+ return isect_tri_tri_v2_impl_edge(t_a0, t_a1, t_a2, t_b2, t_b0, t_b1);
+ }
+ else {
+ return isect_tri_tri_v2_impl_vert(t_a0, t_a1, t_a2, t_b0, t_b1, t_b2);
+ }
+ }
+ }
+ else {
+ if (line_point_side_v2(t_b1, t_b2, t_a0) >= 0.0f) {
+ if (line_point_side_v2(t_b2, t_b0, t_a0) >= 0.0f) {
+ return isect_tri_tri_v2_impl_edge(t_a0, t_a1, t_a2, t_b1, t_b2, t_b0);
+ }
+ else {
+ return isect_tri_tri_v2_impl_vert(t_a0, t_a1, t_a2, t_b1, t_b2, t_b0);
+ }
+ }
+ else {
+ return isect_tri_tri_v2_impl_vert(t_a0, t_a1, t_a2, t_b2, t_b0, t_b1);
+ }
+ }
+}
+
+bool isect_tri_tri_v2(const float t_a0[2],
+ const float t_a1[2],
+ const float t_a2[2],
+ const float t_b0[2],
+ const float t_b1[2],
+ const float t_b2[2])
+{
+ if (line_point_side_v2(t_a0, t_a1, t_a2) < 0.0f) {
+ if (line_point_side_v2(t_b0, t_b1, t_b2) < 0.0f) {
+ return isect_tri_tri_impl_ccw_v2(t_a0, t_a2, t_a1, t_b0, t_b2, t_b1);
+ }
+ else {
+ return isect_tri_tri_impl_ccw_v2(t_a0, t_a2, t_a1, t_b0, t_b1, t_b2);
+ }
+ }
+ else {
+ if (line_point_side_v2(t_b0, t_b1, t_b2) < 0.0f) {
+ return isect_tri_tri_impl_ccw_v2(t_a0, t_a1, t_a2, t_b0, t_b2, t_b1);
+ }
+ else {
+ return isect_tri_tri_impl_ccw_v2(t_a0, t_a1, t_a2, t_b0, t_b1, t_b2);
+ }
+ }
+}
+
+/** \} */
+
/* Adapted from the paper by Kasper Fauerby */
/* "Improved Collision detection and Response" */
@@ -3245,7 +3452,7 @@ bool clip_segment_v3_plane(
}
}
- /* incase input/output values match (above also) */
+ /* In case input/output values match (above also). */
const float p1_copy[3] = {UNPACK3(p1)};
copy_v3_v3(r_p2, p2);
copy_v3_v3(r_p1, p1_copy);
@@ -3304,7 +3511,7 @@ bool clip_segment_v3_plane_n(const float p1[3],
}
}
- /* incase input/output values match */
+ /* In case input/output values match. */
const float p1_copy[3] = {UNPACK3(p1)};
madd_v3_v3v3fl(r_p1, p1_copy, dp, p1_fac);
@@ -5523,6 +5730,27 @@ float form_factor_hemi_poly(
}
/**
+ * Check if the edge is convex or concave
+ * (depends on face winding)
+ * Copied from BM_edge_is_convex().
+ */
+bool is_edge_convex_v3(const float v1[3],
+ const float v2[3],
+ const float f1_no[3],
+ const float f2_no[3])
+{
+ if (!equals_v3v3(f1_no, f2_no)) {
+ float cross[3];
+ float l_dir[3];
+ cross_v3_v3v3(cross, f1_no, f2_no);
+ /* we assume contiguous normals, otherwise the result isn't meaningful */
+ sub_v3_v3v3(l_dir, v2, v1);
+ return (dot_v3v3(l_dir, cross) > 0.0f);
+ }
+ return false;
+}
+
+/**
* Evaluate if entire quad is a proper convex quad
*/
bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
diff --git a/source/blender/blenlib/intern/math_statistics.c b/source/blender/blenlib/intern/math_statistics.c
index d4fcb32ce37..18affbed708 100644
--- a/source/blender/blenlib/intern/math_statistics.c
+++ b/source/blender/blenlib/intern/math_statistics.c
@@ -96,7 +96,7 @@ static void covariance_m_vn_ex_task_cb(void *__restrict userdata,
* \param center: the center (or mean point) of cos_vn. If NULL,
* it is assumed cos_vn is already centered.
* \param use_sample_correction: whether to apply sample correction
- * (i.e. get 'sample varince' instead of 'population variance').
+ * (i.e. get 'sample variance' instead of 'population variance').
* \return r_covmat the computed covariance matrix.
*/
void BLI_covariance_m_vn_ex(const int n,
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 111b530a527..18acbca00a1 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -1685,6 +1685,24 @@ void BLI_split_file_part(const char *string, char *file, const size_t filelen)
}
/**
+ * Returns a pointer to the last extension (e.g. the position of the last period).
+ * Returns NULL if there is no extension.
+ */
+const char *BLI_path_extension(const char *filepath)
+{
+ const char *extension = strrchr(filepath, '.');
+ if (extension == NULL) {
+ return NULL;
+ }
+ if (BLI_first_slash(extension) != NULL) {
+ /* There is a path separator in the extension, so the '.' was found in a
+ * directory component and not in the filename. */
+ return NULL;
+ }
+ return extension;
+}
+
+/**
* Append a filename to a dir, ensuring slash separates.
*/
void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file)
diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c
index f2b3ef2ad87..b956e1c0a7e 100644
--- a/source/blender/blenlib/intern/string_utils.c
+++ b/source/blender/blenlib/intern/string_utils.c
@@ -82,6 +82,21 @@ size_t BLI_split_name_num(char *left, int *nr, const char *name, const char deli
return name_len;
}
+bool BLI_string_is_decimal(const char *string)
+{
+ if (*string == '\0') {
+ return false;
+ }
+
+ /* Keep iterating over the string until a non-digit is found. */
+ while (isdigit(*string)) {
+ string++;
+ }
+
+ /* If the non-digit we found is the terminating \0, everything was digits. */
+ return *string == '\0';
+}
+
static bool is_char_sep(const char c)
{
return ELEM(c, '.', ' ', '-', '_');
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index bea38a232cc..034a6d4017e 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -149,7 +149,7 @@ typedef struct TaskThreadLocalStorage {
* without "interrupting" for task execution.
*
* We try to accumulate as much tasks as possible in a local queue without
- * any locks first, and then we push all of them into a scheduler's queue
+ * any locks first, and then we push all of them into a schedulers queue
* from within a single mutex lock.
*/
bool do_delayed_push;
diff --git a/source/blender/blenloader/BLO_blend_defs.h b/source/blender/blenloader/BLO_blend_defs.h
index 0787d054141..fec61605dca 100644
--- a/source/blender/blenloader/BLO_blend_defs.h
+++ b/source/blender/blenloader/BLO_blend_defs.h
@@ -18,7 +18,7 @@
/** \file
* \ingroup blenloader
- * \brief defines for blendfile codes
+ * \brief defines for blend-file codes.
*/
/* INTEGER CODES */
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 737a70615ae..1e3342cef04 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -222,7 +222,7 @@
* which keeps large arrays in memory from data-blocks we may not even use.
*
* \note This is disabled when using compression,
- * while zlib supports seek ist's unusably slow, see: T61880.
+ * while zlib supports seek it's unusably slow, see: T61880.
*/
#define USE_BHEAD_READ_ON_DEMAND
@@ -271,13 +271,13 @@ typedef struct BHeadN {
* because ID names are used in lookup tables. */
#define BHEAD_USE_READ_ON_DEMAND(bhead) ((bhead)->code == DATA)
-/* this function ensures that reports are printed,
- * in the case of libraray linking errors this is important!
+/**
+ * This function ensures that reports are printed,
+ * in the case of library linking errors this is important!
*
* bit kludge but better then doubling up on prints,
* we could alternatively have a versions of a report function which forces printing - campbell
*/
-
void blo_reportf_wrap(ReportList *reports, ReportType type, const char *format, ...)
{
char fixed_buf[1024]; /* should be long enough */
@@ -533,7 +533,7 @@ static void split_libdata(ListBase *lb_src, Main **lib_main_array, const uint li
if (id->lib) {
if (((uint)id->lib->temp_index < lib_main_array_len) &&
- /* this check should never fail, just incase 'id->lib' is a dangling pointer. */
+ /* this check should never fail, just in case 'id->lib' is a dangling pointer. */
(lib_main_array[id->lib->temp_index]->curlib == id->lib)) {
Main *mainvar = lib_main_array[id->lib->temp_index];
ListBase *lb_dst = which_libbase(mainvar, GS(id->name));
@@ -679,8 +679,10 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab
/* Add library data-block itself to 'main' Main, since libraries are **never** linked data.
* Fixes bug where you could end with all ID_LI data-blocks having the same name... */
lib = BKE_libblock_alloc(mainlist->first, ID_LI, BLI_path_basename(filepath), 0);
- lib->id.us = ID_FAKE_USERS(
- lib); /* Important, consistency with main ID reading code from read_libblock(). */
+
+ /* Important, consistency with main ID reading code from read_libblock(). */
+ lib->id.us = ID_FAKE_USERS(lib);
+
BLI_strncpy(lib->name, filepath, sizeof(lib->name));
BLI_strncpy(lib->filepath, name1, sizeof(lib->filepath));
@@ -2496,16 +2498,13 @@ static void IDP_DirectLinkProperty(IDProperty *prop, int switch_endian, FileData
IDP_DirectLinkIDPArray(prop, switch_endian, fd);
break;
case IDP_DOUBLE:
- /* erg, stupid doubles. since I'm storing them
- * in the same field as int val; val2 in the
- * IDPropertyData struct, they have to deal with
- * endianness specifically
+ /* Workaround for doubles.
+ * They are stored in the same field as `int val, val2` in the IDPropertyData struct,
+ * they have to deal with endianness specifically.
*
- * in theory, val and val2 would've already been swapped
+ * In theory, val and val2 would've already been swapped
* if switch_endian is true, so we have to first unswap
- * them then reswap them as a single 64-bit entity.
- */
-
+ * them then re-swap them as a single 64-bit entity. */
if (switch_endian) {
BLI_endian_switch_int32(&prop->data.val);
BLI_endian_switch_int32(&prop->data.val2);
@@ -3367,8 +3366,10 @@ static void direct_link_workspace(FileData *fd, WorkSpace *workspace, const Main
for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first; relation;
relation = relation->next) {
- relation->parent = newglobadr(
- fd, relation->parent); /* data from window - need to access through global oldnew-map */
+
+ /* data from window - need to access through global oldnew-map */
+ relation->parent = newglobadr(fd, relation->parent);
+
relation->value = newdataadr(fd, relation->value);
}
@@ -7682,8 +7683,8 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
win->addmousemove = true;
win->stereo3d_format = newdataadr(fd, win->stereo3d_format);
- /* multiview always fallback to anaglyph at file opening
- * otherwise quadbuffer saved files can break Blender */
+ /* Multi-view always fallback to anaglyph at file opening
+ * otherwise quad-buffer saved files can break Blender. */
if (win->stereo3d_format) {
win->stereo3d_format->display_mode = S3D_DISPLAY_ANAGLYPH;
}
@@ -8940,6 +8941,37 @@ static void direct_link_linestyle(FileData *fd, FreestyleLineStyle *linestyle)
/** \name Read Library Data Block
* \{ */
+static ID *create_placeholder(Main *mainvar, const short idcode, const char *idname, const int tag)
+{
+ ListBase *lb = which_libbase(mainvar, idcode);
+ ID *ph_id = BKE_libblock_alloc_notest(idcode);
+
+ *((short *)ph_id->name) = idcode;
+ BLI_strncpy(ph_id->name + 2, idname, sizeof(ph_id->name) - 2);
+ BKE_libblock_init_empty(ph_id);
+ ph_id->lib = mainvar->curlib;
+ ph_id->tag = tag | LIB_TAG_MISSING;
+ ph_id->us = ID_FAKE_USERS(ph_id);
+ ph_id->icon_id = 0;
+
+ BLI_addtail(lb, ph_id);
+ id_sort_by_name(lb, ph_id);
+
+ return ph_id;
+}
+
+static void placeholders_ensure_valid(Main *bmain)
+{
+ /* Placeholder ObData IDs won't have any material, we have to update their objects for that,
+ * otherwise the inconsistency between both will lead to crashes (especially in Eevee?). */
+ for (Object *ob = bmain->objects.first; ob != NULL; ob = ob->id.next) {
+ ID *obdata = ob->data;
+ if (obdata != NULL && obdata->tag & LIB_TAG_MISSING) {
+ test_object_materials(bmain, ob, obdata);
+ }
+ }
+}
+
static const char *dataname(short id_code)
{
switch (id_code) {
@@ -9125,8 +9157,9 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const int ta
/* do after read_struct, for dna reconstruct */
lb = which_libbase(main, idcode);
if (lb) {
- oldnewmap_insert(
- fd->libmap, bhead->old, id, bhead->code); /* for ID_LINK_PLACEHOLDER check */
+ /* for ID_LINK_PLACEHOLDER check */
+ oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code);
+
BLI_addtail(lb, id);
}
else {
@@ -9156,7 +9189,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const int ta
* flags dependency graph does not do animation update to avoid loss of unkeyed changes.,
* which conflicts with undo/redo of changes to animation data itself.
*
- * But for regular file load we clear the flag, since the flags might have been changed sinde
+ * But for regular file load we clear the flag, since the flags might have been changed since
* the version the file has been saved with. */
if (!fd->memfile) {
id->recalc = 0;
@@ -9456,7 +9489,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
/* don't forget to set version number in BKE_blender_version.h! */
}
-static void do_versions_after_linking(Main *main)
+static void do_versions_after_linking(Main *main, ReportList *reports)
{
// printf("%s for %s (%s), %d.%d\n", __func__, main->curlib ? main->curlib->name : main->name,
// main->curlib ? "LIB" : "MAIN", main->versionfile, main->subversionfile);
@@ -9464,7 +9497,7 @@ static void do_versions_after_linking(Main *main)
do_versions_after_linking_250(main);
do_versions_after_linking_260(main);
do_versions_after_linking_270(main);
- do_versions_after_linking_280(main);
+ do_versions_after_linking_280(main, reports);
do_versions_after_linking_cycles(main);
}
@@ -9493,8 +9526,10 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_material(fd, main);
lib_link_texture(fd, main);
lib_link_image(fd, main);
- lib_link_ipo(
- fd, main); /* XXX deprecated... still needs to be maintained for version patches still */
+
+ /* XXX deprecated... still needs to be maintained for version patches still. */
+ lib_link_ipo(fd, main);
+
lib_link_key(fd, main);
lib_link_world(fd, main);
lib_link_light(fd, main);
@@ -9508,8 +9543,10 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_armature(fd, main);
lib_link_action(fd, main);
lib_link_vfont(fd, main);
- lib_link_nodetree(fd,
- main); /* has to be done after scene/materials, this will verify group nodes */
+
+ /* Has to be done after scene/materials, this will verify group nodes. */
+ lib_link_nodetree(fd, main);
+
lib_link_palette(fd, main);
lib_link_brush(fd, main);
lib_link_paint_curve(fd, main);
@@ -9767,7 +9804,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
blo_split_main(&mainlist, bfd->main);
for (Main *mainvar = mainlist.first; mainvar; mainvar = mainvar->next) {
BLI_assert(mainvar->versionfile != 0);
- do_versions_after_linking(mainvar);
+ do_versions_after_linking(mainvar, fd->reports);
}
blo_join_main(&mainlist);
@@ -9775,6 +9812,8 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
ntreeUpdateAllNew(bfd->main);
}
+ placeholders_ensure_valid(bfd->main);
+
BKE_main_id_tag_all(bfd->main, LIB_TAG_NEW, false);
/* Now that all our data-blocks are loaded,
@@ -11096,6 +11135,19 @@ static bool object_in_any_scene(Main *bmain, Object *ob)
return false;
}
+static bool object_in_any_collection(Main *bmain, Object *ob)
+{
+ Collection *collection;
+
+ for (collection = bmain->collections.first; collection; collection = collection->id.next) {
+ if (BKE_collection_has_object(collection, ob)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
static void add_loose_objects_to_scene(Main *mainvar,
Main *bmain,
Scene *scene,
@@ -11105,7 +11157,7 @@ static void add_loose_objects_to_scene(Main *mainvar,
const short flag)
{
Collection *active_collection = NULL;
- const bool is_link = (flag & FILE_LINK) != 0;
+ const bool do_append = (flag & FILE_LINK) == 0;
BLI_assert(scene);
@@ -11114,14 +11166,13 @@ static void add_loose_objects_to_scene(Main *mainvar,
for (Object *ob = mainvar->objects.first; ob; ob = ob->id.next) {
bool do_it = (ob->id.tag & LIB_TAG_DOIT) != 0;
if (do_it || ((ob->id.tag & LIB_TAG_INDIRECT) && (ob->id.tag & LIB_TAG_PRE_EXISTING) == 0)) {
- if (!is_link) {
+ if (do_append) {
if (ob->id.us == 0) {
do_it = true;
}
- else if ((ob->id.lib == lib) && (object_in_any_scene(bmain, ob) == 0)) {
- /* When appending, make sure any indirectly loaded objects get a base,
- * else they cant be accessed at all
- * (see T27437). */
+ else if ((ob->id.lib == lib) && (object_in_any_collection(bmain, ob) == 0)) {
+ /* When appending, make sure any indirectly loaded object gets a base,
+ * when they are not part of any collection yet. */
do_it = true;
}
}
@@ -11171,8 +11222,6 @@ static void add_collections_to_scene(Main *mainvar,
Library *lib,
const short flag)
{
- const bool do_append = (flag & FILE_LINK) == 0;
-
Collection *active_collection = scene->master_collection;
if (flag & FILE_ACTIVE_COLLECTION) {
LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
@@ -11211,12 +11260,10 @@ static void add_collections_to_scene(Main *mainvar,
ob->transflag |= OB_DUPLICOLLECTION;
copy_v3_v3(ob->loc, scene->cursor.location);
}
- /* We do not want to force instantiation of indirectly linked collections...
- * Except when we are appending (since in that case, we'll end up instantiating all objects,
- * it's better to do it via their own collections if possible).
- * Reports showing that desired difference in behaviors between link and append:
- * See T62570, T61796. */
- else if (do_append || (collection->id.tag & LIB_TAG_INDIRECT) == 0) {
+ /* We do not want to force instantiation of indirectly linked collections,
+ * not even when appending. Users can now easily instantiate collections (and their objects)
+ * as needed by themselves. See T67032. */
+ else if ((collection->id.tag & LIB_TAG_INDIRECT) == 0) {
bool do_add_collection = (collection->id.tag & LIB_TAG_DOIT) != 0;
if (!do_add_collection) {
/* We need to check that objects in that collections are already instantiated in a scene.
@@ -11228,9 +11275,8 @@ static void add_collections_to_scene(Main *mainvar,
for (CollectionObject *coll_ob = collection->gobject.first; coll_ob != NULL;
coll_ob = coll_ob->next) {
Object *ob = coll_ob->ob;
- if ((ob->id.tag & LIB_TAG_PRE_EXISTING) == 0 && (ob->id.tag & LIB_TAG_DOIT) == 0 &&
- (do_append || (ob->id.tag & LIB_TAG_INDIRECT) == 0) && (ob->id.lib == lib) &&
- (object_in_any_scene(bmain, ob) == 0)) {
+ if ((ob->id.tag & (LIB_TAG_PRE_EXISTING | LIB_TAG_DOIT | LIB_TAG_INDIRECT)) == 0 &&
+ (ob->id.lib == lib) && (object_in_any_scene(bmain, ob) == 0)) {
do_add_collection = true;
break;
}
@@ -11252,6 +11298,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.tag |= LIB_TAG_EXTERN;
}
@@ -11259,25 +11306,6 @@ static void add_collections_to_scene(Main *mainvar,
}
}
-static ID *create_placeholder(Main *mainvar, const short idcode, const char *idname, const int tag)
-{
- ListBase *lb = which_libbase(mainvar, idcode);
- ID *ph_id = BKE_libblock_alloc_notest(idcode);
-
- *((short *)ph_id->name) = idcode;
- BLI_strncpy(ph_id->name + 2, idname, sizeof(ph_id->name) - 2);
- BKE_libblock_init_empty(ph_id);
- ph_id->lib = mainvar->curlib;
- ph_id->tag = tag | LIB_TAG_MISSING;
- ph_id->us = ID_FAKE_USERS(ph_id);
- ph_id->icon_id = 0;
-
- BLI_addtail(lb, ph_id);
- id_sort_by_name(lb, ph_id);
-
- return ph_id;
-}
-
/* returns true if the item was found
* but it may already have already been appended/linked */
static ID *link_named_part(
@@ -11547,7 +11575,7 @@ static void library_link_end(Main *mainl,
* or they will go again through do_versions - bad, very bad! */
split_main_newid(mainvar, main_newid);
- do_versions_after_linking(main_newid);
+ do_versions_after_linking(main_newid, (*fd)->reports);
add_main_to_main(mainvar, main_newid);
}
@@ -11559,10 +11587,12 @@ static void library_link_end(Main *mainl,
/* After all data has been read and versioned, uses LIB_TAG_NEW. */
ntreeUpdateAllNew(mainvar);
+ placeholders_ensure_valid(mainvar);
+
BKE_main_id_tag_all(mainvar, LIB_TAG_NEW, false);
- fix_relpaths_library(BKE_main_blendfile_path(mainvar),
- mainvar); /* make all relative paths, relative to the open blend file */
+ /* Make all relative paths, relative to the open blend file. */
+ fix_relpaths_library(BKE_main_blendfile_path(mainvar), mainvar);
/* Give a base to loose objects and collections.
* Only directly linked objects & collections are instantiated by
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index 7cd5bb7ac93..10ee3d52a74 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -187,7 +187,7 @@ void blo_do_versions_cycles(struct FileData *fd, struct Library *lib, struct Mai
void do_versions_after_linking_250(struct Main *bmain);
void do_versions_after_linking_260(struct Main *bmain);
void do_versions_after_linking_270(struct Main *bmain);
-void do_versions_after_linking_280(struct Main *bmain);
+void do_versions_after_linking_280(struct Main *bmain, ReportList *reports);
void do_versions_after_linking_cycles(struct Main *bmain);
#endif
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 0ef566d9e89..837c78d303f 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -125,8 +125,8 @@ static void do_version_workspaces_create_from_screens(Main *bmain)
}
if (screen_parent) {
- /* fullscreen with "Back to Previous" option, don't create
- * a new workspace, add layout workspace containing parent */
+ /* Full-screen with "Back to Previous" option, don't create
+ * a new workspace, add layout workspace containing parent. */
workspace = BLI_findstring(
&bmain->workspaces, screen_parent->id.name + 2, offsetof(ID, name) + 2);
}
@@ -734,7 +734,98 @@ static void do_versions_seq_alloc_transform_and_crop(ListBase *seqbase)
}
}
-void do_versions_after_linking_280(Main *bmain)
+/* Return true if there is something to convert. */
+static void do_versions_material_convert_legacy_blend_mode(bNodeTree *ntree, char blend_method)
+{
+ bool need_update = false;
+
+ /* Iterate backwards from end so we don't encounter newly added links. */
+ bNodeLink *prevlink;
+ for (bNodeLink *link = ntree->links.last; link; link = prevlink) {
+ prevlink = link->prev;
+
+ /* Detect link to replace. */
+ bNode *fromnode = link->fromnode;
+ bNodeSocket *fromsock = link->fromsock;
+ bNode *tonode = link->tonode;
+ bNodeSocket *tosock = link->tosock;
+
+ if (!(tonode->type == SH_NODE_OUTPUT_MATERIAL && STREQ(tosock->identifier, "Surface"))) {
+ continue;
+ }
+
+ /* Only do outputs that are enabled for EEVEE */
+ if (!ELEM(tonode->custom1, SHD_OUTPUT_ALL, SHD_OUTPUT_EEVEE)) {
+ continue;
+ }
+
+ if (blend_method == 1 /* MA_BM_ADD */) {
+ nodeRemLink(ntree, link);
+
+ bNode *add_node = nodeAddStaticNode(NULL, ntree, SH_NODE_ADD_SHADER);
+ add_node->locx = 0.5f * (fromnode->locx + tonode->locx);
+ add_node->locy = 0.5f * (fromnode->locy + tonode->locy);
+
+ bNodeSocket *shader1_socket = add_node->inputs.first;
+ bNodeSocket *shader2_socket = add_node->inputs.last;
+ bNodeSocket *add_socket = nodeFindSocket(add_node, SOCK_OUT, "Shader");
+
+ bNode *transp_node = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_TRANSPARENT);
+ transp_node->locx = add_node->locx;
+ transp_node->locy = add_node->locy - 110.0f;
+
+ bNodeSocket *transp_socket = nodeFindSocket(transp_node, SOCK_OUT, "BSDF");
+
+ /* Link to input and material output node. */
+ nodeAddLink(ntree, fromnode, fromsock, add_node, shader1_socket);
+ nodeAddLink(ntree, transp_node, transp_socket, add_node, shader2_socket);
+ nodeAddLink(ntree, add_node, add_socket, tonode, tosock);
+
+ need_update = true;
+ }
+ else if (blend_method == 2 /* MA_BM_MULTIPLY */) {
+ nodeRemLink(ntree, link);
+
+ bNode *transp_node = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_TRANSPARENT);
+
+ bNodeSocket *color_socket = nodeFindSocket(transp_node, SOCK_IN, "Color");
+ bNodeSocket *transp_socket = nodeFindSocket(transp_node, SOCK_OUT, "BSDF");
+
+ /* If incomming link is from a closure socket, we need to convert it. */
+ if (fromsock->type == SOCK_SHADER) {
+ transp_node->locx = 0.33f * fromnode->locx + 0.66f * tonode->locx;
+ transp_node->locy = 0.33f * fromnode->locy + 0.66f * tonode->locy;
+
+ bNode *shtorgb_node = nodeAddStaticNode(NULL, ntree, SH_NODE_SHADERTORGB);
+ shtorgb_node->locx = 0.66f * fromnode->locx + 0.33f * tonode->locx;
+ shtorgb_node->locy = 0.66f * fromnode->locy + 0.33f * tonode->locy;
+
+ bNodeSocket *shader_socket = nodeFindSocket(shtorgb_node, SOCK_IN, "Shader");
+ bNodeSocket *rgba_socket = nodeFindSocket(shtorgb_node, SOCK_OUT, "Color");
+
+ nodeAddLink(ntree, fromnode, fromsock, shtorgb_node, shader_socket);
+ nodeAddLink(ntree, shtorgb_node, rgba_socket, transp_node, color_socket);
+ }
+ else {
+ transp_node->locx = 0.5f * (fromnode->locx + tonode->locx);
+ transp_node->locy = 0.5f * (fromnode->locy + tonode->locy);
+
+ nodeAddLink(ntree, fromnode, fromsock, transp_node, color_socket);
+ }
+
+ /* Link to input and material output node. */
+ nodeAddLink(ntree, transp_node, transp_socket, tonode, tosock);
+
+ need_update = true;
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
+void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
{
bool use_collection_compat_28 = true;
@@ -1129,6 +1220,28 @@ void do_versions_after_linking_280(Main *bmain)
camera->dof_ob = NULL;
}
}
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 2)) {
+ /* Replace Multiply and Additive blend mode by Alpha Blend
+ * now that we use dualsource blending. */
+ /* We take care of doing only nodetrees that are always part of materials
+ * with old blending modes. */
+ for (Material *ma = bmain->materials.first; ma; ma = ma->id.next) {
+ bNodeTree *ntree = ma->nodetree;
+ if (ma->blend_method == 1 /* MA_BM_ADD */) {
+ if (ma->use_nodes) {
+ do_versions_material_convert_legacy_blend_mode(ntree, 1 /* MA_BM_ADD */);
+ }
+ ma->blend_method = MA_BM_BLEND;
+ }
+ else if (ma->blend_method == 2 /* MA_BM_MULTIPLY */) {
+ if (ma->use_nodes) {
+ do_versions_material_convert_legacy_blend_mode(ntree, 2 /* MA_BM_MULTIPLY */);
+ }
+ ma->blend_method = MA_BM_BLEND;
+ }
+ }
+ }
}
/* NOTE: This version patch is intended for versions < 2.52.2,
@@ -2668,9 +2781,9 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
navigation_region = MEM_callocN(sizeof(ARegion),
"userpref navigation-region do_versions");
- BLI_insertlinkbefore(regionbase,
- main_region,
- navigation_region); /* order matters, addhead not addtail! */
+ /* Order matters, addhead not addtail! */
+ BLI_insertlinkbefore(regionbase, main_region, navigation_region);
+
navigation_region->regiontype = RGN_TYPE_NAV_BAR;
navigation_region->alignment = RGN_ALIGN_LEFT;
}
@@ -3565,9 +3678,20 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
ar->alignment = RGN_ALIGN_RIGHT;
}
}
+ /* Mark outliners as dirty for syncing and enable synced selection */
+ if (sl->spacetype == SPACE_OUTLINER) {
+ SpaceOutliner *soutliner = (SpaceOutliner *)sl;
+ soutliner->sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_ALL;
+ soutliner->flag |= SO_SYNC_SELECT;
+ }
}
}
}
+ for (Mesh *mesh = bmain->meshes.first; mesh; mesh = mesh->id.next) {
+ if (mesh->remesh_voxel_size == 0.0f) {
+ mesh->remesh_voxel_size = 0.1f;
+ }
+ }
}
{
diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c
index cebe15e2719..10f24cff61b 100644
--- a/source/blender/blenloader/intern/versioning_cycles.c
+++ b/source/blender/blenloader/intern/versioning_cycles.c
@@ -26,6 +26,7 @@
#include "BLI_math.h"
#include "BLI_string.h"
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "DNA_color_types.h"
@@ -185,7 +186,7 @@ static void square_roughness_node_insert(bNodeTree *ntree)
/* Add sqrt node. */
bNode *node = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH);
- node->custom1 = NODE_MATH_POW;
+ node->custom1 = NODE_MATH_POWER;
node->locx = 0.5f * (fromnode->locx + tonode->locx);
node->locy = 0.5f * (fromnode->locy + tonode->locy);
@@ -385,6 +386,46 @@ static void light_emission_unify(Light *light, const char *engine)
}
}
+/* The B input of the Math node is no longer used for single-operand operators.
+ * Previously, if the B input was linked and the A input was not, the B input
+ * was used as the input of the operator. To correct this, we move the link
+ * from B to A if B is linked and A is not.
+ */
+static void update_math_node_single_operand_operators(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_MATH) {
+ if (ELEM(node->custom1,
+ NODE_MATH_SQRT,
+ NODE_MATH_CEIL,
+ NODE_MATH_SINE,
+ NODE_MATH_ROUND,
+ NODE_MATH_FLOOR,
+ NODE_MATH_COSINE,
+ NODE_MATH_ARCSINE,
+ NODE_MATH_TANGENT,
+ NODE_MATH_ABSOLUTE,
+ NODE_MATH_FRACTION,
+ NODE_MATH_ARCCOSINE,
+ NODE_MATH_ARCTANGENT)) {
+ bNodeSocket *sockA = BLI_findlink(&node->inputs, 0);
+ bNodeSocket *sockB = BLI_findlink(&node->inputs, 1);
+ if (!sockA->link && sockB->link) {
+ nodeAddLink(ntree, sockB->link->fromnode, sockB->link->fromsock, node, sockA);
+ nodeRemLink(ntree, sockB->link);
+ 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. */
@@ -526,4 +567,13 @@ void do_versions_after_linking_cycles(Main *bmain)
}
}
}
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 2)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ update_math_node_single_operand_operators(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
}
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index 02c777ee9b9..2ef1a5c096c 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -145,6 +145,11 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
* Include next version bump.
*/
{
+ FROM_DEFAULT_V4_UCHAR(space_outliner.selected_highlight);
+ FROM_DEFAULT_V4_UCHAR(space_outliner.active);
+
+
+
FROM_DEFAULT_V4_UCHAR(space_file.execution_buts);
}
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 5954ba9cf8e..0ff7ba0034f 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -1142,9 +1142,12 @@ typedef struct RenderInfo {
char scene_name[MAX_ID_NAME - 2];
} RenderInfo;
-/* was for historic render-deamon feature,
- * now write because it can be easily extracted without
- * reading the whole blend file */
+/**
+ * This was originally added for the historic render-daemon feature,
+ * now write because it can be easily extracted without reading the whole blend file.
+ *
+ * See: `release/scripts/modules/blend_render_info.py`
+ */
static void write_renderinfo(WriteData *wd, Main *mainvar)
{
bScreen *curscreen;
diff --git a/source/blender/blentranslation/msgfmt/msgfmt.c b/source/blender/blentranslation/msgfmt/msgfmt.c
index 215c92f87de..4691d791301 100644
--- a/source/blender/blentranslation/msgfmt/msgfmt.c
+++ b/source/blender/blentranslation/msgfmt/msgfmt.c
@@ -24,7 +24,7 @@
*
* Generate binary message catalog from textual translation description.
*
- * This program converts a textual Uniforum-style message catalog (.po file)
+ * This program converts a textual Uniform-style message catalog (.po file)
* into a binary GNU catalog (.mo file).
* This is essentially the same function as the GNU msgfmt program,
* however, it is a simpler implementation.
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index 5aec59ccd5d..788edc348d9 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -870,9 +870,11 @@ void BM_editselection_normal(BMEditSelection *ese, float r_normal[3])
}
}
-/* Calculate a plane that is rightangles to the edge/vert/faces normal
+/**
+ * Calculate a plane that is right angles to the edge/vert/faces normal
* also make the plane run along an axis that is related to the geometry,
- * because this is used for the gizmos Y axis. */
+ * because this is used for the gizmos Y axis.
+ */
void BM_editselection_plane(BMEditSelection *ese, float r_plane[3])
{
if (ese->htype == BM_VERT) {
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c
index 2000689b496..9bab959f0a2 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c
@@ -422,7 +422,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
/* don't use 'j' since we may have skipped some faces, hence some loops. */
BM_elem_index_set(l_iter, totloops++); /* set_ok */
- /* Save index of correspsonding MLoop */
+ /* Save index of corresponding #MLoop. */
CustomData_to_bmesh_block(&me->ldata, &bm->ldata, j++, &l_iter->head.data, true);
} while ((l_iter = l_iter->next) != l_first);
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index e8b35afdcb1..b9f0bcc05f0 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -336,7 +336,7 @@ static BMOpDefine bmo_find_doubles_def = {
/* slots_in */
{{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* input vertices */
{"keep_verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* list of verts to keep */
- {"dist", BMO_OP_SLOT_FLT}, /* minimum distance */
+ {"dist", BMO_OP_SLOT_FLT}, /* maximum distance */
{{'\0'}},
},
/* slots_out */
@@ -379,7 +379,7 @@ static BMOpDefine bmo_automerge_def = {
"automerge",
/* slots_in */
{{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* input verts */
- {"dist", BMO_OP_SLOT_FLT}, /* minimum distance */
+ {"dist", BMO_OP_SLOT_FLT}, /* maximum distance */
{{'\0'}},
},
{{{'\0'}}}, /* no output */
@@ -1173,7 +1173,7 @@ static BMOpDefine bmo_dissolve_limit_def = {
static BMOpDefine bmo_dissolve_degenerate_def = {
"dissolve_degenerate",
/* slots_in */
- {{"dist", BMO_OP_SLOT_FLT}, /* minimum distance to consider degenerate */
+ {{"dist", BMO_OP_SLOT_FLT}, /* maximum distance to consider degenerate */
{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}},
{{'\0'}},
},
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index dc839054987..915ad6bf5c4 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -483,7 +483,7 @@ void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_tangent[3])
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- /* incase of degenerate faces */
+ /* In case of degenerate faces. */
zero_v3(r_tangent);
/* warning: O(n^2) loop here, take care! */
@@ -520,7 +520,7 @@ void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_tangent[3])
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- /* incase of degenerate faces */
+ /* In case of degenerate faces. */
zero_v3(r_tangent);
/* warning: O(n^2) loop here, take care! */
diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c
index 4a47bcccb25..51bc86e40eb 100644
--- a/source/blender/bmesh/intern/bmesh_query.c
+++ b/source/blender/bmesh/intern/bmesh_query.c
@@ -1542,7 +1542,7 @@ float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq,
/**
* #BM_loop_calc_face_normal_safe_ex with pre-defined sane epsilon.
*
- * Since this doesn't scale baed on triangle size, fixed value works well.
+ * Since this doesn't scale based on triangle size, fixed value works well.
*/
float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3])
{
diff --git a/source/blender/bmesh/intern/bmesh_walkers_impl.c b/source/blender/bmesh/intern/bmesh_walkers_impl.c
index ade6fdfcbed..f317c59b8d1 100644
--- a/source/blender/bmesh/intern/bmesh_walkers_impl.c
+++ b/source/blender/bmesh/intern/bmesh_walkers_impl.c
@@ -648,7 +648,7 @@ static void *bmw_ConnectedVertexWalker_step(BMWalker *walker)
* \note that this doesn't work on non-manifold geometry.
* it might be better to rewrite this to extract
* boundary info from the island walker, rather then directly walking
- * over the boundary. raises an error if it encounters nonmanifold geometry.
+ * over the boundary. raises an error if it encounters non-manifold geometry.
*
* \todo Add restriction flag/callback for wire edges.
*/
diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c
index 287a7e93470..ff7dcc388b3 100644
--- a/source/blender/bmesh/operators/bmo_primitive.c
+++ b/source/blender/bmesh/operators/bmo_primitive.c
@@ -1560,9 +1560,10 @@ void BM_mesh_calc_uvs_cone(BMesh *bm,
float inv_mat[4][4];
int loop_index;
- mul_mat3_m4_v3(
- mat, local_up); /* transform the upvector like we did the cone itself, without location. */
- normalize_v3(local_up); /* remove global scaling... */
+ /* Transform the upvector like we did the cone itself, without location. */
+ mul_mat3_m4_v3(mat, local_up);
+ /* Remove global scaling... */
+ normalize_v3(local_up);
invert_m4_m4(inv_mat, mat);
diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c
index 616886deba1..d783842c017 100644
--- a/source/blender/bmesh/operators/bmo_removedoubles.c
+++ b/source/blender/bmesh/operators/bmo_removedoubles.c
@@ -80,10 +80,12 @@ static BMFace *remdoubles_createface(BMesh *bm,
{
BMEdge *e_new;
- BMEdge **edges = BLI_array_alloca(edges, f->len); /* new ordered edges */
- BMVert **verts = BLI_array_alloca(verts, f->len); /* new ordered verts */
- BMLoop **loops = BLI_array_alloca(
- loops, f->len); /* original ordered loops to copy attrs into the new face */
+ /* New ordered edges. */
+ BMEdge **edges = BLI_array_alloca(edges, f->len);
+ /* New ordered verts. */
+ BMVert **verts = BLI_array_alloca(verts, f->len);
+ /* Original ordered loops to copy attributes into the new face. */
+ BMLoop **loops = BLI_array_alloca(loops, f->len);
STACK_DECLARE(edges);
STACK_DECLARE(loops);
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 94935f2090b..797e2ca864e 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -3122,6 +3122,7 @@ static void adjust_offsets(BevelParams *bp, BMesh *bm)
}
if (!iscycle) {
/* right->left direction, changing vchainstart at each step */
+ v->adjchain = NULL;
v = vchainstart;
bvcur = bv;
do {
diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
index e32a9334343..198b4c8e76b 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
@@ -363,7 +363,7 @@ static void bm_decim_build_edge_cost(BMesh *bm,
struct KD_Symmetry_Data {
/* pre-flipped coords */
float e_v1_co[3], e_v2_co[3];
- /* Use to compare the correct endpoints incase v1/v2 are swapped */
+ /* Use to compare the correct endpoints in case v1/v2 are swapped. */
float e_dir[3];
int e_found_index;
@@ -1371,8 +1371,8 @@ void BM_mesh_decimate_collapse(BMesh *bm,
/* handy to detect corruptions elsewhere */
BLI_assert(BM_elem_index_get(e) < tot_edge_orig);
- /* under normal conditions wont be accessed again,
- * but NULL just incase so we don't use freed node */
+ /* Under normal conditions wont be accessed again,
+ * but NULL just in case so we don't use freed node. */
eheap_table[BM_elem_index_get(e)] = NULL;
bm_decim_edge_collapse(bm,
diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
index 27b4fa15f26..2cc86a7c93f 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
@@ -231,7 +231,7 @@ void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool
if (BMO_vert_flag_test(bm, v, ELE_VERT_TAG))
#endif
{
- /* check again incase the topology changed */
+ /* Check again in case the topology changed. */
if (bm_vert_dissolve_fan_test(v)) {
v_first = v;
}
diff --git a/source/blender/bmesh/tools/bmesh_region_match.c b/source/blender/bmesh/tools/bmesh_region_match.c
index 943f7532960..c30992fa296 100644
--- a/source/blender/bmesh/tools/bmesh_region_match.c
+++ b/source/blender/bmesh/tools/bmesh_region_match.c
@@ -1099,7 +1099,7 @@ static BMEdge *bm_face_region_pivot_edge_find(BMFace **faces_region,
}
}
else {
- /* use incase (depth == 0), no interior verts */
+ /* Use in case (depth == 0), no interior verts. */
e_pivot_fallback = e;
}
} while ((l_iter = l_iter->next) != l_first);
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index 657cce24a82..64031e10d77 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -1149,8 +1149,9 @@ Object *MeshImporter::create_mesh_object(
BKE_mesh_assign_object(m_bmain, ob, new_mesh);
BKE_mesh_calc_normals(new_mesh);
- id_us_plus(
- &old_mesh->id); /* Because BKE_mesh_assign_object would have already decreased it... */
+ /* Because BKE_mesh_assign_object would have already decreased it... */
+ id_us_plus(&old_mesh->id);
+
BKE_id_free_us(m_bmain, old_mesh);
COLLADAFW::MaterialBindingArray &mat_array = geom->getMaterialBindings();
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 308a95c0e0c..50b5951f99f 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -276,11 +276,12 @@ set(SRC
nodes/COM_VectorBlurNode.h
operations/COM_VectorBlurOperation.cpp
operations/COM_VectorBlurOperation.h
-
nodes/COM_BlurNode.cpp
nodes/COM_BlurNode.h
nodes/COM_BokehBlurNode.cpp
nodes/COM_BokehBlurNode.h
+ nodes/COM_DenoiseNode.h
+ nodes/COM_DenoiseNode.cpp
nodes/COM_DespeckleNode.cpp
nodes/COM_DespeckleNode.h
nodes/COM_DilateErodeNode.cpp
@@ -490,6 +491,8 @@ set(SRC
operations/COM_ConvolutionEdgeFilterOperation.h
operations/COM_ConvolutionFilterOperation.cpp
operations/COM_ConvolutionFilterOperation.h
+ operations/COM_DenoiseOperation.h
+ operations/COM_DenoiseOperation.cpp
operations/COM_DespeckleOperation.cpp
operations/COM_DespeckleOperation.h
operations/COM_DilateErodeOperation.cpp
@@ -558,4 +561,12 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_OPENIMAGEDENOISE)
+ add_definitions(-DWITH_OPENIMAGEDENOISE)
+ add_definitions(-DOIDN_STATIC_LIB)
+ list(APPEND INC_SYS
+ ${OPENIMAGEDENOISE_INCLUDE_DIRS}
+ )
+endif()
+
blender_add_lib(bf_compositor "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/compositor/intern/COM_CompositorContext.h b/source/blender/compositor/intern/COM_CompositorContext.h
index f4cd60e3ee0..b28d5ff0cdf 100644
--- a/source/blender/compositor/intern/COM_CompositorContext.h
+++ b/source/blender/compositor/intern/COM_CompositorContext.h
@@ -215,7 +215,7 @@ class CompositorContext {
}
/**
- * \brief get the current framenumber of the scene in this context
+ * \brief get the current frame-number of the scene in this context
*/
int getFramenumber() const;
diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp
index 9dc55527f0d..704833389f8 100644
--- a/source/blender/compositor/intern/COM_Converter.cpp
+++ b/source/blender/compositor/intern/COM_Converter.cpp
@@ -53,6 +53,7 @@ extern "C" {
#include "COM_CropNode.h"
#include "COM_CryptomatteNode.h"
#include "COM_DefocusNode.h"
+#include "COM_DenoiseNode.h"
#include "COM_DespeckleNode.h"
#include "COM_DifferenceMatteNode.h"
#include "COM_DilateErodeNode.h"
@@ -122,7 +123,7 @@ bool Converter::is_fast_node(bNode *b_node)
b_node->type == CMP_NODE_BOKEHBLUR || b_node->type == CMP_NODE_GLARE ||
b_node->type == CMP_NODE_DBLUR || b_node->type == CMP_NODE_MOVIEDISTORTION ||
b_node->type == CMP_NODE_LENSDIST || b_node->type == CMP_NODE_DOUBLEEDGEMASK ||
- b_node->type == CMP_NODE_DILATEERODE);
+ b_node->type == CMP_NODE_DILATEERODE || b_node->type == CMP_NODE_DENOISE);
}
Node *Converter::convert(bNode *b_node)
@@ -402,6 +403,9 @@ Node *Converter::convert(bNode *b_node)
case CMP_NODE_CRYPTOMATTE:
node = new CryptomatteNode(b_node);
break;
+ case CMP_NODE_DENOISE:
+ node = new DenoiseNode(b_node);
+ break;
}
return node;
}
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h
index df936818f33..7e5b0264aa3 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.h
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.h
@@ -73,7 +73,7 @@ class MemoryBuffer {
rcti m_rect;
/**
- * brief refers to the chunknumber within the executiongroup where related to the MemoryProxy
+ * brief refers to the chunk-number within the execution-group where related to the MemoryProxy
* \see memoryProxy
*/
unsigned int m_chunkNumber;
diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h
index af9ed2648c9..6b073452771 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.h
+++ b/source/blender/compositor/intern/COM_NodeOperation.h
@@ -368,7 +368,7 @@ class NodeOperation : public SocketReader {
return true;
}
- inline bool isBreaked() const
+ inline bool isBraked() const
{
return this->m_btree->test_break(this->m_btree->tbh);
}
diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.cpp b/source/blender/compositor/intern/COM_OpenCLDevice.cpp
index 0aa054b8c77..2529637801d 100644
--- a/source/blender/compositor/intern/COM_OpenCLDevice.cpp
+++ b/source/blender/compositor/intern/COM_OpenCLDevice.cpp
@@ -248,7 +248,7 @@ void OpenCLDevice::COM_clEnqueueRange(cl_kernel kernel,
printf("CLERROR[%d]: %s\n", error, clewErrorString(error));
}
clFlush(this->m_queue);
- if (operation->isBreaked()) {
+ if (operation->isBraked()) {
breaked = false;
}
}
diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.h b/source/blender/compositor/intern/COM_OpenCLDevice.h
index 7a83bda162c..45ce77acac7 100644
--- a/source/blender/compositor/intern/COM_OpenCLDevice.h
+++ b/source/blender/compositor/intern/COM_OpenCLDevice.h
@@ -78,8 +78,8 @@ class OpenCLDevice : public Device {
bool initialize();
/**
- * \brief deinitialize the device
- * During deintiialization the command queue is cleared
+ * \brief de-initialize the device
+ * During de-initialization the command queue is cleared
*/
void deinitialize();
diff --git a/source/blender/compositor/nodes/COM_DenoiseNode.cpp b/source/blender/compositor/nodes/COM_DenoiseNode.cpp
new file mode 100644
index 00000000000..7de120d1204
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_DenoiseNode.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor:
+ * Stefan Werner
+ */
+
+#include "COM_DenoiseNode.h"
+#include "DNA_node_types.h"
+#include "COM_SetValueOperation.h"
+#include "COM_MixOperation.h"
+#include "COM_DenoiseOperation.h"
+
+DenoiseNode::DenoiseNode(bNode *editorNode) : Node(editorNode)
+{
+ /* pass */
+}
+
+void DenoiseNode::convertToOperations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
+{
+ bNode *node = this->getbNode();
+ NodeDenoise *denoise = (NodeDenoise *)node->storage;
+
+ DenoiseOperation *operation = new DenoiseOperation();
+ converter.addOperation(operation);
+ operation->setDenoiseSettings(denoise);
+
+ converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
+ converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
+ converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2));
+ converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+}
diff --git a/source/blender/compositor/nodes/COM_DenoiseNode.h b/source/blender/compositor/nodes/COM_DenoiseNode.h
new file mode 100644
index 00000000000..0924da8931c
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_DenoiseNode.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor:
+ * Stefan Werner
+ */
+
+#ifndef __COM_DENOISENODE_H__
+#define __COM_DENOISENODE_H__
+
+#include "COM_Node.h"
+
+/**
+ * \brief DenoiseNode
+ * \ingroup Node
+ */
+class DenoiseNode : public Node {
+ public:
+ DenoiseNode(bNode *editorNode);
+ void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
+};
+
+#endif
diff --git a/source/blender/compositor/nodes/COM_ImageNode.cpp b/source/blender/compositor/nodes/COM_ImageNode.cpp
index dc3f65deb1f..6bce56ffd52 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.cpp
+++ b/source/blender/compositor/nodes/COM_ImageNode.cpp
@@ -195,7 +195,7 @@ void ImageNode::convertToOperations(NodeConverter &converter,
}
}
- /* incase we can't load the layer */
+ /* In case we can't load the layer. */
if (operation == NULL) {
converter.setInvalidOutput(getOutputSocket(index));
}
diff --git a/source/blender/compositor/nodes/COM_MathNode.cpp b/source/blender/compositor/nodes/COM_MathNode.cpp
index 5a2f934f37f..d13b34bb6b5 100644
--- a/source/blender/compositor/nodes/COM_MathNode.cpp
+++ b/source/blender/compositor/nodes/COM_MathNode.cpp
@@ -29,61 +29,61 @@ void MathNode::convertToOperations(NodeConverter &converter,
case NODE_MATH_ADD:
operation = new MathAddOperation();
break;
- case NODE_MATH_SUB:
+ case NODE_MATH_SUBTRACT:
operation = new MathSubtractOperation();
break;
- case NODE_MATH_MUL:
+ case NODE_MATH_MULTIPLY:
operation = new MathMultiplyOperation();
break;
case NODE_MATH_DIVIDE:
operation = new MathDivideOperation();
break;
- case NODE_MATH_SIN:
+ case NODE_MATH_SINE:
operation = new MathSineOperation();
break;
- case NODE_MATH_COS:
+ case NODE_MATH_COSINE:
operation = new MathCosineOperation();
break;
- case NODE_MATH_TAN:
+ case NODE_MATH_TANGENT:
operation = new MathTangentOperation();
break;
- case NODE_MATH_ASIN:
+ case NODE_MATH_ARCSINE:
operation = new MathArcSineOperation();
break;
- case NODE_MATH_ACOS:
+ case NODE_MATH_ARCCOSINE:
operation = new MathArcCosineOperation();
break;
- case NODE_MATH_ATAN:
+ case NODE_MATH_ARCTANGENT:
operation = new MathArcTangentOperation();
break;
- case NODE_MATH_POW:
+ case NODE_MATH_POWER:
operation = new MathPowerOperation();
break;
- case NODE_MATH_LOG:
+ case NODE_MATH_LOGARITHM:
operation = new MathLogarithmOperation();
break;
- case NODE_MATH_MIN:
+ case NODE_MATH_MINIMUM:
operation = new MathMinimumOperation();
break;
- case NODE_MATH_MAX:
+ case NODE_MATH_MAXIMUM:
operation = new MathMaximumOperation();
break;
case NODE_MATH_ROUND:
operation = new MathRoundOperation();
break;
- case NODE_MATH_LESS:
+ case NODE_MATH_LESS_THAN:
operation = new MathLessThanOperation();
break;
- case NODE_MATH_GREATER:
+ case NODE_MATH_GREATER_THAN:
operation = new MathGreaterThanOperation();
break;
- case NODE_MATH_MOD:
+ case NODE_MATH_MODULO:
operation = new MathModuloOperation();
break;
- case NODE_MATH_ABS:
+ case NODE_MATH_ABSOLUTE:
operation = new MathAbsoluteOperation();
break;
- case NODE_MATH_ATAN2:
+ case NODE_MATH_ARCTAN2:
operation = new MathArcTan2Operation();
break;
case NODE_MATH_FLOOR:
@@ -92,7 +92,7 @@ void MathNode::convertToOperations(NodeConverter &converter,
case NODE_MATH_CEIL:
operation = new MathCeilOperation();
break;
- case NODE_MATH_FRACT:
+ case NODE_MATH_FRACTION:
operation = new MathFractOperation();
break;
case NODE_MATH_SQRT:
diff --git a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp
index 68b5af3089a..1578a805d1e 100644
--- a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp
@@ -22,7 +22,7 @@
inline float colorbalance_lgg(float in, float lift_lgg, float gamma_inv, float gain)
{
/* 1:1 match with the sequencer with linear/srgb conversions, the conversion isnt pretty
- * but best keep it this way, sice testing for durian shows a similar calculation
+ * but best keep it this way, since testing for durian shows a similar calculation
* without lin/srgb conversions gives bad results (over-saturated shadows) with colors
* slightly below 1.0. some correction can be done but it ends up looking bad for shadows or
* lighter tones - campbell */
diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cpp b/source/blender/compositor/operations/COM_CompositorOperation.cpp
index 40315d217ce..5bd466658c0 100644
--- a/source/blender/compositor/operations/COM_CompositorOperation.cpp
+++ b/source/blender/compositor/operations/COM_CompositorOperation.cpp
@@ -78,7 +78,7 @@ void CompositorOperation::deinitExecution()
return;
}
- if (!isBreaked()) {
+ if (!isBraked()) {
Render *re = RE_GetSceneRender(this->m_scene);
RenderResult *rr = RE_AcquireResultWrite(re);
@@ -207,7 +207,7 @@ void CompositorOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
zbuffer[offset] = color[0];
offset4 += COM_NUM_CHANNELS_COLOR;
offset++;
- if (isBreaked()) {
+ if (isBraked()) {
breaked = true;
}
}
diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.cpp b/source/blender/compositor/operations/COM_DenoiseOperation.cpp
new file mode 100644
index 00000000000..ad53ab13def
--- /dev/null
+++ b/source/blender/compositor/operations/COM_DenoiseOperation.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2019, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor:
+ * Stefan Werner
+ */
+
+#include "COM_DenoiseOperation.h"
+#include "BLI_math.h"
+#ifdef WITH_OPENIMAGEDENOISE
+# include <OpenImageDenoise/oidn.hpp>
+#endif
+#include <iostream>
+
+DenoiseOperation::DenoiseOperation() : SingleThreadedOperation()
+{
+ this->addInputSocket(COM_DT_COLOR);
+ this->addInputSocket(COM_DT_COLOR);
+ this->addInputSocket(COM_DT_VECTOR);
+ this->addOutputSocket(COM_DT_COLOR);
+ this->m_settings = NULL;
+}
+void DenoiseOperation::initExecution()
+{
+ SingleThreadedOperation::initExecution();
+ this->m_inputProgramColor = getInputSocketReader(0);
+ this->m_inputProgramAlbedo = getInputSocketReader(1);
+ this->m_inputProgramNormal = getInputSocketReader(2);
+}
+
+void DenoiseOperation::deinitExecution()
+{
+ this->m_inputProgramColor = NULL;
+ this->m_inputProgramAlbedo = NULL;
+ this->m_inputProgramNormal = 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);
+ rcti rect;
+ rect.xmin = 0;
+ rect.ymin = 0;
+ rect.xmax = getWidth();
+ rect.ymax = getHeight();
+ MemoryBuffer *result = new MemoryBuffer(COM_DT_COLOR, &rect);
+ float *data = result->getBuffer();
+ this->generateDenoise(data, tileColor, tileAlbedo, tileNormal, this->m_settings);
+ return result;
+}
+
+bool DenoiseOperation::determineDependingAreaOfInterest(rcti * /*input*/,
+ ReadBufferOperation *readOperation,
+ rcti *output)
+{
+ if (isCached()) {
+ return false;
+ }
+ else {
+ rcti newInput;
+ newInput.xmax = this->getWidth();
+ newInput.xmin = 0;
+ newInput.ymax = this->getHeight();
+ newInput.ymin = 0;
+ return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ }
+}
+
+void DenoiseOperation::generateDenoise(float *data,
+ MemoryBuffer *inputTileColor,
+ MemoryBuffer *inputTileAlbedo,
+ MemoryBuffer *inputTileNormal,
+ NodeDenoise *settings)
+{
+ float *inputBufferColor = inputTileColor->getBuffer();
+ BLI_assert(inputBufferColor);
+ if (!inputBufferColor) {
+ return;
+ }
+#ifdef WITH_OPENIMAGEDENOISE
+ 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::Format::Float3,
+ inputTileAlbedo->getWidth(),
+ inputTileAlbedo->getHeight(),
+ 0,
+ 4 * sizeof(float));
+ }
+ if (inputTileNormal && inputTileNormal->getBuffer()) {
+ filter.setImage("normal",
+ inputTileNormal->getBuffer(),
+ oidn::Format::Float3,
+ inputTileNormal->getWidth(),
+ inputTileNormal->getHeight(),
+ 0,
+ 3 * sizeof(float));
+ }
+ filter.setImage("output",
+ data,
+ oidn::Format::Float3,
+ inputTileColor->getWidth(),
+ inputTileColor->getHeight(),
+ 0,
+ 4 * sizeof(float));
+
+ BLI_assert(settings);
+ if (settings) {
+ filter.set("hdr", settings->hdr);
+ filter.set("srgb", false);
+ }
+
+ filter.commit();
+ filter.execute();
+
+ /* 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];
+ }
+#else
+ 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
new file mode 100644
index 00000000000..6e19bd6034a
--- /dev/null
+++ b/source/blender/compositor/operations/COM_DenoiseOperation.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2019, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor:
+ * Stefan Werner
+ */
+
+#ifndef __COM_DENOISEBASEOPERATION_H__
+#define __COM_DENOISEBASEOPERATION_H__
+
+#include "COM_SingleThreadedOperation.h"
+#include "DNA_node_types.h"
+
+class DenoiseOperation : public SingleThreadedOperation {
+ private:
+ /**
+ * \brief Cached reference to the input programs
+ */
+ SocketReader *m_inputProgramColor;
+ SocketReader *m_inputProgramAlbedo;
+ SocketReader *m_inputProgramNormal;
+
+ /**
+ * \brief settings of the denoise node.
+ */
+ NodeDenoise *m_settings;
+
+ public:
+ DenoiseOperation();
+ /**
+ * Initialize the execution
+ */
+ void initExecution();
+
+ /**
+ * Deinitialize the execution
+ */
+ void deinitExecution();
+
+ void setDenoiseSettings(NodeDenoise *settings)
+ {
+ this->m_settings = settings;
+ }
+ bool determineDependingAreaOfInterest(rcti *input,
+ ReadBufferOperation *readOperation,
+ rcti *output);
+
+ protected:
+ void generateDenoise(float *data,
+ MemoryBuffer *inputTileColor,
+ MemoryBuffer *inputTileAlbedo,
+ MemoryBuffer *inputTileNormal,
+ NodeDenoise *settings);
+
+ MemoryBuffer *createMemoryBuffer(rcti *rect);
+};
+#endif
diff --git a/source/blender/compositor/operations/COM_GlareGhostOperation.cpp b/source/blender/compositor/operations/COM_GlareGhostOperation.cpp
index 944a1d9c5dc..9f01cf5d63a 100644
--- a/source/blender/compositor/operations/COM_GlareGhostOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareGhostOperation.cpp
@@ -51,7 +51,7 @@ void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, No
if (!breaked) {
FastGaussianBlurOperation::IIR_gauss(tbuf1, s1, 1, 3);
}
- if (isBreaked()) {
+ if (isBraked()) {
breaked = true;
}
if (!breaked) {
@@ -60,19 +60,19 @@ void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, No
MemoryBuffer *tbuf2 = tbuf1->duplicate();
- if (isBreaked()) {
+ if (isBraked()) {
breaked = true;
}
if (!breaked) {
FastGaussianBlurOperation::IIR_gauss(tbuf2, s2, 0, 3);
}
- if (isBreaked()) {
+ if (isBraked()) {
breaked = true;
}
if (!breaked) {
FastGaussianBlurOperation::IIR_gauss(tbuf2, s2, 1, 3);
}
- if (isBreaked()) {
+ if (isBraked()) {
breaked = true;
}
if (!breaked) {
@@ -117,7 +117,7 @@ void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, No
gbuf->writePixel(x, y, c);
}
- if (isBreaked()) {
+ if (isBraked()) {
breaked = true;
}
}
@@ -142,7 +142,7 @@ void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, No
}
tbuf1->addPixel(x, y, tc);
}
- if (isBreaked()) {
+ if (isBraked()) {
breaked = true;
}
}
diff --git a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp
index 1ceeba18960..75c2ae51bde 100644
--- a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp
@@ -58,7 +58,7 @@ void GlareSimpleStarOperation::generateGlare(float *data,
c[3] = 1.0f;
tbuf2->writePixel(x, y, c);
}
- if (isBreaked()) {
+ if (isBraked()) {
breaked = true;
}
}
@@ -87,7 +87,7 @@ void GlareSimpleStarOperation::generateGlare(float *data,
c[3] = 1.0f;
tbuf2->writePixel(x, y, c);
}
- if (isBreaked()) {
+ if (isBraked()) {
breaked = true;
}
}
diff --git a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp b/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
index 78ca373faaf..951dec9281e 100644
--- a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
@@ -78,7 +78,7 @@ void GlareStreaksOperation::generateGlare(float *data,
tdstcol[2] = 0.5f * (tdstcol[2] + c1[2] + wt * (c2[2] + wt * (c3[2] + wt * c4[2])));
tdstcol[3] = 1.0f;
}
- if (isBreaked()) {
+ if (isBraked()) {
breaked = true;
}
}
diff --git a/source/blender/compositor/operations/COM_MaskOperation.cpp b/source/blender/compositor/operations/COM_MaskOperation.cpp
index 0c9208fb6bb..88a3a5c535c 100644
--- a/source/blender/compositor/operations/COM_MaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_MaskOperation.cpp
@@ -148,7 +148,7 @@ void MaskOperation::executePixelSampled(float output[4],
}
}
else {
- /* incase loop below fails */
+ /* In case loop below fails. */
output[0] = 0.0f;
for (unsigned int i = 0; i < this->m_rasterMaskHandleTot; i++) {
diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cpp b/source/blender/compositor/operations/COM_ViewerOperation.cpp
index d5b9edae719..3f7619523e3 100644
--- a/source/blender/compositor/operations/COM_ViewerOperation.cpp
+++ b/source/blender/compositor/operations/COM_ViewerOperation.cpp
@@ -111,7 +111,7 @@ void ViewerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
offset++;
offset4 += 4;
}
- if (isBreaked()) {
+ if (isBraked()) {
breaked = true;
}
offset += offsetadd;
diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp b/source/blender/compositor/operations/COM_WriteBufferOperation.cpp
index beba29e6755..6c5e45472a8 100644
--- a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp
+++ b/source/blender/compositor/operations/COM_WriteBufferOperation.cpp
@@ -76,7 +76,7 @@ void WriteBufferOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/
this->m_input->read(&(buffer[offset4]), x, y, data);
offset4 += num_channels;
}
- if (isBreaked()) {
+ if (isBraked()) {
breaked = true;
}
}
@@ -100,7 +100,7 @@ void WriteBufferOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/
this->m_input->readSampled(&(buffer[offset4]), x, y, COM_PS_NEAREST);
offset4 += num_channels;
}
- if (isBreaked()) {
+ if (isBraked()) {
breaked = true;
}
}
@@ -119,7 +119,7 @@ void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice *device,
/*
* 1. create cl_mem from outputbuffer
* 2. call NodeOperation (input) executeOpenCLChunk(.....)
- * 3. schedule readback from opencl to main device (outputbuffer)
+ * 3. schedule read back from opencl to main device (outputbuffer)
* 4. schedule native callback
*
* note: list of cl_mem will be filled by 2, and needs to be cleaned up by 4
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 986f65df3fc..fd4c1e251e4 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -944,8 +944,9 @@ void DepsgraphNodeBuilder::build_driver_id_property(ID *id, const char *rna_path
}
PointerRNA id_ptr, ptr;
PropertyRNA *prop;
+ int index;
RNA_id_pointer_create(id, &id_ptr);
- if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, NULL)) {
+ if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, &index)) {
return;
}
if (prop == NULL) {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 0e608bdf903..3c226338bfd 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -531,7 +531,7 @@ void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_coll
/* If we came from layer collection we don't go deeper, view layer
* builder takes care of going deeper.
*
- * NOTE: Do early output before tagging build as done, so possbile
+ * NOTE: Do early output before tagging build as done, so possible
* subsequent builds from outside of the layer collection properly
* recurses into all the nested objects and collections. */
return;
@@ -1531,8 +1531,9 @@ void DepsgraphRelationBuilder::build_driver_id_property(ID *id, const char *rna_
}
PointerRNA id_ptr, ptr;
PropertyRNA *prop;
+ int index;
RNA_id_pointer_create(id, &id_ptr);
- if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, NULL)) {
+ if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, &index)) {
return;
}
if (prop == NULL) {
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index 392514990e3..b73a3c08e10 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -638,7 +638,7 @@ void graph_id_tag_update(
* This way IDs in the undo steps will have this flag preserved, making it possible to restore
* all needed tags when new dependency graph is created on redo.
* This is the only way to ensure modifications to animation data (such as keyframes i.e.)
- * properly triggers animation update for the newely constructed dependency graph on redo (while
+ * properly triggers animation update for the newly constructed dependency graph on redo (while
* usually newly created dependency graph skips animation update to avoid loss of unkeyed
* changes). */
if (update_source == DEG_UPDATE_SOURCE_USER_EDIT) {
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
index 1f310957896..1f9c12f604d 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
@@ -1027,7 +1027,7 @@ class SceneBackup {
*
* NOTE: Scene can not disappear after relations update, because otherwise the entire dependency
* graph will be gone. This means we don't need to compare original scene pointer, or worry about
- * freeing those if they cant' be restorted: we just copy them over to a new scene. */
+ * freeing those if they cant' be restored: we just copy them over to a new scene. */
void *sound_scene;
void *playback_handle;
void *sound_scrub_handle;
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 27328084f31..1112a7a87db 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -52,6 +52,7 @@ set(SRC
intern/draw_anim_viz.c
intern/draw_armature.c
intern/draw_cache.c
+ intern/draw_cache_extract_mesh.c
intern/draw_cache_impl_curve.c
intern/draw_cache_impl_displist.c
intern/draw_cache_impl_lattice.c
@@ -69,6 +70,7 @@ set(SRC
intern/draw_manager_shader.c
intern/draw_manager_text.c
intern/draw_manager_texture.c
+ intern/draw_select_buffer.c
intern/draw_view.c
modes/edit_armature_mode.c
modes/edit_curve_mode.c
@@ -127,14 +129,14 @@ set(SRC
engines/gpencil/gpencil_engine.h
engines/gpencil/gpencil_render.c
engines/gpencil/gpencil_shader_fx.c
- engines/select/select_engine.c
engines/select/select_draw_utils.c
- engines/select/select_buffer.c
+ engines/select/select_engine.c
DRW_engine.h
DRW_select_buffer.h
intern/DRW_render.h
intern/draw_cache.h
+ intern/draw_cache_extract.h
intern/draw_cache_impl.h
intern/draw_cache_inline.h
intern/draw_common.h
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index 53cec599b82..58cf0c2a8e0 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -141,9 +141,7 @@ void DRW_draw_depth_object(struct ARegion *ar,
void DRW_draw_select_id(struct Depsgraph *depsgraph,
struct ARegion *ar,
struct View3D *v3d,
- struct Base **bases,
- const uint bases_len,
- short select_mode);
+ const struct rcti *rect);
/* grease pencil render */
bool DRW_render_check_grease_pencil(struct Depsgraph *depsgraph);
@@ -168,8 +166,8 @@ void DRW_opengl_context_disable_ex(bool restore);
void DRW_opengl_render_context_enable(void *re_gl_context);
void DRW_opengl_render_context_disable(void *re_gl_context);
-void DRW_gawain_render_context_enable(void *re_gpu_context);
-void DRW_gawain_render_context_disable(void *re_gpu_context);
+void DRW_gpu_render_context_enable(void *re_gpu_context);
+void DRW_gpu_render_context_disable(void *re_gpu_context);
void DRW_deferred_shader_remove(struct GPUMaterial *mat);
diff --git a/source/blender/draw/DRW_select_buffer.h b/source/blender/draw/DRW_select_buffer.h
index cc3cb94175a..4aa1c403710 100644
--- a/source/blender/draw/DRW_select_buffer.h
+++ b/source/blender/draw/DRW_select_buffer.h
@@ -33,33 +33,105 @@ struct View3D;
struct ViewLayer;
struct rcti;
-/* select_buffer.c */
-void DRW_select_buffer_context_create(struct Base **bases,
- const uint bases_len,
- short select_mode);
+typedef struct SELECTID_ObjectData {
+ DrawData dd;
+
+ uint drawn_index;
+ bool is_drawn;
+} SELECTID_ObjectData;
+
+struct ObjectOffsets {
+ /* For convenience only. */
+ union {
+ uint offset;
+ uint face_start;
+ };
+ union {
+ uint face;
+ uint edge_start;
+ };
+ union {
+ uint edge;
+ uint vert_start;
+ };
+ uint vert;
+};
+
+struct SELECTID_Context {
+ struct GPUFrameBuffer *framebuffer_select_id;
+ struct GPUTexture *texture_u32;
+
+ /* All context objects */
+ struct Object **objects;
+ uint objects_len;
+
+ /* Array with only drawn objects. When a new object is found within the rect,
+ * it is added to the end of the list.
+ * The list is reset to any viewport or context update. */
+ struct ObjectOffsets *index_offsets;
+ struct Object **objects_drawn;
+ uint objects_drawn_len;
+
+ /** Total number of element indices `index_offsets[object_drawn_len - 1].vert`. */
+ uint index_drawn_len;
+
+ short select_mode;
+
+ /* To check for updates. */
+ float persmat[4][4];
+ bool is_dirty;
+
+ /* rect is used to check which objects whose indexes need to be drawn. */
+ rcti last_rect;
+};
+
+/* draw_select_buffer.c */
bool DRW_select_buffer_elem_get(const uint sel_id,
uint *r_elem,
uint *r_base_index,
char *r_elem_type);
-uint DRW_select_buffer_context_offset_for_object_elem(const uint base_index, char elem_type);
-uint *DRW_select_buffer_read(const struct rcti *rect, uint *r_buf_len);
-void DRW_draw_select_id_object(struct Depsgraph *depsgraph,
- struct ViewLayer *view_layer,
- struct ARegion *ar,
- struct View3D *v3d,
- struct Object *ob,
- short select_mode);
-uint *DRW_select_buffer_bitmap_from_rect(const struct rcti *rect, uint *r_bitmap_len);
-uint *DRW_select_buffer_bitmap_from_circle(const int center[2],
+uint DRW_select_buffer_context_offset_for_object_elem(struct Depsgraph *depsgraph,
+ struct Object *object,
+ char elem_type);
+uint *DRW_select_buffer_read(struct Depsgraph *depsgraph,
+ struct ARegion *ar,
+ struct View3D *v3d,
+ const rcti *rect,
+ uint *r_buf_len);
+uint *DRW_select_buffer_bitmap_from_rect(struct Depsgraph *depsgraph,
+ struct ARegion *ar,
+ struct View3D *v3d,
+ const struct rcti *rect,
+ uint *r_bitmap_len);
+uint *DRW_select_buffer_bitmap_from_circle(struct Depsgraph *depsgraph,
+ struct ARegion *ar,
+ struct View3D *v3d,
+ const int center[2],
const int radius,
uint *r_bitmap_len);
-uint *DRW_select_buffer_bitmap_from_poly(const int poly[][2],
+uint *DRW_select_buffer_bitmap_from_poly(struct Depsgraph *depsgraph,
+ struct ARegion *ar,
+ struct View3D *v3d,
+ const int poly[][2],
const int poly_len,
- const struct rcti *rect);
-uint DRW_select_buffer_sample_point(const int center[2]);
-uint DRW_select_buffer_find_nearest_to_point(const int center[2],
+ const struct rcti *rect,
+ uint *r_bitmap_len);
+uint DRW_select_buffer_sample_point(struct Depsgraph *depsgraph,
+ struct ARegion *ar,
+ struct View3D *v3d,
+ const int center[2]);
+uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph,
+ struct ARegion *ar,
+ struct View3D *v3d,
+ const int center[2],
const uint id_min,
const uint id_max,
uint *dist);
+void DRW_select_buffer_context_create(struct Base **bases,
+ const uint bases_len,
+ short select_mode);
+
+/* select_engine.c */
+struct SELECTID_Context *DRW_select_engine_context_get(void);
#endif /* __DRW_SELECT_BUFFER_H__ */
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c
index 93521c71127..0ca1e0b2858 100644
--- a/source/blender/draw/engines/eevee/eevee_effects.c
+++ b/source/blender/draw/engines/eevee/eevee_effects.c
@@ -509,7 +509,7 @@ void EEVEE_downsample_buffer(EEVEE_Data *vedata, GPUTexture *texture_src, int le
}
/**
- * Simple downsampling algorithm for cubemap. Reconstruct mip chain up to mip level.
+ * Simple down-sampling algorithm for cubemap. Reconstruct mip chain up to mip level.
*/
void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, GPUTexture *texture_src, int level)
{
@@ -580,7 +580,7 @@ void EEVEE_draw_effects(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
/* NOTE: Lookdev drawing happens before TAA but after
* motion blur and dof to avoid distortions.
* Velocity resolve use a hack to exclude lookdev
- * spheres from creating shimering reprojection vectors. */
+ * spheres from creating shimmering re-projection vectors. */
EEVEE_lookdev_draw(vedata);
EEVEE_velocity_resolve(vedata);
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index b36ad540ef9..ab4eb7b8532 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -295,7 +295,13 @@ static void eevee_draw_background(void *vedata)
EEVEE_volumes_resolve(sldata, vedata);
/* Transparent */
+ /* TODO(fclem): should be its own Framebuffer.
+ * This is needed because dualsource blending only works with 1 color buffer. */
+ GPU_framebuffer_texture_attach(fbl->main_color_fb, dtxl->depth, 0, 0);
+ GPU_framebuffer_bind(fbl->main_color_fb);
DRW_draw_pass(psl->transparent_pass);
+ GPU_framebuffer_bind(fbl->main_fb);
+ GPU_framebuffer_texture_detach(fbl->main_color_fb, dtxl->depth);
/* Post Process */
DRW_stats_group_start("Post FX");
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c
index c82a112b343..275e185a0e4 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.c
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.c
@@ -80,8 +80,8 @@ extern void DRW_opengl_context_disable(void);
extern void DRW_opengl_render_context_enable(void *re_gl_context);
extern void DRW_opengl_render_context_disable(void *re_gl_context);
-extern void DRW_gawain_render_context_enable(void *re_gpu_context);
-extern void DRW_gawain_render_context_disable(void *re_gpu_context);
+extern void DRW_gpu_render_context_enable(void *re_gpu_context);
+extern void DRW_gpu_render_context_disable(void *re_gpu_context);
typedef struct EEVEE_LightBake {
Depsgraph *depsgraph;
@@ -412,7 +412,7 @@ static void eevee_lightbake_context_enable(EEVEE_LightBake *lbake)
if (lbake->gpu_context == NULL) {
lbake->gpu_context = GPU_context_create(0);
}
- DRW_gawain_render_context_enable(lbake->gpu_context);
+ DRW_gpu_render_context_enable(lbake->gpu_context);
}
else {
DRW_opengl_context_enable();
@@ -422,7 +422,7 @@ static void eevee_lightbake_context_enable(EEVEE_LightBake *lbake)
static void eevee_lightbake_context_disable(EEVEE_LightBake *lbake)
{
if (lbake->gl_context) {
- DRW_gawain_render_context_disable(lbake->gpu_context);
+ DRW_gpu_render_context_disable(lbake->gpu_context);
DRW_opengl_render_context_disable(lbake->gl_context);
}
else {
@@ -654,7 +654,7 @@ static void eevee_lightbake_delete_resources(EEVEE_LightBake *lbake)
if (lbake->gl_context) {
DRW_opengl_render_context_enable(lbake->gl_context);
- DRW_gawain_render_context_enable(lbake->gpu_context);
+ DRW_gpu_render_context_enable(lbake->gpu_context);
}
else if (!lbake->resource_only) {
DRW_opengl_context_enable();
@@ -675,8 +675,8 @@ static void eevee_lightbake_delete_resources(EEVEE_LightBake *lbake)
}
if (lbake->gpu_context) {
- DRW_gawain_render_context_disable(lbake->gpu_context);
- DRW_gawain_render_context_enable(lbake->gpu_context);
+ DRW_gpu_render_context_disable(lbake->gpu_context);
+ DRW_gpu_render_context_enable(lbake->gpu_context);
GPU_context_discard(lbake->gpu_context);
}
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
index 2026b44fe87..8b1309e8537 100644
--- a/source/blender/draw/engines/eevee/eevee_lightprobes.c
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -1213,7 +1213,7 @@ void EEVEE_lightbake_filter_visibility(EEVEE_ViewLayerData *sldata,
DRW_draw_pass(psl->probe_visibility_compute);
}
-/* Actually a simple downsampling */
+/* Actually a simple down-sampling. */
static void downsample_planar(void *vedata, int level)
{
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c
index d23287264b3..0bfc23b8354 100644
--- a/source/blender/draw/engines/eevee/eevee_lights.c
+++ b/source/blender/draw/engines/eevee/eevee_lights.c
@@ -779,7 +779,7 @@ static void eevee_light_setup(Object *ob, EEVEE_Light *evli)
/**
* Special ball distribution:
- * Point are distributed in a way that when they are orthogonaly
+ * 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.
*/
@@ -1166,9 +1166,8 @@ static void eevee_shadow_cascade_setup(Object *ob,
/* Compute offset. */
sub_v2_v2(shadow_texco, shadow_origin);
- mul_v2_fl(shadow_texco,
- (2.0f * sh_data->radius[c]) /
- linfo->shadow_cascade_size); /* Texture to light space. */
+ /* 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);
diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c
index e6e699bef10..f52fcf31267 100644
--- a/source/blender/draw/engines/eevee/eevee_lookdev.c
+++ b/source/blender/draw/engines/eevee/eevee_lookdev.c
@@ -75,22 +75,21 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata,
if (LOOK_DEV_OVERLAY_ENABLED(v3d)) {
/* Viewport / Spheres size. */
- rcti rect;
- ED_region_visible_rect(draw_ctx->ar, &rect);
+ const rcti *rect = ED_region_visible_rect(draw_ctx->ar);
/* Make the viewport width scale the lookdev spheres a bit.
* Scale between 1000px and 2000px. */
const float viewport_scale = clamp_f(
- BLI_rcti_size_x(&rect) / (2000.0f * U.dpi_fac), 0.5f, 1.0f);
+ BLI_rcti_size_x(rect) / (2000.0f * U.dpi_fac), 0.5f, 1.0f);
const int sphere_size = U.lookdev_sphere_size * U.dpi_fac * viewport_scale;
- if (sphere_size != effects->sphere_size || rect.xmax != effects->anchor[0] ||
- rect.ymin != effects->anchor[1]) {
+ if (sphere_size != effects->sphere_size || rect->xmax != effects->anchor[0] ||
+ rect->ymin != effects->anchor[1]) {
/* If sphere size or anchor point moves, reset TAA to avoid ghosting issue.
* This needs to happen early because we are changing taa_current_sample. */
effects->sphere_size = sphere_size;
- effects->anchor[0] = rect.xmax;
- effects->anchor[1] = rect.ymin;
+ effects->anchor[0] = rect->xmax;
+ effects->anchor[1] = rect->ymin;
EEVEE_temporal_sampling_reset(vedata);
}
}
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 61da9e21cc8..738745f3072 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -382,11 +382,6 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp,
LightCache *lcache = vedata->stl->g_data->light_cache;
EEVEE_EffectsInfo *effects = vedata->stl->effects;
- if (ssr_id == NULL) {
- static int no_ssr = -1.0f;
- ssr_id = &no_ssr;
- }
-
DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo);
DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo);
DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo);
@@ -394,6 +389,8 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp,
DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo);
DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_int_copy(shgrp, "outputSssId", 1);
+
if (use_diffuse || use_glossy || use_refract) {
DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex);
DRW_shgroup_uniform_texture_ref(shgrp, "shadowCubeTexture", &sldata->shadow_cube_pool);
@@ -411,7 +408,7 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp,
}
if (use_glossy) {
DRW_shgroup_uniform_texture_ref(shgrp, "probePlanars", &vedata->txl->planar_pool);
- DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1);
+ DRW_shgroup_uniform_int_copy(shgrp, "outputSsrId", ssr_id ? *ssr_id : 0);
}
if (use_refract) {
DRW_shgroup_uniform_float_copy(
@@ -736,7 +733,6 @@ struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene,
Material *ma,
EEVEE_Data *vedata,
bool use_blend,
- bool use_multiply,
bool use_refract,
bool use_translucency,
int shadow_method)
@@ -746,7 +742,6 @@ struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene,
int options = VAR_MAT_MESH;
SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND);
- SET_FLAG_FROM_TEST(options, use_multiply, VAR_MAT_MULT);
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);
@@ -1191,15 +1186,11 @@ 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,
- false,
- use_ssrefract,
- use_translucency,
- linfo->shadow_method) :
- NULL;
+ *gpumat =
+ (use_gpumat) ?
+ EEVEE_material_mesh_get(
+ scene, ma, vedata, false, use_ssrefract, use_translucency, linfo->shadow_method) :
+ NULL;
*gpumat_depth = (use_gpumat) ? EEVEE_material_mesh_depth_get(
scene, ma, (ma->blend_method == MA_BM_HASHED), false) :
NULL;
@@ -1213,7 +1204,7 @@ static void material_opaque(Material *ma,
/* Shading */
*gpumat = EEVEE_material_mesh_get(
- scene, ma, vedata, false, false, use_ssrefract, use_translucency, linfo->shadow_method);
+ scene, ma, vedata, false, use_ssrefract, use_translucency, linfo->shadow_method);
eGPUMaterialStatus status_mat_surface = GPU_material_status(*gpumat);
@@ -1286,7 +1277,7 @@ static void material_opaque(Material *ma,
switch (status_mat_surface) {
case GPU_MAT_SUCCESS: {
- static int no_ssr = -1;
+ static int no_ssr = 0;
static int first_ssr = 1;
int *ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_ssrefract) ?
&first_ssr :
@@ -1426,22 +1417,16 @@ static void material_transparent(Material *ma,
static float half = 0.5f;
/* Shading */
- *gpumat = EEVEE_material_mesh_get(scene,
- ma,
- vedata,
- true,
- (ma->blend_method == MA_BM_MULTIPLY),
- use_ssrefract,
- false,
- linfo->shadow_method);
+ *gpumat = EEVEE_material_mesh_get(
+ scene, ma, vedata, true, use_ssrefract, false, linfo->shadow_method);
switch (GPU_material_status(*gpumat)) {
case GPU_MAT_SUCCESS: {
static int ssr_id = -1; /* TODO transparent SSR */
- bool use_blend = (ma->blend_method & MA_BM_BLEND) != 0;
*shgrp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass);
+ bool use_blend = true;
bool use_diffuse = GPU_material_flag_get(*gpumat, GPU_MATFLAG_DIFFUSE);
bool use_glossy = GPU_material_flag_get(*gpumat, GPU_MATFLAG_GLOSSY);
bool use_refract = GPU_material_flag_get(*gpumat, GPU_MATFLAG_REFRACT);
@@ -1487,27 +1472,12 @@ static void material_transparent(Material *ma,
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_ALPHA | DRW_STATE_BLEND_ADD | DRW_STATE_BLEND_MUL);
+ DRW_STATE_BLEND_CUSTOM);
- DRWState cur_state = DRW_STATE_WRITE_COLOR;
+ DRWState 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;
- switch (ma->blend_method) {
- case MA_BM_ADD:
- cur_state |= DRW_STATE_BLEND_ADD;
- break;
- case MA_BM_MULTIPLY:
- cur_state |= DRW_STATE_BLEND_MUL;
- break;
- case MA_BM_BLEND:
- cur_state |= DRW_STATE_BLEND_ALPHA;
- break;
- default:
- BLI_assert(0);
- break;
- }
-
/* Disable other blend modes and use the one we want. */
DRW_shgroup_state_disable(*shgrp, all_state);
DRW_shgroup_state_enable(*shgrp, cur_state);
@@ -1583,8 +1553,6 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
&shgrp_depth_array[i],
&shgrp_depth_clip_array[i]);
break;
- case MA_BM_ADD:
- case MA_BM_MULTIPLY:
case MA_BM_BLEND:
material_transparent(ma_array[i],
sldata,
diff --git a/source/blender/draw/engines/eevee/eevee_mist.c b/source/blender/draw/engines/eevee/eevee_mist.c
index 2e56b64bd50..7209651a1d4 100644
--- a/source/blender/draw/engines/eevee/eevee_mist.c
+++ b/source/blender/draw/engines/eevee/eevee_mist.c
@@ -66,8 +66,9 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
}
/* Create FrameBuffer. */
- DRW_texture_ensure_fullscreen_2d(
- &txl->mist_accum, GPU_R32F, 0); /* Should be enough precision for many samples. */
+
+ /* Should be enough precision for many samples. */
+ DRW_texture_ensure_fullscreen_2d(&txl->mist_accum, GPU_R32F, 0);
GPU_framebuffer_ensure_config(&fbl->mist_accum_fb,
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->mist_accum)});
diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c
index 49f62c6bf5e..924b3d3b19b 100644
--- a/source/blender/draw/engines/eevee/eevee_occlusion.c
+++ b/source/blender/draw/engines/eevee/eevee_occlusion.c
@@ -146,8 +146,8 @@ void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- DRW_texture_ensure_fullscreen_2d(
- &txl->ao_accum, GPU_R32F, 0); /* Should be enough precision for many samples. */
+ /* Should be enough precision for many samples. */
+ DRW_texture_ensure_fullscreen_2d(&txl->ao_accum, GPU_R32F, 0);
GPU_framebuffer_ensure_config(&fbl->ao_accum_fb,
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->ao_accum)});
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 8aeddc72316..27edd44075b 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -897,7 +897,6 @@ struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene,
Material *ma,
EEVEE_Data *vedata,
bool use_blend,
- bool use_multiply,
bool use_refract,
bool use_translucency,
int shadow_method);
diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c
index ebd13ef1cf5..f840fa23bd2 100644
--- a/source/blender/draw/engines/eevee/eevee_render.c
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -628,7 +628,11 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
/* Mist output */
EEVEE_mist_output_accumulate(sldata, vedata);
/* Transparent */
+ GPU_framebuffer_texture_attach(fbl->main_color_fb, dtxl->depth, 0, 0);
+ GPU_framebuffer_bind(fbl->main_color_fb);
DRW_draw_pass(psl->transparent_pass);
+ GPU_framebuffer_bind(fbl->main_fb);
+ GPU_framebuffer_texture_detach(fbl->main_color_fb, dtxl->depth);
/* Result Z */
eevee_render_result_z(rl, viewname, rect, vedata, sldata);
/* Post Process */
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 274269846bc..7f795eaac2b 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -164,6 +164,19 @@ float sum(vec4 v)
return dot(vec4(1.0), v);
}
+float avg(vec2 v)
+{
+ return dot(vec2(1.0 / 2.0), v);
+}
+float avg(vec3 v)
+{
+ return dot(vec3(1.0 / 3.0), v);
+}
+float avg(vec4 v)
+{
+ return dot(vec4(1.0 / 4.0), v);
+}
+
float saturate(float a)
{
return clamp(a, 0.0, 1.0);
@@ -716,6 +729,7 @@ float cone_cosine(float r)
}
/* --------- Closure ---------- */
+
#ifdef VOLUMETRICS
struct Closure {
@@ -725,6 +739,8 @@ struct Closure {
float anisotropy;
};
+Closure nodetree_exec(void); /* Prototype */
+
# define CLOSURE_DEFAULT Closure(vec3(0.0), vec3(0.0), vec3(0.0), 0.0)
Closure closure_mix(Closure cl1, Closure cl2, float fac)
@@ -758,7 +774,8 @@ Closure closure_emission(vec3 rgb)
struct Closure {
vec3 radiance;
- float opacity;
+ vec3 transmittance;
+ float holdout;
# ifdef USE_SSS
vec4 sss_data;
# ifdef USE_SSS_ALBEDO
@@ -767,110 +784,117 @@ struct Closure {
# endif
vec4 ssr_data;
vec2 ssr_normal;
- int ssr_id;
+ int flag;
};
-/* This is hacking ssr_id to tag transparent bsdf */
-# define TRANSPARENT_CLOSURE_FLAG -2
-# define REFRACT_CLOSURE_FLAG -3
-# define NO_SSR -999
+Closure nodetree_exec(void); /* Prototype */
+
+# define FLAG_TEST(flag, val) (((flag) & (val)) != 0)
+
+# define CLOSURE_SSR_FLAG 1
+# define CLOSURE_SSS_FLAG 2
+# define CLOSURE_HOLDOUT_FLAG 4
# ifdef USE_SSS
# ifdef USE_SSS_ALBEDO
# define CLOSURE_DEFAULT \
- Closure(vec3(0.0), 1.0, vec4(0.0), vec3(0.0), vec4(0.0), vec2(0.0), -1)
+ 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), 1.0, vec4(0.0), vec4(0.0), vec2(0.0), -1)
+# define CLOSURE_DEFAULT \
+ Closure(vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec4(0.0), vec2(0.0), 0)
# endif
# else
-# define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0, vec4(0.0), vec2(0.0), -1)
+# define CLOSURE_DEFAULT Closure(vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec2(0.0), 0)
# endif
-uniform int outputSsrId;
+uniform int outputSsrId = 1;
+uniform int outputSssId = 1;
-Closure closure_mix(Closure cl1, Closure cl2, float fac)
+void closure_load_ssr_data(
+ vec3 ssr_spec, float roughness, vec3 N, vec3 viewVec, int ssr_id, inout Closure cl)
{
- Closure cl;
+ /* Still encode to avoid artifacts in the SSR pass. */
+ vec3 vN = normalize(mat3(ViewMatrix) * N);
+ cl.ssr_normal = normal_encode(vN, viewVec);
+
+ if (ssr_id == outputSsrId) {
+ cl.ssr_data = vec4(ssr_spec, roughness);
+ cl.flag |= CLOSURE_SSR_FLAG;
+ }
+}
- if (cl1.ssr_id == TRANSPARENT_CLOSURE_FLAG) {
- cl.ssr_normal = cl2.ssr_normal;
- cl.ssr_data = cl2.ssr_data;
- cl.ssr_id = cl2.ssr_id;
# ifdef USE_SSS
- cl1.sss_data = cl2.sss_data;
+void closure_load_sss_data(float radius,
+ vec3 sss_radiance,
# ifdef USE_SSS_ALBEDO
- cl1.sss_albedo = cl2.sss_albedo;
+ vec3 sss_albedo,
# endif
-# endif
- }
- else if (cl2.ssr_id == TRANSPARENT_CLOSURE_FLAG) {
- cl.ssr_normal = cl1.ssr_normal;
- cl.ssr_data = cl1.ssr_data;
- cl.ssr_id = cl1.ssr_id;
-# ifdef USE_SSS
- cl2.sss_data = cl1.sss_data;
+ int sss_id,
+ inout Closure cl)
+{
+ if (sss_id == outputSssId) {
+ cl.sss_data = vec4(sss_radiance, radius);
# ifdef USE_SSS_ALBEDO
- cl2.sss_albedo = cl1.sss_albedo;
+ cl.sss_albedo = sss_albedo;
# endif
-# endif
- }
- else if (cl1.ssr_id == outputSsrId) {
- /* When mixing SSR don't blend roughness.
- *
- * It makes no sense to mix them really, so we take either one of them and
- * tone down its specularity (ssr_data.xyz) while keeping its roughness (ssr_data.w).
- */
- cl.ssr_data = mix(cl1.ssr_data.xyzw, vec4(vec3(0.0), cl1.ssr_data.w), fac);
- cl.ssr_normal = cl1.ssr_normal;
- cl.ssr_id = cl1.ssr_id;
+ cl.flag |= CLOSURE_SSS_FLAG;
}
else {
- cl.ssr_data = mix(vec4(vec3(0.0), cl2.ssr_data.w), cl2.ssr_data.xyzw, fac);
- cl.ssr_normal = cl2.ssr_normal;
- cl.ssr_id = cl2.ssr_id;
+ cl.radiance += sss_radiance;
+# ifdef USE_SSS_ALBEDO
+ cl.radiance += sss_radiance * sss_albedo;
+# endif
}
+}
+# endif
- cl.opacity = mix(cl1.opacity, cl2.opacity, fac);
- cl.radiance = mix(cl1.radiance * cl1.opacity, cl2.radiance * cl2.opacity, fac);
- cl.radiance /= max(1e-8, cl.opacity);
+Closure closure_mix(Closure cl1, Closure cl2, float fac)
+{
+ Closure cl;
+ cl.holdout = mix(cl1.holdout, cl2.holdout, fac);
+ cl.transmittance = mix(cl1.transmittance, cl2.transmittance, fac);
+ cl.radiance = mix(cl1.radiance, cl2.radiance, fac);
+ cl.flag = cl1.flag | cl2.flag;
+ cl.ssr_data = mix(cl1.ssr_data, cl2.ssr_data, fac);
+ bool use_cl1_ssr = FLAG_TEST(cl1.flag, CLOSURE_SSR_FLAG);
+ /* When mixing SSR don't blend roughness and normals but only specular (ssr_data.xyz).*/
+ cl.ssr_data.w = (use_cl1_ssr) ? cl1.ssr_data.w : cl2.ssr_data.w;
+ cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal;
# ifdef USE_SSS
- /* Apply Mix on input */
- cl1.sss_data.rgb *= 1.0 - fac;
- cl2.sss_data.rgb *= fac;
-
- /* Select biggest radius. */
- bool use_cl1 = (cl1.sss_data.a > cl2.sss_data.a);
- cl.sss_data = (use_cl1) ? cl1.sss_data : cl2.sss_data;
-
+ cl.sss_data = mix(cl1.sss_data, cl2.sss_data, 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
- /* TODO Find a solution to this. Dither? */
- cl.sss_albedo = (use_cl1) ? cl1.sss_albedo : cl2.sss_albedo;
- /* Add radiance that was supposed to be filtered but was rejected. */
- cl.radiance += (use_cl1) ? cl2.sss_data.rgb * cl2.sss_albedo : cl1.sss_data.rgb * cl1.sss_albedo;
-# else
- /* Add radiance that was supposed to be filtered but was rejected. */
- cl.radiance += (use_cl1) ? cl2.sss_data.rgb : cl1.sss_data.rgb;
+ cl.sss_albedo = (use_cl1_sss) ? cl1.sss_albedo : cl2.sss_albedo;
# endif
# endif
-
return cl;
}
Closure closure_add(Closure cl1, Closure cl2)
{
- Closure cl = (cl1.ssr_id == outputSsrId) ? cl1 : cl2;
+ Closure cl;
+ cl.transmittance = cl1.transmittance + cl2.transmittance;
cl.radiance = cl1.radiance + cl2.radiance;
+ cl.holdout = cl1.holdout + cl2.holdout;
+ cl.flag = cl1.flag | cl2.flag;
+ cl.ssr_data = cl1.ssr_data + cl2.ssr_data;
+ bool use_cl1_ssr = FLAG_TEST(cl1.flag, CLOSURE_SSR_FLAG);
+ /* When mixing SSR don't blend roughness and normals.*/
+ cl.ssr_data.w = (use_cl1_ssr) ? cl1.ssr_data.w : cl2.ssr_data.w;
+ cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal;
+
# ifdef USE_SSS
- cl.sss_data = (cl1.sss_data.a > 0.0) ? cl1.sss_data : cl2.sss_data;
- /* Add radiance that was supposed to be filtered but was rejected. */
- cl.radiance += (cl1.sss_data.a > 0.0) ? cl2.sss_data.rgb : cl1.sss_data.rgb;
+ cl.sss_data = cl1.sss_data + cl2.sss_data;
+ 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
- /* TODO Find a solution to this. Dither? */
- cl.sss_albedo = (cl1.sss_data.a > 0.0) ? cl1.sss_albedo : cl2.sss_albedo;
+ cl.sss_albedo = (use_cl1_sss) ? cl1.sss_albedo : cl2.sss_albedo;
# endif
# endif
- cl.opacity = saturate(cl1.opacity + cl2.opacity);
return cl;
}
@@ -883,19 +907,23 @@ Closure closure_emission(vec3 rgb)
/* Breaking this across multiple lines causes issues for some older GLSL compilers. */
/* clang-format off */
-# if defined(MESH_SHADER) && !defined(USE_ALPHA_HASH) && !defined(USE_ALPHA_CLIP) && !defined(SHADOW_SHADER) && !defined(USE_MULTIPLY)
+# if defined(MESH_SHADER) && !defined(USE_ALPHA_HASH) && !defined(USE_ALPHA_CLIP) && !defined(SHADOW_SHADER)
/* clang-format on */
-layout(location = 0) out vec4 fragColor;
-layout(location = 1) out vec4 ssrNormals;
+# ifndef USE_ALPHA_BLEND
+layout(location = 0) out vec4 outRadiance;
+layout(location = 1) out vec2 ssrNormals;
layout(location = 2) out vec4 ssrData;
-# ifdef USE_SSS
+# ifdef USE_SSS
layout(location = 3) out vec4 sssData;
-# ifdef USE_SSS_ALBEDO
+# ifdef USE_SSS_ALBEDO
layout(location = 4) out vec4 sssAlbedo;
-# endif /* USE_SSS_ALBEDO */
-# endif /* USE_SSS */
-
-Closure nodetree_exec(void); /* Prototype */
+# endif
+# endif
+# else /* USE_ALPHA_BLEND */
+/* Use dual source blending to be able to make a whole range of effects. */
+layout(location = 0, index = 0) out vec4 outRadiance;
+layout(location = 0, index = 1) out vec4 outTransmittance;
+# endif /* USE_ALPHA_BLEND */
# if defined(USE_ALPHA_BLEND)
/* Prototype because this file is included before volumetric_lib.glsl */
@@ -909,27 +937,26 @@ void volumetric_resolve(vec2 frag_uvs,
void main()
{
Closure cl = nodetree_exec();
-# ifndef USE_ALPHA_BLEND
- /* Prevent alpha hash material writing into alpha channel. */
- cl.opacity = 1.0;
-# endif
-# if defined(USE_ALPHA_BLEND)
+ float holdout = 1.0 - saturate(cl.holdout);
+
+# ifdef USE_ALPHA_BLEND
vec2 uvs = gl_FragCoord.xy * volCoordScale.zw;
- vec3 transmittance, scattering;
- volumetric_resolve(uvs, gl_FragCoord.z, transmittance, scattering);
- fragColor.rgb = cl.radiance * transmittance + scattering;
- fragColor.a = cl.opacity;
-# else
- fragColor = vec4(cl.radiance, cl.opacity);
-# endif
+ vec3 vol_transmit, vol_scatter;
+ volumetric_resolve(uvs, gl_FragCoord.z, vol_transmit, vol_scatter);
- ssrNormals = cl.ssr_normal.xyyy;
+ float transmit = saturate(avg(cl.transmittance));
+ outRadiance = vec4(cl.radiance * vol_transmit + vol_scatter, (1.0 - transmit) * holdout);
+ outTransmittance = vec4(cl.transmittance, transmit * holdout);
+# else
+ outRadiance = vec4(cl.radiance, holdout);
+ ssrNormals = cl.ssr_normal;
ssrData = cl.ssr_data;
-# ifdef USE_SSS
+# ifdef USE_SSS
sssData = cl.sss_data;
-# ifdef USE_SSS_ALBEDO
+# ifdef USE_SSS_ALBEDO
sssAlbedo = cl.sss_albedo.rgbb;
+# endif
# endif
# endif
@@ -945,9 +972,9 @@ void main()
# endif
# ifdef USE_SSS_ALBEDO
- fragColor.rgb += cl.sss_data.rgb * cl.sss_albedo.rgb * fac;
+ outRadiance.rgb += cl.sss_data.rgb * cl.sss_albedo.rgb * fac;
# else
- fragColor.rgb += cl.sss_data.rgb * fac;
+ outRadiance.rgb += cl.sss_data.rgb * fac;
# endif
# endif
}
@@ -955,18 +982,3 @@ void main()
# endif /* MESH_SHADER && !SHADOW_SHADER */
#endif /* VOLUMETRICS */
-
-Closure nodetree_exec(void); /* Prototype */
-
-/* TODO find a better place */
-#ifdef USE_MULTIPLY
-
-out vec4 fragColor;
-
-# define NODETREE_EXEC
-void main()
-{
- Closure cl = nodetree_exec();
- fragColor = vec4(mix(vec3(1.0), cl.radiance, cl.opacity), 1.0);
-}
-#endif
diff --git a/source/blender/draw/engines/eevee/shaders/default_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_frag.glsl
index 64a1c725a6b..1f60661d234 100644
--- a/source/blender/draw/engines/eevee/shaders/default_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/default_frag.glsl
@@ -33,15 +33,13 @@ Closure nodetree_exec(void)
vec3 out_diff, out_spec, ssr_spec;
eevee_closure_default(N, albedo, f0, f90, 1, roughness, 1.0, out_diff, out_spec, ssr_spec);
- Closure result = Closure(out_spec + out_diff * albedo,
- 1.0,
- vec4(ssr_spec, roughness),
- normal_encode(vN, viewCameraVec),
- 0);
+ Closure cl = CLOSURE_DEFAULT;
+ cl.radiance = out_spec + out_diff * albedo;
+ closure_load_ssr_data(ssr_spec, roughness, N, viewCameraVec, 1, cl);
#ifdef LOOKDEV
gl_FragDepth = 0.0;
#endif
- return result;
+ return cl;
}
diff --git a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
index 2d14f52d7e6..c3643cccbfc 100644
--- a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
@@ -393,8 +393,8 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale)
return vec3(0.0);
}
- float range = abs(data.sh_far -
- data.sh_near); /* Same factor as in get_cascade_world_distance(). */
+ /* 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;
diff --git a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
index e7b31b94f81..dea6bc020ec 100644
--- a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
@@ -71,14 +71,16 @@ void main()
Closure cl = nodetree_exec();
+ float opacity = saturate(1.0 - avg(cl.transmittance));
+
# if defined(USE_ALPHA_HASH)
/* Hashed Alpha Testing */
- if (cl.opacity < hashed_alpha_threshold(worldPosition)) {
+ if (opacity < hashed_alpha_threshold(worldPosition)) {
discard;
}
# elif defined(USE_ALPHA_CLIP)
/* Alpha clip */
- if (cl.opacity <= alphaThreshold) {
+ if (opacity <= alphaThreshold) {
discard;
}
# endif
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index 16162645f3d..efe67e1ead0 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -564,6 +564,8 @@ static void gpencil_add_draw_data(void *vedata, Object *ob)
GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
bGPdata *gpd = (bGPdata *)ob->data;
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const View3D *v3d = draw_ctx->v3d;
int i = stl->g_data->gp_cache_used - 1;
tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i];
@@ -580,7 +582,9 @@ static void gpencil_add_draw_data(void *vedata, Object *ob)
/* FX passses */
cache_ob->has_fx = false;
- if ((!stl->storage->simplify_fx) && (!ELEM(cache_ob->shading_type[0], OB_WIRE, OB_SOLID)) &&
+ if ((!stl->storage->simplify_fx) &&
+ ((!ELEM(cache_ob->shading_type[0], OB_WIRE, OB_SOLID)) ||
+ ((v3d->spacetype != SPACE_VIEW3D))) &&
(BKE_shaderfx_has_gpencil(ob))) {
cache_ob->has_fx = true;
if ((!stl->storage->simplify_fx) && (!is_multiedit)) {
diff --git a/source/blender/draw/engines/select/select_draw_utils.c b/source/blender/draw/engines/select/select_draw_utils.c
index c3ee7f962a1..f3b6d324f33 100644
--- a/source/blender/draw/engines/select/select_draw_utils.c
+++ b/source/blender/draw/engines/select/select_draw_utils.c
@@ -23,6 +23,8 @@
*/
#include "BKE_editmesh.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
@@ -32,6 +34,8 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
+#include "DRW_select_buffer.h"
+
#include "draw_cache_impl.h"
#include "select_private.h"
@@ -40,7 +44,7 @@
/** \name Draw Utilities
* \{ */
-void draw_select_framebuffer_select_id_setup(struct SELECTID_Context *select_ctx)
+static void select_id_framebuffer_setup(struct SELECTID_Context *select_ctx)
{
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
int size[2];
@@ -71,6 +75,32 @@ void draw_select_framebuffer_select_id_setup(struct SELECTID_Context *select_ctx
}
}
+/* Remove all tags from drawn or culled objects. */
+void select_id_context_clear(struct SELECTID_Context *select_ctx)
+{
+ select_ctx->objects_drawn_len = 0;
+ select_ctx->index_drawn_len = 1;
+ select_id_framebuffer_setup(select_ctx);
+ GPU_framebuffer_bind(select_ctx->framebuffer_select_id);
+ GPU_framebuffer_clear_color_depth(
+ select_ctx->framebuffer_select_id, (const float[4]){0.0f}, 1.0f);
+}
+
+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);
+ }
+ else {
+ bb = BKE_object_boundbox_get(obj);
+ }
+ copy_v3_v3(r_min, bb->vec[0]);
+ copy_v3_v3(r_max, bb->vec[6]);
+}
+
short select_id_get_object_select_mode(Scene *scene, Object *ob)
{
short r_select_mode = 0;
@@ -121,32 +151,33 @@ static void draw_select_id_edit_mesh(SELECTID_StorageList *stl,
BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE);
- struct GPUBatch *geom_faces;
- DRWShadingGroup *face_shgrp;
if (select_mode & SCE_SELECT_FACE) {
- geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me);
- face_shgrp = DRW_shgroup_create_sub(stl->g_data->shgrp_face_flat);
+ struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me);
+ DRWShadingGroup *face_shgrp = DRW_shgroup_create_sub(stl->g_data->shgrp_face_flat);
DRW_shgroup_uniform_int_copy(face_shgrp, "offset", *(int *)&initial_offset);
+ DRW_shgroup_call_no_cull(face_shgrp, geom_faces, ob);
if (draw_facedot) {
struct GPUBatch *geom_facedots = DRW_mesh_batch_cache_get_facedots_with_select_id(me);
- DRW_shgroup_call(face_shgrp, geom_facedots, ob);
+ DRW_shgroup_call_no_cull(face_shgrp, geom_facedots, ob);
}
*r_face_offset = initial_offset + em->bm->totface;
}
else {
- geom_faces = DRW_mesh_batch_cache_get_surface(me);
- face_shgrp = stl->g_data->shgrp_face_unif;
+ if (ob->dt >= OB_SOLID) {
+ struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_surface(me);
+ DRWShadingGroup *face_shgrp = stl->g_data->shgrp_face_unif;
+ DRW_shgroup_call_no_cull(face_shgrp, geom_faces, ob);
+ }
*r_face_offset = initial_offset;
}
- DRW_shgroup_call(face_shgrp, geom_faces, ob);
/* Unlike faces, only draw edges if edge select mode. */
if (select_mode & SCE_SELECT_EDGE) {
struct GPUBatch *geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(me);
DRWShadingGroup *edge_shgrp = DRW_shgroup_create_sub(stl->g_data->shgrp_edge);
DRW_shgroup_uniform_int_copy(edge_shgrp, "offset", *(int *)r_face_offset);
- DRW_shgroup_call(edge_shgrp, geom_edges, ob);
+ DRW_shgroup_call_no_cull(edge_shgrp, geom_edges, ob);
*r_edge_offset = *r_face_offset + em->bm->totedge;
}
else {
@@ -160,7 +191,7 @@ static void draw_select_id_edit_mesh(SELECTID_StorageList *stl,
struct GPUBatch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(me);
DRWShadingGroup *vert_shgrp = DRW_shgroup_create_sub(stl->g_data->shgrp_vert);
DRW_shgroup_uniform_int_copy(vert_shgrp, "offset", *(int *)r_edge_offset);
- DRW_shgroup_call(vert_shgrp, geom_verts, ob);
+ DRW_shgroup_call_no_cull(vert_shgrp, geom_verts, ob);
*r_vert_offset = *r_edge_offset + em->bm->totvert;
}
else {
@@ -190,13 +221,13 @@ static void draw_select_id_mesh(SELECTID_StorageList *stl,
face_shgrp = stl->g_data->shgrp_face_unif;
*r_face_offset = initial_offset;
}
- DRW_shgroup_call(face_shgrp, geom_faces, ob);
+ DRW_shgroup_call_no_cull(face_shgrp, geom_faces, ob);
if (select_mode & SCE_SELECT_EDGE) {
struct GPUBatch *geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(me);
DRWShadingGroup *edge_shgrp = DRW_shgroup_create_sub(stl->g_data->shgrp_edge);
DRW_shgroup_uniform_int_copy(edge_shgrp, "offset", *(int *)r_face_offset);
- DRW_shgroup_call(edge_shgrp, geom_edges, ob);
+ DRW_shgroup_call_no_cull(edge_shgrp, geom_edges, ob);
*r_edge_offset = *r_face_offset + me->totedge;
}
else {
@@ -207,7 +238,7 @@ static void draw_select_id_mesh(SELECTID_StorageList *stl,
struct GPUBatch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(me);
DRWShadingGroup *vert_shgrp = DRW_shgroup_create_sub(stl->g_data->shgrp_vert);
DRW_shgroup_uniform_int_copy(vert_shgrp, "offset", *r_edge_offset);
- DRW_shgroup_call(vert_shgrp, geom_verts, ob);
+ DRW_shgroup_call_no_cull(vert_shgrp, geom_verts, ob);
*r_vert_offset = *r_edge_offset + me->totvert;
}
else {
diff --git a/source/blender/draw/engines/select/select_engine.c b/source/blender/draw/engines/select/select_engine.c
index 3e4e4861f50..d0347891120 100644
--- a/source/blender/draw/engines/select/select_engine.c
+++ b/source/blender/draw/engines/select/select_engine.c
@@ -24,11 +24,13 @@
#include "DNA_screen_types.h"
-#include "GPU_shader.h"
-
#include "UI_resources.h"
#include "DRW_engine.h"
+#include "DRW_select_buffer.h"
+
+#include "draw_cache_impl.h"
+#include "draw_manager.h"
#include "select_private.h"
#include "select_engine.h"
@@ -40,6 +42,7 @@
static struct {
SELECTID_Shaders sh_data[GPU_SHADER_CFG_LEN];
struct SELECTID_Context context;
+ uint runtime_new_objects;
} e_data = {{{NULL}}}; /* Engine data */
/* Shaders */
@@ -89,8 +92,23 @@ static void select_engine_init(void *vedata)
}
{
+ /* Create view from a subregion */
+ const DRWView *view_default = DRW_view_default_get();
+ float viewmat[4][4], winmat[4][4], winmat_subregion[4][4];
+ DRW_view_viewmat_get(view_default, viewmat, false);
+ DRW_view_winmat_get(view_default, winmat, false);
+ projmat_from_subregion(winmat,
+ (int[2]){draw_ctx->ar->winx, draw_ctx->ar->winy},
+ e_data.context.last_rect.xmin,
+ e_data.context.last_rect.xmax,
+ e_data.context.last_rect.ymin,
+ e_data.context.last_rect.ymax,
+ winmat_subregion);
+
+ stl->g_data->view_subregion = DRW_view_create(viewmat, winmat_subregion, NULL, NULL, NULL);
+
/* Create view with depth offset */
- stl->g_data->view_faces = (DRWView *)DRW_view_default_get();
+ stl->g_data->view_faces = (DRWView *)view_default;
stl->g_data->view_edges = DRW_view_create_with_zoffset(draw_ctx->rv3d, 1.0f);
stl->g_data->view_verts = DRW_view_create_with_zoffset(draw_ctx->rv3d, 1.1f);
}
@@ -106,11 +124,19 @@ static void select_cache_init(void *vedata)
if (e_data.context.select_mode == -1) {
e_data.context.select_mode = select_id_get_object_select_mode(draw_ctx->scene,
- OBACT(draw_ctx->view_layer));
+ draw_ctx->obact);
BLI_assert(e_data.context.select_mode != 0);
}
{
+ psl->depth_only_pass = DRW_pass_create("Depth Only Pass", DRW_STATE_DEFAULT);
+ stl->g_data->shgrp_depth_only = DRW_shgroup_create(sh_data->select_id_uniform,
+ psl->depth_only_pass);
+
+ if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
+ DRW_shgroup_state_enable(stl->g_data->shgrp_depth_only, DRW_STATE_CLIP_PLANES);
+ }
+
psl->select_id_face_pass = DRW_pass_create("Face Pass", DRW_STATE_DEFAULT);
if (e_data.context.select_mode & SCE_SELECT_FACE) {
@@ -156,28 +182,82 @@ static void select_cache_init(void *vedata)
}
}
- e_data.context.last_object_drawn = 0;
- e_data.context.last_index_drawn = 1;
+ /* Check if the viewport has changed. */
+ float(*persmat)[4] = draw_ctx->rv3d->persmat;
+ e_data.context.is_dirty = !compare_m4m4(e_data.context.persmat, persmat, FLT_EPSILON);
+ if (e_data.context.is_dirty) {
+ copy_m4_m4(e_data.context.persmat, persmat);
+ select_id_context_clear(&e_data.context);
+ }
+ e_data.runtime_new_objects = 0;
}
static void select_cache_populate(void *vedata, Object *ob)
{
+ SELECTID_StorageList *stl = ((SELECTID_Data *)vedata)->stl;
const DRWContextState *draw_ctx = DRW_context_state_get();
- struct BaseOffset *base_ofs = &e_data.context.index_offsets[e_data.context.last_object_drawn++];
- uint offset = e_data.context.last_index_drawn;
+ SELECTID_ObjectData *sel_data = (SELECTID_ObjectData *)DRW_drawdata_get(
+ &ob->id, &draw_engine_select_type);
+
+ if (!e_data.context.is_dirty && sel_data && sel_data->is_drawn) {
+ /* The object indices have already been drawn. Fill depth pass.
+ * Opti: Most of the time this depth pass is not used. */
+ struct Mesh *me = ob->data;
+ if (e_data.context.select_mode & SCE_SELECT_FACE) {
+ struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me);
+ DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_faces, ob->obmat);
+ }
+ else if (ob->dt >= OB_SOLID) {
+ struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_surface(me);
+ DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_faces, ob->obmat);
+ }
+
+ if (e_data.context.select_mode & SCE_SELECT_EDGE) {
+ struct GPUBatch *geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(me);
+ DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_edges, ob->obmat);
+ }
+
+ if (e_data.context.select_mode & SCE_SELECT_VERTEX) {
+ struct GPUBatch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(me);
+ DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_verts, ob->obmat);
+ }
+ return;
+ }
- select_id_draw_object(vedata,
- draw_ctx->v3d,
- ob,
- e_data.context.select_mode,
- offset,
- &base_ofs->vert,
- &base_ofs->edge,
- &base_ofs->face);
+ float min[3], max[3];
+ select_id_object_min_max(ob, min, max);
- base_ofs->offset = offset;
- e_data.context.last_index_drawn = base_ofs->vert;
+ if (DRW_culling_min_max_test(stl->g_data->view_subregion, ob->obmat, min, max)) {
+ if (sel_data == NULL) {
+ sel_data = (SELECTID_ObjectData *)DRW_drawdata_ensure(
+ &ob->id, &draw_engine_select_type, sizeof(SELECTID_ObjectData), NULL, NULL);
+ }
+ sel_data->drawn_index = e_data.context.objects_drawn_len;
+ sel_data->is_drawn = true;
+
+ struct ObjectOffsets *ob_offsets =
+ &e_data.context.index_offsets[e_data.context.objects_drawn_len];
+
+ uint offset = e_data.context.index_drawn_len;
+ select_id_draw_object(vedata,
+ draw_ctx->v3d,
+ ob,
+ e_data.context.select_mode,
+ offset,
+ &ob_offsets->vert,
+ &ob_offsets->edge,
+ &ob_offsets->face);
+
+ ob_offsets->offset = offset;
+ e_data.context.index_drawn_len = ob_offsets->vert;
+ e_data.context.objects_drawn[e_data.context.objects_drawn_len] = ob;
+ e_data.context.objects_drawn_len++;
+ e_data.runtime_new_objects++;
+ }
+ else if (sel_data) {
+ sel_data->is_drawn = false;
+ }
}
static void select_draw_scene(void *vedata)
@@ -185,17 +265,26 @@ static void select_draw_scene(void *vedata)
SELECTID_StorageList *stl = ((SELECTID_Data *)vedata)->stl;
SELECTID_PassList *psl = ((SELECTID_Data *)vedata)->psl;
- /* Setup framebuffer */
- draw_select_framebuffer_select_id_setup(&e_data.context);
- GPU_framebuffer_bind(e_data.context.framebuffer_select_id);
+ if (!e_data.runtime_new_objects) {
+ /* Nothing new needs to be drawn. */
+ return;
+ }
/* dithering and AA break color coding, so disable */
glDisable(GL_DITHER);
- GPU_framebuffer_clear_color_depth(
- e_data.context.framebuffer_select_id, (const float[4]){0.0f}, 1.0f);
-
DRW_view_set_active(stl->g_data->view_faces);
+
+ if (!DRW_pass_is_empty(psl->depth_only_pass)) {
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ GPU_framebuffer_bind(dfbl->depth_only_fb);
+ GPU_framebuffer_clear_depth(dfbl->depth_only_fb, 1.0f);
+ DRW_draw_pass(psl->depth_only_pass);
+ }
+
+ /* Setup framebuffer */
+ GPU_framebuffer_bind(e_data.context.framebuffer_select_id);
+
DRW_draw_pass(psl->select_id_face_pass);
if (e_data.context.select_mode & SCE_SELECT_EDGE) {
@@ -219,7 +308,9 @@ static void select_engine_free(void)
DRW_TEXTURE_FREE_SAFE(e_data.context.texture_u32);
GPU_FRAMEBUFFER_FREE_SAFE(e_data.context.framebuffer_select_id);
+ MEM_SAFE_FREE(e_data.context.objects);
MEM_SAFE_FREE(e_data.context.index_offsets);
+ MEM_SAFE_FREE(e_data.context.objects_drawn);
}
/** \} */
@@ -272,7 +363,7 @@ RenderEngineType DRW_engine_viewport_select_type = {
/** \name Exposed `select_private.h` functions
* \{ */
-struct SELECTID_Context *select_context_get(void)
+struct SELECTID_Context *DRW_select_engine_context_get(void)
{
return &e_data.context;
}
diff --git a/source/blender/draw/engines/select/select_private.h b/source/blender/draw/engines/select/select_private.h
index 2104f1485e7..e48ce4314ae 100644
--- a/source/blender/draw/engines/select/select_private.h
+++ b/source/blender/draw/engines/select/select_private.h
@@ -32,6 +32,7 @@ typedef struct SELECTID_StorageList {
} SELECTID_StorageList;
typedef struct SELECTID_PassList {
+ struct DRWPass *depth_only_pass;
struct DRWPass *select_id_face_pass;
struct DRWPass *select_id_edge_pass;
struct DRWPass *select_id_vert_pass;
@@ -52,51 +53,21 @@ typedef struct SELECTID_Shaders {
} SELECTID_Shaders;
typedef struct SELECTID_PrivateData {
+ DRWShadingGroup *shgrp_depth_only;
DRWShadingGroup *shgrp_face_unif;
DRWShadingGroup *shgrp_face_flat;
DRWShadingGroup *shgrp_edge;
DRWShadingGroup *shgrp_vert;
+ DRWView *view_subregion;
DRWView *view_faces;
DRWView *view_edges;
DRWView *view_verts;
} SELECTID_PrivateData; /* Transient data */
-struct BaseOffset {
- /* For convenience only. */
- union {
- uint offset;
- uint face_start;
- };
- union {
- uint face;
- uint edge_start;
- };
- union {
- uint edge;
- uint vert_start;
- };
- uint vert;
-};
-
-struct SELECTID_Context {
- struct GPUFrameBuffer *framebuffer_select_id;
- struct GPUTexture *texture_u32;
-
- struct BaseOffset *index_offsets;
- uint objects_len;
- uint last_object_drawn;
- /** Total number of items `base_array_index_offsets[bases_len - 1].vert`. */
- uint last_index_drawn;
-
- short select_mode;
-};
-
-/* select_engine.c */
-struct SELECTID_Context *select_context_get(void);
-
/* select_draw_utils.c */
-void draw_select_framebuffer_select_id_setup(struct SELECTID_Context *r_select_ctx);
+void select_id_context_clear(struct SELECTID_Context *select_ctx);
+void select_id_object_min_max(struct Object *obj, float r_min[3], float r_max[3]);
short select_id_get_object_select_mode(Scene *scene, Object *ob);
void select_id_draw_object(void *vedata,
View3D *v3d,
diff --git a/source/blender/draw/engines/workbench/workbench_studiolight.c b/source/blender/draw/engines/workbench/workbench_studiolight.c
index 944bca73993..1a09498b228 100644
--- a/source/blender/draw/engines/workbench/workbench_studiolight.c
+++ b/source/blender/draw/engines/workbench/workbench_studiolight.c
@@ -82,8 +82,9 @@ void studiolight_update_world(WORKBENCH_PrivateData *wpd,
-sl->spherical_harmonics_coefs[3][i],
sl->spherical_harmonics_coefs[2][i],
-sl->spherical_harmonics_coefs[1][i]);
- mul_v3_fl(wd->spherical_harmonics_coefs[i + 1],
- M_1_PI * 1.5f); /* 1.5f is to improve the contrast a bit. */
+
+ /* 1.5f is to improve the contrast a bit. */
+ mul_v3_fl(wd->spherical_harmonics_coefs[i + 1], M_1_PI * 1.5f);
}
/* Precompute as much as we can. See shader code for derivation. */
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index a8f67e10a4d..3379aa28d0f 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -597,6 +597,7 @@ bool DRW_view_is_persp_get(const DRWView *view);
bool DRW_culling_sphere_test(const DRWView *view, const BoundSphere *bsphere);
bool DRW_culling_box_test(const DRWView *view, const BoundBox *bbox);
bool DRW_culling_plane_test(const DRWView *view, const float plane[4]);
+bool DRW_culling_min_max_test(const DRWView *view, float obmat[4][4], float min[3], float max[3]);
void DRW_culling_frustum_corners_get(const DRWView *view, BoundBox *corners);
void DRW_culling_frustum_planes_get(const DRWView *view, float planes[6][4]);
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index e2e98a2db5a..520932bc429 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -4001,7 +4001,7 @@ GPUBatch *DRW_cache_cursor_get(bool crosshair_lines)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Batch Cache Impl. common
+/** \name Batch Cache Implementation (common)
* \{ */
void drw_batch_cache_validate(Object *ob)
@@ -4033,7 +4033,7 @@ void drw_batch_cache_validate(Object *ob)
void drw_batch_cache_generate_requested(Object *ob)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
- const ToolSettings *ts = draw_ctx->scene->toolsettings;
+ const Scene *scene = draw_ctx->scene;
const enum eContextObjectMode mode = CTX_data_mode_enum_ex(
draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode);
const bool is_paint_mode = ELEM(
@@ -4047,13 +4047,13 @@ void drw_batch_cache_generate_requested(Object *ob)
struct Mesh *mesh_eval = ob->runtime.mesh_eval;
switch (ob->type) {
case OB_MESH:
- DRW_mesh_batch_cache_create_requested(ob, (Mesh *)ob->data, ts, is_paint_mode, use_hide);
+ DRW_mesh_batch_cache_create_requested(ob, (Mesh *)ob->data, scene, is_paint_mode, use_hide);
break;
case OB_CURVE:
case OB_FONT:
case OB_SURF:
if (mesh_eval) {
- DRW_mesh_batch_cache_create_requested(ob, mesh_eval, ts, is_paint_mode, use_hide);
+ DRW_mesh_batch_cache_create_requested(ob, mesh_eval, scene, is_paint_mode, use_hide);
}
DRW_curve_batch_cache_create_requested(ob);
break;
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
index 129b180957a..5dadcdc1457 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -27,6 +27,7 @@ struct GPUBatch;
struct GPUMaterial;
struct ModifierData;
struct Object;
+struct ParticleSystem;
struct PTCacheEdit;
void DRW_shape_cache_free(void);
@@ -58,7 +59,7 @@ struct GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob,
char **auto_layer_names,
int **auto_layer_is_srgb,
int *auto_layer_count);
-struct GPUBatch *DRW_cache_object_face_wireframe_get(Object *ob);
+struct GPUBatch *DRW_cache_object_face_wireframe_get(struct Object *ob);
/* Empties */
struct GPUBatch *DRW_cache_plain_axes_get(void);
@@ -152,7 +153,7 @@ struct GPUBatch **DRW_cache_curve_surface_shaded_get(struct Object *ob,
uint gpumat_array_len);
struct GPUBatch *DRW_cache_curve_loose_edges_get(struct Object *ob);
struct GPUBatch *DRW_cache_curve_edge_wire_get(struct Object *ob);
-struct GPUBatch *DRW_cache_curve_face_wireframe_get(Object *ob);
+struct GPUBatch *DRW_cache_curve_face_wireframe_get(struct Object *ob);
struct GPUBatch *DRW_cache_curve_edge_detection_get(struct Object *ob, bool *r_is_manifold);
/* edit-mode */
struct GPUBatch *DRW_cache_curve_edge_normal_get(struct Object *ob);
@@ -161,13 +162,13 @@ struct GPUBatch *DRW_cache_curve_vert_overlay_get(struct Object *ob, bool handle
/* Font */
struct GPUBatch *DRW_cache_text_surface_get(struct Object *ob);
-struct GPUBatch *DRW_cache_text_edge_detection_get(Object *ob, bool *r_is_manifold);
+struct GPUBatch *DRW_cache_text_edge_detection_get(struct Object *ob, bool *r_is_manifold);
struct GPUBatch *DRW_cache_text_loose_edges_get(struct Object *ob);
struct GPUBatch *DRW_cache_text_edge_wire_get(struct Object *ob);
struct GPUBatch **DRW_cache_text_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len);
-struct GPUBatch *DRW_cache_text_face_wireframe_get(Object *ob);
+struct GPUBatch *DRW_cache_text_face_wireframe_get(struct Object *ob);
/* Surface */
struct GPUBatch *DRW_cache_surf_surface_get(struct Object *ob);
@@ -176,7 +177,7 @@ struct GPUBatch *DRW_cache_surf_loose_edges_get(struct Object *ob);
struct GPUBatch **DRW_cache_surf_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len);
-struct GPUBatch *DRW_cache_surf_face_wireframe_get(Object *ob);
+struct GPUBatch *DRW_cache_surf_face_wireframe_get(struct Object *ob);
struct GPUBatch *DRW_cache_surf_edge_detection_get(struct Object *ob, bool *r_is_manifold);
/* Lattice */
@@ -206,7 +207,7 @@ struct GPUBatch *DRW_cache_mball_surface_get(struct Object *ob);
struct GPUBatch **DRW_cache_mball_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len);
-struct GPUBatch *DRW_cache_mball_face_wireframe_get(Object *ob);
+struct GPUBatch *DRW_cache_mball_face_wireframe_get(struct Object *ob);
struct GPUBatch *DRW_cache_mball_edge_detection_get(struct Object *ob, bool *r_is_manifold);
#endif /* __DRAW_CACHE_H__ */
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
new file mode 100644
index 00000000000..9305dc6eef7
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -0,0 +1,250 @@
+/*
+ * 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 draw
+ */
+
+#ifndef __DRAW_CACHE_EXTRACT_MESH_H__
+#define __DRAW_CACHE_EXTRACT_MESH_H__
+
+/* Vertex Group Selection and display options */
+typedef struct DRW_MeshWeightState {
+ int defgroup_active;
+ int defgroup_len;
+
+ short flags;
+ char alert_mode;
+
+ /* Set of all selected bones for Multipaint. */
+ bool *defgroup_sel; /* [defgroup_len] */
+ int defgroup_sel_count;
+} DRW_MeshWeightState;
+
+/* DRW_MeshWeightState.flags */
+enum {
+ DRW_MESH_WEIGHT_STATE_MULTIPAINT = (1 << 0),
+ DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE = (1 << 1),
+};
+
+typedef struct DRW_MeshCDMask {
+ uint32_t uv : 8;
+ uint32_t tan : 8;
+ uint32_t vcol : 8;
+ uint32_t orco : 1;
+ uint32_t tan_orco : 1;
+} DRW_MeshCDMask;
+
+typedef enum eMRIterType {
+ MR_ITER_LOOPTRI = 1 << 0,
+ MR_ITER_LOOP = 1 << 1,
+ MR_ITER_LEDGE = 1 << 2,
+ MR_ITER_LVERT = 1 << 3,
+} eMRIterType;
+
+typedef enum eMRDataType {
+ MR_DATA_POLY_NOR = 1 << 1,
+ MR_DATA_LOOP_NOR = 1 << 2,
+ MR_DATA_LOOPTRI = 1 << 3,
+ /** Force loop normals calculation. */
+ MR_DATA_TAN_LOOP_NOR = 1 << 4,
+} eMRDataType;
+
+typedef enum eMRExtractType {
+ MR_EXTRACT_BMESH,
+ MR_EXTRACT_MAPPED,
+ MR_EXTRACT_MESH,
+} eMRExtractType;
+
+BLI_INLINE int mesh_render_mat_len_get(Mesh *me)
+{
+ return MAX2(1, me->totcol);
+}
+
+typedef struct MeshBufferCache {
+ /* Every VBO below contains at least enough
+ * data for every loops in the mesh (except fdots).
+ * For some VBOs, it extends to (in this exact order) :
+ * loops + loose_edges*2 + loose_verts */
+ struct {
+ GPUVertBuf *pos_nor; /* extend */
+ GPUVertBuf *lnor; /* extend */
+ GPUVertBuf *edge_fac; /* extend */
+ GPUVertBuf *weights; /* extend */
+ GPUVertBuf *uv;
+ GPUVertBuf *tan;
+ GPUVertBuf *vcol;
+ GPUVertBuf *orco;
+ /* Only for edit mode. */
+ GPUVertBuf *edit_data; /* extend */
+ GPUVertBuf *edituv_data;
+ GPUVertBuf *stretch_area;
+ GPUVertBuf *stretch_angle;
+ GPUVertBuf *mesh_analysis;
+ GPUVertBuf *fdots_pos;
+ GPUVertBuf *fdots_nor;
+ GPUVertBuf *fdots_uv;
+ // GPUVertBuf *fdots_edit_data; /* inside fdots_nor for now. */
+ GPUVertBuf *fdots_edituv_data;
+ /* Selection */
+ GPUVertBuf *vert_idx; /* extend */
+ GPUVertBuf *edge_idx; /* extend */
+ GPUVertBuf *poly_idx;
+ GPUVertBuf *fdot_idx;
+ } vbo;
+ /* Index Buffers:
+ * Only need to be updated when topology changes. */
+ struct {
+ /* Indices to vloops. */
+ GPUIndexBuf *tris; /* Ordered per material. */
+ GPUIndexBuf *lines; /* Loose edges last. */
+ GPUIndexBuf *points;
+ GPUIndexBuf *fdots;
+ /* 3D overlays. */
+ GPUIndexBuf *lines_paint_mask; /* no loose edges. */
+ GPUIndexBuf *lines_adjacency;
+ /* Uv overlays. (visibility can differ from 3D view) */
+ GPUIndexBuf *edituv_tris;
+ GPUIndexBuf *edituv_lines;
+ GPUIndexBuf *edituv_points;
+ GPUIndexBuf *edituv_fdots;
+ } ibo;
+} MeshBufferCache;
+
+typedef enum DRWBatchFlag {
+ MBC_SURFACE = (1 << 0),
+ MBC_SURFACE_WEIGHTS = (1 << 1),
+ MBC_EDIT_TRIANGLES = (1 << 2),
+ MBC_EDIT_VERTICES = (1 << 3),
+ MBC_EDIT_EDGES = (1 << 4),
+ MBC_EDIT_VNOR = (1 << 5),
+ 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 = (1 << 11),
+ MBC_EDITUV_EDGES = (1 << 12),
+ MBC_EDITUV_VERTS = (1 << 13),
+ MBC_EDITUV_FACEDOTS = (1 << 14),
+ MBC_EDIT_SELECTION_VERTS = (1 << 15),
+ MBC_EDIT_SELECTION_EDGES = (1 << 16),
+ MBC_EDIT_SELECTION_FACES = (1 << 17),
+ MBC_EDIT_SELECTION_FACEDOTS = (1 << 18),
+ MBC_ALL_VERTS = (1 << 19),
+ MBC_ALL_EDGES = (1 << 20),
+ MBC_LOOSE_EDGES = (1 << 21),
+ MBC_EDGE_DETECTION = (1 << 22),
+ MBC_WIRE_EDGES = (1 << 23),
+ MBC_WIRE_LOOPS = (1 << 24),
+ MBC_WIRE_LOOPS_UVS = (1 << 25),
+ MBC_SURF_PER_MAT = (1 << 26),
+} DRWBatchFlag;
+
+#define MBC_EDITUV \
+ (MBC_EDITUV_FACES_STRECH_AREA | MBC_EDITUV_FACES_STRECH_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) \
+ for (MeshBufferCache *mbc = &batch_cache->final; \
+ mbc == &batch_cache->final || mbc == &batch_cache->cage || mbc == &batch_cache->uv_cage; \
+ mbc = (mbc == &batch_cache->final) ? \
+ &batch_cache->cage : \
+ ((mbc == &batch_cache->cage) ? &batch_cache->uv_cage : NULL))
+
+typedef struct MeshBatchCache {
+ MeshBufferCache final, cage, uv_cage;
+
+ struct {
+ /* Surfaces / Render */
+ GPUBatch *surface;
+ GPUBatch *surface_weights;
+ /* Edit mode */
+ GPUBatch *edit_triangles;
+ GPUBatch *edit_vertices;
+ GPUBatch *edit_edges;
+ GPUBatch *edit_vnor;
+ GPUBatch *edit_lnor;
+ GPUBatch *edit_fdots;
+ GPUBatch *edit_mesh_analysis;
+ /* Edit UVs */
+ GPUBatch *edituv_faces_strech_area;
+ GPUBatch *edituv_faces_strech_angle;
+ GPUBatch *edituv_faces;
+ GPUBatch *edituv_edges;
+ GPUBatch *edituv_verts;
+ GPUBatch *edituv_fdots;
+ /* Edit selection */
+ GPUBatch *edit_selection_verts;
+ GPUBatch *edit_selection_edges;
+ GPUBatch *edit_selection_faces;
+ GPUBatch *edit_selection_fdots;
+ /* Common display / Other */
+ GPUBatch *all_verts;
+ GPUBatch *all_edges;
+ GPUBatch *loose_edges;
+ GPUBatch *edge_detection;
+ GPUBatch *wire_edges; /* Individual edges with face normals. */
+ GPUBatch *wire_loops; /* Loops around faces. no edges between selected faces */
+ GPUBatch *wire_loops_uvs; /* Same as wire_loops but only has uvs. */
+ } batch;
+
+ GPUBatch **surface_per_mat;
+
+ /* arrays of bool uniform names (and value) that will be use to
+ * set srgb conversion for auto attributes.*/
+ char *auto_layer_names;
+ int *auto_layer_is_srgb;
+ int auto_layer_len;
+
+ DRWBatchFlag batch_requested;
+ DRWBatchFlag batch_ready;
+
+ /* settings to determine if cache is invalid */
+ int edge_len;
+ int tri_len;
+ int poly_len;
+ int vert_len;
+ int mat_len;
+ bool is_dirty; /* Instantly invalidates cache, skipping mesh check */
+ bool is_editmode;
+ bool is_uvsyncsel;
+
+ struct DRW_MeshWeightState weight_state;
+
+ DRW_MeshCDMask cd_used, cd_needed, cd_used_over_time;
+
+ int lastmatch;
+
+ /* Valid only if edge_detection is up to date. */
+ bool is_manifold;
+
+ bool no_loose_wire;
+} MeshBatchCache;
+
+void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
+ MeshBufferCache mbc,
+ Mesh *me,
+ const bool do_final,
+ const bool do_uvedit,
+ const bool use_subsurf_fdots,
+ const DRW_MeshCDMask *cd_layer_used,
+ const ToolSettings *ts,
+ const bool use_hide);
+
+#endif /* __DRAW_CACHE_EXTRACT_MESH_H__ */
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c
new file mode 100644
index 00000000000..5b56067d355
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.c
@@ -0,0 +1,4313 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup draw
+ *
+ * \brief Extraction of Mesh data into VBO to feed to GPU.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_bitmap.h"
+#include "BLI_buffer.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_math_bits.h"
+#include "BLI_string.h"
+#include "BLI_alloca.h"
+#include "BLI_edgehash.h"
+#include "BLI_task.h"
+#include "BLI_jitter_2d.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_bvhutils.h"
+#include "BKE_customdata.h"
+#include "BKE_deform.h"
+#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
+#include "BKE_editmesh_tangent.h"
+#include "BKE_editmesh_bvh.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_tangent.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.h"
+#include "BKE_object_deform.h"
+
+#include "atomic_ops.h"
+
+#include "bmesh.h"
+
+#include "GPU_batch.h"
+#include "GPU_extensions.h"
+#include "GPU_material.h"
+
+#include "DRW_render.h"
+
+#include "ED_mesh.h"
+#include "ED_uvedit.h"
+
+#include "draw_cache_inline.h"
+#include "draw_cache_impl.h"
+
+#include "draw_cache_extract.h"
+
+// #define DEBUG_TIME
+
+#ifdef DEBUG_TIME
+# include "PIL_time_utildefines.h"
+#endif
+
+/* ---------------------------------------------------------------------- */
+/** \name Mesh/BMesh Interface (indirect, partially cached access to complex data).
+ * \{ */
+
+typedef struct MeshRenderData {
+ eMRExtractType extract_type;
+
+ int poly_len, edge_len, vert_len, loop_len;
+ int edge_loose_len;
+ int vert_loose_len;
+ int loop_loose_len;
+ int tri_len;
+ int mat_len;
+
+ bool use_hide;
+ bool use_subsurf_fdots;
+ bool use_final_mesh;
+
+ const ToolSettings *toolsettings;
+ /* HACK not supposed to be there but it's needed. */
+ struct MeshBatchCache *cache;
+ /** Edit Mesh */
+ BMEditMesh *edit_bmesh;
+ BMesh *bm;
+ EditMeshData *edit_data;
+ int *v_origindex, *e_origindex, *p_origindex;
+ int crease_ofs;
+ int bweight_ofs;
+ int freestyle_edge_ofs;
+ int freestyle_face_ofs;
+ /** Mesh */
+ Mesh *me;
+ const MVert *mvert;
+ const MEdge *medge;
+ const MLoop *mloop;
+ const MPoly *mpoly;
+ BMVert *eve_act;
+ BMEdge *eed_act;
+ BMFace *efa_act;
+ BMFace *efa_act_uv;
+ /* Data created on-demand (usually not for bmesh-based data). */
+ MLoopTri *mlooptri;
+ float (*loop_normals)[3];
+ float (*poly_normals)[3];
+ int *lverts, *ledges;
+} MeshRenderData;
+
+static MeshRenderData *mesh_render_data_create(Mesh *me,
+ const bool do_final,
+ const bool do_uvedit,
+ const eMRIterType iter_type,
+ const eMRDataType data_flag,
+ const DRW_MeshCDMask *UNUSED(cd_used),
+ const ToolSettings *ts)
+{
+ MeshRenderData *mr = MEM_callocN(sizeof(*mr), __func__);
+ mr->toolsettings = ts;
+ mr->mat_len = mesh_render_mat_len_get(me);
+
+ const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0;
+ const float split_angle = is_auto_smooth ? me->smoothresh : (float)M_PI;
+
+ if (me->edit_mesh) {
+ BLI_assert(me->edit_mesh->mesh_eval_cage && me->edit_mesh->mesh_eval_final);
+ mr->bm = me->edit_mesh->bm;
+ mr->edit_bmesh = me->edit_mesh;
+ mr->edit_data = me->runtime.edit_data;
+ mr->me = (do_final) ? me->edit_mesh->mesh_eval_final : me->edit_mesh->mesh_eval_cage;
+ bool use_mapped = !do_uvedit && mr->me && !mr->me->runtime.is_original;
+
+ int bm_ensure_types = BM_VERT | BM_EDGE | BM_LOOP | BM_FACE;
+
+ BM_mesh_elem_index_ensure(mr->bm, bm_ensure_types);
+ BM_mesh_elem_table_ensure(mr->bm, bm_ensure_types & ~BM_LOOP);
+
+ mr->efa_act_uv = EDBM_uv_active_face_get(mr->edit_bmesh, false, false);
+ mr->efa_act = BM_mesh_active_face_get(mr->bm, false, true);
+ mr->eed_act = BM_mesh_active_edge_get(mr->bm);
+ mr->eve_act = BM_mesh_active_vert_get(mr->bm);
+
+ mr->crease_ofs = CustomData_get_offset(&mr->bm->edata, CD_CREASE);
+ mr->bweight_ofs = CustomData_get_offset(&mr->bm->edata, CD_BWEIGHT);
+#ifdef WITH_FREESTYLE
+ mr->freestyle_edge_ofs = CustomData_get_offset(&mr->bm->edata, CD_FREESTYLE_EDGE);
+ mr->freestyle_face_ofs = CustomData_get_offset(&mr->bm->pdata, CD_FREESTYLE_FACE);
+#endif
+
+ if (use_mapped) {
+ mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
+ mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
+ mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
+
+ use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex);
+ }
+
+ mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_BMESH;
+
+ /* Seems like the mesh_eval_final do not have the right origin indices.
+ * Force not mapped in this case. */
+ if (do_final && me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage) {
+ // mr->edit_bmesh = NULL;
+ mr->extract_type = MR_EXTRACT_MESH;
+ }
+ }
+ else {
+ mr->me = me;
+ mr->edit_bmesh = NULL;
+ mr->extract_type = MR_EXTRACT_MESH;
+ }
+
+ if (mr->extract_type != MR_EXTRACT_BMESH) {
+ /* Mesh */
+ mr->vert_len = mr->me->totvert;
+ mr->edge_len = mr->me->totedge;
+ mr->loop_len = mr->me->totloop;
+ mr->poly_len = mr->me->totpoly;
+ mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
+
+ mr->mvert = CustomData_get_layer(&mr->me->vdata, CD_MVERT);
+ mr->medge = CustomData_get_layer(&mr->me->edata, CD_MEDGE);
+ mr->mloop = CustomData_get_layer(&mr->me->ldata, CD_MLOOP);
+ mr->mpoly = CustomData_get_layer(&mr->me->pdata, CD_MPOLY);
+
+ mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
+ mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
+ mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
+
+ if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) {
+ mr->poly_normals = MEM_mallocN(sizeof(*mr->poly_normals) * mr->poly_len, __func__);
+ BKE_mesh_calc_normals_poly((MVert *)mr->mvert,
+ NULL,
+ mr->vert_len,
+ mr->mloop,
+ mr->mpoly,
+ mr->loop_len,
+ mr->poly_len,
+ mr->poly_normals,
+ true);
+ }
+ if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
+ mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
+ short(*clnors)[2] = CustomData_get_layer(&mr->me->ldata, CD_CUSTOMLOOPNORMAL);
+ BKE_mesh_normals_loop_split(mr->me->mvert,
+ mr->vert_len,
+ mr->me->medge,
+ mr->edge_len,
+ mr->me->mloop,
+ mr->loop_normals,
+ mr->loop_len,
+ mr->me->mpoly,
+ mr->poly_normals,
+ mr->poly_len,
+ is_auto_smooth,
+ split_angle,
+ NULL,
+ clnors,
+ NULL);
+ }
+ if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) {
+ mr->mlooptri = MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI");
+ BKE_mesh_recalc_looptri(mr->me->mloop,
+ mr->me->mpoly,
+ mr->me->mvert,
+ mr->me->totloop,
+ mr->me->totpoly,
+ mr->mlooptri);
+ }
+ if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) {
+ mr->vert_loose_len = 0;
+ mr->edge_loose_len = 0;
+
+ BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, "lvert map");
+
+ mr->ledges = MEM_mallocN(mr->edge_len * sizeof(int), __func__);
+ const MEdge *medge = mr->medge;
+ for (int e = 0; e < mr->edge_len; e++, medge++) {
+ if (medge->flag & ME_LOOSEEDGE) {
+ mr->ledges[mr->edge_loose_len++] = e;
+ }
+ /* Tag verts as not loose. */
+ BLI_BITMAP_ENABLE(lvert_map, medge->v1);
+ BLI_BITMAP_ENABLE(lvert_map, medge->v2);
+ }
+ if (mr->edge_loose_len < mr->edge_len) {
+ mr->ledges = MEM_reallocN(mr->ledges, mr->edge_loose_len * sizeof(*mr->ledges));
+ }
+
+ mr->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__);
+ for (int v = 0; v < mr->vert_len; v++) {
+ if (!BLI_BITMAP_TEST(lvert_map, v)) {
+ mr->lverts[mr->vert_loose_len++] = v;
+ }
+ }
+ if (mr->vert_loose_len < mr->vert_len) {
+ mr->lverts = MEM_reallocN(mr->lverts, mr->vert_loose_len * sizeof(*mr->lverts));
+ }
+
+ MEM_freeN(lvert_map);
+
+ mr->loop_loose_len = mr->vert_loose_len + mr->edge_loose_len * 2;
+ }
+ }
+ else {
+ /* BMesh */
+ BMesh *bm = mr->bm;
+
+ mr->vert_len = bm->totvert;
+ mr->edge_len = bm->totedge;
+ mr->loop_len = bm->totloop;
+ mr->poly_len = bm->totface;
+ mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
+
+ if (data_flag & MR_DATA_POLY_NOR) {
+ /* Use bmface->no instead. */
+ }
+ if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
+ mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
+ int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL);
+ BM_loops_calc_normal_vcos(mr->bm,
+ NULL,
+ NULL,
+ NULL,
+ is_auto_smooth,
+ split_angle,
+ mr->loop_normals,
+ NULL,
+ NULL,
+ clnors_offset,
+ false);
+ }
+ if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) {
+ /* Edit mode ensures this is valid, no need to calculate. */
+ BLI_assert((bm->totloop == 0) || (mr->edit_bmesh->looptris != NULL));
+ }
+ if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) {
+ int elem_id;
+ BMIter iter;
+ BMVert *eve;
+ BMEdge *ede;
+ mr->vert_loose_len = 0;
+ mr->edge_loose_len = 0;
+
+ mr->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__);
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) {
+ if (eve->e == NULL) {
+ mr->lverts[mr->vert_loose_len++] = elem_id;
+ }
+ }
+ if (mr->vert_loose_len < mr->vert_len) {
+ mr->lverts = MEM_reallocN(mr->lverts, mr->vert_loose_len * sizeof(*mr->lverts));
+ }
+
+ mr->ledges = MEM_mallocN(mr->edge_len * sizeof(*mr->ledges), __func__);
+ BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) {
+ if (ede->l == NULL) {
+ mr->ledges[mr->edge_loose_len++] = elem_id;
+ }
+ }
+ if (mr->edge_loose_len < mr->edge_len) {
+ mr->ledges = MEM_reallocN(mr->ledges, mr->edge_loose_len * sizeof(*mr->ledges));
+ }
+
+ mr->loop_loose_len = mr->vert_loose_len + mr->edge_loose_len * 2;
+ }
+ }
+ return mr;
+}
+
+static void mesh_render_data_free(MeshRenderData *mr)
+{
+ MEM_SAFE_FREE(mr->mlooptri);
+ MEM_SAFE_FREE(mr->poly_normals);
+ MEM_SAFE_FREE(mr->loop_normals);
+
+ MEM_SAFE_FREE(mr->lverts);
+ MEM_SAFE_FREE(mr->ledges);
+
+ MEM_freeN(mr);
+}
+
+BLI_INLINE BMFace *bm_original_face_get(const MeshRenderData *mr, int idx)
+{
+ return ((mr->p_origindex != NULL) && (mr->p_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
+ BM_face_at_index(mr->bm, mr->p_origindex[idx]) :
+ NULL;
+}
+
+BLI_INLINE BMEdge *bm_original_edge_get(const MeshRenderData *mr, int idx)
+{
+ return ((mr->e_origindex != NULL) && (mr->e_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
+ BM_edge_at_index(mr->bm, mr->e_origindex[idx]) :
+ NULL;
+}
+
+BLI_INLINE BMVert *bm_original_vert_get(const MeshRenderData *mr, int idx)
+{
+ return ((mr->v_origindex != NULL) && (mr->v_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
+ BM_vert_at_index(mr->bm, mr->v_origindex[idx]) :
+ NULL;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Mesh Elements Extract Iter
+ * \{ */
+
+typedef void *(ExtractInitFn)(const MeshRenderData *mr, void *buffer);
+typedef void(ExtractEditTriFn)(const MeshRenderData *mr, int t, BMLoop **e, void *data);
+typedef void(ExtractEditLoopFn)(const MeshRenderData *mr, int l, BMLoop *el, void *data);
+typedef void(ExtractEditLedgeFn)(const MeshRenderData *mr, int e, BMEdge *ed, void *data);
+typedef void(ExtractEditLvertFn)(const MeshRenderData *mr, int v, BMVert *ev, void *data);
+typedef void(ExtractTriFn)(const MeshRenderData *mr, int t, const MLoopTri *mlt, void *data);
+typedef void(ExtractLoopFn)(
+ const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *data);
+typedef void(ExtractLedgeFn)(const MeshRenderData *mr, int e, const MEdge *medge, void *data);
+typedef void(ExtractLvertFn)(const MeshRenderData *mr, int v, const MVert *mvert, void *data);
+typedef void(ExtractFinishFn)(const MeshRenderData *mr, void *buffer, void *data);
+
+typedef struct MeshExtract {
+ /** Executed on main thread and return user data for iter functions. */
+ ExtractInitFn *init;
+ /** Executed on one (or more if use_threading) worker thread(s). */
+ ExtractEditTriFn *iter_looptri_bm;
+ ExtractTriFn *iter_looptri;
+ ExtractEditLoopFn *iter_loop_bm;
+ ExtractLoopFn *iter_loop;
+ ExtractEditLedgeFn *iter_ledge_bm;
+ ExtractLedgeFn *iter_ledge;
+ ExtractEditLvertFn *iter_lvert_bm;
+ ExtractLvertFn *iter_lvert;
+ /** Executed on one worker thread after all elements iterations. */
+ ExtractFinishFn *finish;
+ /** Used to request common data. */
+ const eMRDataType data_flag;
+ /** Used to know if the element callbacks are threadsafe and can be parallelized. */
+ const bool use_threading;
+} MeshExtract;
+
+BLI_INLINE eMRIterType mesh_extract_iter_type(const MeshExtract *ext)
+{
+ eMRIterType type = 0;
+ SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri), MR_ITER_LOOPTRI);
+ SET_FLAG_FROM_TEST(type, (ext->iter_loop_bm || ext->iter_loop), MR_ITER_LOOP);
+ SET_FLAG_FROM_TEST(type, (ext->iter_ledge_bm || ext->iter_ledge), MR_ITER_LEDGE);
+ SET_FLAG_FROM_TEST(type, (ext->iter_lvert_bm || ext->iter_lvert), MR_ITER_LVERT);
+ return type;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Triangles Indices
+ * \{ */
+
+typedef struct MeshExtract_Tri_Data {
+ GPUIndexBufBuilder elb;
+ int *tri_mat_start;
+ int *tri_mat_end;
+} MeshExtract_Tri_Data;
+
+static void *extract_tris_init(const MeshRenderData *mr, void *UNUSED(ibo))
+{
+ MeshExtract_Tri_Data *data = MEM_callocN(sizeof(*data), __func__);
+
+ size_t mat_tri_idx_size = sizeof(int) * mr->mat_len;
+ data->tri_mat_start = MEM_callocN(mat_tri_idx_size, __func__);
+ data->tri_mat_end = MEM_callocN(mat_tri_idx_size, __func__);
+
+ int *mat_tri_len = data->tri_mat_start;
+ /* Count how many triangle for each material. */
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ BMIter iter;
+ BMFace *efa;
+ BM_ITER_MESH (efa, &iter, mr->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ mat_tri_len[efa->mat_nr] += efa->len - 2;
+ }
+ }
+ }
+ else {
+ const MPoly *mpoly = mr->mpoly;
+ for (int p = 0; p < mr->poly_len; p++, mpoly++) {
+ if (!(mr->use_hide && (mpoly->flag & ME_HIDE))) {
+ mat_tri_len[mpoly->mat_nr] += mpoly->totloop - 2;
+ }
+ }
+ }
+ /* Accumulate tri len per mat to have correct offsets. */
+ int ofs = mat_tri_len[0];
+ mat_tri_len[0] = 0;
+ for (int i = 1; i < mr->mat_len; i++) {
+ int tmp = mat_tri_len[i];
+ mat_tri_len[i] = ofs;
+ ofs += tmp;
+ }
+
+ memcpy(data->tri_mat_end, mat_tri_len, mat_tri_idx_size);
+
+ int visible_tri_tot = ofs;
+ GPU_indexbuf_init(&data->elb, GPU_PRIM_TRIS, visible_tri_tot, mr->loop_len);
+
+ return data;
+}
+
+static void extract_tris_looptri_bmesh(const MeshRenderData *UNUSED(mr),
+ int UNUSED(t),
+ BMLoop **elt,
+ void *_data)
+{
+ if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) {
+ MeshExtract_Tri_Data *data = _data;
+ int *mat_tri_ofs = data->tri_mat_end;
+ GPU_indexbuf_set_tri_verts(&data->elb,
+ mat_tri_ofs[elt[0]->f->mat_nr]++,
+ BM_elem_index_get(elt[0]),
+ BM_elem_index_get(elt[1]),
+ BM_elem_index_get(elt[2]));
+ }
+}
+
+static void extract_tris_looptri_mesh(const MeshRenderData *mr,
+ int UNUSED(t),
+ const MLoopTri *mlt,
+ void *_data)
+{
+ const MPoly *mpoly = &mr->mpoly[mlt->poly];
+ if (!(mr->use_hide && (mpoly->flag & ME_HIDE))) {
+ MeshExtract_Tri_Data *data = _data;
+ int *mat_tri_ofs = data->tri_mat_end;
+ GPU_indexbuf_set_tri_verts(
+ &data->elb, mat_tri_ofs[mpoly->mat_nr]++, mlt->tri[0], mlt->tri[1], mlt->tri[2]);
+ }
+}
+
+static void extract_tris_finish(const MeshRenderData *mr, void *ibo, void *_data)
+{
+ MeshExtract_Tri_Data *data = _data;
+ GPU_indexbuf_build_in_place(&data->elb, ibo);
+ /* 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) {
+ /* 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;
+ GPUIndexBuf *sub_ibo = GPU_indexbuf_create_subrange(ibo, start, len);
+ /* WARNING: We modify the GPUBatch here! */
+ GPU_batch_elembuf_set(mr->cache->surface_per_mat[i], sub_ibo, true);
+ }
+ }
+ MEM_freeN(data->tri_mat_start);
+ MEM_freeN(data->tri_mat_end);
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_tris = {extract_tris_init,
+ extract_tris_looptri_bmesh,
+ extract_tris_looptri_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_tris_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edges Indices
+ * \{ */
+
+static void *extract_lines_init(const MeshRenderData *mr, void *UNUSED(buf))
+{
+ GPUIndexBufBuilder *elb = MEM_mallocN(sizeof(*elb), __func__);
+ /* Put loose edges at the end. */
+ GPU_indexbuf_init(
+ elb, GPU_PRIM_LINES, mr->edge_len + mr->edge_loose_len, mr->loop_len + mr->loop_loose_len);
+ return elb;
+}
+
+static void extract_lines_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *elb)
+{
+ if (!BM_elem_flag_test(loop->e, BM_ELEM_HIDDEN)) {
+ GPU_indexbuf_set_line_verts(elb, BM_elem_index_get(loop->e), l, BM_elem_index_get(loop->next));
+ }
+ else {
+ GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(loop->e));
+ }
+}
+
+static void extract_lines_loop_mesh(const MeshRenderData *mr,
+ int l,
+ const MLoop *mloop,
+ int UNUSED(p),
+ const MPoly *mpoly,
+ void *elb)
+{
+ const MEdge *medge = &mr->medge[mloop->e];
+ if (!((mr->use_hide && (medge->flag & ME_HIDE)) ||
+ ((mr->extract_type == MR_EXTRACT_MAPPED) &&
+ (mr->e_origindex[mloop->e] == ORIGINDEX_NONE)))) {
+ int loopend = mpoly->totloop + mpoly->loopstart - 1;
+ int other_loop = (l == loopend) ? mpoly->loopstart : (l + 1);
+ GPU_indexbuf_set_line_verts(elb, mloop->e, l, other_loop);
+ }
+ else {
+ GPU_indexbuf_set_line_restart(elb, mloop->e);
+ }
+}
+
+static void extract_lines_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *elb)
+{
+ int ledge_idx = mr->edge_len + e;
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ int l = mr->loop_len + e * 2;
+ GPU_indexbuf_set_line_verts(elb, ledge_idx, l, l + 1);
+ }
+ else {
+ GPU_indexbuf_set_line_restart(elb, ledge_idx);
+ }
+ /* Don't render the edge twice. */
+ GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(eed));
+}
+
+static void extract_lines_ledge_mesh(const MeshRenderData *mr,
+ int e,
+ const MEdge *medge,
+ void *elb)
+{
+ int ledge_idx = mr->edge_len + e;
+ int edge_idx = mr->ledges[e];
+ if (!((mr->use_hide && (medge->flag & ME_HIDE)) ||
+ ((mr->extract_type == MR_EXTRACT_MAPPED) &&
+ (mr->e_origindex[edge_idx] == ORIGINDEX_NONE)))) {
+ int l = mr->loop_len + e * 2;
+ GPU_indexbuf_set_line_verts(elb, ledge_idx, l, l + 1);
+ }
+ else {
+ GPU_indexbuf_set_line_restart(elb, ledge_idx);
+ }
+ /* Don't render the edge twice. */
+ GPU_indexbuf_set_line_restart(elb, edge_idx);
+}
+
+static void extract_lines_finish(const MeshRenderData *mr, void *ibo, void *elb)
+{
+ GPU_indexbuf_build_in_place(elb, ibo);
+ MEM_freeN(elb);
+ /* HACK Create ibo subranges and assign them to GPUBatch. */
+ if (mr->use_final_mesh && mr->cache->batch.loose_edges) {
+ BLI_assert(mr->cache->batch.loose_edges->elem == ibo);
+ /* Multiply by 2 because these are edges indices. */
+ int start = mr->edge_len * 2;
+ int len = mr->edge_loose_len * 2;
+ GPUIndexBuf *sub_ibo = GPU_indexbuf_create_subrange(ibo, start, len);
+ /* WARNING: We modify the GPUBatch here! */
+ GPU_batch_elembuf_set(mr->cache->batch.loose_edges, sub_ibo, true);
+ }
+}
+
+const MeshExtract extract_lines = {extract_lines_init,
+ NULL,
+ NULL,
+ extract_lines_loop_bmesh,
+ extract_lines_loop_mesh,
+ extract_lines_ledge_bmesh,
+ extract_lines_ledge_mesh,
+ NULL,
+ NULL,
+ extract_lines_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Point Indices
+ * \{ */
+
+static void *extract_points_init(const MeshRenderData *mr, void *UNUSED(buf))
+{
+ GPUIndexBufBuilder *elb = MEM_mallocN(sizeof(*elb), __func__);
+ GPU_indexbuf_init(elb, GPU_PRIM_POINTS, mr->vert_len, mr->loop_len + mr->loop_loose_len);
+ return elb;
+}
+
+BLI_INLINE void vert_set_bmesh(GPUIndexBufBuilder *elb, BMVert *eve, int loop)
+{
+ int vert_idx = BM_elem_index_get(eve);
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ GPU_indexbuf_set_point_vert(elb, vert_idx, loop);
+ }
+ else {
+ GPU_indexbuf_set_point_restart(elb, vert_idx);
+ }
+}
+
+BLI_INLINE void vert_set_mesh(GPUIndexBufBuilder *elb,
+ const MeshRenderData *mr,
+ int vert_idx,
+ int loop)
+{
+ const MVert *mvert = &mr->mvert[vert_idx];
+ if (!((mr->use_hide && (mvert->flag & ME_HIDE)) ||
+ ((mr->extract_type == MR_EXTRACT_MAPPED) &&
+ (mr->v_origindex[vert_idx] == ORIGINDEX_NONE)))) {
+ GPU_indexbuf_set_point_vert(elb, vert_idx, loop);
+ }
+ else {
+ GPU_indexbuf_set_point_restart(elb, vert_idx);
+ }
+}
+
+static void extract_points_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *elb)
+{
+ vert_set_bmesh(elb, loop->v, l);
+}
+
+static void extract_points_loop_mesh(const MeshRenderData *mr,
+ int l,
+ const MLoop *mloop,
+ int UNUSED(p),
+ const MPoly *UNUSED(mpoly),
+ void *elb)
+{
+ vert_set_mesh(elb, mr, mloop->v, l);
+}
+
+static void extract_points_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *elb)
+{
+ vert_set_bmesh(elb, eed->v1, mr->loop_len + e * 2);
+ vert_set_bmesh(elb, eed->v2, mr->loop_len + e * 2 + 1);
+}
+
+static void extract_points_ledge_mesh(const MeshRenderData *mr,
+ int e,
+ const MEdge *medge,
+ void *elb)
+{
+ vert_set_mesh(elb, mr, medge->v1, mr->loop_len + e * 2);
+ vert_set_mesh(elb, mr, medge->v2, mr->loop_len + e * 2 + 1);
+}
+
+static void extract_points_lvert_bmesh(const MeshRenderData *mr, int v, BMVert *eve, void *elb)
+{
+ vert_set_bmesh(elb, eve, mr->loop_len + mr->edge_loose_len * 2 + v);
+}
+
+static void extract_points_lvert_mesh(const MeshRenderData *mr,
+ int v,
+ const MVert *UNUSED(mvert),
+ void *elb)
+{
+ vert_set_mesh(elb, mr, mr->lverts[v], mr->loop_len + mr->edge_loose_len * 2 + v);
+}
+
+static void extract_points_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *elb)
+{
+ GPU_indexbuf_build_in_place(elb, ibo);
+ MEM_freeN(elb);
+}
+
+const MeshExtract extract_points = {extract_points_init,
+ NULL,
+ NULL,
+ extract_points_loop_bmesh,
+ extract_points_loop_mesh,
+ extract_points_ledge_bmesh,
+ extract_points_ledge_mesh,
+ extract_points_lvert_bmesh,
+ extract_points_lvert_mesh,
+ extract_points_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Facedots Indices
+ * \{ */
+
+static void *extract_fdots_init(const MeshRenderData *mr, void *UNUSED(buf))
+{
+ GPUIndexBufBuilder *elb = MEM_mallocN(sizeof(*elb), __func__);
+ GPU_indexbuf_init(elb, GPU_PRIM_POINTS, mr->poly_len, mr->poly_len);
+ return elb;
+}
+
+static void extract_fdots_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int UNUSED(l),
+ BMLoop *loop,
+ void *elb)
+{
+ int face_idx = BM_elem_index_get(loop->f);
+ if (!BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN)) {
+ GPU_indexbuf_set_point_vert(elb, face_idx, face_idx);
+ }
+ else {
+ GPU_indexbuf_set_point_restart(elb, face_idx);
+ }
+}
+
+static void extract_fdots_loop_mesh(const MeshRenderData *mr,
+ int UNUSED(l),
+ const MLoop *mloop,
+ int p,
+ const MPoly *mpoly,
+ void *elb)
+{
+ const MVert *mvert = &mr->mvert[mloop->v];
+ if ((!mr->use_subsurf_fdots || (mvert->flag & ME_VERT_FACEDOT)) &&
+ !(mr->use_hide && (mpoly->flag & ME_HIDE))) {
+ GPU_indexbuf_set_point_vert(elb, p, p);
+ }
+ else {
+ GPU_indexbuf_set_point_restart(elb, p);
+ }
+}
+
+static void extract_fdots_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *elb)
+{
+ GPU_indexbuf_build_in_place(elb, ibo);
+ MEM_freeN(elb);
+}
+
+const MeshExtract extract_fdots = {extract_fdots_init,
+ NULL,
+ NULL,
+ extract_fdots_loop_bmesh,
+ extract_fdots_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_fdots_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Paint Mask Line Indices
+ * \{ */
+
+typedef struct MeshExtract_LinePaintMask_Data {
+ GPUIndexBufBuilder elb;
+ /** One bit per edge set if face is selected. */
+ BLI_bitmap select_map[0];
+} MeshExtract_LinePaintMask_Data;
+
+static void *extract_lines_paint_mask_init(const MeshRenderData *mr, void *UNUSED(buf))
+{
+ size_t bitmap_size = BLI_BITMAP_SIZE(mr->edge_len);
+ MeshExtract_LinePaintMask_Data *data = MEM_callocN(sizeof(*data) + bitmap_size, __func__);
+ GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES, mr->edge_len, mr->loop_len);
+ return data;
+}
+
+static void extract_lines_paint_mask_loop_mesh(const MeshRenderData *mr,
+ int l,
+ const MLoop *mloop,
+ int UNUSED(p),
+ const MPoly *mpoly,
+ void *_data)
+{
+ MeshExtract_LinePaintMask_Data *data = (MeshExtract_LinePaintMask_Data *)_data;
+ if (!(mr->use_hide && (mpoly->flag & ME_HIDE))) {
+ int loopend = mpoly->totloop + mpoly->loopstart - 1;
+ int other_loop = (l == loopend) ? mpoly->loopstart : (l + 1);
+ int edge_idx = mloop->e;
+ if (mpoly->flag & ME_FACE_SEL) {
+ if (BLI_BITMAP_TEST_AND_SET_ATOMIC(data->select_map, edge_idx)) {
+ /* Hide edge as it has more than 2 selected loop. */
+ GPU_indexbuf_set_line_restart(&data->elb, edge_idx);
+ }
+ else {
+ /* First selected loop. Set edge visible, overwritting any unsel loop. */
+ GPU_indexbuf_set_line_verts(&data->elb, edge_idx, l, other_loop);
+ }
+ }
+ else {
+ /* Set theses unselected loop only if this edge has no other selected loop. */
+ if (!BLI_BITMAP_TEST(data->select_map, edge_idx)) {
+ GPU_indexbuf_set_line_verts(&data->elb, edge_idx, l, other_loop);
+ }
+ }
+ }
+}
+static void extract_lines_paint_mask_finish(const MeshRenderData *UNUSED(mr),
+ void *ibo,
+ void *_data)
+{
+ MeshExtract_LinePaintMask_Data *data = (MeshExtract_LinePaintMask_Data *)_data;
+
+ GPU_indexbuf_build_in_place(&data->elb, ibo);
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_lines_paint_mask = {extract_lines_paint_mask_init,
+ NULL,
+ NULL,
+ NULL,
+ extract_lines_paint_mask_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_lines_paint_mask_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Line Adjacency Indices
+ * \{ */
+
+#define NO_EDGE INT_MAX
+
+typedef struct MeshExtract_LineAdjacency_Data {
+ GPUIndexBufBuilder elb;
+ EdgeHash *eh;
+ bool is_manifold;
+ /* Array to convert vert index to any loop index of this vert. */
+ uint vert_to_loop[0];
+} MeshExtract_LineAdjacency_Data;
+
+static void *extract_lines_adjacency_init(const MeshRenderData *mr, void *UNUSED(buf))
+{
+ /* Similar to poly_to_tri_count().
+ * There is always loop + tri - 1 edges inside a polygon.
+ * Accumulate for all polys and you get : */
+ uint tess_edge_len = mr->loop_len + mr->tri_len - mr->poly_len;
+
+ size_t vert_to_loop_size = sizeof(uint) * mr->vert_len;
+
+ MeshExtract_LineAdjacency_Data *data = MEM_callocN(sizeof(*data) + vert_to_loop_size, __func__);
+ GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES_ADJ, tess_edge_len, mr->loop_len);
+ data->eh = BLI_edgehash_new_ex(__func__, tess_edge_len);
+ data->is_manifold = true;
+ return data;
+}
+
+BLI_INLINE void lines_adjacency_triangle(
+ uint v1, uint v2, uint v3, uint l1, uint l2, uint l3, MeshExtract_LineAdjacency_Data *data)
+{
+ 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;
+
+ bool inv_indices = (v2 > v3);
+ void **pval;
+ bool value_is_init = BLI_edgehash_ensure_p(data->eh, v2, v3, &pval);
+ int v_data = POINTER_AS_INT(*pval);
+ if (!value_is_init || v_data == NO_EDGE) {
+ /* Save the winding order inside the sign bit. Because the
+ * edgehash sort the keys and we need to compare winding later. */
+ int value = (int)l1 + 1; /* 0 cannot be signed so add one. */
+ *pval = POINTER_FROM_INT((inv_indices) ? -value : value);
+ /* Store loop indices for remaining non-manifold edges. */
+ data->vert_to_loop[v2] = l2;
+ data->vert_to_loop[v3] = l3;
+ }
+ else {
+ /* HACK Tag as not used. Prevent overhead of BLI_edgehash_remove. */
+ *pval = POINTER_FROM_INT(NO_EDGE);
+ bool inv_opposite = (v_data < 0);
+ uint l_opposite = (uint)abs(v_data) - 1;
+ /* TODO Make this part threadsafe. */
+ if (inv_opposite == inv_indices) {
+ /* Don't share edge if triangles have non matching winding. */
+ GPU_indexbuf_add_line_adj_verts(elb, l1, l2, l3, l1);
+ GPU_indexbuf_add_line_adj_verts(elb, l_opposite, l2, l3, l_opposite);
+ data->is_manifold = false;
+ }
+ else {
+ GPU_indexbuf_add_line_adj_verts(elb, l1, l2, l3, l_opposite);
+ }
+ }
+ }
+}
+
+static void extract_lines_adjacency_looptri_bmesh(const MeshRenderData *UNUSED(mr),
+ int UNUSED(t),
+ BMLoop **elt,
+ void *data)
+{
+ if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) {
+ lines_adjacency_triangle(BM_elem_index_get(elt[0]->v),
+ BM_elem_index_get(elt[1]->v),
+ BM_elem_index_get(elt[2]->v),
+ BM_elem_index_get(elt[0]),
+ BM_elem_index_get(elt[1]),
+ BM_elem_index_get(elt[2]),
+ data);
+ }
+}
+
+static void extract_lines_adjacency_looptri_mesh(const MeshRenderData *mr,
+ int UNUSED(t),
+ const MLoopTri *mlt,
+ void *data)
+{
+ const MPoly *mpoly = &mr->mpoly[mlt->poly];
+ if (!(mpoly->flag & ME_HIDE)) {
+ lines_adjacency_triangle(mr->mloop[mlt->tri[0]].v,
+ mr->mloop[mlt->tri[1]].v,
+ mr->mloop[mlt->tri[2]].v,
+ mlt->tri[0],
+ mlt->tri[1],
+ mlt->tri[2],
+ data);
+ }
+}
+
+static void extract_lines_adjacency_finish(const MeshRenderData *mr, void *ibo, void *_data)
+{
+ MeshExtract_LineAdjacency_Data *data = (MeshExtract_LineAdjacency_Data *)_data;
+ /* Create edges for remaining non manifold edges. */
+ EdgeHashIterator *ehi = BLI_edgehashIterator_new(data->eh);
+ for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
+ uint v2, v3, l1, l2, l3;
+ int v_data = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi));
+ if (v_data != NO_EDGE) {
+ BLI_edgehashIterator_getKey(ehi, &v2, &v3);
+ l1 = (uint)abs(v_data) - 1;
+ if (v_data < 0) { /* inv_opposite */
+ SWAP(uint, v2, v3);
+ }
+ l2 = data->vert_to_loop[v2];
+ l3 = data->vert_to_loop[v3];
+ GPU_indexbuf_add_line_adj_verts(&data->elb, l1, l2, l3, l1);
+ data->is_manifold = false;
+ }
+ }
+ BLI_edgehashIterator_free(ehi);
+ BLI_edgehash_free(data->eh, NULL);
+
+ mr->cache->is_manifold = data->is_manifold;
+
+ GPU_indexbuf_build_in_place(&data->elb, ibo);
+ MEM_freeN(data);
+}
+
+#undef NO_EDGE
+
+const MeshExtract extract_lines_adjacency = {extract_lines_adjacency_init,
+ extract_lines_adjacency_looptri_bmesh,
+ extract_lines_adjacency_looptri_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_lines_adjacency_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edit UV Triangles Indices
+ * \{ */
+
+typedef struct MeshExtract_EditUvElem_Data {
+ GPUIndexBufBuilder elb;
+ bool sync_selection;
+} MeshExtract_EditUvElem_Data;
+
+static void *extract_edituv_tris_init(const MeshRenderData *mr, void *UNUSED(ibo))
+{
+ MeshExtract_EditUvElem_Data *data = MEM_callocN(sizeof(*data), __func__);
+ GPU_indexbuf_init(&data->elb, GPU_PRIM_TRIS, mr->tri_len, mr->loop_len);
+ data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
+ return data;
+}
+
+BLI_INLINE void edituv_tri_add(
+ MeshExtract_EditUvElem_Data *data, bool hidden, bool selected, int v1, int v2, int v3)
+{
+ if (!hidden && (data->sync_selection || selected)) {
+ GPU_indexbuf_add_tri_verts(&data->elb, v1, v2, v3);
+ }
+}
+
+static void extract_edituv_tris_looptri_bmesh(const MeshRenderData *UNUSED(mr),
+ int UNUSED(t),
+ BMLoop **elt,
+ void *data)
+{
+ edituv_tri_add(data,
+ BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN),
+ BM_elem_flag_test(elt[0]->f, BM_ELEM_SELECT),
+ BM_elem_index_get(elt[0]),
+ BM_elem_index_get(elt[1]),
+ BM_elem_index_get(elt[2]));
+}
+
+static void extract_edituv_tris_looptri_mesh(const MeshRenderData *mr,
+ int UNUSED(t),
+ const MLoopTri *mlt,
+ void *data)
+{
+ const MPoly *mpoly = &mr->mpoly[mlt->poly];
+ edituv_tri_add(data,
+ (mpoly->flag & ME_HIDE) != 0,
+ (mpoly->flag & ME_FACE_SEL) != 0,
+ mlt->tri[0],
+ mlt->tri[1],
+ mlt->tri[2]);
+}
+
+static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *data)
+{
+ MeshExtract_EditUvElem_Data *extract_data = (MeshExtract_EditUvElem_Data *)data;
+ GPU_indexbuf_build_in_place(&extract_data->elb, ibo);
+ MEM_freeN(extract_data);
+}
+
+const MeshExtract extract_edituv_tris = {extract_edituv_tris_init,
+ extract_edituv_tris_looptri_bmesh,
+ extract_edituv_tris_looptri_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_edituv_tris_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edit UV Line Indices around faces
+ * \{ */
+
+static void *extract_edituv_lines_init(const MeshRenderData *mr, void *UNUSED(ibo))
+{
+ MeshExtract_EditUvElem_Data *data = MEM_callocN(sizeof(*data), __func__);
+ GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES, mr->loop_len, mr->loop_len);
+
+ data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
+ return data;
+}
+
+BLI_INLINE void edituv_edge_add(
+ MeshExtract_EditUvElem_Data *data, bool hidden, bool selected, int v1, int v2)
+{
+ if (!hidden && (data->sync_selection || selected)) {
+ GPU_indexbuf_add_line_verts(&data->elb, v1, v2);
+ }
+}
+
+static void extract_edituv_lines_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *data)
+{
+ edituv_edge_add(data,
+ BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN),
+ BM_elem_flag_test(loop->f, BM_ELEM_SELECT),
+ l,
+ BM_elem_index_get(loop->next));
+}
+
+static void extract_edituv_lines_loop_mesh(const MeshRenderData *mr,
+ int loop_idx,
+ const MLoop *mloop,
+ int UNUSED(p),
+ const MPoly *mpoly,
+ void *data)
+{
+ 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);
+ edituv_edge_add(data,
+ (mpoly->flag & ME_HIDE) != 0 || !real_edge,
+ (mpoly->flag & ME_FACE_SEL) != 0,
+ loop_idx,
+ loop_next_idx);
+}
+
+static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *data)
+{
+ MeshExtract_EditUvElem_Data *extract_data = (MeshExtract_EditUvElem_Data *)data;
+ GPU_indexbuf_build_in_place(&extract_data->elb, ibo);
+ MEM_freeN(extract_data);
+}
+
+const MeshExtract extract_edituv_lines = {extract_edituv_lines_init,
+ NULL,
+ NULL,
+ extract_edituv_lines_loop_bmesh,
+ extract_edituv_lines_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_edituv_lines_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edit UV Points Indices
+ * \{ */
+
+static void *extract_edituv_points_init(const MeshRenderData *mr, void *UNUSED(ibo))
+{
+ MeshExtract_EditUvElem_Data *data = MEM_callocN(sizeof(*data), __func__);
+ GPU_indexbuf_init(&data->elb, GPU_PRIM_POINTS, mr->loop_len, mr->loop_len);
+
+ data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
+ return data;
+}
+
+BLI_INLINE void edituv_point_add(MeshExtract_EditUvElem_Data *data,
+ bool hidden,
+ bool selected,
+ int v1)
+{
+ if (!hidden && (data->sync_selection || selected)) {
+ GPU_indexbuf_add_point_vert(&data->elb, v1);
+ }
+}
+
+static void extract_edituv_points_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *data)
+{
+ edituv_point_add(data,
+ BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN),
+ BM_elem_flag_test(loop->f, BM_ELEM_SELECT),
+ l);
+}
+
+static void extract_edituv_points_loop_mesh(const MeshRenderData *mr,
+ int l,
+ const MLoop *mloop,
+ int UNUSED(p),
+ const MPoly *mpoly,
+ void *data)
+{
+ const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED &&
+ mr->v_origindex[mloop->v] != ORIGINDEX_NONE);
+ edituv_point_add(
+ data, ((mpoly->flag & ME_HIDE) != 0) || !real_vert, (mpoly->flag & ME_FACE_SEL) != 0, l);
+}
+
+static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *data)
+{
+ MeshExtract_EditUvElem_Data *extract_data = (MeshExtract_EditUvElem_Data *)data;
+ GPU_indexbuf_build_in_place(&extract_data->elb, ibo);
+ MEM_freeN(extract_data);
+}
+
+const MeshExtract extract_edituv_points = {extract_edituv_points_init,
+ NULL,
+ NULL,
+ extract_edituv_points_loop_bmesh,
+ extract_edituv_points_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_edituv_points_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edit UV Facedots Indices
+ * \{ */
+
+static void *extract_edituv_fdots_init(const MeshRenderData *mr, void *UNUSED(ibo))
+{
+ MeshExtract_EditUvElem_Data *data = MEM_callocN(sizeof(*data), __func__);
+ GPU_indexbuf_init(&data->elb, GPU_PRIM_POINTS, mr->poly_len, mr->poly_len);
+
+ data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
+ return data;
+}
+
+BLI_INLINE void edituv_facedot_add(MeshExtract_EditUvElem_Data *data,
+ bool hidden,
+ bool selected,
+ int face_idx)
+{
+ if (!hidden && (data->sync_selection || selected)) {
+ GPU_indexbuf_set_point_vert(&data->elb, face_idx, face_idx);
+ }
+ else {
+ GPU_indexbuf_set_point_restart(&data->elb, face_idx);
+ }
+}
+
+static void extract_edituv_fdots_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int UNUSED(l),
+ BMLoop *loop,
+ void *data)
+{
+ edituv_facedot_add(data,
+ BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN),
+ BM_elem_flag_test(loop->f, BM_ELEM_SELECT),
+ BM_elem_index_get(loop->f));
+}
+
+static void extract_edituv_fdots_loop_mesh(const MeshRenderData *mr,
+ int UNUSED(l),
+ const MLoop *mloop,
+ int p,
+ const MPoly *mpoly,
+ void *data)
+{
+ const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED &&
+ mr->p_origindex[p] != ORIGINDEX_NONE);
+ const bool subd_fdot = (!mr->use_subsurf_fdots ||
+ (mr->mvert[mloop->v].flag & ME_VERT_FACEDOT) != 0);
+ edituv_facedot_add(data,
+ ((mpoly->flag & ME_HIDE) != 0) || !real_fdot || !subd_fdot,
+ (mpoly->flag & ME_FACE_SEL) != 0,
+ p);
+}
+
+static void extract_edituv_fdots_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *_data)
+{
+ MeshExtract_EditUvElem_Data *data = (MeshExtract_EditUvElem_Data *)_data;
+ GPU_indexbuf_build_in_place(&data->elb, ibo);
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_edituv_fdots = {extract_edituv_fdots_init,
+ NULL,
+ NULL,
+ extract_edituv_fdots_loop_bmesh,
+ extract_edituv_fdots_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_edituv_fdots_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Position and Vertex Normal
+ * \{ */
+
+typedef struct PosNorLoop {
+ float pos[3];
+ GPUPackedNormal nor;
+} PosNorLoop;
+
+typedef struct MeshExtract_PosNor_Data {
+ PosNorLoop *vbo_data;
+ GPUPackedNormal packed_nor[];
+} MeshExtract_PosNor_Data;
+
+static void *extract_pos_nor_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* WARNING Adjust PosNorLoop struct accordingly. */
+ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ GPU_vertformat_alias_add(&format, "vnor");
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
+
+ /* Pack normals per vert, reduce amount of computation. */
+ size_t packed_nor_len = sizeof(GPUPackedNormal) * mr->vert_len;
+ MeshExtract_PosNor_Data *data = MEM_mallocN(sizeof(*data) + packed_nor_len, __func__);
+ data->vbo_data = (PosNorLoop *)vbo->data;
+
+ /* Quicker than doing it for each loop. */
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ BMIter iter;
+ BMVert *eve;
+ int v;
+ BM_ITER_MESH_INDEX (eve, &iter, mr->bm, BM_VERTS_OF_MESH, v) {
+ data->packed_nor[v] = GPU_normal_convert_i10_v3(eve->no);
+ }
+ }
+ else {
+ const MVert *mvert = mr->mvert;
+ for (int v = 0; v < mr->vert_len; v++, mvert++) {
+ data->packed_nor[v] = GPU_normal_convert_i10_s3(mvert->no);
+ }
+ }
+ return data;
+}
+
+static void extract_pos_nor_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *_data)
+{
+ MeshExtract_PosNor_Data *data = _data;
+ PosNorLoop *vert = data->vbo_data + l;
+ copy_v3_v3(vert->pos, loop->v->co);
+ vert->nor = data->packed_nor[BM_elem_index_get(loop->v)];
+}
+
+static void extract_pos_nor_loop_mesh(const MeshRenderData *mr,
+ int l,
+ const MLoop *mloop,
+ int UNUSED(p),
+ const MPoly *mpoly,
+ void *_data)
+{
+ MeshExtract_PosNor_Data *data = _data;
+ PosNorLoop *vert = data->vbo_data + l;
+ const MVert *mvert = &mr->mvert[mloop->v];
+ copy_v3_v3(vert->pos, mvert->co);
+ vert->nor = data->packed_nor[mloop->v];
+ /* Flag for paint mode overlay. */
+ if (mpoly->flag & ME_HIDE)
+ vert->nor.w = -1;
+ else if (mpoly->flag & ME_FACE_SEL)
+ vert->nor.w = 1;
+ else
+ vert->nor.w = 0;
+}
+
+static void extract_pos_nor_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *_data)
+{
+ int l = mr->loop_len + e * 2;
+ MeshExtract_PosNor_Data *data = _data;
+ PosNorLoop *vert = data->vbo_data + l;
+ copy_v3_v3(vert[0].pos, eed->v1->co);
+ copy_v3_v3(vert[1].pos, eed->v2->co);
+ vert[0].nor = data->packed_nor[BM_elem_index_get(eed->v1)];
+ vert[1].nor = data->packed_nor[BM_elem_index_get(eed->v2)];
+}
+
+static void extract_pos_nor_ledge_mesh(const MeshRenderData *mr,
+ int e,
+ const MEdge *medge,
+ void *_data)
+{
+ int l = mr->loop_len + e * 2;
+ MeshExtract_PosNor_Data *data = _data;
+ PosNorLoop *vert = data->vbo_data + l;
+ copy_v3_v3(vert[0].pos, mr->mvert[medge->v1].co);
+ copy_v3_v3(vert[1].pos, mr->mvert[medge->v2].co);
+ vert[0].nor = data->packed_nor[medge->v1];
+ vert[1].nor = data->packed_nor[medge->v2];
+}
+
+static void extract_pos_nor_lvert_bmesh(const MeshRenderData *mr, int v, BMVert *eve, void *_data)
+{
+ int l = mr->loop_len + mr->edge_loose_len * 2 + v;
+ MeshExtract_PosNor_Data *data = _data;
+ PosNorLoop *vert = data->vbo_data + l;
+ copy_v3_v3(vert->pos, eve->co);
+ vert->nor = data->packed_nor[BM_elem_index_get(eve)];
+}
+
+static void extract_pos_nor_lvert_mesh(const MeshRenderData *mr,
+ int v,
+ const MVert *mvert,
+ void *_data)
+{
+ int l = mr->loop_len + mr->edge_loose_len * 2 + v;
+ int v_idx = mr->lverts[v];
+ MeshExtract_PosNor_Data *data = _data;
+ PosNorLoop *vert = data->vbo_data + l;
+ copy_v3_v3(vert->pos, mvert->co);
+ vert->nor = data->packed_nor[v_idx];
+}
+
+static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(vbo), void *data)
+{
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_pos_nor = {extract_pos_nor_init,
+ NULL,
+ NULL,
+ extract_pos_nor_loop_bmesh,
+ extract_pos_nor_loop_mesh,
+ extract_pos_nor_ledge_bmesh,
+ extract_pos_nor_ledge_mesh,
+ extract_pos_nor_lvert_bmesh,
+ extract_pos_nor_lvert_mesh,
+ extract_pos_nor_finish,
+ 0,
+ true};
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Loop Normal
+ * \{ */
+
+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_alias_add(&format, "lnor");
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len);
+
+ return vbo->data;
+}
+
+static void extract_lnor_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *data)
+{
+ if (mr->loop_normals) {
+ ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(mr->loop_normals[l]);
+ }
+ else if (BM_elem_flag_test(loop->f, BM_ELEM_SMOOTH)) {
+ ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(loop->v->no);
+ }
+ else {
+ ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(loop->f->no);
+ }
+}
+
+static void extract_lnor_loop_mesh(
+ const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *data)
+{
+ if (mr->loop_normals) {
+ ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(mr->loop_normals[l]);
+ }
+ else if (mpoly->flag & ME_SMOOTH) {
+ ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_s3(mr->mvert[mloop->v].no);
+ }
+ else {
+ ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(mr->poly_normals[p]);
+ }
+}
+
+const MeshExtract extract_lnor = {extract_lnor_init,
+ NULL,
+ NULL,
+ extract_lnor_loop_bmesh,
+ extract_lnor_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ MR_DATA_LOOP_NOR,
+ true};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract UV layers
+ * \{ */
+
+static void *extract_uv_init(const MeshRenderData *mr, void *buf)
+{
+ GPUVertFormat format = {0};
+ GPU_vertformat_deinterleave(&format);
+
+ CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
+ uint32_t uv_layers = mr->cache->cd_used.uv;
+
+ for (int i = 0; i < MAX_MTFACE; i++) {
+ if (uv_layers & (1 << i)) {
+ char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
+ const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i);
+
+ GPU_vertformat_safe_attrib_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
+ /* UV layer name. */
+ BLI_snprintf(attr_name, sizeof(attr_name), "u%s", attr_safe_name);
+ GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ /* Auto layer name. */
+ BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
+ GPU_vertformat_alias_add(&format, attr_name);
+ /* Active render layer name. */
+ if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPUV)) {
+ GPU_vertformat_alias_add(&format, "u");
+ }
+ /* Active display layer name. */
+ if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) {
+ GPU_vertformat_alias_add(&format, "au");
+ /* Alias to pos for edit uvs. */
+ GPU_vertformat_alias_add(&format, "pos");
+ }
+ /* Stencil mask uv layer name. */
+ if (i == CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV)) {
+ GPU_vertformat_alias_add(&format, "mu");
+ }
+ }
+ }
+
+ int v_len = mr->loop_len;
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ /* VBO will not be used, only allocate minimum of memory. */
+ v_len = 1;
+ }
+
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, v_len);
+
+ float(*uv_data)[2] = (float(*)[2])vbo->data;
+ for (int i = 0; i < MAX_MTFACE; i++) {
+ if (uv_layers & (1 << i)) {
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPUV, i);
+ BMIter f_iter, l_iter;
+ BMFace *efa;
+ BMLoop *loop;
+ BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, cd_ofs);
+ memcpy(uv_data, luv->uv, sizeof(*uv_data));
+ uv_data++;
+ }
+ }
+ }
+ else {
+ MLoopUV *layer_data = CustomData_get_layer_n(cd_ldata, CD_MLOOPUV, i);
+ for (int l = 0; l < mr->loop_len; l++, uv_data++, layer_data++) {
+ memcpy(uv_data, layer_data->uv, sizeof(*uv_data));
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+const MeshExtract extract_uv = {
+ extract_uv_init, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, false};
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Tangent layers
+ * \{ */
+
+static void *extract_tan_init(const MeshRenderData *mr, void *buf)
+{
+ GPUVertFormat format = {0};
+ GPU_vertformat_deinterleave(&format);
+
+ CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
+ CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
+ uint32_t tan_layers = mr->cache->cd_used.tan;
+ float(*orco)[3] = CustomData_get_layer(cd_vdata, CD_ORCO);
+ bool orco_allocated = false;
+ const bool use_orco_tan = mr->cache->cd_used.tan_orco != 0;
+
+ int tan_len = 0;
+ char tangent_names[MAX_MTFACE][MAX_CUSTOMDATA_LAYER_NAME];
+
+ for (int i = 0; i < MAX_MTFACE; i++) {
+ if (tan_layers & (1 << i)) {
+ char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
+ const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i);
+ GPU_vertformat_safe_attrib_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
+ /* Tangent layer name. */
+ BLI_snprintf(attr_name, sizeof(attr_name), "t%s", attr_safe_name);
+ GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ /* Active render layer name. */
+ if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPUV)) {
+ GPU_vertformat_alias_add(&format, "t");
+ }
+ /* Active display layer name. */
+ if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) {
+ GPU_vertformat_alias_add(&format, "at");
+ }
+
+ BLI_strncpy(tangent_names[tan_len++], layer_name, MAX_CUSTOMDATA_LAYER_NAME);
+ }
+ }
+ if (use_orco_tan && orco == NULL) {
+ /* If orco is not available compute it ourselves */
+ orco_allocated = true;
+ orco = MEM_mallocN(sizeof(*orco) * mr->vert_len, __func__);
+
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ BMesh *bm = mr->bm;
+ for (int v = 0; v < mr->vert_len; v++) {
+ copy_v3_v3(orco[v], BM_vert_at_index(bm, v)->co);
+ }
+ }
+ else {
+ const MVert *mvert = mr->mvert;
+ for (int v = 0; v < mr->vert_len; v++, mvert++) {
+ copy_v3_v3(orco[v], mvert->co);
+ }
+ }
+ BKE_mesh_orco_verts_transform(mr->me, orco, mr->vert_len, 0);
+ }
+
+ /* Start Fresh */
+ CustomData_free_layers(cd_ldata, CD_TANGENT, mr->loop_len);
+
+ if (tan_len != 0 || use_orco_tan) {
+ short tangent_mask = 0;
+ bool calc_active_tangent = false;
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ BKE_editmesh_loop_tangent_calc(mr->edit_bmesh,
+ calc_active_tangent,
+ tangent_names,
+ tan_len,
+ mr->poly_normals,
+ mr->loop_normals,
+ orco,
+ cd_ldata,
+ mr->loop_len,
+ &tangent_mask);
+ }
+ else {
+ BKE_mesh_calc_loop_tangent_ex(mr->mvert,
+ mr->mpoly,
+ mr->poly_len,
+ mr->mloop,
+ mr->mlooptri,
+ mr->tri_len,
+ cd_ldata,
+ calc_active_tangent,
+ tangent_names,
+ tan_len,
+ mr->poly_normals,
+ mr->loop_normals,
+ orco,
+ cd_ldata,
+ mr->loop_len,
+ &tangent_mask);
+ }
+ }
+
+ if (use_orco_tan) {
+ char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
+ const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_TANGENT, 0);
+ GPU_vertformat_safe_attrib_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
+ BLI_snprintf(attr_name, sizeof(*attr_name), "t%s", attr_safe_name);
+ GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_alias_add(&format, "t");
+ GPU_vertformat_alias_add(&format, "at");
+ }
+
+ if (orco_allocated) {
+ MEM_SAFE_FREE(orco);
+ }
+
+ int v_len = mr->loop_len;
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ /* VBO will not be used, only allocate minimum of memory. */
+ v_len = 1;
+ }
+
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, v_len);
+
+ float(*tan_data)[4] = (float(*)[4])vbo->data;
+ for (int i = 0; i < tan_len; i++) {
+ void *layer_data = CustomData_get_layer_named(cd_ldata, CD_TANGENT, tangent_names[i]);
+ memcpy(tan_data, layer_data, sizeof(*tan_data) * mr->loop_len);
+ tan_data += mr->loop_len;
+ }
+ if (use_orco_tan) {
+ void *layer_data = CustomData_get_layer_n(cd_ldata, CD_TANGENT, 0);
+ memcpy(tan_data, layer_data, sizeof(*tan_data) * mr->loop_len);
+ }
+
+ CustomData_free_layers(cd_ldata, CD_TANGENT, mr->loop_len);
+
+ return NULL;
+}
+
+const MeshExtract extract_tan = {extract_tan_init,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract VCol
+ * \{ */
+
+static void *extract_vcol_init(const MeshRenderData *mr, void *buf)
+{
+ GPUVertFormat format = {0};
+ GPU_vertformat_deinterleave(&format);
+
+ CustomData *cd_ldata = &mr->me->ldata;
+ uint32_t vcol_layers = mr->cache->cd_used.vcol;
+
+ for (int i = 0; i < 8; i++) {
+ if (vcol_layers & (1 << i)) {
+ char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
+ const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i);
+ GPU_vertformat_safe_attrib_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
+
+ BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name);
+ GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL)) {
+ GPU_vertformat_alias_add(&format, "c");
+ }
+ if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL)) {
+ GPU_vertformat_alias_add(&format, "ac");
+ }
+ /* Gather number of auto layers. */
+ /* We only do vcols that are not overridden by uvs */
+ if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) {
+ BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
+ GPU_vertformat_alias_add(&format, attr_name);
+ }
+ }
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len);
+
+ MLoopCol *vcol_data = (MLoopCol *)vbo->data;
+ for (int i = 0; i < 8; i++) {
+ if (vcol_layers & (1 << i)) {
+ void *layer_data = CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i);
+ memcpy(vcol_data, layer_data, sizeof(*vcol_data) * mr->loop_len);
+ vcol_data += mr->loop_len;
+ }
+ }
+ return NULL;
+}
+
+const MeshExtract extract_vcol = {
+ extract_vcol_init, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, false};
+
+/** \} */ /** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Orco
+ * \{ */
+
+typedef struct MeshExtract_Orco_Data {
+ float (*vbo_data)[4];
+ float (*orco)[3];
+} MeshExtract_Orco_Data;
+
+static void *extract_orco_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex
+ * attribs. This is a substantial waste of Vram and should be done another way.
+ * Unfortunately, at the time of writing, I did not found any other "non disruptive"
+ * alternative. */
+ GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len);
+
+ CustomData *cd_vdata = &mr->me->vdata;
+
+ MeshExtract_Orco_Data *data = MEM_mallocN(sizeof(*data), __func__);
+ data->vbo_data = (float(*)[4])vbo->data;
+ data->orco = CustomData_get_layer(cd_vdata, CD_ORCO);
+ /* Make sure orco layer was requested only if needed! */
+ BLI_assert(data->orco);
+ return data;
+}
+
+static void extract_orco_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *data)
+{
+ MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data;
+ float *loop_orco = orco_data->vbo_data[l];
+ copy_v3_v3(loop_orco, orco_data->orco[BM_elem_index_get(loop->v)]);
+ loop_orco[3] = 0.0; /* Tag as not a generic attrib */
+}
+
+static void extract_orco_loop_mesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ const MLoop *mloop,
+ int UNUSED(p),
+ const MPoly *UNUSED(mpoly),
+ void *data)
+{
+ MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data;
+ float *loop_orco = orco_data->vbo_data[l];
+ copy_v3_v3(loop_orco, orco_data->orco[mloop->v]);
+ loop_orco[3] = 0.0; /* Tag as not a generic attrib */
+}
+
+static void extract_orco_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(buf), void *data)
+{
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_orco = {extract_orco_init,
+ NULL,
+ NULL,
+ extract_orco_loop_bmesh,
+ extract_orco_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_orco_finish,
+ 0,
+ true};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edge Factor
+ * Defines how much an edge is visible.
+ * \{ */
+
+typedef struct MeshExtract_EdgeFac_Data {
+ uchar *vbo_data;
+ bool use_edge_render;
+ /* Number of loop per edge. */
+ uchar edge_loop_count[0];
+} MeshExtract_EdgeFac_Data;
+
+static float loop_edge_factor_get(const float f_no[3],
+ const float v_co[3],
+ const float v_no[3],
+ const float v_next_co[3])
+{
+ float enor[3], evec[3];
+ sub_v3_v3v3(evec, v_next_co, v_co);
+ cross_v3_v3v3(enor, v_no, evec);
+ normalize_v3(enor);
+ float d = fabsf(dot_v3v3(enor, f_no));
+ /* Rescale to the slider range. */
+ d *= (1.0f / 0.065f);
+ CLAMP(d, 0.0f, 1.0f);
+ return d;
+}
+
+static void *extract_edge_fac_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
+
+ MeshExtract_EdgeFac_Data *data;
+
+ if (mr->extract_type == MR_EXTRACT_MESH) {
+ size_t edge_loop_count_size = sizeof(uint32_t) * mr->edge_len;
+ data = MEM_callocN(sizeof(*data) + edge_loop_count_size, __func__);
+
+ /* HACK(fclem) Detecting the need for edge render.
+ * We could have a flag in the mesh instead or check the modifier stack. */
+ const MEdge *medge = mr->medge;
+ for (int e = 0; e < mr->edge_len; e++, medge++) {
+ if ((medge->flag & ME_EDGERENDER) == 0) {
+ data->use_edge_render = true;
+ break;
+ }
+ }
+ }
+ else {
+ data = MEM_callocN(sizeof(*data), __func__);
+ /* HACK to bypass non-manifold check in mesh_edge_fac_finish(). */
+ data->use_edge_render = true;
+ }
+
+ data->vbo_data = vbo->data;
+ return data;
+}
+
+static void extract_edge_fac_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *_data)
+{
+ MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data;
+ if (BM_edge_is_manifold(loop->e)) {
+ float ratio = loop_edge_factor_get(loop->f->no, loop->v->co, loop->v->no, loop->next->v->co);
+ data->vbo_data[l] = ratio * 253 + 1;
+ }
+ else {
+ data->vbo_data[l] = 255;
+ }
+}
+
+static void extract_edge_fac_loop_mesh(
+ const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *_data)
+{
+ MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data;
+ if (data->use_edge_render) {
+ const MEdge *medge = &mr->medge[mloop->e];
+ data->vbo_data[l] = (medge->flag & ME_EDGERENDER) ? 255 : 0;
+ }
+ else {
+ /* Count loop per edge to detect non-manifold. */
+ if (data->edge_loop_count[mloop->e] < 3) {
+ data->edge_loop_count[mloop->e]++;
+ }
+ if (data->edge_loop_count[mloop->e] == 2) {
+ /* Manifold */
+ int loopend = mpoly->totloop + mpoly->loopstart - 1;
+ int other_loop = (l == loopend) ? mpoly->loopstart : (l + 1);
+ const MLoop *mloop_next = &mr->mloop[other_loop];
+ const MVert *v1 = &mr->mvert[mloop->v];
+ const MVert *v2 = &mr->mvert[mloop_next->v];
+ float vnor_f[3];
+ normal_short_to_float_v3(vnor_f, v1->no);
+ float ratio = loop_edge_factor_get(mr->poly_normals[p], v1->co, vnor_f, v2->co);
+ data->vbo_data[l] = ratio * 253 + 1;
+ }
+ else {
+ /* Non-manifold */
+ data->vbo_data[l] = 255;
+ }
+ }
+}
+
+static void extract_edge_fac_ledge_bmesh(const MeshRenderData *mr,
+ int e,
+ BMEdge *UNUSED(eed),
+ void *_data)
+{
+ MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data;
+ data->vbo_data[mr->loop_len + e * 2 + 0] = 255;
+ data->vbo_data[mr->loop_len + e * 2 + 1] = 255;
+}
+
+static void extract_edge_fac_ledge_mesh(const MeshRenderData *mr,
+ int e,
+ const MEdge *UNUSED(edge),
+ void *_data)
+{
+ MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data;
+ data->vbo_data[mr->loop_len + e * 2 + 0] = 255;
+ data->vbo_data[mr->loop_len + e * 2 + 1] = 255;
+}
+
+static void extract_edge_fac_finish(const MeshRenderData *mr, void *buf, void *_data)
+{
+ MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data;
+
+ if (GPU_crappy_amd_driver()) {
+ GPUVertBuf *vbo = (GPUVertBuf *)buf;
+ /* Some AMD drivers strangely crash with VBOs with a one byte format.
+ * To workaround we reinit the vbo with another format and convert
+ * all bytes to floats. */
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "wd", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+ /* We keep the data reference in data->vbo_data. */
+ vbo->data = NULL;
+ GPU_vertbuf_clear(vbo);
+
+ int buf_len = mr->loop_len + mr->loop_loose_len;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, buf_len);
+
+ float *fdata = (float *)vbo->data;
+ for (int l = 0; l < buf_len; l++, fdata++) {
+ *fdata = data->vbo_data[l] / 255.0f;
+ }
+ /* Free old byte data. */
+ MEM_freeN(data->vbo_data);
+ }
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_edge_fac = {extract_edge_fac_init,
+ NULL,
+ NULL,
+ extract_edge_fac_loop_bmesh,
+ extract_edge_fac_loop_mesh,
+ extract_edge_fac_ledge_bmesh,
+ extract_edge_fac_ledge_mesh,
+ NULL,
+ NULL,
+ extract_edge_fac_finish,
+ MR_DATA_POLY_NOR,
+ false};
+
+/** \} */
+/* ---------------------------------------------------------------------- */
+/** \name Extract Vertex Weight
+ * \{ */
+
+typedef struct MeshExtract_Weight_Data {
+ float *vbo_data;
+ const DRW_MeshWeightState *wstate;
+ const MDeformVert *dvert; /* For Mesh. */
+ int cd_ofs; /* For BMesh. */
+} MeshExtract_Weight_Data;
+
+static float evaluate_vertex_weight(const MDeformVert *dvert, const DRW_MeshWeightState *wstate)
+{
+ /* Error state. */
+ if ((wstate->defgroup_active < 0) && (wstate->defgroup_len > 0)) {
+ return -2.0f;
+ }
+ else if (dvert == NULL) {
+ return (wstate->alert_mode != OB_DRAW_GROUPUSER_NONE) ? -1.0f : 0.0f;
+ }
+
+ float input = 0.0f;
+ if (wstate->flags & DRW_MESH_WEIGHT_STATE_MULTIPAINT) {
+ /* Multi-Paint feature */
+ input = BKE_defvert_multipaint_collective_weight(
+ dvert,
+ wstate->defgroup_len,
+ wstate->defgroup_sel,
+ wstate->defgroup_sel_count,
+ (wstate->flags & DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE) != 0);
+ /* make it black if the selected groups have no weight on a vertex */
+ if (input == 0.0f) {
+ return -1.0f;
+ }
+ }
+ else {
+ /* default, non tricky behavior */
+ input = defvert_find_weight(dvert, wstate->defgroup_active);
+
+ if (input == 0.0f) {
+ switch (wstate->alert_mode) {
+ case OB_DRAW_GROUPUSER_ACTIVE:
+ return -1.0f;
+ break;
+ case OB_DRAW_GROUPUSER_ALL:
+ if (defvert_is_weight_zero(dvert, wstate->defgroup_len)) {
+ return -1.0f;
+ }
+ break;
+ }
+ }
+ }
+ CLAMP(input, 0.0f, 1.0f);
+ return input;
+}
+
+static void *extract_weights_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
+
+ MeshExtract_Weight_Data *data = MEM_callocN(sizeof(*data), __func__);
+ data->vbo_data = (float *)vbo->data;
+ data->wstate = &mr->cache->weight_state;
+
+ if (data->wstate->defgroup_active == -1) {
+ /* Nothing to show. */
+ data->dvert = NULL;
+ data->cd_ofs = -1;
+ }
+ else if (mr->extract_type == MR_EXTRACT_BMESH) {
+ data->dvert = NULL;
+ data->cd_ofs = CustomData_get_offset(&mr->bm->vdata, CD_MDEFORMVERT);
+ }
+ else {
+ data->dvert = CustomData_get_layer(&mr->me->vdata, CD_MDEFORMVERT);
+ data->cd_ofs = -1;
+ }
+ return data;
+}
+
+static void extract_weights_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *_data)
+{
+ MeshExtract_Weight_Data *data = (MeshExtract_Weight_Data *)_data;
+ const MDeformVert *dvert = (data->cd_ofs != -1) ? BM_ELEM_CD_GET_VOID_P(loop->v, data->cd_ofs) :
+ NULL;
+ data->vbo_data[l] = evaluate_vertex_weight(dvert, data->wstate);
+}
+
+static void extract_weights_loop_mesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ const MLoop *mloop,
+ int UNUSED(p),
+ const MPoly *UNUSED(mpoly),
+ void *_data)
+{
+ MeshExtract_Weight_Data *data = (MeshExtract_Weight_Data *)_data;
+ const MDeformVert *dvert = data->dvert ? &data->dvert[mloop->v] : NULL;
+ data->vbo_data[l] = evaluate_vertex_weight(dvert, data->wstate);
+}
+
+static void extract_weights_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(buf), void *data)
+{
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_weights = {extract_weights_init,
+ NULL,
+ NULL,
+ extract_weights_loop_bmesh,
+ extract_weights_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_weights_finish,
+ 0,
+ true};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edit Mode Data / Flags
+ * \{ */
+
+typedef struct EditLoopData {
+ uchar v_flag;
+ uchar e_flag;
+ uchar crease;
+ uchar bweight;
+} EditLoopData;
+
+static void mesh_render_data_face_flag(const MeshRenderData *mr,
+ BMFace *efa,
+ const int cd_ofs,
+ EditLoopData *eattr)
+{
+ if (efa == mr->efa_act) {
+ eattr->v_flag |= VFLAG_FACE_ACTIVE;
+ }
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ eattr->v_flag |= VFLAG_FACE_SELECTED;
+ }
+
+ if (efa == mr->efa_act_uv) {
+ eattr->v_flag |= VFLAG_FACE_UV_ACTIVE;
+ }
+ if ((cd_ofs != -1) && uvedit_face_select_test_ex(mr->toolsettings, (BMFace *)efa, cd_ofs)) {
+ eattr->v_flag |= VFLAG_FACE_UV_SELECT;
+ }
+
+#ifdef WITH_FREESTYLE
+ if (mr->freestyle_face_ofs != -1) {
+ const FreestyleFace *ffa = BM_ELEM_CD_GET_VOID_P(efa, mr->freestyle_face_ofs);
+ if (ffa->flag & FREESTYLE_FACE_MARK) {
+ eattr->v_flag |= VFLAG_FACE_FREESTYLE;
+ }
+ }
+#endif
+}
+
+static void mesh_render_data_edge_flag(const MeshRenderData *mr, BMEdge *eed, EditLoopData *eattr)
+{
+ const ToolSettings *ts = mr->toolsettings;
+ const bool is_vertex_select_mode = (ts != NULL) && (ts->selectmode & SCE_SELECT_VERTEX) != 0;
+ const bool is_face_only_select_mode = (ts != NULL) && (ts->selectmode == SCE_SELECT_FACE);
+
+ if (eed == mr->eed_act) {
+ eattr->e_flag |= VFLAG_EDGE_ACTIVE;
+ }
+ if (!is_vertex_select_mode && BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ eattr->e_flag |= VFLAG_EDGE_SELECTED;
+ }
+ if (is_vertex_select_mode && BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) &&
+ BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) {
+ eattr->e_flag |= VFLAG_EDGE_SELECTED;
+ eattr->e_flag |= VFLAG_VERT_SELECTED;
+ }
+ if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
+ eattr->e_flag |= VFLAG_EDGE_SEAM;
+ }
+ if (!BM_elem_flag_test(eed, BM_ELEM_SMOOTH)) {
+ eattr->e_flag |= VFLAG_EDGE_SHARP;
+ }
+
+ /* Use active edge color for active face edges because
+ * specular highlights make it hard to see T55456#510873.
+ *
+ * This isn't ideal since it can't be used when mixing edge/face modes
+ * but it's still better then not being able to see the active face. */
+ if (is_face_only_select_mode) {
+ if (mr->efa_act != NULL) {
+ if (BM_edge_in_face(eed, mr->efa_act)) {
+ eattr->e_flag |= VFLAG_EDGE_ACTIVE;
+ }
+ }
+ }
+
+ /* Use a byte for value range */
+ if (mr->crease_ofs != -1) {
+ float crease = BM_ELEM_CD_GET_FLOAT(eed, mr->crease_ofs);
+ if (crease > 0) {
+ eattr->crease = (uchar)(crease * 255.0f);
+ }
+ }
+ /* Use a byte for value range */
+ if (mr->bweight_ofs != -1) {
+ float bweight = BM_ELEM_CD_GET_FLOAT(eed, mr->bweight_ofs);
+ if (bweight > 0) {
+ eattr->bweight = (uchar)(bweight * 255.0f);
+ }
+ }
+#ifdef WITH_FREESTYLE
+ if (mr->freestyle_edge_ofs != -1) {
+ const FreestyleEdge *fed = BM_ELEM_CD_GET_VOID_P(eed, mr->freestyle_edge_ofs);
+ if (fed->flag & FREESTYLE_EDGE_MARK) {
+ eattr->e_flag |= VFLAG_EDGE_FREESTYLE;
+ }
+ }
+#endif
+}
+
+static void mesh_render_data_loop_flag(const MeshRenderData *mr,
+ BMLoop *loop,
+ const int cd_ofs,
+ EditLoopData *eattr)
+{
+ if (cd_ofs == -1) {
+ return;
+ }
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, cd_ofs);
+ if (luv != NULL && (luv->flag & MLOOPUV_PINNED)) {
+ eattr->v_flag |= VFLAG_VERT_UV_PINNED;
+ }
+ if (uvedit_uv_select_test_ex(mr->toolsettings, loop, cd_ofs)) {
+ eattr->v_flag |= VFLAG_VERT_UV_SELECT;
+ }
+}
+
+static void mesh_render_data_loop_edge_flag(const MeshRenderData *mr,
+ BMLoop *loop,
+ const int cd_ofs,
+ EditLoopData *eattr)
+{
+ if (cd_ofs == -1) {
+ return;
+ }
+ if (uvedit_edge_select_test_ex(mr->toolsettings, loop, cd_ofs)) {
+ eattr->v_flag |= VFLAG_EDGE_UV_SELECT;
+ eattr->v_flag |= VFLAG_VERT_UV_SELECT;
+ }
+}
+
+static void mesh_render_data_vert_flag(const MeshRenderData *mr, BMVert *eve, EditLoopData *eattr)
+{
+ if (eve == mr->eve_act) {
+ eattr->e_flag |= VFLAG_VERT_ACTIVE;
+ }
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ eattr->e_flag |= VFLAG_VERT_SELECTED;
+ }
+}
+
+static void *extract_edit_data_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* WARNING Adjust EditLoopData struct accordingly. */
+ GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT);
+ GPU_vertformat_alias_add(&format, "flag");
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
+ return vbo->data;
+}
+
+static void extract_edit_data_loop_bmesh(const MeshRenderData *mr,
+ int l,
+ BMLoop *loop,
+ void *_data)
+{
+ EditLoopData *data = (EditLoopData *)_data + l;
+ memset(data, 0x0, sizeof(*data));
+ mesh_render_data_face_flag(mr, loop->f, -1, data);
+ mesh_render_data_edge_flag(mr, loop->e, data);
+ mesh_render_data_vert_flag(mr, loop->v, data);
+}
+
+static void extract_edit_data_loop_mesh(const MeshRenderData *mr,
+ int l,
+ const MLoop *mloop,
+ int p,
+ const MPoly *UNUSED(mpoly),
+ void *_data)
+{
+ EditLoopData *data = (EditLoopData *)_data + l;
+ memset(data, 0x0, sizeof(*data));
+ BMFace *efa = bm_original_face_get(mr, p);
+ BMEdge *eed = bm_original_edge_get(mr, mloop->e);
+ BMVert *eve = bm_original_vert_get(mr, mloop->v);
+ if (efa) {
+ mesh_render_data_face_flag(mr, efa, -1, data);
+ }
+ if (eed) {
+ mesh_render_data_edge_flag(mr, eed, data);
+ }
+ if (eve) {
+ mesh_render_data_vert_flag(mr, eve, data);
+ }
+}
+
+static void extract_edit_data_ledge_bmesh(const MeshRenderData *mr,
+ int e,
+ BMEdge *eed,
+ void *_data)
+{
+ EditLoopData *data = (EditLoopData *)_data + mr->loop_len + e * 2;
+ memset(data, 0x0, sizeof(*data) * 2);
+ mesh_render_data_edge_flag(mr, eed, &data[0]);
+ data[1] = data[0];
+ mesh_render_data_vert_flag(mr, eed->v1, &data[0]);
+ mesh_render_data_vert_flag(mr, eed->v2, &data[1]);
+}
+
+static void extract_edit_data_ledge_mesh(const MeshRenderData *mr,
+ int e,
+ const MEdge *edge,
+ void *_data)
+{
+ EditLoopData *data = (EditLoopData *)_data + mr->loop_len + e * 2;
+ memset(data, 0x0, sizeof(*data) * 2);
+ int e_idx = mr->ledges[e];
+ BMEdge *eed = bm_original_edge_get(mr, e_idx);
+ BMVert *eve1 = bm_original_vert_get(mr, edge->v1);
+ BMVert *eve2 = bm_original_vert_get(mr, edge->v2);
+ if (eed) {
+ mesh_render_data_edge_flag(mr, eed, &data[0]);
+ data[1] = data[0];
+ }
+ if (eve1) {
+ mesh_render_data_vert_flag(mr, eve1, &data[0]);
+ }
+ if (eve2) {
+ mesh_render_data_vert_flag(mr, eve2, &data[1]);
+ }
+}
+
+static void extract_edit_data_lvert_bmesh(const MeshRenderData *mr,
+ int v,
+ BMVert *eve,
+ void *_data)
+{
+ EditLoopData *data = (EditLoopData *)_data + mr->loop_len + mr->edge_loose_len * 2 + v;
+ memset(data, 0x0, sizeof(*data));
+ mesh_render_data_vert_flag(mr, eve, data);
+}
+
+static void extract_edit_data_lvert_mesh(const MeshRenderData *mr,
+ int v,
+ const MVert *UNUSED(mvert),
+ void *_data)
+{
+ EditLoopData *data = (EditLoopData *)_data + mr->loop_len + mr->edge_loose_len * 2 + v;
+ memset(data, 0x0, sizeof(*data));
+ int v_idx = mr->lverts[v];
+ BMVert *eve = bm_original_vert_get(mr, v_idx);
+ if (eve) {
+ mesh_render_data_vert_flag(mr, eve, data);
+ }
+}
+
+const MeshExtract extract_edit_data = {extract_edit_data_init,
+ NULL,
+ NULL,
+ extract_edit_data_loop_bmesh,
+ extract_edit_data_loop_mesh,
+ extract_edit_data_ledge_bmesh,
+ extract_edit_data_ledge_mesh,
+ extract_edit_data_lvert_bmesh,
+ extract_edit_data_lvert_mesh,
+ NULL,
+ 0,
+ true};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edit UV Data / Flags
+ * \{ */
+
+typedef struct MeshExtract_EditUVData_Data {
+ EditLoopData *vbo_data;
+ int cd_ofs;
+} MeshExtract_EditUVData_Data;
+
+static void *extract_edituv_data_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* WARNING Adjust EditLoopData struct accordingly. */
+ GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT);
+ GPU_vertformat_alias_add(&format, "flag");
+ }
+
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len);
+
+ CustomData *cd_ldata = &mr->me->ldata;
+
+ MeshExtract_EditUVData_Data *data = MEM_callocN(sizeof(*data), __func__);
+ data->vbo_data = (EditLoopData *)vbo->data;
+ data->cd_ofs = CustomData_get_offset(cd_ldata, CD_MLOOPUV);
+ return data;
+}
+
+static void extract_edituv_data_loop_bmesh(const MeshRenderData *mr,
+ int l,
+ BMLoop *loop,
+ void *_data)
+{
+ MeshExtract_EditUVData_Data *data = (MeshExtract_EditUVData_Data *)_data;
+ EditLoopData *eldata = data->vbo_data + l;
+ memset(eldata, 0x0, sizeof(*eldata));
+ mesh_render_data_loop_flag(mr, loop, data->cd_ofs, eldata);
+ mesh_render_data_loop_edge_flag(mr, loop, data->cd_ofs, eldata);
+}
+
+static void extract_edituv_data_loop_mesh(
+ const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *_data)
+{
+ MeshExtract_EditUVData_Data *data = (MeshExtract_EditUVData_Data *)_data;
+ EditLoopData *eldata = data->vbo_data + l;
+ memset(eldata, 0x0, sizeof(*eldata));
+ BMFace *efa = bm_original_face_get(mr, p);
+ if (efa) {
+ BMEdge *eed = bm_original_edge_get(mr, mloop->e);
+ BMVert *eve = bm_original_vert_get(mr, mloop->v);
+ if (eed && eve) {
+ /* Loop on an edge endpoint. */
+ BMLoop *loop = BM_face_edge_share_loop(efa, eed);
+ mesh_render_data_loop_flag(mr, loop, data->cd_ofs, eldata);
+ mesh_render_data_loop_edge_flag(mr, loop, data->cd_ofs, eldata);
+ }
+ else {
+ if (eed == NULL) {
+ /* Find if the loop's vert is not part of an edit edge.
+ * For this, we check if the previous loop was on an edge. */
+ int loopend = mpoly->loopstart + mpoly->totloop - 1;
+ int l_prev = (l == mpoly->loopstart) ? loopend : (l - 1);
+ const MLoop *mloop_prev = &mr->mloop[l_prev];
+ eed = bm_original_edge_get(mr, mloop_prev->e);
+ }
+ if (eed) {
+ /* Mapped points on an edge between two edit verts. */
+ BMLoop *loop = BM_face_edge_share_loop(efa, eed);
+ mesh_render_data_loop_edge_flag(mr, loop, data->cd_ofs, eldata);
+ }
+ }
+ }
+}
+
+static void extract_edituv_data_finish(const MeshRenderData *UNUSED(mr),
+ void *UNUSED(buf),
+ void *data)
+{
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_edituv_data = {extract_edituv_data_init,
+ NULL,
+ NULL,
+ extract_edituv_data_loop_bmesh,
+ extract_edituv_data_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_edituv_data_finish,
+ 0,
+ true};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edit UV area stretch
+ * \{ */
+
+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);
+ }
+
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len);
+
+ return NULL;
+}
+
+BLI_INLINE float area_ratio_get(float area, float uvarea)
+{
+ if (area >= FLT_EPSILON && uvarea >= FLT_EPSILON) {
+ /* Tag inversion by using the sign. */
+ return (area > uvarea) ? (uvarea / area) : -(area / uvarea);
+ }
+ return 0.0f;
+}
+
+BLI_INLINE 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;
+}
+
+static void mesh_stretch_area_finish(const MeshRenderData *mr, void *buf, void *UNUSED(data))
+{
+ float totarea = 0, totuvarea = 0;
+ float *area_ratio = MEM_mallocN(sizeof(float) * mr->poly_len, __func__);
+
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ CustomData *cd_ldata = &mr->bm->ldata;
+ int uv_ofs = CustomData_get_offset(cd_ldata, CD_MLOOPUV);
+
+ BMFace *efa;
+ BMIter f_iter;
+ int f;
+ 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;
+ area_ratio[f] = area_ratio_get(area, uvarea);
+ }
+ }
+ else if (mr->extract_type == MR_EXTRACT_MAPPED) {
+ const MLoopUV *uv_data = CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
+ const MPoly *mpoly = mr->mpoly;
+ 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;
+ area_ratio[p] = area_ratio_get(area, uvarea);
+ }
+ }
+ else {
+ /* Should not happen. */
+ 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;
+ }
+
+ /* 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;
+ }
+
+ /* Copy face data for each loop. */
+ GPUVertBuf *vbo = buf;
+ uint16_t *loop_stretch = (uint16_t *)vbo->data;
+
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ BMFace *efa;
+ BMIter f_iter;
+ int f, l = 0;
+ BM_ITER_MESH_INDEX (efa, &f_iter, mr->bm, BM_FACES_OF_MESH, f) {
+ for (int i = 0; i < efa->len; i++, l++) {
+ loop_stretch[l] = poly_stretch[f];
+ }
+ }
+ }
+ else if (mr->extract_type == MR_EXTRACT_MAPPED) {
+ const MPoly *mpoly = mr->mpoly;
+ for (int p = 0, l = 0; p < mr->poly_len; p++, mpoly++) {
+ for (int i = 0; i < mpoly->totloop; i++, l++) {
+ loop_stretch[l] = poly_stretch[p];
+ }
+ }
+ }
+ else {
+ /* Should not happen. */
+ BLI_assert(0);
+ }
+
+ MEM_freeN(area_ratio);
+}
+
+const MeshExtract extract_stretch_area = {extract_stretch_area_init,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ mesh_stretch_area_finish,
+ 0,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edit UV angle stretch
+ * \{ */
+
+typedef struct UVStretchAngle {
+ int16_t angle;
+ int16_t uv_angles[2];
+} UVStretchAngle;
+
+typedef struct MeshExtract_StretchAngle_Data {
+ UVStretchAngle *vbo_data;
+ MLoopUV *luv;
+ float auv[2][2], last_auv[2];
+ float av[2][3], last_av[3];
+ int cd_ofs;
+} MeshExtract_StretchAngle_Data;
+
+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])
+{
+ /* Move previous edge. */
+ copy_v2_v2(auv[0], auv[1]);
+ copy_v3_v3(av[0], av[1]);
+ /* 2d edge */
+ sub_v2_v2v2(auv[1], uv_prev, uv);
+ normalize_v2(auv[1]);
+ /* 3d edge */
+ sub_v3_v3v3(av[1], co_prev, co);
+ normalize_v3(av[1]);
+}
+
+static short v2_to_short_angle(float v[2])
+{
+ return atan2f(v[1], v[0]) * (float)M_1_PI * SHRT_MAX;
+}
+
+static void edituv_get_stretch_angle(float auv[2][2], float av[2][3], UVStretchAngle *r_stretch)
+{
+ /* Send uvs to the shader and let it compute the aspect corrected angle. */
+ r_stretch->uv_angles[0] = v2_to_short_angle(auv[0]);
+ r_stretch->uv_angles[1] = v2_to_short_angle(auv[1]);
+ /* Compute 3D angle here. */
+ r_stretch->angle = angle_normalized_v3v3(av[0], av[1]) * (float)M_1_PI * SHRT_MAX;
+
+#if 0 /* here for reference, this is done in shader now. */
+ float uvang = angle_normalized_v2v2(auv0, auv1);
+ float ang = angle_normalized_v3v3(av0, av1);
+ float stretch = fabsf(uvang - ang) / (float)M_PI;
+ return 1.0f - pow2f(1.0f - stretch);
+#endif
+}
+
+static void *extract_stretch_angle_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* WARNING Adjust UVStretchAngle struct accordingly. */
+ GPU_vertformat_attr_add(&format, "angle", GPU_COMP_I16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ GPU_vertformat_attr_add(&format, "uv_angles", GPU_COMP_I16, 2, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len);
+
+ MeshExtract_StretchAngle_Data *data = MEM_callocN(sizeof(*data), __func__);
+ data->vbo_data = (UVStretchAngle *)vbo->data;
+
+ /* Special iter nneded to save about half of the computing cost. */
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV);
+ }
+ else if (mr->extract_type == MR_EXTRACT_MAPPED) {
+ data->luv = CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
+ }
+ else {
+ BLI_assert(0);
+ }
+ return data;
+}
+
+static void extract_stretch_angle_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *_data)
+{
+ MeshExtract_StretchAngle_Data *data = (MeshExtract_StretchAngle_Data *)_data;
+ float(*auv)[2] = data->auv, *last_auv = data->last_auv;
+ float(*av)[3] = data->av, *last_av = data->last_av;
+ const MLoopUV *luv, *luv_next;
+ BMLoop *l_next = loop->next;
+ BMFace *efa = loop->f;
+ if (loop == efa->l_first) {
+ /* First loop in face. */
+ BMLoop *l_tmp = loop->prev;
+ BMLoop *l_next_tmp = loop;
+ luv = BM_ELEM_CD_GET_VOID_P(l_tmp, data->cd_ofs);
+ luv_next = BM_ELEM_CD_GET_VOID_P(l_next_tmp, data->cd_ofs);
+ compute_normalize_edge_vectors(
+ auv, av, luv->uv, luv_next->uv, l_tmp->v->co, l_next_tmp->v->co);
+ /* Save last edge. */
+ copy_v2_v2(last_auv, auv[1]);
+ copy_v3_v3(last_av, av[1]);
+ }
+ if (l_next == efa->l_first) {
+ /* Move previous edge. */
+ copy_v2_v2(auv[0], auv[1]);
+ copy_v3_v3(av[0], av[1]);
+ /* Copy already calculated last edge. */
+ copy_v2_v2(auv[1], last_auv);
+ copy_v3_v3(av[1], last_av);
+ }
+ else {
+ luv = BM_ELEM_CD_GET_VOID_P(loop, data->cd_ofs);
+ luv_next = BM_ELEM_CD_GET_VOID_P(l_next, data->cd_ofs);
+ compute_normalize_edge_vectors(auv, av, luv->uv, luv_next->uv, loop->v->co, l_next->v->co);
+ }
+ edituv_get_stretch_angle(auv, av, data->vbo_data + l);
+}
+
+static void extract_stretch_angle_loop_mesh(const MeshRenderData *mr,
+ int l,
+ const MLoop *UNUSED(mloop),
+ int UNUSED(p),
+ const MPoly *mpoly,
+ void *_data)
+{
+ MeshExtract_StretchAngle_Data *data = (MeshExtract_StretchAngle_Data *)_data;
+ float(*auv)[2] = data->auv, *last_auv = data->last_auv;
+ float(*av)[3] = data->av, *last_av = data->last_av;
+ int l_next = l + 1, loopend = mpoly->loopstart + mpoly->totloop;
+ const MVert *v, *v_next;
+ if (l == mpoly->loopstart) {
+ /* First loop in face. */
+ int l_tmp = loopend - 1;
+ int l_next_tmp = mpoly->loopstart;
+ v = &mr->mvert[mr->mloop[l_tmp].v];
+ v_next = &mr->mvert[mr->mloop[l_next_tmp].v];
+ compute_normalize_edge_vectors(
+ auv, av, data->luv[l_tmp].uv, data->luv[l_next_tmp].uv, v->co, v_next->co);
+ /* Save last edge. */
+ copy_v2_v2(last_auv, auv[1]);
+ copy_v3_v3(last_av, av[1]);
+ }
+ if (l_next == loopend) {
+ l_next = mpoly->loopstart;
+ /* Move previous edge. */
+ copy_v2_v2(auv[0], auv[1]);
+ copy_v3_v3(av[0], av[1]);
+ /* Copy already calculated last edge. */
+ copy_v2_v2(auv[1], last_auv);
+ copy_v3_v3(av[1], last_av);
+ }
+ else {
+ v = &mr->mvert[mr->mloop[l].v];
+ v_next = &mr->mvert[mr->mloop[l_next].v];
+ compute_normalize_edge_vectors(
+ auv, av, data->luv[l].uv, data->luv[l_next].uv, v->co, v_next->co);
+ }
+ edituv_get_stretch_angle(auv, av, data->vbo_data + l);
+}
+
+static void extract_stretch_angle_finish(const MeshRenderData *UNUSED(mr),
+ void *UNUSED(buf),
+ void *data)
+{
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_stretch_angle = {extract_stretch_angle_init,
+ NULL,
+ NULL,
+ extract_stretch_angle_loop_bmesh,
+ extract_stretch_angle_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_stretch_angle_finish,
+ 0,
+ true};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Edit UV angle stretch
+ * \{ */
+
+static void *extract_mesh_analysis_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len);
+
+ return NULL;
+}
+
+static void axis_from_enum_v3(float v[3], const char axis)
+{
+ zero_v3(v);
+ if (axis < 3) {
+ v[axis] = 1.0f;
+ }
+ else {
+ v[axis - 3] = -1.0f;
+ }
+}
+
+BLI_INLINE float overhang_remap(float fac, float min, float max, float minmax_irange)
+{
+ if (fac < min) {
+ fac = 1.0f;
+ }
+ else if (fac > max) {
+ fac = -1.0f;
+ }
+ else {
+ fac = (fac - min) * minmax_irange;
+ fac = 1.0f - fac;
+ CLAMP(fac, 0.0f, 1.0f);
+ }
+ return fac;
+}
+
+static void statvis_calc_overhang(const MeshRenderData *mr, float *r_overhang)
+{
+ const MeshStatVis *statvis = &mr->toolsettings->statvis;
+ const float min = statvis->overhang_min / (float)M_PI;
+ const float max = statvis->overhang_max / (float)M_PI;
+ const char axis = statvis->overhang_axis;
+ BMEditMesh *em = mr->edit_bmesh;
+ BMIter iter;
+ BMesh *bm = em->bm;
+ BMFace *f;
+ float dir[3];
+ const float minmax_irange = 1.0f / (max - min);
+
+ BLI_assert(min <= max);
+
+ axis_from_enum_v3(dir, axis);
+
+ if (em && LIKELY(em->ob)) {
+ /* now convert into global space */
+ mul_transposed_mat3_m4_v3(em->ob->obmat, dir);
+ normalize_v3(dir);
+ }
+
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ int l = 0;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ float fac = angle_normalized_v3v3(f->no, dir) / (float)M_PI;
+ fac = overhang_remap(fac, min, max, minmax_irange);
+ for (int i = 0; i < f->len; i++, l++) {
+ r_overhang[l] = fac;
+ }
+ }
+ }
+ else {
+ const MPoly *mpoly = mr->mpoly;
+ for (int p = 0, l = 0; p < mr->poly_len; p++, mpoly++) {
+ float fac = angle_normalized_v3v3(mr->poly_normals[p], dir) / (float)M_PI;
+ fac = overhang_remap(fac, min, max, minmax_irange);
+ for (int i = 0; i < mpoly->totloop; i++, l++) {
+ r_overhang[l] = fac;
+ }
+ }
+ }
+}
+
+/* so we can use jitter values for face interpolation */
+static void uv_from_jitter_v2(float uv[2])
+{
+ uv[0] += 0.5f;
+ uv[1] += 0.5f;
+ if (uv[0] + uv[1] > 1.0f) {
+ uv[0] = 1.0f - uv[0];
+ uv[1] = 1.0f - uv[1];
+ }
+
+ CLAMP(uv[0], 0.0f, 1.0f);
+ CLAMP(uv[1], 0.0f, 1.0f);
+}
+
+BLI_INLINE float thickness_remap(float fac, float min, float max, float minmax_irange)
+{
+ /* important not '<=' */
+ if (fac < max) {
+ fac = (fac - min) * minmax_irange;
+ fac = 1.0f - fac;
+ CLAMP(fac, 0.0f, 1.0f);
+ }
+ else {
+ fac = -1.0f;
+ }
+ return fac;
+}
+
+static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness)
+{
+ const float eps_offset = 0.00002f; /* values <= 0.00001 give errors */
+ /* cheating to avoid another allocation */
+ float *face_dists = r_thickness + (mr->loop_len - mr->poly_len);
+ BMEditMesh *em = mr->edit_bmesh;
+ const float scale = 1.0f / mat4_to_scale(em->ob->obmat);
+ const MeshStatVis *statvis = &mr->toolsettings->statvis;
+ const float min = statvis->thickness_min * scale;
+ const float max = statvis->thickness_max * scale;
+ const float minmax_irange = 1.0f / (max - min);
+ const int samples = statvis->thickness_samples;
+ float jit_ofs[32][2];
+ BLI_assert(samples <= 32);
+ BLI_assert(min <= max);
+
+ copy_vn_fl(face_dists, mr->poly_len, max);
+
+ BLI_jitter_init(jit_ofs, samples);
+ for (int j = 0; j < samples; j++) {
+ uv_from_jitter_v2(jit_ofs[j]);
+ }
+
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ BMesh *bm = em->bm;
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
+
+ struct BMBVHTree *bmtree = BKE_bmbvh_new_from_editmesh(em, 0, NULL, false);
+ struct BMLoop *(*looptris)[3] = em->looptris;
+ for (int i = 0; i < mr->tri_len; i++) {
+ BMLoop **ltri = looptris[i];
+ const int index = BM_elem_index_get(ltri[0]->f);
+ const float *cos[3] = {ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co};
+ float ray_co[3];
+ float ray_no[3];
+
+ normal_tri_v3(ray_no, cos[2], cos[1], cos[0]);
+
+ for (int j = 0; j < samples; j++) {
+ float dist = face_dists[index];
+ interp_v3_v3v3v3_uv(ray_co, cos[0], cos[1], cos[2], jit_ofs[j]);
+ madd_v3_v3fl(ray_co, ray_no, eps_offset);
+
+ BMFace *f_hit = BKE_bmbvh_ray_cast(bmtree, ray_co, ray_no, 0.0f, &dist, NULL, NULL);
+ if (f_hit && dist < face_dists[index]) {
+ float angle_fac = fabsf(dot_v3v3(ltri[0]->f->no, f_hit->no));
+ angle_fac = 1.0f - angle_fac;
+ angle_fac = angle_fac * angle_fac * angle_fac;
+ angle_fac = 1.0f - angle_fac;
+ dist /= angle_fac;
+ if (dist < face_dists[index]) {
+ face_dists[index] = dist;
+ }
+ }
+ }
+ }
+ BKE_bmbvh_free(bmtree);
+
+ BMIter iter;
+ BMFace *f;
+ int l = 0;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ float fac = face_dists[BM_elem_index_get(f)];
+ fac = thickness_remap(fac, min, max, minmax_irange);
+ for (int i = 0; i < f->len; i++, l++) {
+ r_thickness[l] = fac;
+ }
+ }
+ }
+ else {
+ BVHTreeFromMesh treeData = {NULL};
+
+ BVHTree *tree = BKE_bvhtree_from_mesh_get(&treeData, mr->me, BVHTREE_FROM_LOOPTRI, 4);
+ const MLoopTri *mlooptri = mr->mlooptri;
+ for (int i = 0; i < mr->tri_len; i++, mlooptri++) {
+ const int index = mlooptri->poly;
+ const float *cos[3] = {mr->mvert[mr->mloop[mlooptri->tri[0]].v].co,
+ mr->mvert[mr->mloop[mlooptri->tri[1]].v].co,
+ mr->mvert[mr->mloop[mlooptri->tri[2]].v].co};
+ float ray_co[3];
+ float ray_no[3];
+
+ normal_tri_v3(ray_no, cos[2], cos[1], cos[0]);
+
+ for (int j = 0; j < samples; j++) {
+ interp_v3_v3v3v3_uv(ray_co, cos[0], cos[1], cos[2], jit_ofs[j]);
+ madd_v3_v3fl(ray_co, ray_no, eps_offset);
+
+ BVHTreeRayHit hit;
+ hit.index = -1;
+ hit.dist = face_dists[index];
+ if ((BLI_bvhtree_ray_cast(
+ tree, ray_co, ray_no, 0.0f, &hit, treeData.raycast_callback, &treeData) != -1) &&
+ hit.dist < face_dists[index]) {
+ float angle_fac = fabsf(dot_v3v3(mr->poly_normals[index], hit.no));
+ angle_fac = 1.0f - angle_fac;
+ angle_fac = angle_fac * angle_fac * angle_fac;
+ angle_fac = 1.0f - angle_fac;
+ hit.dist /= angle_fac;
+ if (hit.dist < face_dists[index]) {
+ face_dists[index] = hit.dist;
+ }
+ }
+ }
+ }
+
+ const MPoly *mpoly = mr->mpoly;
+ for (int p = 0, l = 0; p < mr->poly_len; p++, mpoly++) {
+ float fac = face_dists[p];
+ fac = thickness_remap(fac, min, max, minmax_irange);
+ for (int i = 0; i < mpoly->totloop; i++, l++) {
+ r_thickness[l] = fac;
+ }
+ }
+ }
+}
+
+struct BVHTree_OverlapData {
+ const Mesh *me;
+ const MLoopTri *mlooptri;
+ float epsilon;
+};
+
+static bool bvh_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
+{
+ struct BVHTree_OverlapData *data = userdata;
+ const Mesh *me = data->me;
+
+ const MLoopTri *tri_a = &data->mlooptri[index_a];
+ const MLoopTri *tri_b = &data->mlooptri[index_b];
+
+ if (UNLIKELY(tri_a->poly == tri_b->poly)) {
+ return false;
+ }
+
+ const float *tri_a_co[3] = {me->mvert[me->mloop[tri_a->tri[0]].v].co,
+ me->mvert[me->mloop[tri_a->tri[1]].v].co,
+ me->mvert[me->mloop[tri_a->tri[2]].v].co};
+ const float *tri_b_co[3] = {me->mvert[me->mloop[tri_b->tri[0]].v].co,
+ me->mvert[me->mloop[tri_b->tri[1]].v].co,
+ me->mvert[me->mloop[tri_b->tri[2]].v].co};
+ float ix_pair[2][3];
+ int verts_shared = 0;
+
+ verts_shared = (ELEM(tri_a_co[0], UNPACK3(tri_b_co)) + ELEM(tri_a_co[1], UNPACK3(tri_b_co)) +
+ ELEM(tri_a_co[2], UNPACK3(tri_b_co)));
+
+ /* if 2 points are shared, bail out */
+ if (verts_shared >= 2) {
+ return false;
+ }
+
+ return (isect_tri_tri_epsilon_v3(
+ UNPACK3(tri_a_co), UNPACK3(tri_b_co), ix_pair[0], ix_pair[1], data->epsilon) &&
+ /* if we share a vertex, check the intersection isn't a 'point' */
+ ((verts_shared == 0) || (len_squared_v3v3(ix_pair[0], ix_pair[1]) > data->epsilon)));
+}
+
+static void statvis_calc_intersect(const MeshRenderData *mr, float *r_intersect)
+{
+ BMEditMesh *em = mr->edit_bmesh;
+
+ for (int l = 0; l < mr->loop_len; l++) {
+ r_intersect[l] = -1.0f;
+ }
+
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ uint overlap_len;
+ BMesh *bm = em->bm;
+
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
+
+ struct BMBVHTree *bmtree = BKE_bmbvh_new_from_editmesh(em, 0, NULL, false);
+ BVHTreeOverlap *overlap = BKE_bmbvh_overlap(bmtree, bmtree, &overlap_len);
+
+ if (overlap) {
+ for (int i = 0; i < overlap_len; i++) {
+ BMFace *f_hit_pair[2] = {
+ em->looptris[overlap[i].indexA][0]->f,
+ em->looptris[overlap[i].indexB][0]->f,
+ };
+ for (int j = 0; j < 2; j++) {
+ BMFace *f_hit = f_hit_pair[j];
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f_hit);
+ int l = BM_elem_index_get(l_first);
+ for (int k = 0; k < f_hit->len; k++, l++) {
+ r_intersect[l] = 1.0f;
+ }
+ }
+ }
+ MEM_freeN(overlap);
+ }
+
+ BKE_bmbvh_free(bmtree);
+ }
+ else {
+ uint overlap_len;
+ BVHTreeFromMesh treeData = {NULL};
+
+ BVHTree *tree = BKE_bvhtree_from_mesh_get(&treeData, mr->me, BVHTREE_FROM_LOOPTRI, 4);
+
+ struct BVHTree_OverlapData data = {
+ .me = mr->me, .mlooptri = mr->mlooptri, .epsilon = BLI_bvhtree_get_epsilon(tree)};
+
+ BVHTreeOverlap *overlap = BLI_bvhtree_overlap(tree, tree, &overlap_len, bvh_overlap_cb, &data);
+ if (overlap) {
+ for (int i = 0; i < overlap_len; i++) {
+ const MPoly *f_hit_pair[2] = {
+ &mr->mpoly[mr->mlooptri[overlap[i].indexA].poly],
+ &mr->mpoly[mr->mlooptri[overlap[i].indexB].poly],
+ };
+ for (int j = 0; j < 2; j++) {
+ const MPoly *f_hit = f_hit_pair[j];
+ int l = f_hit->loopstart;
+ for (int k = 0; k < f_hit->totloop; k++, l++) {
+ r_intersect[l] = 1.0f;
+ }
+ }
+ }
+ MEM_freeN(overlap);
+ }
+ }
+}
+
+BLI_INLINE float distort_remap(float fac, float min, float UNUSED(max), float minmax_irange)
+{
+ if (fac >= min) {
+ fac = (fac - min) * minmax_irange;
+ CLAMP(fac, 0.0f, 1.0f);
+ }
+ else {
+ /* fallback */
+ fac = -1.0f;
+ }
+ return fac;
+}
+
+static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort)
+{
+ BMEditMesh *em = mr->edit_bmesh;
+ const MeshStatVis *statvis = &mr->toolsettings->statvis;
+ const float min = statvis->distort_min;
+ const float max = statvis->distort_max;
+ const float minmax_irange = 1.0f / (max - min);
+
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ BMIter iter;
+ BMesh *bm = em->bm;
+ BMFace *f;
+
+ int l = 0;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ float fac = -1.0f;
+
+ if (f->len > 3) {
+ BMLoop *l_iter, *l_first;
+
+ fac = 0.0f;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ float no_corner[3];
+ BM_loop_calc_face_normal_safe(l_iter, no_corner);
+ /* simple way to detect (what is most likely) concave */
+ if (dot_v3v3(f->no, no_corner) < 0.0f) {
+ negate_v3(no_corner);
+ }
+ fac = max_ff(fac, angle_normalized_v3v3(f->no, no_corner));
+ } while ((l_iter = l_iter->next) != l_first);
+ fac *= 2.0f;
+ }
+
+ fac = distort_remap(fac, min, max, minmax_irange);
+ for (int i = 0; i < f->len; i++, l++) {
+ r_distort[l] = fac;
+ }
+ }
+ }
+ else {
+ const MPoly *mpoly = mr->mpoly;
+ for (int p = 0, l = 0; p < mr->poly_len; p++, mpoly++) {
+ float fac = -1.0f;
+
+ if (mpoly->totloop > 3) {
+ float *f_no = mr->poly_normals[p];
+ fac = 0.0f;
+
+ for (int i = 1; i <= mpoly->totloop; i++) {
+ const MLoop *l_prev = &mr->mloop[mpoly->loopstart + (i - 1) % mpoly->totloop];
+ const MLoop *l_curr = &mr->mloop[mpoly->loopstart + (i + 0) % mpoly->totloop];
+ const MLoop *l_next = &mr->mloop[mpoly->loopstart + (i + 1) % mpoly->totloop];
+ float no_corner[3];
+ normal_tri_v3(no_corner,
+ mr->mvert[l_prev->v].co,
+ mr->mvert[l_curr->v].co,
+ mr->mvert[l_next->v].co);
+ /* simple way to detect (what is most likely) concave */
+ if (dot_v3v3(f_no, no_corner) < 0.0f) {
+ negate_v3(no_corner);
+ }
+ fac = max_ff(fac, angle_normalized_v3v3(f_no, no_corner));
+ }
+ fac *= 2.0f;
+ }
+
+ fac = distort_remap(fac, min, max, minmax_irange);
+ for (int i = 0; i < mpoly->totloop; i++, l++) {
+ r_distort[l] = fac;
+ }
+ }
+ }
+}
+
+BLI_INLINE float sharp_remap(float fac, float min, float UNUSED(max), float minmax_irange)
+{
+ /* important not '>=' */
+ if (fac > min) {
+ fac = (fac - min) * minmax_irange;
+ CLAMP(fac, 0.0f, 1.0f);
+ }
+ else {
+ /* fallback */
+ fac = -1.0f;
+ }
+ return fac;
+}
+
+static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp)
+{
+ BMEditMesh *em = mr->edit_bmesh;
+ const MeshStatVis *statvis = &mr->toolsettings->statvis;
+ const float min = statvis->sharp_min;
+ const float max = statvis->sharp_max;
+ const float minmax_irange = 1.0f / (max - min);
+
+ /* Can we avoid this extra allocation? */
+ float *vert_angles = MEM_mallocN(sizeof(float) * mr->vert_len, __func__);
+ copy_vn_fl(vert_angles, mr->vert_len, -M_PI);
+
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ BMIter iter, l_iter;
+ BMesh *bm = em->bm;
+ BMFace *efa;
+ BMEdge *e;
+ BMLoop *loop;
+ /* first assign float values to verts */
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ float angle = BM_edge_calc_face_angle_signed(e);
+ float *col1 = &vert_angles[BM_elem_index_get(e->v1)];
+ float *col2 = &vert_angles[BM_elem_index_get(e->v2)];
+ *col1 = max_ff(*col1, angle);
+ *col2 = max_ff(*col2, angle);
+ }
+ /* Copy vert value to loops. */
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) {
+ int l = BM_elem_index_get(loop);
+ int v = BM_elem_index_get(loop->v);
+ r_sharp[l] = sharp_remap(vert_angles[v], min, max, minmax_irange);
+ }
+ }
+ }
+ else {
+ /* first assign float values to verts */
+ const MPoly *mpoly = mr->mpoly;
+
+ EdgeHash *eh = BLI_edgehash_new_ex(__func__, mr->edge_len);
+
+ for (int p = 0; p < mr->poly_len; p++, mpoly++) {
+ for (int i = 0; i < mpoly->totloop; i++) {
+ const MLoop *l_curr = &mr->mloop[mpoly->loopstart + (i + 0) % mpoly->totloop];
+ const MLoop *l_next = &mr->mloop[mpoly->loopstart + (i + 1) % mpoly->totloop];
+ const MVert *v_curr = &mr->mvert[l_curr->v];
+ const MVert *v_next = &mr->mvert[l_next->v];
+ float angle;
+ void **pval;
+ bool value_is_init = BLI_edgehash_ensure_p(eh, l_curr->v, l_next->v, &pval);
+ if (!value_is_init) {
+ *pval = mr->poly_normals[p];
+ /* non-manifold edge, yet... */
+ continue;
+ }
+ else if (*pval != NULL) {
+ const float *f1_no = mr->poly_normals[p];
+ const float *f2_no = *pval;
+ angle = angle_normalized_v3v3(f1_no, f2_no);
+ angle = is_edge_convex_v3(v_curr->co, v_next->co, f1_no, f2_no) ? angle : -angle;
+ /* Tag as manifold. */
+ *pval = NULL;
+ }
+ else {
+ /* non-manifold edge */
+ angle = DEG2RADF(90.0f);
+ }
+ float *col1 = &vert_angles[l_curr->v];
+ float *col2 = &vert_angles[l_next->v];
+ *col1 = max_ff(*col1, angle);
+ *col2 = max_ff(*col2, angle);
+ }
+ }
+ /* Remaining non manifold edges. */
+ EdgeHashIterator *ehi = BLI_edgehashIterator_new(eh);
+ for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
+ if (BLI_edgehashIterator_getValue(ehi) != NULL) {
+ uint v1, v2;
+ const float angle = DEG2RADF(90.0f);
+ BLI_edgehashIterator_getKey(ehi, &v1, &v2);
+ float *col1 = &vert_angles[v1];
+ float *col2 = &vert_angles[v2];
+ *col1 = max_ff(*col1, angle);
+ *col2 = max_ff(*col2, angle);
+ }
+ }
+ BLI_edgehashIterator_free(ehi);
+ BLI_edgehash_free(eh, NULL);
+
+ const MLoop *mloop = mr->mloop;
+ for (int l = 0; l < mr->loop_len; l++, mloop++) {
+ r_sharp[l] = sharp_remap(vert_angles[mloop->v], min, max, minmax_irange);
+ }
+ }
+
+ MEM_freeN(vert_angles);
+}
+
+static void extract_mesh_analysis_finish(const MeshRenderData *mr, void *buf, void *UNUSED(data))
+{
+ BLI_assert(mr->edit_bmesh);
+
+ GPUVertBuf *vbo = buf;
+ float *l_weight = (float *)vbo->data;
+
+ switch (mr->toolsettings->statvis.type) {
+ case SCE_STATVIS_OVERHANG:
+ statvis_calc_overhang(mr, l_weight);
+ break;
+ case SCE_STATVIS_THICKNESS:
+ statvis_calc_thickness(mr, l_weight);
+ break;
+ case SCE_STATVIS_INTERSECT:
+ statvis_calc_intersect(mr, l_weight);
+ break;
+ case SCE_STATVIS_DISTORT:
+ statvis_calc_distort(mr, l_weight);
+ break;
+ case SCE_STATVIS_SHARP:
+ statvis_calc_sharp(mr, l_weight);
+ break;
+ }
+}
+
+const MeshExtract extract_mesh_analysis = {extract_mesh_analysis_init,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_mesh_analysis_finish,
+ /* This is not needed for all vis type.
+ * Maybe split into different extract. */
+ MR_DATA_POLY_NOR | MR_DATA_LOOPTRI,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Facedots positions
+ * \{ */
+
+static void *extract_fdots_pos_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->poly_len);
+ if (!mr->use_subsurf_fdots) {
+ /* Clear so we can accumulate on it. */
+ memset(vbo->data, 0x0, mr->poly_len * vbo->format.stride);
+ }
+ return vbo->data;
+}
+
+static void extract_fdots_pos_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int UNUSED(l),
+ BMLoop *loop,
+ void *data)
+{
+ float(*center)[3] = (float(*)[3])data;
+ float w = 1.0f / (float)loop->f->len;
+ madd_v3_v3fl(center[BM_elem_index_get(loop->f)], loop->v->co, w);
+}
+
+static void extract_fdots_pos_loop_mesh(const MeshRenderData *mr,
+ int UNUSED(l),
+ const MLoop *mloop,
+ int p,
+ const MPoly *mpoly,
+ void *data)
+{
+ float(*center)[3] = (float(*)[3])data;
+ const MVert *mvert = &mr->mvert[mloop->v];
+ if (mr->use_subsurf_fdots) {
+ if (mvert->flag & ME_VERT_FACEDOT) {
+ copy_v3_v3(center[p], mvert->co);
+ }
+ }
+ else {
+ float w = 1.0f / (float)mpoly->totloop;
+ madd_v3_v3fl(center[p], mvert->co, w);
+ }
+}
+
+const MeshExtract extract_fdots_pos = {extract_fdots_pos_init,
+ NULL,
+ NULL,
+ extract_fdots_pos_loop_bmesh,
+ extract_fdots_pos_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ true};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Facedots Normal and edit flag
+ * \{ */
+
+static void *extract_fdots_nor_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->poly_len);
+
+ return NULL;
+}
+
+static void extract_fdots_nor_finish(const MeshRenderData *mr, void *buf, void *UNUSED(data))
+{
+ GPUVertBuf *vbo = buf;
+ GPUPackedNormal *nor = (GPUPackedNormal *)vbo->data;
+ BMFace *efa;
+
+ /* Quicker than doing it for each loop. */
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ for (int f = 0; f < mr->poly_len; f++) {
+ efa = BM_face_at_index(mr->bm, f);
+ nor[f] = GPU_normal_convert_i10_v3(efa->no);
+ /* Select / Active Flag. */
+ nor[f].w = BM_elem_flag_test(efa, BM_ELEM_SELECT) ? ((efa == mr->efa_act) ? -1 : 1) : 0;
+ }
+ }
+ else {
+ for (int f = 0; f < mr->poly_len; f++) {
+ nor[f] = GPU_normal_convert_i10_v3(mr->poly_normals[f]);
+ if ((efa = bm_original_face_get(mr, f))) {
+ /* Select / Active Flag. */
+ nor[f].w = BM_elem_flag_test(efa, BM_ELEM_SELECT) ? ((efa == mr->efa_act) ? -1 : 1) : 0;
+ }
+ }
+ }
+}
+
+const MeshExtract extract_fdots_nor = {extract_fdots_nor_init,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_fdots_nor_finish,
+ MR_DATA_POLY_NOR,
+ false};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Facedots Normal and edit flag
+ * \{ */
+
+typedef struct MeshExtract_FdotUV_Data {
+ float (*vbo_data)[2];
+ MLoopUV *uv_data;
+} MeshExtract_FdotUV_Data;
+
+static void *extract_fdots_uv_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "u", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ GPU_vertformat_alias_add(&format, "au");
+ GPU_vertformat_alias_add(&format, "pos");
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->poly_len);
+
+ if (!mr->use_subsurf_fdots) {
+ /* Clear so we can accumulate on it. */
+ memset(vbo->data, 0x0, mr->poly_len * vbo->format.stride);
+ }
+
+ CustomData *cd_ldata = &mr->me->ldata;
+
+ MeshExtract_FdotUV_Data *data = MEM_callocN(sizeof(*data), __func__);
+ data->vbo_data = (float(*)[2])vbo->data;
+ data->uv_data = CustomData_get_layer(cd_ldata, CD_MLOOPUV);
+ return data;
+}
+
+static void extract_fdots_uv_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *_data)
+{
+ MeshExtract_FdotUV_Data *data = (MeshExtract_FdotUV_Data *)_data;
+ float w = 1.0f / (float)loop->f->len;
+ madd_v2_v2fl(data->vbo_data[BM_elem_index_get(loop->f)], data->uv_data[l].uv, w);
+}
+
+static void extract_fdots_uv_loop_mesh(
+ const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *_data)
+{
+ MeshExtract_FdotUV_Data *data = (MeshExtract_FdotUV_Data *)_data;
+ if (mr->use_subsurf_fdots) {
+ const MVert *mvert = &mr->mvert[mloop->v];
+ if (mvert->flag & ME_VERT_FACEDOT) {
+ copy_v2_v2(data->vbo_data[p], data->uv_data[l].uv);
+ }
+ }
+ else {
+ float w = 1.0f / (float)mpoly->totloop;
+ madd_v2_v2fl(data->vbo_data[p], data->uv_data[l].uv, w);
+ }
+}
+
+static void extract_fdots_uv_finish(const MeshRenderData *UNUSED(mr),
+ void *UNUSED(buf),
+ void *data)
+{
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_fdots_uv = {extract_fdots_uv_init,
+ NULL,
+ NULL,
+ extract_fdots_uv_loop_bmesh,
+ extract_fdots_uv_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_fdots_uv_finish,
+ 0,
+ true};
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Facedots Edit UV flag
+ * \{ */
+
+typedef struct MeshExtract_EditUVFdotData_Data {
+ EditLoopData *vbo_data;
+ int cd_ofs;
+} MeshExtract_EditUVFdotData_Data;
+
+static void *extract_fdots_edituv_data_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "flag", GPU_COMP_U8, 4, GPU_FETCH_INT);
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->poly_len);
+
+ MeshExtract_EditUVFdotData_Data *data = MEM_callocN(sizeof(*data), __func__);
+ data->vbo_data = (EditLoopData *)vbo->data;
+ data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV);
+ return data;
+}
+
+static void extract_fdots_edituv_data_loop_bmesh(const MeshRenderData *mr,
+ int UNUSED(l),
+ BMLoop *loop,
+ void *_data)
+{
+ MeshExtract_EditUVFdotData_Data *data = (MeshExtract_EditUVFdotData_Data *)_data;
+ EditLoopData *eldata = data->vbo_data + BM_elem_index_get(loop->f);
+ memset(eldata, 0x0, sizeof(*eldata));
+ mesh_render_data_face_flag(mr, loop->f, data->cd_ofs, eldata);
+}
+
+static void extract_fdots_edituv_data_loop_mesh(const MeshRenderData *mr,
+ int UNUSED(l),
+ const MLoop *UNUSED(mloop),
+ int p,
+ const MPoly *UNUSED(mpoly),
+ void *_data)
+{
+ MeshExtract_EditUVFdotData_Data *data = (MeshExtract_EditUVFdotData_Data *)_data;
+ EditLoopData *eldata = data->vbo_data + p;
+ memset(eldata, 0x0, sizeof(*eldata));
+ BMFace *efa = bm_original_face_get(mr, p);
+ if (efa) {
+ mesh_render_data_face_flag(mr, efa, data->cd_ofs, eldata);
+ }
+}
+
+static void extract_fdots_edituv_data_finish(const MeshRenderData *UNUSED(mr),
+ void *UNUSED(buf),
+ void *data)
+{
+ MEM_freeN(data);
+}
+
+const MeshExtract extract_fdots_edituv_data = {extract_fdots_edituv_data_init,
+ NULL,
+ NULL,
+ extract_fdots_edituv_data_loop_bmesh,
+ extract_fdots_edituv_data_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ extract_fdots_edituv_data_finish,
+ 0,
+ true};
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Selection Index
+ * \{ */
+
+static void *extract_select_idx_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* TODO rename "color" to something more descriptive. */
+ GPU_vertformat_attr_add(&format, "color", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
+ return vbo->data;
+}
+
+/* TODO Use glVertexID to get loop index and use the data structure on the CPU to retrieve the
+ * select element associated with this loop ID. This would remove the need for this separate index
+ * VBOs. We could upload the p/e/v_origindex as a buffer texture and sample it inside the shader to
+ * output original index. */
+
+static void extract_poly_idx_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *data)
+{
+ ((uint32_t *)data)[l] = BM_elem_index_get(loop->f);
+}
+
+static void extract_edge_idx_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *data)
+{
+ ((uint32_t *)data)[l] = BM_elem_index_get(loop->e);
+}
+
+static void extract_vert_idx_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int l,
+ BMLoop *loop,
+ void *data)
+{
+ ((uint32_t *)data)[l] = BM_elem_index_get(loop->v);
+}
+
+static void extract_edge_idx_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *data)
+{
+ ((uint32_t *)data)[mr->loop_len + e * 2 + 0] = BM_elem_index_get(eed);
+ ((uint32_t *)data)[mr->loop_len + e * 2 + 1] = BM_elem_index_get(eed);
+}
+
+static void extract_vert_idx_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge *eed, void *data)
+{
+ ((uint32_t *)data)[mr->loop_len + e * 2 + 0] = BM_elem_index_get(eed->v1);
+ ((uint32_t *)data)[mr->loop_len + e * 2 + 1] = BM_elem_index_get(eed->v2);
+}
+
+static void extract_vert_idx_lvert_bmesh(const MeshRenderData *mr, int v, BMVert *eve, void *data)
+{
+ ((uint32_t *)data)[mr->loop_len + mr->edge_loose_len * 2 + v] = BM_elem_index_get(eve);
+}
+
+static void extract_poly_idx_loop_mesh(const MeshRenderData *mr,
+ int l,
+ const MLoop *UNUSED(mloop),
+ int p,
+ const MPoly *UNUSED(mpoly),
+ void *data)
+{
+ ((uint32_t *)data)[l] = (mr->p_origindex) ? mr->p_origindex[p] : p;
+}
+
+static void extract_edge_idx_loop_mesh(const MeshRenderData *mr,
+ int l,
+ const MLoop *mloop,
+ int UNUSED(p),
+ const MPoly *UNUSED(mpoly),
+ void *data)
+{
+ ((uint32_t *)data)[l] = (mr->e_origindex) ? mr->e_origindex[mloop->e] : mloop->e;
+}
+
+static void extract_vert_idx_loop_mesh(const MeshRenderData *mr,
+ int l,
+ const MLoop *mloop,
+ int UNUSED(p),
+ const MPoly *UNUSED(mpoly),
+ void *data)
+{
+ ((uint32_t *)data)[l] = (mr->v_origindex) ? mr->v_origindex[mloop->v] : mloop->v;
+}
+
+static void extract_edge_idx_ledge_mesh(const MeshRenderData *mr,
+ int e,
+ const MEdge *UNUSED(medge),
+ void *data)
+{
+ int e_idx = mr->ledges[e];
+ int e_orig = (mr->e_origindex) ? mr->e_origindex[e_idx] : e_idx;
+ ((uint32_t *)data)[mr->loop_len + e * 2 + 0] = e_orig;
+ ((uint32_t *)data)[mr->loop_len + e * 2 + 1] = e_orig;
+}
+
+static void extract_vert_idx_ledge_mesh(const MeshRenderData *mr,
+ int e,
+ const MEdge *medge,
+ void *data)
+{
+ int v1_orig = (mr->v_origindex) ? mr->v_origindex[medge->v1] : medge->v1;
+ int v2_orig = (mr->v_origindex) ? mr->v_origindex[medge->v2] : medge->v2;
+ ((uint32_t *)data)[mr->loop_len + e * 2 + 0] = v1_orig;
+ ((uint32_t *)data)[mr->loop_len + e * 2 + 1] = v2_orig;
+}
+
+static void extract_vert_idx_lvert_mesh(const MeshRenderData *mr,
+ int v,
+ const MVert *UNUSED(mvert),
+ void *data)
+{
+ int v_idx = mr->lverts[v];
+ int v_orig = (mr->v_origindex) ? mr->v_origindex[v_idx] : v_idx;
+ ((uint32_t *)data)[mr->loop_len + mr->edge_loose_len * 2 + v] = v_orig;
+}
+
+const MeshExtract extract_poly_idx = {extract_select_idx_init,
+ NULL,
+ NULL,
+ extract_poly_idx_loop_bmesh,
+ extract_poly_idx_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ true};
+
+const MeshExtract extract_edge_idx = {extract_select_idx_init,
+ NULL,
+ NULL,
+ extract_edge_idx_loop_bmesh,
+ extract_edge_idx_loop_mesh,
+ extract_edge_idx_ledge_bmesh,
+ extract_edge_idx_ledge_mesh,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ true};
+
+const MeshExtract extract_vert_idx = {extract_select_idx_init,
+ NULL,
+ NULL,
+ extract_vert_idx_loop_bmesh,
+ extract_vert_idx_loop_mesh,
+ extract_vert_idx_ledge_bmesh,
+ extract_vert_idx_ledge_mesh,
+ extract_vert_idx_lvert_bmesh,
+ extract_vert_idx_lvert_mesh,
+ NULL,
+ 0,
+ true};
+
+static void *extract_select_fdot_idx_init(const MeshRenderData *mr, void *buf)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* TODO rename "color" to something more descriptive. */
+ GPU_vertformat_attr_add(&format, "color", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->poly_len);
+ return vbo->data;
+}
+
+static void extract_fdot_idx_loop_bmesh(const MeshRenderData *UNUSED(mr),
+ int UNUSED(l),
+ BMLoop *loop,
+ void *data)
+{
+ ((uint32_t *)data)[BM_elem_index_get(loop->f)] = BM_elem_index_get(loop->f);
+}
+
+static void extract_fdot_idx_loop_mesh(const MeshRenderData *mr,
+ int UNUSED(l),
+ const MLoop *UNUSED(mloop),
+ int p,
+ const MPoly *UNUSED(mpoly),
+ void *data)
+{
+ ((uint32_t *)data)[p] = (mr->p_origindex) ? mr->p_origindex[p] : p;
+}
+
+const MeshExtract extract_fdot_idx = {extract_select_fdot_idx_init,
+ NULL,
+ NULL,
+ extract_fdot_idx_loop_bmesh,
+ extract_fdot_idx_loop_mesh,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ true};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Loop
+ * \{ */
+
+typedef struct ExtractTaskData {
+ const MeshRenderData *mr;
+ const MeshExtract *extract;
+ eMRIterType iter_type;
+ int start, end;
+ /** Decremented each time a task is finished. */
+ int32_t *task_counter;
+ void *buf;
+ void *user_data;
+} ExtractTaskData;
+
+BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr,
+ const eMRIterType iter_type,
+ int start,
+ int end,
+ const MeshExtract *extract,
+ void *user_data)
+{
+ switch (mr->extract_type) {
+ case MR_EXTRACT_BMESH:
+ if (iter_type & MR_ITER_LOOPTRI) {
+ int t_end = min_ii(mr->tri_len, end);
+ for (int t = start; t < t_end; t++) {
+ BMLoop **elt = &mr->edit_bmesh->looptris[t][0];
+ extract->iter_looptri_bm(mr, t, elt, user_data);
+ }
+ }
+ if (iter_type & MR_ITER_LOOP) {
+ int l_end = min_ii(mr->poly_len, end);
+ for (int f = start; f < l_end; f++) {
+ BMFace *efa = BM_face_at_index(mr->bm, f);
+ BMLoop *loop;
+ BMIter l_iter;
+ BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) {
+ extract->iter_loop_bm(mr, BM_elem_index_get(loop), loop, user_data);
+ }
+ }
+ }
+ if (iter_type & MR_ITER_LEDGE) {
+ int le_end = min_ii(mr->edge_loose_len, end);
+ for (int e = start; e < le_end; e++) {
+ BMEdge *eed = BM_edge_at_index(mr->bm, mr->ledges[e]);
+ extract->iter_ledge_bm(mr, e, eed, user_data);
+ }
+ }
+ if (iter_type & MR_ITER_LVERT) {
+ int lv_end = min_ii(mr->vert_loose_len, end);
+ for (int v = start; v < lv_end; v++) {
+ BMVert *eve = BM_vert_at_index(mr->bm, mr->lverts[v]);
+ extract->iter_lvert_bm(mr, v, eve, user_data);
+ }
+ }
+ break;
+ case MR_EXTRACT_MAPPED:
+ case MR_EXTRACT_MESH:
+ if (iter_type & MR_ITER_LOOPTRI) {
+ int t_end = min_ii(mr->tri_len, end);
+ for (int t = start; t < t_end; t++) {
+ extract->iter_looptri(mr, t, &mr->mlooptri[t], user_data);
+ }
+ }
+ if (iter_type & MR_ITER_LOOP) {
+ int l_end = min_ii(mr->poly_len, end);
+ for (int p = start; p < l_end; p++) {
+ const MPoly *mpoly = &mr->mpoly[p];
+ int l = mpoly->loopstart;
+ for (int i = 0; i < mpoly->totloop; i++, l++) {
+ extract->iter_loop(mr, l, &mr->mloop[l], p, mpoly, user_data);
+ }
+ }
+ }
+ if (iter_type & MR_ITER_LEDGE) {
+ int le_end = min_ii(mr->edge_loose_len, end);
+ for (int e = start; e < le_end; e++) {
+ extract->iter_ledge(mr, e, &mr->medge[mr->ledges[e]], user_data);
+ }
+ }
+ if (iter_type & MR_ITER_LVERT) {
+ int lv_end = min_ii(mr->vert_loose_len, end);
+ for (int v = start; v < lv_end; v++) {
+ extract->iter_lvert(mr, v, &mr->mvert[mr->lverts[v]], user_data);
+ }
+ }
+ break;
+ }
+}
+
+static void extract_run(TaskPool *__restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+ ExtractTaskData *data = taskdata;
+ mesh_extract_iter(
+ data->mr, data->iter_type, data->start, data->end, data->extract, data->user_data);
+
+ /* If this is the last task, we do the finish function. */
+ int remainin_tasks = atomic_sub_and_fetch_int32(data->task_counter, 1);
+ if (remainin_tasks == 0 && data->extract->finish != NULL) {
+ data->extract->finish(data->mr, data->buf, data->user_data);
+ }
+}
+
+static void extract_range_task_create(
+ TaskPool *task_pool, ExtractTaskData *taskdata, const eMRIterType type, int start, int length)
+{
+ taskdata = MEM_dupallocN(taskdata);
+ atomic_add_and_fetch_int32(taskdata->task_counter, 1);
+ taskdata->iter_type = type;
+ taskdata->start = start;
+ taskdata->end = start + length;
+ BLI_task_pool_push(task_pool, extract_run, taskdata, true, TASK_PRIORITY_HIGH);
+}
+
+static void extract_task_create(TaskPool *task_pool,
+ const MeshRenderData *mr,
+ const MeshExtract *extract,
+ void *buf,
+ int32_t *task_counter)
+{
+ /* Divide extraction of the VBO/IBO into sensible chunks of works. */
+ ExtractTaskData *taskdata = MEM_mallocN(sizeof(*taskdata), "ExtractTaskData");
+ taskdata->mr = mr;
+ taskdata->extract = extract;
+ taskdata->buf = buf;
+ taskdata->user_data = extract->init(mr, buf);
+ taskdata->iter_type = mesh_extract_iter_type(extract);
+ taskdata->task_counter = task_counter;
+ taskdata->start = 0;
+ taskdata->end = INT_MAX;
+
+ /* Simple heuristic. */
+ const bool use_thread = (mr->loop_len + mr->loop_loose_len) > 8192;
+ if (use_thread && extract->use_threading) {
+ /* Divide task into sensible chunks. */
+ const int chunk_size = 8192;
+ if (taskdata->iter_type & MR_ITER_LOOPTRI) {
+ for (int i = 0; i < mr->tri_len; i += chunk_size) {
+ extract_range_task_create(task_pool, taskdata, MR_ITER_LOOPTRI, i, chunk_size);
+ }
+ }
+ if (taskdata->iter_type & MR_ITER_LOOP) {
+ for (int i = 0; i < mr->poly_len; i += chunk_size) {
+ extract_range_task_create(task_pool, taskdata, MR_ITER_LOOP, i, chunk_size);
+ }
+ }
+ if (taskdata->iter_type & MR_ITER_LEDGE) {
+ for (int i = 0; i < mr->edge_loose_len; i += chunk_size) {
+ extract_range_task_create(task_pool, taskdata, MR_ITER_LEDGE, i, chunk_size);
+ }
+ }
+ if (taskdata->iter_type & MR_ITER_LVERT) {
+ for (int i = 0; i < mr->vert_loose_len; i += chunk_size) {
+ extract_range_task_create(task_pool, taskdata, MR_ITER_LVERT, i, chunk_size);
+ }
+ }
+ MEM_freeN(taskdata);
+ }
+ else if (use_thread) {
+ /* One task for the whole VBO. */
+ (*task_counter)++;
+ BLI_task_pool_push(task_pool, extract_run, taskdata, true, TASK_PRIORITY_HIGH);
+ }
+ else {
+ /* Single threaded extraction. */
+ (*task_counter)++;
+ extract_run(NULL, taskdata, -1);
+ MEM_freeN(taskdata);
+ }
+}
+
+void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
+ MeshBufferCache mbc,
+ Mesh *me,
+ const bool do_final,
+ const bool do_uvedit,
+ const bool use_subsurf_fdots,
+ const DRW_MeshCDMask *cd_layer_used,
+ const ToolSettings *ts,
+ const bool use_hide)
+{
+ eMRIterType iter_flag = 0;
+ eMRDataType data_flag = 0;
+
+#define TEST_ASSIGN(type, type_lowercase, name) \
+ do { \
+ if (DRW_TEST_ASSIGN_##type(mbc.type_lowercase.name)) { \
+ iter_flag |= mesh_extract_iter_type(&extract_##name); \
+ data_flag |= extract_##name.data_flag; \
+ } \
+ } while (0)
+
+ TEST_ASSIGN(VBO, vbo, pos_nor);
+ TEST_ASSIGN(VBO, vbo, lnor);
+ TEST_ASSIGN(VBO, vbo, uv);
+ TEST_ASSIGN(VBO, vbo, tan);
+ TEST_ASSIGN(VBO, vbo, vcol);
+ TEST_ASSIGN(VBO, vbo, orco);
+ TEST_ASSIGN(VBO, vbo, edge_fac);
+ TEST_ASSIGN(VBO, vbo, weights);
+ TEST_ASSIGN(VBO, vbo, edit_data);
+ TEST_ASSIGN(VBO, vbo, edituv_data);
+ TEST_ASSIGN(VBO, vbo, stretch_area);
+ TEST_ASSIGN(VBO, vbo, stretch_angle);
+ TEST_ASSIGN(VBO, vbo, mesh_analysis);
+ TEST_ASSIGN(VBO, vbo, fdots_pos);
+ TEST_ASSIGN(VBO, vbo, fdots_nor);
+ TEST_ASSIGN(VBO, vbo, fdots_uv);
+ TEST_ASSIGN(VBO, vbo, fdots_edituv_data);
+ TEST_ASSIGN(VBO, vbo, poly_idx);
+ TEST_ASSIGN(VBO, vbo, edge_idx);
+ TEST_ASSIGN(VBO, vbo, vert_idx);
+ TEST_ASSIGN(VBO, vbo, fdot_idx);
+
+ TEST_ASSIGN(IBO, ibo, tris);
+ TEST_ASSIGN(IBO, ibo, lines);
+ TEST_ASSIGN(IBO, ibo, points);
+ TEST_ASSIGN(IBO, ibo, fdots);
+ TEST_ASSIGN(IBO, ibo, lines_paint_mask);
+ TEST_ASSIGN(IBO, ibo, lines_adjacency);
+ TEST_ASSIGN(IBO, ibo, edituv_tris);
+ TEST_ASSIGN(IBO, ibo, edituv_lines);
+ TEST_ASSIGN(IBO, ibo, edituv_points);
+ TEST_ASSIGN(IBO, ibo, edituv_fdots);
+
+#undef TEST_ASSIGN
+
+#ifdef DEBUG_TIME
+ double rdata_start = PIL_check_seconds_timer();
+#endif
+
+ MeshRenderData *mr = mesh_render_data_create(
+ me, do_final, do_uvedit, iter_flag, data_flag, cd_layer_used, ts);
+ mr->cache = cache; /* HACK */
+ mr->use_hide = use_hide;
+ mr->use_subsurf_fdots = use_subsurf_fdots;
+ mr->use_final_mesh = do_final;
+
+#ifdef DEBUG_TIME
+ double rdata_end = PIL_check_seconds_timer();
+#endif
+
+ TaskScheduler *task_scheduler;
+ TaskPool *task_pool;
+
+ task_scheduler = BLI_task_scheduler_get();
+ task_pool = BLI_task_pool_create(task_scheduler, NULL);
+
+ size_t counters_size = (sizeof(mbc) / sizeof(void *)) * sizeof(int32_t);
+ int32_t *task_counters = MEM_callocN(counters_size, __func__);
+ int counter_used = 0;
+
+#define EXTRACT(buf, name) \
+ if (mbc.buf.name) { \
+ extract_task_create( \
+ task_pool, mr, &extract_##name, mbc.buf.name, &task_counters[counter_used++]); \
+ }
+
+ EXTRACT(vbo, pos_nor);
+ EXTRACT(vbo, lnor);
+ EXTRACT(vbo, uv);
+ EXTRACT(vbo, tan);
+ EXTRACT(vbo, vcol);
+ EXTRACT(vbo, orco);
+ EXTRACT(vbo, edge_fac);
+ EXTRACT(vbo, weights);
+ EXTRACT(vbo, edit_data);
+ EXTRACT(vbo, edituv_data);
+ EXTRACT(vbo, stretch_area);
+ EXTRACT(vbo, stretch_angle);
+ EXTRACT(vbo, mesh_analysis);
+ EXTRACT(vbo, fdots_pos);
+ EXTRACT(vbo, fdots_nor);
+ EXTRACT(vbo, fdots_uv);
+ EXTRACT(vbo, fdots_edituv_data);
+ EXTRACT(vbo, poly_idx);
+ EXTRACT(vbo, edge_idx);
+ EXTRACT(vbo, vert_idx);
+ EXTRACT(vbo, fdot_idx);
+
+ EXTRACT(ibo, tris);
+ EXTRACT(ibo, lines);
+ EXTRACT(ibo, points);
+ EXTRACT(ibo, fdots);
+ EXTRACT(ibo, lines_paint_mask);
+ EXTRACT(ibo, lines_adjacency);
+ EXTRACT(ibo, edituv_tris);
+ EXTRACT(ibo, edituv_lines);
+ EXTRACT(ibo, edituv_points);
+ EXTRACT(ibo, edituv_fdots);
+
+#undef EXTRACT
+
+ /* TODO(fclem) Ideally, we should have one global pool for all
+ * objects and wait for finish only before drawing when buffers
+ * need to be ready. */
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+
+ MEM_freeN(task_counters);
+
+ mesh_render_data_free(mr);
+
+#ifdef DEBUG_TIME
+ double end = PIL_check_seconds_timer();
+
+ static double avg = 0;
+ static double avg_fps = 0;
+ static double avg_rdata = 0;
+ static double end_prev = 0;
+
+ if (end_prev == 0) {
+ end_prev = end;
+ }
+
+ avg = avg * 0.95 + (end - rdata_end) * 0.05;
+ avg_fps = avg_fps * 0.95 + (end - end_prev) * 0.05;
+ avg_rdata = avg_rdata * 0.95 + (rdata_end - rdata_start) * 0.05;
+
+ printf(
+ "rdata %.0fms iter %.0fms (frame %.0fms)\n", avg_rdata * 1000, avg * 1000, avg_fps * 1000);
+
+ end_prev = end;
+#endif
+}
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index 4dc58972ce6..d392db63938 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -119,7 +119,7 @@ struct GPUBatch *DRW_lattice_batch_cache_get_edit_verts(struct Lattice *lt);
/* Mesh */
void DRW_mesh_batch_cache_create_requested(struct Object *ob,
struct Mesh *me,
- const struct ToolSettings *ts,
+ const struct Scene *scene,
const bool is_paint_mode,
const bool use_hide);
@@ -143,6 +143,7 @@ struct GPUBatch *DRW_mesh_batch_cache_get_surface_weights(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_triangles(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_vertices(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_edges(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_edit_vnors(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_lnors(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_facedots(struct Mesh *me);
/* edit-mesh selection */
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index ba58dc3d9de..12c6a715685 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -64,313 +64,12 @@
#include "ED_uvedit.h"
#include "draw_cache_inline.h"
+#include "draw_cache_extract.h"
#include "draw_cache_impl.h" /* own include */
static void mesh_batch_cache_clear(Mesh *me);
-/* Vertex Group Selection and display options */
-typedef struct DRW_MeshWeightState {
- int defgroup_active;
- int defgroup_len;
-
- short flags;
- char alert_mode;
-
- /* Set of all selected bones for Multipaint. */
- bool *defgroup_sel; /* [defgroup_len] */
- int defgroup_sel_count;
-} DRW_MeshWeightState;
-
-typedef struct DRW_MeshCDMask {
- uint32_t uv : 8;
- uint32_t tan : 8;
- uint32_t vcol : 8;
- uint32_t orco : 1;
- uint32_t tan_orco : 1;
-} DRW_MeshCDMask;
-
-/* DRW_MeshWeightState.flags */
-enum {
- DRW_MESH_WEIGHT_STATE_MULTIPAINT = (1 << 0),
- DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE = (1 << 1),
-};
-
-/* ---------------------------------------------------------------------- */
-/** \name BMesh Inline Wrappers
- * \{ */
-
-/**
- * Wrapper for #BM_vert_find_first_loop_visible
- * since most of the time this can be accessed directly without a function call.
- */
-BLI_INLINE BMLoop *bm_vert_find_first_loop_visible_inline(BMVert *v)
-{
- if (v->e) {
- BMLoop *l = v->e->l;
- if (l && !BM_elem_flag_test(l->f, BM_ELEM_HIDDEN)) {
- return l->v == v ? l : l->next;
- }
- return BM_vert_find_first_loop_visible(v);
- }
- return NULL;
-}
-
-BLI_INLINE BMLoop *bm_edge_find_first_loop_visible_inline(BMEdge *e)
-{
- if (e->l) {
- BMLoop *l = e->l;
- if (!BM_elem_flag_test(l->f, BM_ELEM_HIDDEN)) {
- return l;
- }
- return BM_edge_find_first_loop_visible(e);
- }
- return NULL;
-}
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Mesh/BMesh Interface (direct access to basic data).
- * \{ */
-
-static int mesh_render_verts_len_get(Mesh *me)
-{
- return me->edit_mesh ? me->edit_mesh->bm->totvert : me->totvert;
-}
-
-static int mesh_render_edges_len_get(Mesh *me)
-{
- return me->edit_mesh ? me->edit_mesh->bm->totedge : me->totedge;
-}
-
-static int mesh_render_looptri_len_get(Mesh *me)
-{
- return me->edit_mesh ? me->edit_mesh->tottri : poly_to_tri_count(me->totpoly, me->totloop);
-}
-
-static int mesh_render_polys_len_get(Mesh *me)
-{
- return me->edit_mesh ? me->edit_mesh->bm->totface : me->totpoly;
-}
-
-static int mesh_render_mat_len_get(Mesh *me)
-{
- return MAX2(1, me->totcol);
-}
-
-static int UNUSED_FUNCTION(mesh_render_loops_len_get)(Mesh *me)
-{
- return me->edit_mesh ? me->edit_mesh->bm->totloop : me->totloop;
-}
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Mesh/BMesh Interface (indirect, partially cached access to complex data).
- * \{ */
-
-typedef struct EdgeAdjacentPolys {
- int count;
- int face_index[2];
-} EdgeAdjacentPolys;
-
-typedef struct EdgeAdjacentVerts {
- int vert_index[2]; /* -1 if none */
-} EdgeAdjacentVerts;
-
-typedef struct EdgeDrawAttr {
- uchar v_flag;
- uchar e_flag;
- uchar crease;
- uchar bweight;
-} EdgeDrawAttr;
-
-typedef struct MeshRenderData {
- int types;
-
- int vert_len;
- int edge_len;
- int tri_len;
- int loop_len;
- int poly_len;
- int mat_len;
- int loose_vert_len;
- int loose_edge_len;
-
- /* Support for mapped mesh data. */
- struct {
- /* Must be set if we want to get mapped data. */
- bool use;
- bool supported;
-
- Mesh *me_cage;
-
- int vert_len;
- int edge_len;
- int tri_len;
- int loop_len;
- int poly_len;
-
- int *loose_verts;
- int loose_vert_len;
-
- int *loose_edges;
- int loose_edge_len;
-
- /* origindex layers */
- int *v_origindex;
- int *e_origindex;
- int *l_origindex;
- int *p_origindex;
- } mapped;
-
- BMEditMesh *edit_bmesh;
- struct EditMeshData *edit_data;
- const ToolSettings *toolsettings;
-
- Mesh *me;
-
- MVert *mvert;
- const MEdge *medge;
- const MLoop *mloop;
- const MPoly *mpoly;
- float (*orco)[3]; /* vertex coordinates normalized to bounding box */
- bool is_orco_allocated;
- MDeformVert *dvert;
- MLoopUV *mloopuv;
- MLoopCol *mloopcol;
- float (*loop_normals)[3];
-
- /* CustomData 'cd' cache for efficient access. */
- struct {
- struct {
- MLoopUV **uv;
- MLoopCol **vcol;
- float (**tangent)[4];
-
- int uv_len;
- int uv_active;
- int uv_render;
- int uv_mask_active;
-
- int vcol_len;
- int vcol_active;
- int vcol_render;
-
- int tangent_len;
- int tangent_active;
- int tangent_render;
-
- bool *auto_vcol;
- } layers;
-
- /* Custom-data offsets (only needed for BMesh access) */
- struct {
- int crease;
- int bweight;
- int *uv;
- int *vcol;
-#ifdef WITH_FREESTYLE
- int freestyle_edge;
- int freestyle_face;
-#endif
- } offset;
-
- struct {
- char (*auto_mix)[32];
- char (*uv)[32];
- char (*vcol)[32];
- char (*tangent)[32];
- } uuid;
-
- /* for certain cases we need an output loop-data storage (bmesh tangents) */
- struct {
- CustomData ldata;
- /* grr, special case variable (use in place of 'dm->tangent_mask') */
- short tangent_mask;
- } output;
- } cd;
-
- BMVert *eve_act;
- BMEdge *eed_act;
- BMFace *efa_act;
- BMFace *efa_act_uv;
-
- /* Data created on-demand (usually not for bmesh-based data). */
- EdgeAdjacentPolys *edges_adjacent_polys;
- MLoopTri *mlooptri;
- int *loose_edges;
- int *loose_verts;
-
- float (*poly_normals)[3];
- float *vert_weight;
- char (*vert_color)[3];
- GPUPackedNormal *poly_normals_pack;
- GPUPackedNormal *vert_normals_pack;
- bool *edge_select_bool;
- bool *edge_visible_bool;
-} MeshRenderData;
-
-typedef enum eMRDataType {
- MR_DATATYPE_VERT = 1 << 0,
- MR_DATATYPE_EDGE = 1 << 1,
- MR_DATATYPE_LOOPTRI = 1 << 2,
- MR_DATATYPE_LOOP = 1 << 3,
- MR_DATATYPE_POLY = 1 << 4,
- MR_DATATYPE_OVERLAY = 1 << 5,
- MR_DATATYPE_SHADING = 1 << 6,
- MR_DATATYPE_DVERT = 1 << 7,
- MR_DATATYPE_LOOPCOL = 1 << 8,
- MR_DATATYPE_LOOPUV = 1 << 9,
- MR_DATATYPE_LOOSE_VERT = 1 << 10,
- MR_DATATYPE_LOOSE_EDGE = 1 << 11,
- MR_DATATYPE_LOOP_NORMALS = 1 << 12,
-} eMRDataType;
-
-#define MR_DATATYPE_VERT_LOOP_POLY (MR_DATATYPE_VERT | MR_DATATYPE_POLY | MR_DATATYPE_LOOP)
-#define MR_DATATYPE_VERT_LOOP_TRI_POLY (MR_DATATYPE_VERT_LOOP_POLY | MR_DATATYPE_LOOPTRI)
-#define MR_DATATYPE_LOOSE_VERT_EGDE (MR_DATATYPE_LOOSE_VERT | MR_DATATYPE_LOOSE_EDGE)
-
-/**
- * These functions look like they would be slow but they will typically return true on the first
- * iteration. Only false when all attached elements are hidden.
- */
-static bool bm_vert_has_visible_edge(const BMVert *v)
-{
- const BMEdge *e_iter, *e_first;
-
- e_iter = e_first = v->e;
- do {
- if (!BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN)) {
- return true;
- }
- } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
- return false;
-}
-
-static bool bm_edge_has_visible_face(const BMEdge *e)
-{
- const BMLoop *l_iter, *l_first;
- l_iter = l_first = e->l;
- do {
- if (!BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
- return true;
- }
- } while ((l_iter = l_iter->radial_next) != l_first);
- return false;
-}
-
-BLI_INLINE bool bm_vert_is_loose_and_visible(const BMVert *v)
-{
- return (!BM_elem_flag_test(v, BM_ELEM_HIDDEN) && (v->e == NULL || !bm_vert_has_visible_edge(v)));
-}
-
-BLI_INLINE bool bm_edge_is_loose_and_visible(const BMEdge *e)
-{
- return (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && (e->l == NULL || !bm_edge_has_visible_face(e)));
-}
-
/* Return true is all layers in _b_ are inside _a_. */
BLI_INLINE bool mesh_cd_layers_type_overlap(DRW_MeshCDMask a, DRW_MeshCDMask b)
{
@@ -523,43 +222,6 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
return cd_used;
}
-static void mesh_render_calc_normals_loop_and_poly(const Mesh *me,
- const float split_angle,
- MeshRenderData *rdata)
-{
- BLI_assert((me->flag & ME_AUTOSMOOTH) != 0);
-
- int totloop = me->totloop;
- int totpoly = me->totpoly;
- float(*loop_normals)[3] = MEM_mallocN(sizeof(*loop_normals) * totloop, __func__);
- float(*poly_normals)[3] = MEM_mallocN(sizeof(*poly_normals) * totpoly, __func__);
- short(*clnors)[2] = CustomData_get_layer(&me->ldata, CD_CUSTOMLOOPNORMAL);
-
- BKE_mesh_calc_normals_poly(
- me->mvert, NULL, me->totvert, me->mloop, me->mpoly, totloop, totpoly, poly_normals, false);
-
- BKE_mesh_normals_loop_split(me->mvert,
- me->totvert,
- me->medge,
- me->totedge,
- me->mloop,
- loop_normals,
- totloop,
- me->mpoly,
- poly_normals,
- totpoly,
- true,
- split_angle,
- NULL,
- clnors,
- NULL);
-
- rdata->loop_len = totloop;
- rdata->poly_len = totpoly;
- rdata->loop_normals = loop_normals;
- rdata->poly_normals = poly_normals;
-}
-
static void mesh_cd_extract_auto_layers_names_and_srgb(Mesh *me,
DRW_MeshCDMask cd_used,
char **r_auto_layers_names,
@@ -582,10 +244,12 @@ static void mesh_cd_extract_auto_layers_names_and_srgb(Mesh *me,
for (int i = 0; i < uv_len; i++) {
if ((cd_used.uv & (1 << i)) != 0) {
const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i);
- uint hash = BLI_ghashutil_strhash_p(name);
+ char safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
+ GPU_vertformat_safe_attrib_name(name, safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
+ auto_ofs += BLI_snprintf_rlen(
+ auto_names + auto_ofs, auto_names_len - auto_ofs, "ba%s", safe_name);
/* +1 to include '\0' terminator. */
- auto_ofs += 1 + BLI_snprintf_rlen(
- auto_names + auto_ofs, auto_names_len - auto_ofs, "ba%u", hash);
+ auto_ofs += 1;
}
}
@@ -595,10 +259,12 @@ static void mesh_cd_extract_auto_layers_names_and_srgb(Mesh *me,
const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i);
/* We only do vcols that are not overridden by a uv layer with same name. */
if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, name) == -1) {
- uint hash = BLI_ghashutil_strhash_p(name);
+ char safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
+ GPU_vertformat_safe_attrib_name(name, safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
+ auto_ofs += BLI_snprintf_rlen(
+ auto_names + auto_ofs, auto_names_len - auto_ofs, "ba%s", safe_name);
/* +1 to include '\0' terminator. */
- auto_ofs += 1 + BLI_snprintf_rlen(
- auto_names + auto_ofs, auto_names_len - auto_ofs, "ba%u", hash);
+ auto_ofs += 1;
auto_is_srgb[auto_is_srgb_ofs] = true;
auto_is_srgb_ofs++;
}
@@ -617,1265 +283,6 @@ static void mesh_cd_extract_auto_layers_names_and_srgb(Mesh *me,
*r_auto_layers_len = auto_is_srgb_ofs;
}
-/**
- * TODO(campbell): 'gpumat_array' may include materials linked to the object.
- * While not default, object materials should be supported.
- * Although this only impacts the data that's generated, not the materials that display.
- */
-static MeshRenderData *mesh_render_data_create_ex(Mesh *me,
- const int types,
- const DRW_MeshCDMask *cd_used,
- const ToolSettings *ts)
-{
- MeshRenderData *rdata = MEM_callocN(sizeof(*rdata), __func__);
- rdata->types = types;
- rdata->toolsettings = ts;
- rdata->mat_len = mesh_render_mat_len_get(me);
-
- CustomData_reset(&rdata->cd.output.ldata);
-
- const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0;
- const float split_angle = is_auto_smooth ? me->smoothresh : (float)M_PI;
-
- if (me->edit_mesh) {
- BMEditMesh *embm = me->edit_mesh;
- BMesh *bm = embm->bm;
-
- rdata->edit_bmesh = embm;
- rdata->edit_data = me->runtime.edit_data;
-
- if (embm->mesh_eval_cage && (embm->mesh_eval_cage->runtime.is_original == false)) {
- Mesh *me_cage = embm->mesh_eval_cage;
-
- rdata->mapped.me_cage = me_cage;
- if (types & MR_DATATYPE_VERT) {
- rdata->mapped.vert_len = me_cage->totvert;
- }
- if (types & MR_DATATYPE_EDGE) {
- rdata->mapped.edge_len = me_cage->totedge;
- }
- if (types & MR_DATATYPE_LOOP) {
- rdata->mapped.loop_len = me_cage->totloop;
- }
- if (types & MR_DATATYPE_POLY) {
- rdata->mapped.poly_len = me_cage->totpoly;
- }
- if (types & MR_DATATYPE_LOOPTRI) {
- rdata->mapped.tri_len = poly_to_tri_count(me_cage->totpoly, me_cage->totloop);
- }
- if (types & MR_DATATYPE_LOOPUV) {
- rdata->mloopuv = CustomData_get_layer(&me_cage->ldata, CD_MLOOPUV);
- }
-
- rdata->mapped.v_origindex = CustomData_get_layer(&me_cage->vdata, CD_ORIGINDEX);
- rdata->mapped.e_origindex = CustomData_get_layer(&me_cage->edata, CD_ORIGINDEX);
- rdata->mapped.l_origindex = CustomData_get_layer(&me_cage->ldata, CD_ORIGINDEX);
- rdata->mapped.p_origindex = CustomData_get_layer(&me_cage->pdata, CD_ORIGINDEX);
- rdata->mapped.supported = (rdata->mapped.v_origindex || rdata->mapped.e_origindex ||
- rdata->mapped.p_origindex);
- }
-
- int bm_ensure_types = 0;
- if (types & MR_DATATYPE_VERT) {
- rdata->vert_len = bm->totvert;
- bm_ensure_types |= BM_VERT;
- }
- if (types & MR_DATATYPE_EDGE) {
- rdata->edge_len = bm->totedge;
- bm_ensure_types |= BM_EDGE;
- }
- if (types & MR_DATATYPE_LOOPTRI) {
- bm_ensure_types |= BM_LOOP;
- }
- if (types & MR_DATATYPE_LOOP) {
- rdata->loop_len = bm->totloop;
- bm_ensure_types |= BM_LOOP;
- }
- if (types & MR_DATATYPE_POLY) {
- rdata->poly_len = bm->totface;
- bm_ensure_types |= BM_FACE;
- }
- if (types & MR_DATATYPE_LOOP_NORMALS) {
- BLI_assert(types & MR_DATATYPE_LOOP);
- if (is_auto_smooth) {
- rdata->loop_normals = MEM_mallocN(sizeof(*rdata->loop_normals) * bm->totloop, __func__);
- int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
- BM_loops_calc_normal_vcos(bm,
- NULL,
- NULL,
- NULL,
- true,
- split_angle,
- rdata->loop_normals,
- NULL,
- NULL,
- cd_loop_clnors_offset,
- false);
- }
- }
- if (types & MR_DATATYPE_OVERLAY) {
- rdata->efa_act_uv = EDBM_uv_active_face_get(embm, false, false);
- rdata->efa_act = BM_mesh_active_face_get(bm, false, true);
- rdata->eed_act = BM_mesh_active_edge_get(bm);
- rdata->eve_act = BM_mesh_active_vert_get(bm);
- rdata->cd.offset.crease = CustomData_get_offset(&bm->edata, CD_CREASE);
- rdata->cd.offset.bweight = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
-
-#ifdef WITH_FREESTYLE
- rdata->cd.offset.freestyle_edge = CustomData_get_offset(&bm->edata, CD_FREESTYLE_EDGE);
- rdata->cd.offset.freestyle_face = CustomData_get_offset(&bm->pdata, CD_FREESTYLE_FACE);
-#endif
- }
- if (types & (MR_DATATYPE_DVERT)) {
- bm_ensure_types |= BM_VERT;
- }
- if (rdata->edit_data != NULL) {
- bm_ensure_types |= BM_VERT;
- }
-
- BM_mesh_elem_index_ensure(bm, bm_ensure_types);
- BM_mesh_elem_table_ensure(bm, bm_ensure_types & ~BM_LOOP);
-
- if (types & MR_DATATYPE_LOOPTRI) {
- /* Edit mode ensures this is valid, no need to calculate. */
- BLI_assert((bm->totloop == 0) || (embm->looptris != NULL));
- int tottri = embm->tottri;
- MLoopTri *mlooptri = MEM_mallocN(sizeof(*rdata->mlooptri) * embm->tottri, __func__);
- for (int index = 0; index < tottri; index++) {
- BMLoop **bmtri = embm->looptris[index];
- MLoopTri *mtri = &mlooptri[index];
- mtri->tri[0] = BM_elem_index_get(bmtri[0]);
- mtri->tri[1] = BM_elem_index_get(bmtri[1]);
- mtri->tri[2] = BM_elem_index_get(bmtri[2]);
- }
- rdata->mlooptri = mlooptri;
- rdata->tri_len = tottri;
- }
-
- if (types & MR_DATATYPE_LOOSE_VERT) {
- BLI_assert(types & MR_DATATYPE_VERT);
- rdata->loose_vert_len = 0;
-
- {
- int *lverts = MEM_mallocN(rdata->vert_len * sizeof(int), __func__);
- BLI_assert((bm->elem_table_dirty & BM_VERT) == 0);
- for (int i = 0; i < bm->totvert; i++) {
- const BMVert *eve = BM_vert_at_index(bm, i);
- if (bm_vert_is_loose_and_visible(eve)) {
- lverts[rdata->loose_vert_len++] = i;
- }
- }
- rdata->loose_verts = MEM_reallocN(lverts, rdata->loose_vert_len * sizeof(int));
- }
-
- if (rdata->mapped.supported) {
- Mesh *me_cage = embm->mesh_eval_cage;
- rdata->mapped.loose_vert_len = 0;
-
- if (rdata->loose_vert_len) {
- int *lverts = MEM_mallocN(me_cage->totvert * sizeof(int), __func__);
- const int *v_origindex = rdata->mapped.v_origindex;
- for (int i = 0; i < me_cage->totvert; i++) {
- const int v_orig = v_origindex[i];
- if (v_orig != ORIGINDEX_NONE) {
- BMVert *eve = BM_vert_at_index(bm, v_orig);
- if (bm_vert_is_loose_and_visible(eve)) {
- lverts[rdata->mapped.loose_vert_len++] = i;
- }
- }
- }
- rdata->mapped.loose_verts = MEM_reallocN(lverts,
- rdata->mapped.loose_vert_len * sizeof(int));
- }
- }
- }
-
- if (types & MR_DATATYPE_LOOSE_EDGE) {
- BLI_assert(types & MR_DATATYPE_EDGE);
- rdata->loose_edge_len = 0;
-
- {
- int *ledges = MEM_mallocN(rdata->edge_len * sizeof(int), __func__);
- BLI_assert((bm->elem_table_dirty & BM_EDGE) == 0);
- for (int i = 0; i < bm->totedge; i++) {
- const BMEdge *eed = BM_edge_at_index(bm, i);
- if (bm_edge_is_loose_and_visible(eed)) {
- ledges[rdata->loose_edge_len++] = i;
- }
- }
- rdata->loose_edges = MEM_reallocN(ledges, rdata->loose_edge_len * sizeof(int));
- }
-
- if (rdata->mapped.supported) {
- Mesh *me_cage = embm->mesh_eval_cage;
- rdata->mapped.loose_edge_len = 0;
-
- if (rdata->loose_edge_len) {
- int *ledges = MEM_mallocN(me_cage->totedge * sizeof(int), __func__);
- const int *e_origindex = rdata->mapped.e_origindex;
- for (int i = 0; i < me_cage->totedge; i++) {
- const int e_orig = e_origindex[i];
- if (e_orig != ORIGINDEX_NONE) {
- BMEdge *eed = BM_edge_at_index(bm, e_orig);
- if (bm_edge_is_loose_and_visible(eed)) {
- ledges[rdata->mapped.loose_edge_len++] = i;
- }
- }
- }
- rdata->mapped.loose_edges = MEM_reallocN(ledges,
- rdata->mapped.loose_edge_len * sizeof(int));
- }
- }
- }
- }
- else {
- rdata->me = me;
-
- if (types & (MR_DATATYPE_VERT)) {
- rdata->vert_len = me->totvert;
- rdata->mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
- }
- if (types & (MR_DATATYPE_EDGE)) {
- rdata->edge_len = me->totedge;
- rdata->medge = CustomData_get_layer(&me->edata, CD_MEDGE);
- }
- if (types & MR_DATATYPE_LOOPTRI) {
- const int tri_len = rdata->tri_len = poly_to_tri_count(me->totpoly, me->totloop);
- MLoopTri *mlooptri = MEM_mallocN(sizeof(*mlooptri) * tri_len, __func__);
- BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mlooptri);
- rdata->mlooptri = mlooptri;
- }
- if (types & MR_DATATYPE_LOOP) {
- rdata->loop_len = me->totloop;
- rdata->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP);
- }
- if (types & MR_DATATYPE_LOOP_NORMALS) {
- BLI_assert(types & MR_DATATYPE_LOOP);
- if (is_auto_smooth) {
- mesh_render_calc_normals_loop_and_poly(me, split_angle, rdata);
- }
- }
- if (types & MR_DATATYPE_POLY) {
- rdata->poly_len = me->totpoly;
- rdata->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY);
- }
- if (types & MR_DATATYPE_DVERT) {
- rdata->vert_len = me->totvert;
- rdata->dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
- }
- if (types & MR_DATATYPE_LOOPCOL) {
- rdata->loop_len = me->totloop;
- rdata->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
- }
- if (types & MR_DATATYPE_LOOPUV) {
- rdata->loop_len = me->totloop;
- rdata->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
- }
- }
-
- if (types & MR_DATATYPE_SHADING) {
- CustomData *cd_vdata, *cd_ldata;
-
- BLI_assert(cd_used != NULL);
-
- if (me->edit_mesh) {
- BMesh *bm = me->edit_mesh->bm;
- cd_vdata = &bm->vdata;
- cd_ldata = &bm->ldata;
- }
- else {
- cd_vdata = &me->vdata;
- cd_ldata = &me->ldata;
- }
-
- rdata->cd.layers.uv_active = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
- rdata->cd.layers.uv_render = CustomData_get_render_layer(cd_ldata, CD_MLOOPUV);
- rdata->cd.layers.uv_mask_active = CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV);
- rdata->cd.layers.vcol_active = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL);
- rdata->cd.layers.vcol_render = CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL);
- rdata->cd.layers.tangent_active = rdata->cd.layers.uv_active;
- rdata->cd.layers.tangent_render = rdata->cd.layers.uv_render;
-
-#define CD_VALIDATE_ACTIVE_LAYER(active_index, used) \
- if ((active_index != -1) && (used & (1 << active_index)) == 0) { \
- active_index = -1; \
- } \
- ((void)0)
-
- CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.uv_active, cd_used->uv);
- CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.uv_render, cd_used->uv);
- CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.uv_mask_active, cd_used->uv);
- CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.tangent_active, cd_used->tan);
- CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.tangent_render, cd_used->tan);
- CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.vcol_active, cd_used->vcol);
- CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.vcol_render, cd_used->vcol);
-
-#undef CD_VALIDATE_ACTIVE_LAYER
-
- rdata->is_orco_allocated = false;
- if (cd_used->orco != 0) {
- rdata->orco = CustomData_get_layer(cd_vdata, CD_ORCO);
- /* If orco is not available compute it ourselves */
- if (!rdata->orco) {
- rdata->is_orco_allocated = true;
- if (me->edit_mesh) {
- BMesh *bm = me->edit_mesh->bm;
- rdata->orco = MEM_mallocN(sizeof(*rdata->orco) * rdata->vert_len, "orco mesh");
- BLI_assert((bm->elem_table_dirty & BM_VERT) == 0);
- for (int i = 0; i < bm->totvert; i++) {
- copy_v3_v3(rdata->orco[i], BM_vert_at_index(bm, i)->co);
- }
- BKE_mesh_orco_verts_transform(me, rdata->orco, rdata->vert_len, 0);
- }
- else {
- rdata->orco = MEM_mallocN(sizeof(*rdata->orco) * rdata->vert_len, "orco mesh");
- MVert *mvert = rdata->mvert;
- for (int a = 0; a < rdata->vert_len; a++, mvert++) {
- copy_v3_v3(rdata->orco[a], mvert->co);
- }
- BKE_mesh_orco_verts_transform(me, rdata->orco, rdata->vert_len, 0);
- }
- }
- }
- else {
- rdata->orco = NULL;
- }
-
- /* don't access mesh directly, instead use vars taken from BMesh or Mesh */
-#define me DONT_USE_THIS
-#ifdef me /* quiet warning */
-#endif
- struct {
- uint uv_len;
- uint vcol_len;
- } cd_layers_src = {
- .uv_len = CustomData_number_of_layers(cd_ldata, CD_MLOOPUV),
- .vcol_len = CustomData_number_of_layers(cd_ldata, CD_MLOOPCOL),
- };
-
- rdata->cd.layers.uv_len = min_ii(cd_layers_src.uv_len, count_bits_i(cd_used->uv));
- rdata->cd.layers.tangent_len = count_bits_i(cd_used->tan) + cd_used->tan_orco;
- rdata->cd.layers.vcol_len = min_ii(cd_layers_src.vcol_len, count_bits_i(cd_used->vcol));
-
- rdata->cd.layers.uv = MEM_mallocN(sizeof(*rdata->cd.layers.uv) * rdata->cd.layers.uv_len,
- __func__);
- rdata->cd.layers.vcol = MEM_mallocN(sizeof(*rdata->cd.layers.vcol) * rdata->cd.layers.vcol_len,
- __func__);
- rdata->cd.layers.tangent = MEM_mallocN(
- sizeof(*rdata->cd.layers.tangent) * rdata->cd.layers.tangent_len, __func__);
-
- rdata->cd.uuid.uv = MEM_mallocN(sizeof(*rdata->cd.uuid.uv) * rdata->cd.layers.uv_len,
- __func__);
- rdata->cd.uuid.vcol = MEM_mallocN(sizeof(*rdata->cd.uuid.vcol) * rdata->cd.layers.vcol_len,
- __func__);
- rdata->cd.uuid.tangent = MEM_mallocN(
- sizeof(*rdata->cd.uuid.tangent) * rdata->cd.layers.tangent_len, __func__);
-
- rdata->cd.offset.uv = MEM_mallocN(sizeof(*rdata->cd.offset.uv) * rdata->cd.layers.uv_len,
- __func__);
- rdata->cd.offset.vcol = MEM_mallocN(sizeof(*rdata->cd.offset.vcol) * rdata->cd.layers.vcol_len,
- __func__);
-
- /* Allocate max */
- rdata->cd.layers.auto_vcol = MEM_callocN(
- sizeof(*rdata->cd.layers.auto_vcol) * rdata->cd.layers.vcol_len, __func__);
- rdata->cd.uuid.auto_mix = MEM_mallocN(
- sizeof(*rdata->cd.uuid.auto_mix) * (rdata->cd.layers.vcol_len + rdata->cd.layers.uv_len),
- __func__);
-
- /* XXX FIXME XXX */
- /* We use a hash to identify each data layer based on its name.
- * Gawain then search for this name in the current shader and bind if it exists.
- * NOTE : This is prone to hash collision.
- * One solution to hash collision would be to format the cd layer name
- * to a safe glsl var name, but without name clash.
- * NOTE 2 : Replicate changes to code_generate_vertex_new() in gpu_codegen.c */
- if (rdata->cd.layers.vcol_len != 0) {
- int act_vcol = rdata->cd.layers.vcol_active;
- int ren_vcol = rdata->cd.layers.vcol_render;
- for (int i_src = 0, i_dst = 0; i_src < cd_layers_src.vcol_len; i_src++, i_dst++) {
- if ((cd_used->vcol & (1 << i_src)) == 0) {
- /* This is a non-used VCol slot. Skip. */
- i_dst--;
- if (rdata->cd.layers.vcol_active >= i_src) {
- act_vcol--;
- }
- if (rdata->cd.layers.vcol_render >= i_src) {
- ren_vcol--;
- }
- }
- else {
- const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i_src);
- uint hash = BLI_ghashutil_strhash_p(name);
- BLI_snprintf(rdata->cd.uuid.vcol[i_dst], sizeof(*rdata->cd.uuid.vcol), "c%u", hash);
- rdata->cd.layers.vcol[i_dst] = CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i_src);
- if (rdata->edit_bmesh) {
- rdata->cd.offset.vcol[i_dst] = CustomData_get_n_offset(
- &rdata->edit_bmesh->bm->ldata, CD_MLOOPCOL, i_src);
- }
-
- /* Gather number of auto layers. */
- /* We only do vcols that are not overridden by uvs */
- if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, name) == -1) {
- BLI_snprintf(rdata->cd.uuid.auto_mix[rdata->cd.layers.uv_len + i_dst],
- sizeof(*rdata->cd.uuid.auto_mix),
- "a%u",
- hash);
- rdata->cd.layers.auto_vcol[i_dst] = true;
- }
- }
- }
- /* Actual active Vcol slot inside vcol layers used for shading. */
- if (rdata->cd.layers.vcol_active != -1) {
- rdata->cd.layers.vcol_active = act_vcol;
- }
- if (rdata->cd.layers.vcol_render != -1) {
- rdata->cd.layers.vcol_render = ren_vcol;
- }
- }
-
- /* Start Fresh */
- CustomData_free_layers(cd_ldata, CD_TANGENT, rdata->loop_len);
- CustomData_free_layers(cd_ldata, CD_MLOOPTANGENT, rdata->loop_len);
-
- if (rdata->cd.layers.uv_len != 0) {
- int ren_uv = rdata->cd.layers.uv_render;
- int act_uv = rdata->cd.layers.uv_active;
- for (int i_src = 0, i_dst = 0; i_src < cd_layers_src.uv_len; i_src++, i_dst++) {
- if ((cd_used->uv & (1 << i_src)) == 0) {
- /* This is a non-used UV slot. Skip. */
- i_dst--;
- if (rdata->cd.layers.uv_render >= i_src) {
- ren_uv--;
- }
- if (rdata->cd.layers.uv_active >= i_src) {
- act_uv--;
- }
- }
- else {
- const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i_src);
- uint hash = BLI_ghashutil_strhash_p(name);
-
- BLI_snprintf(rdata->cd.uuid.uv[i_dst], sizeof(*rdata->cd.uuid.uv), "u%u", hash);
- rdata->cd.layers.uv[i_dst] = CustomData_get_layer_n(cd_ldata, CD_MLOOPUV, i_src);
- if (rdata->edit_bmesh) {
- rdata->cd.offset.uv[i_dst] = CustomData_get_n_offset(
- &rdata->edit_bmesh->bm->ldata, CD_MLOOPUV, i_src);
- }
- BLI_snprintf(
- rdata->cd.uuid.auto_mix[i_dst], sizeof(*rdata->cd.uuid.auto_mix), "a%u", hash);
- }
- }
- /* Actual active / Render UV slot inside uv layers used for shading. */
- if (rdata->cd.layers.uv_render != -1) {
- rdata->cd.layers.uv_render = ren_uv;
- }
- if (rdata->cd.layers.uv_active != -1) {
- rdata->cd.layers.uv_active = act_uv;
- }
- }
-
- if (rdata->cd.layers.tangent_len != 0) {
-
- /* -------------------------------------------------------------------- */
- /* Pre-calculate tangents into 'rdata->cd.output.ldata' */
-
- BLI_assert(!CustomData_has_layer(&rdata->cd.output.ldata, CD_TANGENT));
-
- /* Tangent Names */
- char tangent_names[MAX_MTFACE][MAX_NAME];
- for (int i_src = 0, i_dst = 0; i_src < cd_layers_src.uv_len; i_src++, i_dst++) {
- if ((cd_used->tan & (1 << i_src)) == 0) {
- i_dst--;
- }
- else {
- BLI_strncpy(tangent_names[i_dst],
- CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i_src),
- MAX_NAME);
- }
- }
-
- /* If tangent from orco is requested, decrement tangent_len */
- int actual_tangent_len = (cd_used->tan_orco != 0) ? rdata->cd.layers.tangent_len - 1 :
- rdata->cd.layers.tangent_len;
- if (rdata->edit_bmesh) {
- BMEditMesh *em = rdata->edit_bmesh;
- BMesh *bm = em->bm;
-
- if (is_auto_smooth && rdata->loop_normals == NULL) {
- /* Should we store the previous array of `loop_normals` in somewhere? */
- rdata->loop_len = bm->totloop;
- rdata->loop_normals = MEM_mallocN(sizeof(*rdata->loop_normals) * rdata->loop_len,
- __func__);
- BM_loops_calc_normal_vcos(
- bm, NULL, NULL, NULL, true, split_angle, rdata->loop_normals, NULL, NULL, -1, false);
- }
-
- bool calc_active_tangent = false;
-
- BKE_editmesh_loop_tangent_calc(em,
- calc_active_tangent,
- tangent_names,
- actual_tangent_len,
- rdata->poly_normals,
- rdata->loop_normals,
- rdata->orco,
- &rdata->cd.output.ldata,
- bm->totloop,
- &rdata->cd.output.tangent_mask);
- }
- else {
-#undef me
-
- if (is_auto_smooth && rdata->loop_normals == NULL) {
- /* Should we store the previous array of `loop_normals` in CustomData? */
- mesh_render_calc_normals_loop_and_poly(me, split_angle, rdata);
- }
-
- bool calc_active_tangent = false;
-
- BKE_mesh_calc_loop_tangent_ex(me->mvert,
- me->mpoly,
- me->totpoly,
- me->mloop,
- rdata->mlooptri,
- rdata->tri_len,
- cd_ldata,
- calc_active_tangent,
- tangent_names,
- actual_tangent_len,
- rdata->poly_normals,
- rdata->loop_normals,
- rdata->orco,
- &rdata->cd.output.ldata,
- me->totloop,
- &rdata->cd.output.tangent_mask);
-
- /* If we store tangents in the mesh, set temporary. */
-#if 0
- CustomData_set_layer_flag(cd_ldata, CD_TANGENT, CD_FLAG_TEMPORARY);
-#endif
-
-#define me DONT_USE_THIS
-#ifdef me /* quiet warning */
-#endif
- }
-
- /* End tangent calculation */
- /* -------------------------------------------------------------------- */
-
- BLI_assert(CustomData_number_of_layers(&rdata->cd.output.ldata, CD_TANGENT) ==
- rdata->cd.layers.tangent_len);
-
- int i_dst = 0;
- int act_tan = rdata->cd.layers.tangent_active;
- int ren_tan = rdata->cd.layers.tangent_render;
- for (int i_src = 0; i_src < cd_layers_src.uv_len; i_src++, i_dst++) {
- if ((cd_used->tan & (1 << i_src)) == 0) {
- i_dst--;
- if (rdata->cd.layers.tangent_render >= i_src) {
- ren_tan--;
- }
- if (rdata->cd.layers.tangent_active >= i_src) {
- act_tan--;
- }
- }
- else {
- const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i_src);
- uint hash = BLI_ghashutil_strhash_p(name);
-
- BLI_snprintf(
- rdata->cd.uuid.tangent[i_dst], sizeof(*rdata->cd.uuid.tangent), "t%u", hash);
-
- /* Done adding tangents. */
-
- /* note: BKE_editmesh_loop_tangent_calc calculates 'CD_TANGENT',
- * not 'CD_MLOOPTANGENT' (as done below). It's OK, they're compatible. */
-
- /* note: normally we'd use 'i_src' here, but 'i_dst' is in sync with 'rdata->cd.output'
- */
- rdata->cd.layers.tangent[i_dst] = CustomData_get_layer_n(
- &rdata->cd.output.ldata, CD_TANGENT, i_dst);
- if (rdata->tri_len != 0) {
- BLI_assert(rdata->cd.layers.tangent[i_dst] != NULL);
- }
- }
- }
- /* Actual active rangent slot inside uv layers used for shading. */
- if (rdata->cd.layers.tangent_active != -1) {
- rdata->cd.layers.tangent_active = act_tan;
- }
- if (rdata->cd.layers.tangent_render != -1) {
- rdata->cd.layers.tangent_render = ren_tan;
- }
-
- if (cd_used->tan_orco != 0) {
- const char *name = CustomData_get_layer_name(&rdata->cd.output.ldata, CD_TANGENT, i_dst);
- uint hash = BLI_ghashutil_strhash_p(name);
- BLI_snprintf(rdata->cd.uuid.tangent[i_dst], sizeof(*rdata->cd.uuid.tangent), "t%u", hash);
-
- rdata->cd.layers.tangent[i_dst] = CustomData_get_layer_n(
- &rdata->cd.output.ldata, CD_TANGENT, i_dst);
- }
- }
-
-#undef me
- }
-
- return rdata;
-}
-
-/* Warning replace mesh pointer. */
-#define MBC_GET_FINAL_MESH(me) \
- /* Hack to show the final result. */ \
- const bool _use_em_final = ((me)->edit_mesh && (me)->edit_mesh->mesh_eval_final && \
- ((me)->edit_mesh->mesh_eval_final->runtime.is_original == false)); \
- Mesh _me_fake; \
- if (_use_em_final) { \
- _me_fake = *(me)->edit_mesh->mesh_eval_final; \
- _me_fake.mat = (me)->mat; \
- _me_fake.totcol = (me)->totcol; \
- (me) = &_me_fake; \
- } \
- ((void)0)
-
-static void mesh_render_data_free(MeshRenderData *rdata)
-{
- if (rdata->is_orco_allocated) {
- MEM_SAFE_FREE(rdata->orco);
- }
- MEM_SAFE_FREE(rdata->cd.offset.uv);
- MEM_SAFE_FREE(rdata->cd.offset.vcol);
- MEM_SAFE_FREE(rdata->cd.uuid.auto_mix);
- MEM_SAFE_FREE(rdata->cd.uuid.uv);
- MEM_SAFE_FREE(rdata->cd.uuid.vcol);
- MEM_SAFE_FREE(rdata->cd.uuid.tangent);
- MEM_SAFE_FREE(rdata->cd.layers.uv);
- MEM_SAFE_FREE(rdata->cd.layers.vcol);
- MEM_SAFE_FREE(rdata->cd.layers.tangent);
- MEM_SAFE_FREE(rdata->cd.layers.auto_vcol);
- MEM_SAFE_FREE(rdata->loose_verts);
- MEM_SAFE_FREE(rdata->loose_edges);
- MEM_SAFE_FREE(rdata->edges_adjacent_polys);
- MEM_SAFE_FREE(rdata->mlooptri);
- MEM_SAFE_FREE(rdata->loop_normals);
- MEM_SAFE_FREE(rdata->poly_normals);
- MEM_SAFE_FREE(rdata->poly_normals_pack);
- MEM_SAFE_FREE(rdata->vert_normals_pack);
- MEM_SAFE_FREE(rdata->vert_weight);
- MEM_SAFE_FREE(rdata->edge_select_bool);
- MEM_SAFE_FREE(rdata->edge_visible_bool);
- MEM_SAFE_FREE(rdata->vert_color);
-
- MEM_SAFE_FREE(rdata->mapped.loose_verts);
- MEM_SAFE_FREE(rdata->mapped.loose_edges);
-
- CustomData_free(&rdata->cd.output.ldata, rdata->loop_len);
-
- MEM_freeN(rdata);
-}
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Accessor Functions
- * \{ */
-
-static const char *mesh_render_data_uv_auto_layer_uuid_get(const MeshRenderData *rdata, int layer)
-{
- BLI_assert(rdata->types & MR_DATATYPE_SHADING);
- return rdata->cd.uuid.auto_mix[layer];
-}
-
-static const char *mesh_render_data_vcol_auto_layer_uuid_get(const MeshRenderData *rdata,
- int layer)
-{
- BLI_assert(rdata->types & MR_DATATYPE_SHADING);
- return rdata->cd.uuid.auto_mix[rdata->cd.layers.uv_len + layer];
-}
-
-static const char *mesh_render_data_uv_layer_uuid_get(const MeshRenderData *rdata, int layer)
-{
- BLI_assert(rdata->types & MR_DATATYPE_SHADING);
- return rdata->cd.uuid.uv[layer];
-}
-
-static const char *mesh_render_data_vcol_layer_uuid_get(const MeshRenderData *rdata, int layer)
-{
- BLI_assert(rdata->types & MR_DATATYPE_SHADING);
- return rdata->cd.uuid.vcol[layer];
-}
-
-static const char *mesh_render_data_tangent_layer_uuid_get(const MeshRenderData *rdata, int layer)
-{
- BLI_assert(rdata->types & MR_DATATYPE_SHADING);
- return rdata->cd.uuid.tangent[layer];
-}
-
-static int UNUSED_FUNCTION(mesh_render_data_verts_len_get)(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_VERT);
- return rdata->vert_len;
-}
-static int mesh_render_data_verts_len_get_maybe_mapped(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_VERT);
- return ((rdata->mapped.use == false) ? rdata->vert_len : rdata->mapped.vert_len);
-}
-
-static int UNUSED_FUNCTION(mesh_render_data_loose_verts_len_get)(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_LOOSE_VERT);
- return rdata->loose_vert_len;
-}
-static int mesh_render_data_loose_verts_len_get_maybe_mapped(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_LOOSE_VERT);
- return ((rdata->mapped.use == false) ? rdata->loose_vert_len : rdata->mapped.loose_vert_len);
-}
-
-static int mesh_render_data_edges_len_get(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_EDGE);
- return rdata->edge_len;
-}
-static int mesh_render_data_edges_len_get_maybe_mapped(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_EDGE);
- return ((rdata->mapped.use == false) ? rdata->edge_len : rdata->mapped.edge_len);
-}
-
-static int UNUSED_FUNCTION(mesh_render_data_loose_edges_len_get)(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_LOOSE_EDGE);
- return rdata->loose_edge_len;
-}
-static int mesh_render_data_loose_edges_len_get_maybe_mapped(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_LOOSE_EDGE);
- return ((rdata->mapped.use == false) ? rdata->loose_edge_len : rdata->mapped.loose_edge_len);
-}
-
-static int mesh_render_data_looptri_len_get(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_LOOPTRI);
- return rdata->tri_len;
-}
-static int mesh_render_data_looptri_len_get_maybe_mapped(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_LOOPTRI);
- return ((rdata->mapped.use == false) ? rdata->tri_len : rdata->mapped.tri_len);
-}
-
-static int UNUSED_FUNCTION(mesh_render_data_mat_len_get)(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_POLY);
- return rdata->mat_len;
-}
-
-static int mesh_render_data_loops_len_get(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_LOOP);
- return rdata->loop_len;
-}
-
-static int mesh_render_data_loops_len_get_maybe_mapped(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_LOOP);
- return ((rdata->mapped.use == false) ? rdata->loop_len : rdata->mapped.loop_len);
-}
-
-static int mesh_render_data_polys_len_get(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_POLY);
- return rdata->poly_len;
-}
-static int mesh_render_data_polys_len_get_maybe_mapped(const MeshRenderData *rdata)
-{
- BLI_assert(rdata->types & MR_DATATYPE_POLY);
- return ((rdata->mapped.use == false) ? rdata->poly_len : rdata->mapped.poly_len);
-}
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-
-/** \name Internal Cache (Lazy Initialization)
- * \{ */
-
-/** Ensure #MeshRenderData.poly_normals_pack */
-static void mesh_render_data_ensure_poly_normals_pack(MeshRenderData *rdata)
-{
- GPUPackedNormal *pnors_pack = rdata->poly_normals_pack;
- if (pnors_pack == NULL) {
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter fiter;
- BMFace *efa;
- int i;
-
- pnors_pack = rdata->poly_normals_pack = MEM_mallocN(sizeof(*pnors_pack) * rdata->poly_len,
- __func__);
- if (rdata->edit_data && rdata->edit_data->vertexCos != NULL) {
- BKE_editmesh_cache_ensure_poly_normals(rdata->edit_bmesh, rdata->edit_data);
- const float(*pnors)[3] = rdata->edit_data->polyNos;
- for (i = 0; i < bm->totface; i++) {
- pnors_pack[i] = GPU_normal_convert_i10_v3(pnors[i]);
- }
- }
- else {
- BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
- pnors_pack[i] = GPU_normal_convert_i10_v3(efa->no);
- }
- }
- }
- else {
- float(*pnors)[3] = rdata->poly_normals;
-
- if (!pnors) {
- pnors = rdata->poly_normals = MEM_mallocN(sizeof(*pnors) * rdata->poly_len, __func__);
- BKE_mesh_calc_normals_poly(rdata->mvert,
- NULL,
- rdata->vert_len,
- rdata->mloop,
- rdata->mpoly,
- rdata->loop_len,
- rdata->poly_len,
- pnors,
- true);
- }
-
- pnors_pack = rdata->poly_normals_pack = MEM_mallocN(sizeof(*pnors_pack) * rdata->poly_len,
- __func__);
- for (int i = 0; i < rdata->poly_len; i++) {
- pnors_pack[i] = GPU_normal_convert_i10_v3(pnors[i]);
- }
- }
- }
-}
-
-/** Ensure #MeshRenderData.vert_normals_pack */
-static void mesh_render_data_ensure_vert_normals_pack(MeshRenderData *rdata)
-{
- GPUPackedNormal *vnors_pack = rdata->vert_normals_pack;
- if (vnors_pack == NULL) {
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter viter;
- BMVert *eve;
- int i;
-
- vnors_pack = rdata->vert_normals_pack = MEM_mallocN(sizeof(*vnors_pack) * rdata->vert_len,
- __func__);
- BM_ITER_MESH_INDEX (eve, &viter, bm, BM_VERT, i) {
- vnors_pack[i] = GPU_normal_convert_i10_v3(eve->no);
- }
- }
- else {
- /* data from mesh used directly */
- BLI_assert(0);
- }
- }
-}
-
-/** Ensure #MeshRenderData.vert_color */
-static void UNUSED_FUNCTION(mesh_render_data_ensure_vert_color)(MeshRenderData *rdata)
-{
- char(*vcol)[3] = rdata->vert_color;
- if (vcol == NULL) {
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
- if (cd_loop_color_offset == -1) {
- goto fallback;
- }
-
- vcol = rdata->vert_color = MEM_mallocN(sizeof(*vcol) * rdata->loop_len, __func__);
-
- BMIter fiter;
- BMFace *efa;
- int i = 0;
-
- BM_ITER_MESH (efa, &fiter, bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- do {
- const MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_color_offset);
- vcol[i][0] = lcol->r;
- vcol[i][1] = lcol->g;
- vcol[i][2] = lcol->b;
- i += 1;
- } while ((l_iter = l_iter->next) != l_first);
- }
- BLI_assert(i == rdata->loop_len);
- }
- else {
- if (rdata->mloopcol == NULL) {
- goto fallback;
- }
-
- vcol = rdata->vert_color = MEM_mallocN(sizeof(*vcol) * rdata->loop_len, __func__);
-
- for (int i = 0; i < rdata->loop_len; i++) {
- vcol[i][0] = rdata->mloopcol[i].r;
- vcol[i][1] = rdata->mloopcol[i].g;
- vcol[i][2] = rdata->mloopcol[i].b;
- }
- }
- }
- return;
-
-fallback:
- vcol = rdata->vert_color = MEM_mallocN(sizeof(*vcol) * rdata->loop_len, __func__);
-
- for (int i = 0; i < rdata->loop_len; i++) {
- vcol[i][0] = 255;
- vcol[i][1] = 255;
- vcol[i][2] = 255;
- }
-}
-
-static float evaluate_vertex_weight(const MDeformVert *dvert, const DRW_MeshWeightState *wstate)
-{
- float input = 0.0f;
- bool show_alert_color = false;
-
- if (wstate->flags & DRW_MESH_WEIGHT_STATE_MULTIPAINT) {
- /* Multi-Paint feature */
- input = BKE_defvert_multipaint_collective_weight(
- dvert,
- wstate->defgroup_len,
- wstate->defgroup_sel,
- wstate->defgroup_sel_count,
- (wstate->flags & DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE) != 0);
-
- /* make it black if the selected groups have no weight on a vertex */
- if (input == 0.0f) {
- show_alert_color = true;
- }
- }
- else {
- /* default, non tricky behavior */
- input = defvert_find_weight(dvert, wstate->defgroup_active);
-
- if (input == 0.0f) {
- switch (wstate->alert_mode) {
- case OB_DRAW_GROUPUSER_ACTIVE:
- show_alert_color = true;
- break;
-
- case OB_DRAW_GROUPUSER_ALL:
- show_alert_color = defvert_is_weight_zero(dvert, wstate->defgroup_len);
- break;
- }
- }
- }
-
- if (show_alert_color) {
- return -1.0f;
- }
- else {
- CLAMP(input, 0.0f, 1.0f);
- return input;
- }
-}
-
-/** Ensure #MeshRenderData.vert_weight */
-static void mesh_render_data_ensure_vert_weight(MeshRenderData *rdata,
- const struct DRW_MeshWeightState *wstate)
-{
- float *vweight = rdata->vert_weight;
- if (vweight == NULL) {
- if (wstate->defgroup_active == -1) {
- goto fallback;
- }
-
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
- if (cd_dvert_offset == -1) {
- goto fallback;
- }
-
- BMIter viter;
- BMVert *eve;
- int i;
-
- vweight = rdata->vert_weight = MEM_mallocN(sizeof(*vweight) * rdata->vert_len, __func__);
- BM_ITER_MESH_INDEX (eve, &viter, bm, BM_VERT, i) {
- const MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
- vweight[i] = evaluate_vertex_weight(dvert, wstate);
- }
- }
- else {
- if (rdata->dvert == NULL) {
- goto fallback;
- }
-
- vweight = rdata->vert_weight = MEM_mallocN(sizeof(*vweight) * rdata->vert_len, __func__);
- for (int i = 0; i < rdata->vert_len; i++) {
- vweight[i] = evaluate_vertex_weight(&rdata->dvert[i], wstate);
- }
- }
- }
- return;
-
-fallback:
- vweight = rdata->vert_weight = MEM_callocN(sizeof(*vweight) * rdata->vert_len, __func__);
-
- if ((wstate->defgroup_active < 0) && (wstate->defgroup_len > 0)) {
- copy_vn_fl(vweight, rdata->vert_len, -2.0f);
- }
- else if (wstate->alert_mode != OB_DRAW_GROUPUSER_NONE) {
- copy_vn_fl(vweight, rdata->vert_len, -1.0f);
- }
-}
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Internal Cache Generation
- * \{ */
-
-static uchar mesh_render_data_face_flag(MeshRenderData *rdata, const BMFace *efa, const int cd_ofs)
-{
- uchar fflag = 0;
-
- if (efa == rdata->efa_act) {
- fflag |= VFLAG_FACE_ACTIVE;
- }
- if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- fflag |= VFLAG_FACE_SELECTED;
- }
-
- if (efa == rdata->efa_act_uv) {
- fflag |= VFLAG_FACE_UV_ACTIVE;
- }
- if ((cd_ofs != -1) && uvedit_face_select_test_ex(rdata->toolsettings, (BMFace *)efa, cd_ofs)) {
- fflag |= VFLAG_FACE_UV_SELECT;
- }
-
-#ifdef WITH_FREESTYLE
- if (rdata->cd.offset.freestyle_face != -1) {
- const FreestyleFace *ffa = BM_ELEM_CD_GET_VOID_P(efa, rdata->cd.offset.freestyle_face);
- if (ffa->flag & FREESTYLE_FACE_MARK) {
- fflag |= VFLAG_FACE_FREESTYLE;
- }
- }
-#endif
-
- return fflag;
-}
-
-static void mesh_render_data_edge_flag(const MeshRenderData *rdata,
- const BMEdge *eed,
- EdgeDrawAttr *eattr)
-{
- const ToolSettings *ts = rdata->toolsettings;
- const bool is_vertex_select_mode = (ts != NULL) && (ts->selectmode & SCE_SELECT_VERTEX) != 0;
- const bool is_face_only_select_mode = (ts != NULL) && (ts->selectmode == SCE_SELECT_FACE);
-
- if (eed == rdata->eed_act) {
- eattr->e_flag |= VFLAG_EDGE_ACTIVE;
- }
- if (!is_vertex_select_mode && BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- eattr->e_flag |= VFLAG_EDGE_SELECTED;
- }
- if (is_vertex_select_mode && BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) &&
- BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) {
- eattr->e_flag |= VFLAG_EDGE_SELECTED;
- eattr->e_flag |= VFLAG_VERT_SELECTED;
- }
- if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
- eattr->e_flag |= VFLAG_EDGE_SEAM;
- }
- if (!BM_elem_flag_test(eed, BM_ELEM_SMOOTH)) {
- eattr->e_flag |= VFLAG_EDGE_SHARP;
- }
-
- /* Use active edge color for active face edges because
- * specular highlights make it hard to see T55456#510873.
- *
- * This isn't ideal since it can't be used when mixing edge/face modes
- * but it's still better then not being able to see the active face. */
- if (is_face_only_select_mode) {
- if (rdata->efa_act != NULL) {
- if (BM_edge_in_face(eed, rdata->efa_act)) {
- eattr->e_flag |= VFLAG_EDGE_ACTIVE;
- }
- }
- }
-
- /* Use a byte for value range */
- if (rdata->cd.offset.crease != -1) {
- float crease = BM_ELEM_CD_GET_FLOAT(eed, rdata->cd.offset.crease);
- if (crease > 0) {
- eattr->crease = (uchar)(crease * 255.0f);
- }
- }
- /* Use a byte for value range */
- if (rdata->cd.offset.bweight != -1) {
- float bweight = BM_ELEM_CD_GET_FLOAT(eed, rdata->cd.offset.bweight);
- if (bweight > 0) {
- eattr->bweight = (uchar)(bweight * 255.0f);
- }
- }
-#ifdef WITH_FREESTYLE
- if (rdata->cd.offset.freestyle_edge != -1) {
- const FreestyleEdge *fed = BM_ELEM_CD_GET_VOID_P(eed, rdata->cd.offset.freestyle_edge);
- if (fed->flag & FREESTYLE_EDGE_MARK) {
- eattr->e_flag |= VFLAG_EDGE_FREESTYLE;
- }
- }
-#endif
-}
-
-static void mesh_render_data_loop_flag(MeshRenderData *rdata,
- BMLoop *loop,
- const int cd_ofs,
- EdgeDrawAttr *eattr)
-{
- if (cd_ofs == -1) {
- return;
- }
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, cd_ofs);
- if (luv != NULL && (luv->flag & MLOOPUV_PINNED)) {
- eattr->v_flag |= VFLAG_VERT_UV_PINNED;
- }
- if (uvedit_uv_select_test_ex(rdata->toolsettings, loop, cd_ofs)) {
- eattr->v_flag |= VFLAG_VERT_UV_SELECT;
- }
- if (uvedit_edge_select_test_ex(rdata->toolsettings, loop, cd_ofs)) {
- eattr->v_flag |= VFLAG_EDGE_UV_SELECT;
- }
-}
-
-static void mesh_render_data_vert_flag(MeshRenderData *rdata,
- const BMVert *eve,
- EdgeDrawAttr *eattr)
-{
- if (eve == rdata->eve_act) {
- eattr->e_flag |= VFLAG_VERT_ACTIVE;
- }
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- eattr->e_flag |= VFLAG_VERT_SELECTED;
- }
-}
-
-static bool add_edit_facedot(MeshRenderData *rdata,
- GPUVertBuf *vbo,
- const uint fdot_pos_id,
- const uint fdot_nor_flag_id,
- const int poly,
- const int base_vert_idx)
-{
- BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
- float pnor[3], center[3];
- int facedot_flag;
- if (rdata->edit_bmesh) {
- BMEditMesh *em = rdata->edit_bmesh;
- const BMFace *efa = BM_face_at_index(em->bm, poly);
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- return false;
- }
- if (rdata->edit_data && rdata->edit_data->vertexCos) {
- copy_v3_v3(center, rdata->edit_data->polyCos[poly]);
- copy_v3_v3(pnor, rdata->edit_data->polyNos[poly]);
- }
- else {
- BM_face_calc_center_median(efa, center);
- copy_v3_v3(pnor, efa->no);
- }
- facedot_flag = BM_elem_flag_test(efa, BM_ELEM_SELECT) ? ((efa == em->bm->act_face) ? -1 : 1) :
- 0;
- }
- else {
- MVert *mvert = rdata->mvert;
- const MPoly *mpoly = rdata->mpoly + poly;
- const MLoop *mloop = rdata->mloop + mpoly->loopstart;
-
- BKE_mesh_calc_poly_center(mpoly, mloop, mvert, center);
- BKE_mesh_calc_poly_normal(mpoly, mloop, mvert, pnor);
- /* No selection if not in edit mode. */
- facedot_flag = 0;
- }
-
- GPUPackedNormal nor = GPU_normal_convert_i10_v3(pnor);
- nor.w = facedot_flag;
- GPU_vertbuf_attr_set(vbo, fdot_nor_flag_id, base_vert_idx, &nor);
- GPU_vertbuf_attr_set(vbo, fdot_pos_id, base_vert_idx, center);
-
- return true;
-}
-static bool add_edit_facedot_mapped(MeshRenderData *rdata,
- GPUVertBuf *vbo,
- const uint fdot_pos_id,
- const uint fdot_nor_flag_id,
- const int poly,
- const int base_vert_idx)
-{
- BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
- float pnor[3], center[3];
- const int *p_origindex = rdata->mapped.p_origindex;
- const int p_orig = p_origindex[poly];
- if (p_orig == ORIGINDEX_NONE) {
- return false;
- }
- BMEditMesh *em = rdata->edit_bmesh;
- const BMFace *efa = BM_face_at_index(em->bm, p_orig);
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- return false;
- }
-
- Mesh *me_cage = em->mesh_eval_cage;
- const MVert *mvert = me_cage->mvert;
- const MLoop *mloop = me_cage->mloop;
- const MPoly *mpoly = me_cage->mpoly;
-
- const MPoly *mp = mpoly + poly;
- const MLoop *ml = mloop + mp->loopstart;
-
- BKE_mesh_calc_poly_center(mp, ml, mvert, center);
- BKE_mesh_calc_poly_normal(mp, ml, mvert, pnor);
-
- GPUPackedNormal nor = GPU_normal_convert_i10_v3(pnor);
- nor.w = BM_elem_flag_test(efa, BM_ELEM_SELECT) ? ((efa == em->bm->act_face) ? -1 : 1) : 0;
- GPU_vertbuf_attr_set(vbo, fdot_nor_flag_id, base_vert_idx, &nor);
- GPU_vertbuf_attr_set(vbo, fdot_pos_id, base_vert_idx, center);
-
- return true;
-}
-static bool add_edit_facedot_subdiv(MeshRenderData *rdata,
- GPUVertBuf *vbo,
- const uint fdot_pos_id,
- const uint fdot_nor_flag_id,
- const int vert,
- const int poly,
- const int base_vert_idx)
-{
- BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
- const int *p_origindex = rdata->mapped.p_origindex;
- const int p_orig = p_origindex[poly];
- if (p_orig == ORIGINDEX_NONE) {
- return false;
- }
- BMEditMesh *em = rdata->edit_bmesh;
- const BMFace *efa = BM_face_at_index(em->bm, p_orig);
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- return false;
- }
-
- Mesh *me_cage = em->mesh_eval_cage;
- const MVert *mvert = &me_cage->mvert[vert];
-
- GPUPackedNormal nor = GPU_normal_convert_i10_s3(mvert->no);
- nor.w = BM_elem_flag_test(efa, BM_ELEM_SELECT) ? ((efa == em->bm->act_face) ? -1 : 1) : 0;
- GPU_vertbuf_attr_set(vbo, fdot_nor_flag_id, base_vert_idx, &nor);
- GPU_vertbuf_attr_set(vbo, fdot_pos_id, base_vert_idx, mvert->co);
-
- return true;
-}
-
/** \} */
/* ---------------------------------------------------------------------- */
@@ -1963,170 +370,6 @@ static void drw_mesh_weight_state_extract(Object *ob,
/** \name Mesh GPUBatch Cache
* \{ */
-typedef enum DRWBatchFlag {
- MBC_SURFACE = (1 << 0),
- MBC_SURFACE_WEIGHTS = (1 << 1),
- MBC_EDIT_TRIANGLES = (1 << 2),
- MBC_EDIT_VERTICES = (1 << 3),
- MBC_EDIT_EDGES = (1 << 4),
- MBC_EDIT_LNOR = (1 << 5),
- MBC_EDIT_FACEDOTS = (1 << 6),
- MBC_EDIT_MESH_ANALYSIS = (1 << 7),
- MBC_EDITUV_FACES_STRECH_AREA = (1 << 8),
- MBC_EDITUV_FACES_STRECH_ANGLE = (1 << 9),
- MBC_EDITUV_FACES = (1 << 10),
- MBC_EDITUV_EDGES = (1 << 11),
- MBC_EDITUV_VERTS = (1 << 12),
- MBC_EDITUV_FACEDOTS = (1 << 13),
- MBC_EDIT_SELECTION_VERTS = (1 << 14),
- MBC_EDIT_SELECTION_EDGES = (1 << 15),
- MBC_EDIT_SELECTION_FACES = (1 << 16),
- MBC_EDIT_SELECTION_FACEDOTS = (1 << 17),
- MBC_ALL_VERTS = (1 << 18),
- MBC_ALL_EDGES = (1 << 19),
- MBC_LOOSE_EDGES = (1 << 20),
- MBC_EDGE_DETECTION = (1 << 21),
- MBC_WIRE_EDGES = (1 << 22),
- MBC_WIRE_LOOPS = (1 << 23),
- MBC_WIRE_LOOPS_UVS = (1 << 24),
- MBC_SURF_PER_MAT = (1 << 25),
-} DRWBatchFlag;
-
-#define MBC_EDITUV \
- (MBC_EDITUV_FACES_STRECH_AREA | MBC_EDITUV_FACES_STRECH_ANGLE | MBC_EDITUV_FACES | \
- MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_EDITUV_FACEDOTS)
-
-typedef struct MeshBatchCache {
- /* In order buffers: All verts only specified once
- * or once per loop. To be used with a GPUIndexBuf. */
- struct {
- /* Vertex data. */
- GPUVertBuf *pos_nor;
- GPUVertBuf *weights;
- /* Loop data. */
- GPUVertBuf *loop_pos_nor;
- GPUVertBuf *loop_uv_tan;
- GPUVertBuf *loop_vcol;
- GPUVertBuf *loop_edge_fac;
- GPUVertBuf *loop_orco;
- } ordered;
-
- /* Edit Mesh Data:
- * Edit cage can be different from final mesh so vertex count
- * might differ. */
- struct {
- /* TODO(fclem): Reuse ordered.loop_pos_nor and maybe even
- * ordered.loop_uv_tan when cage match final mesh. */
- GPUVertBuf *loop_pos_nor;
- GPUVertBuf *loop_data;
- GPUVertBuf *loop_lnor;
- GPUVertBuf *facedots_pos_nor_data;
- GPUVertBuf *loop_mesh_analysis;
- /* UV data without modifier applied.
- * Vertex count is always the one of the cage. */
- GPUVertBuf *loop_uv;
- GPUVertBuf *loop_uv_data;
- GPUVertBuf *loop_stretch_angle;
- GPUVertBuf *loop_stretch_area;
- GPUVertBuf *facedots_uv;
- GPUVertBuf *facedots_uv_data;
- /* Selection */
- GPUVertBuf *loop_vert_idx;
- GPUVertBuf *loop_edge_idx;
- GPUVertBuf *loop_face_idx;
- GPUVertBuf *facedots_idx;
- } edit;
-
- /* Index Buffers:
- * Only need to be updated when topology changes. */
- struct {
- /* Indices to verts. */
- GPUIndexBuf *surf_tris;
- GPUIndexBuf *edges_lines;
- GPUIndexBuf *edges_adj_lines;
- GPUIndexBuf *loose_edges_lines;
- /* Indices to vloops. */
- GPUIndexBuf *loops_tris;
- GPUIndexBuf *loops_lines;
- GPUIndexBuf *loops_lines_paint_mask;
- GPUIndexBuf *loops_line_strips;
- /* Edit mode. */
- GPUIndexBuf *edit_loops_points; /* verts */
- GPUIndexBuf *edit_loops_lines; /* edges */
- GPUIndexBuf *edit_loops_tris; /* faces */
- /* Edit UVs */
- GPUIndexBuf *edituv_loops_points; /* verts */
- GPUIndexBuf *edituv_loops_line_strips; /* edges */
- GPUIndexBuf *edituv_loops_tri_fans; /* faces */
- } ibo;
-
- struct {
- /* Surfaces / Render */
- GPUBatch *surface;
- GPUBatch *surface_weights;
- /* Edit mode */
- GPUBatch *edit_triangles;
- GPUBatch *edit_vertices;
- GPUBatch *edit_edges;
- GPUBatch *edit_lnor;
- GPUBatch *edit_facedots;
- GPUBatch *edit_mesh_analysis;
- /* Edit UVs */
- GPUBatch *edituv_faces_strech_area;
- GPUBatch *edituv_faces_strech_angle;
- GPUBatch *edituv_faces;
- GPUBatch *edituv_edges;
- GPUBatch *edituv_verts;
- GPUBatch *edituv_facedots;
- /* Edit selection */
- GPUBatch *edit_selection_verts;
- GPUBatch *edit_selection_edges;
- GPUBatch *edit_selection_faces;
- GPUBatch *edit_selection_facedots;
- /* Common display / Other */
- GPUBatch *all_verts;
- GPUBatch *all_edges;
- GPUBatch *loose_edges;
- GPUBatch *edge_detection;
- GPUBatch *wire_edges; /* Individual edges with face normals. */
- GPUBatch *wire_loops; /* Loops around faces. no edges between selected faces */
- GPUBatch *wire_loops_uvs; /* Same as wire_loops but only has uvs. */
- } batch;
-
- GPUIndexBuf **surf_per_mat_tris;
- GPUBatch **surf_per_mat;
-
- /* arrays of bool uniform names (and value) that will be use to
- * set srgb conversion for auto attributes.*/
- char *auto_layer_names;
- int *auto_layer_is_srgb;
- int auto_layer_len;
-
- DRWBatchFlag batch_requested;
- DRWBatchFlag batch_ready;
-
- /* settings to determine if cache is invalid */
- int edge_len;
- int tri_len;
- int poly_len;
- int vert_len;
- int mat_len;
- bool is_dirty; /* Instantly invalidates cache, skipping mesh check */
- bool is_editmode;
- bool is_uvsyncsel;
-
- struct DRW_MeshWeightState weight_state;
-
- DRW_MeshCDMask cd_used, cd_needed, cd_used_over_time;
-
- int lastmatch;
-
- /* Valid only if edge_detection is up to date. */
- bool is_manifold;
-
- bool no_loose_wire;
-} MeshBatchCache;
-
BLI_INLINE void mesh_batch_cache_add_request(MeshBatchCache *cache, DRWBatchFlag new_flag)
{
atomic_fetch_and_or_uint32((uint32_t *)(&cache->batch_requested), *(uint32_t *)&new_flag);
@@ -2171,16 +414,14 @@ static void mesh_batch_cache_init(Mesh *me)
cache->is_editmode = me->edit_mesh != NULL;
if (cache->is_editmode == false) {
- cache->edge_len = mesh_render_edges_len_get(me);
- cache->tri_len = mesh_render_looptri_len_get(me);
- cache->poly_len = mesh_render_polys_len_get(me);
- cache->vert_len = mesh_render_verts_len_get(me);
+ // cache->edge_len = mesh_render_edges_len_get(me);
+ // cache->tri_len = mesh_render_looptri_len_get(me);
+ // cache->poly_len = mesh_render_polys_len_get(me);
+ // cache->vert_len = mesh_render_verts_len_get(me);
}
cache->mat_len = mesh_render_mat_len_get(me);
- cache->surf_per_mat_tris = MEM_callocN(sizeof(*cache->surf_per_mat_tris) * cache->mat_len,
- __func__);
- cache->surf_per_mat = MEM_callocN(sizeof(*cache->surf_per_mat) * cache->mat_len, __func__);
+ cache->surface_per_mat = MEM_callocN(sizeof(*cache->surface_per_mat) * cache->mat_len, __func__);
cache->is_dirty = false;
cache->batch_ready = 0;
@@ -2206,8 +447,11 @@ static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache,
const struct DRW_MeshWeightState *wstate)
{
if (!drw_mesh_weight_state_compare(&cache->weight_state, wstate)) {
+ FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
+ {
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.weights);
+ }
GPU_BATCH_CLEAR_SAFE(cache->batch.surface_weights);
- GPU_VERTBUF_DISCARD_SAFE(cache->ordered.weights);
cache->batch_ready &= ~MBC_SURFACE_WEIGHTS;
@@ -2217,23 +461,21 @@ static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache,
static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache)
{
- GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_pos_nor);
- GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_uv_tan);
- GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_vcol);
- GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_orco);
-
- if (cache->surf_per_mat_tris) {
- for (int i = 0; i < cache->mat_len; i++) {
- GPU_INDEXBUF_DISCARD_SAFE(cache->surf_per_mat_tris[i]);
- }
+ FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
+ {
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.pos_nor);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.uv);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.tan);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.vcol);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.orco);
}
- MEM_SAFE_FREE(cache->surf_per_mat_tris);
- if (cache->surf_per_mat) {
+
+ if (cache->surface_per_mat) {
for (int i = 0; i < cache->mat_len; i++) {
- GPU_BATCH_DISCARD_SAFE(cache->surf_per_mat[i]);
+ GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]);
}
}
- MEM_SAFE_FREE(cache->surf_per_mat);
+ MEM_SAFE_FREE(cache->surface_per_mat);
cache->batch_ready &= ~MBC_SURF_PER_MAT;
@@ -2247,21 +489,26 @@ static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache)
static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache)
{
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_stretch_angle);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_stretch_area);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_uv);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_uv_data);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.facedots_uv);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.facedots_uv_data);
- GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.edituv_loops_tri_fans);
- GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.edituv_loops_line_strips);
- GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.edituv_loops_points);
+ FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
+ {
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.stretch_angle);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.stretch_area);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.uv);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edituv_data);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_uv);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_edituv_data);
+ GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_tris);
+ GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_lines);
+ 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);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_edges);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_verts);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_facedots);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_fdots);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.wire_loops_uvs);
cache->batch_ready &= ~MBC_EDITUV;
}
@@ -2274,31 +521,41 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode)
}
switch (mode) {
case BKE_MESH_BATCH_DIRTY_SELECT:
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_data);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.facedots_pos_nor_data);
+ FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
+ {
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edit_data);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_nor);
+ }
GPU_BATCH_DISCARD_SAFE(cache->batch.edit_triangles);
GPU_BATCH_DISCARD_SAFE(cache->batch.edit_vertices);
GPU_BATCH_DISCARD_SAFE(cache->batch.edit_edges);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edit_facedots);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edit_selection_facedots);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edit_fdots);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edit_selection_verts);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edit_selection_edges);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edit_selection_faces);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edit_selection_fdots);
GPU_BATCH_DISCARD_SAFE(cache->batch.edit_mesh_analysis);
cache->batch_ready &= ~(MBC_EDIT_TRIANGLES | MBC_EDIT_VERTICES | MBC_EDIT_EDGES |
MBC_EDIT_FACEDOTS | MBC_EDIT_SELECTION_FACEDOTS |
- MBC_EDIT_MESH_ANALYSIS);
+ MBC_EDIT_SELECTION_FACES | MBC_EDIT_SELECTION_EDGES |
+ MBC_EDIT_SELECTION_VERTS | MBC_EDIT_MESH_ANALYSIS);
/* Because visible UVs depends on edit mode selection, discard everything. */
mesh_batch_cache_discard_uvedit(cache);
break;
case BKE_MESH_BATCH_DIRTY_SELECT_PAINT:
/* Paint mode selection flag is packed inside the nor attrib.
* Note that it can be slow if auto smooth is enabled. (see T63946) */
- GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.loops_lines_paint_mask);
- GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_pos_nor);
+ FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
+ {
+ GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.lines_paint_mask);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.pos_nor);
+ }
GPU_BATCH_DISCARD_SAFE(cache->batch.surface);
GPU_BATCH_DISCARD_SAFE(cache->batch.wire_loops);
GPU_BATCH_DISCARD_SAFE(cache->batch.wire_edges);
- if (cache->surf_per_mat) {
+ if (cache->surface_per_mat) {
for (int i = 0; i < cache->mat_len; i++) {
- GPU_BATCH_DISCARD_SAFE(cache->surf_per_mat[i]);
+ GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]);
}
}
cache->batch_ready &= ~(MBC_SURFACE | MBC_WIRE_EDGES | MBC_WIRE_LOOPS | MBC_SURF_PER_MAT);
@@ -2314,14 +571,17 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode)
mesh_batch_cache_discard_uvedit(cache);
break;
case BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT:
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_uv_data);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.facedots_uv_data);
+ FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
+ {
+ 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);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_edges);
GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_verts);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_facedots);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_fdots);
cache->batch_ready &= ~MBC_EDITUV;
break;
default:
@@ -2335,18 +595,16 @@ static void mesh_batch_cache_clear(Mesh *me)
if (!cache) {
return;
}
-
- 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) {
- GPUVertBuf **vbo = (GPUVertBuf **)&cache->edit;
- GPU_VERTBUF_DISCARD_SAFE(vbo[i]);
- }
- for (int i = 0; i < sizeof(cache->ibo) / sizeof(void *); ++i) {
- GPUIndexBuf **ibo = (GPUIndexBuf **)&cache->ibo;
- GPU_INDEXBUF_DISCARD_SAFE(ibo[i]);
+ FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
+ {
+ GPUVertBuf **vbos = (GPUVertBuf **)&mbufcache->vbo;
+ GPUIndexBuf **ibos = (GPUIndexBuf **)&mbufcache->ibo;
+ 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) {
+ GPU_INDEXBUF_DISCARD_SAFE(ibos[i]);
+ }
}
for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) {
GPUBatch **batch = (GPUBatch **)&cache->batch;
@@ -2368,2074 +626,6 @@ void DRW_mesh_batch_cache_free(Mesh *me)
MEM_SAFE_FREE(me->runtime.batch_cache);
}
-/* GPUBatch cache usage. */
-
-static void mesh_create_edit_vertex_loops(MeshRenderData *rdata,
- GPUVertBuf *vbo_pos_nor,
- GPUVertBuf *vbo_lnor,
- GPUVertBuf *vbo_uv,
- GPUVertBuf *vbo_data,
- GPUVertBuf *vbo_verts,
- GPUVertBuf *vbo_edges,
- GPUVertBuf *vbo_faces)
-{
-#if 0
- const int vert_len = mesh_render_data_verts_len_get_maybe_mapped(rdata);
- const int edge_len = mesh_render_data_edges_len_get_maybe_mapped(rdata);
-#endif
- const int poly_len = mesh_render_data_polys_len_get_maybe_mapped(rdata);
- const int lvert_len = mesh_render_data_loose_verts_len_get_maybe_mapped(rdata);
- const int ledge_len = mesh_render_data_loose_edges_len_get_maybe_mapped(rdata);
- const int loop_len = mesh_render_data_loops_len_get_maybe_mapped(rdata);
- const int tot_loop_len = loop_len + ledge_len * 2 + lvert_len;
- float(*lnors)[3] = rdata->loop_normals;
- uchar fflag;
-
- /* Static formats */
- static struct {
- GPUVertFormat sel_id, pos_nor, lnor, flag, uv;
- } format = {{0}};
- static struct {
- uint sel_id, pos, nor, lnor, data, uvs;
- } attr_id;
- if (format.sel_id.attr_len == 0) {
- attr_id.sel_id = GPU_vertformat_attr_add(
- &format.sel_id, "color", GPU_COMP_U32, 1, GPU_FETCH_INT);
- attr_id.pos = GPU_vertformat_attr_add(
- &format.pos_nor, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- attr_id.nor = GPU_vertformat_attr_add(
- &format.pos_nor, "vnor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- attr_id.lnor = GPU_vertformat_attr_add(
- &format.lnor, "lnor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- attr_id.data = GPU_vertformat_attr_add(&format.flag, "data", GPU_COMP_U8, 4, GPU_FETCH_INT);
- attr_id.uvs = GPU_vertformat_attr_add(&format.uv, "u", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- GPU_vertformat_alias_add(&format.uv, "pos");
- GPU_vertformat_alias_add(&format.flag, "flag");
- }
-
- GPUVertBufRaw raw_verts, raw_edges, raw_faces, raw_pos, raw_nor, raw_lnor, raw_uv, raw_data;
- if (DRW_TEST_ASSIGN_VBO(vbo_pos_nor)) {
- GPU_vertbuf_init_with_format(vbo_pos_nor, &format.pos_nor);
- GPU_vertbuf_data_alloc(vbo_pos_nor, tot_loop_len);
- GPU_vertbuf_attr_get_raw_data(vbo_pos_nor, attr_id.pos, &raw_pos);
- GPU_vertbuf_attr_get_raw_data(vbo_pos_nor, attr_id.nor, &raw_nor);
- }
- if (DRW_TEST_ASSIGN_VBO(vbo_lnor)) {
- GPU_vertbuf_init_with_format(vbo_lnor, &format.lnor);
- GPU_vertbuf_data_alloc(vbo_lnor, tot_loop_len);
- GPU_vertbuf_attr_get_raw_data(vbo_lnor, attr_id.lnor, &raw_lnor);
- }
- if (DRW_TEST_ASSIGN_VBO(vbo_data)) {
- GPU_vertbuf_init_with_format(vbo_data, &format.flag);
- GPU_vertbuf_data_alloc(vbo_data, tot_loop_len);
- GPU_vertbuf_attr_get_raw_data(vbo_data, attr_id.data, &raw_data);
- }
- if (DRW_TEST_ASSIGN_VBO(vbo_uv)) {
- GPU_vertbuf_init_with_format(vbo_uv, &format.uv);
- GPU_vertbuf_data_alloc(vbo_uv, tot_loop_len);
- GPU_vertbuf_attr_get_raw_data(vbo_uv, attr_id.uvs, &raw_uv);
- }
- /* Select Idx */
- if (DRW_TEST_ASSIGN_VBO(vbo_verts)) {
- GPU_vertbuf_init_with_format(vbo_verts, &format.sel_id);
- GPU_vertbuf_data_alloc(vbo_verts, tot_loop_len);
- GPU_vertbuf_attr_get_raw_data(vbo_verts, attr_id.sel_id, &raw_verts);
- }
- if (DRW_TEST_ASSIGN_VBO(vbo_edges)) {
- GPU_vertbuf_init_with_format(vbo_edges, &format.sel_id);
- GPU_vertbuf_data_alloc(vbo_edges, tot_loop_len);
- GPU_vertbuf_attr_get_raw_data(vbo_edges, attr_id.sel_id, &raw_edges);
- }
- if (DRW_TEST_ASSIGN_VBO(vbo_faces)) {
- GPU_vertbuf_init_with_format(vbo_faces, &format.sel_id);
- GPU_vertbuf_data_alloc(vbo_faces, tot_loop_len);
- GPU_vertbuf_attr_get_raw_data(vbo_faces, attr_id.sel_id, &raw_faces);
- }
-
- if (rdata->edit_bmesh && rdata->mapped.use == false) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter_efa, iter_loop, iter_vert;
- BMFace *efa;
- BMEdge *eed;
- BMVert *eve;
- BMLoop *loop;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- /* Face Loops */
- BM_ITER_MESH (efa, &iter_efa, bm, BM_FACES_OF_MESH) {
- int fidx = BM_elem_index_get(efa);
- if (vbo_data) {
- fflag = mesh_render_data_face_flag(rdata, efa, cd_loop_uv_offset);
- }
- BM_ITER_ELEM (loop, &iter_loop, efa, BM_LOOPS_OF_FACE) {
- if (vbo_pos_nor) {
- GPUPackedNormal *vnor = (GPUPackedNormal *)GPU_vertbuf_raw_step(&raw_nor);
- *vnor = GPU_normal_convert_i10_v3(loop->v->no);
- copy_v3_v3(GPU_vertbuf_raw_step(&raw_pos), loop->v->co);
- }
- if (vbo_lnor) {
- const float *nor = (lnors) ? lnors[BM_elem_index_get(loop)] : efa->no;
- GPUPackedNormal *lnor = (GPUPackedNormal *)GPU_vertbuf_raw_step(&raw_lnor);
- *lnor = GPU_normal_convert_i10_v3(nor);
- }
- if (vbo_data) {
- EdgeDrawAttr eattr = {.v_flag = fflag};
- mesh_render_data_edge_flag(rdata, loop->e, &eattr);
- mesh_render_data_vert_flag(rdata, loop->v, &eattr);
- mesh_render_data_loop_flag(rdata, loop, cd_loop_uv_offset, &eattr);
- memcpy(GPU_vertbuf_raw_step(&raw_data), &eattr, sizeof(EdgeDrawAttr));
- }
- if (vbo_uv) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, cd_loop_uv_offset);
- copy_v2_v2(GPU_vertbuf_raw_step(&raw_uv), luv->uv);
- }
- /* Select Idx */
- if (vbo_verts) {
- int vidx = BM_elem_index_get(loop->v);
- *((uint *)GPU_vertbuf_raw_step(&raw_verts)) = vidx;
- }
- if (vbo_edges) {
- int eidx = BM_elem_index_get(loop->e);
- *((uint *)GPU_vertbuf_raw_step(&raw_edges)) = eidx;
- }
- if (vbo_faces) {
- *((uint *)GPU_vertbuf_raw_step(&raw_faces)) = fidx;
- }
- }
- }
- /* Loose edges */
- for (int e = 0; e < ledge_len; e++) {
- eed = BM_edge_at_index(bm, rdata->loose_edges[e]);
- BM_ITER_ELEM (eve, &iter_vert, eed, BM_VERTS_OF_EDGE) {
- if (vbo_pos_nor) {
- GPUPackedNormal *vnor = (GPUPackedNormal *)GPU_vertbuf_raw_step(&raw_nor);
- *vnor = GPU_normal_convert_i10_v3(eve->no);
- copy_v3_v3(GPU_vertbuf_raw_step(&raw_pos), eve->co);
- }
- if (vbo_data) {
- EdgeDrawAttr eattr = {0};
- mesh_render_data_edge_flag(rdata, eed, &eattr);
- mesh_render_data_vert_flag(rdata, eve, &eattr);
- memcpy(GPU_vertbuf_raw_step(&raw_data), &eattr, sizeof(EdgeDrawAttr));
- }
- if (vbo_lnor) {
- memset(GPU_vertbuf_raw_step(&raw_lnor), 0, sizeof(GPUPackedNormal));
- }
- /* Select Idx */
- if (vbo_verts) {
- int vidx = BM_elem_index_get(eve);
- *((uint *)GPU_vertbuf_raw_step(&raw_verts)) = vidx;
- }
- if (vbo_edges) {
- int eidx = BM_elem_index_get(eed);
- *((uint *)GPU_vertbuf_raw_step(&raw_edges)) = eidx;
- }
- }
- }
- /* Loose verts */
- for (int e = 0; e < lvert_len; e++) {
- eve = BM_vert_at_index(bm, rdata->loose_verts[e]);
- if (vbo_pos_nor) {
- GPUPackedNormal *vnor = (GPUPackedNormal *)GPU_vertbuf_raw_step(&raw_nor);
- *vnor = GPU_normal_convert_i10_v3(eve->no);
- copy_v3_v3(GPU_vertbuf_raw_step(&raw_pos), eve->co);
- }
- if (vbo_lnor) {
- memset(GPU_vertbuf_raw_step(&raw_lnor), 0, sizeof(GPUPackedNormal));
- }
- if (vbo_data) {
- EdgeDrawAttr eattr = {0};
- mesh_render_data_vert_flag(rdata, eve, &eattr);
- memcpy(GPU_vertbuf_raw_step(&raw_data), &eattr, sizeof(EdgeDrawAttr));
- }
- /* Select Idx */
- if (vbo_verts) {
- int vidx = BM_elem_index_get(eve);
- *((uint *)GPU_vertbuf_raw_step(&raw_verts)) = vidx;
- }
- }
- }
- else if (rdata->mapped.use == true) {
- BMesh *bm = rdata->edit_bmesh->bm;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- const MPoly *mpoly = rdata->mapped.me_cage->mpoly;
- const MEdge *medge = rdata->mapped.me_cage->medge;
- const MVert *mvert = rdata->mapped.me_cage->mvert;
- const MLoop *mloop = rdata->mapped.me_cage->mloop;
-
- const int *v_origindex = rdata->mapped.v_origindex;
- const int *e_origindex = rdata->mapped.e_origindex;
- const int *p_origindex = rdata->mapped.p_origindex;
-
- /* Face Loops */
- for (int poly = 0; poly < poly_len; poly++, mpoly++) {
- const MLoop *l = &mloop[mpoly->loopstart];
- int fidx = p_origindex[poly];
- BMFace *efa = NULL;
- if (vbo_data) {
- fflag = 0;
- if (fidx != ORIGINDEX_NONE) {
- efa = BM_face_at_index(bm, fidx);
- fflag = mesh_render_data_face_flag(rdata, efa, cd_loop_uv_offset);
- }
- }
- for (int i = 0; i < mpoly->totloop; i++, l++) {
- if (vbo_pos_nor) {
- copy_v3_v3(GPU_vertbuf_raw_step(&raw_pos), mvert[l->v].co);
- }
- if (vbo_lnor || vbo_pos_nor) {
- GPUPackedNormal vnor = GPU_normal_convert_i10_s3(mvert[l->v].no);
- if (vbo_pos_nor) {
- *(GPUPackedNormal *)GPU_vertbuf_raw_step(&raw_nor) = vnor;
- }
- if (vbo_lnor) {
- /* Mapped does not support lnors yet. */
- *(GPUPackedNormal *)GPU_vertbuf_raw_step(&raw_lnor) = vnor;
- }
- }
- if (vbo_data) {
- EdgeDrawAttr eattr = {.v_flag = fflag};
- int vidx = v_origindex[l->v];
- int eidx = e_origindex[l->e];
- if (vidx != ORIGINDEX_NONE) {
- BMVert *eve = BM_vert_at_index(bm, vidx);
- mesh_render_data_vert_flag(rdata, eve, &eattr);
- }
- if (eidx != ORIGINDEX_NONE) {
- BMEdge *eed = BM_edge_at_index(bm, eidx);
- mesh_render_data_edge_flag(rdata, eed, &eattr);
- if (efa) {
- BMLoop *loop = BM_face_edge_share_loop(efa, eed);
- if (loop) {
- mesh_render_data_loop_flag(rdata, loop, cd_loop_uv_offset, &eattr);
- }
- }
- }
- memcpy(GPU_vertbuf_raw_step(&raw_data), &eattr, sizeof(EdgeDrawAttr));
- }
- if (vbo_uv) {
- MLoopUV *luv = &rdata->mloopuv[mpoly->loopstart + i];
- copy_v2_v2(GPU_vertbuf_raw_step(&raw_uv), luv->uv);
- }
- /* Select Idx */
- if (vbo_verts) {
- int vidx = v_origindex[l->v];
- *((uint *)GPU_vertbuf_raw_step(&raw_verts)) = vidx;
- }
- if (vbo_edges) {
- int eidx = e_origindex[l->e];
- *((uint *)GPU_vertbuf_raw_step(&raw_edges)) = eidx;
- }
- if (vbo_faces) {
- *((uint *)GPU_vertbuf_raw_step(&raw_faces)) = fidx;
- }
- }
- }
- /* Loose edges */
- for (int j = 0; j < ledge_len; j++) {
- const int e = rdata->mapped.loose_edges[j];
- for (int i = 0; i < 2; ++i) {
- int v = (i == 0) ? medge[e].v1 : medge[e].v2;
- if (vbo_pos_nor) {
- GPUPackedNormal vnor = GPU_normal_convert_i10_s3(mvert[v].no);
- *(GPUPackedNormal *)GPU_vertbuf_raw_step(&raw_nor) = vnor;
- copy_v3_v3(GPU_vertbuf_raw_step(&raw_pos), mvert[v].co);
- }
- if (vbo_lnor) {
- memset(GPU_vertbuf_raw_step(&raw_lnor), 0, sizeof(GPUPackedNormal));
- }
- if (vbo_data) {
- EdgeDrawAttr eattr = {0};
- int vidx = v_origindex[v];
- int eidx = e_origindex[e];
- if (vidx != ORIGINDEX_NONE) {
- BMVert *eve = BM_vert_at_index(bm, vidx);
- mesh_render_data_vert_flag(rdata, eve, &eattr);
- }
- if (eidx != ORIGINDEX_NONE) {
- BMEdge *eed = BM_edge_at_index(bm, eidx);
- mesh_render_data_edge_flag(rdata, eed, &eattr);
- }
- memcpy(GPU_vertbuf_raw_step(&raw_data), &eattr, sizeof(EdgeDrawAttr));
- }
- /* Select Idx */
- if (vbo_verts) {
- int vidx = v_origindex[v];
- *((uint *)GPU_vertbuf_raw_step(&raw_verts)) = vidx;
- }
- if (vbo_edges) {
- int eidx = e_origindex[e];
- *((uint *)GPU_vertbuf_raw_step(&raw_edges)) = eidx;
- }
- }
- }
- /* Loose verts */
- for (int i = 0; i < lvert_len; i++) {
- const int v = rdata->mapped.loose_verts[i];
- if (vbo_pos_nor) {
- GPUPackedNormal vnor = GPU_normal_convert_i10_s3(mvert[v].no);
- *(GPUPackedNormal *)GPU_vertbuf_raw_step(&raw_nor) = vnor;
- copy_v3_v3(GPU_vertbuf_raw_step(&raw_pos), mvert[v].co);
- }
- if (vbo_lnor) {
- memset(GPU_vertbuf_raw_step(&raw_lnor), 0, sizeof(GPUPackedNormal));
- }
- if (vbo_data) {
- EdgeDrawAttr eattr = {0};
- int vidx = v_origindex[v];
- if (vidx != ORIGINDEX_NONE) {
- BMVert *eve = BM_vert_at_index(bm, vidx);
- mesh_render_data_vert_flag(rdata, eve, &eattr);
- }
- memcpy(GPU_vertbuf_raw_step(&raw_data), &eattr, sizeof(EdgeDrawAttr));
- }
- /* Select Idx */
- if (vbo_verts) {
- int vidx = v_origindex[v];
- *((uint *)GPU_vertbuf_raw_step(&raw_verts)) = vidx;
- }
- }
- }
- else {
- const MPoly *mpoly = rdata->mpoly;
- const MVert *mvert = rdata->mvert;
- const MLoop *mloop = rdata->mloop;
-
- const int *v_origindex = CustomData_get_layer(&rdata->me->vdata, CD_ORIGINDEX);
- const int *e_origindex = CustomData_get_layer(&rdata->me->edata, CD_ORIGINDEX);
- const int *p_origindex = CustomData_get_layer(&rdata->me->pdata, CD_ORIGINDEX);
-
- /* Face Loops */
- for (int poly = 0; poly < poly_len; poly++, mpoly++) {
- const MLoop *l = &mloop[mpoly->loopstart];
- int fidx = p_origindex ? p_origindex[poly] : poly;
- for (int i = 0; i < mpoly->totloop; i++, l++) {
- if (vbo_pos_nor) {
- copy_v3_v3(GPU_vertbuf_raw_step(&raw_pos), mvert[l->v].co);
- }
- if (vbo_lnor || vbo_pos_nor) {
- GPUPackedNormal vnor = GPU_normal_convert_i10_s3(mvert[l->v].no);
- if (vbo_pos_nor) {
- *(GPUPackedNormal *)GPU_vertbuf_raw_step(&raw_nor) = vnor;
- }
- if (vbo_lnor) {
- /* Mapped does not support lnors yet. */
- *(GPUPackedNormal *)GPU_vertbuf_raw_step(&raw_lnor) = vnor;
- }
- }
- if (vbo_uv) {
- MLoopUV *luv = &rdata->mloopuv[mpoly->loopstart + i];
- copy_v2_v2(GPU_vertbuf_raw_step(&raw_uv), luv->uv);
- }
- /* Select Idx */
- if (vbo_verts) {
- int vidx = v_origindex ? v_origindex[l->v] : l->v;
- *((uint *)GPU_vertbuf_raw_step(&raw_verts)) = vidx;
- }
- if (vbo_edges) {
- int eidx = e_origindex ? e_origindex[l->e] : l->e;
- *((uint *)GPU_vertbuf_raw_step(&raw_edges)) = eidx;
- }
- if (vbo_faces) {
- *((uint *)GPU_vertbuf_raw_step(&raw_faces)) = fidx;
- }
- }
- }
- /* TODO(fclem): Until we find a way to detect
- * loose verts easily outside of edit mode, this
- * will remain disabled. */
-#if 0
- /* Loose edges */
- for (int e = 0; e < edge_len; e++, medge++) {
- int eidx = e_origindex[e];
- if (eidx != ORIGINDEX_NONE && (medge->flag & ME_LOOSEEDGE)) {
- for (int i = 0; i < 2; ++i) {
- int vidx = (i == 0) ? medge->v1 : medge->v2;
- if (vbo_pos) {
- copy_v3_v3(GPU_vertbuf_raw_step(&raw_pos), mvert[vidx].co);
- }
- if (vbo_verts) {
- *((uint *)GPU_vertbuf_raw_step(&raw_verts)) = vidx;
- }
- if (vbo_edges) {
- *((uint *)GPU_vertbuf_raw_step(&raw_edges)) = eidx;
- }
- }
- }
- }
- /* Loose verts */
- for (int v = 0; v < vert_len; v++, mvert++) {
- int vidx = v_origindex[v];
- if (vidx != ORIGINDEX_NONE) {
- MVert *eve = BM_vert_at_index(bm, vidx);
- if (eve->e == NULL) {
- if (vbo_pos) {
- copy_v3_v3(GPU_vertbuf_raw_step(&raw_pos), mvert->co);
- }
- if (vbo_verts) {
- *((uint *)GPU_vertbuf_raw_step(&raw_verts)) = vidx;
- }
- }
- }
- }
-#endif
- }
- /* Don't resize */
-}
-
-/* TODO: We could use gl_PrimitiveID as index instead of using another VBO. */
-static void mesh_create_edit_facedots_select_id(MeshRenderData *rdata,
- GPUVertBuf *vbo,
- Scene *scene,
- Object *ob)
-{
- const int poly_len = mesh_render_data_polys_len_get_maybe_mapped(rdata);
-
- static GPUVertFormat format = {0};
- static struct {
- uint idx;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.idx = GPU_vertformat_attr_add(&format, "color", GPU_COMP_U32, 1, GPU_FETCH_INT);
- }
-
- GPUVertBufRaw idx_step;
- GPU_vertbuf_init_with_format(vbo, &format);
- GPU_vertbuf_data_alloc(vbo, poly_len);
- GPU_vertbuf_attr_get_raw_data(vbo, attr_id.idx, &idx_step);
-
- /* Keep in sync with mesh_create_edit_facedots(). */
- if (rdata->mapped.use == false) {
- if (rdata->edit_bmesh) {
- for (int poly = 0; poly < poly_len; poly++) {
- const BMFace *efa = BM_face_at_index(rdata->edit_bmesh->bm, poly);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- *((uint *)GPU_vertbuf_raw_step(&idx_step)) = poly;
- }
- }
- }
- else {
- for (int poly = 0; poly < poly_len; poly++) {
- *((uint *)GPU_vertbuf_raw_step(&idx_step)) = poly;
- }
- }
- }
- else {
- const int *p_origindex = rdata->mapped.p_origindex;
- if (modifiers_usesSubsurfFacedots(scene, ob)) {
- Mesh *me_cage = rdata->mapped.me_cage;
- const MPoly *mpoly = me_cage->mpoly;
- for (int p = 0; p < poly_len; p++, mpoly++) {
- const int p_orig = p_origindex[p];
- if (p_orig != ORIGINDEX_NONE) {
- const MLoop *mloop = me_cage->mloop + mpoly->loopstart;
- for (int l = 0; l < mpoly->totloop; l++, mloop++) {
- if (me_cage->mvert[mloop->v].flag & ME_VERT_FACEDOT) {
- const BMFace *efa = BM_face_at_index(rdata->edit_bmesh->bm, p_orig);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- *((uint *)GPU_vertbuf_raw_step(&idx_step)) = p_orig;
- }
- }
- }
- }
- }
- }
- else {
- for (int poly = 0; poly < poly_len; poly++) {
- const int p_orig = p_origindex[poly];
- if (p_orig != ORIGINDEX_NONE) {
- const BMFace *efa = BM_face_at_index(rdata->edit_bmesh->bm, p_orig);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- *((uint *)GPU_vertbuf_raw_step(&idx_step)) = p_orig;
- }
- }
- }
- }
- }
-
- /* Resize & Finish */
- int facedot_len_used = GPU_vertbuf_raw_used(&idx_step);
- if (facedot_len_used != poly_len) {
- GPU_vertbuf_data_resize(vbo, facedot_len_used);
- }
-}
-
-static void mesh_create_pos_and_nor(MeshRenderData *rdata, GPUVertBuf *vbo)
-{
- static GPUVertFormat format = {0};
- static struct {
- uint pos, nor;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- attr_id.nor = GPU_vertformat_attr_add(
- &format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- }
-
- GPU_vertbuf_init_with_format(vbo, &format);
- const int vbo_len_capacity = mesh_render_data_verts_len_get_maybe_mapped(rdata);
- GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
-
- if (rdata->mapped.use == false) {
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter;
- BMVert *eve;
- uint i;
-
- mesh_render_data_ensure_vert_normals_pack(rdata);
- GPUPackedNormal *vnor = rdata->vert_normals_pack;
-
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i, eve->co);
- GPU_vertbuf_attr_set(vbo, attr_id.nor, i, &vnor[i]);
- }
- BLI_assert(i == vbo_len_capacity);
- }
- else {
- for (int i = 0; i < vbo_len_capacity; i++) {
- const MVert *mv = &rdata->mvert[i];
- GPUPackedNormal vnor_pack = GPU_normal_convert_i10_s3(mv->no);
- vnor_pack.w = (mv->flag & ME_HIDE) ? -1 : ((mv->flag & SELECT) ? 1 : 0);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i, rdata->mvert[i].co);
- GPU_vertbuf_attr_set(vbo, attr_id.nor, i, &vnor_pack);
- }
- }
- }
- else {
- const MVert *mvert = rdata->mapped.me_cage->mvert;
- const int *v_origindex = rdata->mapped.v_origindex;
- for (int i = 0; i < vbo_len_capacity; i++) {
- const int v_orig = v_origindex[i];
- if (v_orig != ORIGINDEX_NONE) {
- const MVert *mv = &mvert[i];
- GPUPackedNormal vnor_pack = GPU_normal_convert_i10_s3(mv->no);
- vnor_pack.w = (mv->flag & ME_HIDE) ? -1 : ((mv->flag & SELECT) ? 1 : 0);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, i, mv->co);
- GPU_vertbuf_attr_set(vbo, attr_id.nor, i, &vnor_pack);
- }
- }
- }
-}
-
-static void mesh_create_weights(MeshRenderData *rdata,
- GPUVertBuf *vbo,
- DRW_MeshWeightState *wstate)
-{
- static GPUVertFormat format = {0};
- static struct {
- uint weight;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.weight = GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- }
-
- const int vbo_len_capacity = mesh_render_data_verts_len_get_maybe_mapped(rdata);
-
- mesh_render_data_ensure_vert_weight(rdata, wstate);
- const float *vert_weight = rdata->vert_weight;
-
- GPU_vertbuf_init_with_format(vbo, &format);
- /* Meh, another allocation / copy for no benefit.
- * Needed because rdata->vert_weight is freed afterwards and
- * GPU module don't have a GPU_vertbuf_data_from_memory or similar. */
- /* TODO get rid of the extra allocation/copy. */
- GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
- GPU_vertbuf_attr_fill(vbo, attr_id.weight, vert_weight);
-}
-
-static float mesh_loop_edge_factor_get(const float f_no[3],
- const float v_co[3],
- const float v_no[3],
- const float v_next_co[3])
-{
- float enor[3], evec[3];
- sub_v3_v3v3(evec, v_next_co, v_co);
- cross_v3_v3v3(enor, v_no, evec);
- normalize_v3(enor);
- float d = fabsf(dot_v3v3(enor, f_no));
- /* Rescale to the slider range. */
- d *= (1.0f / 0.065f);
- CLAMP(d, 0.0f, 1.0f);
- return d;
-}
-
-static void vertbuf_raw_step_u8(GPUVertBufRaw *wd_step, const uchar wiredata)
-{
- *((uchar *)GPU_vertbuf_raw_step(wd_step)) = wiredata;
-}
-
-static void vertbuf_raw_step_u8_to_f32(GPUVertBufRaw *wd_step, const uchar wiredata)
-{
- *((float *)GPU_vertbuf_raw_step(wd_step)) = wiredata / 255.0f;
-}
-
-static void mesh_create_loop_edge_fac(MeshRenderData *rdata, GPUVertBuf *vbo)
-{
- static GPUVertFormat format = {0};
- static struct {
- uint wd;
- } attr_id;
- static union {
- float f;
- uchar u;
- } data;
- static void (*vertbuf_raw_step)(GPUVertBufRaw *, const uchar);
- if (format.attr_len == 0) {
- if (!GPU_crappy_amd_driver()) {
- /* Some AMD drivers strangely crash with a vbo with this format. */
- attr_id.wd = GPU_vertformat_attr_add(
- &format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
- vertbuf_raw_step = vertbuf_raw_step_u8;
- data.u = UCHAR_MAX;
- }
- else {
- attr_id.wd = GPU_vertformat_attr_add(&format, "wd", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- vertbuf_raw_step = vertbuf_raw_step_u8_to_f32;
- data.f = 1.0f;
- }
- }
- const int poly_len = mesh_render_data_polys_len_get(rdata);
- const int loop_len = mesh_render_data_loops_len_get(rdata);
- const int edge_len = mesh_render_data_edges_len_get(rdata);
-
- GPU_vertbuf_init_with_format(vbo, &format);
- GPU_vertbuf_data_alloc(vbo, loop_len);
-
- GPUVertBufRaw wd_step;
- GPU_vertbuf_attr_get_raw_data(vbo, attr_id.wd, &wd_step);
-
- if (rdata->mapped.use == false) {
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter_efa, iter_loop;
- BMFace *efa;
- BMLoop *loop;
- uint f;
-
- BM_ITER_MESH_INDEX (efa, &iter_efa, bm, BM_FACES_OF_MESH, f) {
- BM_ITER_ELEM (loop, &iter_loop, efa, BM_LOOPS_OF_FACE) {
- float ratio = mesh_loop_edge_factor_get(
- efa->no, loop->v->co, loop->v->no, loop->next->v->co);
- vertbuf_raw_step(&wd_step, ratio * 253 + 1);
- }
- }
- BLI_assert(GPU_vertbuf_raw_used(&wd_step) == loop_len);
- }
- else {
- const MVert *mvert = rdata->mvert;
- const MPoly *mpoly = rdata->mpoly;
- const MLoop *mloop = rdata->mloop;
- MEdge *medge = (MEdge *)rdata->medge;
- bool use_edge_render = false;
-
- /* TODO(fclem) We don't need them to be packed. But we need rdata->poly_normals */
- mesh_render_data_ensure_poly_normals_pack(rdata);
-
- /* Reset flag */
- for (int edge = 0; edge < edge_len; ++edge) {
- /* NOTE: not thread safe. */
- medge[edge].flag &= ~ME_EDGE_TMP_TAG;
-
- /* HACK(fclem) Feels like a hack. Detecting the need for edge render. */
- if ((medge[edge].flag & ME_EDGERENDER) == 0) {
- use_edge_render = true;
- }
- }
-
- for (int a = 0; a < poly_len; a++, mpoly++) {
- const float *fnor = rdata->poly_normals[a];
- for (int b = 0; b < mpoly->totloop; b++) {
- const MLoop *ml1 = &mloop[mpoly->loopstart + b];
- const MLoop *ml2 = &mloop[mpoly->loopstart + (b + 1) % mpoly->totloop];
-
- /* Will only work for edges that have an odd number of faces connected. */
- MEdge *ed = (MEdge *)rdata->medge + ml1->e;
- ed->flag ^= ME_EDGE_TMP_TAG;
-
- if (use_edge_render) {
- vertbuf_raw_step(&wd_step, (ed->flag & ME_EDGERENDER) ? 255 : 0);
- }
- else {
- float vnor_f[3];
- normal_short_to_float_v3(vnor_f, mvert[ml1->v].no);
- float ratio = mesh_loop_edge_factor_get(
- fnor, mvert[ml1->v].co, vnor_f, mvert[ml2->v].co);
- vertbuf_raw_step(&wd_step, ratio * 253 + 1);
- }
- }
- }
- /* Gather non-manifold edges. */
- for (int l = 0; l < loop_len; l++, mloop++) {
- MEdge *ed = (MEdge *)rdata->medge + mloop->e;
- if (ed->flag & ME_EDGE_TMP_TAG) {
- GPU_vertbuf_attr_set(vbo, attr_id.wd, l, &data);
- }
- }
-
- BLI_assert(loop_len == GPU_vertbuf_raw_used(&wd_step));
- }
- }
- else {
- BLI_assert(0);
- }
-}
-
-static void mesh_create_loop_pos_and_nor(MeshRenderData *rdata, GPUVertBuf *vbo)
-{
- /* TODO deduplicate format creation*/
- static GPUVertFormat format = {0};
- static struct {
- uint pos, nor;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- attr_id.nor = GPU_vertformat_attr_add(
- &format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- }
- const int poly_len = mesh_render_data_polys_len_get(rdata);
- const int loop_len = mesh_render_data_loops_len_get(rdata);
-
- GPU_vertbuf_init_with_format(vbo, &format);
- GPU_vertbuf_data_alloc(vbo, loop_len);
-
- GPUVertBufRaw pos_step, nor_step;
- GPU_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
- GPU_vertbuf_attr_get_raw_data(vbo, attr_id.nor, &nor_step);
-
- if (rdata->mapped.use == false) {
- if (rdata->edit_bmesh) {
- const GPUPackedNormal *vnor, *pnor;
- const float(*lnors)[3] = rdata->loop_normals;
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter_efa, iter_loop;
- BMFace *efa;
- BMLoop *loop;
- uint f;
-
- if (rdata->loop_normals == NULL) {
- mesh_render_data_ensure_poly_normals_pack(rdata);
- mesh_render_data_ensure_vert_normals_pack(rdata);
- vnor = rdata->vert_normals_pack;
- pnor = rdata->poly_normals_pack;
- }
-
- BM_ITER_MESH_INDEX (efa, &iter_efa, bm, BM_FACES_OF_MESH, f) {
- const bool face_smooth = BM_elem_flag_test(efa, BM_ELEM_SMOOTH);
-
- BM_ITER_ELEM (loop, &iter_loop, efa, BM_LOOPS_OF_FACE) {
- BLI_assert(GPU_vertbuf_raw_used(&pos_step) == BM_elem_index_get(loop));
- copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), loop->v->co);
-
- if (lnors) {
- GPUPackedNormal plnor = GPU_normal_convert_i10_v3(lnors[BM_elem_index_get(loop)]);
- *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = plnor;
- }
- else if (!face_smooth) {
- *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = pnor[f];
- }
- else {
- *((GPUPackedNormal *)GPU_vertbuf_raw_step(
- &nor_step)) = vnor[BM_elem_index_get(loop->v)];
- }
- }
- }
- BLI_assert(GPU_vertbuf_raw_used(&pos_step) == loop_len);
- }
- else {
- const MVert *mvert = rdata->mvert;
- const MPoly *mpoly = rdata->mpoly;
-
- if (rdata->loop_normals == NULL) {
- mesh_render_data_ensure_poly_normals_pack(rdata);
- }
-
- for (int a = 0; a < poly_len; a++, mpoly++) {
- const MLoop *mloop = rdata->mloop + mpoly->loopstart;
- const float(*lnors)[3] = (rdata->loop_normals) ? &rdata->loop_normals[mpoly->loopstart] :
- NULL;
- const GPUPackedNormal *fnor = (mpoly->flag & ME_SMOOTH) ? NULL :
- &rdata->poly_normals_pack[a];
- const int hide_select_flag = (mpoly->flag & ME_HIDE) ?
- -1 :
- ((mpoly->flag & ME_FACE_SEL) ? 1 : 0);
- for (int b = 0; b < mpoly->totloop; b++, mloop++) {
- copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[mloop->v].co);
- GPUPackedNormal *pnor = (GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step);
- if (lnors) {
- *pnor = GPU_normal_convert_i10_v3(lnors[b]);
- }
- else if (fnor) {
- *pnor = *fnor;
- }
- else {
- *pnor = GPU_normal_convert_i10_s3(mvert[mloop->v].no);
- }
- pnor->w = hide_select_flag;
- }
- }
-
- BLI_assert(loop_len == GPU_vertbuf_raw_used(&pos_step));
- }
- }
- else {
- const int *p_origindex = rdata->mapped.p_origindex;
- const MVert *mvert = rdata->mvert;
- const MPoly *mpoly = rdata->mpoly;
-
- if (rdata->loop_normals == NULL) {
- mesh_render_data_ensure_poly_normals_pack(rdata);
- }
-
- for (int a = 0; a < poly_len; a++, mpoly++) {
- const MLoop *mloop = rdata->mloop + mpoly->loopstart;
- const float(*lnors)[3] = (rdata->loop_normals) ? &rdata->loop_normals[mpoly->loopstart] :
- NULL;
- const GPUPackedNormal *fnor = (mpoly->flag & ME_SMOOTH) ? NULL :
- &rdata->poly_normals_pack[a];
- if (p_origindex[a] == ORIGINDEX_NONE) {
- continue;
- }
- for (int b = 0; b < mpoly->totloop; b++, mloop++) {
- copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[mloop->v].co);
- GPUPackedNormal *pnor = (GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step);
- if (lnors) {
- *pnor = GPU_normal_convert_i10_v3(lnors[b]);
- }
- else if (fnor) {
- *pnor = *fnor;
- }
- else {
- *pnor = GPU_normal_convert_i10_s3(mvert[mloop->v].no);
- }
- }
- }
- }
-
- int vbo_len_used = GPU_vertbuf_raw_used(&pos_step);
- if (vbo_len_used < loop_len) {
- GPU_vertbuf_data_resize(vbo, vbo_len_used);
- }
-}
-
-static void mesh_create_loop_orco(MeshRenderData *rdata, GPUVertBuf *vbo)
-{
- const uint loops_len = mesh_render_data_loops_len_get(rdata);
-
- /* initialize vertex format */
- GPUVertFormat format = {0};
- GPUVertBufRaw vbo_step;
-
- /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex attribs.
- * This is a substential waste of Vram and should be done another way. Unfortunately,
- * at the time of writing, I did not found any other "non disruptive" alternative. */
- uint attr_id = GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
-
- GPU_vertbuf_init_with_format(vbo, &format);
- GPU_vertbuf_data_alloc(vbo, loops_len);
- GPU_vertbuf_attr_get_raw_data(vbo, attr_id, &vbo_step);
-
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter_efa, iter_loop;
- BMFace *efa;
- BMLoop *loop;
-
- BM_ITER_MESH (efa, &iter_efa, bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (loop, &iter_loop, efa, BM_LOOPS_OF_FACE) {
- float *data = (float *)GPU_vertbuf_raw_step(&vbo_step);
- copy_v3_v3(data, rdata->orco[BM_elem_index_get(loop->v)]);
- data[3] = 0.0; /* Tag as not a generic attrib */
- }
- }
- }
- else {
- for (uint l = 0; l < loops_len; l++) {
- float *data = (float *)GPU_vertbuf_raw_step(&vbo_step);
- copy_v3_v3(data, rdata->orco[rdata->mloop[l].v]);
- data[3] = 0.0; /* Tag as not a generic attrib */
- }
- }
-}
-
-static void mesh_create_loop_uv_and_tan(MeshRenderData *rdata, GPUVertBuf *vbo)
-{
- const uint loops_len = mesh_render_data_loops_len_get(rdata);
- const uint uv_len = rdata->cd.layers.uv_len;
- const uint tangent_len = rdata->cd.layers.tangent_len;
- const uint layers_combined_len = uv_len + tangent_len;
-
- GPUVertBufRaw *layers_combined_step = BLI_array_alloca(layers_combined_step,
- layers_combined_len);
- GPUVertBufRaw *uv_step = layers_combined_step;
- GPUVertBufRaw *tangent_step = uv_step + uv_len;
-
- uint *layers_combined_id = BLI_array_alloca(layers_combined_id, layers_combined_len);
- uint *uv_id = layers_combined_id;
- uint *tangent_id = uv_id + uv_len;
-
- /* initialize vertex format */
- GPUVertFormat format = {0};
-
- for (uint i = 0; i < uv_len; i++) {
- const char *attr_name = mesh_render_data_uv_layer_uuid_get(rdata, i);
-#if 0 /* these are clamped. Maybe use them as an option in the future */
- uv_id[i] = GPU_vertformat_attr_add(
- &format, attr_name, GPU_COMP_I16, 2, GPU_FETCH_INT_TO_FLOAT_UNIT);
-#else
- uv_id[i] = GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-#endif
- /* Auto Name */
- attr_name = mesh_render_data_uv_auto_layer_uuid_get(rdata, i);
- GPU_vertformat_alias_add(&format, attr_name);
-
- if (i == rdata->cd.layers.uv_render) {
- GPU_vertformat_alias_add(&format, "u");
- }
- if (i == rdata->cd.layers.uv_active) {
- GPU_vertformat_alias_add(&format, "au");
- }
- if (i == rdata->cd.layers.uv_mask_active) {
- GPU_vertformat_alias_add(&format, "mu");
- }
- }
-
- for (uint i = 0; i < tangent_len; i++) {
- const char *attr_name = mesh_render_data_tangent_layer_uuid_get(rdata, i);
-#ifdef USE_COMP_MESH_DATA
- tangent_id[i] = GPU_vertformat_attr_add(
- &format, attr_name, GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
-#else
- tangent_id[i] = GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
-#endif
- if (i == rdata->cd.layers.tangent_render) {
- GPU_vertformat_alias_add(&format, "t");
- }
- if (i == rdata->cd.layers.tangent_active) {
- GPU_vertformat_alias_add(&format, "at");
- }
- }
-
- /* HACK: Create a dummy attribute in case there is no valid UV/tangent layer. */
- if (layers_combined_len == 0) {
- GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
- }
-
- GPU_vertbuf_init_with_format(vbo, &format);
- GPU_vertbuf_data_alloc(vbo, loops_len);
-
- for (uint i = 0; i < uv_len; i++) {
- GPU_vertbuf_attr_get_raw_data(vbo, uv_id[i], &uv_step[i]);
- }
- for (uint i = 0; i < tangent_len; i++) {
- GPU_vertbuf_attr_get_raw_data(vbo, tangent_id[i], &tangent_step[i]);
- }
-
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter_efa, iter_loop;
- BMFace *efa;
- BMLoop *loop;
-
- BM_ITER_MESH (efa, &iter_efa, bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (loop, &iter_loop, efa, BM_LOOPS_OF_FACE) {
- /* UVs */
- for (uint j = 0; j < uv_len; j++) {
- const uint layer_offset = rdata->cd.offset.uv[j];
- const float *elem = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(loop, layer_offset))->uv;
- copy_v2_v2(GPU_vertbuf_raw_step(&uv_step[j]), elem);
- }
- /* TANGENTs */
- for (uint j = 0; j < tangent_len; j++) {
- float(*layer_data)[4] = rdata->cd.layers.tangent[j];
- const float *elem = layer_data[BM_elem_index_get(loop)];
-#ifdef USE_COMP_MESH_DATA
- normal_float_to_short_v4(GPU_vertbuf_raw_step(&tangent_step[j]), elem);
-#else
- copy_v4_v4(GPU_vertbuf_raw_step(&tangent_step[j]), elem);
-#endif
- }
- }
- }
- }
- else {
- for (uint loop = 0; loop < loops_len; loop++) {
- /* UVs */
- for (uint j = 0; j < uv_len; j++) {
- const MLoopUV *layer_data = rdata->cd.layers.uv[j];
- const float *elem = layer_data[loop].uv;
- copy_v2_v2(GPU_vertbuf_raw_step(&uv_step[j]), elem);
- }
- /* TANGENTs */
- for (uint j = 0; j < tangent_len; j++) {
- float(*layer_data)[4] = rdata->cd.layers.tangent[j];
- const float *elem = layer_data[loop];
-#ifdef USE_COMP_MESH_DATA
- normal_float_to_short_v4(GPU_vertbuf_raw_step(&tangent_step[j]), elem);
-#else
- copy_v4_v4(GPU_vertbuf_raw_step(&tangent_step[j]), elem);
-#endif
- }
- }
- }
-
-#ifndef NDEBUG
- /* Check all layers are write aligned. */
- if (layers_combined_len > 0) {
- int vbo_len_used = GPU_vertbuf_raw_used(&layers_combined_step[0]);
- for (uint i = 0; i < layers_combined_len; i++) {
- BLI_assert(vbo_len_used == GPU_vertbuf_raw_used(&layers_combined_step[i]));
- }
- }
-#endif
-
-#undef USE_COMP_MESH_DATA
-}
-
-static void mesh_create_loop_vcol(MeshRenderData *rdata, GPUVertBuf *vbo)
-{
- const uint loops_len = mesh_render_data_loops_len_get(rdata);
- const uint vcol_len = rdata->cd.layers.vcol_len;
-
- GPUVertBufRaw *vcol_step = BLI_array_alloca(vcol_step, vcol_len);
- uint *vcol_id = BLI_array_alloca(vcol_id, vcol_len);
-
- /* initialize vertex format */
- GPUVertFormat format = {0};
-
- for (uint i = 0; i < vcol_len; i++) {
- const char *attr_name = mesh_render_data_vcol_layer_uuid_get(rdata, i);
- vcol_id[i] = GPU_vertformat_attr_add(
- &format, attr_name, GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- /* Auto layer */
- if (rdata->cd.layers.auto_vcol[i]) {
- attr_name = mesh_render_data_vcol_auto_layer_uuid_get(rdata, i);
- GPU_vertformat_alias_add(&format, attr_name);
- }
- if (i == rdata->cd.layers.vcol_render) {
- GPU_vertformat_alias_add(&format, "c");
- }
- if (i == rdata->cd.layers.vcol_active) {
- GPU_vertformat_alias_add(&format, "ac");
- }
- }
-
- GPU_vertbuf_init_with_format(vbo, &format);
- GPU_vertbuf_data_alloc(vbo, loops_len);
-
- for (uint i = 0; i < vcol_len; i++) {
- GPU_vertbuf_attr_get_raw_data(vbo, vcol_id[i], &vcol_step[i]);
- }
-
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter_efa, iter_loop;
- BMFace *efa;
- BMLoop *loop;
-
- BM_ITER_MESH (efa, &iter_efa, bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (loop, &iter_loop, efa, BM_LOOPS_OF_FACE) {
- for (uint j = 0; j < vcol_len; j++) {
- const uint layer_offset = rdata->cd.offset.vcol[j];
- const uchar *elem = &((MLoopCol *)BM_ELEM_CD_GET_VOID_P(loop, layer_offset))->r;
- copy_v3_v3_uchar(GPU_vertbuf_raw_step(&vcol_step[j]), elem);
- }
- }
- }
- }
- else {
- for (uint loop = 0; loop < loops_len; loop++) {
- for (uint j = 0; j < vcol_len; j++) {
- const MLoopCol *layer_data = rdata->cd.layers.vcol[j];
- const uchar *elem = &layer_data[loop].r;
- copy_v3_v3_uchar(GPU_vertbuf_raw_step(&vcol_step[j]), elem);
- }
- }
- }
-
-#ifndef NDEBUG
- /* Check all layers are write aligned. */
- if (vcol_len > 0) {
- int vbo_len_used = GPU_vertbuf_raw_used(&vcol_step[0]);
- for (uint i = 0; i < vcol_len; i++) {
- BLI_assert(vbo_len_used == GPU_vertbuf_raw_used(&vcol_step[i]));
- }
- }
-#endif
-
-#undef USE_COMP_MESH_DATA
-}
-
-static void mesh_create_edit_facedots(MeshRenderData *rdata,
- GPUVertBuf *vbo_facedots_pos_nor_data,
- Scene *scene,
- Object *ob)
-{
- const int poly_len = mesh_render_data_polys_len_get_maybe_mapped(rdata);
- const int verts_facedot_len = poly_len;
- int facedot_len_used = 0;
-
- static struct {
- uint fdot_pos, fdot_nor_flag;
- } attr_id;
- static GPUVertFormat facedot_format = {0};
- if (facedot_format.attr_len == 0) {
- attr_id.fdot_pos = GPU_vertformat_attr_add(
- &facedot_format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- attr_id.fdot_nor_flag = GPU_vertformat_attr_add(
- &facedot_format, "norAndFlag", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- }
-
- if (DRW_TEST_ASSIGN_VBO(vbo_facedots_pos_nor_data)) {
- GPU_vertbuf_init_with_format(vbo_facedots_pos_nor_data, &facedot_format);
- GPU_vertbuf_data_alloc(vbo_facedots_pos_nor_data, verts_facedot_len);
- /* TODO(fclem): Maybe move data generation to mesh_render_data_create() */
- if (rdata->edit_bmesh) {
- if (rdata->edit_data && rdata->edit_data->vertexCos != NULL) {
- BKE_editmesh_cache_ensure_poly_normals(rdata->edit_bmesh, rdata->edit_data);
- BKE_editmesh_cache_ensure_poly_centers(rdata->edit_bmesh, rdata->edit_data);
- }
- }
- }
-
- if (rdata->mapped.use == false) {
- for (int i = 0; i < poly_len; i++) {
- if (add_edit_facedot(rdata,
- vbo_facedots_pos_nor_data,
- attr_id.fdot_pos,
- attr_id.fdot_nor_flag,
- i,
- facedot_len_used)) {
- facedot_len_used += 1;
- }
- }
- }
- else {
- if (modifiers_usesSubsurfFacedots(scene, ob)) {
- /* Facedots that follow surbsurf face center. */
- Mesh *me_cage = rdata->mapped.me_cage;
- const MPoly *mpoly = me_cage->mpoly;
- for (int p = 0; p < poly_len; p++, mpoly++) {
- const MLoop *mloop = me_cage->mloop + mpoly->loopstart;
- for (int l = 0; l < mpoly->totloop; l++, mloop++) {
- if (me_cage->mvert[mloop->v].flag & ME_VERT_FACEDOT) {
- if (add_edit_facedot_subdiv(rdata,
- vbo_facedots_pos_nor_data,
- attr_id.fdot_pos,
- attr_id.fdot_nor_flag,
- mloop->v,
- p,
- facedot_len_used)) {
- facedot_len_used += 1;
- }
- }
- }
- }
- }
- else {
- for (int i = 0; i < poly_len; i++) {
- if (add_edit_facedot_mapped(rdata,
- vbo_facedots_pos_nor_data,
- attr_id.fdot_pos,
- attr_id.fdot_nor_flag,
- i,
- facedot_len_used)) {
- facedot_len_used += 1;
- }
- }
- }
- }
-
- /* Resize & Finish */
- if (facedot_len_used != verts_facedot_len) {
- if (vbo_facedots_pos_nor_data != NULL) {
- GPU_vertbuf_data_resize(vbo_facedots_pos_nor_data, facedot_len_used);
- }
- }
-}
-
-static void mesh_create_edit_mesh_analysis(MeshRenderData *rdata, GPUVertBuf *vbo_mesh_analysis)
-{
- const MeshStatVis *mesh_stat_vis = &rdata->toolsettings->statvis;
-
- int mesh_analysis_len_used = 0;
-
- const uint loops_len = mesh_render_data_loops_len_get(rdata);
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter_efa, iter_loop;
- BMFace *efa;
- BMLoop *loop;
-
- static struct {
- uint weight;
- } attr_id;
- static GPUVertFormat mesh_analysis_format = {0};
- if (mesh_analysis_format.attr_len == 0) {
- attr_id.weight = GPU_vertformat_attr_add(
- &mesh_analysis_format, "weight_color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- }
-
- /* TODO(jbakker): Maybe move data generation to mesh_render_data_create() */
- BKE_editmesh_statvis_calc(rdata->edit_bmesh, rdata->edit_data, mesh_stat_vis);
-
- if (DRW_TEST_ASSIGN_VBO(vbo_mesh_analysis)) {
- GPU_vertbuf_init_with_format(vbo_mesh_analysis, &mesh_analysis_format);
- GPU_vertbuf_data_alloc(vbo_mesh_analysis, loops_len);
- }
-
- const bool is_vertex_data = mesh_stat_vis->type == SCE_STATVIS_SHARP;
- if (is_vertex_data) {
- BM_ITER_MESH (efa, &iter_efa, bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (loop, &iter_loop, efa, BM_LOOPS_OF_FACE) {
- uint vertex_index = BM_elem_index_get(loop->v);
- GPU_vertbuf_attr_set(vbo_mesh_analysis,
- attr_id.weight,
- mesh_analysis_len_used,
- &rdata->edit_bmesh->derivedVertColor[vertex_index]);
- mesh_analysis_len_used += 1;
- }
- }
- }
- else {
- uint face_index;
- BM_ITER_MESH_INDEX (efa, &iter_efa, bm, BM_FACES_OF_MESH, face_index) {
- BM_ITER_ELEM (loop, &iter_loop, efa, BM_LOOPS_OF_FACE) {
- GPU_vertbuf_attr_set(vbo_mesh_analysis,
- attr_id.weight,
- mesh_analysis_len_used,
- &rdata->edit_bmesh->derivedFaceColor[face_index]);
- mesh_analysis_len_used += 1;
- }
- }
- }
-
- // Free temp data in edit bmesh
- BKE_editmesh_color_free(rdata->edit_bmesh);
-
- /* Resize & Finish */
- if (mesh_analysis_len_used != loops_len) {
- if (vbo_mesh_analysis != NULL) {
- GPU_vertbuf_data_resize(vbo_mesh_analysis, mesh_analysis_len_used);
- }
- }
-}
-/* Indices */
-
-#define NO_EDGE INT_MAX
-static void mesh_create_edges_adjacency_lines(MeshRenderData *rdata,
- GPUIndexBuf *ibo,
- bool *r_is_manifold,
- const bool use_hide)
-{
- const MLoopTri *mlooptri;
- const int vert_len = mesh_render_data_verts_len_get_maybe_mapped(rdata);
- const int tri_len = mesh_render_data_looptri_len_get_maybe_mapped(rdata);
-
- *r_is_manifold = true;
-
- /* Allocate max but only used indices are sent to GPU. */
- GPUIndexBufBuilder elb;
- GPU_indexbuf_init(&elb, GPU_PRIM_LINES_ADJ, tri_len * 3, vert_len);
-
- if (rdata->mapped.use) {
- Mesh *me_cage = rdata->mapped.me_cage;
- mlooptri = BKE_mesh_runtime_looptri_ensure(me_cage);
- }
- else {
- mlooptri = rdata->mlooptri;
- }
-
- EdgeHash *eh = BLI_edgehash_new_ex(__func__, tri_len * 3);
- /* Create edges for each pair of triangles sharing an edge. */
- for (int i = 0; i < tri_len; i++) {
- for (int e = 0; e < 3; e++) {
- uint v0, v1, v2;
- if (rdata->mapped.use) {
- const MLoop *mloop = rdata->mloop;
- const MLoopTri *mlt = mlooptri + i;
- const int p_orig = rdata->mapped.p_origindex[mlt->poly];
- if (p_orig != ORIGINDEX_NONE) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMFace *efa = BM_face_at_index(bm, p_orig);
- /* Assume 'use_hide' */
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- break;
- }
- }
- v0 = mloop[mlt->tri[e]].v;
- v1 = mloop[mlt->tri[(e + 1) % 3]].v;
- v2 = mloop[mlt->tri[(e + 2) % 3]].v;
- }
- else if (rdata->edit_bmesh) {
- const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i];
- if (BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) {
- break;
- }
- v0 = BM_elem_index_get(bm_looptri[e]->v);
- v1 = BM_elem_index_get(bm_looptri[(e + 1) % 3]->v);
- v2 = BM_elem_index_get(bm_looptri[(e + 2) % 3]->v);
- }
- else {
- const MLoop *mloop = rdata->mloop;
- const MLoopTri *mlt = mlooptri + i;
- const MPoly *mp = &rdata->mpoly[mlt->poly];
- if (use_hide && (mp->flag & ME_HIDE)) {
- break;
- }
- v0 = mloop[mlt->tri[e]].v;
- v1 = mloop[mlt->tri[(e + 1) % 3]].v;
- v2 = mloop[mlt->tri[(e + 2) % 3]].v;
- }
- bool inv_indices = (v1 > v2);
- void **pval;
- bool value_is_init = BLI_edgehash_ensure_p(eh, v1, v2, &pval);
- int v_data = POINTER_AS_INT(*pval);
- if (!value_is_init || v_data == NO_EDGE) {
- /* Save the winding order inside the sign bit. Because the
- * edgehash sort the keys and we need to compare winding later. */
- int value = (int)v0 + 1; /* Int 0 bm_looptricannot be signed */
- *pval = POINTER_FROM_INT((inv_indices) ? -value : value);
- }
- else {
- /* HACK Tag as not used. Prevent overhead of BLI_edgehash_remove. */
- *pval = POINTER_FROM_INT(NO_EDGE);
- bool inv_opposite = (v_data < 0);
- uint v_opposite = (uint)abs(v_data) - 1;
-
- if (inv_opposite == inv_indices) {
- /* Don't share edge if triangles have non matching winding. */
- GPU_indexbuf_add_line_adj_verts(&elb, v0, v1, v2, v0);
- GPU_indexbuf_add_line_adj_verts(&elb, v_opposite, v1, v2, v_opposite);
- *r_is_manifold = false;
- }
- else {
- GPU_indexbuf_add_line_adj_verts(&elb, v0, v1, v2, v_opposite);
- }
- }
- }
- }
- /* Create edges for remaining non manifold edges. */
- EdgeHashIterator *ehi;
- for (ehi = BLI_edgehashIterator_new(eh); BLI_edgehashIterator_isDone(ehi) == false;
- BLI_edgehashIterator_step(ehi)) {
- uint v1, v2;
- int v_data = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi));
- if (v_data == NO_EDGE) {
- continue;
- }
- BLI_edgehashIterator_getKey(ehi, &v1, &v2);
- uint v0 = (uint)abs(v_data) - 1;
- if (v_data < 0) { /* inv_opposite */
- SWAP(uint, v1, v2);
- }
- GPU_indexbuf_add_line_adj_verts(&elb, v0, v1, v2, v0);
- *r_is_manifold = false;
- }
- BLI_edgehashIterator_free(ehi);
- BLI_edgehash_free(eh, NULL);
-
- GPU_indexbuf_build_in_place(&elb, ibo);
-}
-#undef NO_EDGE
-
-static void mesh_create_edges_lines(MeshRenderData *rdata, GPUIndexBuf *ibo, const bool use_hide)
-{
- const int verts_len = mesh_render_data_verts_len_get_maybe_mapped(rdata);
- const int edges_len = mesh_render_data_edges_len_get_maybe_mapped(rdata);
-
- GPUIndexBufBuilder elb;
- GPU_indexbuf_init(&elb, GPU_PRIM_LINES, edges_len, verts_len);
-
- if (rdata->mapped.use == false) {
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter;
- BMEdge *eed;
-
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- /* use_hide always for edit-mode */
- if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- continue;
- }
- GPU_indexbuf_add_line_verts(&elb, BM_elem_index_get(eed->v1), BM_elem_index_get(eed->v2));
- }
- }
- else {
- const MEdge *ed = rdata->medge;
- for (int i = 0; i < edges_len; i++, ed++) {
- if ((ed->flag & ME_EDGERENDER) == 0) {
- continue;
- }
- if (!(use_hide && (ed->flag & ME_HIDE))) {
- GPU_indexbuf_add_line_verts(&elb, ed->v1, ed->v2);
- }
- }
- }
- }
- else {
- BMesh *bm = rdata->edit_bmesh->bm;
- const MEdge *edge = rdata->medge;
- for (int i = 0; i < edges_len; i++, edge++) {
- const int p_orig = rdata->mapped.e_origindex[i];
- if (p_orig != ORIGINDEX_NONE) {
- BMEdge *eed = BM_edge_at_index(bm, p_orig);
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- GPU_indexbuf_add_line_verts(&elb, edge->v1, edge->v2);
- }
- }
- }
- }
-
- GPU_indexbuf_build_in_place(&elb, ibo);
-}
-
-static void mesh_create_surf_tris(MeshRenderData *rdata, GPUIndexBuf *ibo, const bool use_hide)
-{
- const int vert_len = mesh_render_data_verts_len_get_maybe_mapped(rdata);
- const int tri_len = mesh_render_data_looptri_len_get(rdata);
-
- GPUIndexBufBuilder elb;
- GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tri_len, vert_len * 3);
-
- if (rdata->mapped.use == false) {
- if (rdata->edit_bmesh) {
- for (int i = 0; i < tri_len; i++) {
- const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i];
- const BMFace *bm_face = bm_looptri[0]->f;
- /* use_hide always for edit-mode */
- if (BM_elem_flag_test(bm_face, BM_ELEM_HIDDEN)) {
- continue;
- }
- GPU_indexbuf_add_tri_verts(&elb,
- BM_elem_index_get(bm_looptri[0]->v),
- BM_elem_index_get(bm_looptri[1]->v),
- BM_elem_index_get(bm_looptri[2]->v));
- }
- }
- else {
- const MLoop *loops = rdata->mloop;
- for (int i = 0; i < tri_len; i++) {
- const MLoopTri *mlt = &rdata->mlooptri[i];
- const MPoly *mp = &rdata->mpoly[mlt->poly];
- if (use_hide && (mp->flag & ME_HIDE)) {
- continue;
- }
- GPU_indexbuf_add_tri_verts(
- &elb, loops[mlt->tri[0]].v, loops[mlt->tri[1]].v, loops[mlt->tri[2]].v);
- }
- }
- }
- else {
- /* Note: mapped doesn't support lnors yet. */
- BMesh *bm = rdata->edit_bmesh->bm;
- Mesh *me_cage = rdata->mapped.me_cage;
-
- const MLoop *loops = rdata->mloop;
- const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me_cage);
- for (int i = 0; i < tri_len; i++) {
- const MLoopTri *mlt = &mlooptri[i];
- const int p_orig = rdata->mapped.p_origindex[mlt->poly];
- if (p_orig != ORIGINDEX_NONE) {
- /* Assume 'use_hide' */
- BMFace *efa = BM_face_at_index(bm, p_orig);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- GPU_indexbuf_add_tri_verts(
- &elb, loops[mlt->tri[0]].v, loops[mlt->tri[1]].v, loops[mlt->tri[2]].v);
- }
- }
- }
- }
-
- GPU_indexbuf_build_in_place(&elb, ibo);
-}
-
-static void mesh_create_loops_lines(MeshRenderData *rdata, GPUIndexBuf *ibo, const bool use_hide)
-{
- const int edge_len = mesh_render_data_edges_len_get(rdata);
- const int loop_len = mesh_render_data_loops_len_get(rdata);
- const int poly_len = mesh_render_data_polys_len_get(rdata);
-
- GPUIndexBufBuilder elb;
- GPU_indexbuf_init(&elb, GPU_PRIM_LINES, edge_len, loop_len);
-
- if (rdata->mapped.use == false) {
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter;
- BMEdge *bm_edge;
-
- BM_ITER_MESH (bm_edge, &iter, bm, BM_EDGES_OF_MESH) {
- /* use_hide always for edit-mode */
- if (!BM_elem_flag_test(bm_edge, BM_ELEM_HIDDEN) && bm_edge->l != NULL) {
- BMLoop *bm_loop1 = bm_vert_find_first_loop_visible_inline(bm_edge->v1);
- BMLoop *bm_loop2 = bm_vert_find_first_loop_visible_inline(bm_edge->v2);
- int v1 = BM_elem_index_get(bm_loop1);
- int v2 = BM_elem_index_get(bm_loop2);
- if (v1 > v2) {
- SWAP(int, v1, v2);
- }
- GPU_indexbuf_add_line_verts(&elb, v1, v2);
- }
- }
- }
- else {
- MLoop *mloop = (MLoop *)rdata->mloop;
- MEdge *medge = (MEdge *)rdata->medge;
-
- /* Reset flag */
- for (int edge = 0; edge < edge_len; ++edge) {
- /* NOTE: not thread safe. */
- medge[edge].flag &= ~ME_EDGE_TMP_TAG;
- }
-
- for (int poly = 0; poly < poly_len; poly++) {
- const MPoly *mp = &rdata->mpoly[poly];
- if (!(use_hide && (mp->flag & ME_HIDE))) {
- for (int j = 0; j < mp->totloop; j++) {
- MEdge *ed = (MEdge *)rdata->medge + mloop[mp->loopstart + j].e;
- if ((ed->flag & ME_EDGE_TMP_TAG) == 0) {
- ed->flag |= ME_EDGE_TMP_TAG;
- int v1 = mp->loopstart + j;
- int v2 = mp->loopstart + (j + 1) % mp->totloop;
- GPU_indexbuf_add_line_verts(&elb, v1, v2);
- }
- }
- }
- }
- }
- }
-
- GPU_indexbuf_build_in_place(&elb, ibo);
-}
-
-static void mesh_create_loops_lines_paint_mask(MeshRenderData *rdata, GPUIndexBuf *ibo)
-{
- const int loop_len = mesh_render_data_loops_len_get(rdata);
- const int poly_len = mesh_render_data_polys_len_get(rdata);
- const int edge_len = mesh_render_data_edges_len_get(rdata);
-
- GPUIndexBufBuilder elb;
- GPU_indexbuf_init(&elb, GPU_PRIM_LINES, loop_len, loop_len);
-
- if (rdata->edit_bmesh) {
- /* painting does not use the edit_bmesh */
- BLI_assert(0);
- }
- else {
- if (rdata->me->editflag & ME_EDIT_PAINT_FACE_SEL) {
- /* Each edge has two bits used to count selected edges as 0, 1, 2+. */
- BLI_bitmap *edges_used = BLI_BITMAP_NEW(edge_len * 2, __func__);
-
- /* Fill the edge bitmap table. */
- for (int poly = 0; poly < poly_len; poly++) {
- const MPoly *mpoly = &rdata->mpoly[poly];
-
- /* Do not check faces that are hidden and faces that aren't selected */
- if (mpoly->flag & ME_HIDE || ((mpoly->flag & ME_FACE_SEL) == 0)) {
- continue;
- }
-
- for (int loop_index = mpoly->loopstart, loop_index_end = mpoly->loopstart + mpoly->totloop;
- loop_index < loop_index_end;
- loop_index++) {
- const MLoop *mloop = &rdata->mloop[loop_index];
- const int e_a = mloop->e * 2;
- const int e_b = e_a + 1;
- if (!BLI_BITMAP_TEST(edges_used, e_a)) {
- BLI_BITMAP_ENABLE(edges_used, e_a);
- }
- else {
- BLI_BITMAP_ENABLE(edges_used, e_b);
- }
- }
- }
-
- for (int poly = 0; poly < poly_len; poly++) {
- const MPoly *mpoly = &rdata->mpoly[poly];
- if (!(mpoly->flag & ME_HIDE)) {
-
- for (int loop_index_next = mpoly->loopstart,
- loop_index_end = mpoly->loopstart + mpoly->totloop,
- loop_index_curr = loop_index_end - 1;
- loop_index_next < loop_index_end;
- loop_index_curr = loop_index_next++) {
- const MLoop *mloop = &rdata->mloop[loop_index_curr];
- const int e_a = mloop->e * 2;
- const int e_b = e_a + 1;
-
- /* Draw if a boundary or entirely unselected. */
- if (!BLI_BITMAP_TEST(edges_used, e_b)) {
- GPU_indexbuf_add_line_verts(&elb, loop_index_curr, loop_index_next);
- }
- }
- }
- }
-
- MEM_freeN(edges_used);
- }
- else {
- /* Add edges. */
- for (int poly = 0; poly < poly_len; poly++) {
- const MPoly *mpoly = &rdata->mpoly[poly];
- for (int loop_index_next = mpoly->loopstart,
- loop_index_end = mpoly->loopstart + mpoly->totloop,
- loop_index_curr = loop_index_end - 1;
- loop_index_next < loop_index_end;
- loop_index_curr = loop_index_next++) {
- GPU_indexbuf_add_line_verts(&elb, loop_index_curr, loop_index_next);
- }
- }
- }
- }
-
- GPU_indexbuf_build_in_place(&elb, ibo);
-}
-
-static void mesh_create_loops_line_strips(MeshRenderData *rdata,
- GPUIndexBuf *ibo,
- const bool use_hide)
-{
- const int loop_len = mesh_render_data_loops_len_get(rdata);
- const int poly_len = mesh_render_data_polys_len_get(rdata);
-
- GPUIndexBufBuilder elb;
- GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, loop_len + poly_len * 2, loop_len);
-
- uint v_index = 0;
- if (rdata->mapped.use == false) {
- if (rdata->edit_bmesh) {
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter;
- BMFace *bm_face;
-
- BM_ITER_MESH (bm_face, &iter, bm, BM_FACES_OF_MESH) {
- /* use_hide always for edit-mode */
- if (!BM_elem_flag_test(bm_face, BM_ELEM_HIDDEN)) {
- for (int i = 0; i < bm_face->len; i++) {
- GPU_indexbuf_add_generic_vert(&elb, v_index + i);
- }
- /* Finish loop and restart primitive. */
- GPU_indexbuf_add_generic_vert(&elb, v_index);
- GPU_indexbuf_add_primitive_restart(&elb);
- }
- v_index += bm_face->len;
- }
- }
- else {
- for (int poly = 0; poly < poly_len; poly++) {
- const MPoly *mp = &rdata->mpoly[poly];
- if (!(use_hide && (mp->flag & ME_HIDE))) {
- const int loopend = mp->loopstart + mp->totloop;
- for (int j = mp->loopstart; j < loopend; j++) {
- GPU_indexbuf_add_generic_vert(&elb, j);
- }
- /* Finish loop and restart primitive. */
- GPU_indexbuf_add_generic_vert(&elb, mp->loopstart);
- GPU_indexbuf_add_primitive_restart(&elb);
- }
- v_index += mp->totloop;
- }
- }
- }
- else {
- /* Implement ... eventually if needed. */
- BLI_assert(0);
- }
-
- GPU_indexbuf_build_in_place(&elb, ibo);
-}
-
-static void mesh_create_loose_edges_lines(MeshRenderData *rdata,
- GPUIndexBuf *ibo,
- bool *r_no_loose_wire,
- const bool use_hide)
-{
- const int vert_len = mesh_render_data_verts_len_get_maybe_mapped(rdata);
- const int edge_len = mesh_render_data_edges_len_get_maybe_mapped(rdata);
-
- /* Alloc max (edge_len) and upload only needed range. */
- GPUIndexBufBuilder elb;
- GPU_indexbuf_init(&elb, GPU_PRIM_LINES, edge_len, vert_len);
-
- if (rdata->mapped.use == false) {
- if (rdata->edit_bmesh) {
- /* No need to support since edit mesh already draw them.
- * But some engines may want them ... */
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter eiter;
- BMEdge *eed;
- BM_ITER_MESH (eed, &eiter, bm, BM_EDGES_OF_MESH) {
- if (bm_edge_is_loose_and_visible(eed)) {
- GPU_indexbuf_add_line_verts(
- &elb, BM_elem_index_get(eed->v1), BM_elem_index_get(eed->v2));
- }
- }
- }
- else {
- for (int i = 0; i < edge_len; i++) {
- const MEdge *medge = &rdata->medge[i];
- if ((medge->flag & ME_LOOSEEDGE) && !(use_hide && (medge->flag & ME_HIDE))) {
- GPU_indexbuf_add_line_verts(&elb, medge->v1, medge->v2);
- }
- }
- }
- }
- else {
- /* Hidden checks are already done when creating the loose edge list. */
- Mesh *me_cage = rdata->mapped.me_cage;
- for (int i_iter = 0; i_iter < rdata->mapped.loose_edge_len; i_iter++) {
- const int i = rdata->mapped.loose_edges[i_iter];
- const MEdge *medge = &me_cage->medge[i];
- GPU_indexbuf_add_line_verts(&elb, medge->v1, medge->v2);
- }
- }
-
- *r_no_loose_wire = (elb.index_len == 0);
-
- GPU_indexbuf_build_in_place(&elb, ibo);
-}
-
-static void mesh_create_loops_tris(MeshRenderData *rdata,
- GPUIndexBuf **ibo,
- int ibo_len,
- const bool use_hide)
-{
- const int loop_len = mesh_render_data_loops_len_get(rdata);
- const int tri_len = mesh_render_data_looptri_len_get(rdata);
-
- GPUIndexBufBuilder *elb = BLI_array_alloca(elb, ibo_len);
-
- for (int i = 0; i < ibo_len; ++i) {
- /* TODO alloc minmum necessary. */
- GPU_indexbuf_init(&elb[i], GPU_PRIM_TRIS, tri_len, loop_len * 3);
- }
-
- if (rdata->mapped.use == false) {
- if (rdata->edit_bmesh) {
- for (int i = 0; i < tri_len; i++) {
- const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i];
- const BMFace *bm_face = bm_looptri[0]->f;
- /* use_hide always for edit-mode */
- if (BM_elem_flag_test(bm_face, BM_ELEM_HIDDEN)) {
- continue;
- }
- int mat = min_ii(ibo_len - 1, bm_face->mat_nr);
- GPU_indexbuf_add_tri_verts(&elb[mat],
- BM_elem_index_get(bm_looptri[0]),
- BM_elem_index_get(bm_looptri[1]),
- BM_elem_index_get(bm_looptri[2]));
- }
- }
- else {
- for (int i = 0; i < tri_len; i++) {
- const MLoopTri *mlt = &rdata->mlooptri[i];
- const MPoly *mp = &rdata->mpoly[mlt->poly];
- if (use_hide && (mp->flag & ME_HIDE)) {
- continue;
- }
- int mat = min_ii(ibo_len - 1, mp->mat_nr);
- GPU_indexbuf_add_tri_verts(&elb[mat], mlt->tri[0], mlt->tri[1], mlt->tri[2]);
- }
- }
- }
- else {
- /* Note: mapped doesn't support lnors yet. */
- BMesh *bm = rdata->edit_bmesh->bm;
- Mesh *me_cage = rdata->mapped.me_cage;
-
- const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me_cage);
- for (int i = 0; i < tri_len; i++) {
- const MLoopTri *mlt = &mlooptri[i];
- const int p_orig = rdata->mapped.p_origindex[mlt->poly];
- if (p_orig != ORIGINDEX_NONE) {
- /* Assume 'use_hide' */
- BMFace *efa = BM_face_at_index(bm, p_orig);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- int mat = min_ii(ibo_len - 1, efa->mat_nr);
- GPU_indexbuf_add_tri_verts(&elb[mat], mlt->tri[0], mlt->tri[1], mlt->tri[2]);
- }
- }
- }
- }
-
- for (int i = 0; i < ibo_len; ++i) {
- GPU_indexbuf_build_in_place(&elb[i], ibo[i]);
- }
-}
-
-/* Warning! this function is not thread safe!
- * It writes to MEdge->flag with ME_EDGE_TMP_TAG. */
-static void mesh_create_edit_loops_points_lines(MeshRenderData *rdata,
- GPUIndexBuf *ibo_verts,
- GPUIndexBuf *ibo_edges)
-{
- BMIter iter;
- int i;
-
- const int vert_len = mesh_render_data_verts_len_get_maybe_mapped(rdata);
- const int edge_len = mesh_render_data_edges_len_get_maybe_mapped(rdata);
- const int loop_len = mesh_render_data_loops_len_get_maybe_mapped(rdata);
- const int poly_len = mesh_render_data_polys_len_get_maybe_mapped(rdata);
- const int lvert_len = mesh_render_data_loose_verts_len_get_maybe_mapped(rdata);
- const int ledge_len = mesh_render_data_loose_edges_len_get_maybe_mapped(rdata);
- const int tot_loop_len = loop_len + ledge_len * 2 + lvert_len;
-
- GPUIndexBufBuilder elb_vert, elb_edge;
- if (DRW_TEST_ASSIGN_IBO(ibo_edges)) {
- GPU_indexbuf_init(&elb_edge, GPU_PRIM_LINES, edge_len, tot_loop_len);
- }
- if (DRW_TEST_ASSIGN_IBO(ibo_verts)) {
- GPU_indexbuf_init(&elb_vert, GPU_PRIM_POINTS, tot_loop_len, tot_loop_len);
- }
-
- int loop_idx = 0;
- if (rdata->edit_bmesh && (rdata->mapped.use == false)) {
- BMesh *bm = rdata->edit_bmesh->bm;
- /* Edges not loose. */
- if (ibo_edges) {
- BMEdge *eed;
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- BMLoop *l = bm_edge_find_first_loop_visible_inline(eed);
- if (l != NULL) {
- int v1 = BM_elem_index_get(eed->l);
- int v2 = BM_elem_index_get(eed->l->next);
- GPU_indexbuf_add_line_verts(&elb_edge, v1, v2);
- }
- }
- }
- }
- /* Face Loops */
- if (ibo_verts) {
- BMVert *eve;
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- BMLoop *l = bm_vert_find_first_loop_visible_inline(eve);
- if (l != NULL) {
- int v = BM_elem_index_get(l);
- GPU_indexbuf_add_generic_vert(&elb_vert, v);
- }
- }
- }
- }
- loop_idx = loop_len;
- /* Loose edges */
- for (i = 0; i < ledge_len; ++i) {
- if (ibo_verts) {
- GPU_indexbuf_add_generic_vert(&elb_vert, loop_idx + 0);
- GPU_indexbuf_add_generic_vert(&elb_vert, loop_idx + 1);
- }
- if (ibo_edges) {
- GPU_indexbuf_add_line_verts(&elb_edge, loop_idx + 0, loop_idx + 1);
- }
- loop_idx += 2;
- }
- /* Loose verts */
- if (ibo_verts) {
- for (i = 0; i < lvert_len; ++i) {
- GPU_indexbuf_add_generic_vert(&elb_vert, loop_idx);
- loop_idx += 1;
- }
- }
- }
- else if (rdata->mapped.use) {
- const MPoly *mpoly = rdata->mapped.me_cage->mpoly;
- MVert *mvert = rdata->mapped.me_cage->mvert;
- MEdge *medge = rdata->mapped.me_cage->medge;
- BMesh *bm = rdata->edit_bmesh->bm;
-
- const int *v_origindex = rdata->mapped.v_origindex;
- const int *e_origindex = rdata->mapped.e_origindex;
- const int *p_origindex = rdata->mapped.p_origindex;
-
- /* Reset flag */
- for (int edge = 0; edge < edge_len; ++edge) {
- /* NOTE: not thread safe. */
- medge[edge].flag &= ~ME_EDGE_TMP_TAG;
- }
- for (int vert = 0; vert < vert_len; ++vert) {
- /* NOTE: not thread safe. */
- mvert[vert].flag &= ~ME_VERT_TMP_TAG;
- }
-
- /* Face Loops */
- for (int poly = 0; poly < poly_len; poly++, mpoly++) {
- int fidx = p_origindex[poly];
- if (fidx != ORIGINDEX_NONE) {
- BMFace *efa = BM_face_at_index(bm, fidx);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- const MLoop *mloop = &rdata->mapped.me_cage->mloop[mpoly->loopstart];
- for (i = 0; i < mpoly->totloop; ++i, ++mloop) {
- if (ibo_verts && (v_origindex[mloop->v] != ORIGINDEX_NONE) &&
- (mvert[mloop->v].flag & ME_VERT_TMP_TAG) == 0) {
- mvert[mloop->v].flag |= ME_VERT_TMP_TAG;
- GPU_indexbuf_add_generic_vert(&elb_vert, loop_idx + i);
- }
- if (ibo_edges && (e_origindex[mloop->e] != ORIGINDEX_NONE) &&
- ((medge[mloop->e].flag & ME_EDGE_TMP_TAG) == 0)) {
- medge[mloop->e].flag |= ME_EDGE_TMP_TAG;
- int v1 = loop_idx + i;
- int v2 = loop_idx + ((i + 1) % mpoly->totloop);
- GPU_indexbuf_add_line_verts(&elb_edge, v1, v2);
- }
- }
- }
- }
- loop_idx += mpoly->totloop;
- }
- /* Loose edges */
- for (i = 0; i < ledge_len; ++i) {
- int eidx = e_origindex[rdata->mapped.loose_edges[i]];
- if (eidx != ORIGINDEX_NONE) {
- if (ibo_verts) {
- const MEdge *ed = &medge[rdata->mapped.loose_edges[i]];
- if (v_origindex[ed->v1] != ORIGINDEX_NONE) {
- GPU_indexbuf_add_generic_vert(&elb_vert, loop_idx + 0);
- }
- if (v_origindex[ed->v2] != ORIGINDEX_NONE) {
- GPU_indexbuf_add_generic_vert(&elb_vert, loop_idx + 1);
- }
- }
- if (ibo_edges) {
- GPU_indexbuf_add_line_verts(&elb_edge, loop_idx + 0, loop_idx + 1);
- }
- }
- loop_idx += 2;
- }
- /* Loose verts */
- if (ibo_verts) {
- for (i = 0; i < lvert_len; ++i) {
- int vidx = v_origindex[rdata->mapped.loose_verts[i]];
- if (vidx != ORIGINDEX_NONE) {
- GPU_indexbuf_add_generic_vert(&elb_vert, loop_idx);
- }
- loop_idx += 1;
- }
- }
- }
- else {
- const MPoly *mpoly = rdata->mpoly;
-
- /* Face Loops */
- for (int poly = 0; poly < poly_len; poly++, mpoly++) {
- if ((mpoly->flag & ME_HIDE) == 0) {
- for (i = 0; i < mpoly->totloop; ++i) {
- if (ibo_verts) {
- GPU_indexbuf_add_generic_vert(&elb_vert, loop_idx + i);
- }
- if (ibo_edges) {
- int v1 = loop_idx + i;
- int v2 = loop_idx + ((i + 1) % mpoly->totloop);
- GPU_indexbuf_add_line_verts(&elb_edge, v1, v2);
- }
- }
- }
- loop_idx += mpoly->totloop;
- }
- /* TODO(fclem): Until we find a way to detect
- * loose verts easily outside of edit mode, this
- * will remain disabled. */
-#if 0
- /* Loose edges */
- for (int e = 0; e < edge_len; e++, medge++) {
- if (medge->flag & ME_LOOSEEDGE) {
- int eidx = e_origindex[e];
- if (eidx != ORIGINDEX_NONE) {
- if ((medge->flag & ME_HIDE) == 0) {
- for (int j = 0; j < 2; ++j) {
- if (ibo_verts) {
- GPU_indexbuf_add_generic_vert(&elb_vert, loop_idx + j);
- }
- if (ibo_edges) {
- GPU_indexbuf_add_generic_vert(&elb_edge, loop_idx + j);
- }
- }
- }
- }
- loop_idx += 2;
- }
- }
- /* Loose verts */
- for (int v = 0; v < vert_len; v++, mvert++) {
- int vidx = v_origindex[v];
- if (vidx != ORIGINDEX_NONE) {
- if ((mvert->flag & ME_HIDE) == 0) {
- if (ibo_verts) {
- GPU_indexbuf_add_generic_vert(&elb_vert, loop_idx);
- }
- if (ibo_edges) {
- GPU_indexbuf_add_generic_vert(&elb_edge, loop_idx);
- }
- }
- loop_idx += 1;
- }
- }
-#endif
- }
-
- if (ibo_verts) {
- GPU_indexbuf_build_in_place(&elb_vert, ibo_verts);
- }
- if (ibo_edges) {
- GPU_indexbuf_build_in_place(&elb_edge, ibo_edges);
- }
-}
-
-static void mesh_create_edit_loops_tris(MeshRenderData *rdata, GPUIndexBuf *ibo)
-{
- const int loop_len = mesh_render_data_loops_len_get_maybe_mapped(rdata);
- const int tri_len = mesh_render_data_looptri_len_get_maybe_mapped(rdata);
-
- GPUIndexBufBuilder elb;
- /* TODO alloc minmum necessary. */
- GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tri_len, loop_len * 3);
-
- if (rdata->edit_bmesh && (rdata->mapped.use == false)) {
- for (int i = 0; i < tri_len; i++) {
- const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i];
- const BMFace *bm_face = bm_looptri[0]->f;
- /* use_hide always for edit-mode */
- if (BM_elem_flag_test(bm_face, BM_ELEM_HIDDEN)) {
- continue;
- }
- GPU_indexbuf_add_tri_verts(&elb,
- BM_elem_index_get(bm_looptri[0]),
- BM_elem_index_get(bm_looptri[1]),
- BM_elem_index_get(bm_looptri[2]));
- }
- }
- else if (rdata->mapped.use == true) {
- BMesh *bm = rdata->edit_bmesh->bm;
- Mesh *me_cage = rdata->mapped.me_cage;
-
- const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me_cage);
- for (int i = 0; i < tri_len; i++) {
- const MLoopTri *mlt = &mlooptri[i];
- const int p_orig = rdata->mapped.p_origindex[mlt->poly];
- if (p_orig != ORIGINDEX_NONE) {
- /* Assume 'use_hide' */
- BMFace *efa = BM_face_at_index(bm, p_orig);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- GPU_indexbuf_add_tri_verts(&elb, mlt->tri[0], mlt->tri[1], mlt->tri[2]);
- }
- }
- }
- }
- else {
- const MLoopTri *mlt = rdata->mlooptri;
- for (int i = 0; i < tri_len; i++, mlt++) {
- const MPoly *mpoly = &rdata->mpoly[mlt->poly];
- /* Assume 'use_hide' */
- if ((mpoly->flag & ME_HIDE) == 0) {
- GPU_indexbuf_add_tri_verts(&elb, mlt->tri[0], mlt->tri[1], mlt->tri[2]);
- }
- }
- }
-
- GPU_indexbuf_build_in_place(&elb, ibo);
-}
-
/** \} */
/* ---------------------------------------------------------------------- */
@@ -4563,9 +753,9 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me,
*auto_layer_count = cache->auto_layer_len;
}
for (int i = 0; i < cache->mat_len; ++i) {
- DRW_batch_request(&cache->surf_per_mat[i]);
+ DRW_batch_request(&cache->surface_per_mat[i]);
}
- return cache->surf_per_mat;
+ return cache->surface_per_mat;
}
GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(Mesh *me)
@@ -4574,9 +764,9 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(Mesh *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) {
- DRW_batch_request(&cache->surf_per_mat[i]);
+ DRW_batch_request(&cache->surface_per_mat[i]);
}
- return cache->surf_per_mat;
+ return cache->surface_per_mat;
}
GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(Mesh *me)
@@ -4622,6 +812,13 @@ GPUBatch *DRW_mesh_batch_cache_get_edit_vertices(Mesh *me)
return DRW_batch_request(&cache->batch.edit_vertices);
}
+GPUBatch *DRW_mesh_batch_cache_get_edit_vnors(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+ mesh_batch_cache_add_request(cache, MBC_EDIT_VNOR);
+ return DRW_batch_request(&cache->batch.edit_vnor);
+}
+
GPUBatch *DRW_mesh_batch_cache_get_edit_lnors(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
@@ -4633,7 +830,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edit_facedots(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
mesh_batch_cache_add_request(cache, MBC_EDIT_FACEDOTS);
- return DRW_batch_request(&cache->batch.edit_facedots);
+ return DRW_batch_request(&cache->batch.edit_fdots);
}
/** \} */
@@ -4653,7 +850,7 @@ GPUBatch *DRW_mesh_batch_cache_get_facedots_with_select_id(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
mesh_batch_cache_add_request(cache, MBC_EDIT_SELECTION_FACEDOTS);
- return DRW_batch_request(&cache->batch.edit_selection_facedots);
+ return DRW_batch_request(&cache->batch.edit_selection_fdots);
}
GPUBatch *DRW_mesh_batch_cache_get_edges_with_select_id(Mesh *me)
@@ -4679,6 +876,7 @@ GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(Mesh *me)
GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_area(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_AREA);
return DRW_batch_request(&cache->batch.edituv_faces_strech_area);
}
@@ -4686,6 +884,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_area(Mesh *me)
GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_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);
}
@@ -4693,6 +892,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_angle(Mesh *me)
GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
+ texpaint_request_active_uv(cache, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES);
return DRW_batch_request(&cache->batch.edituv_faces);
}
@@ -4700,6 +900,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(Mesh *me)
GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
+ texpaint_request_active_uv(cache, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_EDGES);
return DRW_batch_request(&cache->batch.edituv_edges);
}
@@ -4707,6 +908,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(Mesh *me)
GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
+ texpaint_request_active_uv(cache, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_VERTS);
return DRW_batch_request(&cache->batch.edituv_verts);
}
@@ -4714,8 +916,9 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(Mesh *me)
GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
+ texpaint_request_active_uv(cache, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACEDOTS);
- return DRW_batch_request(&cache->batch.edituv_facedots);
+ return DRW_batch_request(&cache->batch.edituv_fdots);
}
GPUBatch *DRW_mesh_batch_cache_get_uv_edges(Mesh *me)
@@ -4729,356 +932,11 @@ GPUBatch *DRW_mesh_batch_cache_get_uv_edges(Mesh *me)
GPUBatch *DRW_mesh_batch_cache_get_surface_edges(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
+ texpaint_request_active_uv(cache, me);
mesh_batch_cache_add_request(cache, MBC_WIRE_LOOPS);
return DRW_batch_request(&cache->batch.wire_loops);
}
-/* Compute 3D & 2D areas and their sum. */
-BLI_INLINE void edit_uv_preprocess_stretch_area(BMFace *efa,
- const int cd_loop_uv_offset,
- uint fidx,
- float *totarea,
- float *totuvarea,
- float (*faces_areas)[2])
-{
- faces_areas[fidx][0] = BM_face_calc_area(efa);
- faces_areas[fidx][1] = BM_face_calc_area_uv(efa, cd_loop_uv_offset);
-
- *totarea += faces_areas[fidx][0];
- *totuvarea += faces_areas[fidx][1];
-}
-
-BLI_INLINE float edit_uv_get_stretch_area(float area, float uvarea)
-{
- if (area < FLT_EPSILON || uvarea < FLT_EPSILON) {
- return 1.0f;
- }
- else if (area > uvarea) {
- return 1.0f - (uvarea / area);
- }
- else {
- return 1.0f - (area / uvarea);
- }
-}
-
-/* Compute face's normalized contour vectors. */
-BLI_INLINE void edit_uv_preprocess_stretch_angle(float (*auv)[2],
- float (*av)[3],
- const int cd_loop_uv_offset,
- BMFace *efa)
-{
- BMLoop *l;
- BMIter liter;
- int i;
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset);
-
- sub_v2_v2v2(auv[i], luv_prev->uv, luv->uv);
- normalize_v2(auv[i]);
-
- sub_v3_v3v3(av[i], l->prev->v->co, l->v->co);
- normalize_v3(av[i]);
- }
-}
-
-#if 0 /* here for reference, this is done in shader now. */
-BLI_INLINE float edit_uv_get_loop_stretch_angle(const float auv0[2],
- const float auv1[2],
- const float av0[3],
- const float av1[3])
-{
- float uvang = angle_normalized_v2v2(auv0, auv1);
- float ang = angle_normalized_v3v3(av0, av1);
- float stretch = fabsf(uvang - ang) / (float)M_PI;
- return 1.0f - pow2f(1.0f - stretch);
-}
-#endif
-
-static struct EditUVFormatIndex {
- uint area, angle, uv_adj, flag, fdots_uvs, fdots_flag;
-} uv_attr_id = {0};
-
-static void uvedit_fill_buffer_data(MeshRenderData *rdata,
- GPUVertBuf *vbo_area,
- GPUVertBuf *vbo_angle,
- GPUVertBuf *vbo_fdots_pos,
- GPUVertBuf *vbo_fdots_data,
- GPUIndexBufBuilder *elb_vert,
- GPUIndexBufBuilder *elb_edge,
- GPUIndexBufBuilder *elb_face)
-{
- BMesh *bm = rdata->edit_bmesh->bm;
- BMIter iter, liter;
- BMFace *efa;
- uint vidx, fidx, fdot_idx, i;
- const int poly_len = mesh_render_data_polys_len_get_maybe_mapped(rdata);
- float(*faces_areas)[2] = NULL;
- float totarea = 0.0f, totuvarea = 0.0f;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- BLI_buffer_declare_static(vec3f, vec3_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
- BLI_buffer_declare_static(vec2f, vec2_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
-
- if (vbo_area) {
- faces_areas = MEM_mallocN(sizeof(float) * 2 * bm->totface, "EDITUV faces areas");
- }
-
- /* Preprocess */
- fidx = 0;
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- /* Tag hidden faces */
- BM_elem_flag_set(efa, BM_ELEM_TAG, uvedit_face_visible_nolocal_ex(rdata->toolsettings, efa));
-
- if (vbo_area) {
- edit_uv_preprocess_stretch_area(
- efa, cd_loop_uv_offset, fidx++, &totarea, &totuvarea, faces_areas);
- }
- }
-
- vidx = 0;
- fidx = 0;
- fdot_idx = 0;
- if (rdata->mapped.use == false && rdata->edit_bmesh) {
- BMLoop *l;
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- const bool face_visible = BM_elem_flag_test(efa, BM_ELEM_TAG);
- const int efa_len = efa->len;
- float fdot[2] = {0.0f, 0.0f};
- float(*av)[3], (*auv)[2];
- ushort area_stretch;
-
- /* Face preprocess */
- if (vbo_area) {
- area_stretch = edit_uv_get_stretch_area(faces_areas[fidx][0] / totarea,
- faces_areas[fidx][1] / totuvarea) *
- 65534.0f;
- }
- if (vbo_angle) {
- av = (float(*)[3])BLI_buffer_reinit_data(&vec3_buf, vec3f, efa_len);
- auv = (float(*)[2])BLI_buffer_reinit_data(&vec2_buf, vec2f, efa_len);
- edit_uv_preprocess_stretch_angle(auv, av, cd_loop_uv_offset, efa);
- }
-
- /* Skip hidden faces. */
- if (face_visible) {
- if (elb_face) {
- for (i = 0; i < efa->len; ++i) {
- GPU_indexbuf_add_generic_vert(elb_face, vidx + i);
- }
- }
- if (elb_vert) {
- for (i = 0; i < efa->len; ++i) {
- GPU_indexbuf_add_generic_vert(elb_vert, vidx + i);
- }
- }
- if (elb_edge) {
- for (i = 0; i < efa->len; ++i) {
- GPU_indexbuf_add_line_verts(elb_edge, vidx + i, vidx + (i + 1) % efa->len);
- }
- }
- }
-
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (vbo_area) {
- GPU_vertbuf_attr_set(vbo_area, uv_attr_id.area, vidx, &area_stretch);
- }
- if (vbo_angle) {
- int i_next = (i + 1) % efa_len;
- short suv[4];
- /* Send uvs to the shader and let it compute the aspect corrected angle. */
- normal_float_to_short_v2(&suv[0], auv[i]);
- normal_float_to_short_v2(&suv[2], auv[i_next]);
- GPU_vertbuf_attr_set(vbo_angle, uv_attr_id.uv_adj, vidx, suv);
- /* Compute 3D angle here */
- short angle = 32767.0f * angle_normalized_v3v3(av[i], av[i_next]) / (float)M_PI;
- GPU_vertbuf_attr_set(vbo_angle, uv_attr_id.angle, vidx, &angle);
- }
- if (vbo_fdots_pos) {
- add_v2_v2(fdot, luv->uv);
- }
- vidx++;
- }
-
- if (elb_face && face_visible) {
- GPU_indexbuf_add_generic_vert(elb_face, vidx - efa->len);
- GPU_indexbuf_add_primitive_restart(elb_face);
- }
- if (vbo_fdots_pos && face_visible) {
- mul_v2_fl(fdot, 1.0f / (float)efa->len);
- GPU_vertbuf_attr_set(vbo_fdots_pos, uv_attr_id.fdots_uvs, fdot_idx, fdot);
- }
- if (vbo_fdots_data && face_visible) {
- uchar face_flag = mesh_render_data_face_flag(rdata, efa, cd_loop_uv_offset);
- GPU_vertbuf_attr_set(vbo_fdots_data, uv_attr_id.fdots_flag, fdot_idx, &face_flag);
- }
- fdot_idx += face_visible ? 1 : 0;
- fidx++;
- }
- }
- else {
- const MPoly *mpoly = rdata->mapped.me_cage->mpoly;
- // const MEdge *medge = rdata->mapped.me_cage->medge;
- // const MVert *mvert = rdata->mapped.me_cage->mvert;
- const MLoop *mloop = rdata->mapped.me_cage->mloop;
-
- const int *v_origindex = rdata->mapped.v_origindex;
- const int *e_origindex = rdata->mapped.e_origindex;
- const int *p_origindex = rdata->mapped.p_origindex;
-
- /* Face Loops */
- for (int poly = 0; poly < poly_len; poly++, mpoly++) {
- float fdot[2] = {0.0f, 0.0f};
- const MLoop *l = &mloop[mpoly->loopstart];
- int fidx_ori = p_origindex[poly];
- efa = (fidx_ori != ORIGINDEX_NONE) ? BM_face_at_index(bm, fidx_ori) : NULL;
- const bool face_visible = efa != NULL && BM_elem_flag_test(efa, BM_ELEM_TAG);
- if (efa && vbo_fdots_data) {
- uchar face_flag = mesh_render_data_face_flag(rdata, efa, cd_loop_uv_offset);
- GPU_vertbuf_attr_set(vbo_fdots_data, uv_attr_id.fdots_flag, fdot_idx, &face_flag);
- }
- /* Skip hidden faces. */
- if (face_visible) {
- if (elb_face) {
- for (i = 0; i < mpoly->totloop; ++i) {
- GPU_indexbuf_add_generic_vert(elb_face, vidx + i);
- }
- GPU_indexbuf_add_generic_vert(elb_face, vidx);
- GPU_indexbuf_add_primitive_restart(elb_face);
- }
- if (elb_edge) {
- for (i = 0; i < mpoly->totloop; ++i) {
- if (e_origindex[l[i].e] != ORIGINDEX_NONE) {
- GPU_indexbuf_add_line_verts(elb_edge, vidx + i, vidx + (i + 1) % mpoly->totloop);
- }
- }
- }
- if (elb_vert) {
- for (i = 0; i < mpoly->totloop; ++i) {
- if (v_origindex[l[i].v] != ORIGINDEX_NONE) {
- GPU_indexbuf_add_generic_vert(elb_vert, vidx + i);
- }
- }
- }
- }
- for (i = 0; i < mpoly->totloop; i++, l++) {
- /* TODO support stretch. */
- if (vbo_fdots_pos) {
- MLoopUV *luv = &rdata->mloopuv[mpoly->loopstart + i];
- add_v2_v2(fdot, luv->uv);
- }
- vidx++;
- }
- if (vbo_fdots_pos && face_visible) {
- mul_v2_fl(fdot, 1.0f / mpoly->totloop);
- GPU_vertbuf_attr_set(vbo_fdots_pos, uv_attr_id.fdots_uvs, fdot_idx, fdot);
- }
- fidx++;
- fdot_idx += face_visible ? 1 : 0;
- }
- }
-
- if (faces_areas) {
- MEM_freeN(faces_areas);
- }
-
- BLI_buffer_free(&vec3_buf);
- BLI_buffer_free(&vec2_buf);
-
- if (fdot_idx < poly_len) {
- if (vbo_fdots_pos) {
- GPU_vertbuf_data_resize(vbo_fdots_pos, fdot_idx);
- }
- if (vbo_fdots_data) {
- GPU_vertbuf_data_resize(vbo_fdots_data, fdot_idx);
- }
- }
-}
-
-static void mesh_create_uvedit_buffers(MeshRenderData *rdata,
- GPUVertBuf *vbo_area,
- GPUVertBuf *vbo_angle,
- GPUVertBuf *vbo_fdots_pos,
- GPUVertBuf *vbo_fdots_data,
- GPUIndexBuf *ibo_vert,
- GPUIndexBuf *ibo_edge,
- GPUIndexBuf *ibo_face)
-{
- static GPUVertFormat format_area = {0};
- static GPUVertFormat format_angle = {0};
- static GPUVertFormat format_fdots_pos = {0};
- static GPUVertFormat format_fdots_flag = {0};
-
- if (format_area.attr_len == 0) {
- uv_attr_id.area = GPU_vertformat_attr_add(
- &format_area, "stretch", GPU_COMP_U16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
- uv_attr_id.angle = GPU_vertformat_attr_add(
- &format_angle, "angle", GPU_COMP_I16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
- uv_attr_id.uv_adj = GPU_vertformat_attr_add(
- &format_angle, "uv_adj", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
-
- uv_attr_id.fdots_flag = GPU_vertformat_attr_add(
- &format_fdots_flag, "flag", GPU_COMP_U8, 1, GPU_FETCH_INT);
- uv_attr_id.fdots_uvs = GPU_vertformat_attr_add(
- &format_fdots_pos, "u", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- GPU_vertformat_alias_add(&format_fdots_pos, "pos");
- }
-
- const int loop_len = mesh_render_data_loops_len_get_maybe_mapped(rdata);
- const int face_len = mesh_render_data_polys_len_get_maybe_mapped(rdata);
- const int idx_len = loop_len + face_len * 2;
-
- if (DRW_TEST_ASSIGN_VBO(vbo_area)) {
- GPU_vertbuf_init_with_format(vbo_area, &format_area);
- GPU_vertbuf_data_alloc(vbo_area, loop_len);
- }
- if (DRW_TEST_ASSIGN_VBO(vbo_angle)) {
- GPU_vertbuf_init_with_format(vbo_angle, &format_angle);
- GPU_vertbuf_data_alloc(vbo_angle, loop_len);
- }
- if (DRW_TEST_ASSIGN_VBO(vbo_fdots_pos)) {
- GPU_vertbuf_init_with_format(vbo_fdots_pos, &format_fdots_pos);
- GPU_vertbuf_data_alloc(vbo_fdots_pos, face_len);
- }
- if (DRW_TEST_ASSIGN_VBO(vbo_fdots_data)) {
- GPU_vertbuf_init_with_format(vbo_fdots_data, &format_fdots_flag);
- GPU_vertbuf_data_alloc(vbo_fdots_data, face_len);
- }
-
- GPUIndexBufBuilder elb_vert, elb_edge, elb_face;
- if (DRW_TEST_ASSIGN_IBO(ibo_vert)) {
- GPU_indexbuf_init_ex(&elb_vert, GPU_PRIM_POINTS, loop_len, loop_len);
- }
- if (DRW_TEST_ASSIGN_IBO(ibo_edge)) {
- GPU_indexbuf_init_ex(&elb_edge, GPU_PRIM_LINES, loop_len * 2, loop_len);
- }
- if (DRW_TEST_ASSIGN_IBO(ibo_face)) {
- GPU_indexbuf_init_ex(&elb_face, GPU_PRIM_TRI_FAN, idx_len, loop_len);
- }
-
- uvedit_fill_buffer_data(rdata,
- vbo_area,
- vbo_angle,
- vbo_fdots_pos,
- vbo_fdots_data,
- ibo_vert ? &elb_vert : NULL,
- ibo_edge ? &elb_edge : NULL,
- ibo_face ? &elb_face : NULL);
-
- if (ibo_vert) {
- GPU_indexbuf_build_in_place(&elb_vert, ibo_vert);
- }
-
- if (ibo_edge) {
- GPU_indexbuf_build_in_place(&elb_edge, ibo_edge);
- }
-
- if (ibo_face) {
- GPU_indexbuf_build_in_place(&elb_face, ibo_face);
- }
-}
-
/** \} */
/* ---------------------------------------------------------------------- */
@@ -5109,8 +967,12 @@ void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime)
/* Can be called for any surface type. Mesh *me is the final mesh. */
void DRW_mesh_batch_cache_create_requested(
- Object *ob, Mesh *me, const ToolSettings *ts, const bool is_paint_mode, const bool use_hide)
+ Object *ob, Mesh *me, const Scene *scene, const bool is_paint_mode, const bool use_hide)
{
+ const ToolSettings *ts = NULL;
+ if (scene) {
+ ts = scene->toolsettings;
+ }
MeshBatchCache *cache = mesh_batch_cache_get(me);
/* Early out */
@@ -5136,15 +998,13 @@ void DRW_mesh_batch_cache_create_requested(
}
}
- if (batch_requested & (MBC_SURFACE | MBC_SURF_PER_MAT | MBC_WIRE_LOOPS_UVS)) {
+ 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)) {
/* 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 layer is needed. */
- }
- else if (cache->cd_needed.tan_orco == 0) {
- /* Skip orco calculation if not needed by tangent generation.
- */
+ if (CustomData_get_layer(&me->vdata, CD_ORCO) == NULL) {
+ /* Skip orco calculation */
cache->cd_needed.orco = 0;
}
}
@@ -5155,21 +1015,26 @@ void DRW_mesh_batch_cache_create_requested(
* material. */
bool cd_overlap = mesh_cd_layers_type_overlap(cache->cd_used, cache->cd_needed);
if (cd_overlap == false) {
- if ((cache->cd_used.uv & cache->cd_needed.uv) != cache->cd_needed.uv ||
- (cache->cd_used.tan & cache->cd_needed.tan) != cache->cd_needed.tan ||
- cache->cd_used.tan_orco != cache->cd_needed.tan_orco) {
- GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_uv_tan);
- }
- if (cache->cd_used.orco != cache->cd_needed.orco) {
- GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_orco);
- }
- if ((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) {
- GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_vcol);
+ FOREACH_MESH_BUFFER_CACHE(cache, mbuffercache)
+ {
+ if ((cache->cd_used.uv & cache->cd_needed.uv) != cache->cd_needed.uv) {
+ GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.uv);
+ }
+ if ((cache->cd_used.tan & cache->cd_needed.tan) != cache->cd_needed.tan ||
+ cache->cd_used.tan_orco != cache->cd_needed.tan_orco) {
+ GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.tan);
+ }
+ if (cache->cd_used.orco != cache->cd_needed.orco) {
+ GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.orco);
+ }
+ if ((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) {
+ GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.vcol);
+ }
}
/* 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) {
- GPU_BATCH_CLEAR_SAFE(cache->surf_per_mat[i]);
+ GPU_BATCH_CLEAR_SAFE(cache->surface_per_mat[i]);
}
GPU_BATCH_CLEAR_SAFE(cache->batch.surface);
cache->batch_ready &= ~(MBC_SURFACE | MBC_SURF_PER_MAT);
@@ -5186,22 +1051,26 @@ void DRW_mesh_batch_cache_create_requested(
const bool is_uvsyncsel = (ts->uv_flag & UV_SYNC_SELECTION);
if (cache->is_uvsyncsel != is_uvsyncsel) {
cache->is_uvsyncsel = is_uvsyncsel;
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_uv_data);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_stretch_angle);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_stretch_area);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_uv);
- GPU_VERTBUF_DISCARD_SAFE(cache->edit.facedots_uv);
- GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.edituv_loops_tri_fans);
- GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.edituv_loops_line_strips);
- GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.edituv_loops_points);
+ FOREACH_MESH_BUFFER_CACHE(cache, mbuffercache)
+ {
+ GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.edituv_data);
+ GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.stretch_angle);
+ GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.stretch_area);
+ GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.uv);
+ GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.fdots_uv);
+ GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_tris);
+ GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_lines);
+ GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_points);
+ }
/* 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);
GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_edges);
GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_verts);
- GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_facedots);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_fdots);
cache->batch_ready &= ~MBC_EDITUV;
}
}
@@ -5217,410 +1086,226 @@ void DRW_mesh_batch_cache_create_requested(
cache->batch_ready |= batch_requested;
+ const bool do_cage = (me->edit_mesh &&
+ (me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage));
+
+ const bool do_uvcage = me->edit_mesh && !me->edit_mesh->mesh_eval_final->runtime.is_original;
+
+ MeshBufferCache *mbufcache = &cache->final;
+
/* Init batches and request VBOs & IBOs */
if (DRW_batch_requested(cache->batch.surface, GPU_PRIM_TRIS)) {
- DRW_ibo_request(cache->batch.surface, &cache->ibo.loops_tris);
- DRW_vbo_request(cache->batch.surface, &cache->ordered.loop_pos_nor);
- /* For paint overlay. Active layer should have been queried. */
+ DRW_ibo_request(cache->batch.surface, &mbufcache->ibo.tris);
+ /* Order matters. First ones override latest vbos' attribs. */
+ DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.lnor);
+ DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.pos_nor);
if (cache->cd_used.uv != 0) {
- DRW_vbo_request(cache->batch.surface, &cache->ordered.loop_uv_tan);
+ DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.uv);
}
if (cache->cd_used.vcol != 0) {
- DRW_vbo_request(cache->batch.surface, &cache->ordered.loop_vcol);
+ DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.vcol);
}
}
if (DRW_batch_requested(cache->batch.all_verts, GPU_PRIM_POINTS)) {
- DRW_vbo_request(cache->batch.all_verts, &cache->ordered.pos_nor);
+ DRW_vbo_request(cache->batch.all_verts, &mbufcache->vbo.pos_nor);
}
if (DRW_batch_requested(cache->batch.all_edges, GPU_PRIM_LINES)) {
- DRW_ibo_request(cache->batch.all_edges, &cache->ibo.edges_lines);
- DRW_vbo_request(cache->batch.all_edges, &cache->ordered.pos_nor);
+ DRW_ibo_request(cache->batch.all_edges, &mbufcache->ibo.lines);
+ DRW_vbo_request(cache->batch.all_edges, &mbufcache->vbo.pos_nor);
}
if (DRW_batch_requested(cache->batch.loose_edges, GPU_PRIM_LINES)) {
- DRW_ibo_request(cache->batch.loose_edges, &cache->ibo.loose_edges_lines);
- DRW_vbo_request(cache->batch.loose_edges, &cache->ordered.pos_nor);
+ DRW_ibo_request(cache->batch.loose_edges, &mbufcache->ibo.lines);
+ DRW_vbo_request(cache->batch.loose_edges, &mbufcache->vbo.pos_nor);
}
if (DRW_batch_requested(cache->batch.edge_detection, GPU_PRIM_LINES_ADJ)) {
- DRW_ibo_request(cache->batch.edge_detection, &cache->ibo.edges_adj_lines);
- DRW_vbo_request(cache->batch.edge_detection, &cache->ordered.pos_nor);
+ DRW_ibo_request(cache->batch.edge_detection, &mbufcache->ibo.lines_adjacency);
+ DRW_vbo_request(cache->batch.edge_detection, &mbufcache->vbo.pos_nor);
}
if (DRW_batch_requested(cache->batch.surface_weights, GPU_PRIM_TRIS)) {
- DRW_ibo_request(cache->batch.surface_weights, &cache->ibo.surf_tris);
- DRW_vbo_request(cache->batch.surface_weights, &cache->ordered.pos_nor);
- DRW_vbo_request(cache->batch.surface_weights, &cache->ordered.weights);
+ DRW_ibo_request(cache->batch.surface_weights, &mbufcache->ibo.tris);
+ DRW_vbo_request(cache->batch.surface_weights, &mbufcache->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.surface_weights, &mbufcache->vbo.weights);
}
if (DRW_batch_requested(cache->batch.wire_loops, GPU_PRIM_LINES)) {
- DRW_ibo_request(cache->batch.wire_loops, &cache->ibo.loops_lines_paint_mask);
- DRW_vbo_request(cache->batch.wire_loops, &cache->ordered.loop_pos_nor);
+ DRW_ibo_request(cache->batch.wire_loops, &mbufcache->ibo.lines_paint_mask);
+ DRW_vbo_request(cache->batch.wire_loops, &mbufcache->vbo.pos_nor);
}
if (DRW_batch_requested(cache->batch.wire_edges, GPU_PRIM_LINES)) {
- DRW_ibo_request(cache->batch.wire_edges, &cache->ibo.loops_lines);
- DRW_vbo_request(cache->batch.wire_edges, &cache->ordered.loop_pos_nor);
- DRW_vbo_request(cache->batch.wire_edges, &cache->ordered.loop_edge_fac);
+ DRW_ibo_request(cache->batch.wire_edges, &mbufcache->ibo.lines);
+ DRW_vbo_request(cache->batch.wire_edges, &mbufcache->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.wire_edges, &mbufcache->vbo.edge_fac);
}
- if (DRW_batch_requested(cache->batch.wire_loops_uvs, GPU_PRIM_LINE_STRIP)) {
- DRW_ibo_request(cache->batch.wire_loops_uvs, &cache->ibo.loops_line_strips);
+ if (DRW_batch_requested(cache->batch.wire_loops_uvs, GPU_PRIM_LINES)) {
+ DRW_ibo_request(cache->batch.wire_loops_uvs, &mbufcache->ibo.edituv_lines);
/* For paint overlay. Active layer should have been queried. */
if (cache->cd_used.uv != 0) {
- DRW_vbo_request(cache->batch.wire_loops_uvs, &cache->ordered.loop_uv_tan);
+ DRW_vbo_request(cache->batch.wire_loops_uvs, &mbufcache->vbo.uv);
}
}
-
- /* Edit Mesh */
- if (DRW_batch_requested(cache->batch.edit_triangles, GPU_PRIM_TRIS)) {
- DRW_ibo_request(cache->batch.edit_triangles, &cache->ibo.edit_loops_tris);
- DRW_vbo_request(cache->batch.edit_triangles, &cache->edit.loop_pos_nor);
- DRW_vbo_request(cache->batch.edit_triangles, &cache->edit.loop_data);
- }
- if (DRW_batch_requested(cache->batch.edit_vertices, GPU_PRIM_POINTS)) {
- DRW_ibo_request(cache->batch.edit_vertices, &cache->ibo.edit_loops_points);
- DRW_vbo_request(cache->batch.edit_vertices, &cache->edit.loop_pos_nor);
- DRW_vbo_request(cache->batch.edit_vertices, &cache->edit.loop_data);
- }
- if (DRW_batch_requested(cache->batch.edit_edges, GPU_PRIM_LINES)) {
- DRW_ibo_request(cache->batch.edit_edges, &cache->ibo.edit_loops_lines);
- DRW_vbo_request(cache->batch.edit_edges, &cache->edit.loop_pos_nor);
- DRW_vbo_request(cache->batch.edit_edges, &cache->edit.loop_data);
- }
- if (DRW_batch_requested(cache->batch.edit_lnor, GPU_PRIM_POINTS)) {
- DRW_ibo_request(cache->batch.edit_lnor, &cache->ibo.edit_loops_tris);
- DRW_vbo_request(cache->batch.edit_lnor, &cache->edit.loop_pos_nor);
- DRW_vbo_request(cache->batch.edit_lnor, &cache->edit.loop_lnor);
- }
- if (DRW_batch_requested(cache->batch.edit_facedots, GPU_PRIM_POINTS)) {
- DRW_vbo_request(cache->batch.edit_facedots, &cache->edit.facedots_pos_nor_data);
- }
-
- /* Mesh Analysis */
if (DRW_batch_requested(cache->batch.edit_mesh_analysis, GPU_PRIM_TRIS)) {
- DRW_ibo_request(cache->batch.edit_mesh_analysis, &cache->ibo.edit_loops_tris);
- DRW_vbo_request(cache->batch.edit_mesh_analysis, &cache->edit.loop_pos_nor);
- DRW_vbo_request(cache->batch.edit_mesh_analysis, &cache->edit.loop_mesh_analysis);
- }
-
- /* Edit UV */
- if (DRW_batch_requested(cache->batch.edituv_faces, GPU_PRIM_TRI_FAN)) {
- DRW_ibo_request(cache->batch.edituv_faces, &cache->ibo.edituv_loops_tri_fans);
- DRW_vbo_request(cache->batch.edituv_faces, &cache->edit.loop_uv);
- DRW_vbo_request(cache->batch.edituv_faces, &cache->edit.loop_uv_data);
- }
- if (DRW_batch_requested(cache->batch.edituv_faces_strech_area, GPU_PRIM_TRI_FAN)) {
- DRW_ibo_request(cache->batch.edituv_faces_strech_area, &cache->ibo.edituv_loops_tri_fans);
- DRW_vbo_request(cache->batch.edituv_faces_strech_area, &cache->edit.loop_uv);
- DRW_vbo_request(cache->batch.edituv_faces_strech_area, &cache->edit.loop_uv_data);
- DRW_vbo_request(cache->batch.edituv_faces_strech_area, &cache->edit.loop_stretch_area);
- }
- if (DRW_batch_requested(cache->batch.edituv_faces_strech_angle, GPU_PRIM_TRI_FAN)) {
- DRW_ibo_request(cache->batch.edituv_faces_strech_angle, &cache->ibo.edituv_loops_tri_fans);
- DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &cache->edit.loop_uv);
- DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &cache->edit.loop_uv_data);
- DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &cache->edit.loop_stretch_angle);
- }
- if (DRW_batch_requested(cache->batch.edituv_edges, GPU_PRIM_LINES)) {
- DRW_ibo_request(cache->batch.edituv_edges, &cache->ibo.edituv_loops_line_strips);
- DRW_vbo_request(cache->batch.edituv_edges, &cache->edit.loop_uv);
- DRW_vbo_request(cache->batch.edituv_edges, &cache->edit.loop_uv_data);
- }
- if (DRW_batch_requested(cache->batch.edituv_verts, GPU_PRIM_POINTS)) {
- DRW_ibo_request(cache->batch.edituv_verts, &cache->ibo.edituv_loops_points);
- DRW_vbo_request(cache->batch.edituv_verts, &cache->edit.loop_uv);
- DRW_vbo_request(cache->batch.edituv_verts, &cache->edit.loop_uv_data);
- }
- if (DRW_batch_requested(cache->batch.edituv_facedots, GPU_PRIM_POINTS)) {
- DRW_vbo_request(cache->batch.edituv_facedots, &cache->edit.facedots_uv);
- DRW_vbo_request(cache->batch.edituv_facedots, &cache->edit.facedots_uv_data);
- }
-
- /* Selection */
- /* TODO reuse ordered.loop_pos_nor if possible. */
- if (DRW_batch_requested(cache->batch.edit_selection_verts, GPU_PRIM_POINTS)) {
- DRW_ibo_request(cache->batch.edit_selection_verts, &cache->ibo.edit_loops_points);
- DRW_vbo_request(cache->batch.edit_selection_verts, &cache->edit.loop_pos_nor);
- DRW_vbo_request(cache->batch.edit_selection_verts, &cache->edit.loop_vert_idx);
- }
- if (DRW_batch_requested(cache->batch.edit_selection_edges, GPU_PRIM_LINES)) {
- DRW_ibo_request(cache->batch.edit_selection_edges, &cache->ibo.edit_loops_lines);
- DRW_vbo_request(cache->batch.edit_selection_edges, &cache->edit.loop_pos_nor);
- DRW_vbo_request(cache->batch.edit_selection_edges, &cache->edit.loop_edge_idx);
- }
- if (DRW_batch_requested(cache->batch.edit_selection_faces, GPU_PRIM_TRIS)) {
- DRW_ibo_request(cache->batch.edit_selection_faces, &cache->ibo.edit_loops_tris);
- DRW_vbo_request(cache->batch.edit_selection_faces, &cache->edit.loop_pos_nor);
- DRW_vbo_request(cache->batch.edit_selection_faces, &cache->edit.loop_face_idx);
- }
- if (DRW_batch_requested(cache->batch.edit_selection_facedots, GPU_PRIM_POINTS)) {
- DRW_vbo_request(cache->batch.edit_selection_facedots, &cache->edit.facedots_pos_nor_data);
- DRW_vbo_request(cache->batch.edit_selection_facedots, &cache->edit.facedots_idx);
+ DRW_ibo_request(cache->batch.edit_mesh_analysis, &mbufcache->ibo.tris);
+ DRW_vbo_request(cache->batch.edit_mesh_analysis, &mbufcache->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.edit_mesh_analysis, &mbufcache->vbo.mesh_analysis);
}
/* Per Material */
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]);
- }
- else {
- DRW_ibo_request(cache->surf_per_mat[i], &cache->ibo.loops_tris);
+ if (DRW_batch_requested(cache->surface_per_mat[i], GPU_PRIM_TRIS)) {
+ DRW_ibo_request(cache->surface_per_mat[i], &mbufcache->ibo.tris);
+ /* Order matters. First ones override latest vbos' attribs. */
+ DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.lnor);
+ DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.pos_nor);
+ if (cache->cd_used.uv != 0) {
+ DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.uv);
}
- DRW_vbo_request(cache->surf_per_mat[i], &cache->ordered.loop_pos_nor);
- if ((cache->cd_used.uv != 0) || (cache->cd_used.tan != 0) ||
- (cache->cd_used.tan_orco != 0)) {
- DRW_vbo_request(cache->surf_per_mat[i], &cache->ordered.loop_uv_tan);
+ if ((cache->cd_used.tan != 0) || (cache->cd_used.tan_orco != 0)) {
+ DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.tan);
}
if (cache->cd_used.vcol != 0) {
- DRW_vbo_request(cache->surf_per_mat[i], &cache->ordered.loop_vcol);
+ DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.vcol);
}
if (cache->cd_used.orco != 0) {
- DRW_vbo_request(cache->surf_per_mat[i], &cache->ordered.loop_orco);
+ DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.orco);
}
}
}
-#ifdef DRW_DEBUG_MESH_CACHE_REQUEST
- printf("-- %s %s --\n", __func__, ob->id.name + 2);
-#endif
+ mbufcache = (do_cage) ? &cache->cage : &cache->final;
- /* Generate MeshRenderData flags */
- eMRDataType mr_flag = 0, mr_edit_flag = 0;
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_flag, cache->ordered.pos_nor, MR_DATATYPE_VERT /* A comment to wrap the line ;) */);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_flag, cache->ordered.weights, MR_DATATYPE_VERT | MR_DATATYPE_DVERT);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_flag, cache->ordered.loop_pos_nor, MR_DATATYPE_VERT_LOOP_POLY | MR_DATATYPE_LOOP_NORMALS);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_flag, cache->ordered.loop_uv_tan, MR_DATATYPE_VERT_LOOP_TRI_POLY | MR_DATATYPE_SHADING);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_flag, cache->ordered.loop_orco, MR_DATATYPE_VERT_LOOP_POLY | MR_DATATYPE_SHADING);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_flag, cache->ordered.loop_vcol, MR_DATATYPE_VERT_LOOP_POLY | MR_DATATYPE_SHADING);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_flag, cache->ordered.loop_edge_fac, MR_DATATYPE_VERT_LOOP_POLY | MR_DATATYPE_EDGE);
-
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_flag, cache->ibo.surf_tris, MR_DATATYPE_VERT_LOOP_POLY | MR_DATATYPE_LOOPTRI);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_flag, cache->ibo.loops_tris, MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_LOOPTRI);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_flag, cache->ibo.loops_lines, MR_DATATYPE_LOOP | MR_DATATYPE_EDGE | MR_DATATYPE_POLY);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag,
- cache->ibo.loops_lines_paint_mask,
- MR_DATATYPE_LOOP | MR_DATATYPE_EDGE | MR_DATATYPE_POLY);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_flag, cache->ibo.loops_line_strips, MR_DATATYPE_LOOP | MR_DATATYPE_POLY);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_flag, cache->ibo.edges_lines, MR_DATATYPE_VERT | MR_DATATYPE_EDGE);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_flag, cache->ibo.edges_adj_lines, MR_DATATYPE_VERT_LOOP_POLY | MR_DATATYPE_LOOPTRI);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_flag, cache->ibo.loose_edges_lines, MR_DATATYPE_VERT | MR_DATATYPE_EDGE);
- for (int i = 0; i < cache->mat_len; ++i) {
- int combined_flag = MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_LOOPTRI;
- DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->surf_per_mat_tris[i], combined_flag);
- }
-
- int combined_edit_flag = MR_DATATYPE_VERT_LOOP_POLY | MR_DATATYPE_EDGE |
- MR_DATATYPE_LOOSE_VERT_EGDE;
- int combined_edit_with_lnor_flag = combined_edit_flag | MR_DATATYPE_LOOP_NORMALS;
- int combined_edituv_flag = combined_edit_flag | MR_DATATYPE_LOOPUV;
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.loop_pos_nor, combined_edit_flag | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.loop_lnor, combined_edit_with_lnor_flag | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.loop_data, combined_edit_flag | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.loop_uv_data, combined_edit_flag | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.loop_uv, combined_edituv_flag | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.loop_stretch_angle, combined_edit_flag | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.loop_stretch_area, combined_edit_flag | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.loop_mesh_analysis, MR_DATATYPE_VERT_LOOP_POLY);
-
- DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_edit_flag, cache->edit.loop_vert_idx, combined_edit_flag);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_edit_flag, cache->edit.loop_edge_idx, combined_edit_flag);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_edit_flag, cache->edit.loop_face_idx, combined_edit_flag);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_edit_flag, cache->edit.facedots_idx, MR_DATATYPE_POLY);
-
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.facedots_pos_nor_data, MR_DATATYPE_POLY | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.facedots_uv, combined_edituv_flag | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_VBO_REQUEST(
- mr_edit_flag, cache->edit.facedots_uv_data, combined_edit_flag | MR_DATATYPE_OVERLAY);
-
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_edit_flag, cache->ibo.edituv_loops_points, combined_edit_flag | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_edit_flag, cache->ibo.edituv_loops_line_strips, combined_edit_flag | MR_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_edit_flag, cache->ibo.edituv_loops_tri_fans, combined_edit_flag | MR_DATATYPE_OVERLAY);
-
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_edit_flag, cache->ibo.edit_loops_points, combined_edit_flag | MR_DATATYPE_LOOPTRI);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_edit_flag, cache->ibo.edit_loops_lines, combined_edit_flag | MR_DATATYPE_LOOPTRI);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(
- mr_edit_flag, cache->ibo.edit_loops_tris, combined_edit_flag | MR_DATATYPE_LOOPTRI);
-
- Mesh *me_original = me;
- MBC_GET_FINAL_MESH(me);
-
-#ifdef DRW_DEBUG_MESH_CACHE_REQUEST
- printf(" mr_flag %u, mr_edit_flag %u\n\n", mr_flag, mr_edit_flag);
-#endif
-
- if (me_original == me) {
- mr_flag |= mr_edit_flag;
- }
-
- MeshRenderData *rdata = NULL;
-
- if (mr_flag != 0) {
- rdata = mesh_render_data_create_ex(me, mr_flag, &cache->cd_used, ts);
- }
-
- /* Generate VBOs */
- if (DRW_vbo_requested(cache->ordered.pos_nor)) {
- mesh_create_pos_and_nor(rdata, cache->ordered.pos_nor);
- }
- if (DRW_vbo_requested(cache->ordered.weights)) {
- mesh_create_weights(rdata, cache->ordered.weights, &cache->weight_state);
- }
- if (DRW_vbo_requested(cache->ordered.loop_pos_nor)) {
- mesh_create_loop_pos_and_nor(rdata, cache->ordered.loop_pos_nor);
- }
- if (DRW_vbo_requested(cache->ordered.loop_edge_fac)) {
- mesh_create_loop_edge_fac(rdata, cache->ordered.loop_edge_fac);
- }
- if (DRW_vbo_requested(cache->ordered.loop_uv_tan)) {
- mesh_create_loop_uv_and_tan(rdata, cache->ordered.loop_uv_tan);
- }
- if (DRW_vbo_requested(cache->ordered.loop_orco)) {
- mesh_create_loop_orco(rdata, cache->ordered.loop_orco);
- }
- if (DRW_vbo_requested(cache->ordered.loop_vcol)) {
- mesh_create_loop_vcol(rdata, cache->ordered.loop_vcol);
- }
- if (DRW_ibo_requested(cache->ibo.edges_lines)) {
- mesh_create_edges_lines(rdata, cache->ibo.edges_lines, use_hide);
- }
- if (DRW_ibo_requested(cache->ibo.edges_adj_lines)) {
- mesh_create_edges_adjacency_lines(
- rdata, cache->ibo.edges_adj_lines, &cache->is_manifold, use_hide);
- }
- if (DRW_ibo_requested(cache->ibo.loose_edges_lines)) {
- mesh_create_loose_edges_lines(
- rdata, cache->ibo.loose_edges_lines, &cache->no_loose_wire, use_hide);
- }
- if (DRW_ibo_requested(cache->ibo.surf_tris)) {
- mesh_create_surf_tris(rdata, cache->ibo.surf_tris, use_hide);
- }
- if (DRW_ibo_requested(cache->ibo.loops_lines)) {
- mesh_create_loops_lines(rdata, cache->ibo.loops_lines, use_hide);
- }
- if (DRW_ibo_requested(cache->ibo.loops_lines_paint_mask)) {
- mesh_create_loops_lines_paint_mask(rdata, cache->ibo.loops_lines_paint_mask);
+ /* Edit Mesh */
+ if (DRW_batch_requested(cache->batch.edit_triangles, GPU_PRIM_TRIS)) {
+ DRW_ibo_request(cache->batch.edit_triangles, &mbufcache->ibo.tris);
+ DRW_vbo_request(cache->batch.edit_triangles, &mbufcache->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.edit_triangles, &mbufcache->vbo.edit_data);
}
- if (DRW_ibo_requested(cache->ibo.loops_line_strips)) {
- mesh_create_loops_line_strips(rdata, cache->ibo.loops_line_strips, use_hide);
+ if (DRW_batch_requested(cache->batch.edit_vertices, GPU_PRIM_POINTS)) {
+ DRW_ibo_request(cache->batch.edit_vertices, &mbufcache->ibo.points);
+ DRW_vbo_request(cache->batch.edit_vertices, &mbufcache->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.edit_vertices, &mbufcache->vbo.edit_data);
}
- if (DRW_ibo_requested(cache->ibo.loops_tris)) {
- mesh_create_loops_tris(rdata, &cache->ibo.loops_tris, 1, use_hide);
+ if (DRW_batch_requested(cache->batch.edit_edges, GPU_PRIM_LINES)) {
+ DRW_ibo_request(cache->batch.edit_edges, &mbufcache->ibo.lines);
+ DRW_vbo_request(cache->batch.edit_edges, &mbufcache->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.edit_edges, &mbufcache->vbo.edit_data);
}
- if (DRW_ibo_requested(cache->surf_per_mat_tris[0])) {
- mesh_create_loops_tris(rdata, cache->surf_per_mat_tris, cache->mat_len, use_hide);
+ if (DRW_batch_requested(cache->batch.edit_vnor, GPU_PRIM_POINTS)) {
+ DRW_ibo_request(cache->batch.edit_vnor, &mbufcache->ibo.points);
+ DRW_vbo_request(cache->batch.edit_vnor, &mbufcache->vbo.pos_nor);
}
-
- /* Use original Mesh* to have the correct edit cage. */
- if (me_original != me && mr_edit_flag != 0) {
- if (rdata) {
- mesh_render_data_free(rdata);
- }
- rdata = mesh_render_data_create_ex(me_original, mr_edit_flag, NULL, ts);
+ if (DRW_batch_requested(cache->batch.edit_lnor, GPU_PRIM_POINTS)) {
+ DRW_ibo_request(cache->batch.edit_lnor, &mbufcache->ibo.tris);
+ DRW_vbo_request(cache->batch.edit_lnor, &mbufcache->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.edit_lnor, &mbufcache->vbo.lnor);
}
-
- if (rdata && rdata->mapped.supported) {
- rdata->mapped.use = true;
+ if (DRW_batch_requested(cache->batch.edit_fdots, GPU_PRIM_POINTS)) {
+ DRW_ibo_request(cache->batch.edit_fdots, &mbufcache->ibo.fdots);
+ DRW_vbo_request(cache->batch.edit_fdots, &mbufcache->vbo.fdots_pos);
+ DRW_vbo_request(cache->batch.edit_fdots, &mbufcache->vbo.fdots_nor);
}
- if (DRW_vbo_requested(cache->edit.loop_pos_nor) || DRW_vbo_requested(cache->edit.loop_lnor) ||
- DRW_vbo_requested(cache->edit.loop_data) || DRW_vbo_requested(cache->edit.loop_vert_idx) ||
- DRW_vbo_requested(cache->edit.loop_edge_idx) ||
- DRW_vbo_requested(cache->edit.loop_face_idx)) {
- mesh_create_edit_vertex_loops(rdata,
- cache->edit.loop_pos_nor,
- cache->edit.loop_lnor,
- NULL,
- cache->edit.loop_data,
- cache->edit.loop_vert_idx,
- cache->edit.loop_edge_idx,
- cache->edit.loop_face_idx);
- }
- if (DRW_vbo_requested(cache->edit.facedots_pos_nor_data)) {
- Scene *scene = DRW_context_state_get()->scene;
- mesh_create_edit_facedots(rdata, cache->edit.facedots_pos_nor_data, scene, ob);
- }
- if (DRW_vbo_requested(cache->edit.facedots_idx)) {
- Scene *scene = DRW_context_state_get()->scene;
- mesh_create_edit_facedots_select_id(rdata, cache->edit.facedots_idx, scene, ob);
+ /* Selection */
+ if (DRW_batch_requested(cache->batch.edit_selection_verts, GPU_PRIM_POINTS)) {
+ DRW_ibo_request(cache->batch.edit_selection_verts, &mbufcache->ibo.points);
+ DRW_vbo_request(cache->batch.edit_selection_verts, &mbufcache->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.edit_selection_verts, &mbufcache->vbo.vert_idx);
}
- if (DRW_ibo_requested(cache->ibo.edit_loops_points) ||
- DRW_ibo_requested(cache->ibo.edit_loops_lines)) {
- mesh_create_edit_loops_points_lines(
- rdata, cache->ibo.edit_loops_points, cache->ibo.edit_loops_lines);
+ if (DRW_batch_requested(cache->batch.edit_selection_edges, GPU_PRIM_LINES)) {
+ DRW_ibo_request(cache->batch.edit_selection_edges, &mbufcache->ibo.lines);
+ DRW_vbo_request(cache->batch.edit_selection_edges, &mbufcache->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.edit_selection_edges, &mbufcache->vbo.edge_idx);
}
- if (DRW_ibo_requested(cache->ibo.edit_loops_tris)) {
- mesh_create_edit_loops_tris(rdata, cache->ibo.edit_loops_tris);
+ if (DRW_batch_requested(cache->batch.edit_selection_faces, GPU_PRIM_TRIS)) {
+ DRW_ibo_request(cache->batch.edit_selection_faces, &mbufcache->ibo.tris);
+ DRW_vbo_request(cache->batch.edit_selection_faces, &mbufcache->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.edit_selection_faces, &mbufcache->vbo.poly_idx);
}
- if (DRW_vbo_requested(cache->edit.loop_mesh_analysis)) {
- mesh_create_edit_mesh_analysis(rdata, cache->edit.loop_mesh_analysis);
+ if (DRW_batch_requested(cache->batch.edit_selection_fdots, GPU_PRIM_POINTS)) {
+ DRW_ibo_request(cache->batch.edit_selection_fdots, &mbufcache->ibo.fdots);
+ DRW_vbo_request(cache->batch.edit_selection_fdots, &mbufcache->vbo.fdots_pos);
+ DRW_vbo_request(cache->batch.edit_selection_fdots, &mbufcache->vbo.fdot_idx);
}
- /* UV editor */
/**
* TODO: The code and data structure is ready to support modified UV display
* but the selection code for UVs needs to support it first. So for now, only
* display the cage in all cases.
*/
- if (rdata && rdata->mapped.supported) {
- rdata->mapped.use = false;
- }
+ mbufcache = (do_uvcage) ? &cache->uv_cage : &cache->final;
- if (DRW_vbo_requested(cache->edit.loop_uv_data) || DRW_vbo_requested(cache->edit.loop_uv)) {
- mesh_create_edit_vertex_loops(
- rdata, NULL, NULL, cache->edit.loop_uv, cache->edit.loop_uv_data, NULL, NULL, NULL);
+ /* Edit UV */
+ if (DRW_batch_requested(cache->batch.edituv_faces, GPU_PRIM_TRIS)) {
+ DRW_ibo_request(cache->batch.edituv_faces, &mbufcache->ibo.edituv_tris);
+ 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_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_vbo_requested(cache->edit.loop_stretch_angle) ||
- DRW_vbo_requested(cache->edit.loop_stretch_area) ||
- DRW_vbo_requested(cache->edit.facedots_uv) ||
- DRW_vbo_requested(cache->edit.facedots_uv_data) ||
- DRW_ibo_requested(cache->ibo.edituv_loops_points) ||
- DRW_ibo_requested(cache->ibo.edituv_loops_line_strips) ||
- DRW_ibo_requested(cache->ibo.edituv_loops_tri_fans)) {
- mesh_create_uvedit_buffers(rdata,
- cache->edit.loop_stretch_area,
- cache->edit.loop_stretch_angle,
- cache->edit.facedots_uv,
- cache->edit.facedots_uv_data,
- cache->ibo.edituv_loops_points,
- cache->ibo.edituv_loops_line_strips,
- cache->ibo.edituv_loops_tri_fans);
+ if (DRW_batch_requested(cache->batch.edituv_edges, GPU_PRIM_LINES)) {
+ DRW_ibo_request(cache->batch.edituv_edges, &mbufcache->ibo.edituv_lines);
+ DRW_vbo_request(cache->batch.edituv_edges, &mbufcache->vbo.uv);
+ DRW_vbo_request(cache->batch.edituv_edges, &mbufcache->vbo.edituv_data);
+ }
+ if (DRW_batch_requested(cache->batch.edituv_verts, GPU_PRIM_POINTS)) {
+ DRW_ibo_request(cache->batch.edituv_verts, &mbufcache->ibo.edituv_points);
+ DRW_vbo_request(cache->batch.edituv_verts, &mbufcache->vbo.uv);
+ DRW_vbo_request(cache->batch.edituv_verts, &mbufcache->vbo.edituv_data);
}
+ if (DRW_batch_requested(cache->batch.edituv_fdots, GPU_PRIM_POINTS)) {
+ DRW_ibo_request(cache->batch.edituv_fdots, &mbufcache->ibo.edituv_fdots);
+ DRW_vbo_request(cache->batch.edituv_fdots, &mbufcache->vbo.fdots_uv);
+ DRW_vbo_request(cache->batch.edituv_fdots, &mbufcache->vbo.fdots_edituv_data);
+ }
+
+ /* Meh loose Scene const correctness here. */
+ const bool use_subsurf_fdots = scene ? modifiers_usesSubsurfFacedots((Scene *)scene, ob) : false;
- if (rdata) {
- mesh_render_data_free(rdata);
+ if (do_uvcage) {
+ mesh_buffer_cache_create_requested(
+ cache, cache->uv_cage, me, false, true, false, &cache->cd_used, ts, true);
}
+ if (do_cage) {
+ mesh_buffer_cache_create_requested(
+ cache, cache->cage, me, false, false, use_subsurf_fdots, &cache->cd_used, ts, true);
+ }
+
+ mesh_buffer_cache_create_requested(
+ cache, cache->final, me, true, false, use_subsurf_fdots, &cache->cd_used, ts, use_hide);
+
#ifdef DEBUG
check:
/* Make sure all requested batches have been setup. */
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) {
+ BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->final.vbo)[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) {
+ BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->cage.vbo)[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) {
+ BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->uv_cage.vbo)[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_hair.c b/source/blender/draw/intern/draw_hair.c
index fa1f1f2aab4..44ed01c47aa 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.c
@@ -253,7 +253,7 @@ void DRW_hair_update(void)
* On some system it crashes (see T58489) and on some other it renders garbage (see T60171).
*
* So instead of using transform feedback we render to a texture,
- * readback the result to system memory and reupload as VBO data.
+ * read back the result to system memory and re-upload as VBO data.
* It is really not ideal performance wise, but it is the simplest
* and the most local workaround that still uses the power of the GPU.
*/
diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c
index 802f49d6549..8f26cc72a02 100644
--- a/source/blender/draw/intern/draw_instance_data.c
+++ b/source/blender/draw/intern/draw_instance_data.c
@@ -23,7 +23,7 @@
/**
* DRW Instance Data Manager
* This is a special memory manager that keeps memory blocks ready to send as vbo data in one
- * continuous allocation. This way we avoid feeding gawain each instance data one by one and
+ * continuous allocation. This way we avoid feeding #GPUBatch each instance data one by one and
* unnecessary memcpy. Since we loose which memory block was used each #DRWShadingGroup we need to
* redistribute them in the same order/size to avoid to realloc each frame. This is why
* #DRWInstanceDatas are sorted in a list for each different data size.
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 070713ad404..72fcb9ac968 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -1725,9 +1725,9 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
if (G.debug_value > 20 && G.debug_value < 30) {
GPU_depth_test(false);
- rcti rect; /* local coordinate visible rect inside region, to accommodate overlapping ui */
- ED_region_visible_rect(DST.draw_ctx.ar, &rect);
- DRW_stats_draw(&rect);
+ /* local coordinate visible rect inside region, to accommodate overlapping ui */
+ const rcti *rect = ED_region_visible_rect(DST.draw_ctx.ar);
+ DRW_stats_draw(rect);
GPU_depth_test(true);
}
@@ -1864,7 +1864,7 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph
DRW_opengl_render_context_enable(re_gl_context);
/* We need to query gpu context after a gl context has been bound. */
re_gpu_context = RE_gpu_context_get(render);
- DRW_gawain_render_context_enable(re_gpu_context);
+ DRW_gpu_render_context_enable(re_gpu_context);
}
else {
DRW_opengl_context_enable();
@@ -1949,13 +1949,13 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
DRW_opengl_render_context_enable(re_gl_context);
/* We need to query gpu context after a gl context has been bound. */
re_gpu_context = RE_gpu_context_get(render);
- DRW_gawain_render_context_enable(re_gpu_context);
+ DRW_gpu_render_context_enable(re_gpu_context);
}
else {
DRW_opengl_context_enable();
}
- /* IMPORTANT: We dont support immediate mode in render mode!
+ /* IMPORTANT: We don't support immediate mode in render mode!
* This shall remain in effect until immediate mode supports
* multiple threads. */
@@ -2040,7 +2040,7 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
/* Changing Context */
if (re_gl_context != NULL) {
- DRW_gawain_render_context_disable(re_gpu_context);
+ DRW_gpu_render_context_disable(re_gpu_context);
DRW_opengl_render_context_disable(re_gl_context);
}
else {
@@ -2555,23 +2555,13 @@ void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph,
DRW_opengl_context_disable();
}
-void DRW_draw_select_id(Depsgraph *depsgraph,
- ARegion *ar,
- View3D *v3d,
- Base **bases,
- const uint bases_len,
- short select_mode)
+void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *ar, View3D *v3d, const rcti *rect)
{
Scene *scene = DEG_get_evaluated_scene(depsgraph);
ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
- DRW_select_buffer_context_create(bases, bases_len, select_mode);
-
- DRW_opengl_context_enable();
-
/* Reset before using it. */
drw_state_prepare_clean_for_draw(&DST);
- DST.buffer_finish_called = true;
/* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */
DST.draw_ctx = (DRWContextState){
@@ -2584,7 +2574,6 @@ void DRW_draw_select_id(Depsgraph *depsgraph,
.depsgraph = depsgraph,
};
- use_drw_engine(&draw_engine_select_type);
drw_context_state_init();
/* Setup viewport */
@@ -2594,20 +2583,24 @@ void DRW_draw_select_id(Depsgraph *depsgraph,
/* Update ubos */
DRW_globals_update();
- /* Init engines */
- drw_engines_init();
+ /* Init Select Engine */
+ struct SELECTID_Context *sel_ctx = DRW_select_engine_context_get();
+ sel_ctx->last_rect = *rect;
+ use_drw_engine(&draw_engine_select_type);
+ drw_engines_init();
{
drw_engines_cache_init();
- /* Keep `base_index` in sync with `e_data.context.last_base_drawn`.
- * So don't skip objects. */
- for (uint base_index = 0; base_index < bases_len; base_index++) {
- Object *obj_eval = DEG_get_evaluated_object(depsgraph, bases[base_index]->object);
+ Object **obj = &sel_ctx->objects[0];
+ for (uint remaining = sel_ctx->objects_len; remaining--; obj++) {
+ Object *obj_eval = DEG_get_evaluated_object(depsgraph, *obj);
drw_engines_cache_populate(obj_eval);
}
drw_engines_cache_finish();
+
+ DRW_render_instance_buffer_finish();
}
/* Start Drawing */
@@ -2617,14 +2610,12 @@ void DRW_draw_select_id(Depsgraph *depsgraph,
drw_engines_disable();
+ drw_viewport_cache_resize();
+
#ifdef DEBUG
/* Avoid accidental reuse. */
drw_state_ensure_not_reused(&DST);
#endif
-
- /* Changin context */
- GPU_framebuffer_restore();
- DRW_opengl_context_disable();
}
/** See #DRW_shgroup_world_clip_planes_from_rv3d. */
@@ -2932,7 +2923,7 @@ void DRW_opengl_context_create(void)
/* This changes the active context. */
DST.gl_context = WM_opengl_context_create();
WM_opengl_context_activate(DST.gl_context);
- /* Be sure to create gawain.context too. */
+ /* Be sure to create gpu_context too. */
DST.gpu_context = GPU_context_create(0);
if (!G.background) {
immActivate();
@@ -3031,7 +3022,7 @@ void DRW_opengl_render_context_disable(void *re_gl_context)
}
/* Needs to be called AFTER DRW_opengl_render_context_enable() */
-void DRW_gawain_render_context_enable(void *re_gpu_context)
+void DRW_gpu_render_context_enable(void *re_gpu_context)
{
/* If thread is main you should use DRW_opengl_context_enable(). */
BLI_assert(!BLI_thread_is_main());
@@ -3041,7 +3032,7 @@ void DRW_gawain_render_context_enable(void *re_gpu_context)
}
/* Needs to be called BEFORE DRW_opengl_render_context_disable() */
-void DRW_gawain_render_context_disable(void *UNUSED(re_gpu_context))
+void DRW_gpu_render_context_disable(void *UNUSED(re_gpu_context))
{
DRW_shape_cache_reset(); /* XXX fix that too. */
GPU_context_active_set(NULL);
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index 949d3e1d38b..09bf12dba7b 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -22,6 +22,7 @@
#include "draw_manager.h"
+#include "BLI_math.h"
#include "BLI_math_bits.h"
#include "BLI_memblock.h"
@@ -488,6 +489,26 @@ bool DRW_culling_plane_test(const DRWView *view, const float plane[4])
return draw_culling_plane_test(&view->frustum_corners, plane);
}
+/* Return True if the given box intersect the current view frustum.
+ * This function will have to be replaced when world space bb per objects is implemented. */
+bool DRW_culling_min_max_test(const DRWView *view, float obmat[4][4], float min[3], float max[3])
+{
+ view = view ? view : DST.view_default;
+ float tobmat[4][4];
+ transpose_m4_m4(tobmat, obmat);
+ for (int i = 6; i--;) {
+ float frustum_plane_local[4], bb_near[3], bb_far[3];
+ mul_v4_m4v4(frustum_plane_local, tobmat, view->frustum_planes[i]);
+ aabb_get_near_far_from_plane(frustum_plane_local, min, max, bb_near, bb_far);
+
+ if (plane_point_side_v3(frustum_plane_local, bb_far) < 0.0f) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
void DRW_culling_frustum_corners_get(const DRWView *view, BoundBox *corners)
{
view = view ? view : DST.view_default;
@@ -601,12 +622,12 @@ BLI_INLINE void draw_geometry_execute(DRWShadingGroup *shgroup,
GPU_batch_bind(geom);
}
- /* XXX hacking gawain. we don't want to call glUseProgram! (huge performance loss) */
+ /* 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 gawain */
+ geom->program_in_use = false; /* XXX hacking #GPUBatch */
}
enum {
diff --git a/source/blender/draw/intern/draw_manager_profiling.c b/source/blender/draw/intern/draw_manager_profiling.c
index 5e21e5e576c..bab69cf7a57 100644
--- a/source/blender/draw/intern/draw_manager_profiling.c
+++ b/source/blender/draw/intern/draw_manager_profiling.c
@@ -200,7 +200,7 @@ void DRW_stats_reset(void)
}
}
-static void draw_stat_5row(rcti *rect, int u, int v, const char *txt, const int size)
+static void draw_stat_5row(const rcti *rect, int u, int v, const char *txt, const int size)
{
BLF_draw_default_ascii(rect->xmin + (1 + u * 5) * U.widget_unit,
rect->ymax - (3 + v) * U.widget_unit,
@@ -209,13 +209,13 @@ static void draw_stat_5row(rcti *rect, int u, int v, const char *txt, const int
size);
}
-static void draw_stat(rcti *rect, int u, int v, const char *txt, const int size)
+static void draw_stat(const rcti *rect, int u, int v, const char *txt, const int size)
{
BLF_draw_default_ascii(
rect->xmin + (1 + u) * U.widget_unit, rect->ymax - (3 + v) * U.widget_unit, 0.0f, txt, size);
}
-void DRW_stats_draw(rcti *rect)
+void DRW_stats_draw(const rcti *rect)
{
char stat_string[64];
int lvl_index[MAX_NESTED_TIMER];
diff --git a/source/blender/draw/intern/draw_manager_profiling.h b/source/blender/draw/intern/draw_manager_profiling.h
index 7fe2280f9b2..3da6a4c8b1c 100644
--- a/source/blender/draw/intern/draw_manager_profiling.h
+++ b/source/blender/draw/intern/draw_manager_profiling.h
@@ -35,6 +35,6 @@ void DRW_stats_group_end(void);
void DRW_stats_query_start(const char *name);
void DRW_stats_query_end(void);
-void DRW_stats_draw(rcti *rect);
+void DRW_stats_draw(const rcti *rect);
#endif /* __DRAW_MANAGER_PROFILING_H__ */
diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c
index d0aa6d55c03..9c34cdbac3b 100644
--- a/source/blender/draw/intern/draw_manager_shader.c
+++ b/source/blender/draw/intern/draw_manager_shader.c
@@ -178,7 +178,7 @@ static void drw_deferred_shader_compilation_free(void *custom_data)
static void drw_deferred_shader_add(GPUMaterial *mat, bool deferred)
{
- /* Do not deferre the compilation if we are rendering for image.
+ /* Do not defer the compilation if we are rendering for image.
* deferred rendering is only possible when `evil_C` is available */
if (DST.draw_ctx.evil_C == NULL || DRW_state_is_image_render() || !USE_DEFERRED_COMPILATION ||
!deferred) {
diff --git a/source/blender/draw/engines/select/select_buffer.c b/source/blender/draw/intern/draw_select_buffer.c
index b184992cb56..974ea22ccea 100644
--- a/source/blender/draw/engines/select/select_buffer.c
+++ b/source/blender/draw/intern/draw_select_buffer.c
@@ -32,59 +32,81 @@
#include "GPU_select.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "DRW_engine.h"
#include "DRW_select_buffer.h"
-#include "select_private.h"
-#include "select_engine.h"
+#include "draw_manager.h"
+
+#include "../engines/select/select_engine.h"
/* -------------------------------------------------------------------- */
/** \name Buffer of select ID's
* \{ */
-/* Read a block of pixels from the select frame buffer. */
-uint *DRW_select_buffer_read(const rcti *rect, uint *r_buf_len)
+/* Main function to read a block of pixels from the select frame buffer. */
+uint *DRW_select_buffer_read(struct Depsgraph *depsgraph,
+ struct ARegion *ar,
+ struct View3D *v3d,
+ const rcti *rect,
+ uint *r_buf_len)
{
- struct SELECTID_Context *select_ctx = select_context_get();
+ uint *r_buf = NULL;
+ uint buf_len = 0;
- /* clamp rect by texture */
+ /* Clamp rect. */
rcti r = {
.xmin = 0,
- .xmax = GPU_texture_width(select_ctx->texture_u32),
+ .xmax = ar->winx,
.ymin = 0,
- .ymax = GPU_texture_height(select_ctx->texture_u32),
+ .ymax = ar->winy,
};
+ /* Make sure that the rect is within the bounds of the viewport.
+ * Some GPUs have problems reading pixels off limits. */
rcti rect_clamp = *rect;
if (BLI_rcti_isect(&r, &rect_clamp, &rect_clamp)) {
- uint buf_len = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
- uint *r_buf = MEM_mallocN(buf_len * sizeof(*r_buf), __func__);
+ struct SELECTID_Context *select_ctx = DRW_select_engine_context_get();
DRW_opengl_context_enable();
- GPU_framebuffer_bind(select_ctx->framebuffer_select_id);
- glReadBuffer(GL_COLOR_ATTACHMENT0);
- glReadPixels(rect_clamp.xmin,
- rect_clamp.ymin,
- BLI_rcti_size_x(&rect_clamp),
- BLI_rcti_size_y(&rect_clamp),
- GL_RED_INTEGER,
- GL_UNSIGNED_INT,
- r_buf);
+ /* Update the drawing. */
+ DRW_draw_select_id(depsgraph, ar, v3d, rect);
+
+ if (select_ctx->index_drawn_len > 1) {
+ BLI_assert(ar->winx == GPU_texture_width(select_ctx->texture_u32) &&
+ ar->winy == GPU_texture_height(select_ctx->texture_u32));
+
+ /* Read the UI32 pixels. */
+ buf_len = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
+ r_buf = MEM_mallocN(buf_len * sizeof(*r_buf), __func__);
+
+ GPU_framebuffer_bind(select_ctx->framebuffer_select_id);
+ glReadBuffer(GL_COLOR_ATTACHMENT0);
+ glReadPixels(rect_clamp.xmin,
+ rect_clamp.ymin,
+ BLI_rcti_size_x(&rect_clamp),
+ BLI_rcti_size_y(&rect_clamp),
+ GL_RED_INTEGER,
+ GL_UNSIGNED_INT,
+ r_buf);
+
+ if (!BLI_rcti_compare(rect, &rect_clamp)) {
+ /* The rect has been clamped so you need to realign the buffer and fill in the blanks */
+ GPU_select_buffer_stride_realign(rect, &rect_clamp, r_buf);
+ }
+ }
GPU_framebuffer_restore();
DRW_opengl_context_disable();
+ }
- if (!BLI_rcti_compare(rect, &rect_clamp)) {
- GPU_select_buffer_stride_realign(rect, &rect_clamp, r_buf);
- }
-
- if (r_buf_len) {
- *r_buf_len = buf_len;
- }
-
- return r_buf;
+ if (r_buf_len) {
+ *r_buf_len = buf_len;
}
- return NULL;
+
+ return r_buf;
}
/** \} */
@@ -102,25 +124,27 @@ uint *DRW_select_buffer_read(const rcti *rect, uint *r_buf_len)
* \param mask: Specifies the rect pixels (optional).
* \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure.
*/
-uint *DRW_select_buffer_bitmap_from_rect(const rcti *rect, uint *r_bitmap_len)
+uint *DRW_select_buffer_bitmap_from_rect(struct Depsgraph *depsgraph,
+ struct ARegion *ar,
+ struct View3D *v3d,
+ const rcti *rect,
+ uint *r_bitmap_len)
{
- struct SELECTID_Context *select_ctx = select_context_get();
-
- const uint bitmap_len = select_ctx->last_index_drawn;
- if (bitmap_len == 0) {
- return NULL;
- }
+ struct SELECTID_Context *select_ctx = DRW_select_engine_context_get();
rcti rect_px = *rect;
rect_px.xmax += 1;
rect_px.ymax += 1;
uint buf_len;
- uint *buf = DRW_select_buffer_read(&rect_px, &buf_len);
+ uint *buf = DRW_select_buffer_read(depsgraph, ar, v3d, &rect_px, &buf_len);
if (buf == NULL) {
return NULL;
}
+ BLI_assert(select_ctx->index_drawn_len > 0);
+ const uint bitmap_len = select_ctx->index_drawn_len - 1;
+
BLI_bitmap *bitmap_buf = BLI_BITMAP_NEW(bitmap_len, __func__);
const uint *buf_iter = buf;
while (buf_len--) {
@@ -145,16 +169,14 @@ uint *DRW_select_buffer_bitmap_from_rect(const rcti *rect, uint *r_bitmap_len)
* \param radius: Circle radius.
* \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure.
*/
-uint *DRW_select_buffer_bitmap_from_circle(const int center[2],
+uint *DRW_select_buffer_bitmap_from_circle(struct Depsgraph *depsgraph,
+ struct ARegion *ar,
+ struct View3D *v3d,
+ const int center[2],
const int radius,
uint *r_bitmap_len)
{
- struct SELECTID_Context *select_ctx = select_context_get();
-
- const uint bitmap_len = select_ctx->last_index_drawn;
- if (bitmap_len == 0) {
- return NULL;
- }
+ struct SELECTID_Context *select_ctx = DRW_select_engine_context_get();
const rcti rect = {
.xmin = center[0] - radius,
@@ -163,15 +185,17 @@ uint *DRW_select_buffer_bitmap_from_circle(const int center[2],
.ymax = center[1] + radius + 1,
};
- const uint *buf = DRW_select_buffer_read(&rect, NULL);
+ const uint *buf = DRW_select_buffer_read(depsgraph, ar, v3d, &rect, NULL);
if (buf == NULL) {
return NULL;
}
- const uint *buf_iter = buf;
+ BLI_assert(select_ctx->index_drawn_len > 0);
+ const uint bitmap_len = select_ctx->index_drawn_len - 1;
BLI_bitmap *bitmap_buf = BLI_BITMAP_NEW(bitmap_len, __func__);
+ const uint *buf_iter = buf;
const int radius_sq = radius * radius;
for (int yc = -radius; yc <= radius; yc++) {
for (int xc = -radius; xc <= radius; xc++, buf_iter++) {
@@ -215,21 +239,22 @@ static void drw_select_mask_px_cb(int x, int x_end, int y, void *user_data)
* \param rect: Polygon boundaries.
* \returns a #BLI_bitmap.
*/
-uint *DRW_select_buffer_bitmap_from_poly(const int poly[][2], const int poly_len, const rcti *rect)
+uint *DRW_select_buffer_bitmap_from_poly(struct Depsgraph *depsgraph,
+ struct ARegion *ar,
+ struct View3D *v3d,
+ const int poly[][2],
+ const int poly_len,
+ const rcti *rect,
+ uint *r_bitmap_len)
{
- struct SELECTID_Context *select_ctx = select_context_get();
-
- const uint bitmap_len = select_ctx->last_index_drawn;
- if (bitmap_len == 0) {
- return NULL;
- }
+ struct SELECTID_Context *select_ctx = DRW_select_engine_context_get();
rcti rect_px = *rect;
rect_px.xmax += 1;
rect_px.ymax += 1;
uint buf_len;
- uint *buf = DRW_select_buffer_read(&rect_px, &buf_len);
+ uint *buf = DRW_select_buffer_read(depsgraph, ar, v3d, &rect_px, &buf_len);
if (buf == NULL) {
return NULL;
}
@@ -249,6 +274,9 @@ uint *DRW_select_buffer_bitmap_from_poly(const int poly[][2], const int poly_len
drw_select_mask_px_cb,
&poly_mask_data);
+ BLI_assert(select_ctx->index_drawn_len > 0);
+ const uint bitmap_len = select_ctx->index_drawn_len - 1;
+
BLI_bitmap *bitmap_buf = BLI_BITMAP_NEW(bitmap_len, __func__);
const uint *buf_iter = buf;
int i = 0;
@@ -263,6 +291,10 @@ uint *DRW_select_buffer_bitmap_from_poly(const int poly[][2], const int poly_len
MEM_freeN((void *)buf);
MEM_freeN(buf_mask);
+ if (r_bitmap_len) {
+ *r_bitmap_len = bitmap_len;
+ }
+
return bitmap_buf;
}
@@ -278,8 +310,13 @@ uint *DRW_select_buffer_bitmap_from_poly(const int poly[][2], const int poly_len
/**
* Samples a single pixel.
*/
-uint DRW_select_buffer_sample_point(const int center[2])
+uint DRW_select_buffer_sample_point(struct Depsgraph *depsgraph,
+ struct ARegion *ar,
+ struct View3D *v3d,
+ const int center[2])
{
+ uint ret = 0;
+
const rcti rect = {
.xmin = center[0],
.xmax = center[0] + 1,
@@ -288,10 +325,13 @@ uint DRW_select_buffer_sample_point(const int center[2])
};
uint buf_len;
- uint *buf = DRW_select_buffer_read(&rect, &buf_len);
- BLI_assert(0 != buf_len);
- uint ret = buf[0];
- MEM_freeN(buf);
+ uint *buf = DRW_select_buffer_read(depsgraph, ar, v3d, &rect, &buf_len);
+ if (buf) {
+ BLI_assert(0 != buf_len);
+ ret = buf[0];
+ MEM_freeN(buf);
+ }
+
return ret;
}
@@ -300,7 +340,10 @@ uint DRW_select_buffer_sample_point(const int center[2])
* \param dist[in,out]: Use to initialize the distance,
* when found, this value is set to the distance of the selection that's returned.
*/
-uint DRW_select_buffer_find_nearest_to_point(const int center[2],
+uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph,
+ struct ARegion *ar,
+ struct View3D *v3d,
+ const int center[2],
const uint id_min,
const uint id_max,
uint *dist)
@@ -325,7 +368,7 @@ uint DRW_select_buffer_find_nearest_to_point(const int center[2],
/* Read from selection framebuffer. */
uint buf_len;
- const uint *buf = DRW_select_buffer_read(&rect, &buf_len);
+ const uint *buf = DRW_select_buffer_read(depsgraph, ar, v3d, &rect, &buf_len);
if (buf == NULL) {
return index;
@@ -399,14 +442,14 @@ bool DRW_select_buffer_elem_get(const uint sel_id,
uint *r_base_index,
char *r_elem_type)
{
- struct SELECTID_Context *select_ctx = select_context_get();
+ struct SELECTID_Context *select_ctx = DRW_select_engine_context_get();
char elem_type = 0;
- uint elem_id;
+ uint elem_id = 0;
uint base_index = 0;
- for (; base_index < select_ctx->objects_len; base_index++) {
- struct BaseOffset *base_ofs = &select_ctx->index_offsets[base_index];
+ for (; base_index < select_ctx->objects_drawn_len; base_index++) {
+ struct ObjectOffsets *base_ofs = &select_ctx->index_offsets[base_index];
if (base_ofs->face > sel_id) {
elem_id = sel_id - base_ofs->face_start;
@@ -425,14 +468,15 @@ bool DRW_select_buffer_elem_get(const uint sel_id,
}
}
- if (base_index == select_ctx->objects_len) {
+ if (base_index == select_ctx->objects_drawn_len) {
return false;
}
*r_elem = elem_id;
if (r_base_index) {
- *r_base_index = base_index;
+ Object *obj_orig = DEG_get_original_object(select_ctx->objects_drawn[base_index]);
+ *r_base_index = obj_orig->runtime.select_id;
}
if (r_elem_type) {
@@ -442,19 +486,31 @@ bool DRW_select_buffer_elem_get(const uint sel_id,
return true;
}
-uint DRW_select_buffer_context_offset_for_object_elem(const uint base_index, char elem_type)
+uint DRW_select_buffer_context_offset_for_object_elem(Depsgraph *depsgraph,
+ Object *object,
+ char elem_type)
{
- struct SELECTID_Context *select_ctx = select_context_get();
- struct BaseOffset *base_ofs = &select_ctx->index_offsets[base_index];
+ struct SELECTID_Context *select_ctx = DRW_select_engine_context_get();
+
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, object);
+
+ SELECTID_ObjectData *sel_data = (SELECTID_ObjectData *)DRW_drawdata_get(
+ &ob_eval->id, &draw_engine_select_type);
+
+ if (!sel_data || !sel_data->is_drawn) {
+ return 0;
+ }
+
+ struct ObjectOffsets *base_ofs = &select_ctx->index_offsets[sel_data->drawn_index];
if (elem_type == SCE_SELECT_VERTEX) {
- return base_ofs->vert_start - 1;
+ return base_ofs->vert_start;
}
if (elem_type == SCE_SELECT_EDGE) {
- return base_ofs->edge_start - 1;
+ return base_ofs->edge_start;
}
if (elem_type == SCE_SELECT_FACE) {
- return base_ofs->face_start - 1;
+ return base_ofs->face_start;
}
BLI_assert(0);
return 0;
@@ -466,35 +522,29 @@ uint DRW_select_buffer_context_offset_for_object_elem(const uint base_index, cha
/** \name Context
* \{ */
-void DRW_select_buffer_context_create(Base **UNUSED(bases),
- const uint bases_len,
- short select_mode)
+void DRW_select_buffer_context_create(Base **bases, const uint bases_len, short select_mode)
{
- struct SELECTID_Context *select_ctx = select_context_get();
+ struct SELECTID_Context *select_ctx = DRW_select_engine_context_get();
- select_ctx->select_mode = select_mode;
- select_ctx->objects_len = bases_len;
+ select_ctx->objects = MEM_reallocN(select_ctx->objects,
+ sizeof(*select_ctx->objects) * bases_len);
- MEM_SAFE_FREE(select_ctx->index_offsets);
- select_ctx->index_offsets = MEM_mallocN(sizeof(*select_ctx->index_offsets) * bases_len,
- __func__);
-}
+ select_ctx->index_offsets = MEM_reallocN(select_ctx->index_offsets,
+ sizeof(*select_ctx->index_offsets) * bases_len);
-/** \} */
+ select_ctx->objects_drawn = MEM_reallocN(select_ctx->objects_drawn,
+ sizeof(*select_ctx->objects_drawn) * bases_len);
-/* -------------------------------------------------------------------- */
-/** \name Legacy
- * \{ */
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Object *obj = bases[base_index]->object;
+ select_ctx->objects[base_index] = obj;
-void DRW_draw_select_id_object(Depsgraph *depsgraph,
- ViewLayer *view_layer,
- ARegion *ar,
- View3D *v3d,
- Object *ob,
- short select_mode)
-{
- Base *base = BKE_view_layer_base_find(view_layer, ob);
- DRW_draw_select_id(depsgraph, ar, v3d, &base, 1, select_mode);
-}
+ /* Weak but necessary for `DRW_select_buffer_elem_get`. */
+ obj->runtime.select_id = base_index;
+ }
+ select_ctx->objects_len = bases_len;
+ select_ctx->select_mode = select_mode;
+ memset(select_ctx->persmat, 0, sizeof(select_ctx->persmat));
+}
/** \} */
diff --git a/source/blender/draw/modes/edit_mesh_mode.c b/source/blender/draw/modes/edit_mesh_mode.c
index f0e35e47a66..f8247d7929e 100644
--- a/source/blender/draw/modes/edit_mesh_mode.c
+++ b/source/blender/draw/modes/edit_mesh_mode.c
@@ -128,8 +128,7 @@ typedef struct EDIT_MESH_Shaders {
GPUShader *depth;
/* Mesh analysis shader */
- GPUShader *mesh_analysis_face;
- GPUShader *mesh_analysis_vertex;
+ GPUShader *mesh_analysis;
} EDIT_MESH_Shaders;
/* *********** STATIC *********** */
@@ -307,15 +306,9 @@ static void EDIT_MESH_engine_init(void *vedata)
});
/* Mesh Analysis */
- sh_data->mesh_analysis_face = GPU_shader_create_from_arrays({
+ sh_data->mesh_analysis = GPU_shader_create_from_arrays({
.vert = (const char *[]){lib, datatoc_edit_mesh_overlay_mesh_analysis_vert_glsl, NULL},
.frag = (const char *[]){datatoc_edit_mesh_overlay_mesh_analysis_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, "#define FACE_COLOR\n", NULL},
- });
- sh_data->mesh_analysis_vertex = GPU_shader_create_from_arrays({
- .vert = (const char *[]){lib, datatoc_edit_mesh_overlay_mesh_analysis_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_edit_mesh_overlay_mesh_analysis_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, "#define VERTEX_COLOR\n", NULL},
});
MEM_freeN(lib);
@@ -548,10 +541,9 @@ static void EDIT_MESH_cache_init(void *vedata)
/* Mesh Analysis Pass */
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
psl->mesh_analysis_pass = DRW_pass_create("Mesh Analysis", state);
- const bool is_vertex_color = scene->toolsettings->statvis.type == SCE_STATVIS_SHARP;
- g_data->mesh_analysis_shgrp = DRW_shgroup_create(
- is_vertex_color ? sh_data->mesh_analysis_vertex : sh_data->mesh_analysis_face,
- psl->mesh_analysis_pass);
+ g_data->mesh_analysis_shgrp = DRW_shgroup_create(sh_data->mesh_analysis,
+ psl->mesh_analysis_pass);
+ DRW_shgroup_uniform_texture(g_data->mesh_analysis_shgrp, "weightTex", G_draw.weight_ramp);
if (rv3d->rflag & RV3D_CLIPPING) {
DRW_shgroup_state_enable(g_data->mesh_analysis_shgrp, DRW_STATE_CLIP_PLANES);
}
@@ -704,17 +696,10 @@ static void EDIT_MESH_cache_populate(void *vedata, Object *ob)
geom = DRW_cache_mesh_surface_weights_get(ob);
DRW_shgroup_call_no_cull(g_data->fweights_shgrp, geom, ob);
}
-
- if (do_show_mesh_analysis && !XRAY_ACTIVE(v3d)) {
- Mesh *me = (Mesh *)ob->data;
- BMEditMesh *embm = me->edit_mesh;
- const bool is_original = embm->mesh_eval_final &&
- (embm->mesh_eval_final->runtime.is_original == true);
- if (is_original) {
- geom = DRW_cache_mesh_surface_mesh_analysis_get(ob);
- if (geom) {
- DRW_shgroup_call_no_cull(g_data->mesh_analysis_shgrp, geom, ob);
- }
+ else if (do_show_mesh_analysis && !XRAY_ACTIVE(v3d)) {
+ geom = DRW_cache_mesh_surface_mesh_analysis_get(ob);
+ if (geom) {
+ DRW_shgroup_call_no_cull(g_data->mesh_analysis_shgrp, geom, ob);
}
}
@@ -727,7 +712,7 @@ static void EDIT_MESH_cache_populate(void *vedata, Object *ob)
}
if (vnormals_do) {
- geom = DRW_mesh_batch_cache_get_edit_vertices(ob->data);
+ geom = DRW_mesh_batch_cache_get_edit_vnors(ob->data);
DRW_shgroup_call_no_cull(g_data->vnormals_shgrp, geom, ob);
}
if (lnormals_do) {
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_frag.glsl
index 8581453e810..8d96c0e418f 100644
--- a/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_frag.glsl
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_frag.glsl
@@ -1,12 +1,6 @@
out vec4 fragColor;
-#ifdef FACE_COLOR
-flat in vec4 weightColor;
-#endif
-
-#ifdef VERTEX_COLOR
in vec4 weightColor;
-#endif
void main()
{
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl
index 7065ce3df7c..b89a3f407f9 100644
--- a/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl
@@ -1,14 +1,25 @@
in vec3 pos;
-in vec4 weight_color;
+in float weight;
-#ifdef FACE_COLOR
-flat out vec4 weightColor;
-#endif
+uniform sampler1D weightTex;
-#ifdef VERTEX_COLOR
out vec4 weightColor;
-#endif
+
+vec3 weight_to_rgb(float t)
+{
+ if (t < 0.0) {
+ /* Minimum color, grey */
+ return vec3(0.25, 0.25, 0.25);
+ }
+ else if (t > 1.0) {
+ /* Error color */
+ return vec3(1.0, 0.0, 1.0);
+ }
+ else {
+ return texture(weightTex, t).rgb;
+ }
+}
void main()
{
@@ -16,7 +27,7 @@ void main()
vec3 world_pos = point_object_to_world(pos);
gl_Position = point_world_to_ndc(world_pos);
- weightColor = vec4(weight_color.rgb, 1.0);
+ weightColor = vec4(weight_to_rgb(weight), 1.0);
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index 625a52fc800..a78a63f1347 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -1829,13 +1829,13 @@ static size_t animdata_filter_gpencil(bAnimContext *ac,
}
}
- /* check selection and object type filters */
- if ((ads->filterflag & ADS_FILTER_ONLYSEL) &&
- !((base->flag & BASE_SELECTED) /*|| (base == scene->basact)*/)) {
- /* only selected should be shown */
- continue;
+ /* check selection and object type filters only for Object mode */
+ if (ob->mode == OB_MODE_OBJECT) {
+ if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & BASE_SELECTED))) {
+ /* only selected should be shown */
+ continue;
+ }
}
-
/* check if object belongs to the filtering group if option to filter
* objects by the grouped status is on
* - used to ease the process of doing multiple-character choreographies
diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c
index 7a5b57b1ce6..bd4886817cd 100644
--- a/source/blender/editors/animation/anim_motion_paths.c
+++ b/source/blender/editors/animation/anim_motion_paths.c
@@ -60,9 +60,8 @@ typedef struct MPathTarget {
Object *ob; /* source object */
bPoseChannel *pchan; /* source posechannel (if applicable) */
- /* "Evaluated" Copies (these come from the background COW copie
- * that provide all the coordinates we want to save off)
- */
+ /* "Evaluated" Copies (these come from the background COW copy
+ * that provide all the coordinates we want to save off). */
Object *ob_eval; /* evaluated object */
} MPathTarget;
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 935d11a388f..e341a16378c 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -218,7 +218,7 @@ static int add_driver_with_target(ReportList *UNUSED(reports),
/* Create a driver variable for the target
* - For transform properties, we want to automatically use "transform channel" instead
- * (The only issue is with quat rotations vs euler channels...)
+ * (The only issue is with quaternion rotations vs euler channels...)
* - To avoid problems with transform properties depending on the final transform that they
* control (thus creating pseudo-cycles - see T48734), we don't use transform channels
* when both the source and destinations are in same places.
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index de6e4c2fd0d..7fd2338dbf3 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -1484,10 +1484,10 @@ short insert_keyframe(Main *bmain,
flag);
}
}
- }
- if (values != value_buffer) {
- MEM_freeN(values);
+ if (values != value_buffer) {
+ MEM_freeN(values);
+ }
}
BKE_animsys_free_nla_keyframing_context_cache(&tmp_nla_cache);
@@ -1544,9 +1544,9 @@ static bool delete_keyframe_fcurve(AnimData *adt, FCurve *fcu, float cfra)
static void deg_tag_after_keyframe_delete(Main *bmain, ID *id, AnimData *adt)
{
if (adt->action == NULL) {
- /* In the case last f-curve wes removed need to inform dependency graph
+ /* In the case last f-curve was removed need to inform dependency graph
* about relations update, since it needs to get rid of animation operation
- * for this datablock. */
+ * for this data-block. */
DEG_id_tag_update_ex(bmain, id, ID_RECALC_ANIMATION_NO_FLUSH);
DEG_relations_tag_update(bmain);
}
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index ccd0fc54611..7d31c6d3e3a 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -712,9 +712,9 @@ int ANIM_scene_get_keyingset_index(Scene *scene, KeyingSet *ks)
}
}
- /* still here, so try builtins list too
- * - builtins are from (<= -1)
- * - none/invalid is (= 0)
+ /* Still here, so try built-ins list too:
+ * - Built-ins are from (<= -1).
+ * - None/Invalid is (= 0).
*/
index = BLI_findindex(&builtin_keyingsets, ks);
if (index != -1) {
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index d2fa77f90be..1073034383d 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -769,7 +769,7 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
EditBone *ebone = ebone_iter->temp.ebone;
- /* copy flags incase bone is pre-existing data */
+ /* Copy flags in case bone is pre-existing data. */
ebone->flag = (ebone->flag & ~flag_copy) | (ebone_iter->flag & flag_copy);
if (ebone_iter->parent == NULL) {
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 23ddf77e63d..eff621d7b71 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -46,6 +46,7 @@
#include "ED_armature.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_view3d.h"
@@ -356,6 +357,8 @@ static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEv
}
}
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+
ED_armature_edit_sync_selection(arm->edbo);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object);
@@ -1027,6 +1030,8 @@ static int armature_de_select_all_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
return OPERATOR_FINISHED;
@@ -1148,6 +1153,8 @@ static int armature_de_select_more_exec(bContext *C, wmOperator *UNUSED(op))
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
}
MEM_freeN(objects);
+
+ ED_outliner_select_sync_from_edit_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -1178,6 +1185,8 @@ static int armature_de_select_less_exec(bContext *C, wmOperator *UNUSED(op))
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
}
MEM_freeN(objects);
+
+ ED_outliner_select_sync_from_edit_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -1569,6 +1578,8 @@ static int armature_select_similar_exec(bContext *C, wmOperator *op)
#undef STRUCT_SIZE_AND_OFFSET
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+
return OPERATOR_FINISHED;
}
@@ -1663,6 +1674,8 @@ static int armature_select_hierarchy_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+
ED_armature_edit_sync_selection(arm->edbo);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
@@ -1748,6 +1761,8 @@ static int armature_select_mirror_exec(bContext *C, wmOperator *op)
arm->act_edbone = ebone_mirror_act;
}
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+
ED_armature_edit_sync_selection(arm->edbo);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
@@ -1876,6 +1891,7 @@ static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const
if (changed) {
arm->act_edbone = ebone_dst;
+ ED_outliner_select_sync_from_edit_bone_tag(C);
ED_armature_edit_sync_selection(arm->edbo);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 8434fee6e78..beec2f8358f 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -54,6 +54,7 @@
#include "ED_keyframing.h"
#include "ED_mesh.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_view3d.h"
@@ -449,6 +450,8 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve
selectconnected_posebonechildren(base->object, curBone, extend);
}
+ ED_outliner_select_sync_from_pose_bone_tag(C);
+
ED_pose_bone_select_tag_update(base->object);
return OPERATOR_FINISHED;
@@ -514,6 +517,8 @@ static int pose_de_select_all_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
+ ED_outliner_select_sync_from_pose_bone_tag(C);
+
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
return OPERATOR_FINISHED;
@@ -560,6 +565,8 @@ static int pose_select_parent_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
+ ED_outliner_select_sync_from_pose_bone_tag(C);
+
ED_pose_bone_select_tag_update(ob);
return OPERATOR_FINISHED;
}
@@ -624,6 +631,8 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
return OPERATOR_CANCELLED;
}
+ ED_outliner_select_sync_from_pose_bone_tag(C);
+
return OPERATOR_FINISHED;
}
@@ -712,6 +721,8 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ ED_outliner_select_sync_from_pose_bone_tag(C);
+
ED_pose_bone_select_tag_update(ob);
return OPERATOR_FINISHED;
@@ -1061,6 +1072,8 @@ static int pose_select_grouped_exec(bContext *C, wmOperator *op)
/* report done status */
if (changed) {
+ ED_outliner_select_sync_from_pose_bone_tag(C);
+
return OPERATOR_FINISHED;
}
else {
@@ -1172,6 +1185,8 @@ static int pose_select_mirror_exec(bContext *C, wmOperator *op)
}
MEM_freeN(objects);
+ ED_outliner_select_sync_from_pose_bone_tag(C);
+
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index c4bb5eec723..c93531bb6cc 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -1399,8 +1399,12 @@ static int separate_exec(bContext *C, wmOperator *op)
}
/* 2. Duplicate the object and data. */
- newbase = ED_object_add_duplicate(
- bmain, scene, view_layer, oldbase, 0); /* 0 = fully linked. */
+ newbase = ED_object_add_duplicate(bmain,
+ scene,
+ view_layer,
+ oldbase,
+ /* 0 = fully linked. */
+ 0);
DEG_relations_tag_update(bmain);
newob = newbase->object;
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index 5e0053782d4..c7c19aa2d02 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -120,7 +120,7 @@ struct CurveDrawData {
struct {
float mouse[2];
- /* used incase we can't calculate the depth */
+ /* Used in case we can't calculate the depth. */
float location_world[3];
float location_world_valid[3];
@@ -1053,7 +1053,7 @@ static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
- /* fallback (incase we can't find the depth on first test) */
+ /* Fallback (in case we can't find the depth on first test). */
{
const float mval_fl[2] = {UNPACK2(event->mval)};
float center[3];
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 d23965269ab..fa9c0f1fbb2 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
@@ -363,8 +363,8 @@ static void gizmo_arrow_exit(bContext *C, wmGizmo *gz, const bool cancel)
const bool is_prop_valid = WM_gizmo_target_property_is_valid(gz_prop);
if (!cancel) {
- /* Assign incase applying the operation needs an updated offset
- * editmesh bisect needs this. */
+ /* Assign in case applying the operation needs an updated offset
+ * edit-mesh bisect needs this. */
if (is_prop_valid) {
const int transform_flag = RNA_enum_get(arrow->gizmo.ptr, "transform");
const bool constrained = (transform_flag & ED_GIZMO_ARROW_XFORM_FLAG_CONSTRAINED) != 0;
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 e2a86469da1..406f76bc65e 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
@@ -358,7 +358,7 @@ static void gizmo_cage3d_draw_intern(
bool show = false;
if (gz->highlight_part == ED_GIZMO_CAGE3D_PART_TRANSLATE) {
/* Only show if we're drawing the center handle
- * otherwise the entire rectangle is the hotspot. */
+ * otherwise the entire rectangle is the hot-spot. */
if (draw_options & ED_GIZMO_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE) {
show = true;
}
diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c
index dce6ed29c05..697d06aa098 100644
--- a/source/blender/editors/gpencil/annotate_draw.c
+++ b/source/blender/editors/gpencil/annotate_draw.c
@@ -936,7 +936,6 @@ static void annotation_draw_data_layers(
/* draw a short status message in the top-right corner */
static void annotation_draw_status_text(const bGPdata *gpd, ARegion *ar)
{
- rcti rect;
/* Cannot draw any status text when drawing OpenGL Renders */
if (G.f & G_FLAG_RENDER_VIEWPORT) {
@@ -944,7 +943,7 @@ static void annotation_draw_status_text(const bGPdata *gpd, ARegion *ar)
}
/* Get bounds of region - Necessary to avoid problems with region overlap */
- ED_region_visible_rect(ar, &rect);
+ const rcti *rect = ED_region_visible_rect(ar);
/* for now, this should only be used to indicate when we are in stroke editmode */
if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
@@ -956,8 +955,8 @@ static void annotation_draw_status_text(const bGPdata *gpd, ARegion *ar)
BLF_width_and_height(
font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
- int xco = (rect.xmax - U.widget_unit) - (int)printable_size[0];
- int yco = (rect.ymax - U.widget_unit);
+ int xco = (rect->xmax - U.widget_unit) - (int)printable_size[0];
+ int yco = (rect->ymax - U.widget_unit);
/* text label */
UI_FontThemeColor(font_id, TH_TEXT_HI);
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index c9c4a67644e..22f1753a810 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -1156,7 +1156,7 @@ static tGPsdata *gp_session_initpaint(bContext *C)
/* create new context data */
p = MEM_callocN(sizeof(tGPsdata), "Annotation Drawing Data");
- /* Try to initialise context data
+ /* Try to initialize context data
* WARNING: This may not always succeed (e.g. using GP in an annotation-only context)
*/
if (gp_session_initdata(C, p) == 0) {
@@ -1252,15 +1252,6 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
/* Ensure active frame is set correctly... */
p->gpf = p->gpl->actframe;
- /* Restrict eraser to only affecting selected strokes, if the "selection mask" is on
- * (though this is only available in editmode)
- */
- if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) {
- if (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_SELECT_MASK) {
- p->flags |= GP_PAINTFLAG_SELECTMASK;
- }
- }
-
if (has_layer_to_erase == false) {
p->status = GP_STATUS_CAPTURE;
// if (G.debug & G_DEBUG)
@@ -2242,11 +2233,9 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else if (p->ar) {
- rcti region_rect;
-
- /* Perform bounds check using */
- ED_region_visible_rect(p->ar, &region_rect);
- in_bounds = BLI_rcti_isect_pt_v(&region_rect, event->mval);
+ /* Perform bounds check. */
+ const rcti *region_rect = ED_region_visible_rect(p->ar);
+ in_bounds = BLI_rcti_isect_pt_v(region_rect, event->mval);
}
else {
/* No region */
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 2b31af5ff1f..7c76f3aeab6 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -1173,15 +1173,14 @@ void ED_gp_draw_fill(tGPDdraw *tgpw)
/* draw a short status message in the top-right corner */
static void UNUSED_FUNCTION(gp_draw_status_text)(const bGPdata *gpd, ARegion *ar)
{
- rcti rect;
/* Cannot draw any status text when drawing OpenGL Renders */
if (G.f & G_FLAG_RENDER_VIEWPORT) {
return;
}
- /* Get bounds of region - Necessary to avoid problems with region overlap */
- ED_region_visible_rect(ar, &rect);
+ /* Get bounds of region - Necessary to avoid problems with region overlap. */
+ const rcti *rect = ED_region_visible_rect(ar);
/* for now, this should only be used to indicate when we are in stroke editmode */
if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
@@ -1193,8 +1192,8 @@ static void UNUSED_FUNCTION(gp_draw_status_text)(const bGPdata *gpd, ARegion *ar
BLF_width_and_height(
font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
- int xco = (rect.xmax - U.widget_unit) - (int)printable_size[0];
- int yco = (rect.ymax - U.widget_unit);
+ int xco = (rect->xmax - U.widget_unit) - (int)printable_size[0];
+ int yco = (rect->ymax - U.widget_unit);
/* text label */
UI_FontThemeColor(font_id, TH_TEXT_HI);
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c
index 8e4d2655ef0..4312bed657e 100644
--- a/source/blender/editors/gpencil/gpencil_brush.c
+++ b/source/blender/editors/gpencil/gpencil_brush.c
@@ -105,6 +105,7 @@ typedef struct tGP_BrushEditData {
eGP_Sculpt_Types brush_type;
eGP_Sculpt_Types brush_type_old;
eGP_Sculpt_Flag flag;
+ eGP_Sculpt_SelectMaskFlag mask;
/* Space Conversion Data */
GP_SpaceConversion gsc;
@@ -1276,6 +1277,9 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
gso->sa = CTX_wm_area(C);
gso->ar = CTX_wm_region(C);
+ /* save mask */
+ gso->mask = ts->gpencil_selectmode_sculpt;
+
/* multiframe settings */
gso->is_multiframe = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd);
gso->use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) != 0;
@@ -1486,7 +1490,7 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
/* Skip if neither one is selected
* (and we are only allowed to edit/consider selected points) */
- if ((gso->settings->flag & GP_SCULPT_SETT_FLAG_SELECT_MASK) && (!gso->is_weight_mode)) {
+ if ((GPENCIL_ANY_SCULPT_MASK(gso->mask)) && (!gso->is_weight_mode)) {
if (!(pt1->flag & GP_SPOINT_SELECT) && !(pt2->flag & GP_SPOINT_SELECT)) {
include_last = false;
continue;
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index f3ab0b45122..d03c53bf9cb 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -220,6 +220,17 @@ void GPENCIL_OT_editmode_toggle(wmOperatorType *ot)
}
/* set select mode */
+static bool gpencil_selectmode_toggle_poll(bContext *C)
+{
+ /* edit only supported with grease pencil objects */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL) || (ob->mode != OB_MODE_EDIT_GPENCIL)) {
+ return false;
+ }
+
+ return ED_operator_view3d_active(C);
+}
+
static int gpencil_selectmode_toggle_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -227,7 +238,7 @@ static int gpencil_selectmode_toggle_exec(bContext *C, wmOperator *op)
const int mode = RNA_int_get(op->ptr, "mode");
/* Just set mode */
- ts->gpencil_selectmode = mode;
+ ts->gpencil_selectmode_edit = mode;
WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
@@ -246,7 +257,7 @@ void GPENCIL_OT_selectmode_toggle(wmOperatorType *ot)
/* callbacks */
ot->exec = gpencil_selectmode_toggle_exec;
- ot->poll = gp_strokes_edit3d_poll;
+ ot->poll = gpencil_selectmode_toggle_poll;
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
@@ -3331,7 +3342,7 @@ typedef enum eGP_ReprojectModes {
GP_REPROJECT_FRONT = 0,
GP_REPROJECT_SIDE,
GP_REPROJECT_TOP,
- /* On same plane, parallel to viewplane */
+ /* On same plane, parallel to view-plane. */
GP_REPROJECT_VIEW,
/* Reprojected on to the scene geometry */
GP_REPROJECT_SURFACE,
@@ -3374,11 +3385,10 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
float xy[2];
- /* 3D to Screenspace */
- /* Note: We can't use gp_point_to_xy() here because that uses ints for the screenspace
- * coordinates, resulting in lost precision, which in turn causes stairstepping
- * artifacts in the final points.
- */
+ /* 3D to Screen-space */
+ /* Note: We can't use gp_point_to_xy() here because that uses ints for the screen-space
+ * coordinates, resulting in lost precision, which in turn causes stair-stepping
+ * artifacts in the final points. */
bGPDspoint pt2;
gp_point_to_parent_space(pt, gpstroke_iter.diff_mat, &pt2);
gp_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]);
@@ -3427,16 +3437,15 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
/* apply parent again */
gp_apply_parent_point(depsgraph, ob, gpd, gpl, pt);
}
- /* Project screenspace back to 3D space (from current perspective)
- * so that all points have been treated the same way
- */
+ /* Project screen-space back to 3D space (from current perspective)
+ * so that all points have been treated the same way. */
else if (mode == GP_REPROJECT_VIEW) {
- /* Planar - All on same plane parallel to the viewplane */
+ /* Planar - All on same plane parallel to the view-plane. */
gp_point_xy_to_3d(&gsc, scene, xy, &pt->x);
}
else {
/* Geometry - Snap to surfaces of visible geometry */
- /* XXX: There will be precision loss (possible stairstep artifacts)
+ /* XXX: There will be precision loss (possible stair-step artifacts)
* from this conversion to satisfy the API's */
const int screen_co[2] = {(int)xy[0], (int)xy[1]};
@@ -3548,7 +3557,7 @@ static void gp_smooth_stroke(bContext *C, wmOperator *op)
}
if (smooth_thickness) {
/* thickness need to repeat process several times */
- for (int r2 = 0; r2 < r * 10; r2++) {
+ for (int r2 = 0; r2 < r * 20; r2++) {
BKE_gpencil_smooth_stroke_thickness(gps, i, factor);
}
}
@@ -4052,8 +4061,10 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
}
/* add duplicate materials */
- ma = give_current_material(
- ob, gps->mat_nr + 1); /* XXX same material can be in multiple slots */
+
+ /* XXX same material can be in multiple slots. */
+ ma = give_current_material(ob, gps->mat_nr + 1);
+
idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma);
/* selected points mode */
@@ -4302,7 +4313,7 @@ void GPENCIL_OT_stroke_smooth(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- prop = RNA_def_int(ot->srna, "repeat", 1, 1, 10, "Repeat", "", 1, 5);
+ prop = RNA_def_int(ot->srna, "repeat", 1, 1, 50, "Repeat", "", 1, 20);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 2.0f, "Factor", "", 0.0f, 2.0f);
@@ -4438,7 +4449,7 @@ static int gpencil_cutter_lasso_select(bContext *C,
if ((pt->flag & GP_SPOINT_SELECT) || (pt->flag & GP_SPOINT_TAG)) {
continue;
}
- /* convert point coords to screenspace */
+ /* convert point coords to screen-space */
const bool is_inside = is_inside_fn(gps, pt, &gsc, gpstroke_iter.diff_mat, user_data);
if (is_inside) {
tot_inside++;
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 2a608d44a0b..715665fe6e9 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -635,6 +635,10 @@ struct GP_EditableStrokes_Iter {
} \
(void)0
+#define GPENCIL_ANY_SCULPT_MASK(flag) \
+ ((flag & (GP_SCULPT_MASK_SELECTMODE_POINT | GP_SCULPT_MASK_SELECTMODE_STROKE | \
+ GP_SCULPT_MASK_SELECTMODE_SEGMENT)))
+
/* ****************************************************** */
#endif /* __GPENCIL_INTERN_H__ */
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 06ff0e744b9..ee78a947b55 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -563,7 +563,7 @@ static void gp_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const floa
static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
{
bGPdata *gpd = p->gpd;
- short num_points = gpd->runtime.sbuffer_used;
+ const short num_points = gpd->runtime.sbuffer_used;
/* Do nothing if not enough points to smooth out */
if ((num_points < 3) || (idx < 3) || (inf == 0.0f)) {
@@ -571,10 +571,7 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
}
tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
- float steps = 4.0f;
- if (idx < 4) {
- steps--;
- }
+ const float steps = (idx < 4) ? 3.0f : 4.0f;
tGPspoint *pta = idx >= 4 ? &points[idx - 4] : NULL;
tGPspoint *ptb = idx >= 3 ? &points[idx - 3] : NULL;
@@ -583,29 +580,36 @@ 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;
const float average_fac = 1.0f / steps;
/* Compute smoothed coordinate by taking the ones nearby */
if (pta) {
copy_v2_v2(a, &pta->x);
madd_v2_v2fl(sco, a, average_fac);
+ pressure += pta->pressure * average_fac;
}
if (ptb) {
copy_v2_v2(b, &ptb->x);
madd_v2_v2fl(sco, b, average_fac);
+ pressure += ptb->pressure * average_fac;
}
if (ptc) {
copy_v2_v2(c, &ptc->x);
madd_v2_v2fl(sco, c, average_fac);
+ pressure += ptc->pressure * average_fac;
}
if (ptd) {
copy_v2_v2(d, &ptd->x);
madd_v2_v2fl(sco, d, average_fac);
+ pressure += ptd->pressure * average_fac;
}
- /* Based on influence factor, blend between original and optimal smoothed coordinate */
+ /* Based on influence factor, blend between original and optimal smoothed coordinate. */
interp_v2_v2v2(c, c, sco, inf);
copy_v2_v2(&ptc->x, c);
+ /* Interpolate pressure. */
+ ptc->pressure = interpf(ptc->pressure, pressure, inf);
}
/* add current stroke-point to buffer (returns whether point was successfully added) */
@@ -2128,15 +2132,6 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
/* Ensure this gets set... */
p->gpf = p->gpl->actframe;
- /* Restrict eraser to only affecting selected strokes, if the "selection mask" is on
- * (though this is only available in editmode)
- */
- if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) {
- if (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_SELECT_MASK) {
- p->flags |= GP_PAINTFLAG_SELECTMASK;
- }
- }
-
if (has_layer_to_erase == false) {
p->status = GP_STATUS_ERROR;
return;
@@ -3460,12 +3455,18 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* We don't pass on key events, GP is used with key-modifiers -
* prevents Dkey to insert drivers. */
if (ISKEYBOARD(event->type)) {
- if (ELEM(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY, ZKEY)) {
+ if (ELEM(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY)) {
/* allow some keys:
* - for frame changing [#33412]
* - for undo (during sketching sessions)
*/
}
+ else if (event->type == ZKEY) {
+ if (event->ctrl) {
+ p->status = GP_STATUS_DONE;
+ estate = OPERATOR_FINISHED;
+ }
+ }
else if (ELEM(event->type, PAD0, PAD1, PAD2, PAD3, PAD4, PAD5, PAD6, PAD7, PAD8, PAD9)) {
/* allow numpad keys so that camera/view manipulations can still take place
* - PAD0 in particular is really important for Grease Pencil drawing,
@@ -3623,11 +3624,9 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else if (p->ar) {
- rcti region_rect;
-
/* Perform bounds check using */
- ED_region_visible_rect(p->ar, &region_rect);
- in_bounds = BLI_rcti_isect_pt_v(&region_rect, event->mval);
+ const rcti *region_rect = ED_region_visible_rect(p->ar);
+ in_bounds = BLI_rcti_isect_pt_v(region_rect, event->mval);
}
else {
/* No region */
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index 5a962809954..4c185b7fb8a 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -67,10 +67,34 @@
/** \name Shared Utilities
* \{ */
+/* Convert sculpt mask mode to Select mode */
+static int gpencil_select_mode_from_sculpt(eGP_Sculpt_SelectMaskFlag mode)
+{
+ if (mode & GP_SCULPT_MASK_SELECTMODE_POINT) {
+ return GP_SELECTMODE_POINT;
+ }
+ else if (mode & GP_SCULPT_MASK_SELECTMODE_STROKE) {
+ return GP_SELECTMODE_STROKE;
+ }
+ else if (GP_SCULPT_MASK_SELECTMODE_SEGMENT) {
+ return GP_SELECTMODE_SEGMENT;
+ }
+ else {
+ return GP_SELECTMODE_POINT;
+ }
+}
+
static bool gpencil_select_poll(bContext *C)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
+ if (GPENCIL_SCULPT_MODE(gpd)) {
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ if (!(GPENCIL_ANY_SCULPT_MASK(ts->gpencil_selectmode_sculpt))) {
+ return false;
+ }
+ }
+
/* we just need some visible strokes, and to be in editmode or other modes only to catch event */
if (GPENCIL_ANY_MODE(gpd)) {
/* TODO: include a check for visible strokes? */
@@ -910,7 +934,11 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
ToolSettings *ts = CTX_data_tool_settings(C);
- const int selectmode = ts->gpencil_selectmode;
+ Object *ob = CTX_data_active_object(C);
+
+ const int selectmode = (ob && ob->mode == OB_MODE_SCULPT_GPENCIL) ?
+ gpencil_select_mode_from_sculpt(ts->gpencil_selectmode_sculpt) :
+ ts->gpencil_selectmode_edit;
const float scale = ts->gp_sculpt.isect_threshold;
/* if not edit/sculpt mode, the event is catched but not processed */
@@ -1016,12 +1044,18 @@ static int gpencil_generic_select_exec(bContext *C,
GPencilTestFn is_inside_fn,
void *user_data)
{
+ Object *ob = CTX_data_active_object(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
ToolSettings *ts = CTX_data_tool_settings(C);
ScrArea *sa = CTX_wm_area(C);
- const bool strokemode = ((ts->gpencil_selectmode == GP_SELECTMODE_STROKE) &&
+
+ const short selectmode = (ob && ob->mode == OB_MODE_SCULPT_GPENCIL) ?
+ gpencil_select_mode_from_sculpt(ts->gpencil_selectmode_sculpt) :
+ ts->gpencil_selectmode_edit;
+
+ const bool strokemode = ((selectmode == GP_SELECTMODE_STROKE) &&
((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0));
- const bool segmentmode = ((ts->gpencil_selectmode == GP_SELECTMODE_SEGMENT) &&
+ const bool segmentmode = ((selectmode == GP_SELECTMODE_SEGMENT) &&
((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0));
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
const float scale = ts->gp_sculpt.isect_threshold;
@@ -1064,7 +1098,6 @@ static int gpencil_generic_select_exec(bContext *C,
for (i = 0, pt = gps->points; i < gps->totpoints; i++, 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->flag & GP_SPOINT_SELECT) != 0;
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
@@ -1285,6 +1318,7 @@ static void deselect_all_selected(bContext *C)
static int gpencil_select_exec(bContext *C, wmOperator *op)
{
ScrArea *sa = CTX_wm_area(C);
+ Object *ob = CTX_data_active_object(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
ToolSettings *ts = CTX_data_tool_settings(C);
const float scale = ts->gp_sculpt.isect_threshold;
@@ -1315,8 +1349,12 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
}
/* if select mode is stroke, use whole stroke */
- if (ts->gpencil_selectmode == GP_SELECTMODE_STROKE) {
- whole = true;
+ if ((ob) && (ob->mode == OB_MODE_SCULPT_GPENCIL)) {
+ whole = (bool)(gpencil_select_mode_from_sculpt(ts->gpencil_selectmode_sculpt) ==
+ GP_SELECTMODE_STROKE);
+ }
+ else {
+ whole = (bool)(ts->gpencil_selectmode_edit == GP_SELECTMODE_STROKE);
}
/* init space conversion stuff */
@@ -1417,7 +1455,11 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
hit_stroke->flag |= GP_STROKE_SELECT;
/* expand selection to segment */
- if (ts->gpencil_selectmode == GP_SELECTMODE_SEGMENT) {
+ const short selectmode = (ob && ob->mode == OB_MODE_SCULPT_GPENCIL) ?
+ gpencil_select_mode_from_sculpt(ts->gpencil_selectmode_sculpt) :
+ ts->gpencil_selectmode_edit;
+
+ if (selectmode == GP_SELECTMODE_SEGMENT) {
float r_hita[3], r_hitb[3];
bool hit_select = (bool)(hit_point->flag & GP_SPOINT_SELECT);
ED_gpencil_select_stroke_segment(
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index a232e1376d3..cb6c66ed795 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -25,9 +25,9 @@
#define __ED_ANIM_API_H__
struct AnimData;
+struct Depsgraph;
struct ID;
struct ListBase;
-struct Depsgraph;
struct ARegion;
struct Main;
diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h
index e94aedc2b2b..30e2624604c 100644
--- a/source/blender/editors/include/ED_outliner.h
+++ b/source/blender/editors/include/ED_outliner.h
@@ -30,4 +30,17 @@ bool ED_outliner_collections_editor_poll(struct bContext *C);
void ED_outliner_selected_objects_get(const struct bContext *C, struct ListBase *objects);
+Base *ED_outliner_give_base_under_cursor(struct bContext *C, const int mval[2]);
+
+void ED_outliner_select_sync_from_object_tag(struct bContext *C);
+void ED_outliner_select_sync_from_edit_bone_tag(struct bContext *C);
+void ED_outliner_select_sync_from_pose_bone_tag(struct bContext *C);
+void ED_outliner_select_sync_from_sequence_tag(struct bContext *C);
+
+bool ED_outliner_select_sync_is_dirty(const struct bContext *C);
+
+void ED_outliner_select_sync_from_outliner(struct bContext *C, struct SpaceOutliner *soops);
+
+void ED_outliner_select_sync_flag_outliners(const struct bContext *C);
+
#endif /* __ED_OUTLINER_H__ */
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index e67a3b003fc..c7ee7be49b5 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -124,7 +124,8 @@ void ED_region_image_metadata_draw(
void ED_region_image_metadata_panel_draw(struct ImBuf *ibuf, struct uiLayout *layout);
void ED_region_grid_draw(struct ARegion *ar, float zoomx, float zoomy);
float ED_region_blend_alpha(struct ARegion *ar);
-void ED_region_visible_rect(struct ARegion *ar, struct rcti *rect);
+void ED_region_visible_rect_calc(struct ARegion *ar, struct rcti *rect);
+const rcti *ED_region_visible_rect(ARegion *ar);
bool ED_region_is_overlap(int spacetype, int regiontype);
int ED_region_snap_size_test(const struct ARegion *ar);
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 86e108a26c6..034e002f86a 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -45,4 +45,7 @@ bool ED_sculpt_mask_box_select(struct bContext *C,
/* sculpt_undo.c */
void ED_sculpt_undosys_type(struct UndoType *ut);
+void ED_sculpt_undo_geometry_begin(struct Object *ob);
+void ED_sculpt_undo_geometry_end(struct Object *ob);
+
#endif /* __ED_SCULPT_H__ */
diff --git a/source/blender/editors/include/ED_text.h b/source/blender/editors/include/ED_text.h
index ed71439bd37..ade1dde6c33 100644
--- a/source/blender/editors/include/ED_text.h
+++ b/source/blender/editors/include/ED_text.h
@@ -26,8 +26,10 @@
struct ARegion;
struct SpaceText;
+struct Text;
struct UndoStep;
struct UndoType;
+struct bContext;
bool ED_text_region_location_from_cursor(struct SpaceText *st,
struct ARegion *ar,
@@ -39,4 +41,7 @@ void ED_text_undosys_type(struct UndoType *ut);
struct UndoStep *ED_text_undo_push_init(struct bContext *C);
+/* text_format.c */
+bool ED_text_is_syntax_highlight_supported(struct Text *text);
+
#endif /* __ED_TEXT_H__ */
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index 3b080b6df95..29022adac6c 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -255,6 +255,7 @@ typedef enum ThemeColorID {
TH_MATCH, /* highlight color for search matches */
TH_SELECT_HIGHLIGHT, /* highlight color for selected outliner item */
+ TH_SELECT_ACTIVE, /* highlight color for active outliner item */
TH_SELECTED_OBJECT, /* selected object color for outliner */
TH_ACTIVE_OBJECT, /* active object color for outliner */
TH_EDITED_OBJECT, /* edited object color for outliner */
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index f9c65249918..7a123599be5 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -2553,8 +2553,8 @@ void ui_but_string_get_ex(uiBut *but,
}
}
else {
+ const int int_digits_num = integer_digits_f(value);
if (use_exp_float) {
- const int int_digits_num = integer_digits_f(value);
if (int_digits_num < -6 || int_digits_num > 12) {
BLI_snprintf(str, maxlen, "%.*g", prec, value);
if (r_use_exp_float) {
@@ -2568,10 +2568,8 @@ void ui_but_string_get_ex(uiBut *but,
}
}
else {
-#if 0 /* TODO, but will likely break some stuff, so better after 2.79 release. */
prec -= int_digits_num;
CLAMP(prec, 0, UI_PRECISION_FLOAT_MAX);
-#endif
BLI_snprintf(str, maxlen, "%.*f", prec, value);
}
}
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index 88fe8704082..22b75da4968 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -523,6 +523,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
/* determine if we can key a single component of an array */
const bool is_array = RNA_property_array_length(&but->rnapoin, but->rnaprop) != 0;
const bool is_array_component = (is_array && but->rnaindex != -1);
+ const bool is_whole_array = (is_array && but->rnaindex == -1);
const int override_status = RNA_property_override_library_status(ptr, prop, -1);
const bool is_overridable = (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE) != 0;
@@ -658,21 +659,23 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
1);
}
- uiItemO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Driver"),
- ICON_NONE,
- "ANIM_OT_copy_driver_button");
- if (ANIM_driver_can_paste()) {
+ if (!is_whole_array) {
uiItemO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Paste Driver"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Driver"),
ICON_NONE,
- "ANIM_OT_paste_driver_button");
- }
+ "ANIM_OT_copy_driver_button");
+ if (ANIM_driver_can_paste()) {
+ uiItemO(layout,
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Paste Driver"),
+ ICON_NONE,
+ "ANIM_OT_paste_driver_button");
+ }
- uiItemO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Edit Driver"),
- ICON_DRIVER,
- "ANIM_OT_driver_button_edit");
+ uiItemO(layout,
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Edit Driver"),
+ ICON_DRIVER,
+ "ANIM_OT_driver_button_edit");
+ }
uiItemO(layout,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open Drivers Editor"),
@@ -690,11 +693,13 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
ICON_DRIVER,
"ANIM_OT_driver_button_add");
- if (ANIM_driver_can_paste()) {
- uiItemO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Paste Driver"),
- ICON_NONE,
- "ANIM_OT_paste_driver_button");
+ if (!is_whole_array) {
+ if (ANIM_driver_can_paste()) {
+ uiItemO(layout,
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Paste Driver"),
+ ICON_NONE,
+ "ANIM_OT_paste_driver_button");
+ }
}
uiItemO(layout,
@@ -862,7 +867,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
"UI_OT_unset_property_button");
}
- if (is_idprop && !is_array_component && ELEM(type, PROP_INT, PROP_FLOAT)) {
+ if (is_idprop && !is_array && ELEM(type, PROP_INT, PROP_FLOAT)) {
uiItemO(layout,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Assign Value as Default"),
ICON_NONE,
@@ -899,7 +904,8 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
ICON_NONE,
"UI_OT_copy_data_path_button");
- if (ptr->id.data && ELEM(type, PROP_BOOLEAN, PROP_INT, PROP_FLOAT, PROP_ENUM)) {
+ if (ptr->id.data && !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"),
ICON_NONE,
diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c
index 658aa4f67f9..efbe5922aa5 100644
--- a/source/blender/editors/interface/interface_eyedropper_datablock.c
+++ b/source/blender/editors/interface/interface_eyedropper_datablock.c
@@ -51,6 +51,7 @@
#include "ED_space_api.h"
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "ED_outliner.h"
#include "interface_intern.h"
#include "interface_eyedropper_intern.h"
@@ -67,6 +68,7 @@ typedef struct DataDropper {
ID *init_id; /* for resetting on cancel */
+ ScrArea *cursor_area; /* Area under the cursor */
ARegionType *art;
void *draw_handle_pixel;
char name[200];
@@ -103,6 +105,7 @@ static int datadropper_init(bContext *C, wmOperator *op)
ddr->is_undo = UI_but_flag_is_set(but, UI_BUT_UNDO);
+ ddr->cursor_area = CTX_wm_area(C);
ddr->art = art;
ddr->draw_handle_pixel = ED_region_draw_cb_activate(
art, datadropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
@@ -141,7 +144,7 @@ static void datadropper_exit(bContext *C, wmOperator *op)
/* *** datadropper id helper functions *** */
/**
- * \brief get the ID from the screen.
+ * \brief get the ID from the 3D view or outliner.
*/
static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int my, ID **r_id)
{
@@ -155,7 +158,7 @@ static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int
ddr->name[0] = '\0';
if (sa) {
- if (sa->spacetype == SPACE_VIEW3D) {
+ if (ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_OUTLINER)) {
ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
if (ar) {
const int mval[2] = {mx - ar->winrct.xmin, my - ar->winrct.ymin};
@@ -167,7 +170,13 @@ static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int
/* grr, always draw else we leave stale text */
ED_region_tag_redraw(ar);
- base = ED_view3d_give_base_under_cursor(C, mval);
+ if (sa->spacetype == SPACE_VIEW3D) {
+ base = ED_view3d_give_base_under_cursor(C, mval);
+ }
+ else {
+ base = ED_outliner_give_base_under_cursor(C, mval);
+ }
+
if (base) {
Object *ob = base->object;
ID *id = NULL;
@@ -232,6 +241,36 @@ static void datadropper_cancel(bContext *C, wmOperator *op)
datadropper_exit(C, op);
}
+/* To switch the draw callback when region under mouse event changes */
+static void datadropper_set_draw_callback_region(bContext *C,
+ DataDropper *ddr,
+ const int mx,
+ const int my)
+{
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, -1, mx, my);
+
+ if (sa) {
+ /* If spacetype changed */
+ if (sa->spacetype != ddr->cursor_area->spacetype) {
+ /* Remove old callback */
+ ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel);
+
+ /* Redraw old area */
+ ARegion *ar = BKE_area_find_region_type(ddr->cursor_area, RGN_TYPE_WINDOW);
+ ED_region_tag_redraw(ar);
+
+ /* Set draw callback in new region */
+ ARegionType *art = BKE_regiontype_from_id(sa->type, RGN_TYPE_WINDOW);
+
+ ddr->cursor_area = sa;
+ ddr->art = art;
+ ddr->draw_handle_pixel = ED_region_draw_cb_activate(
+ art, datadropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
+ }
+ }
+}
+
/* main modal status check */
static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
@@ -260,6 +299,10 @@ static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
else if (event->type == MOUSEMOVE) {
ID *id = NULL;
+
+ /* Set the region for eyedropper cursor text drawing */
+ datadropper_set_draw_callback_region(C, ddr, event->x, event->y);
+
datadropper_id_sample_pt(C, ddr, event->x, event->y, &id);
}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 52933a89045..19eb9699fc8 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -4001,6 +4001,11 @@ static int ui_do_but_HOTKEYEVT(bContext *C,
return WM_UI_HANDLER_CONTINUE;
}
else if (event->type == UNKNOWNKEY) {
+ WM_report(RPT_WARNING, "Unsupported key: Unknown");
+ return WM_UI_HANDLER_CONTINUE;
+ }
+ else if (event->type == CAPSLOCKKEY) {
+ WM_report(RPT_WARNING, "Unsupported key: CapsLock");
return WM_UI_HANDLER_CONTINUE;
}
@@ -4795,37 +4800,24 @@ static int ui_do_but_NUM(
if (click) {
/* we can click on the side arrows to increment/decrement,
* or click inside to edit the value directly */
- float tempf, softmin, softmax;
- int temp;
-
- softmin = but->softmin;
- softmax = but->softmax;
+ const float softmin = but->softmin;
+ const float softmax = but->softmax;
if (!ui_but_is_float(but)) {
- if (but->drawflag & UI_BUT_ACTIVE_LEFT) {
+ /* Integer Value. */
+ if (but->drawflag & (UI_BUT_ACTIVE_LEFT | UI_BUT_ACTIVE_RIGHT)) {
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
-
- temp = (int)data->value - 1;
- if (temp >= softmin && temp <= softmax) {
- data->value = (double)temp;
+ const int value_step = (int)but->a1;
+ BLI_assert(value_step > 0);
+ const double value_test = (but->drawflag & UI_BUT_ACTIVE_LEFT) ?
+ (double)max_ii((int)softmin, (int)data->value - value_step) :
+ (double)min_ii((int)softmax, (int)data->value + value_step);
+ if (value_test != data->value) {
+ data->value = (double)value_test;
}
else {
data->cancel = true;
}
-
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- }
- else if (but->drawflag & UI_BUT_ACTIVE_RIGHT) {
- button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
-
- temp = (int)data->value + 1;
- if (temp >= softmin && temp <= softmax) {
- data->value = (double)temp;
- }
- else {
- data->cancel = true;
- }
-
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
else {
@@ -4833,26 +4825,20 @@ static int ui_do_but_NUM(
}
}
else {
- if (but->drawflag & UI_BUT_ACTIVE_LEFT) {
+ /* Float Value. */
+ if (but->drawflag & (UI_BUT_ACTIVE_LEFT | UI_BUT_ACTIVE_RIGHT)) {
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
-
- tempf = (float)data->value - (UI_PRECISION_FLOAT_SCALE * but->a1);
- if (tempf < softmin) {
- tempf = softmin;
+ const double value_step = (double)but->a1 * UI_PRECISION_FLOAT_SCALE;
+ BLI_assert(value_step > 0.0f);
+ const double value_test = (but->drawflag & UI_BUT_ACTIVE_LEFT) ?
+ (double)max_ff(softmin, (float)(data->value - value_step)) :
+ (double)min_ff(softmax, (float)(data->value + value_step));
+ if (value_test != data->value) {
+ data->value = value_test;
}
- data->value = tempf;
-
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- }
- else if (but->drawflag & UI_BUT_ACTIVE_RIGHT) {
- button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
-
- tempf = (float)data->value + (UI_PRECISION_FLOAT_SCALE * but->a1);
- if (tempf > softmax) {
- tempf = softmax;
+ else {
+ data->cancel = true;
}
- data->value = tempf;
-
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
else {
@@ -8198,7 +8184,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
else {
/* Do this so we can still mouse-up, closing the menu and running the button.
* This is nice to support but there are times when the button gets left pressed.
- * Keep disavled for now. */
+ * Keep disabled for now. */
WM_event_remove_timer(data->wm, data->window, data->hold_action_timer);
data->hold_action_timer = NULL;
}
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 25fedf8519a..78eed98eb77 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -648,7 +648,7 @@ static void ui_item_array(uiLayout *layout,
* to work with common cases, but may need to be re-worked */
/* special case, boolean array in a menu, this could be used in a more generic way too */
- if (ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA) && !expand) {
+ if (ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA) && !expand && ELEM(len, 3, 4)) {
uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, 0, 0, w, UI_UNIT_Y);
}
else {
@@ -1832,7 +1832,9 @@ static void ui_item_rna_size(uiLayout *layout,
h += len * UI_UNIT_Y;
}
}
- else if (ui_layout_variable_size(layout)) {
+
+ /* Increase width requirement if in a variable size layout. */
+ if (ui_layout_variable_size(layout)) {
if (type == PROP_BOOLEAN && name[0]) {
w += UI_UNIT_X / 5;
}
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index f5a894d7620..fbd422a9752 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -172,7 +172,8 @@ static bool copy_as_driver_button_poll(bContext *C)
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.id.data && ptr.data && prop &&
- ELEM(RNA_property_type(prop), PROP_BOOLEAN, PROP_INT, PROP_FLOAT, PROP_ENUM)) {
+ ELEM(RNA_property_type(prop), PROP_BOOLEAN, PROP_INT, PROP_FLOAT, PROP_ENUM) &&
+ (index >= 0 || !RNA_property_array_check(prop))) {
path = RNA_path_from_ID_to_property(&ptr, prop);
if (path) {
@@ -1118,7 +1119,7 @@ static int reports_to_text_exec(bContext *C, wmOperator *UNUSED(op))
txt = BKE_text_add(bmain, "Recent Reports");
/* convert entire list to a display string, and add this to the text-block
- * - if commandline debug option enabled, show debug reports too
+ * - if command-line debug option enabled, show debug reports too
* - otherwise, up to info (which is what users normally see)
*/
str = BKE_reports_string(reports, (G.debug & G_DEBUG) ? RPT_DEBUG : RPT_INFO);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 37eb1770f68..22573c9c7d2 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -2523,7 +2523,7 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
/* enabled */
UI_block_emboss_set(block, UI_EMBOSS_NONE);
- uiItemR(row, &ptr, "mute", 0, "", (con->flag & CONSTRAINT_OFF) ? ICON_HIDE_ON : ICON_HIDE_OFF);
+ uiItemR(row, &ptr, "mute", 0, "", 0);
UI_block_emboss_set(block, UI_EMBOSS);
uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
@@ -6392,22 +6392,17 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
block, UI_BTYPE_LABEL, 0, icon, 2, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
}
- UI_block_emboss_set(block, UI_EMBOSS);
-
- uiDefBut(block,
- UI_BTYPE_LABEL,
- 0,
- report->message,
- UI_UNIT_X + 5,
- 0,
- UI_UNIT_X + width,
- UI_UNIT_Y,
- NULL,
- 0.0f,
- 0.0f,
- 0,
- 0,
- "");
+ but = uiDefButO(block,
+ UI_BTYPE_BUT,
+ "SCREEN_OT_info_log_show",
+ WM_OP_INVOKE_REGION_WIN,
+ report->message,
+ UI_UNIT_X + 5,
+ 0,
+ UI_UNIT_X + width,
+ UI_UNIT_Y,
+ "Show in Info Log");
+ rgba_float_to_uchar(but->col, rti->col);
}
void uiTemplateInputStatus(uiLayout *layout, struct bContext *C)
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index bf52cc625c2..9c8787d002f 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -417,8 +417,9 @@ void ui_rna_collection_search_cb(const struct bContext *C,
}
}
- name = RNA_struct_name_get_alloc(
- &itemptr, NULL, 0, NULL); /* could use the string length here */
+ /* Could use the string length here. */
+ name = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL);
+
iconid = 0;
if (itemptr.type && RNA_struct_is_ID(itemptr.type)) {
iconid = ui_id_icon_get(C, itemptr.data, false);
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index c31de60c7ed..7c5d5401d08 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -794,6 +794,10 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
cp = ts->selected_highlight;
break;
+ case TH_SELECT_ACTIVE:
+ cp = ts->active;
+ break;
+
case TH_SELECTED_OBJECT:
cp = ts->selected_object;
break;
diff --git a/source/blender/editors/interface/view2d_gizmo_navigate.c b/source/blender/editors/interface/view2d_gizmo_navigate.c
index 883f16c63f2..9b15f2309a1 100644
--- a/source/blender/editors/interface/view2d_gizmo_navigate.c
+++ b/source/blender/editors/interface/view2d_gizmo_navigate.c
@@ -201,21 +201,20 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
struct NavigateWidgetGroup *navgroup = gzgroup->customdata;
ARegion *ar = CTX_wm_region(C);
- rcti rect_visible;
- ED_region_visible_rect(ar, &rect_visible);
+ const rcti *rect_visible = ED_region_visible_rect(ar);
- if ((navgroup->state.rect_visible.xmax == rect_visible.xmax) &&
- (navgroup->state.rect_visible.ymax == rect_visible.ymax)) {
+ if ((navgroup->state.rect_visible.xmax == rect_visible->xmax) &&
+ (navgroup->state.rect_visible.ymax == rect_visible->ymax)) {
return;
}
- navgroup->state.rect_visible = rect_visible;
+ navgroup->state.rect_visible = *rect_visible;
const float icon_size = GIZMO_SIZE;
const float icon_offset_mini = icon_size * GIZMO_MINI_OFFSET_FAC * UI_DPI_FAC;
const float co[2] = {
- rect_visible.xmax - (icon_offset_mini * 0.75f),
- rect_visible.ymax - (icon_offset_mini * 0.75f),
+ rect_visible->xmax - (icon_offset_mini * 0.75f),
+ rect_visible->ymax - (icon_offset_mini * 0.75f),
};
wmGizmo *gz;
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index f32fcffabd4..032fb7e4cc2 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -1844,7 +1844,7 @@ static void scroller_activate_init(bContext *C,
*/
scrollers = UI_view2d_scrollers_calc(v2d, NULL);
- /* use a union of 'cur' & 'tot' incase the current view is far outside 'tot'. In this cases
+ /* Use a union of 'cur' & 'tot' in case the current view is far outside 'tot'. In this cases
* moving the scroll bars has far too little effect and the view can get stuck T31476. */
tot_cur_union = v2d->tot;
BLI_rctf_union(&tot_cur_union, &v2d->cur);
diff --git a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
index 74700e59e99..7155348fed5 100644
--- a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
+++ b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
@@ -1008,8 +1008,17 @@ static void gizmo_mesh_spin_redo_setup(const bContext *C, wmGizmoGroup *gzgroup)
});
}
- /* Become modal as soon as it's started. */
- gizmo_mesh_spin_redo_modal_from_setup(C, gzgroup);
+ wmWindow *win = CTX_wm_window(C);
+ if (win && win->active) {
+ bScreen *screen = WM_window_get_active_screen(win);
+ if (screen->active_region) {
+ ARegion *ar = CTX_wm_region(C);
+ if (screen->active_region == ar) {
+ /* Become modal as soon as it's started. */
+ gizmo_mesh_spin_redo_modal_from_setup(C, gzgroup);
+ }
+ }
+ }
}
static void gizmo_mesh_spin_redo_draw_prepare(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index bb584094580..ab1595997e5 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -2949,7 +2949,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
case KNF_MODAL_ADD_CUT_CLOSED:
if (kcd->mode == MODE_DRAGGING) {
- /* shouldn't be possible with default key-layout, just incase... */
+ /* Shouldn't be possible with default key-layout, just in case. */
if (kcd->is_drag_hold) {
kcd->is_drag_hold = false;
knifetool_update_mval(kcd, kcd->curr.mval);
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 2f4688e2de7..94ffd9a34d6 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -317,9 +317,10 @@ BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc,
/* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */
{
- DRW_draw_select_id(vc->depsgraph, vc->ar, vc->v3d, bases, bases_len, SCE_SELECT_VERTEX);
+ DRW_select_buffer_context_create(bases, bases_len, SCE_SELECT_VERTEX);
- index = DRW_select_buffer_find_nearest_to_point(vc->mval, 1, UINT_MAX, &dist_px);
+ index = DRW_select_buffer_find_nearest_to_point(
+ vc->depsgraph, vc->ar, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px);
if (index) {
eve = (BMVert *)edbm_select_id_bm_elem_get(bases, index, &base_index);
@@ -539,9 +540,10 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc,
/* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */
{
- DRW_draw_select_id(vc->depsgraph, vc->ar, vc->v3d, bases, bases_len, SCE_SELECT_EDGE);
+ DRW_select_buffer_context_create(bases, bases_len, SCE_SELECT_EDGE);
- index = DRW_select_buffer_find_nearest_to_point(vc->mval, 1, UINT_MAX, &dist_px);
+ index = DRW_select_buffer_find_nearest_to_point(
+ vc->depsgraph, vc->ar, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px);
if (index) {
eed = (BMEdge *)edbm_select_id_bm_elem_get(bases, index, &base_index);
@@ -745,9 +747,9 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc,
BMFace *efa;
{
- DRW_draw_select_id(vc->depsgraph, vc->ar, vc->v3d, bases, bases_len, SCE_SELECT_FACE);
+ DRW_select_buffer_context_create(bases, bases_len, SCE_SELECT_FACE);
- index = DRW_select_buffer_sample_point(vc->mval);
+ index = DRW_select_buffer_sample_point(vc->depsgraph, vc->ar, vc->v3d, vc->mval);
if (index) {
efa = (BMFace *)edbm_select_id_bm_elem_get(bases, index, &base_index);
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index cb147772b6a..4e58fee61a2 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -3190,7 +3190,7 @@ void MESH_OT_remove_doubles(wmOperatorType *ot)
1e-6f,
50.0f,
"Merge Distance",
- "Minimum distance between elements to merge",
+ "Maximum distance between elements to merge",
1e-5f,
10.0f);
RNA_def_boolean(ot->srna,
@@ -4040,7 +4040,7 @@ static void mesh_separate_material_assign_mat_nr(Main *bmain, Object *ob, const
ma_obdata = NULL;
}
- BKE_material_clear_id(bmain, obdata, true);
+ BKE_material_clear_id(bmain, obdata);
BKE_material_resize_object(bmain, ob, 1, true);
BKE_material_resize_id(bmain, obdata, 1, true);
@@ -4051,7 +4051,7 @@ static void mesh_separate_material_assign_mat_nr(Main *bmain, Object *ob, const
id_us_plus((ID *)ma_obdata);
}
else {
- BKE_material_clear_id(bmain, obdata, true);
+ BKE_material_clear_id(bmain, obdata);
BKE_material_resize_object(bmain, ob, 0, true);
BKE_material_resize_id(bmain, obdata, 0, true);
}
@@ -5791,7 +5791,7 @@ void MESH_OT_dissolve_degenerate(wmOperatorType *ot)
1e-6f,
50.0f,
"Merge Distance",
- "Minimum distance between elements to merge",
+ "Maximum distance between elements to merge",
1e-5f,
10.0f);
}
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 0bdc59c7185..8d9d0e40f44 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -1116,11 +1116,12 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px,
if (dist_px) {
/* sample rect to increase chances of selecting, so that when clicking
* on an edge in the backbuf, we can still select a face */
- *r_index = DRW_select_buffer_find_nearest_to_point(mval, 1, me->totpoly + 1, &dist_px);
+ *r_index = DRW_select_buffer_find_nearest_to_point(
+ vc.depsgraph, vc.ar, vc.v3d, mval, 1, me->totpoly + 1, &dist_px);
}
else {
/* sample only on the exact position */
- *r_index = DRW_select_buffer_sample_point(mval);
+ *r_index = DRW_select_buffer_sample_point(vc.depsgraph, vc.ar, vc.v3d, mval);
}
if ((*r_index) == 0 || (*r_index) > (unsigned int)me->totpoly) {
@@ -1297,11 +1298,12 @@ bool ED_mesh_pick_vert(
if (dist_px > 0) {
/* sample rect to increase chances of selecting, so that when clicking
* on an face in the backbuf, we can still select a vert */
- *r_index = DRW_select_buffer_find_nearest_to_point(mval, 1, me->totvert + 1, &dist_px);
+ *r_index = DRW_select_buffer_find_nearest_to_point(
+ vc.depsgraph, vc.ar, vc.v3d, mval, 1, me->totvert + 1, &dist_px);
}
else {
/* sample only on the exact position */
- *r_index = DRW_select_buffer_sample_point(mval);
+ *r_index = DRW_select_buffer_sample_point(vc.depsgraph, vc.ar, vc.v3d, mval);
}
if ((*r_index) == 0 || (*r_index) > (uint)me->totvert) {
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt
index eaef9313431..2490f88b5eb 100644
--- a/source/blender/editors/object/CMakeLists.txt
+++ b/source/blender/editors/object/CMakeLists.txt
@@ -57,6 +57,7 @@ set(SRC
object_ops.c
object_random.c
object_relations.c
+ object_remesh.c
object_select.c
object_shader_fx.c
object_shapekey.c
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 7e031866dec..80d150506ad 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -103,6 +103,7 @@
#include "ED_mesh.h"
#include "ED_node.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_physics.h"
#include "ED_render.h"
#include "ED_screen.h"
@@ -502,6 +503,8 @@ Object *ED_object_add_type(bContext *C,
/* TODO(sergey): Use proper flag for tagging here. */
DEG_id_tag_update(&scene->id, 0);
+ ED_outliner_select_sync_from_object_tag(C);
+
return ob;
}
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index e697c25b37f..4b369c10e4d 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -279,6 +279,9 @@ void OBJECT_OT_bake(wmOperatorType *ot);
/* object_random.c */
void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot);
+/* object_remesh.c */
+void OBJECT_OT_voxel_remesh(struct wmOperatorType *ot);
+
/* object_transfer_data.c */
void OBJECT_OT_data_transfer(struct wmOperatorType *ot);
void OBJECT_OT_datalayout_transfer(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index b653c7fa70c..38c06319450 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -257,6 +257,8 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_hide_view_clear);
WM_operatortype_append(OBJECT_OT_hide_view_set);
WM_operatortype_append(OBJECT_OT_hide_collection);
+
+ WM_operatortype_append(OBJECT_OT_voxel_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 a69f4872e72..88ef0be3bc6 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -1744,7 +1744,7 @@ static Collection *single_object_users_collection(Main *bmain,
}
/* Since master collection has already be duplicated as part of scene copy,
- * we do not duplictae it here.
+ * we do not duplicate it here.
* However, this means its children need to be re-added manually here,
* otherwise their parent lists are empty (which will lead to crashes, see T63101). */
CollectionChild *child_next, *child = collection->children.first;
diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c
new file mode 100644
index 00000000000..bc94b3f7875
--- /dev/null
+++ b/source/blender/editors/object/object_remesh.c
@@ -0,0 +1,158 @@
+/*
+ * 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 edobj
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
+#include <ctype.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_customdata.h"
+#include "BKE_mesh_remesh_voxel.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "ED_mesh.h"
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_undo.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+
+#include "object_intern.h" // own include
+
+static bool object_remesh_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+
+ if (BKE_object_is_in_editmode(ob)) {
+ CTX_wm_operator_poll_msg_set(C, "The voxel 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.");
+ }
+
+ return ED_operator_object_active_editable_mesh(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;
+
+ if (mesh->remesh_voxel_size <= 0.0f) {
+ BKE_report(op->reports, RPT_ERROR, "Voxel remesher cannot run with a voxel size of 0.0.");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (ob->mode == OB_MODE_SCULPT) {
+ ED_sculpt_undo_geometry_begin(ob);
+ }
+
+ new_mesh = BKE_mesh_remesh_voxel_to_mesh_nomain(mesh, mesh->remesh_voxel_size);
+
+ 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);
+ }
+ }
+
+ BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
+
+ if (mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK) {
+ BKE_remesh_reproject_paint_mask(mesh, obj_mesh_copy);
+ BKE_mesh_free(obj_mesh_copy);
+ }
+
+ if (mesh->flag & ME_REMESH_SMOOTH_NORMALS) {
+ BKE_mesh_smooth_flag_set(ob, 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);
+ 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);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_voxel_remesh(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Voxel Remesh";
+ ot->description =
+ "Calculates a new manifold mesh based on the volume of the current mesh. All data layers "
+ "will be lost";
+ ot->idname = "OBJECT_OT_voxel_remesh";
+
+ /* api callbacks */
+ ot->poll = object_remesh_poll;
+ ot->exec = voxel_remesh_exec;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index da06707ebac..28242b986f1 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -69,6 +69,7 @@
#include "ED_armature.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_keyframing.h"
@@ -436,6 +437,8 @@ static int object_select_by_type_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ ED_outliner_select_sync_from_object_tag(C);
+
return OPERATOR_FINISHED;
}
@@ -717,6 +720,7 @@ static int object_select_linked_exec(bContext *C, wmOperator *op)
if (changed) {
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
@@ -1100,6 +1104,7 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op)
if (changed) {
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
@@ -1150,6 +1155,8 @@ static int object_select_all_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ ED_outliner_select_sync_from_object_tag(C);
+
return OPERATOR_FINISHED;
}
else if (any_visible == false) {
@@ -1218,6 +1225,8 @@ static int object_select_same_collection_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ ED_outliner_select_sync_from_object_tag(C);
+
return OPERATOR_FINISHED;
}
@@ -1281,6 +1290,8 @@ static int object_select_mirror_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ ED_outliner_select_sync_from_object_tag(C);
+
return OPERATOR_FINISHED;
}
@@ -1369,6 +1380,9 @@ static int object_select_more_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+
+ ED_outliner_select_sync_from_object_tag(C);
+
return OPERATOR_FINISHED;
}
else {
@@ -1399,6 +1413,9 @@ static int object_select_less_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+
+ ED_outliner_select_sync_from_object_tag(C);
+
return OPERATOR_FINISHED;
}
else {
@@ -1448,6 +1465,8 @@ static int object_select_random_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ ED_outliner_select_sync_from_object_tag(C);
+
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_shader_fx.c b/source/blender/editors/object/object_shader_fx.c
index 6212269c099..457d2421253 100644
--- a/source/blender/editors/object/object_shader_fx.c
+++ b/source/blender/editors/object/object_shader_fx.c
@@ -282,8 +282,9 @@ void OBJECT_OT_shaderfx_add(wmOperatorType *ot)
ot->prop = RNA_def_enum(
ot->srna, "type", rna_enum_object_shaderfx_type_items, eShaderFxType_Blur, "Type", "");
RNA_def_enum_funcs(ot->prop, shaderfx_add_itemf);
- RNA_def_property_translation_context(ot->prop,
- BLT_I18NCONTEXT_ID_ID); /* Abused, for "Light"... */
+
+ /* Abused, for "Light"... */
+ RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_ID);
}
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index a43ac59c9b8..08fe5e818b2 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -1139,7 +1139,7 @@ static bool vgroup_normalize(Object *ob)
int i, dvert_tot = 0;
const int def_nr = ob->actdef - 1;
- const int use_vert_sel = vertex_group_use_vert_sel(ob);
+ const bool use_vert_sel = vertex_group_use_vert_sel(ob);
if (!BLI_findlink(&ob->defbase, def_nr)) {
return false;
@@ -1623,7 +1623,7 @@ static bool vgroup_normalize_all(Object *ob,
int i, dvert_tot = 0;
const int def_nr = ob->actdef - 1;
- const int use_vert_sel = vertex_group_use_vert_sel(ob);
+ const bool use_vert_sel = vertex_group_use_vert_sel(ob);
if (subset_count == 0) {
BKE_report(reports, RPT_ERROR, "No vertex groups to operate on");
@@ -2047,7 +2047,7 @@ static int vgroup_limit_total_subset(Object *ob,
{
MDeformVert *dv, **dvert_array = NULL;
int i, dvert_tot = 0;
- const int use_vert_sel = vertex_group_use_vert_sel(ob);
+ const bool use_vert_sel = vertex_group_use_vert_sel(ob);
int remove_tot = 0;
ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index cd5edcdc3f4..3154d5d0985 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -223,8 +223,8 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
/* get the correct image, and scale it */
sima->image = BKE_image_verify_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result");
- /* if we're rendering to full screen, set appropriate hints on image editor
- * so it can restore properly on pressing esc */
+ /* If we're rendering to full screen, set appropriate hints on image editor
+ * so it can restore properly on pressing escape. */
if (sa->full) {
sima->flag |= SI_FULLWINDOW;
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index e30a21d3c6c..16af61f06f3 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -188,51 +188,17 @@ void ED_area_do_refresh(bContext *C, ScrArea *sa)
/**
* \brief Corner widget use for quitting fullscreen.
*/
-static void area_draw_azone_fullscreen(short x1, short y1, short x2, short y2, float alpha)
+static void area_draw_azone_fullscreen(
+ short UNUSED(x1), short UNUSED(y1), short x2, short y2, float alpha)
{
- int x = x2 - ((float)x2 - x1) * 0.5f / UI_DPI_FAC;
- int y = y2 - ((float)y2 - y1) * 0.5f / UI_DPI_FAC;
-
- /* adjust the icon distance from the corner */
- x += 36.0f / UI_DPI_FAC;
- y += 36.0f / UI_DPI_FAC;
-
- /* draws from the left bottom corner of the icon */
- x -= UI_DPI_ICON_SIZE;
- y -= UI_DPI_ICON_SIZE;
-
- alpha = min_ff(alpha, 0.75f);
-
- UI_icon_draw_ex(x, y, ICON_FULLSCREEN_EXIT, 0.7f * U.inv_dpi_fac, 0.0f, alpha, NULL, false);
-
- /* debug drawing :
- * The click_rect is the same as defined in fullscreen_click_rcti_init
- * Keep them both in sync */
-
- if (G.debug_value == 101) {
- rcti click_rect;
- float icon_size = UI_DPI_ICON_SIZE + 7 * UI_DPI_FAC;
-
- BLI_rcti_init(&click_rect, x, x + icon_size, y, y + icon_size);
-
- 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(1.0f, 0.0f, 0.0f, alpha);
- imm_draw_box_wire_2d(pos, click_rect.xmin, click_rect.ymin, click_rect.xmax, click_rect.ymax);
-
- immUniformColor4f(0.0f, 1.0f, 1.0f, alpha);
- immBegin(GPU_PRIM_LINES, 4);
- immVertex2f(pos, click_rect.xmin, click_rect.ymin);
- immVertex2f(pos, click_rect.xmax, click_rect.ymax);
- immVertex2f(pos, click_rect.xmin, click_rect.ymax);
- immVertex2f(pos, click_rect.xmax, click_rect.ymin);
- immEnd();
-
- immUnbindProgram();
- }
+ UI_icon_draw_ex(x2 - U.widget_unit,
+ y2 - U.widget_unit,
+ ICON_FULLSCREEN_EXIT,
+ U.inv_dpi_fac,
+ min_ff(alpha, 0.75f),
+ 0.0f,
+ NULL,
+ false);
}
/**
@@ -368,7 +334,9 @@ static void region_draw_azones(ScrArea *sa, ARegion *ar)
}
}
else if (az->type == AZONE_FULLSCREEN) {
- area_draw_azone_fullscreen(az->x1, az->y1, az->x2, az->y2, az->alpha);
+ if (az->alpha > 0.0f) {
+ area_draw_azone_fullscreen(az->x1, az->y1, az->x2, az->y2, az->alpha);
+ }
}
}
if (!IS_EQF(az->alpha, 0.0f) && ELEM(az->type, AZONE_FULLSCREEN, AZONE_REGION_SCROLL)) {
@@ -906,10 +874,18 @@ static void fullscreen_azone_initialize(ScrArea *sa, ARegion *ar)
az->ar = ar;
az->alpha = 0.0f;
- az->x1 = ar->winrct.xmax - (AZONEFADEOUT - 1);
- az->y1 = ar->winrct.ymax - (AZONEFADEOUT - 1);
- az->x2 = ar->winrct.xmax;
- az->y2 = ar->winrct.ymax;
+ if (U.uiflag2 & USER_REGION_OVERLAP) {
+ const rcti *rect_visible = ED_region_visible_rect(ar);
+ az->x2 = ar->winrct.xmin + rect_visible->xmax;
+ az->y2 = ar->winrct.ymin + rect_visible->ymax;
+ }
+ else {
+ az->x2 = ar->winrct.xmax;
+ az->y2 = ar->winrct.ymax;
+ }
+ az->x1 = az->x2 - AZONEFADEOUT;
+ az->y1 = az->y2 - AZONEFADEOUT;
+
BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
}
@@ -1512,6 +1488,9 @@ static void region_rect_recursive(
if (ar->winx != prev_winx || ar->winy != prev_winy) {
ED_region_tag_redraw(ar);
}
+
+ /* Clear, initialize on demand. */
+ memset(&ar->runtime.visible_rect, 0, sizeof(ar->runtime.visible_rect));
}
static void area_calc_totrct(ScrArea *sa, const rcti *window_rect)
@@ -2810,11 +2789,10 @@ void ED_region_info_draw_multiline(ARegion *ar,
uiStyle *style = UI_style_get_dpi();
int fontid = style->widget.uifont_id;
int scissor[4];
- rcti rect;
int num_lines = 0;
/* background box */
- ED_region_visible_rect(ar, &rect);
+ rcti rect = *ED_region_visible_rect(ar);
/* Box fill entire width or just around text. */
if (!full_redraw) {
@@ -3292,7 +3270,7 @@ void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy)
/* If the area has overlapping regions, it returns visible rect for Region *ar */
/* rect gets returned in local region coordinates */
-void ED_region_visible_rect(ARegion *ar, rcti *rect)
+static void region_visible_rect_calc(ARegion *ar, rcti *rect)
{
ARegion *arn = ar;
@@ -3339,6 +3317,15 @@ void ED_region_visible_rect(ARegion *ar, rcti *rect)
BLI_rcti_translate(rect, -ar->winrct.xmin, -ar->winrct.ymin);
}
+const rcti *ED_region_visible_rect(ARegion *ar)
+{
+ rcti *rect = &ar->runtime.visible_rect;
+ if (rect->xmin == 0 && rect->ymin == 0 && rect->xmax == 0 && rect->ymax == 0) {
+ region_visible_rect_calc(ar, rect);
+ }
+ return rect;
+}
+
/* Cache display helpers */
void ED_region_cache_draw_background(const ARegion *ar)
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index dddc33e3ad0..326bbbd8770 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -1116,7 +1116,7 @@ void ED_screen_full_prevspace(bContext *C, ScrArea *sa)
void ED_screen_restore_temp_type(bContext *C, ScrArea *sa)
{
- /* incase nether functions below run */
+ /* In case nether functions below run. */
ED_area_tag_redraw(sa);
if (sa->flag & AREA_FLAG_TEMP_TYPE) {
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 4fb5e0c1af3..885cd1ee77d 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -696,21 +696,9 @@ static bool actionzone_area_poll(bContext *C)
/* the debug drawing of the click_rect is in area_draw_azone_fullscreen, keep both in sync */
static void fullscreen_click_rcti_init(
- rcti *rect, const short x1, const short y1, const short x2, const short y2)
+ rcti *rect, const short UNUSED(x1), const short UNUSED(y1), const short x2, const short y2)
{
- int x = x2 - ((float)x2 - x1) * 0.5f / UI_DPI_FAC;
- int y = y2 - ((float)y2 - y1) * 0.5f / UI_DPI_FAC;
- float icon_size = UI_DPI_ICON_SIZE + 7 * UI_DPI_FAC;
-
- /* adjust the icon distance from the corner */
- x += 36.0f / UI_DPI_FAC;
- y += 36.0f / UI_DPI_FAC;
-
- /* draws from the left bottom corner of the icon */
- x -= UI_DPI_ICON_SIZE;
- y -= UI_DPI_ICON_SIZE;
-
- BLI_rcti_init(rect, x, x + icon_size, y, y + icon_size);
+ BLI_rcti_init(rect, x2 - U.widget_unit, x2, y2 - U.widget_unit, y2);
}
static bool azone_clipped_rect_calc(const AZone *az, rcti *r_rect_clip)
@@ -3754,7 +3742,7 @@ static int region_quadview_exec(bContext *C, wmOperator *op)
rv3d->viewlock = 0;
rv3d->rflag &= ~RV3D_CLIPPING;
- /* accumulate locks, incase they're mixed */
+ /* Accumulate locks, in case they're mixed. */
for (ar_iter = sa->regionbase.first; ar_iter; ar_iter = ar_iter->next) {
if (ar_iter->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d_iter = ar_iter->regiondata;
@@ -4787,6 +4775,40 @@ static void SCREEN_OT_drivers_editor_show(struct wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Show Info Log Operator
+ * \{ */
+
+static int info_log_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ int sizex = 900 * UI_DPI_FAC;
+ int sizey = 580 * UI_DPI_FAC;
+ int shift_y = 480;
+
+ /* changes context! */
+ if (WM_window_open_temp(C, event->x, event->y + shift_y, sizex, sizey, WM_WINDOW_INFO) != NULL) {
+ return OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Failed to open window!");
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static void SCREEN_OT_info_log_show(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Show Info Log";
+ ot->description = "Show info log in a separate window";
+ ot->idname = "SCREEN_OT_info_log_show";
+
+ /* api callbacks */
+ ot->invoke = info_log_show_invoke;
+ ot->poll = ED_operator_screenactive;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name New Screen Operator
* \{ */
@@ -5253,6 +5275,7 @@ void ED_operatortypes_screen(void)
WM_operatortype_append(SCREEN_OT_screenshot);
WM_operatortype_append(SCREEN_OT_userpref_show);
WM_operatortype_append(SCREEN_OT_drivers_editor_show);
+ WM_operatortype_append(SCREEN_OT_info_log_show);
WM_operatortype_append(SCREEN_OT_region_blend);
WM_operatortype_append(SCREEN_OT_space_type_set_or_cycle);
WM_operatortype_append(SCREEN_OT_space_context_cycle);
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 342d0b6e820..397b2981ace 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -1719,9 +1719,9 @@ static float project_paint_uvpixel_mask(const ProjPaintState *ps,
normalize_v3(no);
}
else {
- /* incase the */
#if 1
- /* normalizing per pixel isn't optimal, we could cache or check ps->*/
+ /* In case the normalizing per pixel isn't optimal,
+ * we could cache or access from evaluated mesh. */
normal_tri_v3(no,
ps->mvert_eval[lt_vtri[0]].co,
ps->mvert_eval[lt_vtri[1]].co,
diff --git a/source/blender/editors/sculpt_paint/paint_image_undo.c b/source/blender/editors/sculpt_paint/paint_image_undo.c
index c7ec4f3f2b9..93dcd3ad0f6 100644
--- a/source/blender/editors/sculpt_paint/paint_image_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_image_undo.c
@@ -75,7 +75,8 @@ typedef struct UndoImageTile {
* adds unnecessary overhead restoring undo steps when most tiles share the same image. */
UndoRefID_Image image_ref;
- short source, use_float;
+ short source;
+ bool use_float;
char gen_type;
bool valid;
@@ -172,7 +173,7 @@ void *image_undo_find_tile(ListBase *undo_tiles,
bool validate)
{
UndoImageTile *tile;
- short use_float = ibuf->rect_float ? 1 : 0;
+ 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 &&
@@ -214,7 +215,7 @@ void *image_undo_push_tile(ListBase *undo_tiles,
{
UndoImageTile *tile;
int allocsize;
- short use_float = ibuf->rect_float ? 1 : 0;
+ const bool use_float = (ibuf->rect_float != NULL);
void *data;
/* check if tile is already pushed */
@@ -315,7 +316,6 @@ static void image_undo_restore_list(ListBase *lb)
IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
for (UndoImageTile *tile = lb->first; tile; tile = tile->next) {
- short use_float;
Image *ima = tile->image_ref.ptr;
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
@@ -341,7 +341,7 @@ static void image_undo_restore_list(ListBase *lb)
continue;
}
- use_float = ibuf->rect_float ? 1 : 0;
+ const bool use_float = (ibuf->rect_float != NULL);
if (use_float != tile->use_float) {
BKE_image_release_ibuf(ima, ibuf, NULL);
@@ -450,7 +450,7 @@ static bool image_undosys_step_encode(struct bContext *C,
tile = tmp_tile;
}
else {
- us->step.data_size += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char));
+ us->step.data_size += allocsize * (tile->use_float ? sizeof(float) : sizeof(char));
tile = tile->next;
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 6144f5751f2..694dae49d30 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -233,6 +233,23 @@ static bool paint_tool_require_location(Brush *brush, ePaintMode mode)
return true;
}
+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)) {
+ return false;
+ }
+ else {
+ return true;
+ }
+ default:
+ break;
+ }
+
+ return true;
+}
+
/* Initialize the stroke cache variants from operator properties */
static bool paint_brush_update(bContext *C,
Brush *brush,
@@ -1188,6 +1205,10 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
bool redraw = false;
float pressure;
+ if (event->type == INBETWEEN_MOUSEMOVE && !paint_tool_require_inbetween_mouse_events(br, mode)) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
/* see if tablet affects event. Line, anchored and drag dot strokes do not support pressure */
pressure = ((br->flag & (BRUSH_LINE | BRUSH_ANCHORED | BRUSH_DRAG_DOT)) ?
1.0f :
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 806b7c471c6..4b9d9a2cc01 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -392,7 +392,7 @@ static int imapaint_pick_face(ViewContext *vc,
/* sample only on the exact position */
ED_view3d_select_id_validate(vc);
- *r_index = DRW_select_buffer_sample_point(mval);
+ *r_index = DRW_select_buffer_sample_point(vc->depsgraph, vc->ar, vc->v3d, mval);
if ((*r_index) == 0 || (*r_index) > (unsigned int)totpoly) {
return 0;
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 72fc08cc38d..4aa9dc8a295 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -580,7 +580,7 @@ typedef struct WPGradient_userData {
BLI_bitmap *vert_visit;
/* options */
- short use_select;
+ bool use_select;
short type;
float weightpaint;
} WPGradient_userData;
@@ -786,7 +786,7 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
data.sco_end = sco_end;
data.sco_line_div = 1.0f / len_v2v2(sco_start, sco_end);
data.def_nr = ob->actdef - 1;
- data.use_select = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL));
+ data.use_select = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
data.vert_cache = vert_cache;
data.vert_visit = NULL;
data.type = RNA_enum_get(op->ptr, "type");
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 285e6aff7d0..440c4d42cae 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -92,6 +92,240 @@
#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 */
+
+static int sculpt_active_vertex_get(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;
+ }
+}
+
+static int sculpt_vertex_count_get(SculptSession *ss)
+{
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES:
+ return ss->totvert;
+ case PBVH_BMESH:
+ return BM_mesh_elem_count(BKE_pbvh_get_bmesh(ss->pbvh), BM_VERT);
+ default:
+ return 0;
+ }
+}
+
+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;
+ }
+}
+
+static 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;
+ }
+}
+
+static void sculpt_vertex_mask_set(SculptSession *ss, int index, float mask)
+{
+ BMVert *v;
+ float *mask_p;
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES:
+ ss->vmask[index] = mask;
+ 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;
+ }
+}
+
+static float sculpt_vertex_mask_get(SculptSession *ss, int index)
+{
+ BMVert *v;
+ float *mask;
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES:
+ return ss->vmask[index];
+ case PBVH_BMESH:
+ 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;
+ }
+}
+
+static void sculpt_vertex_tag_update(SculptSession *ss, int index)
+{
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES:
+ ss->mvert[index].flag |= ME_VERT_PBVH_UPDATE;
+ return;
+ case PBVH_BMESH:
+ return;
+ default:
+ return;
+ }
+}
+
+# define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256
+
+typedef struct SculptVertexNeighborIter {
+ int *neighbors;
+ int size;
+ int capacity;
+
+ int neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY];
+
+ int index;
+ int i;
+} SculptVertexNeighborIter;
+
+static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, int neighbor_index)
+{
+ for (int i = 0; i < iter->size; i++) {
+ if (iter->neighbors[i] == neighbor_index) {
+ return;
+ }
+ }
+
+ if (iter->size >= iter->capacity) {
+ iter->capacity += SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
+
+ if (iter->neighbors == iter->neighbors_fixed) {
+ iter->neighbors = MEM_mallocN(iter->capacity * sizeof(int), "neighbor array");
+ memcpy(iter->neighbors, iter->neighbors_fixed, sizeof(int) * iter->size);
+ }
+ else {
+ iter->neighbors = MEM_reallocN_id(
+ iter->neighbors, iter->capacity * sizeof(int), "neighbor array");
+ }
+ }
+
+ iter->neighbors[iter->size] = neighbor_index;
+ iter->size++;
+}
+
+static void sculpt_vertex_neighbors_get_bmesh(SculptSession *ss,
+ int index,
+ SculptVertexNeighborIter *iter)
+{
+ BMVert *v = BM_vert_at_index(ss->bm, index);
+ BMIter liter;
+ BMLoop *l;
+ iter->size = 0;
+ iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
+ iter->neighbors = iter->neighbors_fixed;
+
+ int i = 0;
+ BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
+ const BMVert *adj_v[2] = {l->prev->v, l->next->v};
+ for (i = 0; i < ARRAY_SIZE(adj_v); i++) {
+ const BMVert *v_other = adj_v[i];
+ if (BM_elem_index_get(v_other) != (int)index) {
+ sculpt_vertex_neighbor_add(iter, BM_elem_index_get(v_other));
+ }
+ }
+ }
+}
+
+static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
+ int index,
+ SculptVertexNeighborIter *iter)
+{
+ int i;
+ MeshElemMap *vert_map = &ss->pmap[(int)index];
+ iter->size = 0;
+ iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
+ iter->neighbors = iter->neighbors_fixed;
+
+ for (i = 0; i < ss->pmap[(int)index].count; i++) {
+ const MPoly *p = &ss->mpoly[vert_map->indices[i]];
+ unsigned f_adj_v[2];
+ 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]);
+ }
+ }
+ }
+ }
+ }
+}
+
+static void sculpt_vertex_neighbors_get(SculptSession *ss,
+ int index,
+ SculptVertexNeighborIter *iter)
+{
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES:
+ sculpt_vertex_neighbors_get_faces(ss, index, iter);
+ return;
+ case PBVH_BMESH:
+ sculpt_vertex_neighbors_get_bmesh(ss, index, iter);
+ return;
+ default:
+ break;
+ }
+}
+
+# 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); \
+ }
+
+#endif /* UNUSED */
+
/** \name Tool Capabilities
*
* Avoid duplicate checks, internal logic only,
@@ -5695,31 +5929,19 @@ static void sculpt_dynamic_topology_disable_ex(
CustomData_free(&me->pdata, me->totpoly);
/* Copy over stored custom data */
- me->totvert = unode->bm_enter_totvert;
- me->totloop = unode->bm_enter_totloop;
- me->totpoly = unode->bm_enter_totpoly;
- me->totedge = unode->bm_enter_totedge;
+ me->totvert = unode->geom_totvert;
+ me->totloop = unode->geom_totloop;
+ me->totpoly = unode->geom_totpoly;
+ me->totedge = unode->geom_totedge;
me->totface = 0;
- CustomData_copy(&unode->bm_enter_vdata,
- &me->vdata,
- CD_MASK_MESH.vmask,
- CD_DUPLICATE,
- unode->bm_enter_totvert);
- CustomData_copy(&unode->bm_enter_edata,
- &me->edata,
- CD_MASK_MESH.emask,
- CD_DUPLICATE,
- unode->bm_enter_totedge);
- CustomData_copy(&unode->bm_enter_ldata,
- &me->ldata,
- CD_MASK_MESH.lmask,
- CD_DUPLICATE,
- unode->bm_enter_totloop);
- CustomData_copy(&unode->bm_enter_pdata,
- &me->pdata,
- CD_MASK_MESH.pmask,
- CD_DUPLICATE,
- unode->bm_enter_totpoly);
+ CustomData_copy(
+ &unode->geom_vdata, &me->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, unode->geom_totvert);
+ CustomData_copy(
+ &unode->geom_edata, &me->edata, CD_MASK_MESH.emask, CD_DUPLICATE, unode->geom_totedge);
+ CustomData_copy(
+ &unode->geom_ldata, &me->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, unode->geom_totloop);
+ CustomData_copy(
+ &unode->geom_pdata, &me->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, unode->geom_totpoly);
BKE_mesh_update_customdata_pointers(me, false);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index e66e1c49685..e646accf108 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -63,6 +63,7 @@ typedef enum {
SCULPT_UNDO_DYNTOPO_BEGIN,
SCULPT_UNDO_DYNTOPO_END,
SCULPT_UNDO_DYNTOPO_SYMMETRIZE,
+ SCULPT_UNDO_GEOMETRY,
} SculptUndoType;
typedef struct SculptUndoNode {
@@ -94,18 +95,20 @@ typedef struct SculptUndoNode {
/* bmesh */
struct BMLogEntry *bm_entry;
bool applied;
- CustomData bm_enter_vdata;
- CustomData bm_enter_edata;
- CustomData bm_enter_ldata;
- CustomData bm_enter_pdata;
- int bm_enter_totvert;
- int bm_enter_totedge;
- int bm_enter_totloop;
- int bm_enter_totpoly;
/* shape keys */
char shapeName[sizeof(((KeyBlock *)0))->name];
+ /* geometry modification operations and bmesh enter data */
+ CustomData geom_vdata;
+ CustomData geom_edata;
+ CustomData geom_ldata;
+ CustomData geom_pdata;
+ int geom_totvert;
+ int geom_totedge;
+ int geom_totloop;
+ int geom_totpoly;
+
size_t undo_size;
} SculptUndoNode;
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index d4c97faa0a6..3a3487227a3 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -44,6 +44,7 @@
#include "BKE_ccg.h"
#include "BKE_context.h"
+#include "BKE_customdata.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BKE_key.h"
@@ -425,6 +426,32 @@ static void sculpt_undo_bmesh_restore_end(bContext *C,
}
}
+static void sculpt_undo_geometry_restore(SculptUndoNode *unode, Object *ob)
+{
+ Mesh *me;
+ sculpt_pbvh_clear(ob);
+ me = ob->data;
+ CustomData_free(&me->vdata, me->totvert);
+ CustomData_free(&me->edata, me->totedge);
+ CustomData_free(&me->fdata, me->totface);
+ CustomData_free(&me->ldata, me->totloop);
+ CustomData_free(&me->pdata, me->totpoly);
+ me->totvert = unode->geom_totvert;
+ me->totedge = unode->geom_totedge;
+ me->totloop = unode->geom_totloop;
+ me->totpoly = unode->geom_totpoly;
+ me->totface = 0;
+ CustomData_copy(
+ &unode->geom_vdata, &me->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, unode->geom_totvert);
+ CustomData_copy(
+ &unode->geom_edata, &me->edata, CD_MASK_MESH.emask, CD_DUPLICATE, unode->geom_totedge);
+ CustomData_copy(
+ &unode->geom_ldata, &me->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, unode->geom_totloop);
+ CustomData_copy(
+ &unode->geom_pdata, &me->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, unode->geom_totpoly);
+ BKE_mesh_update_customdata_pointers(me, false);
+}
+
/* Handle all dynamic-topology updates
*
* Returns true if this was a dynamic-topology undo step, otherwise
@@ -442,7 +469,6 @@ static int sculpt_undo_bmesh_restore(bContext *C,
case SCULPT_UNDO_DYNTOPO_END:
sculpt_undo_bmesh_restore_end(C, unode, ob, ss);
return true;
-
default:
if (ss->bm_log) {
sculpt_undo_bmesh_restore_generic(C, unode, ob, ss);
@@ -480,6 +506,24 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
+ if (lb->first) {
+ unode = lb->first;
+ if (unode->type == SCULPT_UNDO_GEOMETRY) {
+ if (unode->applied) {
+ sculpt_undo_geometry_restore(unode->next, ob);
+ unode->next->applied = true;
+ unode->applied = false;
+ }
+ else {
+ sculpt_undo_geometry_restore(unode, ob);
+ unode->next->applied = false;
+ unode->applied = true;
+ }
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask);
+ return;
+ }
+ }
+
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask);
if (lb->first && sculpt_undo_bmesh_restore(C, lb->first, ob, ss)) {
@@ -487,6 +531,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
}
for (unode = lb->first; unode; unode = unode->next) {
+
if (!STREQ(unode->idname, ob->id.name)) {
continue;
}
@@ -530,6 +575,8 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
BLI_assert(!"Dynamic topology should've already been handled");
break;
+ case SCULPT_UNDO_GEOMETRY:
+ break;
}
}
@@ -617,17 +664,17 @@ static void sculpt_undo_free_list(ListBase *lb)
BM_log_entry_drop(unode->bm_entry);
}
- if (unode->bm_enter_totvert) {
- CustomData_free(&unode->bm_enter_vdata, unode->bm_enter_totvert);
+ if (unode->geom_totvert) {
+ CustomData_free(&unode->geom_vdata, unode->geom_totvert);
}
- if (unode->bm_enter_totedge) {
- CustomData_free(&unode->bm_enter_edata, unode->bm_enter_totedge);
+ if (unode->geom_totedge) {
+ CustomData_free(&unode->geom_edata, unode->geom_totedge);
}
- if (unode->bm_enter_totloop) {
- CustomData_free(&unode->bm_enter_ldata, unode->bm_enter_totloop);
+ if (unode->geom_totloop) {
+ CustomData_free(&unode->geom_ldata, unode->geom_totloop);
}
- if (unode->bm_enter_totpoly) {
- CustomData_free(&unode->bm_enter_pdata, unode->bm_enter_totpoly);
+ if (unode->geom_totpoly) {
+ CustomData_free(&unode->geom_pdata, unode->geom_totpoly);
}
MEM_freeN(unode);
@@ -743,6 +790,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
case SCULPT_UNDO_DYNTOPO_END:
case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
BLI_assert(!"Dynamic topology should've already been handled");
+ case SCULPT_UNDO_GEOMETRY:
break;
}
@@ -824,6 +872,36 @@ static void sculpt_undo_store_mask(Object *ob, SculptUndoNode *unode)
BKE_pbvh_vertex_iter_end;
}
+static SculptUndoNode *sculpt_undo_geometry_push(Object *ob, SculptUndoType type)
+{
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
+ Mesh *me = ob->data;
+ bool applied;
+
+ SculptUndoNode *unode = usculpt->nodes.first;
+ /* Store the original mesh in the first node, modifications in the second */
+ applied = unode != NULL;
+
+ unode = MEM_callocN(sizeof(*unode), __func__);
+
+ BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
+ unode->type = type;
+ unode->applied = applied;
+
+ CustomData_copy(&me->vdata, &unode->geom_vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, me->totvert);
+ CustomData_copy(&me->edata, &unode->geom_edata, CD_MASK_MESH.emask, CD_DUPLICATE, me->totedge);
+ CustomData_copy(&me->ldata, &unode->geom_ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, me->totloop);
+ CustomData_copy(&me->pdata, &unode->geom_pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, me->totpoly);
+ unode->geom_totvert = me->totvert;
+ unode->geom_totedge = me->totedge;
+ unode->geom_totloop = me->totloop;
+ unode->geom_totpoly = me->totpoly;
+
+ BLI_addtail(&usculpt->nodes, unode);
+
+ return unode;
+}
+
static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, SculptUndoType type)
{
UndoSculpt *usculpt = sculpt_undo_get_nodes();
@@ -852,17 +930,17 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
* (converting polys to triangles) that the BMLog can't
* fully restore from */
CustomData_copy(
- &me->vdata, &unode->bm_enter_vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, me->totvert);
+ &me->vdata, &unode->geom_vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, me->totvert);
CustomData_copy(
- &me->edata, &unode->bm_enter_edata, CD_MASK_MESH.emask, CD_DUPLICATE, me->totedge);
+ &me->edata, &unode->geom_edata, CD_MASK_MESH.emask, CD_DUPLICATE, me->totedge);
CustomData_copy(
- &me->ldata, &unode->bm_enter_ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, me->totloop);
+ &me->ldata, &unode->geom_ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, me->totloop);
CustomData_copy(
- &me->pdata, &unode->bm_enter_pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, me->totpoly);
- unode->bm_enter_totvert = me->totvert;
- unode->bm_enter_totedge = me->totedge;
- unode->bm_enter_totloop = me->totloop;
- unode->bm_enter_totpoly = me->totpoly;
+ &me->pdata, &unode->geom_pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, me->totpoly);
+ unode->geom_totvert = me->totvert;
+ unode->geom_totedge = me->totedge;
+ unode->geom_totloop = me->totloop;
+ unode->geom_totpoly = me->totpoly;
unode->bm_entry = BM_log_entry_add(ss->bm_log);
BM_log_all_added(ss->bm, ss->bm_log);
@@ -906,6 +984,7 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
case SCULPT_UNDO_DYNTOPO_BEGIN:
case SCULPT_UNDO_DYNTOPO_END:
case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
+ case SCULPT_UNDO_GEOMETRY:
break;
}
}
@@ -928,6 +1007,11 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
BLI_thread_unlock(LOCK_CUSTOM1);
return unode;
}
+ else if (type == SCULPT_UNDO_GEOMETRY) {
+ unode = sculpt_undo_geometry_push(ob, type);
+ BLI_thread_unlock(LOCK_CUSTOM1);
+ return unode;
+ }
else if ((unode = sculpt_undo_get_node(node))) {
BLI_thread_unlock(LOCK_CUSTOM1);
return unode;
@@ -967,6 +1051,7 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
case SCULPT_UNDO_DYNTOPO_END:
case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
BLI_assert(!"Dynamic topology should've already been handled");
+ case SCULPT_UNDO_GEOMETRY:
break;
}
@@ -1163,6 +1248,18 @@ static void sculpt_undosys_step_free(UndoStep *us_p)
sculpt_undo_free_list(&us->data.nodes);
}
+void ED_sculpt_undo_geometry_begin(struct Object *ob)
+{
+ sculpt_undo_push_begin("voxel remesh");
+ sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_GEOMETRY);
+}
+
+void ED_sculpt_undo_geometry_end(struct Object *ob)
+{
+ sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_GEOMETRY);
+ sculpt_undo_push_end();
+}
+
/* Export for ED_undo_sys. */
void ED_sculpt_undosys_type(UndoType *ut)
{
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index fde8b8f85f8..bb381e0dd1e 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -785,11 +785,11 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
SpaceProperties *sbuts = CTX_wm_space_properties(C);
ButsContextPath *path = sbuts ? sbuts->path : NULL;
- if (sbuts->mainb == BCONTEXT_TOOL) {
+ if (!path) {
return 0;
}
- if (!path) {
+ if (sbuts->mainb == BCONTEXT_TOOL) {
return 0;
}
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index 97a3c7f2480..9a2b0d95c20 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -156,9 +156,8 @@ void ED_image_draw_info(Scene *scene,
char str[256];
int dx = 6;
/* local coordinate visible rect inside region, to accommodate overlapping ui */
- rcti rect;
- ED_region_visible_rect(ar, &rect);
- const int ymin = rect.ymin;
+ const rcti *rect = ED_region_visible_rect(ar);
+ const int ymin = rect->ymin;
const int dy = ymin + 0.3f * UI_UNIT_Y;
/* text colors */
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 17f808f727d..5fa4fe3e077 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -501,11 +501,10 @@ static void image_main_region_set_view2d(SpaceImage *sima, ARegion *ar)
int winy = BLI_rcti_size_y(&ar->winrct) + 1;
/* For region overlap, move center so image doesn't overlap header. */
- rcti visible_rect;
- ED_region_visible_rect(ar, &visible_rect);
- const int visible_winy = BLI_rcti_size_y(&visible_rect) + 1;
+ const rcti *visible_rect = ED_region_visible_rect(ar);
+ const int visible_winy = BLI_rcti_size_y(visible_rect) + 1;
int visible_centerx = 0;
- int visible_centery = visible_rect.ymin + (visible_winy - winy) / 2;
+ int visible_centery = visible_rect->ymin + (visible_winy - winy) / 2;
ar->v2d.tot.xmin = 0;
ar->v2d.tot.ymin = 0;
@@ -587,7 +586,7 @@ static void image_main_region_draw(const bContext *C, ARegion *ar)
float col[3];
/* XXX This is in order to draw UI batches with the DRW
- * olg context since we now use it for drawing the entire area */
+ * old context since we now use it for drawing the entire area. */
gpu_batch_presets_reset();
GPUViewport *viewport =
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index 946274de882..106edc290d5 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -574,7 +574,7 @@ void ED_info_stats_clear(ViewLayer *view_layer)
const char *ED_info_stats_string(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
- /* Loopin through dependency graph when interface is locked in not safe.
+ /* Looping through dependency graph when interface is locked in not safe.
* Thew interface is marked as locked when jobs wants to modify the
* dependency graph. */
wmWindowManager *wm = bmain->wm.first;
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index 03c83305618..f8c30f9a688 100644
--- a/source/blender/editors/space_node/CMakeLists.txt
+++ b/source/blender/editors/space_node/CMakeLists.txt
@@ -71,6 +71,10 @@ if(WITH_COMPOSITOR)
add_definitions(-DWITH_COMPOSITOR)
endif()
+if(WITH_OPENIMAGEDENOISE)
+ add_definitions(-DWITH_OPENIMAGEDENOISE)
+endif()
+
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_editor_space_node "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index e63c8331f18..c3ecc34aaf4 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -249,6 +249,11 @@ static void node_buts_texture(uiLayout *layout, bContext *UNUSED(C), PointerRNA
}
}
+static void node_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "clamp", 0, NULL, ICON_NONE);
+}
+
static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
@@ -1209,6 +1214,9 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_VALTORGB:
ntype->draw_buttons = node_buts_colorramp;
break;
+ case SH_NODE_MAP_RANGE:
+ ntype->draw_buttons = node_buts_map_range;
+ break;
case SH_NODE_MATH:
ntype->draw_buttons = node_buts_math;
break;
@@ -2683,6 +2691,15 @@ static void node_composit_buts_brightcontrast(uiLayout *layout,
uiItemR(layout, ptr, "use_premultiply", 0, NULL, ICON_NONE);
}
+static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+#ifndef WITH_OPENIMAGEDENOISE
+ uiItemL(layout, IFACE_("Disabled, built without OpenImageDenoise"), ICON_ERROR);
+#endif
+
+ uiItemR(layout, ptr, "use_hdr", 0, NULL, ICON_NONE);
+}
+
/* only once called */
static void node_composit_set_butfunc(bNodeType *ntype)
{
@@ -2916,6 +2933,10 @@ static void node_composit_set_butfunc(bNodeType *ntype)
break;
case CMP_NODE_BRIGHTCONTRAST:
ntype->draw_buttons = node_composit_buts_brightcontrast;
+ break;
+ case CMP_NODE_DENOISE:
+ ntype->draw_buttons = node_composit_buts_denoise;
+ break;
}
}
@@ -3333,7 +3354,18 @@ static void std_node_socket_draw(
uiItemR(layout, ptr, "default_value", 0, text, 0);
break;
case SOCK_VECTOR:
- uiTemplateComponentMenu(layout, ptr, "default_value", text);
+ if (sock->flag & SOCK_COMPACT) {
+ uiTemplateComponentMenu(layout, ptr, "default_value", text);
+ }
+ else {
+ if (sock->typeinfo->subtype == PROP_DIRECTION) {
+ uiItemR(layout, ptr, "default_value", 0, "", ICON_NONE);
+ }
+ else {
+ uiLayout *column = uiLayoutColumn(layout, true);
+ uiItemR(column, ptr, "default_value", 0, text, ICON_NONE);
+ }
+ }
break;
case SOCK_RGBA:
case SOCK_STRING: {
diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt
index d235dd47136..616915dbc2c 100644
--- a/source/blender/editors/space_outliner/CMakeLists.txt
+++ b/source/blender/editors/space_outliner/CMakeLists.txt
@@ -41,6 +41,7 @@ set(SRC
outliner_edit.c
outliner_ops.c
outliner_select.c
+ outliner_sync.c
outliner_tools.c
outliner_tree.c
outliner_utils.c
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c
index d8276aa2bbc..6031ba5cffc 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.c
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.c
@@ -326,38 +326,57 @@ static bool parent_drop_poll(bContext *C,
return false;
}
-static int parent_drop_exec(bContext *C, wmOperator *op)
+static void parent_drop_set_parents(
+ bContext *C, ReportList *reports, wmDragID *drag, Object *parent, short parent_type)
{
- Object *par = NULL, *ob = NULL;
Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- int partype = -1;
- char parname[MAX_NAME], childname[MAX_NAME];
+ SpaceOutliner *soops = CTX_wm_space_outliner(C);
- partype = RNA_enum_get(op->ptr, "type");
- RNA_string_get(op->ptr, "parent", parname);
- par = (Object *)BKE_libblock_find_name(bmain, ID_OB, parname);
- RNA_string_get(op->ptr, "child", childname);
- ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, childname);
+ TreeElement *te = outliner_find_id(soops, &soops->tree, &parent->id);
+ Scene *scene = (Scene *)outliner_search_back(soops, te, ID_SCE);
- if (ID_IS_LINKED(ob)) {
- BKE_report(op->reports, RPT_INFO, "Can't edit library linked object");
- return OPERATOR_CANCELLED;
+ if (scene == NULL) {
+ /* currently outliner organized in a way, that if there's no parent scene
+ * element for object it means that all displayed objects belong to
+ * active scene and parenting them is allowed (sergey)
+ */
+
+ scene = CTX_data_scene(C);
}
- ED_object_parent_set(op->reports, C, scene, ob, par, partype, false, false, NULL);
+ bool parent_set = false;
+ bool linked_objects = false;
- DEG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
+ for (wmDragID *drag_id = drag; drag_id; drag_id = drag_id->next) {
+ if (GS(drag_id->id->name) == ID_OB) {
+ Object *object = (Object *)drag_id->id;
- return OPERATOR_FINISHED;
+ /* Do nothing to linked data */
+ if (ID_IS_LINKED(object)) {
+ linked_objects = true;
+ continue;
+ }
+
+ if (ED_object_parent_set(
+ reports, C, scene, object, parent, parent_type, false, false, NULL)) {
+ parent_set = true;
+ }
+ }
+ }
+
+ if (linked_objects) {
+ BKE_report(reports, RPT_INFO, "Can't edit library linked object(s)");
+ }
+
+ if (parent_set) {
+ DEG_relations_tag_update(bmain);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
+ }
}
static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Main *bmain = CTX_data_main(C);
- SpaceOutliner *soops = CTX_wm_space_outliner(C);
TreeElement *te = outliner_drop_find(C, event);
TreeStoreElem *tselem = te ? TREESTORE(te) : NULL;
@@ -374,107 +393,15 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (ob == par) {
return OPERATOR_CANCELLED;
}
- if (ID_IS_LINKED(ob)) {
- BKE_report(op->reports, RPT_INFO, "Can't edit library linked object");
- return OPERATOR_CANCELLED;
- }
-
- char childname[MAX_NAME];
- char parname[MAX_NAME];
- STRNCPY(childname, ob->id.name + 2);
- STRNCPY(parname, par->id.name + 2);
- RNA_string_set(op->ptr, "child", childname);
- RNA_string_set(op->ptr, "parent", parname);
- Scene *scene = (Scene *)outliner_search_back(soops, te, ID_SCE);
-
- if (scene == NULL) {
- /* currently outlier organized in a way, that if there's no parent scene
- * element for object it means that all displayed objects belong to
- * active scene and parenting them is allowed (sergey)
- */
-
- scene = CTX_data_scene(C);
+ if (event->custom != EVT_DATA_DRAGDROP) {
+ return OPERATOR_CANCELLED;
}
- if ((par->type != OB_ARMATURE) && (par->type != OB_CURVE) && (par->type != OB_LATTICE)) {
- int partype = 0;
- if (ED_object_parent_set(op->reports, C, scene, ob, par, partype, false, false, NULL)) {
- DEG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
- }
- }
- else {
- /* Menu creation */
- wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_parent_drop", false);
- uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Set Parent To"), ICON_NONE);
- uiLayout *layout = UI_popup_menu_layout(pup);
- PointerRNA ptr;
-
- /* Cannot use uiItemEnumO()... have multiple properties to set. */
- uiItemFullO_ptr(layout, ot, IFACE_("Object"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
- RNA_string_set(&ptr, "parent", parname);
- RNA_string_set(&ptr, "child", childname);
- RNA_enum_set(&ptr, "type", PAR_OBJECT);
-
- /* par becomes parent, make the associated menus */
- if (par->type == OB_ARMATURE) {
- uiItemFullO_ptr(layout, ot, IFACE_("Armature Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
- RNA_string_set(&ptr, "parent", parname);
- RNA_string_set(&ptr, "child", childname);
- RNA_enum_set(&ptr, "type", PAR_ARMATURE);
-
- uiItemFullO_ptr(
- layout, ot, IFACE_(" With Empty Groups"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
- RNA_string_set(&ptr, "parent", parname);
- RNA_string_set(&ptr, "child", childname);
- RNA_enum_set(&ptr, "type", PAR_ARMATURE_NAME);
-
- uiItemFullO_ptr(
- layout, ot, IFACE_(" With Envelope Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
- RNA_string_set(&ptr, "parent", parname);
- RNA_string_set(&ptr, "child", childname);
- RNA_enum_set(&ptr, "type", PAR_ARMATURE_ENVELOPE);
-
- uiItemFullO_ptr(
- layout, ot, IFACE_(" With Automatic Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
- RNA_string_set(&ptr, "parent", parname);
- RNA_string_set(&ptr, "child", childname);
- RNA_enum_set(&ptr, "type", PAR_ARMATURE_AUTO);
-
- uiItemFullO_ptr(layout, ot, IFACE_("Bone"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
- RNA_string_set(&ptr, "parent", parname);
- RNA_string_set(&ptr, "child", childname);
- RNA_enum_set(&ptr, "type", PAR_BONE);
- }
- else if (par->type == OB_CURVE) {
- uiItemFullO_ptr(layout, ot, IFACE_("Curve Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
- RNA_string_set(&ptr, "parent", parname);
- RNA_string_set(&ptr, "child", childname);
- RNA_enum_set(&ptr, "type", PAR_CURVE);
-
- uiItemFullO_ptr(layout, ot, IFACE_("Follow Path"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
- RNA_string_set(&ptr, "parent", parname);
- RNA_string_set(&ptr, "child", childname);
- RNA_enum_set(&ptr, "type", PAR_FOLLOW);
-
- uiItemFullO_ptr(layout, ot, IFACE_("Path Constraint"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
- RNA_string_set(&ptr, "parent", parname);
- RNA_string_set(&ptr, "child", childname);
- RNA_enum_set(&ptr, "type", PAR_PATH_CONST);
- }
- else if (par->type == OB_LATTICE) {
- uiItemFullO_ptr(layout, ot, IFACE_("Lattice Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
- RNA_string_set(&ptr, "parent", parname);
- RNA_string_set(&ptr, "child", childname);
- RNA_enum_set(&ptr, "type", PAR_LATTICE);
- }
-
- UI_popup_menu_end(C, pup);
+ ListBase *lb = event->customdata;
+ wmDrag *drag = lb->first;
- return OPERATOR_INTERFACE;
- }
+ parent_drop_set_parents(C, op->reports, drag->ids.first, par, PAR_OBJECT);
return OPERATOR_FINISHED;
}
@@ -488,17 +415,11 @@ void OUTLINER_OT_parent_drop(wmOperatorType *ot)
/* api callbacks */
ot->invoke = parent_drop_invoke;
- ot->exec = parent_drop_exec;
ot->poll = ED_operator_outliner_active;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
-
- /* properties */
- RNA_def_string(ot->srna, "child", "Object", MAX_NAME, "Child", "Child Object");
- RNA_def_string(ot->srna, "parent", "Object", MAX_NAME, "Parent", "Parent Object");
- RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", "");
}
/* ******************** Parent Clear Operator *********************** */
@@ -549,13 +470,21 @@ static bool parent_clear_poll(bContext *C,
static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
Main *bmain = CTX_data_main(C);
- Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB);
- if (ob == NULL) {
+ if (event->custom != EVT_DATA_DRAGDROP) {
return OPERATOR_CANCELLED;
}
- ED_object_parent_clear(ob, 0);
+ ListBase *lb = event->customdata;
+ wmDrag *drag = lb->first;
+
+ for (wmDragID *drag_id = drag->ids.first; drag_id; drag_id = drag_id->next) {
+ if (GS(drag_id->id->name) == ID_OB) {
+ Object *object = (Object *)drag_id->id;
+
+ ED_object_parent_clear(object, 0);
+ }
+ }
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -966,6 +895,12 @@ static int outliner_item_drag_drop_invoke(bContext *C,
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
}
+ float view_mval[2];
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
+ if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) {
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
+
wmDrag *drag = WM_event_start_drag(C, data.icon, WM_DRAG_ID, NULL, 0.0, WM_DRAG_NOP);
if (ELEM(GS(data.drag_id->name), ID_OB, ID_GR)) {
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index e4881a6f13d..9c45fb15f6b 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -31,6 +31,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_constraint_types.h"
#include "DNA_object_force_types.h"
#include "BLI_math.h"
@@ -60,6 +61,7 @@
#include "ED_armature.h"
#include "ED_keyframing.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "WM_api.h"
@@ -848,6 +850,7 @@ typedef struct RestrictProperties {
PropertyRNA *layer_collection_holdout, *layer_collection_indirect_only,
*layer_collection_hide_viewport;
PropertyRNA *modifier_show_viewport, *modifier_show_render;
+ PropertyRNA *constraint_enable;
} RestrictProperties;
/* We don't care about the value of the property
@@ -865,6 +868,7 @@ typedef struct RestrictPropertiesActive {
bool layer_collection_hide_viewport;
bool modifier_show_viewport;
bool modifier_show_render;
+ bool constraint_enable;
} RestrictPropertiesActive;
static void outliner_restrict_properties_enable_collection_set(
@@ -878,6 +882,7 @@ static void outliner_restrict_properties_enable_collection_set(
props_active->layer_collection_indirect_only = false;
props_active->object_hide_render = false;
props_active->modifier_show_render = false;
+ props_active->constraint_enable = false;
}
}
@@ -891,6 +896,7 @@ static void outliner_restrict_properties_enable_collection_set(
props_active->object_hide_viewport = false;
props_active->base_hide_viewport = false;
props_active->modifier_show_viewport = false;
+ props_active->constraint_enable = false;
}
}
@@ -995,6 +1001,8 @@ static void outliner_draw_restrictbuts(uiBlock *block,
props.modifier_show_viewport = RNA_struct_type_find_property(&RNA_Modifier, "show_viewport");
props.modifier_show_render = RNA_struct_type_find_property(&RNA_Modifier, "show_render");
+ props.constraint_enable = RNA_struct_type_find_property(&RNA_Constraint, "mute");
+
props.initialized = true;
}
@@ -1181,6 +1189,35 @@ static void outliner_draw_restrictbuts(uiBlock *block,
}
}
}
+ else if (tselem->type == TSE_CONSTRAINT) {
+ bConstraint *con = (bConstraint *)te->directdata;
+
+ PointerRNA ptr;
+ RNA_pointer_create(tselem->id, &RNA_Constraint, con, &ptr);
+
+ if (soops->show_restrict_flags & SO_RESTRICT_HIDE) {
+ bt = uiDefIconButR_prop(block,
+ UI_BTYPE_ICON_TOGGLE,
+ 0,
+ 0,
+ (int)(ar->v2d.cur.xmax - restrict_offsets.hide),
+ te->ys,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ &ptr,
+ props.constraint_enable,
+ -1,
+ 0,
+ 0,
+ -1,
+ -1,
+ NULL);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+ if (!props_active.constraint_enable) {
+ UI_but_flag_enable(bt, UI_BUT_INACTIVE);
+ }
+ }
+ }
else if (tselem->type == TSE_MODIFIER) {
ModifierData *md = (ModifierData *)te->directdata;
@@ -1878,6 +1915,9 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case TSE_DEFGROUP_BASE:
data.icon = ICON_GROUP_VERTEX;
break;
+ case TSE_DEFGROUP:
+ data.icon = ICON_GROUP_VERTEX;
+ break;
case TSE_BONE:
case TSE_EBONE:
data.icon = ICON_BONE_DATA;
@@ -1885,6 +1925,100 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case TSE_CONSTRAINT_BASE:
data.icon = ICON_CONSTRAINT;
break;
+ case TSE_CONSTRAINT: {
+ bConstraint *con = te->directdata;
+ switch ((eBConstraint_Types)con->type) {
+ case CONSTRAINT_TYPE_CAMERASOLVER:
+ data.icon = ICON_CON_CAMERASOLVER;
+ break;
+ case CONSTRAINT_TYPE_FOLLOWTRACK:
+ data.icon = ICON_CON_FOLLOWTRACK;
+ break;
+ case CONSTRAINT_TYPE_OBJECTSOLVER:
+ data.icon = ICON_CON_OBJECTSOLVER;
+ break;
+ case CONSTRAINT_TYPE_LOCLIKE:
+ data.icon = ICON_CON_LOCLIKE;
+ break;
+ case CONSTRAINT_TYPE_ROTLIKE:
+ data.icon = ICON_CON_ROTLIKE;
+ break;
+ case CONSTRAINT_TYPE_SIZELIKE:
+ data.icon = ICON_CON_SIZELIKE;
+ break;
+ case CONSTRAINT_TYPE_TRANSLIKE:
+ data.icon = ICON_CON_TRANSLIKE;
+ break;
+ case CONSTRAINT_TYPE_DISTLIMIT:
+ data.icon = ICON_CON_DISTLIMIT;
+ break;
+ case CONSTRAINT_TYPE_LOCLIMIT:
+ data.icon = ICON_CON_LOCLIMIT;
+ break;
+ case CONSTRAINT_TYPE_ROTLIMIT:
+ data.icon = ICON_CON_ROTLIMIT;
+ break;
+ case CONSTRAINT_TYPE_SIZELIMIT:
+ data.icon = ICON_CON_SIZELIMIT;
+ break;
+ case CONSTRAINT_TYPE_SAMEVOL:
+ data.icon = ICON_CON_SAMEVOL;
+ break;
+ case CONSTRAINT_TYPE_TRANSFORM:
+ data.icon = ICON_CON_TRANSFORM;
+ break;
+ case CONSTRAINT_TYPE_TRANSFORM_CACHE:
+ data.icon = ICON_CON_TRANSFORM_CACHE;
+ break;
+ case CONSTRAINT_TYPE_CLAMPTO:
+ data.icon = ICON_CON_CLAMPTO;
+ break;
+ case CONSTRAINT_TYPE_DAMPTRACK:
+ data.icon = ICON_CON_TRACKTO;
+ break;
+ case CONSTRAINT_TYPE_KINEMATIC:
+ data.icon = ICON_CON_KINEMATIC;
+ break;
+ case CONSTRAINT_TYPE_LOCKTRACK:
+ data.icon = ICON_CON_LOCKTRACK;
+ break;
+ case CONSTRAINT_TYPE_SPLINEIK:
+ data.icon = ICON_CON_SPLINEIK;
+ break;
+ case CONSTRAINT_TYPE_STRETCHTO:
+ data.icon = ICON_CON_STRETCHTO;
+ break;
+ case CONSTRAINT_TYPE_TRACKTO:
+ data.icon = ICON_CON_TRACKTO;
+ break;
+ case CONSTRAINT_TYPE_ACTION:
+ data.icon = ICON_ACTION;
+ break;
+ case CONSTRAINT_TYPE_ARMATURE:
+ data.icon = ICON_CON_ARMATURE;
+ break;
+ case CONSTRAINT_TYPE_CHILDOF:
+ data.icon = ICON_CON_CHILDOF;
+ break;
+ case CONSTRAINT_TYPE_MINMAX:
+ data.icon = ICON_CON_FLOOR;
+ break;
+ case CONSTRAINT_TYPE_FOLLOWPATH:
+ data.icon = ICON_CON_FOLLOWPATH;
+ break;
+ case CONSTRAINT_TYPE_PIVOT:
+ data.icon = ICON_CON_PIVOT;
+ break;
+ case CONSTRAINT_TYPE_SHRINKWRAP:
+ data.icon = ICON_CON_SHRINKWRAP;
+ break;
+
+ default:
+ data.icon = ICON_DOT;
+ break;
+ }
+ break;
+ }
case TSE_MODIFIER_BASE:
data.icon = ICON_MODIFIER_DATA;
break;
@@ -2137,23 +2271,57 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
data.icon = ICON_GROUP_BONE;
break;
case TSE_SEQUENCE:
- if (te->idcode == SEQ_TYPE_MOVIE) {
- data.icon = ICON_SEQUENCE;
- }
- else if (te->idcode == SEQ_TYPE_META) {
- data.icon = ICON_DOT;
- }
- else if (te->idcode == SEQ_TYPE_SCENE) {
- data.icon = ICON_SCENE;
- }
- else if (te->idcode == SEQ_TYPE_SOUND_RAM) {
- data.icon = ICON_SOUND;
- }
- else if (te->idcode == SEQ_TYPE_IMAGE) {
- data.icon = ICON_IMAGE;
- }
- else {
- data.icon = ICON_PARTICLES;
+ switch (te->idcode) {
+ case SEQ_TYPE_SCENE:
+ data.icon = ICON_SCENE_DATA;
+ break;
+ case SEQ_TYPE_MOVIECLIP:
+ data.icon = ICON_TRACKER;
+ break;
+ case SEQ_TYPE_MASK:
+ data.icon = ICON_MOD_MASK;
+ break;
+ case SEQ_TYPE_MOVIE:
+ data.icon = ICON_FILE_MOVIE;
+ break;
+ case SEQ_TYPE_SOUND_RAM:
+ data.icon = ICON_SOUND;
+ break;
+ case SEQ_TYPE_IMAGE:
+ data.icon = ICON_FILE_IMAGE;
+ break;
+ case SEQ_TYPE_COLOR:
+ case SEQ_TYPE_ADJUSTMENT:
+ data.icon = ICON_COLOR;
+ break;
+ case SEQ_TYPE_TEXT:
+ data.icon = ICON_FONT_DATA;
+ break;
+ case SEQ_TYPE_ADD:
+ case SEQ_TYPE_SUB:
+ case SEQ_TYPE_MUL:
+ case SEQ_TYPE_OVERDROP:
+ case SEQ_TYPE_ALPHAOVER:
+ case SEQ_TYPE_ALPHAUNDER:
+ case SEQ_TYPE_COLORMIX:
+ case SEQ_TYPE_MULTICAM:
+ case SEQ_TYPE_TRANSFORM:
+ case SEQ_TYPE_SPEED:
+ case SEQ_TYPE_GLOW:
+ case SEQ_TYPE_GAUSSIAN_BLUR:
+ data.icon = ICON_SHADERFX;
+ break;
+ case SEQ_TYPE_CROSS:
+ case SEQ_TYPE_GAMCROSS:
+ case SEQ_TYPE_WIPE:
+ data.icon = ICON_ARROW_LEFTRIGHT;
+ break;
+ case SEQ_TYPE_META:
+ data.icon = ICON_DOT;
+ break;
+ default:
+ data.icon = ICON_DOT;
+ break;
}
break;
case TSE_SEQ_STRIP:
@@ -2459,7 +2627,11 @@ static void tselem_draw_icon(uiBlock *block,
return;
}
+ /* Icon is covered by restrict buttons */
if (!is_clickable || x >= xmax) {
+ /* Reduce alpha to match icon buttons */
+ alpha *= 0.8f;
+
/* placement of icons, copied from interface_widgets.c */
float aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT;
x += 2.0f * aspect;
@@ -2567,7 +2739,6 @@ static void outliner_draw_iconrow_doit(uiBlock *block,
float ufac = UI_UNIT_X / 20.0f;
float icon_color[4], icon_border[4];
outliner_icon_background_colors(icon_color, icon_border);
- icon_color[3] *= alpha_fac;
if (active == OL_DRAWSEL_ACTIVE) {
UI_GetThemeColor4fv(TH_EDITED_OBJECT, icon_color);
icon_border[3] = 0.3f;
@@ -2592,6 +2763,9 @@ static void outliner_draw_iconrow_doit(uiBlock *block,
GPU_blend(true); /* Roundbox disables. */
}
+ if (tselem->flag & TSE_HIGHLIGHTED) {
+ alpha_fac += 0.5;
+ }
tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, alpha_fac, false);
te->xs = *offsx;
te->ys = ys;
@@ -2599,7 +2773,12 @@ static void outliner_draw_iconrow_doit(uiBlock *block,
if (num_elements > 1) {
outliner_draw_iconrow_number(fstyle, *offsx, ys, num_elements);
+ te->flag |= TE_ICONROW_MERGED;
+ }
+ else {
+ te->flag |= TE_ICONROW;
}
+
(*offsx) += UI_UNIT_X;
}
@@ -2609,7 +2788,7 @@ static void outliner_draw_iconrow_doit(uiBlock *block,
* We use a continuum of indices until we get to the object data-blocks
* and we then make room for the object types.
*/
-static int tree_element_id_type_to_index(TreeElement *te)
+int tree_element_id_type_to_index(TreeElement *te)
{
TreeStoreElem *tselem = TREESTORE(te);
@@ -2739,7 +2918,7 @@ static void outliner_set_coord_tree_element(TreeElement *te, int startx, int sta
TreeElement *ten;
/* closed items may be displayed in row of parent, don't change their coordinate! */
- if ((te->flag & TE_ICONROW) == 0) {
+ if ((te->flag & TE_ICONROW) == 0 && (te->flag & TE_ICONROW_MERGED) == 0) {
/* store coord and continue, we need coordinates for elements outside view too */
te->xs = startx;
te->ys = starty;
@@ -3193,6 +3372,7 @@ static void outliner_draw_highlights_recursive(unsigned pos,
const SpaceOutliner *soops,
const ListBase *lb,
const float col_selection[4],
+ const float col_active[4],
const float col_highlight[4],
const float col_searchmatch[4],
int start_x,
@@ -3206,7 +3386,11 @@ static void outliner_draw_highlights_recursive(unsigned pos,
const int start_y = *io_start_y;
/* selection status */
- if (tselem->flag & TSE_SELECTED) {
+ if ((tselem->flag & TSE_ACTIVE) && (tselem->flag & TSE_SELECTED)) {
+ immUniformColor4fv(col_active);
+ immRecti(pos, 0, start_y, (int)ar->v2d.cur.xmax, start_y + UI_UNIT_Y);
+ }
+ else if (tselem->flag & TSE_SELECTED) {
immUniformColor4fv(col_selection);
immRecti(pos, 0, start_y, (int)ar->v2d.cur.xmax, start_y + UI_UNIT_Y);
}
@@ -3260,6 +3444,7 @@ static void outliner_draw_highlights_recursive(unsigned pos,
soops,
&te->subtree,
col_selection,
+ col_active,
col_highlight,
col_searchmatch,
start_x + UI_UNIT_X,
@@ -3271,10 +3456,12 @@ static void outliner_draw_highlights_recursive(unsigned pos,
static void outliner_draw_highlights(ARegion *ar, SpaceOutliner *soops, int startx, int *starty)
{
const float col_highlight[4] = {1.0f, 1.0f, 1.0f, 0.13f};
- float col_selection[4], col_searchmatch[4];
+ float col_selection[4], col_active[4], col_searchmatch[4];
UI_GetThemeColor3fv(TH_SELECT_HIGHLIGHT, col_selection);
col_selection[3] = 1.0f; /* no alpha */
+ UI_GetThemeColor3fv(TH_SELECT_ACTIVE, col_active);
+ col_active[3] = 1.0f; /* no alpha */
UI_GetThemeColor4fv(TH_MATCH, col_searchmatch);
col_searchmatch[3] = 0.5f;
@@ -3282,8 +3469,16 @@ static void outliner_draw_highlights(ARegion *ar, SpaceOutliner *soops, int star
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- outliner_draw_highlights_recursive(
- pos, ar, soops, &soops->tree, col_selection, col_highlight, col_searchmatch, startx, starty);
+ outliner_draw_highlights_recursive(pos,
+ ar,
+ soops,
+ &soops->tree,
+ col_selection,
+ col_active,
+ col_highlight,
+ col_searchmatch,
+ startx,
+ starty);
immUnbindProgram();
GPU_blend(false);
}
@@ -3439,6 +3634,17 @@ void draw_outliner(const bContext *C)
outliner_build_tree(mainvar, scene, view_layer, soops, ar); // always
+ /* If global sync select is dirty, flag other outliners */
+ if (ED_outliner_select_sync_is_dirty(C)) {
+ ED_outliner_select_sync_flag_outliners(C);
+ }
+
+ /* Sync selection state from view layer */
+ if (!ELEM(soops->outlinevis, SO_LIBRARIES, SO_DATA_API, SO_ID_ORPHANS) &&
+ soops->flag & SO_SYNC_SELECT) {
+ outliner_sync_selection(C, soops);
+ }
+
/* force display to pixel coords */
v2d->flag |= (V2D_PIXELOFS_X | V2D_PIXELOFS_Y);
/* set matrix for 2d-view controls */
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index de6e89e47c4..318d90d0dca 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -101,9 +101,15 @@ static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const
ARegion *ar = CTX_wm_region(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
- const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]);
- TreeElement *hovered_te = outliner_find_item_at_y(soops, &soops->tree, my);
+ float view_mval[2];
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
+
+ TreeElement *hovered_te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
+
+ if (hovered_te) {
+ hovered_te = outliner_find_item_at_x_in_row(soops, hovered_te, view_mval[0], NULL);
+ }
bool changed = false;
if (!hovered_te || !(hovered_te->store_elem->flag & TSE_HIGHLIGHTED)) {
@@ -134,59 +140,108 @@ void OUTLINER_OT_highlight_update(wmOperatorType *ot)
/* Toggle Open/Closed ------------------------------------------- */
-static int do_outliner_item_openclose(
- bContext *C, SpaceOutliner *soops, TreeElement *te, const bool all, const float mval[2])
+/* Open or close a tree element, optionally toggling all children recursively */
+void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all)
{
+ TreeStoreElem *tselem = TREESTORE(te);
- if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
- TreeStoreElem *tselem = TREESTORE(te);
+ if (open) {
+ tselem->flag &= ~TSE_CLOSED;
+ }
+ else {
+ tselem->flag |= TSE_CLOSED;
+ }
- /* all below close/open? */
- if (all) {
- tselem->flag &= ~TSE_CLOSED;
- outliner_flag_set(
- &te->subtree, TSE_CLOSED, !outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1));
- }
- else {
- if (tselem->flag & TSE_CLOSED) {
- tselem->flag &= ~TSE_CLOSED;
- }
- else {
- tselem->flag |= TSE_CLOSED;
+ if (toggle_all) {
+ outliner_flag_set(&te->subtree, TSE_CLOSED, !open);
+ }
+}
+
+typedef struct OpenCloseData {
+ TreeStoreElem *prev_tselem;
+ bool open;
+ int x_location;
+} OpenCloseData;
+
+static int outliner_item_openclose_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ SpaceOutliner *soops = CTX_wm_space_outliner(C);
+
+ float view_mval[2];
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
+
+ if (event->type == MOUSEMOVE) {
+ TreeElement *te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
+
+ OpenCloseData *data = (OpenCloseData *)op->customdata;
+
+ /* Only openclose if mouse is not over the previously toggled element */
+ if (te && TREESTORE(te) != data->prev_tselem) {
+
+ /* Only toggle openclose on the same level as the first clicked element */
+ if (te->xs == data->x_location) {
+ outliner_item_openclose(te, data->open, false);
+ ED_region_tag_redraw(ar);
}
}
- return 1;
+ if (te) {
+ data->prev_tselem = TREESTORE(te);
+ }
+ else {
+ data->prev_tselem = NULL;
+ }
}
+ else if (event->val == KM_RELEASE) {
+ MEM_freeN(op->customdata);
- for (te = te->subtree.first; te; te = te->next) {
- if (do_outliner_item_openclose(C, soops, te, all, mval)) {
- return 1;
- }
+ return OPERATOR_FINISHED;
}
- return 0;
+
+ return OPERATOR_RUNNING_MODAL;
}
-/* event can enterkey, then it opens/closes */
-static int outliner_item_openclose(bContext *C, wmOperator *op, const wmEvent *event)
+static int outliner_item_openclose_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
- TreeElement *te;
- float fmval[2];
- const bool all = RNA_boolean_get(op->ptr, "all");
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+ const bool toggle_all = RNA_boolean_get(op->ptr, "all");
- for (te = soops->tree.first; te; te = te->next) {
- if (do_outliner_item_openclose(C, soops, te, all, fmval)) {
- break;
+ float view_mval[2];
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
+
+ TreeElement *te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
+
+ if (te && outliner_item_is_co_within_close_toggle(te, view_mval[0])) {
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ const bool open = (tselem->flag & TSE_CLOSED) ||
+ (toggle_all && (outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1)));
+
+ outliner_item_openclose(te, open, toggle_all);
+ ED_region_tag_redraw(ar);
+
+ /* Only toggle once for single click toggling */
+ if (event->type == LEFTMOUSE) {
+ return OPERATOR_FINISHED;
}
- }
- ED_region_tag_redraw(ar);
+ /* Store last expanded tselem and x coordinate of disclosure triangle */
+ OpenCloseData *toggle_data = MEM_callocN(sizeof(OpenCloseData), "open_close_data");
+ toggle_data->prev_tselem = tselem;
+ toggle_data->open = open;
+ toggle_data->x_location = te->xs;
- return OPERATOR_FINISHED;
+ /* Store the first clicked on element */
+ op->customdata = toggle_data;
+
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
void OUTLINER_OT_item_openclose(wmOperatorType *ot)
@@ -195,11 +250,12 @@ void OUTLINER_OT_item_openclose(wmOperatorType *ot)
ot->idname = "OUTLINER_OT_item_openclose";
ot->description = "Toggle whether item under cursor is enabled or closed";
- ot->invoke = outliner_item_openclose;
+ ot->invoke = outliner_item_openclose_invoke;
+ ot->modal = outliner_item_openclose_modal;
ot->poll = ED_operator_outliner_active;
- RNA_def_boolean(ot->srna, "all", 1, "All", "Close or open all items");
+ RNA_def_boolean(ot->srna, "all", false, "All", "Close or open all items");
}
/* -------------------------------------------------------------------- */
@@ -330,10 +386,10 @@ void item_rename_cb(bContext *C,
do_item_rename(ar, te, tselem, reports);
}
-static int do_outliner_item_rename(ReportList *reports,
- ARegion *ar,
- TreeElement *te,
- const float mval[2])
+static void do_outliner_item_rename(ReportList *reports,
+ ARegion *ar,
+ TreeElement *te,
+ const float mval[2])
{
if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
TreeStoreElem *tselem = TREESTORE(te);
@@ -341,17 +397,12 @@ static int do_outliner_item_rename(ReportList *reports,
/* click on name */
if (mval[0] > te->xs + UI_UNIT_X * 2 && mval[0] < te->xend) {
do_item_rename(ar, te, tselem, reports);
- return 1;
}
- return 0;
}
for (te = te->subtree.first; te; te = te->next) {
- if (do_outliner_item_rename(reports, ar, te, mval)) {
- return 1;
- }
+ do_outliner_item_rename(reports, ar, te, mval);
}
- return 0;
}
static int outliner_item_rename(bContext *C, wmOperator *op, const wmEvent *event)
@@ -360,25 +411,34 @@ static int outliner_item_rename(bContext *C, wmOperator *op, const wmEvent *even
SpaceOutliner *soops = CTX_wm_space_outliner(C);
TreeElement *te;
float fmval[2];
- bool changed = false;
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+ /* Rename active element if key pressed, otherwise rename element at cursor coordinates */
+ if (event->val == KM_PRESS) {
+ TreeElement *active_element = outliner_find_element_with_flag(&soops->tree, TSE_ACTIVE);
- for (te = soops->tree.first; te; te = te->next) {
- if (do_outliner_item_rename(op->reports, ar, te, fmval)) {
- changed = true;
- break;
+ if (active_element) {
+ do_item_rename(ar, active_element, TREESTORE(active_element), op->reports);
+ }
+ else {
+ BKE_report(op->reports, RPT_WARNING, "No active item to rename");
}
}
+ else {
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
- return changed ? OPERATOR_FINISHED : OPERATOR_PASS_THROUGH;
+ for (te = soops->tree.first; te; te = te->next) {
+ do_outliner_item_rename(op->reports, ar, te, fmval);
+ }
+ }
+
+ return OPERATOR_FINISHED;
}
void OUTLINER_OT_item_rename(wmOperatorType *ot)
{
ot->name = "Rename";
ot->idname = "OUTLINER_OT_item_rename";
- ot->description = "Rename item under cursor";
+ ot->description = "Rename the active element";
ot->invoke = outliner_item_rename;
@@ -1103,6 +1163,10 @@ static int outliner_select_all_exec(bContext *C, wmOperator *op)
break;
}
+ if (soops->flag & SO_SYNC_SELECT) {
+ ED_outliner_select_sync_from_outliner(C, soops);
+ }
+
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_region_tag_redraw_no_rebuild(ar);
@@ -1179,20 +1243,17 @@ static int outliner_open_back(TreeElement *te)
return retval;
}
-static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
+/* Return element representing the active base or bone in the outliner, or NULL if none exists */
+static TreeElement *outliner_show_active_get_element(bContext *C,
+ SpaceOutliner *so,
+ ViewLayer *view_layer)
{
- SpaceOutliner *so = CTX_wm_space_outliner(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- ARegion *ar = CTX_wm_region(C);
- View2D *v2d = &ar->v2d;
-
TreeElement *te;
- int xdelta, ytop;
Object *obact = OBACT(view_layer);
if (!obact) {
- return OPERATOR_CANCELLED;
+ return NULL;
}
te = outliner_find_id(so, &so->tree, &obact->id);
@@ -1215,25 +1276,50 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- if (te) {
- /* open up tree to active object/bone */
+ return te;
+}
+
+static void outliner_show_active(SpaceOutliner *so, ARegion *ar, TreeElement *te, ID *id)
+{
+ /* open up tree to active object/bone */
+ if (TREESTORE(te)->id == id) {
if (outliner_open_back(te)) {
outliner_set_coordinates(ar, so);
}
+ return;
+ }
+
+ for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) {
+ outliner_show_active(so, ar, ten, id);
+ }
+}
+
+static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceOutliner *so = CTX_wm_space_outliner(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ARegion *ar = CTX_wm_region(C);
+ View2D *v2d = &ar->v2d;
+
+ TreeElement *active_element = outliner_show_active_get_element(C, so, view_layer);
- /* make te->ys center of view */
- ytop = te->ys + BLI_rcti_size_y(&v2d->mask) / 2;
- if (ytop > 0) {
- ytop = 0;
+ if (active_element) {
+ ID *id = TREESTORE(active_element)->id;
+
+ /* Expand all elements in the outliner with matching ID */
+ for (TreeElement *te = so->tree.first; te; te = te->next) {
+ outliner_show_active(so, ar, te, id);
}
- v2d->cur.ymax = (float)ytop;
- v2d->cur.ymin = (float)(ytop - BLI_rcti_size_y(&v2d->mask));
+ /* Center view on first element found */
+ int size_y = BLI_rcti_size_y(&v2d->mask) + 1;
+ int ytop = (active_element->ys + (size_y / 2));
+ int delta_y = ytop - v2d->cur.ymax;
- /* make te->xs ==> te->xend center of view */
- xdelta = (int)(te->xs - v2d->cur.xmin);
- v2d->cur.xmin += xdelta;
- v2d->cur.xmax += xdelta;
+ outliner_scroll_view(ar, delta_y);
+ }
+ else {
+ return OPERATOR_CANCELLED;
}
ED_region_tag_redraw_no_rebuild(ar);
@@ -1259,18 +1345,15 @@ void OUTLINER_OT_show_active(wmOperatorType *ot)
static int outliner_scroll_page_exec(bContext *C, wmOperator *op)
{
ARegion *ar = CTX_wm_region(C);
- int dy = BLI_rcti_size_y(&ar->v2d.mask);
- int up = 0;
+ int size_y = BLI_rcti_size_y(&ar->v2d.mask) + 1;
- if (RNA_boolean_get(op->ptr, "up")) {
- up = 1;
- }
+ bool up = RNA_boolean_get(op->ptr, "up");
- if (up == 0) {
- dy = -dy;
+ if (!up) {
+ size_y = -size_y;
}
- ar->v2d.cur.ymin += dy;
- ar->v2d.cur.ymax += dy;
+
+ outliner_scroll_view(ar, size_y);
ED_region_tag_redraw_no_rebuild(ar);
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index fa28d119244..466e6684eca 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -50,6 +50,14 @@ typedef enum TreeElementInsertType {
TE_INSERT_INTO,
} TreeElementInsertType;
+/* Use generic walk select after D4771 is committed */
+typedef enum WalkSelectDirection {
+ OUTLINER_SELECT_WALK_UP,
+ OUTLINER_SELECT_WALK_DOWN,
+ OUTLINER_SELECT_WALK_LEFT,
+ OUTLINER_SELECT_WALK_RIGHT,
+} WalkSelectDirection;
+
typedef enum TreeTraversalAction {
/* Continue traversal regularly, don't skip children. */
TRAVERSE_CONTINUE = 0,
@@ -131,6 +139,9 @@ enum {
TE_DISABLED = (1 << 4),
TE_DRAGGING = (1 << 5),
TE_CHILD_NOT_IN_COLLECTION = (1 << 6),
+ /* Child elements of the same type in the icon-row are drawn merged as one icon.
+ * This flag is set for an element that is part of these merged child icons. */
+ TE_ICONROW_MERGED = (1 << 7),
};
/* button events */
@@ -223,6 +234,8 @@ void outliner_collection_isolate_flag(struct Scene *scene,
const char *propname,
const bool value);
+int tree_element_id_type_to_index(TreeElement *te);
+
/* outliner_select.c -------------------------------------------- */
eOLDrawState tree_element_type_active(struct bContext *C,
struct Scene *scene,
@@ -253,6 +266,10 @@ void outliner_object_mode_toggle(struct bContext *C,
ViewLayer *view_layer,
Base *base);
+void outliner_element_activate(struct SpaceOutliner *soops, struct TreeStoreElem *tselem);
+
+bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_co_x);
+
/* outliner_edit.c ---------------------------------------------- */
typedef void (*outliner_operation_cb)(struct bContext *C,
struct ReportList *,
@@ -337,6 +354,8 @@ void item_object_mode_exit_cb(struct bContext *C,
void outliner_set_coordinates(struct ARegion *ar, struct SpaceOutliner *soops);
+void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all);
+
/* outliner_dragdrop.c */
void outliner_dropboxes(void);
@@ -364,6 +383,7 @@ void OUTLINER_OT_show_active(struct wmOperatorType *ot);
void OUTLINER_OT_show_hierarchy(struct wmOperatorType *ot);
void OUTLINER_OT_select_box(struct wmOperatorType *ot);
+void OUTLINER_OT_select_walk(struct wmOperatorType *ot);
void OUTLINER_OT_select_all(struct wmOperatorType *ot);
void OUTLINER_OT_expanded_toggle(struct wmOperatorType *ot);
@@ -380,6 +400,10 @@ void OUTLINER_OT_orphans_purge(struct wmOperatorType *ot);
/* outliner_tools.c ---------------------------------------------- */
+void merged_element_search_menu_invoke(struct bContext *C,
+ TreeElement *parent_te,
+ TreeElement *activate_te);
+
void OUTLINER_OT_operation(struct wmOperatorType *ot);
void OUTLINER_OT_scene_operation(struct wmOperatorType *ot);
void OUTLINER_OT_object_operation(struct wmOperatorType *ot);
@@ -439,7 +463,8 @@ TreeElement *outliner_find_item_at_y(const SpaceOutliner *soops,
float view_co_y);
TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *soops,
const TreeElement *parent_te,
- float view_co_x);
+ float view_co_x,
+ bool *multiple_objects);
TreeElement *outliner_find_tse(struct SpaceOutliner *soops, const TreeStoreElem *tse);
TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem);
TreeElement *outliner_find_parent_element(ListBase *lb,
@@ -456,5 +481,12 @@ bool outliner_tree_traverse(const SpaceOutliner *soops,
TreeTraversalFunc func,
void *customdata);
float outliner_restrict_columns_width(const struct SpaceOutliner *soops);
+TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag);
+bool outliner_is_element_visible(const TreeElement *te);
+void outliner_scroll_view(struct ARegion *ar, int delta_y);
+
+/* outliner_sync.c ---------------------------------------------- */
+
+void outliner_sync_selection(const struct bContext *C, struct SpaceOutliner *soops);
#endif /* __OUTLINER_INTERN_H__ */
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index f155a2d5f89..4b57d4ad771 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -50,6 +50,7 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_highlight_update);
WM_operatortype_append(OUTLINER_OT_item_activate);
WM_operatortype_append(OUTLINER_OT_select_box);
+ WM_operatortype_append(OUTLINER_OT_select_walk);
WM_operatortype_append(OUTLINER_OT_item_openclose);
WM_operatortype_append(OUTLINER_OT_item_rename);
WM_operatortype_append(OUTLINER_OT_item_drag_drop);
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index c932766ab93..19fd4511e50 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -51,14 +51,16 @@
#include "BKE_workspace.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "ED_armature.h"
+#include "ED_gpencil.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_sequencer.h"
#include "ED_undo.h"
-#include "ED_gpencil.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -251,9 +253,7 @@ static eOLDrawState active_viewlayer(bContext *C,
}
/**
- * Select object tree:
- * CTRL+LMB: Select/Deselect object and all children.
- * CTRL+SHIFT+LMB: Add/Remove object and all children.
+ * Select object tree
*/
static void do_outliner_object_select_recursive(ViewLayer *view_layer,
Object *ob_parent,
@@ -450,9 +450,9 @@ static eOLDrawState tree_element_active_material(bContext *C,
return OL_DRAWSEL_NONE;
}
-static eOLDrawState tree_element_active_camera(bContext *UNUSED(C),
+static eOLDrawState tree_element_active_camera(bContext *C,
Scene *scene,
- ViewLayer *UNUSED(sl),
+ ViewLayer *UNUSED(view_layer),
SpaceOutliner *soops,
TreeElement *te,
const eOLSetState set)
@@ -460,10 +460,21 @@ static eOLDrawState tree_element_active_camera(bContext *UNUSED(C),
Object *ob = (Object *)outliner_search_back(soops, te, ID_OB);
if (set != OL_SETSEL_NONE) {
+ scene->camera = ob;
+
+ Main *bmain = CTX_data_main(C);
+ wmWindowManager *wm = bmain->wm.first;
+
+ WM_windows_scene_data_sync(&wm->windows, scene);
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+ WM_event_add_notifier(C, NC_SCENE | NA_EDITED, NULL);
+
return OL_DRAWSEL_NONE;
}
-
- return scene->camera == ob;
+ else {
+ return scene->camera == ob;
+ }
}
static eOLDrawState tree_element_active_world(bContext *C,
@@ -1083,6 +1094,13 @@ eOLDrawState tree_element_type_active(bContext *C,
/* ================================================ */
+/* Activate a tree store element and set the walk navigation start element */
+void outliner_element_activate(SpaceOutliner *soops, TreeStoreElem *tselem)
+{
+ outliner_flag_set(&soops->tree, TSE_ACTIVE | TSE_ACTIVE_WALK, false);
+ tselem->flag |= TSE_ACTIVE | TSE_ACTIVE_WALK;
+}
+
/**
* Action when clicking to activate an item (typically under the mouse cursor),
* but don't do any cursor intersection checks.
@@ -1114,7 +1132,8 @@ static void do_outliner_item_activate_tree_element(bContext *C,
else if (tselem->type == TSE_POSE_BASE) {
/* Support pose mode toggle, keeping the active object as is. */
}
- else {
+ else if (soops->flag & SO_SYNC_SELECT) {
+ /* Only activate when synced selection is enabled */
tree_element_set_active_object(C,
scene,
view_layer,
@@ -1125,6 +1144,9 @@ static void do_outliner_item_activate_tree_element(bContext *C,
recursive && tselem->type == 0);
}
+ /* Mark as active in the outliner */
+ outliner_element_activate(soops, tselem);
+
if (tselem->type == 0) { // the lib blocks
/* editmode? */
if (te->idcode == ID_SCE) {
@@ -1189,7 +1211,7 @@ static void do_outliner_item_activate_tree_element(bContext *C,
tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, false);
}
}
- else {
+ else if (soops->flag & SO_SYNC_SELECT) {
tree_element_type_active(C,
scene,
view_layer,
@@ -1211,7 +1233,8 @@ void outliner_item_select(SpaceOutliner *soops,
const bool toggle)
{
TreeStoreElem *tselem = TREESTORE(te);
- const short new_flag = toggle ? (tselem->flag ^ TSE_SELECTED) : (tselem->flag | TSE_SELECTED);
+ const short new_flag = (toggle && (tselem->flag & TSE_ACTIVE)) ? (tselem->flag ^ TSE_SELECTED) :
+ (tselem->flag | TSE_SELECTED);
if (extend == false) {
outliner_flag_set(&soops->tree, TSE_SELECTED, false);
@@ -1219,24 +1242,66 @@ void outliner_item_select(SpaceOutliner *soops,
tselem->flag = new_flag;
}
-static void outliner_item_toggle_closed(TreeElement *te, const bool toggle_children)
+static void do_outliner_range_select_recursive(ListBase *lb,
+ TreeElement *active,
+ TreeElement *cursor,
+ bool *selecting)
{
- TreeStoreElem *tselem = TREESTORE(te);
- if (toggle_children) {
- tselem->flag &= ~TSE_CLOSED;
+ for (TreeElement *te = lb->first; te; te = te->next) {
+ if (*selecting) {
+ TREESTORE(te)->flag |= TSE_SELECTED;
+ }
- const bool all_opened = !outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1);
- outliner_flag_set(&te->subtree, TSE_CLOSED, all_opened);
- }
- else {
- tselem->flag ^= TSE_CLOSED;
+ /* Set state for selection */
+ if (te == active || te == cursor) {
+ *selecting = !*selecting;
+ }
+
+ if (*selecting) {
+ TREESTORE(te)->flag |= TSE_SELECTED;
+ }
+
+ /* Don't look inside closed elements */
+ if (!(TREESTORE(te)->flag & TSE_CLOSED)) {
+ do_outliner_range_select_recursive(&te->subtree, active, cursor, selecting);
+ }
}
}
-static bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_co_x)
+/* Select a range of items between cursor and active element */
+static void do_outliner_range_select(bContext *C, SpaceOutliner *soops, TreeElement *cursor)
{
- return ((te->flag & TE_ICONROW) == 0) && (view_co_x > te->xs) &&
- (view_co_x < te->xs + UI_UNIT_X);
+ TreeElement *active = outliner_find_element_with_flag(&soops->tree, TSE_ACTIVE);
+ outliner_flag_set(&soops->tree, TSE_ACTIVE_WALK, false);
+
+ if (!active) {
+ outliner_item_select(soops, cursor, false, false);
+ outliner_item_do_activate_from_tree_element(C, cursor, TREESTORE(cursor), false, false);
+ return;
+ }
+
+ TreeStoreElem *tselem = TREESTORE(active);
+ const bool active_selected = (tselem->flag & TSE_SELECTED);
+
+ outliner_flag_set(&soops->tree, TSE_SELECTED | TSE_ACTIVE_WALK, false);
+
+ /* Select active if under cursor */
+ if (active == cursor) {
+ TREESTORE(cursor)->flag |= TSE_SELECTED;
+ return;
+ }
+
+ /* If active is not selected, just select the element under the cursor */
+ if (!active_selected || !outliner_is_element_visible(active)) {
+ outliner_item_select(soops, cursor, false, false);
+ outliner_item_do_activate_from_tree_element(C, cursor, TREESTORE(cursor), false, false);
+ return;
+ }
+
+ outliner_flag_set(&soops->tree, TSE_SELECTED, false);
+
+ bool selecting = false;
+ do_outliner_range_select_recursive(&soops->tree, active, cursor, &selecting);
}
static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *soops,
@@ -1247,7 +1312,7 @@ static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *soops,
}
/**
- * A version of #outliner_item_do_acticate_from_cursor that takes the tree element directly.
+ * A version of #outliner_item_do_activate_from_cursor that takes the tree element directly.
* and doesn't depend on the pointer position.
*
* This allows us to simulate clicking on an item without dealing with the mouse cursor.
@@ -1271,10 +1336,11 @@ void outliner_item_do_activate_from_tree_element(
static int outliner_item_do_activate_from_cursor(bContext *C,
const int mval[2],
const bool extend,
- const bool recursive,
+ const bool use_range,
const bool deselect_all)
{
ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
TreeElement *te;
float view_mval[2];
@@ -1292,21 +1358,36 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
changed = true;
}
}
- else if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) {
- outliner_item_toggle_closed(te, extend);
- changed = true;
- rebuild_tree = true;
+ /* Don't allow toggle on scene collection */
+ else if ((TREESTORE(te)->type != TSE_VIEW_COLLECTION_BASE) &&
+ outliner_item_is_co_within_close_toggle(te, view_mval[0])) {
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
else {
- Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- /* the row may also contain children, if one is hovered we want this instead of current te */
- TreeElement *activate_te = outliner_find_item_at_x_in_row(soops, te, view_mval[0]);
+
+ /* The row may also contain children, if one is hovered we want this instead of current te */
+ bool merged_elements = false;
+ TreeElement *activate_te = outliner_find_item_at_x_in_row(
+ soops, te, view_mval[0], &merged_elements);
+
+ /* If the selected icon was an aggregate of multiple elements, run the search popup */
+ if (merged_elements) {
+ merged_element_search_menu_invoke(C, te, activate_te);
+ return OPERATOR_CANCELLED;
+ }
+
TreeStoreElem *activate_tselem = TREESTORE(activate_te);
- outliner_item_select(soops, activate_te, extend, extend);
- do_outliner_item_activate_tree_element(
- C, scene, view_layer, soops, activate_te, activate_tselem, extend, recursive);
+ if (use_range) {
+ do_outliner_range_select(C, soops, activate_te);
+ }
+ else {
+ outliner_item_select(soops, activate_te, extend, extend);
+ do_outliner_item_activate_tree_element(
+ C, scene, view_layer, soops, activate_te, activate_tselem, extend, false);
+ }
+
changed = true;
}
@@ -1318,6 +1399,10 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
ED_region_tag_redraw_no_rebuild(ar);
}
ED_undo_push(C, "Outliner selection change");
+
+ if (soops->flag & SO_SYNC_SELECT) {
+ ED_outliner_select_sync_from_outliner(C, soops);
+ }
}
return OPERATOR_FINISHED;
@@ -1327,9 +1412,9 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
static int outliner_item_activate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
const bool extend = RNA_boolean_get(op->ptr, "extend");
- const bool recursive = RNA_boolean_get(op->ptr, "recursive");
+ const bool use_range = RNA_boolean_get(op->ptr, "extend_range");
const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
- return outliner_item_do_activate_from_cursor(C, event->mval, extend, recursive, deselect_all);
+ return outliner_item_do_activate_from_cursor(C, event->mval, extend, use_range, deselect_all);
}
void OUTLINER_OT_item_activate(wmOperatorType *ot)
@@ -1344,7 +1429,10 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot)
PropertyRNA *prop;
RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection for activation");
- RNA_def_boolean(ot->srna, "recursive", false, "Recursive", "Select Objects and their children");
+ prop = RNA_def_boolean(
+ ot->srna, "extend_range", false, "Extend Range", "Select a range from active element");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
prop = RNA_def_boolean(ot->srna,
"deselect_all",
false,
@@ -1402,9 +1490,44 @@ static int outliner_box_select_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_region_tag_redraw(ar);
+ if (soops->flag & SO_SYNC_SELECT) {
+ ED_outliner_select_sync_from_outliner(C, soops);
+ }
+
return OPERATOR_FINISHED;
}
+/* Find if x coordinate is over an icon or name */
+static bool outliner_item_is_co_over_name_icons(TreeElement *te, float view_co_x)
+{
+ /* Special case: count area left of Scene Collection as empty space */
+ bool outside_left = (TREESTORE(te)->type == TSE_VIEW_COLLECTION_BASE) ?
+ (view_co_x > te->xs + UI_UNIT_X) :
+ (view_co_x > te->xs);
+
+ return outside_left && (view_co_x < te->xend);
+}
+
+static int outliner_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ SpaceOutliner *soops = CTX_wm_space_outliner(C);
+ ARegion *ar = CTX_wm_region(C);
+ float view_mval[2];
+ const bool tweak = RNA_boolean_get(op->ptr, "tweak");
+
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
+
+ /* Find element clicked on */
+ TreeElement *te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
+
+ /* Pass through if click is over name or icons, or not tweak event */
+ if (te && tweak && outliner_item_is_co_over_name_icons(te, view_mval[0])) {
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
+ }
+
+ return WM_gesture_box_invoke(C, op, event);
+}
+
void OUTLINER_OT_select_box(wmOperatorType *ot)
{
/* identifiers */
@@ -1413,7 +1536,7 @@ void OUTLINER_OT_select_box(wmOperatorType *ot)
ot->description = "Use box selection to select tree elements";
/* api callbacks */
- ot->invoke = WM_gesture_box_invoke;
+ ot->invoke = outliner_box_select_invoke;
ot->exec = outliner_box_select_exec;
ot->modal = WM_gesture_box_modal;
ot->cancel = WM_gesture_box_cancel;
@@ -1424,8 +1547,240 @@ void OUTLINER_OT_select_box(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
+ PropertyRNA *prop;
+
+ prop = RNA_def_boolean(
+ ot->srna, "tweak", false, "Tweak", "Tweak gesture from empty space for box selection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
WM_operator_properties_gesture_box(ot);
WM_operator_properties_select_operation_simple(ot);
}
/* ****************************************************** */
+
+/* **************** Walk Select Tool ****************** */
+
+/* Given a tree element return the rightmost child that is visible in the outliner */
+static TreeElement *outliner_find_rightmost_visible_child(SpaceOutliner *soops, TreeElement *te)
+{
+ while (te->subtree.last) {
+ if (TSELEM_OPEN(TREESTORE(te), soops)) {
+ te = te->subtree.last;
+ }
+ else {
+ break;
+ }
+ }
+ return te;
+}
+
+/* Find previous visible element in the tree */
+static TreeElement *outliner_find_previous_element(SpaceOutliner *soops, TreeElement *walk_element)
+{
+ if (walk_element->prev) {
+ walk_element = outliner_find_rightmost_visible_child(soops, walk_element->prev);
+ }
+ else if (walk_element->parent) {
+ /* Use parent if at beginning of list */
+ walk_element = walk_element->parent;
+ }
+
+ return walk_element;
+}
+
+/* Recursively search up the tree until a successor to a given element is found */
+static TreeElement *outliner_element_find_successor_in_parents(TreeElement *te)
+{
+ TreeElement *successor = te;
+ while (successor->parent) {
+ if (successor->parent->next) {
+ te = successor->parent->next;
+ break;
+ }
+ else {
+ successor = successor->parent;
+ }
+ }
+
+ return te;
+}
+
+/* Find next visible element in the tree */
+static TreeElement *outliner_find_next_element(SpaceOutliner *soops, TreeElement *walk_element)
+{
+ TreeStoreElem *tselem = TREESTORE(walk_element);
+
+ if (TSELEM_OPEN(tselem, soops) && walk_element->subtree.first) {
+ walk_element = walk_element->subtree.first;
+ }
+ else if (walk_element->next) {
+ walk_element = walk_element->next;
+ }
+ else {
+ walk_element = outliner_element_find_successor_in_parents(walk_element);
+ }
+
+ return walk_element;
+}
+
+static TreeElement *do_outliner_select_walk(SpaceOutliner *soops,
+ TreeElement *walk_element,
+ const int direction,
+ const bool extend,
+ const bool toggle_all)
+{
+ TreeStoreElem *tselem = TREESTORE(walk_element);
+
+ if (!extend) {
+ outliner_flag_set(&soops->tree, TSE_SELECTED, false);
+ }
+ tselem->flag &= ~TSE_ACTIVE_WALK;
+
+ switch (direction) {
+ case OUTLINER_SELECT_WALK_UP:
+ walk_element = outliner_find_previous_element(soops, walk_element);
+ break;
+ case OUTLINER_SELECT_WALK_DOWN:
+ walk_element = outliner_find_next_element(soops, walk_element);
+ break;
+ case OUTLINER_SELECT_WALK_LEFT:
+ outliner_item_openclose(walk_element, false, toggle_all);
+ break;
+ case OUTLINER_SELECT_WALK_RIGHT:
+ outliner_item_openclose(walk_element, true, toggle_all);
+ break;
+ }
+
+ TreeStoreElem *tselem_new = TREESTORE(walk_element);
+
+ /* If new element is already selected, deselect the previous element */
+ if (extend) {
+ tselem->flag = (tselem_new->flag & TSE_SELECTED) ? (tselem->flag & ~TSE_SELECTED) :
+ (tselem->flag | TSE_SELECTED);
+ }
+
+ tselem_new->flag |= TSE_SELECTED | TSE_ACTIVE_WALK;
+
+ return walk_element;
+}
+
+/* Find walk select element, or set it if it does not exist.
+ * Changed is set to true if walk element is found, false if it was set */
+static TreeElement *find_walk_select_start_element(SpaceOutliner *soops, bool *changed)
+{
+ TreeElement *walk_element = outliner_find_element_with_flag(&soops->tree, TSE_ACTIVE_WALK);
+
+ *changed = false;
+
+ /* If no walk element exists, start from active */
+ if (!walk_element) {
+ TreeElement *active_element = outliner_find_element_with_flag(&soops->tree, TSE_ACTIVE);
+
+ /* If no active element exists, use the first element in the tree */
+ if (!active_element) {
+ walk_element = soops->tree.first;
+ }
+ else {
+ walk_element = active_element;
+ }
+
+ *changed = true;
+ }
+
+ /* If walk element is not visible, set that element's first visible parent as walk element */
+ if (!outliner_is_element_visible(walk_element)) {
+ TREESTORE(walk_element)->flag &= ~TSE_ACTIVE_WALK;
+
+ while (!outliner_is_element_visible(walk_element)) {
+ walk_element = walk_element->parent;
+ }
+ *changed = true;
+ }
+
+ return walk_element;
+}
+
+/* Scroll the outliner when the walk element reaches the top or bottom boundary */
+static void outliner_walk_scroll(ARegion *ar, TreeElement *te)
+{
+ /* Account for the header height */
+ int y_max = ar->v2d.cur.ymax - UI_UNIT_Y;
+ int y_min = ar->v2d.cur.ymin;
+
+ /* Scroll if walked position is beyond the border */
+ if (te->ys > y_max) {
+ outliner_scroll_view(ar, te->ys - y_max);
+ }
+ else if (te->ys < y_min) {
+ outliner_scroll_view(ar, -(y_min - te->ys));
+ }
+}
+
+static int outliner_walk_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ SpaceOutliner *soops = CTX_wm_space_outliner(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ const short direction = RNA_enum_get(op->ptr, "direction");
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+ const bool toggle_all = RNA_boolean_get(op->ptr, "toggle_all");
+
+ bool changed;
+ TreeElement *walk_element = find_walk_select_start_element(soops, &changed);
+
+ /* If finding the starting walk select element did not move the element, proceed to walk */
+ if (!changed) {
+ walk_element = do_outliner_select_walk(soops, walk_element, direction, extend, toggle_all);
+ }
+ else {
+ TREESTORE(walk_element)->flag |= TSE_SELECTED | TSE_ACTIVE_WALK;
+ }
+
+ /* Scroll outliner to focus on walk element */
+ outliner_walk_scroll(ar, walk_element);
+
+ if (soops->flag & SO_SYNC_SELECT) {
+ ED_outliner_select_sync_from_outliner(C, soops);
+ }
+ ED_region_tag_redraw(ar);
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_select_walk(wmOperatorType *ot)
+{
+ static const EnumPropertyItem direction_items[] = {
+ {OUTLINER_SELECT_WALK_UP, "UP", 0, "Up", ""},
+ {OUTLINER_SELECT_WALK_DOWN, "DOWN", 0, "Down", ""},
+ {OUTLINER_SELECT_WALK_LEFT, "LEFT", 0, "Left", ""},
+ {OUTLINER_SELECT_WALK_RIGHT, "RIGHT", 0, "Right", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Walk Select";
+ ot->idname = "OUTLINER_OT_select_walk";
+ ot->description = "Use walk navigation to select tree elements";
+
+ /* api callbacks */
+ ot->invoke = outliner_walk_select_invoke;
+ ot->poll = ED_operator_outliner_active;
+
+ /* properties */
+ PropertyRNA *prop;
+ prop = RNA_def_enum(ot->srna,
+ "direction",
+ direction_items,
+ 0,
+ "Walk Direction",
+ "Select element in this direction");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection on walk");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(
+ ot->srna, "toggle_all", false, "Toggle All", "Toggle open/close hierarchy");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+/* ****************************************************** */
diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.c
new file mode 100644
index 00000000000..a8aeb7ea4e1
--- /dev/null
+++ b/source/blender/editors/space_outliner/outliner_sync.c
@@ -0,0 +1,548 @@
+/*
+ * 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) 2004 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#include <stdio.h>
+
+#include "DNA_armature_types.h"
+#include "DNA_layer_types.h"
+#include "DNA_outliner_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_compiler_compat.h"
+#include "BLI_ghash.h"
+
+#include "BKE_armature.h"
+#include "BKE_context.h"
+#include "BKE_layer.h"
+#include "BKE_main.h"
+#include "BKE_sequencer.h"
+
+#include "DEG_depsgraph.h"
+
+#include "ED_armature.h"
+#include "ED_object.h"
+#include "ED_outliner.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "outliner_intern.h"
+
+/* Functions for tagging outliner selection syncing is dirty from operators */
+void ED_outliner_select_sync_from_object_tag(bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wm->outliner_sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_OBJECT;
+}
+
+void ED_outliner_select_sync_from_edit_bone_tag(bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wm->outliner_sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE;
+}
+
+void ED_outliner_select_sync_from_pose_bone_tag(bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wm->outliner_sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_POSE_BONE;
+}
+
+void ED_outliner_select_sync_from_sequence_tag(bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wm->outliner_sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_SEQUENCE;
+}
+
+bool ED_outliner_select_sync_is_dirty(const bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ return wm->outliner_sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_ALL;
+}
+
+/* Copy sync select dirty flag from window manager to all outliners to be synced lazily on draw */
+void ED_outliner_select_sync_flag_outliners(const bContext *C)
+{
+ Main *bmain = CTX_data_main(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
+
+ 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_OUTLINER) {
+ SpaceOutliner *soutliner = (SpaceOutliner *)sl;
+
+ soutliner->sync_select_dirty |= wm->outliner_sync_select_dirty;
+ }
+ }
+ }
+ }
+
+ /* Clear global sync flag */
+ wm->outliner_sync_select_dirty = 0;
+}
+
+/**
+ * Outliner sync select dirty flags are not enough to determine which types to sync,
+ * outliner display mode also needs to be considered. This stores the types of data
+ * to sync to increase code clarity.
+ */
+typedef struct SyncSelectTypes {
+ bool object;
+ bool edit_bone;
+ bool pose_bone;
+ bool sequence;
+} SyncSelectTypes;
+
+/**
+ * Set which types of data to sync when syncing selection from the outliner based on object
+ * interaction mode and outliner display mode
+ */
+static void outliner_sync_select_from_outliner_set_types(bContext *C,
+ SpaceOutliner *soops,
+ SyncSelectTypes *sync_types)
+{
+ Object *obact = CTX_data_active_object(C);
+ Object *obedit = CTX_data_edit_object(C);
+
+ const bool sequence_view = soops->outlinevis == SO_SEQUENCE;
+
+ sync_types->object = !sequence_view && (obact && obact->mode == OB_MODE_OBJECT);
+ 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;
+}
+
+/**
+ * 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.
+ */
+static void outliner_sync_select_to_outliner_set_types(const bContext *C,
+ SpaceOutliner *soops,
+ SyncSelectTypes *sync_types)
+{
+ Object *obact = CTX_data_active_object(C);
+ Object *obedit = CTX_data_edit_object(C);
+
+ const bool sequence_view = soops->outlinevis == SO_SEQUENCE;
+
+ sync_types->object = !sequence_view && (obact && obact->mode == OB_MODE_OBJECT) &&
+ (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);
+ sync_types->pose_bone = !sequence_view && (obact && obact->mode == OB_MODE_POSE) &&
+ (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);
+}
+
+/**
+ * Stores items selected from a sync from the outliner. Prevents syncing the selection
+ * state of the last instance of an object linked in multiple collections.
+ */
+typedef struct SelectedItems {
+ GSet *objects;
+ GSet *edit_bones;
+ GSet *pose_bones;
+} SelectedItems;
+
+static void selected_items_init(SelectedItems *selected_items)
+{
+ selected_items->objects = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ selected_items->edit_bones = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ selected_items->pose_bones = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+}
+
+static void selected_items_free(SelectedItems *selected_items)
+{
+ BLI_gset_free(selected_items->objects, NULL);
+ BLI_gset_free(selected_items->edit_bones, NULL);
+ BLI_gset_free(selected_items->pose_bones, NULL);
+}
+
+/* Check if an instance of this object been selected by the sync */
+static bool is_object_selected(GSet *selected_objects, Base *base)
+{
+ return BLI_gset_haskey(selected_objects, base);
+}
+
+/* Check if an instance of this edit bone been selected by the sync */
+static bool is_edit_bone_selected(GSet *selected_ebones, EditBone *ebone)
+{
+ return BLI_gset_haskey(selected_ebones, ebone);
+}
+
+/* Check if an instance of this pose bone been selected by the sync */
+static bool is_pose_bone_selected(GSet *selected_pbones, bPoseChannel *pchan)
+{
+ return BLI_gset_haskey(selected_pbones, pchan);
+}
+
+/* Add element's data to selected item set */
+static void add_selected_item(GSet *selected, void *data)
+{
+ BLI_gset_add(selected, data);
+}
+
+static void outliner_select_sync_to_object(ViewLayer *view_layer,
+ TreeElement *te,
+ TreeStoreElem *tselem,
+ GSet *selected_objects)
+{
+ Object *ob = (Object *)tselem->id;
+ Base *base = (te->directdata) ? (Base *)te->directdata :
+ BKE_view_layer_base_find(view_layer, ob);
+
+ if (base && (base->flag & BASE_SELECTABLE)) {
+ if (tselem->flag & TSE_SELECTED) {
+ ED_object_base_select(base, BA_SELECT);
+
+ add_selected_item(selected_objects, base);
+ }
+ else if (!is_object_selected(selected_objects, base)) {
+ ED_object_base_select(base, BA_DESELECT);
+ }
+ }
+}
+
+static void outliner_select_sync_to_edit_bone(ViewLayer *view_layer,
+ TreeElement *te,
+ TreeStoreElem *tselem,
+ GSet *selected_ebones)
+{
+ bArmature *arm = (bArmature *)tselem->id;
+ EditBone *ebone = (EditBone *)te->directdata;
+
+ short bone_flag = ebone->flag;
+
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ if (tselem->flag & TSE_SELECTED) {
+ ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+
+ add_selected_item(selected_ebones, ebone);
+ }
+ else if (!is_edit_bone_selected(selected_ebones, ebone)) {
+ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+
+ /* Tag if selection changed */
+ if (bone_flag != ebone->flag) {
+ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
+ WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, obedit);
+ }
+}
+
+static void outliner_select_sync_to_pose_bone(TreeElement *te,
+ TreeStoreElem *tselem,
+ GSet *selected_pbones)
+{
+ Object *ob = (Object *)tselem->id;
+ bArmature *arm = ob->data;
+ bPoseChannel *pchan = (bPoseChannel *)te->directdata;
+
+ short bone_flag = pchan->bone->flag;
+
+ if (PBONE_SELECTABLE(arm, pchan->bone)) {
+ if (tselem->flag & TSE_SELECTED) {
+ pchan->bone->flag |= BONE_SELECTED;
+
+ add_selected_item(selected_pbones, pchan);
+ }
+ else if (!is_pose_bone_selected(selected_pbones, pchan)) {
+ pchan->bone->flag &= ~BONE_SELECTED;
+ }
+ }
+
+ /* Tag if selection changed */
+ if (bone_flag != pchan->bone->flag) {
+ DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
+ WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+}
+
+static void outliner_select_sync_to_sequence(Scene *scene, TreeStoreElem *tselem)
+{
+ Sequence *seq = (Sequence *)tselem->id;
+
+ if (tselem->flag & TSE_ACTIVE) {
+ BKE_sequencer_active_set(scene, seq);
+ }
+
+ if (tselem->flag & TSE_SELECTED) {
+ seq->flag |= SELECT;
+ }
+ else {
+ seq->flag &= ~SELECT;
+ }
+}
+
+/** Sync select and active flags from outliner to active view layer, bones, and sequencer. */
+static void outliner_sync_selection_from_outliner(Scene *scene,
+ ViewLayer *view_layer,
+ ListBase *tree,
+ const SyncSelectTypes *sync_types,
+ SelectedItems *selected_items)
+{
+
+ for (TreeElement *te = tree->first; te; te = te->next) {
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (tselem->type == 0 && te->idcode == ID_OB) {
+ if (sync_types->object) {
+ outliner_select_sync_to_object(view_layer, te, tselem, selected_items->objects);
+ }
+ }
+ else if (tselem->type == TSE_EBONE) {
+ if (sync_types->edit_bone) {
+ outliner_select_sync_to_edit_bone(view_layer, te, tselem, selected_items->edit_bones);
+ }
+ }
+ else if (tselem->type == TSE_POSE_CHANNEL) {
+ if (sync_types->pose_bone) {
+ outliner_select_sync_to_pose_bone(te, tselem, selected_items->pose_bones);
+ }
+ }
+ else if (tselem->type == TSE_SEQUENCE) {
+ if (sync_types->sequence) {
+ outliner_select_sync_to_sequence(scene, tselem);
+ }
+ }
+
+ outliner_sync_selection_from_outliner(
+ scene, view_layer, &te->subtree, sync_types, selected_items);
+ }
+}
+
+/* Set clean outliner and mark other outliners for syncing */
+void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *soops)
+{
+ /* Don't sync in certain outliner display modes */
+ if (ELEM(soops->outlinevis, SO_LIBRARIES, SO_DATA_API, SO_ID_ORPHANS)) {
+ return;
+ }
+
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ SyncSelectTypes sync_types;
+ outliner_sync_select_from_outliner_set_types(C, soops, &sync_types);
+
+ /* To store elements that have been selected to prevent linked object sync errors */
+ SelectedItems selected_items;
+
+ selected_items_init(&selected_items);
+
+ outliner_sync_selection_from_outliner(
+ scene, view_layer, &soops->tree, &sync_types, &selected_items);
+
+ selected_items_free(&selected_items);
+
+ /* Tag for updates */
+ if (sync_types.object) {
+ DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ }
+ if (sync_types.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,
+ SpaceOutliner *soops,
+ Object *obact,
+ TreeElement *te,
+ TreeStoreElem *tselem)
+{
+ Object *ob = (Object *)tselem->id;
+ Base *base = (te->directdata) ? (Base *)te->directdata :
+ BKE_view_layer_base_find(view_layer, ob);
+ const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0);
+
+ if (base && (ob == obact)) {
+ outliner_element_activate(soops, tselem);
+ }
+
+ if (is_selected) {
+ tselem->flag |= TSE_SELECTED;
+ }
+ else {
+ tselem->flag &= ~TSE_SELECTED;
+ }
+}
+
+static void outliner_select_sync_from_edit_bone(SpaceOutliner *soops,
+ EditBone *ebone_active,
+ TreeElement *te,
+ TreeStoreElem *tselem)
+{
+ EditBone *ebone = (EditBone *)te->directdata;
+
+ if (ebone == ebone_active) {
+ outliner_element_activate(soops, tselem);
+ }
+
+ if (ebone->flag & BONE_SELECTED) {
+ tselem->flag |= TSE_SELECTED;
+ }
+ else {
+ tselem->flag &= ~TSE_SELECTED;
+ }
+}
+
+static void outliner_select_sync_from_pose_bone(SpaceOutliner *soops,
+ bPoseChannel *pchan_active,
+ TreeElement *te,
+ TreeStoreElem *tselem)
+{
+ bPoseChannel *pchan = (bPoseChannel *)te->directdata;
+ Bone *bone = pchan->bone;
+
+ if (pchan == pchan_active) {
+ outliner_element_activate(soops, tselem);
+ }
+
+ if (bone->flag & BONE_SELECTED) {
+ tselem->flag |= TSE_SELECTED;
+ }
+ else {
+ tselem->flag &= ~TSE_SELECTED;
+ }
+}
+
+static void outliner_select_sync_from_sequence(SpaceOutliner *soops,
+ Sequence *sequence_active,
+ TreeStoreElem *tselem)
+{
+ Sequence *seq = (Sequence *)tselem->id;
+
+ if (seq == sequence_active) {
+ outliner_element_activate(soops, tselem);
+ }
+
+ if (seq->flag & SELECT) {
+ tselem->flag |= TSE_SELECTED;
+ }
+ else {
+ tselem->flag &= ~TSE_SELECTED;
+ }
+}
+
+/**
+ * Contains active object, bones, and sequence for syncing to prevent getting active data
+ * repeatedly throughout syncing to the outliner.
+ */
+typedef struct SyncSelectActiveData {
+ Object *object;
+ EditBone *edit_bone;
+ bPoseChannel *pose_channel;
+ Sequence *sequence;
+} SyncSelectActiveData;
+
+/** Sync select and active flags from active view layer, bones, and sequences to the outliner. */
+static void outliner_sync_selection_to_outliner(ViewLayer *view_layer,
+ SpaceOutliner *soops,
+ ListBase *tree,
+ SyncSelectActiveData *active_data,
+ const SyncSelectTypes *sync_types)
+{
+ for (TreeElement *te = tree->first; te; te = te->next) {
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (tselem->type == 0 && te->idcode == ID_OB) {
+ if (sync_types->object) {
+ outliner_select_sync_from_object(view_layer, soops, active_data->object, te, tselem);
+ }
+ }
+ else if (tselem->type == TSE_EBONE) {
+ if (sync_types->edit_bone) {
+ outliner_select_sync_from_edit_bone(soops, active_data->edit_bone, te, tselem);
+ }
+ }
+ else if (tselem->type == TSE_POSE_CHANNEL) {
+ if (sync_types->pose_bone) {
+ outliner_select_sync_from_pose_bone(soops, active_data->pose_channel, te, tselem);
+ }
+ }
+ else if (tselem->type == TSE_SEQUENCE) {
+ if (sync_types->sequence) {
+ outliner_select_sync_from_sequence(soops, active_data->sequence, tselem);
+ }
+ }
+ else {
+ tselem->flag &= ~TSE_SELECTED;
+ }
+
+ /* Sync subtree elements */
+ outliner_sync_selection_to_outliner(view_layer, soops, &te->subtree, active_data, sync_types);
+ }
+}
+
+/* Get active data from context */
+static void get_sync_select_active_data(const bContext *C, SyncSelectActiveData *active_data)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ active_data->object = OBACT(view_layer);
+ active_data->edit_bone = CTX_data_active_bone(C);
+ active_data->pose_channel = CTX_data_active_pose_bone(C);
+ active_data->sequence = BKE_sequencer_active_get(scene);
+}
+
+/* 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;
+ outliner_sync_select_to_outliner_set_types(C, soops, &sync_types);
+
+ /* Store active object, bones, and sequence */
+ SyncSelectActiveData active_data;
+ get_sync_select_active_data(C, &active_data);
+
+ outliner_sync_selection_to_outliner(
+ view_layer, soops, &soops->tree, &active_data, &sync_types);
+
+ /* Keep any unsynced data in the dirty flag */
+ if (sync_types.object) {
+ soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_OBJECT;
+ }
+ if (sync_types.edit_bone) {
+ soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE;
+ }
+ 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;
+ }
+ }
+}
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index f9905cc4fcd..49f6189c17c 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -63,6 +63,7 @@
#include "ED_armature.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_scene.h"
#include "ED_screen.h"
#include "ED_sequencer.h"
@@ -478,6 +479,129 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot)
}
/* ******************************************** */
+/**
+ * Stores the parent and a child element of a merged icon-row icon for
+ * the merged select popup menu. The sub-tree of the parent is searched and
+ * the child is needed to only show elements of the same type in the popup.
+ */
+typedef struct MergedSearchData {
+ TreeElement *parent_element;
+ TreeElement *select_element;
+} MergedSearchData;
+
+static void merged_element_search_cb_recursive(
+ const ListBase *tree, short tselem_type, short type, const char *str, uiSearchItems *items)
+{
+ char name[64];
+ int iconid;
+
+ for (TreeElement *te = tree->first; te; te = te->next) {
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (tree_element_id_type_to_index(te) == type && tselem_type == tselem->type) {
+ if (BLI_strcasestr(te->name, str)) {
+ BLI_strncpy(name, te->name, 64);
+
+ iconid = tree_element_get_icon(tselem, te).icon;
+
+ /* Don't allow duplicate named items */
+ if (UI_search_items_find_index(items, name) == -1) {
+ if (!UI_search_item_add(items, name, te, iconid)) {
+ break;
+ }
+ }
+ }
+ }
+
+ merged_element_search_cb_recursive(&te->subtree, tselem_type, type, str, items);
+ }
+}
+
+/* Get a list of elements that match the search string */
+static void merged_element_search_cb(const bContext *UNUSED(C),
+ void *data,
+ const char *str,
+ uiSearchItems *items)
+{
+ MergedSearchData *search_data = (MergedSearchData *)data;
+ TreeElement *parent = search_data->parent_element;
+ TreeElement *te = search_data->select_element;
+
+ int type = tree_element_id_type_to_index(te);
+
+ merged_element_search_cb_recursive(&parent->subtree, TREESTORE(te)->type, type, str, items);
+}
+
+/* Activate an element from the merged element search menu */
+static void merged_element_search_call_cb(struct bContext *C, void *UNUSED(arg1), void *element)
+{
+ SpaceOutliner *soops = CTX_wm_space_outliner(C);
+ TreeElement *te = (TreeElement *)element;
+
+ outliner_item_select(soops, te, false, false);
+ outliner_item_do_activate_from_tree_element(C, te, te->store_elem, false, false);
+
+ if (soops->flag & SO_SYNC_SELECT) {
+ ED_outliner_select_sync_from_outliner(C, soops);
+ }
+}
+
+/** Merged element search menu
+ * Created on activation of a merged or aggregated icon-row icon.
+ */
+static uiBlock *merged_element_search_menu(bContext *C, ARegion *ar, void *data)
+{
+ static char search[64] = "";
+ uiBlock *block;
+ uiBut *but;
+
+ /* Clear search on each menu creation */
+ *search = '\0';
+
+ block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
+ 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);
+
+ short menu_width = 10 * UI_UNIT_X;
+ but = uiDefSearchBut(
+ block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, menu_width, UI_UNIT_Y, 0, 0, "");
+ UI_but_func_search_set(
+ but, NULL, merged_element_search_cb, data, false, merged_element_search_call_cb, NULL);
+ UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
+
+ /* Fake button to hold space for search items */
+ uiDefBut(block,
+ UI_BTYPE_LABEL,
+ 0,
+ "",
+ 10,
+ 10 - UI_searchbox_size_y(),
+ menu_width,
+ UI_searchbox_size_y(),
+ NULL,
+ 0,
+ 0,
+ 0,
+ 0,
+ NULL);
+
+ /* Center the menu on the cursor */
+ UI_block_bounds_set_popup(block, 6, (const int[2]){-(menu_width / 2), 0});
+
+ return block;
+}
+
+void merged_element_search_menu_invoke(bContext *C,
+ TreeElement *parent_te,
+ TreeElement *activate_te)
+{
+ MergedSearchData *select_data = MEM_callocN(sizeof(MergedSearchData), "merge_search_data");
+ select_data->parent_element = parent_te;
+ select_data->select_element = activate_te;
+
+ UI_popup_block_invoke(C, merged_element_search_menu, select_data, MEM_freeN);
+}
+
static void object_select_cb(bContext *C,
ReportList *UNUSED(reports),
Scene *UNUSED(scene),
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index cc062467dbe..ec5510cdf84 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -297,7 +297,7 @@ static void outliner_add_scene_contents(SpaceOutliner *soops,
ViewLayer *view_layer;
for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
- TreeElement *tenlay = outliner_add_element(soops, &ten->subtree, sce, te, TSE_R_LAYER, 0);
+ TreeElement *tenlay = outliner_add_element(soops, &ten->subtree, sce, ten, TSE_R_LAYER, 0);
tenlay->name = view_layer->name;
tenlay->directdata = view_layer;
}
@@ -314,7 +314,7 @@ static void outliner_add_scene_contents(SpaceOutliner *soops,
ten = outliner_add_element(soops, lb, sce, te, TSE_SCENE_OBJECTS_BASE, 0);
ten->name = IFACE_("Objects");
FOREACH_SCENE_OBJECT_BEGIN (sce, ob) {
- outliner_add_element(soops, &ten->subtree, ob, NULL, 0, 0);
+ outliner_add_element(soops, &ten->subtree, ob, ten, 0, 0);
}
FOREACH_SCENE_OBJECT_END;
outliner_make_object_parent_hierarchy(&ten->subtree);
@@ -2008,6 +2008,9 @@ static int outliner_exclude_filter_get(SpaceOutliner *soops)
case SO_FILTER_OB_VISIBLE:
exclude_filter |= SO_FILTER_OB_STATE_VISIBLE;
break;
+ case SO_FILTER_OB_INVISIBLE:
+ exclude_filter |= SO_FILTER_OB_STATE_INVISIBLE;
+ break;
case SO_FILTER_OB_SELECTED:
exclude_filter |= SO_FILTER_OB_STATE_SELECTED;
break;
@@ -2086,6 +2089,11 @@ static bool outliner_element_visible_get(ViewLayer *view_layer,
return false;
}
}
+ else if (exclude_filter & SO_FILTER_OB_STATE_INVISIBLE) {
+ if ((base->flag & BASE_VISIBLE) != 0) {
+ return false;
+ }
+ }
else if (exclude_filter & SO_FILTER_OB_STATE_SELECTED) {
if ((base->flag & BASE_SELECTED) == 0) {
return false;
@@ -2339,7 +2347,8 @@ void outliner_build_tree(
te = outliner_add_element(soops, &soops->tree, sce, NULL, 0, 0);
tselem = TREESTORE(te);
- if (sce == scene && show_opened) {
+ /* New scene elements open by default */
+ if ((sce == scene && show_opened) || !tselem->used) {
tselem->flag &= ~TSE_CLOSED;
}
diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c
index f57dce97b38..5dfdf6f129b 100644
--- a/source/blender/editors/space_outliner/outliner_utils.c
+++ b/source/blender/editors/space_outliner/outliner_utils.c
@@ -24,11 +24,15 @@
#include "BLI_utildefines.h"
#include "DNA_action_types.h"
+#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "BKE_context.h"
#include "BKE_outliner_treehash.h"
+#include "BKE_layer.h"
#include "ED_armature.h"
+#include "ED_outliner.h"
#include "UI_interface.h"
#include "UI_view2d.h"
@@ -62,6 +66,38 @@ TreeElement *outliner_find_item_at_y(const SpaceOutliner *soops,
return NULL;
}
+static TreeElement *outliner_find_item_at_x_in_row_recursive(const TreeElement *parent_te,
+ float view_co_x,
+ bool *r_merged)
+{
+ TreeElement *child_te = parent_te->subtree.first;
+
+ bool over_element = false;
+
+ while (child_te) {
+ over_element = (view_co_x > child_te->xs) && (view_co_x < child_te->xend);
+ if ((child_te->flag & TE_ICONROW) && over_element) {
+ return child_te;
+ }
+ else if ((child_te->flag & TE_ICONROW_MERGED) && over_element) {
+ if (r_merged) {
+ *r_merged = true;
+ }
+ return child_te;
+ }
+
+ TreeElement *te = outliner_find_item_at_x_in_row_recursive(child_te, view_co_x, r_merged);
+ if (te != child_te) {
+ return te;
+ }
+
+ child_te = child_te->next;
+ }
+
+ /* return parent if no child is hovered */
+ return (TreeElement *)parent_te;
+}
+
/**
* Collapsed items can show their children as click-able icons. This function tries to find
* such an icon that represents the child item at x-coordinate \a view_co_x (view-space).
@@ -70,24 +106,14 @@ TreeElement *outliner_find_item_at_y(const SpaceOutliner *soops,
*/
TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *soops,
const TreeElement *parent_te,
- float view_co_x)
+ float view_co_x,
+ bool *r_merged)
{
- /* if parent_te is opened, it doesn't show childs in row */
+ /* if parent_te is opened, it doesn't show children in row */
if (!TSELEM_OPEN(TREESTORE(parent_te), soops)) {
- /* no recursion, items can only display their direct children in the row */
- for (TreeElement *child_te = parent_te->subtree.first;
- /* don't look further if co_x is smaller than child position*/
- child_te && view_co_x >= child_te->xs;
-
- child_te = child_te->next) {
- if ((child_te->flag & TE_ICONROW) && (view_co_x > child_te->xs) &&
- (view_co_x < child_te->xend)) {
- return child_te;
- }
- }
+ return outliner_find_item_at_x_in_row_recursive(parent_te, view_co_x, r_merged);
}
- /* return parent if no child is hovered */
return (TreeElement *)parent_te;
}
@@ -300,3 +326,89 @@ float outliner_restrict_columns_width(const SpaceOutliner *soops)
}
return (num_columns * UI_UNIT_X + V2D_SCROLL_WIDTH);
}
+
+/* Find first tree element in tree with matching treestore flag */
+TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag)
+{
+ for (TreeElement *te = lb->first; te; te = te->next) {
+ if ((TREESTORE(te)->flag & flag) == flag) {
+ return te;
+ }
+ TreeElement *active_element = outliner_find_element_with_flag(&te->subtree, flag);
+ if (active_element) {
+ return active_element;
+ }
+ }
+ return NULL;
+}
+
+/* Find if element is visible in the outliner tree */
+bool outliner_is_element_visible(const TreeElement *te)
+{
+ TreeStoreElem *tselem;
+
+ while (te->parent) {
+ tselem = TREESTORE(te->parent);
+
+ if (tselem->flag & TSE_CLOSED) {
+ return false;
+ }
+ else {
+ te = te->parent;
+ }
+ }
+
+ return true;
+}
+
+/* Find if x coordinate is over element disclosure toggle */
+bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_co_x)
+{
+ return (view_co_x > te->xs) && (view_co_x < te->xs + UI_UNIT_X);
+}
+
+/* Scroll view vertically while keeping within total bounds */
+void outliner_scroll_view(ARegion *ar, int delta_y)
+{
+ int y_min = MIN2(ar->v2d.cur.ymin, ar->v2d.tot.ymin);
+
+ ar->v2d.cur.ymax += delta_y;
+ ar->v2d.cur.ymin += delta_y;
+
+ /* Adjust view if delta placed view outside total area */
+ int offset;
+ if (ar->v2d.cur.ymax > -UI_UNIT_Y) {
+ offset = ar->v2d.cur.ymax;
+ ar->v2d.cur.ymax -= offset;
+ ar->v2d.cur.ymin -= offset;
+ }
+ else if (ar->v2d.cur.ymin < y_min) {
+ offset = y_min - ar->v2d.cur.ymin;
+ ar->v2d.cur.ymax += offset;
+ ar->v2d.cur.ymin += offset;
+ }
+}
+
+/* Get base of object under cursor. Used for eyedropper tool */
+Base *ED_outliner_give_base_under_cursor(bContext *C, const int mval[2])
+{
+ ARegion *ar = CTX_wm_region(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ SpaceOutliner *soops = CTX_wm_space_outliner(C);
+ TreeElement *te;
+ Base *base = NULL;
+ float view_mval[2];
+
+ UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
+
+ te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
+ if (te) {
+ TreeStoreElem *tselem = TREESTORE(te);
+ if (tselem->type == 0) {
+ Object *ob = (Object *)tselem->id;
+ base = (te->directdata) ? (Base *)te->directdata : BKE_view_layer_base_find(view_layer, ob);
+ }
+ }
+
+ return base;
+}
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index 091efc56c09..79880c68120 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -131,6 +131,9 @@ static void outliner_main_region_listener(wmWindow *UNUSED(win),
ED_region_tag_redraw(ar);
break;
}
+ if (wmn->action & NA_EDITED) {
+ ED_region_tag_redraw(ar);
+ }
break;
case NC_OBJECT:
switch (wmn->data) {
@@ -145,13 +148,8 @@ static void outliner_main_region_listener(wmWindow *UNUSED(win),
ED_region_tag_redraw(ar);
break;
case ND_CONSTRAINT:
- switch (wmn->action) {
- case NA_ADDED:
- case NA_REMOVED:
- case NA_RENAME:
- ED_region_tag_redraw(ar);
- break;
- }
+ /* all constraint actions now, for reordering */
+ ED_region_tag_redraw(ar);
break;
case ND_MODIFIER:
/* all modifier actions now */
@@ -304,6 +302,8 @@ static SpaceLink *outliner_new(const ScrArea *UNUSED(area), const Scene *UNUSED(
soutliner->filter_id_type = ID_GR;
soutliner->show_restrict_flags = SO_RESTRICT_ENABLE | SO_RESTRICT_HIDE;
soutliner->outlinevis = SO_VIEW_LAYER;
+ soutliner->sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_ALL;
+ soutliner->flag |= SO_SYNC_SELECT;
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for outliner");
@@ -349,6 +349,9 @@ static SpaceLink *outliner_duplicate(SpaceLink *sl)
soutlinern->treestore = NULL;
soutlinern->treehash = NULL;
+ soutlinern->flag |= (soutliner->flag & SO_SYNC_SELECT);
+ soutlinern->sync_select_dirty = WM_OUTLINER_SYNC_SELECT_FROM_ALL;
+
return (SpaceLink *)soutlinern;
}
@@ -415,7 +418,7 @@ void ED_spacetype_outliner(void)
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype outliner region");
art->regionid = RGN_TYPE_WINDOW;
- art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES;
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
art->init = outliner_main_region_init;
art->draw = outliner_main_region_draw;
@@ -428,7 +431,7 @@ void ED_spacetype_outliner(void)
art = MEM_callocN(sizeof(ARegionType), "spacetype outliner header region");
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
- art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
art->init = outliner_header_region_init;
art->draw = outliner_header_region_draw;
diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt
index d57be0c85c3..84ded1dd2c7 100644
--- a/source/blender/editors/space_sequencer/CMakeLists.txt
+++ b/source/blender/editors/space_sequencer/CMakeLists.txt
@@ -20,8 +20,8 @@ set(INC
../../blenkernel
../../blenlib
../../blentranslation
- ../../gpu
../../depsgraph
+ ../../gpu
../../imbuf
../../makesdna
../../makesrna
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 07350b5269e..b15acb12d00 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -1045,9 +1045,8 @@ ImBuf *sequencer_ibuf_get(struct Main *bmain,
bmain, depsgraph, scene, rectx, recty, proxy_size, false, &context);
context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
- /* sequencer could start rendering, in this case we need to be sure it wouldn't be canceled
- * by Esc pressed somewhere in the past
- */
+ /* Sequencer could start rendering, in this case we need to be sure it wouldn't be canceled
+ * by Escape pressed somewhere in the past. */
G.is_break = false;
/* Rendering can change OGL context. Save & Restore framebuffer. */
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 57f86059d9d..affb6d3fd88 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -41,6 +41,7 @@
/* for menu/popup icons etc etc*/
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_sequencer.h"
#include "ED_select_utils.h"
@@ -49,6 +50,7 @@
/* own include */
#include "sequencer_intern.h"
+
static void *find_nearest_marker(int UNUSED(d1), int UNUSED(d2))
{
return NULL;
@@ -254,6 +256,8 @@ static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
}
}
+ ED_outliner_select_sync_from_sequence_tag(C);
+
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -293,6 +297,8 @@ static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
}
}
+ ED_outliner_select_sync_from_sequence_tag(C);
+
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -542,6 +548,8 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
}
}
+ ED_outliner_select_sync_from_sequence_tag(C);
+
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
/* allowing tweaks */
@@ -668,6 +676,8 @@ static int sequencer_select_more_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
+ ED_outliner_select_sync_from_sequence_tag(C);
+
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -699,6 +709,8 @@ static int sequencer_select_less_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
+ ED_outliner_select_sync_from_sequence_tag(C);
+
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -750,6 +762,8 @@ static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, cons
selected = select_more_less_seq__internal(scene, 1, 1);
}
+ ED_outliner_select_sync_from_sequence_tag(C);
+
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -784,6 +798,8 @@ static int sequencer_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
selected = select_more_less_seq__internal(scene, true, true);
}
+ ED_outliner_select_sync_from_sequence_tag(C);
+
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -832,6 +848,8 @@ static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
}
}
+ ED_outliner_select_sync_from_sequence_tag(C);
+
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -876,6 +894,8 @@ static int sequencer_select_active_side_exec(bContext *C, wmOperator *op)
select_active_side(
ed->seqbasep, RNA_enum_get(op->ptr, "side"), seq_act->machine, seq_act->startdisp);
+ ED_outliner_select_sync_from_sequence_tag(C);
+
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -934,6 +954,8 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op)
}
}
+ ED_outliner_select_sync_from_sequence_tag(C);
+
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -1311,6 +1333,7 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
}
if (changed) {
+ ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index 12b446c3f4c..9aa9d14cbc8 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -675,10 +675,9 @@ static void sequencer_preview_region_draw(const bContext *C, ARegion *ar)
WM_gizmomap_draw(ar->gizmo_map, C, WM_GIZMOMAP_DRAWSTEP_2D);
if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) {
- rcti rect;
- ED_region_visible_rect(ar, &rect);
- int xoffset = rect.xmin + U.widget_unit;
- int yoffset = rect.ymax;
+ const rcti *rect = ED_region_visible_rect(ar);
+ int xoffset = rect->xmin + U.widget_unit;
+ int yoffset = rect->ymax;
ED_scene_draw_fps(scene, xoffset, &yoffset);
}
}
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index 8bfb6c87625..c1a3c79b0d8 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -63,6 +63,8 @@ static SpaceLink *text_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scen
stext->lheight = 12;
stext->tabnumber = 4;
stext->margin_column = 80;
+ stext->showsyntax = true;
+ stext->showlinenrs = true;
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for text");
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index 9dc8dfa93b6..e99bf680077 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -54,6 +54,7 @@ typedef struct TextDrawContext {
int font_id;
int cwidth;
int lheight_dpi;
+ bool syntax_highlight;
} TextDrawContext;
static void text_draw_context_init(const SpaceText *st, TextDrawContext *tdc)
@@ -61,6 +62,7 @@ static void text_draw_context_init(const SpaceText *st, TextDrawContext *tdc)
tdc->font_id = blf_mono_font;
tdc->cwidth = 0;
tdc->lheight_dpi = st->lheight_dpi;
+ tdc->syntax_highlight = st->showsyntax && ED_text_is_syntax_highlight_supported(st->text);
}
static void text_font_begin(const TextDrawContext *tdc)
@@ -418,7 +420,7 @@ static int text_draw_wrapped(const SpaceText *st,
const char *format,
int skip)
{
- const bool use_syntax = (st->showsyntax && format);
+ const bool use_syntax = (tdc->syntax_highlight && format);
FlattenString fs;
int basex, lines;
int i, wrap, end, max, columns, padding; /* column */
@@ -514,7 +516,7 @@ static void text_draw(const SpaceText *st,
int y,
const char *format)
{
- const bool use_syntax = (st->showsyntax && format);
+ const bool use_syntax = (tdc->syntax_highlight && format);
FlattenString fs;
int columns, size, n, w = 0, padding, amount = 0;
const char *in = NULL;
@@ -1383,8 +1385,8 @@ static void draw_brackets(const SpaceText *st, const TextDrawContext *tdc, ARegi
char ch;
- // showsyntax must be on or else the format string will be null
- if (!text->curl || !st->showsyntax) {
+ // syntax_highlight must be on or else the format string will be null
+ if (!text->curl || !tdc->syntax_highlight) {
return;
}
@@ -1576,7 +1578,7 @@ void draw_text_main(SpaceText *st, ARegion *ar)
tmp = text->lines.first;
lineno = 0;
for (i = 0; i < st->top && tmp; i++) {
- if (st->showsyntax && !tmp->format) {
+ if (tdc.syntax_highlight && !tmp->format) {
tft->format_line(st, tmp, false);
}
@@ -1631,7 +1633,7 @@ void draw_text_main(SpaceText *st, ARegion *ar)
UI_FontThemeColor(tdc.font_id, TH_TEXT);
for (i = 0; y > clip_min_y && i < st->viewlines && tmp; i++, tmp = tmp->next) {
- if (st->showsyntax && !tmp->format) {
+ if (tdc.syntax_highlight && !tmp->format) {
tft->format_line(st, tmp, false);
}
diff --git a/source/blender/editors/space_text/text_format.c b/source/blender/editors/space_text/text_format.c
index 8c102dc009e..48ee30e450f 100644
--- a/source/blender/editors/space_text/text_format.c
+++ b/source/blender/editors/space_text/text_format.c
@@ -25,10 +25,13 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_string_utils.h"
#include "DNA_text_types.h"
#include "DNA_space_types.h"
+#include "ED_text.h"
+
#include "text_format.h"
/****************** flatten string **********************/
@@ -224,3 +227,38 @@ TextFormatType *ED_text_format_get(Text *text)
return tft_lb.first;
}
}
+
+bool ED_text_is_syntax_highlight_supported(Text *text)
+{
+ if (text == NULL) {
+ return false;
+ }
+
+ TextFormatType *tft;
+
+ const char *text_ext = BLI_path_extension(text->id.name + 2);
+ if (text_ext == NULL) {
+ /* Extensionless datablocks are considered highlightable as Python. */
+ return true;
+ }
+ text_ext++; /* skip the '.' */
+ if (BLI_string_is_decimal(text_ext)) {
+ /* "Text.001" is treated as extensionless, and thus highlightable. */
+ return true;
+ }
+
+ /* Check all text formats in the static list */
+ for (tft = tft_lb.first; tft; tft = tft->next) {
+ /* All formats should have an ext, but just in case */
+ const char **ext;
+ for (ext = tft->ext; *ext; ext++) {
+ /* If extension matches text name, return the matching tft */
+ if (BLI_strcasecmp(text_ext, *ext) == 0) {
+ return true;
+ }
+ }
+ }
+
+ /* The filename has a non-numerical extension that we could not highlight. */
+ return false;
+}
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index a8af9c73bf2..e1550deb659 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -1217,36 +1217,34 @@ static int text_comment_exec(bContext *C, wmOperator *op)
Text *text = CTX_data_edit_text(C);
int type = RNA_enum_get(op->ptr, "type");
- if (txt_has_sel(text)) {
- text_drawcache_tag_update(CTX_wm_space_text(C), 0);
+ text_drawcache_tag_update(CTX_wm_space_text(C), 0);
- ED_text_undo_push_init(C);
+ ED_text_undo_push_init(C);
+ if (txt_has_sel(text)) {
txt_order_cursors(text, false);
+ }
- switch (type) {
- case 1:
+ switch (type) {
+ case 1:
+ txt_comment(text);
+ break;
+ case -1:
+ txt_uncomment(text);
+ break;
+ default:
+ if (txt_uncomment(text) == false) {
txt_comment(text);
- break;
- case -1:
- txt_uncomment(text);
- break;
- default:
- if (txt_uncomment(text) == false) {
- txt_comment(text);
- }
- break;
- }
-
- text_update_edited(text);
+ }
+ break;
+ }
- text_update_cursor_moved(C);
- WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text);
+ text_update_edited(text);
- return OPERATOR_FINISHED;
- }
+ text_update_cursor_moved(C);
+ WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text);
- return OPERATOR_CANCELLED;
+ return OPERATOR_FINISHED;
}
void TEXT_OT_comment_toggle(wmOperatorType *ot)
diff --git a/source/blender/editors/space_text/text_undo.c b/source/blender/editors/space_text/text_undo.c
index a6393291f9a..4a628cf70e4 100644
--- a/source/blender/editors/space_text/text_undo.c
+++ b/source/blender/editors/space_text/text_undo.c
@@ -187,6 +187,7 @@ static bool text_undosys_step_encode(struct bContext *C,
Text *text = us->text_ref.ptr;
BLI_assert(text == CTX_data_edit_text(C));
+ UNUSED_VARS_NDEBUG(C);
us->step.data_size += text_undosys_step_encode_to_state(&us->states[1], text);
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 38e8d285c77..b412a72cce1 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -145,7 +145,7 @@ void ED_draw_object_facemap(Depsgraph *depsgraph,
facemap_data = CustomData_get_layer(&me->pdata, CD_FACEMAP);
- /* use gawain immediate mode fore now */
+ /* Make a batch and free it each time for now. */
const int looptris_len = poly_to_tri_count(mpoly_len, mloop_len);
const int vbo_len_capacity = looptris_len * 3;
int vbo_len_used = 0;
diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c
index 0045094542f..f8f97848d14 100644
--- a/source/blender/editors/space_view3d/view3d_camera_control.c
+++ b/source/blender/editors/space_view3d/view3d_camera_control.c
@@ -87,8 +87,7 @@ typedef struct View3DCameraControl {
float ofs_backup[3];
/* backup the views offset in case the user cancels flying in non camera mode */
- /* backup the views quat in case the user cancels flying in non camera mode.
- * (quat for view, eul for camera) */
+ /* backup the views quat in case the user cancels flying in non camera mode. */
float rot_backup[4];
/* remember if were ortho or not, only used for restoring the view if it was a ortho view */
char persp_backup;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 8844428b1bf..6c534ee1b98 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1382,8 +1382,7 @@ void view3d_draw_region_info(const bContext *C, ARegion *ar)
ED_region_pixelspace(ar);
/* local coordinate visible rect inside region, to accommodate overlapping ui */
- rcti rect;
- ED_region_visible_rect(ar, &rect);
+ const rcti *rect = ED_region_visible_rect(ar);
view3d_draw_border(C, ar);
view3d_draw_grease_pencil(C);
@@ -1399,14 +1398,14 @@ void view3d_draw_region_info(const bContext *C, ARegion *ar)
/* The gizmo handles it's own drawing. */
break;
case USER_MINI_AXIS_TYPE_MINIMAL:
- draw_view_axis(rv3d, &rect);
+ draw_view_axis(rv3d, rect);
case USER_MINI_AXIS_TYPE_NONE:
break;
}
}
- int xoffset = rect.xmin + U.widget_unit;
- int yoffset = rect.ymax;
+ int xoffset = rect->xmin + U.widget_unit;
+ int yoffset = rect->ymax;
if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0 && (v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) {
if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) {
diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c
index 040b257bb90..d5772e5052a 100644
--- a/source/blender/editors/space_view3d/view3d_draw_legacy.c
+++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c
@@ -162,6 +162,7 @@ static void validate_object_select_id(
Object *obact_eval = DEG_get_evaluated_object(depsgraph, obact);
BLI_assert(ar->regiontype == RGN_TYPE_WINDOW);
+ UNUSED_VARS_NDEBUG(ar);
if (obact_eval && (obact_eval->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) ||
BKE_paint_select_face_test(obact_eval))) {
@@ -185,7 +186,8 @@ static void validate_object_select_id(
}
if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE) != 0)) {
- DRW_draw_select_id_object(depsgraph, view_layer, ar, v3d, obact, -1);
+ Base *base = BKE_view_layer_base_find(view_layer, obact);
+ DRW_select_buffer_context_create(&base, 1, -1);
}
/* TODO: Create a flag in `DRW_manager` because the drawing is no longer
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index ec7c1c0b3b9..b9adde6f60e 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -404,9 +404,7 @@ static void viewops_data_create(bContext *C,
if (viewops_flag & VIEWOPS_FLAG_PERSP_ENSURE) {
if (ED_view3d_persp_ensure(depsgraph, vod->v3d, vod->ar)) {
/* If we're switching from camera view to the perspective one,
- * need to tag viewport update, so camera vuew and borders
- * are properly updated.
- */
+ * need to tag viewport update, so camera view and borders are properly updated. */
ED_region_tag_redraw(vod->ar);
}
}
@@ -517,9 +515,6 @@ static void viewops_data_create(bContext *C,
static void viewops_data_free(bContext *C, wmOperator *op)
{
ARegion *ar;
-#if 0
- Paint *p = BKE_paint_get_active_from_context(C);
-#endif
if (op->customdata) {
ViewOpsData *vod = op->customdata;
ar = vod->ar;
@@ -536,12 +531,9 @@ static void viewops_data_free(bContext *C, wmOperator *op)
ar = CTX_wm_region(C);
}
-#if 0
- if (p && (p->flags & PAINT_FAST_NAVIGATE))
-#endif
- {
- ED_region_tag_redraw(ar);
- }
+ /* Need to redraw because drawing code uses RV3D_NAVIGATING to draw
+ * faster while navigation operator runs. */
+ ED_region_tag_redraw(ar);
}
/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c
index 3e2e113be3e..dbbc7f2a32e 100644
--- a/source/blender/editors/space_view3d/view3d_fly.c
+++ b/source/blender/editors/space_view3d/view3d_fly.c
@@ -146,42 +146,60 @@ typedef struct FlyInfo {
struct Depsgraph *depsgraph;
Scene *scene;
- wmTimer *timer; /* needed for redraws */
+ /** Needed for for updating that isn't triggered by input. */
+ wmTimer *timer;
short state;
bool redraw;
bool use_precision;
- /* if the user presses shift they can look about
- * without moving the direction there looking */
+ /** If the user presses shift they can look about without moving the direction there looking. */
bool use_freelook;
- bool anim_playing; /* needed for autokeyframing */
+ /**
+ * Needed for auto-keyframing, when animation isn't playing, only keyframe on confirmation.
+ *
+ * Currently we can't cancel this operator usefully while recording on animation playback
+ * (this would need to un-key all previous frames).
+ */
+ bool anim_playing;
- int mval[2]; /* latest 2D mouse values */
- int center_mval[2]; /* center mouse values */
- float width, height; /* camera viewport dimensions */
+ /** Latest 2D mouse values. */
+ int mval[2];
+ /** Center mouse values. */
+ int center_mval[2];
+ /** Camera viewport dimensions. */
+ float width, height;
#ifdef WITH_INPUT_NDOF
- wmNDOFMotionData *ndof; /* latest 3D mouse values */
+ /** Latest 3D mouse values. */
+ wmNDOFMotionData *ndof;
#endif
/* fly state state */
- float speed; /* the speed the view is moving per redraw */
- short axis; /* Axis index to move along by default Z to move along the view */
- bool pan_view; /* when true, pan the view instead of rotating */
+ /** The speed the view is moving per redraw. */
+ float speed;
+ /** Axis index to move along by default Z to move along the view. */
+ short axis;
+ /** When true, pan the view instead of rotating. */
+ bool pan_view;
eFlyPanState xlock, zlock;
- float xlock_momentum, zlock_momentum; /* nicer dynamics */
- float grid; /* world scale 1.0 default */
+ /** Nicer dynamics. */
+ float xlock_momentum, zlock_momentum;
+ /** World scale 1.0 default. */
+ float grid;
/* compare between last state */
- double time_lastwheel; /* used to accelerate when using the mousewheel a lot */
- double time_lastdraw; /* time between draws */
+ /** Used to accelerate when using the mousewheel a lot. */
+ double time_lastwheel;
+ /** Time between draws. */
+ double time_lastdraw;
void *draw_handle_pixel;
/* use for some lag */
- float dvec_prev[3]; /* old for some lag */
+ /** Keep the previous value to smooth transitions (use lag). */
+ float dvec_prev[3];
struct View3DCameraControl *v3d_camera_control;
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
index ad1a57eb71f..3c911e266a9 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
@@ -246,18 +246,17 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
copy_v3_v3(navgroup->gz_array[GZ_INDEX_ROTATE]->matrix_offset[i], rv3d->viewmat[i]);
}
- rcti rect_visible;
- ED_region_visible_rect(ar, &rect_visible);
+ const rcti *rect_visible = ED_region_visible_rect(ar);
- if ((navgroup->state.rect_visible.xmax == rect_visible.xmax) &&
- (navgroup->state.rect_visible.ymax == rect_visible.ymax) &&
+ if ((navgroup->state.rect_visible.xmax == rect_visible->xmax) &&
+ (navgroup->state.rect_visible.ymax == rect_visible->ymax) &&
(navgroup->state.rv3d.is_persp == rv3d->is_persp) &&
(navgroup->state.rv3d.is_camera == (rv3d->persp == RV3D_CAMOB)) &&
(navgroup->state.rv3d.viewlock == rv3d->viewlock)) {
return;
}
- navgroup->state.rect_visible = rect_visible;
+ navgroup->state.rect_visible = *rect_visible;
navgroup->state.rv3d.is_persp = rv3d->is_persp;
navgroup->state.rv3d.is_camera = (rv3d->persp == RV3D_CAMOB);
navgroup->state.rv3d.viewlock = rv3d->viewlock;
@@ -268,8 +267,8 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
const float icon_offset = (icon_size * 0.52f) * GIZMO_OFFSET_FAC * UI_DPI_FAC;
const float icon_offset_mini = icon_size * GIZMO_MINI_OFFSET_FAC * UI_DPI_FAC;
const float co_rotate[2] = {
- rect_visible.xmax - icon_offset,
- rect_visible.ymax - icon_offset,
+ rect_visible->xmax - icon_offset,
+ rect_visible->ymax - icon_offset,
};
float icon_offset_from_axis = 0.0f;
@@ -286,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_from_axis,
+ rect_visible->ymax - icon_offset_mini * 0.75f,
};
wmGizmo *gz;
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index d20a854c022..37ea10773bf 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -88,6 +88,7 @@
#include "ED_particle.h"
#include "ED_mesh.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_sculpt.h"
@@ -197,43 +198,31 @@ static bool object_deselect_all_except(ViewLayer *view_layer, Base *b)
* \{ */
struct EditSelectBuf_Cache {
- Base **bases;
- uint bases_len;
BLI_bitmap *select_bitmap;
};
-static void editselect_buf_cache_init(struct EditSelectBuf_Cache *esel,
- ViewContext *vc,
- short select_mode)
+static void editselect_buf_cache_init(ViewContext *vc, short select_mode)
{
if (vc->obedit) {
- esel->bases = BKE_view_layer_array_from_bases_in_edit_mode(
- vc->view_layer, vc->v3d, &esel->bases_len);
+ uint bases_len = 0;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(
+ vc->view_layer, vc->v3d, &bases_len);
+
+ DRW_select_buffer_context_create(bases, bases_len, select_mode);
+ MEM_freeN(bases);
}
else {
/* Use for paint modes, currently only a single object at a time. */
if (vc->obact) {
- esel->bases = MEM_mallocN(sizeof(esel->bases), __func__);
- esel->bases[0] = BKE_view_layer_base_find(vc->view_layer, vc->obact);
- esel->bases_len = 1;
+ Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact);
+ DRW_select_buffer_context_create(&base, 1, select_mode);
}
- else {
- esel->bases = NULL;
- esel->bases_len = 0;
- }
- }
-
- DRW_draw_select_id(vc->depsgraph, vc->ar, vc->v3d, esel->bases, esel->bases_len, select_mode);
-
- for (int i = 0; i < esel->bases_len; i++) {
- esel->bases[i]->object->runtime.select_id = i;
}
}
static void editselect_buf_cache_free(struct EditSelectBuf_Cache *esel)
{
MEM_SAFE_FREE(esel->select_bitmap);
- MEM_SAFE_FREE(esel->bases);
}
static void editselect_buf_cache_free_voidp(void *esel_voidp)
@@ -250,7 +239,7 @@ static void editselect_buf_cache_init_with_generic_userdata(wmGenericUserData *w
wm_userdata->data = esel;
wm_userdata->free_fn = editselect_buf_cache_free_voidp;
wm_userdata->use_free = true;
- editselect_buf_cache_init(esel, vc, select_mode);
+ editselect_buf_cache_init(vc, select_mode);
}
/** \} */
@@ -260,6 +249,7 @@ static void editselect_buf_cache_init_with_generic_userdata(wmGenericUserData *w
* \{ */
static bool edbm_backbuf_check_and_select_verts(struct EditSelectBuf_Cache *esel,
+ Depsgraph *depsgraph,
Object *ob,
BMEditMesh *em,
const eSelectOp sel_op)
@@ -269,9 +259,12 @@ static bool edbm_backbuf_check_and_select_verts(struct EditSelectBuf_Cache *esel
bool changed = false;
const BLI_bitmap *select_bitmap = esel->select_bitmap;
- uint index = DRW_select_buffer_context_offset_for_object_elem(ob->runtime.select_id,
- SCE_SELECT_VERTEX);
+ uint index = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_VERTEX);
+ if (index == 0) {
+ return false;
+ }
+ index -= 1;
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
@@ -288,6 +281,7 @@ static bool edbm_backbuf_check_and_select_verts(struct EditSelectBuf_Cache *esel
}
static bool edbm_backbuf_check_and_select_edges(struct EditSelectBuf_Cache *esel,
+ Depsgraph *depsgraph,
Object *ob,
BMEditMesh *em,
const eSelectOp sel_op)
@@ -297,9 +291,12 @@ static bool edbm_backbuf_check_and_select_edges(struct EditSelectBuf_Cache *esel
bool changed = false;
const BLI_bitmap *select_bitmap = esel->select_bitmap;
- uint index = DRW_select_buffer_context_offset_for_object_elem(ob->runtime.select_id,
- SCE_SELECT_EDGE);
+ uint index = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_EDGE);
+ if (index == 0) {
+ return false;
+ }
+ index -= 1;
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
@@ -316,6 +313,7 @@ static bool edbm_backbuf_check_and_select_edges(struct EditSelectBuf_Cache *esel
}
static bool edbm_backbuf_check_and_select_faces(struct EditSelectBuf_Cache *esel,
+ Depsgraph *depsgraph,
Object *ob,
BMEditMesh *em,
const eSelectOp sel_op)
@@ -325,9 +323,12 @@ static bool edbm_backbuf_check_and_select_faces(struct EditSelectBuf_Cache *esel
bool changed = false;
const BLI_bitmap *select_bitmap = esel->select_bitmap;
- uint index = DRW_select_buffer_context_offset_for_object_elem(ob->runtime.select_id,
- SCE_SELECT_FACE);
+ uint index = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_FACE);
+ if (index == 0) {
+ return false;
+ }
+ index -= 1;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
@@ -737,10 +738,12 @@ static void do_lasso_select_mesh__doSelectEdge_pass0(void *user_data,
{
struct LassoSelectUserData_ForMeshEdge *data_for_edge = user_data;
LassoSelectUserData *data = data_for_edge->data;
- const bool is_visible = (data_for_edge->esel ?
- BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap,
- data_for_edge->backbuf_offset + index) :
- true);
+ bool is_visible = true;
+ if (data_for_edge->backbuf_offset) {
+ uint bitmap_inedx = data_for_edge->backbuf_offset + index - 1;
+ is_visible = BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, bitmap_inedx);
+ }
+
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
const bool is_inside =
(is_visible && edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) &&
@@ -761,10 +764,12 @@ static void do_lasso_select_mesh__doSelectEdge_pass1(void *user_data,
{
struct LassoSelectUserData_ForMeshEdge *data_for_edge = user_data;
LassoSelectUserData *data = data_for_edge->data;
- const bool is_visible = (data_for_edge->esel ?
- BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap,
- data_for_edge->backbuf_offset + index) :
- true);
+ bool is_visible = true;
+ if (data_for_edge->backbuf_offset) {
+ uint bitmap_inedx = data_for_edge->backbuf_offset + index - 1;
+ is_visible = BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, bitmap_inedx);
+ }
+
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
const bool is_inside = (is_visible && BLI_lasso_is_edge_inside(data->mcords,
data->moves,
@@ -831,13 +836,15 @@ static bool do_lasso_select_mesh(ViewContext *vc,
if (wm_userdata->data == NULL) {
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode);
esel = wm_userdata->data;
- esel->select_bitmap = DRW_select_buffer_bitmap_from_poly(mcords, moves, &rect);
+ esel->select_bitmap = DRW_select_buffer_bitmap_from_poly(
+ vc->depsgraph, vc->ar, vc->v3d, mcords, moves, &rect, NULL);
}
}
if (ts->selectmode & SCE_SELECT_VERTEX) {
if (use_zbuf) {
- data.is_changed |= edbm_backbuf_check_and_select_verts(esel, vc->obedit, vc->em, sel_op);
+ data.is_changed |= edbm_backbuf_check_and_select_verts(
+ esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
}
else {
mesh_foreachScreenVert(
@@ -850,7 +857,7 @@ static bool do_lasso_select_mesh(ViewContext *vc,
.data = &data,
.esel = use_zbuf ? esel : NULL,
.backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem(
- vc->obedit->runtime.select_id, SCE_SELECT_EDGE) :
+ vc->depsgraph, vc->obedit, SCE_SELECT_EDGE) :
0,
};
@@ -866,7 +873,8 @@ static bool do_lasso_select_mesh(ViewContext *vc,
if (ts->selectmode & SCE_SELECT_FACE) {
if (use_zbuf) {
- data.is_changed |= edbm_backbuf_check_and_select_faces(esel, vc->obedit, vc->em, sel_op);
+ data.is_changed |= edbm_backbuf_check_and_select_faces(
+ esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
}
else {
mesh_foreachScreenFace(
@@ -1141,7 +1149,8 @@ static bool do_lasso_select_paintvert(ViewContext *vc,
if (wm_userdata->data == NULL) {
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_VERTEX);
esel = wm_userdata->data;
- esel->select_bitmap = DRW_select_buffer_bitmap_from_poly(mcords, moves, &rect);
+ esel->select_bitmap = DRW_select_buffer_bitmap_from_poly(
+ vc->depsgraph, vc->ar, vc->v3d, mcords, moves, &rect, NULL);
}
}
@@ -1199,7 +1208,8 @@ static bool do_lasso_select_paintface(ViewContext *vc,
if (esel == NULL) {
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_FACE);
esel = wm_userdata->data;
- esel->select_bitmap = DRW_select_buffer_bitmap_from_poly(mcords, moves, &rect);
+ esel->select_bitmap = DRW_select_buffer_bitmap_from_poly(
+ vc->depsgraph, vc->ar, vc->v3d, mcords, moves, &rect, NULL);
}
if (esel->select_bitmap) {
@@ -1271,9 +1281,15 @@ static bool view3d_lasso_select(
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
changed_multi |= do_lasso_select_pose(vc, mcords, moves, sel_op);
+ if (changed_multi) {
+ ED_outliner_select_sync_from_pose_bone_tag(C);
+ }
}
else {
changed_multi |= do_lasso_select_objects(vc, mcords, moves, sel_op);
+ if (changed_multi) {
+ ED_outliner_select_sync_from_object_tag(C);
+ }
}
}
else { /* Edit Mode */
@@ -1294,6 +1310,9 @@ static bool view3d_lasso_select(
break;
case OB_ARMATURE:
changed = do_lasso_select_armature(vc, mcords, moves, sel_op);
+ if (changed) {
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+ }
break;
case OB_MBALL:
changed = do_lasso_select_meta(vc, mcords, moves, sel_op);
@@ -1479,6 +1498,9 @@ static int object_select_menu_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+
+ ED_outliner_select_sync_from_object_tag(C);
+
return OPERATOR_FINISHED;
}
else {
@@ -2341,6 +2363,9 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
if (!retval && deselect_all) {
retval = ED_armature_edit_deselect_all_visible_multi(C);
}
+ if (retval) {
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+ }
}
else if (obedit->type == OB_LATTICE) {
retval = ED_lattice_select_pick(C, location, extend, deselect, toggle);
@@ -2401,6 +2426,15 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
}
}
+
+ if (retval) {
+ if (obact && obact->mode & OB_MODE_POSE) {
+ ED_outliner_select_sync_from_pose_bone_tag(C);
+ }
+ else {
+ ED_outliner_select_sync_from_object_tag(C);
+ }
+ }
}
/* Pass-through allows tweaks
@@ -2554,7 +2588,8 @@ static bool do_paintvert_box_select(ViewContext *vc,
if (wm_userdata->data == NULL) {
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_VERTEX);
esel = wm_userdata->data;
- esel->select_bitmap = DRW_select_buffer_bitmap_from_rect(rect, NULL);
+ esel->select_bitmap = DRW_select_buffer_bitmap_from_rect(
+ vc->depsgraph, vc->ar, vc->v3d, rect, NULL);
}
if (esel->select_bitmap != NULL) {
changed |= edbm_backbuf_check_and_select_verts_obmode(me, esel, sel_op);
@@ -2608,7 +2643,8 @@ static bool do_paintface_box_select(ViewContext *vc,
if (wm_userdata->data == NULL) {
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_FACE);
esel = wm_userdata->data;
- esel->select_bitmap = DRW_select_buffer_bitmap_from_rect(rect, NULL);
+ esel->select_bitmap = DRW_select_buffer_bitmap_from_rect(
+ vc->depsgraph, vc->ar, vc->v3d, rect, NULL);
}
if (esel->select_bitmap != NULL) {
changed |= edbm_backbuf_check_and_select_faces_obmode(me, esel, sel_op);
@@ -2731,10 +2767,12 @@ static void do_mesh_box_select__doSelectEdge_pass0(
{
struct BoxSelectUserData_ForMeshEdge *data_for_edge = userData;
BoxSelectUserData *data = data_for_edge->data;
- const bool is_visible = (data_for_edge->esel ?
- BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap,
- data_for_edge->backbuf_offset + index) :
- true);
+ bool is_visible = true;
+ if (data_for_edge->backbuf_offset) {
+ uint bitmap_inedx = data_for_edge->backbuf_offset + index - 1;
+ is_visible = BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, bitmap_inedx);
+ }
+
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
const bool is_inside = (is_visible &&
edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b));
@@ -2750,10 +2788,12 @@ static void do_mesh_box_select__doSelectEdge_pass1(
{
struct BoxSelectUserData_ForMeshEdge *data_for_edge = userData;
BoxSelectUserData *data = data_for_edge->data;
- const bool is_visible = (data_for_edge->esel ?
- BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap,
- data_for_edge->backbuf_offset + index) :
- true);
+ bool is_visible = true;
+ if (data_for_edge->backbuf_offset) {
+ uint bitmap_inedx = data_for_edge->backbuf_offset + index - 1;
+ is_visible = BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, bitmap_inedx);
+ }
+
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
const bool is_inside = (is_visible && edge_inside_rect(data->rect_fl, screen_co_a, screen_co_b));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
@@ -2805,13 +2845,15 @@ static bool do_mesh_box_select(ViewContext *vc,
if (wm_userdata->data == NULL) {
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode);
esel = wm_userdata->data;
- esel->select_bitmap = DRW_select_buffer_bitmap_from_rect(rect, NULL);
+ esel->select_bitmap = DRW_select_buffer_bitmap_from_rect(
+ vc->depsgraph, vc->ar, vc->v3d, rect, NULL);
}
}
if (ts->selectmode & SCE_SELECT_VERTEX) {
if (use_zbuf) {
- data.is_changed |= edbm_backbuf_check_and_select_verts(esel, vc->obedit, vc->em, sel_op);
+ data.is_changed |= edbm_backbuf_check_and_select_verts(
+ esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
}
else {
mesh_foreachScreenVert(
@@ -2824,7 +2866,7 @@ static bool do_mesh_box_select(ViewContext *vc,
.data = &data,
.esel = use_zbuf ? esel : NULL,
.backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem(
- vc->obedit->runtime.select_id, SCE_SELECT_EDGE) :
+ vc->depsgraph, vc->obedit, SCE_SELECT_EDGE) :
0,
};
@@ -2840,7 +2882,8 @@ static bool do_mesh_box_select(ViewContext *vc,
if (ts->selectmode & SCE_SELECT_FACE) {
if (use_zbuf) {
- data.is_changed |= edbm_backbuf_check_and_select_faces(esel, vc->obedit, vc->em, sel_op);
+ data.is_changed |= edbm_backbuf_check_and_select_faces(
+ esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
}
else {
mesh_foreachScreenFace(
@@ -3212,6 +3255,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
if (changed) {
DEG_id_tag_update(&vc.obedit->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
}
break;
case OB_LATTICE:
@@ -3246,9 +3290,15 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
}
else if (vc.obact && vc.obact->mode & OB_MODE_POSE) {
changed_multi = do_pose_box_select(C, &vc, &rect, sel_op);
+ if (changed_multi) {
+ ED_outliner_select_sync_from_pose_bone_tag(C);
+ }
}
else { /* object mode with none active */
changed_multi = do_object_box_select(C, &vc, &rect, sel_op);
+ if (changed_multi) {
+ ED_outliner_select_sync_from_object_tag(C);
+ }
}
}
@@ -3392,14 +3442,17 @@ static bool mesh_circle_select(ViewContext *vc,
struct EditSelectBuf_Cache *esel = wm_userdata->data;
if (use_zbuf) {
- esel->select_bitmap = DRW_select_buffer_bitmap_from_circle(mval, (int)(rad + 1.0f), NULL);
+ if (esel->select_bitmap == NULL) {
+ esel->select_bitmap = DRW_select_buffer_bitmap_from_circle(
+ vc->depsgraph, vc->ar, vc->v3d, mval, (int)(rad + 1.0f), NULL);
+ }
}
if (ts->selectmode & SCE_SELECT_VERTEX) {
if (use_zbuf) {
if (esel->select_bitmap != NULL) {
changed |= edbm_backbuf_check_and_select_verts(
- esel, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
+ esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
}
}
else {
@@ -3411,7 +3464,7 @@ static bool mesh_circle_select(ViewContext *vc,
if (use_zbuf) {
if (esel->select_bitmap != NULL) {
changed |= edbm_backbuf_check_and_select_edges(
- esel, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
+ esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
}
}
else {
@@ -3424,7 +3477,7 @@ static bool mesh_circle_select(ViewContext *vc,
if (use_zbuf) {
if (esel->select_bitmap != NULL) {
changed |= edbm_backbuf_check_and_select_faces(
- esel, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
+ esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
}
}
else {
@@ -3432,13 +3485,6 @@ static bool mesh_circle_select(ViewContext *vc,
}
}
- if (use_zbuf) {
- if (esel->select_bitmap != NULL) {
- MEM_freeN(esel->select_bitmap);
- esel->select_bitmap = NULL;
- }
- }
-
changed |= data.is_changed;
if (changed) {
@@ -3469,7 +3515,8 @@ static bool paint_facesel_circle_select(ViewContext *vc,
{
struct EditSelectBuf_Cache *esel = wm_userdata->data;
- esel->select_bitmap = DRW_select_buffer_bitmap_from_circle(mval, (int)(rad + 1.0f), NULL);
+ esel->select_bitmap = DRW_select_buffer_bitmap_from_circle(
+ vc->depsgraph, vc->ar, vc->v3d, mval, (int)(rad + 1.0f), NULL);
if (esel->select_bitmap != NULL) {
changed |= edbm_backbuf_check_and_select_faces_obmode(me, esel, sel_op);
MEM_freeN(esel->select_bitmap);
@@ -3509,8 +3556,8 @@ static bool paint_vertsel_circle_select(ViewContext *vc,
bool changed = false;
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- changed |= paintvert_deselect_all_visible(
- ob, SEL_DESELECT, false); /* flush selection at the end */
+ /* Flush selection at the end. */
+ changed |= paintvert_deselect_all_visible(ob, SEL_DESELECT, false);
}
const bool select = (sel_op != SEL_OP_SUB);
@@ -3523,7 +3570,8 @@ static bool paint_vertsel_circle_select(ViewContext *vc,
if (use_zbuf) {
struct EditSelectBuf_Cache *esel = wm_userdata->data;
- esel->select_bitmap = DRW_select_buffer_bitmap_from_circle(mval, (int)(rad + 1.0f), NULL);
+ esel->select_bitmap = DRW_select_buffer_bitmap_from_circle(
+ vc->depsgraph, vc->ar, vc->v3d, mval, (int)(rad + 1.0f), NULL);
if (esel->select_bitmap != NULL) {
changed |= edbm_backbuf_check_and_select_verts_obmode(me, esel, sel_op);
MEM_freeN(esel->select_bitmap);
@@ -3874,7 +3922,8 @@ static bool mball_circle_select(ViewContext *vc,
/** Callbacks for circle selection in Editmode */
-static bool obedit_circle_select(ViewContext *vc,
+static bool obedit_circle_select(bContext *C,
+ ViewContext *vc,
wmGenericUserData *wm_userdata,
const eSelectOp sel_op,
const int mval[2],
@@ -3895,6 +3944,9 @@ static bool obedit_circle_select(ViewContext *vc,
break;
case OB_ARMATURE:
changed = armature_circle_select(vc, sel_op, mval, rad);
+ if (changed) {
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+ }
break;
case OB_MBALL:
changed = mball_circle_select(vc, sel_op, mval, rad);
@@ -3983,7 +4035,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
obedit = vc.obedit;
if (obedit) {
- obedit_circle_select(&vc, wm_userdata, sel_op, mval, (float)radius);
+ obedit_circle_select(C, &vc, wm_userdata, sel_op, mval, (float)radius);
}
else if (BKE_paint_select_face_test(obact)) {
paint_facesel_circle_select(&vc, wm_userdata, sel_op, mval, (float)radius);
@@ -3993,6 +4045,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
}
else if (obact->mode & OB_MODE_POSE) {
pose_circle_select(&vc, sel_op, mval, (float)radius);
+ ED_outliner_select_sync_from_pose_bone_tag(C);
}
else {
BLI_assert(0);
@@ -4013,6 +4066,8 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
if (object_circle_select(&vc, sel_op, mval, (float)radius)) {
DEG_id_tag_update(&vc.scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc.scene);
+
+ ED_outliner_select_sync_from_object_tag(C);
}
}
@@ -4020,6 +4075,13 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
if (wm_userdata == &wm_userdata_buf) {
WM_generic_user_data_free(wm_userdata);
}
+ else {
+ struct EditSelectBuf_Cache *esel = wm_userdata->data;
+ if (esel && esel->select_bitmap) {
+ MEM_freeN(esel->select_bitmap);
+ esel->select_bitmap = NULL;
+ }
+ }
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c
index 7f930f1d876..1af94e3ade5 100644
--- a/source/blender/editors/space_view3d/view3d_utils.c
+++ b/source/blender/editors/space_view3d/view3d_utils.c
@@ -622,8 +622,8 @@ bool ED_view3d_camera_autokey(
/**
* Call after modifying a locked view.
*
- * \note Not every view edit currently auto-keys (numpad for eg),
- * this is complicated because of smoothview.
+ * \note Not every view edit currently auto-keys (num-pad for eg),
+ * this is complicated because of smooth-view.
*/
bool ED_view3d_camera_lock_autokey(View3D *v3d,
RegionView3D *rv3d,
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 22c1aafd7c4..91c05f5cac6 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -191,71 +191,89 @@ typedef struct WalkInfo {
struct Depsgraph *depsgraph;
Scene *scene;
- wmTimer *timer; /* needed for redraws */
+ /** Needed for for updating that isn't triggered by input. */
+ wmTimer *timer;
short state;
bool redraw;
- bool anim_playing; /* needed for autokeyframing */
+ /**
+ * Needed for auto-keyframing, when animation isn't playing, only keyframe on confirmation.
+ *
+ * Currently we can't cancel this operator usefully while recording on animation playback
+ * (this would need to un-key all previous frames).
+ */
+ bool anim_playing;
+
+ /** Previous 2D mouse values. */
+ int prev_mval[2];
+ /** Center mouse values. */
+ int center_mval[2];
- int prev_mval[2]; /* previous 2D mouse values */
- int center_mval[2]; /* center mouse values */
int moffset[2];
#ifdef WITH_INPUT_NDOF
- wmNDOFMotionData *ndof; /* latest 3D mouse values */
+ /** Latest 3D mouse values. */
+ wmNDOFMotionData *ndof;
#endif
/* walk state state */
- float base_speed; /* the base speed without run/slow down modifications */
- float speed; /* the speed the view is moving per redraw */
- float grid; /* world scale 1.0 default */
+ /** The base speed without run/slow down modifications. */
+ float base_speed;
+ /** The speed the view is moving per redraw. */
+ float speed;
+ /** World scale 1.0 default. */
+ float grid;
/* compare between last state */
- double time_lastdraw; /* time between draws */
+ /** Time between draws. */
+ double time_lastdraw;
void *draw_handle_pixel;
/* use for some lag */
- float dvec_prev[3]; /* old for some lag */
+ /** Keep the previous value to smooth transitions (use lag). */
+ float dvec_prev[3];
- /* walk/fly */
+ /** Walk/free movement. */
eWalkMethod navigation_mode;
/* teleport */
WalkTeleport teleport;
- /* look speed factor - user preferences */
+ /** Look speed factor - user preferences. */
float mouse_speed;
- /* speed adjustments */
+ /** Speed adjustments. */
bool is_fast;
bool is_slow;
- /* mouse reverse */
+ /** Mouse reverse. */
bool is_reversed;
#ifdef USE_TABLET_SUPPORT
- /* check if we had a cursor event before */
+ /** Check if we had a cursor event before. */
bool is_cursor_first;
- /* tablet devices (we can't relocate the cursor) */
+ /** Tablet devices (we can't relocate the cursor). */
bool is_cursor_absolute;
#endif
- /* gravity system */
+ /** Gravity system. */
eWalkGravityState gravity_state;
float gravity;
- /* height to use in walk mode */
+ /** Height to use in walk mode. */
float view_height;
- /* counting system to allow movement to continue if a direction (WASD) key is still pressed */
+ /** Counting system to allow movement to continue if a direction (WASD) key is still pressed. */
int active_directions;
float speed_jump;
- float jump_height; /* maximum jump height */
- float speed_factor; /* to use for fast/slow speeds */
+ /** Maximum jump height. */
+ float jump_height;
+ /** To use for fast/slow speeds. */
+ float speed_factor;
struct SnapObjectContext *snap_context;
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 98203a7e316..6478928a6b6 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -2009,19 +2009,18 @@ static void drawTransformView(const struct bContext *C, ARegion *ar, void *arg)
* to warn that autokeying is enabled */
static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
{
- rcti rect;
const char *printable = IFACE_("Auto Keying On");
float printable_size[2];
int xco, yco;
- ED_region_visible_rect(ar, &rect);
+ const rcti *rect = ED_region_visible_rect(ar);
const int font_id = BLF_default();
BLF_width_and_height(
font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
- xco = (rect.xmax - U.widget_unit) - (int)printable_size[0];
- yco = (rect.ymax - U.widget_unit);
+ xco = (rect->xmax - U.widget_unit) - (int)printable_size[0];
+ yco = (rect->ymax - U.widget_unit);
/* warning text (to clarify meaning of overlays)
* - original color was red to match the icon, but that clashes badly with a less nasty border
@@ -6602,7 +6601,7 @@ static void slide_origdata_interp_data_vert(SlideOrigData *sod,
* 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. MTexPoly) */
+ /* 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 */
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index f78f5c5e623..6a6d3b78d38 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -326,7 +326,7 @@ static void planeProjection(const TransInfo *t, const float in[3], float out[3])
sub_v3_v3v3(vec, out, in);
factor = dot_v3v3(vec, norm);
- if (fabsf(factor) <= 0.001f) {
+ if (factor == 0.0f) {
return; /* prevent divide by zero */
}
factor = dot_v3v3(vec, vec) / factor;
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index ef9d23d1db8..2fb9e2b9591 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -52,6 +52,7 @@
#include "BLI_string.h"
#include "BLI_bitmap.h"
#include "BLI_rect.h"
+#include "BLI_kdtree.h"
#include "BKE_action.h"
#include "BKE_animsys.h"
@@ -235,8 +236,9 @@ static void sort_trans_data_selected_first(TransInfo *t)
}
}
-/* distance calculated from not-selected vertex to nearest selected vertex
- * warning; this is loops inside loop, has minor N^2 issues, but by sorting list it is OK */
+/**
+ * Distance calculated from not-selected vertex to nearest selected vertex.
+ */
static void set_prop_dist(TransInfo *t, const bool with_dist)
{
int a;
@@ -255,54 +257,124 @@ static void set_prop_dist(TransInfo *t, const bool with_dist)
}
}
+ /* Count number of selected. */
+ int td_table_len = 0;
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *tob = tc->data;
- for (a = 0; a < tc->data_len; a++, tob++) {
+ 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;
+ }
+ }
+ }
- tob->rdist = 0.0f; // init, it was mallocced
+ /* 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__);
- if ((tob->flag & TD_SELECTED) == 0) {
- TransData *td;
- int i;
- float dist_sq, vec[3];
+ /* 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);
- tob->rdist = -1.0f; // signal for next loop
+ 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);
+ }
+ }
- for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
- if (td->flag & TD_SELECTED) {
- if (use_island) {
- sub_v3_v3v3(vec, tob->iloc, td->iloc);
- }
- else {
- sub_v3_v3v3(vec, tob->center, td->center);
- }
- mul_m3_v3(tob->mtx, vec);
+ if (proj_vec) {
+ float vec_p[3];
+ project_v3_v3v3(vec_p, vec, proj_vec);
+ sub_v3_v3(vec, vec_p);
+ }
- 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);
- dist_sq = len_squared_v3(vec);
- if ((tob->rdist == -1.0f) || (dist_sq < SQUARE(tob->rdist))) {
- tob->rdist = sqrtf(dist_sq);
- if (use_island) {
- copy_v3_v3(tob->center, td->center);
- copy_m3_m3(tob->axismtx, td->axismtx);
- }
- }
+ 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 {
- break; /* by definition transdata has selected items in beginning */
+ 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) {
- tob->dist = tob->rdist;
+ td->dist = td->rdist;
}
}
}
}
+
+ BLI_kdtree_3d_free(td_tree);
+ MEM_freeN(td_table);
}
/* ************************** CONVERSIONS ************************* */
diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c
index 6ebed88878f..e771fe43bd8 100644
--- a/source/blender/editors/transform/transform_input.c
+++ b/source/blender/editors/transform/transform_input.c
@@ -299,7 +299,7 @@ static void calcSpringFactor(MouseInput *mi)
void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
{
- /* incase we allocate a new value */
+ /* In case we allocate a new value. */
void *mi_data_prev = mi->data;
mi->use_virtual_mval = true;
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index d45a0588003..dbcc6c1b04a 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -1150,12 +1150,19 @@ static void TargetSnapMedian(TransInfo *t)
add_v3_v3(v, td->center);
}
+ if (i == 0) {
+ /* Is this possible? */
+ continue;
+ }
+
+ mul_v3_fl(v, 1.0 / i);
+
if (tc->use_local_mat) {
mul_m4_v3(tc->mat, v);
}
add_v3_v3(t->tsnap.snapTarget, v);
- i_accum += i;
+ i_accum++;
}
mul_v3_fl(t->tsnap.snapTarget, 1.0 / i_accum);
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index ed8178d1908..f485b440692 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -163,13 +163,13 @@ void ED_image_draw_cursor(ARegion *ar, const float cursor[2])
static void uvedit_get_batches(Object *ob,
SpaceImage *sima,
- const ToolSettings *ts,
+ const Scene *scene,
GPUBatch **faces,
GPUBatch **edges,
GPUBatch **verts,
GPUBatch **facedots)
{
- int drawfaces = draw_uvs_face_check(ts);
+ 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;
@@ -197,7 +197,7 @@ static void uvedit_get_batches(Object *ob,
*faces = NULL;
}
- DRW_mesh_batch_cache_create_requested(ob, ob->data, ts, false, false);
+ DRW_mesh_batch_cache_create_requested(ob, ob->data, scene, false, false);
}
static void draw_uvs_shadow(SpaceImage *UNUSED(sima),
@@ -212,7 +212,7 @@ static void draw_uvs_shadow(SpaceImage *UNUSED(sima),
DRW_mesh_batch_cache_validate(me);
GPUBatch *edges = DRW_mesh_batch_cache_get_uv_edges(me);
- DRW_mesh_batch_cache_create_requested(eval_ob, me, scene->toolsettings, false, false);
+ DRW_mesh_batch_cache_create_requested(eval_ob, me, scene, false, false);
if (edges) {
GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UV_UNIFORM_COLOR);
@@ -235,7 +235,7 @@ static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph)
DRW_mesh_batch_cache_validate(me);
GPUBatch *geom = DRW_mesh_batch_cache_get_uv_edges(me);
- DRW_mesh_batch_cache_create_requested(eval_ob, me, scene->toolsettings, false, false);
+ DRW_mesh_batch_cache_create_requested(eval_ob, me, scene, false, false);
GPU_batch_program_set_builtin(geom, GPU_SHADER_2D_UV_UNIFORM_COLOR);
GPU_batch_uniform_4fv(geom, "color", col);
@@ -300,7 +300,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
}
}
- uvedit_get_batches(eval_ob, sima, ts, &faces, &edges, &verts, &facedots);
+ uvedit_get_batches(eval_ob, sima, scene, &faces, &edges, &verts, &facedots);
bool interpedges;
bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0;
@@ -367,33 +367,33 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *
break;
}
case SI_UVDT_BLACK:
- case SI_UVDT_WHITE: {
- GPU_line_width(1.0f);
- GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UNIFORM_COLOR);
- if (sima->dt_uv == SI_UVDT_WHITE) {
- GPU_batch_uniform_4f(edges, "color", 1.0f, 1.0f, 1.0f, 1.0f);
- }
- else {
- GPU_batch_uniform_4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f);
- }
- GPU_batch_draw(edges);
- break;
- }
+ case SI_UVDT_WHITE:
case SI_UVDT_OUTLINE: {
/* We could modify the vbo's data filling
* instead of modifying the provoking vert. */
glProvokingVertex(GL_FIRST_VERTEX_CONVENTION);
- UI_GetThemeColor4fv(TH_WIRE_EDIT, col1);
UI_GetThemeColor4fv(TH_EDGE_SELECT, col2);
GPU_batch_program_set_builtin(
edges, (interpedges) ? GPU_SHADER_2D_UV_EDGES_SMOOTH : GPU_SHADER_2D_UV_EDGES);
- /* 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);
+
+ 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);
+
+ UI_GetThemeColor4fv(TH_WIRE_EDIT, col1);
+ }
+ else if (sima->dt_uv == SI_UVDT_WHITE) {
+ copy_v4_fl4(col1, 1.0f, 1.0f, 1.0f, 1.0f);
+ }
+ else {
+ copy_v4_fl4(col1, 0.0f, 0.0f, 0.0f, 1.0f);
+ }
+
/* Inner Line. Use depth test to insure selection is drawn on top. */
GPU_depth_test(true);
GPU_line_width(1.0f);
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 883671949c8..dcf1d04ffb3 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -4519,7 +4519,9 @@ static int uv_select_overlap(bContext *C, const bool extend)
const float(*t1)[2] = o_a->tri;
const float(*t2)[2] = o_b->tri;
float vi[2];
- bool result =
+ bool result = (
+ /* Don't use 'isect_tri_tri_v2' here
+ * because it's important to ignore overlap at end-points. */
isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[0], t2[1], endpoint_bias, vi) == 1 ||
isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[1], t2[2], endpoint_bias, vi) == 1 ||
isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[2], t2[0], endpoint_bias, vi) == 1 ||
@@ -4529,7 +4531,7 @@ static int uv_select_overlap(bContext *C, const bool extend)
isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[0], t2[1], endpoint_bias, vi) == 1 ||
isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[1], t2[2], endpoint_bias, vi) == 1 ||
isect_point_tri_v2(t1[0], t2[0], t2[1], t2[2]) != 0 ||
- isect_point_tri_v2(t2[0], t1[0], t1[1], t1[2]) != 0;
+ isect_point_tri_v2(t2[0], t1[0], t1[1], t1[2]) != 0);
if (result) {
uvedit_face_select_enable(scene, em_a, face_a, false, cd_loop_uv_offset_a);
diff --git a/source/blender/freestyle/intern/scene_graph/FrsMaterial.h b/source/blender/freestyle/intern/scene_graph/FrsMaterial.h
index c5a87c3baaf..80cd783f164 100644
--- a/source/blender/freestyle/intern/scene_graph/FrsMaterial.h
+++ b/source/blender/freestyle/intern/scene_graph/FrsMaterial.h
@@ -36,14 +36,14 @@ class FrsMaterial {
/*! Default constructor */
inline FrsMaterial();
- /*! Builds a Material from its line, diffuse, ambiant, specular, emissive
+ /*! Builds a Material from its line, diffuse, ambient, specular, emissive
* colors, a shininess coefficient and line color priority.
* \param iLine:
* A 4 element float-array containing the line color.
* \param iDiffuse:
* A 4 element float-array containing the diffuse color.
* \param iAmbiant:
- * A 4 element float-array containing the ambiant color.
+ * A 4 element float-array containing the ambient color.
* \param iSpecular:
* A 4 element float-array containing the specular color.
* \param iEmission:
@@ -159,31 +159,31 @@ class FrsMaterial {
return Specular[3];
}
- /*! Returns the ambiant color as a 4 float array */
+ /*! Returns the ambient color as a 4 float array */
inline const float *ambient() const
{
return Ambient;
}
- /*! Returns the red component of the ambiant color */
+ /*! Returns the red component of the ambient color */
inline const float ambientR() const
{
return Ambient[0];
}
- /*! Returns the green component of the ambiant color */
+ /*! Returns the green component of the ambient color */
inline const float ambientG() const
{
return Ambient[1];
}
- /*! Returns the blue component of the ambiant color */
+ /*! Returns the blue component of the ambient color */
inline const float ambientB() const
{
return Ambient[2];
}
- /*! Returns the alpha component of the ambiant color */
+ /*! Returns the alpha component of the ambient color */
inline const float ambientA() const
{
return Ambient[3];
@@ -267,7 +267,7 @@ class FrsMaterial {
*/
inline void setSpecular(const float r, const float g, const float b, const float a);
- /*! Sets the ambiant color.
+ /*! Sets the ambient color.
* \param r:
* Red component
* \param g:
diff --git a/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.h b/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.h
index d70794d9b78..f8dd25913c1 100644
--- a/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.h
+++ b/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.h
@@ -19,7 +19,7 @@
/** \file
* \ingroup freestyle
- * \brief A Set of indexed faces to represent a surfacic object
+ * \brief A Set of indexed faces to represent a surface object
*/
#include <memory.h>
diff --git a/source/blender/freestyle/intern/scene_graph/NodeTransform.h b/source/blender/freestyle/intern/scene_graph/NodeTransform.h
index ddae714f9d4..1118417657f 100644
--- a/source/blender/freestyle/intern/scene_graph/NodeTransform.h
+++ b/source/blender/freestyle/intern/scene_graph/NodeTransform.h
@@ -48,7 +48,7 @@ class NodeTransform : public NodeGroup {
/*! multiplies the current matrix by the x, y, z translation matrix. */
void Translate(real x, real y, real z);
- /*! multiplis the current matrix by a rotation matrix
+ /*! multiplies the current matrix by a rotation matrix
* iAngle
* The rotation angle
* x, y, z
@@ -56,13 +56,13 @@ class NodeTransform : public NodeGroup {
*/
void Rotate(real iAngle, real x, real y, real z);
- /*! multiplys the current matrix by a scaling matrix.
+ /*! multiplies the current matrix by a scaling matrix.
* x, y, z
* The scaling coefficients with respect to the x,y,z axis
*/
void Scale(real x, real y, real z);
- /*! Multiplys the current matrix by iMatrix */
+ /*! Multiplies the current matrix by iMatrix */
void MultiplyMatrix(const Matrix44r &iMatrix);
/*! Sets the current matrix to iMatrix */
diff --git a/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.h b/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.h
index 4eb4b2616fc..d14a9836b95 100644
--- a/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.h
+++ b/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.h
@@ -250,7 +250,7 @@ class GetSteerableViewMapDensityF1D : public UnaryFunction1D<double> {
// GetViewMapGradientNormF1D
/*! Returns the density of the viewmap for a given Interface1D. The density of each FEdge is
- * evaluated in the proper steerable ViewMap depending on its oorientation.
+ * evaluated in the proper steerable ViewMap depending on its orientation.
*/
class GetViewMapGradientNormF1D : public UnaryFunction1D<double> {
private:
diff --git a/source/blender/freestyle/intern/stroke/Curve.h b/source/blender/freestyle/intern/stroke/Curve.h
index 7eadfa830ce..8a233eef4ab 100644
--- a/source/blender/freestyle/intern/stroke/Curve.h
+++ b/source/blender/freestyle/intern/stroke/Curve.h
@@ -56,7 +56,7 @@ using namespace Geometry;
/*! Class to represent a point of a curve.
* A CurvePoint can be any point of a 1D curve (it doesn't have to be a vertex of the curve).
* Any Interface1D is built upon ViewEdges, themselves built upon FEdges. Therefore, a curve is
- * basically a polyline made of a list SVertex. Thus, a CurvePoint is built by lineraly
+ * basically a polyline made of a list SVertex. Thus, a CurvePoint is built by linearly
* interpolating two SVertex. CurvePoint can be used as virtual points while querying 0D
* information along a curve at a given resolution.
*/
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
index a27fb27d518..2168e7f07ec 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
@@ -46,6 +46,7 @@ static void initData(GpencilModifierData *md)
gpmd->step = 1;
gpmd->factor = 0.0f;
gpmd->length = 0.1f;
+ gpmd->distance = 0.1f;
gpmd->layername[0] = '\0';
}
@@ -94,7 +95,7 @@ static void deformStroke(GpencilModifierData *md,
break;
}
case GP_SIMPLIFY_MERGE: {
- BKE_gpencil_merge_distance_stroke(gpf, gps, mmd->length, true);
+ BKE_gpencil_merge_distance_stroke(gpf, gps, mmd->distance, true);
break;
}
default:
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
index 357e36a06b2..8ab72716f4d 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
@@ -102,16 +102,41 @@ static void deformStroke(GpencilModifierData *md,
return;
}
- /* if normalize, set stroke thickness */
+ /* Check to see if we normalize the whole stroke or only certain points along it. */
+ bool gps_has_affected_points = false;
+ bool gps_has_unaffected_points = false;
+
if (mmd->flag & GP_THICK_NORMALIZE) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
+ const float weight = get_modifier_point_weight(
+ dvert, (mmd->flag & GP_THICK_INVERT_VGROUP) != 0, def_nr);
+ if (weight < 0.0f) {
+ gps_has_unaffected_points = true;
+ }
+ else {
+ gps_has_affected_points = true;
+ }
+
+ /* If both checks are true, we have what we need so we can stop looking. */
+ if (gps_has_affected_points && gps_has_unaffected_points) {
+ break;
+ }
+ }
+ }
+
+ /* If we are normalizing and all points of the stroke are affected, it's safe to reset thickness
+ */
+ if (mmd->flag & GP_THICK_NORMALIZE && gps_has_affected_points && !gps_has_unaffected_points) {
gps->thickness = mmd->thickness;
}
+ /* Without this check, modifier alters the thickness of strokes which have no points in scope */
for (int i = 0; i < gps->totpoints; i++) {
bGPDspoint *pt = &gps->points[i];
MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
float curvef = 1.0f;
- /* verify vertex group */
+ /* Verify point is part of vertex group. */
const float weight = get_modifier_point_weight(
dvert, (mmd->flag & GP_THICK_INVERT_VGROUP) != 0, def_nr);
if (weight < 0.0f) {
@@ -119,11 +144,21 @@ static void deformStroke(GpencilModifierData *md,
}
if (mmd->flag & GP_THICK_NORMALIZE) {
- pt->pressure = 1.0f;
+ if (gps_has_unaffected_points) {
+ /* Clamp value for very weird situations when stroke thickness can be zero. */
+ CLAMP_MIN(gps->thickness, 0.001f);
+ /* Calculate pressure value to match the width of strokes with reset thickness and 1.0
+ * pressure. */
+ pt->pressure = (float)mmd->thickness / (float)gps->thickness;
+ }
+ else {
+ /* Reset point pressure values so only stroke thickness counts. */
+ pt->pressure = 1.0f;
+ }
}
else {
if ((mmd->flag & GP_THICK_CUSTOM_CURVE) && (mmd->curve_thickness)) {
- /* normalize value to evaluate curve */
+ /* Normalize value to evaluate curve. */
float value = (float)i / (gps->totpoints - 1);
curvef = BKE_curvemapping_evaluateF(mmd->curve_thickness, 0, value);
}
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index c620644a5f8..fb7d3c1ace8 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_matrix_private.h
intern/gpu_primitive_private.h
intern/gpu_private.h
intern/gpu_select_private.h
diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h
index 5b0cab220c0..175033f70d9 100644
--- a/source/blender/gpu/GPU_batch.h
+++ b/source/blender/gpu/GPU_batch.h
@@ -40,7 +40,7 @@ typedef enum {
GPU_BATCH_READY_TO_DRAW,
} GPUBatchPhase;
-#define GPU_BATCH_VBO_MAX_LEN 4
+#define GPU_BATCH_VBO_MAX_LEN 6
#define GPU_BATCH_VAO_STATIC_LEN 3
#define GPU_BATCH_VAO_DYN_ALLOC_COUNT 16
@@ -105,8 +105,9 @@ void GPU_batch_copy(GPUBatch *batch_dst, GPUBatch *batch_src);
#define GPU_batch_create(prim, verts, elem) GPU_batch_create_ex(prim, verts, elem, 0)
#define GPU_batch_init(batch, prim, verts, elem) GPU_batch_init_ex(batch, prim, verts, elem, 0)
-void GPU_batch_clear(
- GPUBatch *); /* Same as discard but does not free. (does not clal free callback) */
+/* Same as discard but does not free. (does not call free callback). */
+void GPU_batch_clear(GPUBatch *);
+
void GPU_batch_discard(GPUBatch *); /* verts & elem are not discarded */
void GPU_batch_vao_cache_clear(GPUBatch *);
@@ -114,6 +115,7 @@ void GPU_batch_vao_cache_clear(GPUBatch *);
void GPU_batch_callback_free_set(GPUBatch *, void (*callback)(GPUBatch *, void *), void *);
void GPU_batch_instbuf_set(GPUBatch *, GPUVertBuf *, bool own_vbo); /* Instancing */
+void GPU_batch_elembuf_set(GPUBatch *batch, GPUIndexBuf *elem, bool own_ibo);
int GPU_batch_vertbuf_add_ex(GPUBatch *, GPUVertBuf *, bool own_vbo);
diff --git a/source/blender/gpu/GPU_element.h b/source/blender/gpu/GPU_element.h
index 4ac89d2658b..75caf4cbd6a 100644
--- a/source/blender/gpu/GPU_element.h
+++ b/source/blender/gpu/GPU_element.h
@@ -36,14 +36,19 @@ typedef enum {
} GPUIndexBufType;
typedef struct GPUIndexBuf {
+ uint index_start;
uint index_len;
+ bool is_subrange;
#if GPU_TRACK_INDEX_RANGE
GPUIndexBufType index_type;
uint32_t gl_index_type;
uint base_index;
#endif
uint32_t ibo_id; /* 0 indicates not yet sent to VRAM */
- void *data; /* non-NULL indicates not yet sent to VRAM */
+ union {
+ void *data; /* non-NULL indicates not yet sent to VRAM */
+ struct GPUIndexBuf *src; /* if is_subrange is true, this is the source buffer. */
+ };
} GPUIndexBuf;
void GPU_indexbuf_use(GPUIndexBuf *);
@@ -71,9 +76,21 @@ void GPU_indexbuf_add_line_verts(GPUIndexBufBuilder *, uint v1, uint v2);
void GPU_indexbuf_add_tri_verts(GPUIndexBufBuilder *, uint v1, uint v2, uint v3);
void GPU_indexbuf_add_line_adj_verts(GPUIndexBufBuilder *, uint v1, uint v2, uint v3, uint v4);
+void GPU_indexbuf_set_point_vert(GPUIndexBufBuilder *builder, uint elem, uint v1);
+void GPU_indexbuf_set_line_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2);
+void GPU_indexbuf_set_tri_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2, uint v3);
+
+/* Skip primitive rendering at the given index. */
+void GPU_indexbuf_set_point_restart(GPUIndexBufBuilder *builder, uint elem);
+void GPU_indexbuf_set_line_restart(GPUIndexBufBuilder *builder, uint elem);
+void GPU_indexbuf_set_tri_restart(GPUIndexBufBuilder *builder, uint elem);
+
GPUIndexBuf *GPU_indexbuf_build(GPUIndexBufBuilder *);
void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *, GPUIndexBuf *);
+/* Create a subrange of an existing indexbuffer. */
+GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *ibo, uint start, uint length);
+
void GPU_indexbuf_discard(GPUIndexBuf *);
int GPU_indexbuf_primitive_len(GPUPrimType prim_type);
diff --git a/source/blender/gpu/GPU_matrix.h b/source/blender/gpu/GPU_matrix.h
index 61622c40ff0..a424f3180de 100644
--- a/source/blender/gpu/GPU_matrix.h
+++ b/source/blender/gpu/GPU_matrix.h
@@ -52,12 +52,12 @@ void GPU_matrix_translate_3f(float x, float y, float z);
void GPU_matrix_translate_3fv(const float vec[3]);
void GPU_matrix_scale_3f(float x, float y, float z);
void GPU_matrix_scale_3fv(const float vec[3]);
-void GPU_matrix_rotate_3f(float deg,
- float x,
- float y,
- float z); /* axis of rotation should be a unit vector */
-void GPU_matrix_rotate_3fv(float deg,
- const float axis[3]); /* axis of rotation should be a unit vector */
+
+/* Axis of rotation should be a unit vector. */
+void GPU_matrix_rotate_3f(float deg, float x, float y, float z);
+/* Axis of rotation should be a unit vector. */
+void GPU_matrix_rotate_3fv(float deg, const float axis[3]);
+
void GPU_matrix_rotate_axis(float deg, char axis); /* TODO: enum for axis? */
void GPU_matrix_look_at(float eyeX,
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 124f1f1ff8a..f4a94c7759a 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -396,7 +396,9 @@ void GPU_shader_free_builtin_shaders(void);
/* Vertex attributes for shaders */
-#define GPU_MAX_ATTR 32
+/* Hardware limit is 16. Position attribute is always needed so we reduce to 15.
+ * This makes sure the GPUVertexFormat name buffer does not overflow. */
+#define GPU_MAX_ATTR 15
typedef struct GPUVertAttrLayers {
struct {
diff --git a/source/blender/gpu/GPU_vertex_buffer.h b/source/blender/gpu/GPU_vertex_buffer.h
index 3e178e193dc..2d728422c42 100644
--- a/source/blender/gpu/GPU_vertex_buffer.h
+++ b/source/blender/gpu/GPU_vertex_buffer.h
@@ -87,9 +87,10 @@ void GPU_vertbuf_data_len_set(GPUVertBuf *, uint v_len);
* should not be a problem. */
void GPU_vertbuf_attr_set(GPUVertBuf *, uint a_idx, uint v_idx, const void *data);
-void GPU_vertbuf_attr_fill(GPUVertBuf *,
- uint a_idx,
- const void *data); /* tightly packed, non interleaved input data */
+
+/* Tightly packed, non interleaved input data. */
+void GPU_vertbuf_attr_fill(GPUVertBuf *, uint a_idx, const void *data);
+
void GPU_vertbuf_attr_fill_stride(GPUVertBuf *, uint a_idx, uint stride, const void *data);
/* For low level access only */
diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h
index 68608a98a79..8c22e3e1104 100644
--- a/source/blender/gpu/GPU_vertex_format.h
+++ b/source/blender/gpu/GPU_vertex_format.h
@@ -31,9 +31,11 @@
#include "BLI_assert.h"
#define GPU_VERT_ATTR_MAX_LEN 16
-#define GPU_VERT_ATTR_MAX_NAMES 5
-#define GPU_VERT_ATTR_NAME_AVERAGE_LEN 11
-#define GPU_VERT_ATTR_NAMES_BUF_LEN ((GPU_VERT_ATTR_NAME_AVERAGE_LEN + 1) * GPU_VERT_ATTR_MAX_LEN)
+#define GPU_VERT_ATTR_MAX_NAMES 6
+#define GPU_VERT_ATTR_NAMES_BUF_LEN 256
+#define GPU_VERT_FORMAT_MAX_NAMES 63 /* More than enough, actual max is ~30. */
+/* Computed as GPU_VERT_ATTR_NAMES_BUF_LEN / 30 (actual max format name). */
+#define GPU_MAX_SAFE_ATTRIB_NAME 12
typedef enum {
GPU_COMP_I8,
@@ -80,14 +82,16 @@ BLI_STATIC_ASSERT(GPU_VERT_ATTR_NAMES_BUF_LEN <= 256,
typedef struct GPUVertFormat {
/** 0 to 16 (GPU_VERT_ATTR_MAX_LEN). */
uint attr_len : 5;
- /** Total count of active vertex attribute. */
- uint name_len : 5;
+ /** Total count of active vertex attribute names. (max GPU_VERT_FORMAT_MAX_NAMES) */
+ uint name_len : 6;
/** Stride in bytes, 1 to 1024. */
uint stride : 11;
/** Has the format been packed. */
uint packed : 1;
/** Current offset in names[]. */
uint name_offset : 8;
+ /** Store each attrib in one contiguous buffer region. */
+ uint deinterleaved : 1;
GPUVertAttr attrs[GPU_VERT_ATTR_MAX_LEN];
char names[GPU_VERT_ATTR_NAMES_BUF_LEN];
@@ -104,6 +108,8 @@ uint GPU_vertformat_attr_add(
GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode);
void GPU_vertformat_alias_add(GPUVertFormat *, const char *alias);
+void GPU_vertformat_deinterleave(GPUVertFormat *format);
+
int GPU_vertformat_attr_id_get(const GPUVertFormat *, const char *name);
BLI_INLINE const char *GPU_vertformat_attr_name_get(const GPUVertFormat *format,
@@ -113,6 +119,8 @@ BLI_INLINE const char *GPU_vertformat_attr_name_get(const GPUVertFormat *format,
return format->names + attr->names[n_idx];
}
+void GPU_vertformat_safe_attrib_name(const char *attrib_name, char *r_safe_name, uint max_len);
+
/* format conversion */
typedef struct GPUPackedNormal {
@@ -122,7 +130,59 @@ typedef struct GPUPackedNormal {
int w : 2; /* 0 by default, can manually set to { -2, -1, 0, 1 } */
} GPUPackedNormal;
-GPUPackedNormal GPU_normal_convert_i10_v3(const float data[3]);
-GPUPackedNormal GPU_normal_convert_i10_s3(const short data[3]);
+/* OpenGL ES packs in a different order as desktop GL but component conversion is the same.
+ * Of the code here, only struct GPUPackedNormal needs to change. */
+
+#define SIGNED_INT_10_MAX 511
+#define SIGNED_INT_10_MIN -512
+
+BLI_INLINE int clampi(int x, int min_allowed, int max_allowed)
+{
+#if TRUST_NO_ONE
+ assert(min_allowed <= max_allowed);
+#endif
+ if (x < min_allowed) {
+ return min_allowed;
+ }
+ else if (x > max_allowed) {
+ return max_allowed;
+ }
+ else {
+ return x;
+ }
+}
+
+BLI_INLINE int gpu_convert_normalized_f32_to_i10(float x)
+{
+ int qx = x * 511.0f;
+ return clampi(qx, SIGNED_INT_10_MIN, SIGNED_INT_10_MAX);
+}
+
+BLI_INLINE int gpu_convert_i16_to_i10(short x)
+{
+ /* 16-bit signed --> 10-bit signed */
+ /* TODO: round? */
+ return x >> 6;
+}
+
+BLI_INLINE GPUPackedNormal GPU_normal_convert_i10_v3(const float data[3])
+{
+ GPUPackedNormal n = {
+ gpu_convert_normalized_f32_to_i10(data[0]),
+ gpu_convert_normalized_f32_to_i10(data[1]),
+ gpu_convert_normalized_f32_to_i10(data[2]),
+ };
+ return n;
+}
+
+BLI_INLINE GPUPackedNormal GPU_normal_convert_i10_s3(const short data[3])
+{
+ GPUPackedNormal n = {
+ gpu_convert_i16_to_i10(data[0]),
+ gpu_convert_i16_to_i10(data[1]),
+ gpu_convert_i16_to_i10(data[2]),
+ };
+ return n;
+}
#endif /* __GPU_VERTEX_FORMAT_H__ */
diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c
index 11b487f7be4..583551e3e58 100644
--- a/source/blender/gpu/intern/gpu_batch.c
+++ b/source/blender/gpu/intern/gpu_batch.c
@@ -182,6 +182,25 @@ void GPU_batch_instbuf_set(GPUBatch *batch, GPUVertBuf *inst, bool own_vbo)
}
}
+void GPU_batch_elembuf_set(GPUBatch *batch, GPUIndexBuf *elem, bool own_ibo)
+{
+ BLI_assert(elem != NULL);
+ /* redo the bindings */
+ GPU_batch_vao_cache_clear(batch);
+
+ if (batch->elem != NULL && (batch->owns_flag & GPU_BATCH_OWNS_INDEX)) {
+ GPU_indexbuf_discard(batch->elem);
+ }
+ batch->elem = elem;
+
+ if (own_ibo) {
+ batch->owns_flag |= GPU_BATCH_OWNS_INDEX;
+ }
+ else {
+ batch->owns_flag &= ~GPU_BATCH_OWNS_INDEX;
+ }
+}
+
/* Returns the index of verts in the batch. */
int GPU_batch_vertbuf_add_ex(GPUBatch *batch, GPUVertBuf *verts, bool own_vbo)
{
@@ -362,13 +381,23 @@ static void create_bindings(GPUVertBuf *verts,
const GPUVertFormat *format = &verts->format;
const uint attr_len = format->attr_len;
- const uint stride = format->stride;
+ uint stride = format->stride;
+ uint offset = 0;
GPU_vertbuf_use(verts);
for (uint a_idx = 0; a_idx < attr_len; ++a_idx) {
const GPUVertAttr *a = &format->attrs[a_idx];
- const GLvoid *pointer = (const GLubyte *)0 + a->offset + v_first * stride;
+
+ if (format->deinterleaved) {
+ offset += ((a_idx == 0) ? 0 : format->attrs[a_idx - 1].sz) * verts->vertex_len;
+ stride = a->sz;
+ }
+ else {
+ offset = a->offset;
+ }
+
+ const GLvoid *pointer = (const GLubyte *)0 + offset + v_first * stride;
for (uint n_idx = 0; n_idx < a->name_len; ++n_idx) {
const char *name = GPU_vertformat_attr_name_get(format, a, n_idx);
@@ -419,8 +448,11 @@ static void create_bindings(GPUVertBuf *verts,
static void batch_update_program_bindings(GPUBatch *batch, uint v_first)
{
- for (int v = 0; v < GPU_BATCH_VBO_MAX_LEN && batch->verts[v] != NULL; ++v) {
- create_bindings(batch->verts[v], batch->interface, (batch->inst) ? 0 : v_first, false);
+ /* 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) {
+ if (batch->verts[v] != NULL) {
+ create_bindings(batch->verts[v], batch->interface, (batch->inst) ? 0 : v_first, false);
+ }
}
if (batch->inst) {
create_bindings(batch->inst, batch->interface, v_first, true);
@@ -550,10 +582,10 @@ static void *elem_offset(const GPUIndexBuf *el, int v_first)
{
#if GPU_TRACK_INDEX_RANGE
if (el->index_type == GPU_INDEX_U16) {
- return (GLushort *)0 + v_first;
+ return (GLushort *)0 + v_first + el->index_start;
}
#endif
- return (GLuint *)0 + v_first;
+ return (GLuint *)0 + v_first + el->index_start;
}
/* Use when drawing with GPU_batch_draw_advanced */
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 51b73c93c86..0e15fdd000b 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -46,6 +46,7 @@
#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 */
@@ -929,12 +930,15 @@ static char *code_generate_fragment(GPUMaterial *material,
/* XXX This cannot go into gpu_shader_material.glsl because main()
* would be parsed and generate error */
/* Old glsl mode compat. */
+ /* TODO(fclem) This is only used by world shader now. get rid of it? */
BLI_dynstr_append(ds, "#ifndef NODETREE_EXEC\n");
BLI_dynstr_append(ds, "out vec4 fragColor;\n");
BLI_dynstr_append(ds, "void main()\n");
BLI_dynstr_append(ds, "{\n");
BLI_dynstr_append(ds, "\tClosure cl = nodetree_exec();\n");
- BLI_dynstr_append(ds, "\tfragColor = vec4(cl.radiance, cl.opacity);\n");
+ BLI_dynstr_append(ds,
+ "\tfragColor = vec4(cl.radiance, "
+ "saturate(1.0 - avg(cl.transmittance)));\n");
BLI_dynstr_append(ds, "}\n");
BLI_dynstr_append(ds, "#endif\n\n");
@@ -1008,19 +1012,24 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
ds, "#define att%d %s\n", input->attr_id, attr_prefix_get(input->attr_type));
}
else {
- uint hash = BLI_ghashutil_strhash_p(input->attr_name);
+ char attr_safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
+ GPU_vertformat_safe_attrib_name(
+ input->attr_name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
BLI_dynstr_appendf(ds,
- "DEFINE_ATTR(%s, %s%u);\n",
+ "DEFINE_ATTR(%s, %s%s);\n",
GPU_DATATYPE_STR[input->type],
attr_prefix_get(input->attr_type),
- hash);
- BLI_dynstr_appendf(
- ds, "#define att%d %s%u\n", input->attr_id, attr_prefix_get(input->attr_type), hash);
+ attr_safe_name);
+ BLI_dynstr_appendf(ds,
+ "#define att%d %s%s\n",
+ input->attr_id,
+ attr_prefix_get(input->attr_type),
+ attr_safe_name);
/* Auto attribute can be vertex color byte buffer.
* We need to know and convert them to linear space in VS. */
if (input->attr_type == CD_AUTO_FROM_NAME) {
- BLI_dynstr_appendf(ds, "uniform bool ba%u;\n", hash);
- BLI_dynstr_appendf(ds, "#define att%d_is_srgb ba%u\n", input->attr_id, hash);
+ BLI_dynstr_appendf(ds, "uniform bool ba%s;\n", attr_safe_name);
+ BLI_dynstr_appendf(ds, "#define att%d_is_srgb ba%s\n", input->attr_id, attr_safe_name);
}
}
BLI_dynstr_appendf(ds,
diff --git a/source/blender/gpu/intern/gpu_context.cpp b/source/blender/gpu/intern/gpu_context.cpp
index 97f9e52f944..17b86e3eec8 100644
--- a/source/blender/gpu/intern/gpu_context.cpp
+++ b/source/blender/gpu/intern/gpu_context.cpp
@@ -36,6 +36,7 @@
#include "gpu_batch_private.h"
#include "gpu_context_private.h"
+#include "gpu_matrix_private.h"
#include <vector>
#include <string.h>
@@ -71,6 +72,7 @@ struct GPUContext {
std::unordered_set<GPUFrameBuffer *>
framebuffers; /* Framebuffers that have FBO from this context */
#endif
+ struct GPUMatrixState *matrix_state;
std::vector<GLuint> orphaned_vertarray_ids;
std::vector<GLuint> orphaned_framebuffer_ids;
std::mutex orphans_mutex; /* todo: try spinlock instead */
@@ -101,9 +103,11 @@ static void orphans_add(GPUContext *ctx, std::vector<GLuint> *orphan_list, GLuin
static void orphans_clear(GPUContext *ctx)
{
- BLI_assert(ctx); /* need at least an active context */
- BLI_assert(pthread_equal(pthread_self(),
- ctx->thread)); /* context has been activated by another thread! */
+ /* need at least an active context */
+ BLI_assert(ctx);
+
+ /* context has been activated by another thread! */
+ BLI_assert(pthread_equal(pthread_self(), ctx->thread));
ctx->orphans_mutex.lock();
if (!ctx->orphaned_vertarray_ids.empty()) {
@@ -139,6 +143,7 @@ GPUContext *GPU_context_create(GLuint default_framebuffer)
GPUContext *ctx = new GPUContext;
glGenVertexArrays(1, &ctx->default_vao);
ctx->default_framebuffer = default_framebuffer;
+ ctx->matrix_state = GPU_matrix_state_create();
GPU_context_active_set(ctx);
return ctx;
}
@@ -159,6 +164,7 @@ void GPU_context_discard(GPUContext *ctx)
/* this removes the array entry */
GPU_batch_vao_cache_clear(*ctx->batches.begin());
}
+ GPU_matrix_state_discard(ctx->matrix_state);
glDeleteVertexArrays(1, &ctx->default_vao);
delete ctx;
active_ctx = NULL;
@@ -333,3 +339,9 @@ GPUFrameBuffer *gpu_context_active_framebuffer_get(GPUContext *ctx)
{
return ctx->current_fbo;
}
+
+struct GPUMatrixState *gpu_context_active_matrix_state_get()
+{
+ BLI_assert(active_ctx);
+ return active_ctx->matrix_state;
+}
diff --git a/source/blender/gpu/intern/gpu_context_private.h b/source/blender/gpu/intern/gpu_context_private.h
index 6825b67d2c8..c9379e5433f 100644
--- a/source/blender/gpu/intern/gpu_context_private.h
+++ b/source/blender/gpu/intern/gpu_context_private.h
@@ -59,6 +59,8 @@ void gpu_context_remove_framebuffer(GPUContext *ctx, struct GPUFrameBuffer *fb);
void gpu_context_active_framebuffer_set(GPUContext *ctx, struct GPUFrameBuffer *fb);
struct GPUFrameBuffer *gpu_context_active_framebuffer_get(GPUContext *ctx);
+struct GPUMatrixState *gpu_context_active_matrix_state_get(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/intern/gpu_element.c b/source/blender/gpu/intern/gpu_element.c
index 50e7df96503..6c9331b4903 100644
--- a/source/blender/gpu/intern/gpu_element.c
+++ b/source/blender/gpu/intern/gpu_element.c
@@ -162,6 +162,100 @@ void GPU_indexbuf_add_line_adj_verts(
GPU_indexbuf_add_generic_vert(builder, v4);
}
+void GPU_indexbuf_set_point_vert(GPUIndexBufBuilder *builder, uint elem, uint v1)
+{
+ BLI_assert(builder->prim_type == GPU_PRIM_POINTS);
+ BLI_assert(elem < builder->max_index_len);
+ builder->data[elem++] = v1;
+ if (builder->index_len < elem) {
+ builder->index_len = elem;
+ }
+}
+
+void GPU_indexbuf_set_line_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2)
+{
+ BLI_assert(builder->prim_type == GPU_PRIM_LINES);
+ BLI_assert(v1 != v2);
+ BLI_assert(v1 <= builder->max_allowed_index);
+ BLI_assert(v2 <= builder->max_allowed_index);
+ BLI_assert((elem + 1) * 2 <= builder->max_index_len);
+ uint idx = elem * 2;
+ builder->data[idx++] = v1;
+ builder->data[idx++] = v2;
+ if (builder->index_len < idx) {
+ builder->index_len = idx;
+ }
+}
+
+void GPU_indexbuf_set_tri_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2, uint v3)
+{
+ BLI_assert(builder->prim_type == GPU_PRIM_TRIS);
+ BLI_assert(v1 != v2 && v2 != v3 && v3 != v1);
+ BLI_assert(v1 <= builder->max_allowed_index);
+ BLI_assert(v2 <= builder->max_allowed_index);
+ BLI_assert(v3 <= builder->max_allowed_index);
+ BLI_assert((elem + 1) * 3 <= builder->max_index_len);
+ uint idx = elem * 3;
+ builder->data[idx++] = v1;
+ builder->data[idx++] = v2;
+ builder->data[idx++] = v3;
+ if (builder->index_len < idx) {
+ builder->index_len = idx;
+ }
+}
+
+void GPU_indexbuf_set_point_restart(GPUIndexBufBuilder *builder, uint elem)
+{
+ BLI_assert(builder->prim_type == GPU_PRIM_POINTS);
+ BLI_assert(elem < builder->max_index_len);
+ builder->data[elem++] = RESTART_INDEX;
+ if (builder->index_len < elem) {
+ builder->index_len = elem;
+ }
+}
+
+void GPU_indexbuf_set_line_restart(GPUIndexBufBuilder *builder, uint elem)
+{
+ BLI_assert(builder->prim_type == GPU_PRIM_LINES);
+ BLI_assert((elem + 1) * 2 <= builder->max_index_len);
+ uint idx = elem * 2;
+ builder->data[idx++] = RESTART_INDEX;
+ builder->data[idx++] = RESTART_INDEX;
+ if (builder->index_len < idx) {
+ builder->index_len = idx;
+ }
+}
+
+void GPU_indexbuf_set_tri_restart(GPUIndexBufBuilder *builder, uint elem)
+{
+ BLI_assert(builder->prim_type == GPU_PRIM_TRIS);
+ BLI_assert((elem + 1) * 3 <= builder->max_index_len);
+ uint idx = elem * 3;
+ builder->data[idx++] = RESTART_INDEX;
+ builder->data[idx++] = RESTART_INDEX;
+ builder->data[idx++] = RESTART_INDEX;
+ if (builder->index_len < idx) {
+ builder->index_len = idx;
+ }
+}
+
+GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *elem_src, uint start, uint length)
+{
+ GPUIndexBuf *elem = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf");
+ BLI_assert(elem_src && !elem_src->is_subrange);
+ BLI_assert(start + length <= elem_src->index_len);
+#if GPU_TRACK_INDEX_RANGE
+ elem->index_type = elem_src->index_type;
+ elem->gl_index_type = elem_src->gl_index_type;
+ elem->base_index = elem_src->base_index;
+#endif
+ elem->is_subrange = true;
+ elem->src = elem_src;
+ elem->index_start = start;
+ elem->index_len = length;
+ return elem;
+}
+
#if GPU_TRACK_INDEX_RANGE
/* Everything remains 32 bit while building to keep things simple.
* Find min/max after, then convert to smallest index type possible. */
@@ -271,6 +365,10 @@ static void indexbuf_upload_data(GPUIndexBuf *elem)
void GPU_indexbuf_use(GPUIndexBuf *elem)
{
+ if (elem->is_subrange) {
+ GPU_indexbuf_use(elem->src);
+ return;
+ }
if (elem->ibo_id == 0) {
elem->ibo_id = GPU_buf_alloc();
}
@@ -285,7 +383,7 @@ void GPU_indexbuf_discard(GPUIndexBuf *elem)
if (elem->ibo_id) {
GPU_buf_free(elem->ibo_id);
}
- if (elem->data) {
+ if (!elem->is_subrange && elem->data) {
MEM_freeN(elem->data);
}
MEM_freeN(elem);
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index 99dbff05453..5839b34cd19 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -309,6 +309,7 @@ void gpu_extensions_init(void)
}
else if ((strstr(renderer, "Mesa DRI R")) ||
(strstr(renderer, "Radeon") && strstr(vendor, "X.Org")) ||
+ (strstr(renderer, "AMD") && strstr(vendor, "X.Org")) ||
(strstr(renderer, "Gallium ") && strstr(renderer, " on ATI ")) ||
(strstr(renderer, "Gallium ") && strstr(renderer, " on AMD "))) {
GG.device = GPU_DEVICE_ATI;
diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.c
index 6b5c4836e83..0e3019ad122 100644
--- a/source/blender/gpu/intern/gpu_immediate.c
+++ b/source/blender/gpu/intern/gpu_immediate.c
@@ -220,8 +220,10 @@ void immBegin(GPUPrimType prim_type, uint vertex_len)
/* does the current buffer have enough room? */
const uint available_bytes = IMM_BUFFER_SIZE - imm.buffer_offset;
/* ensure vertex data is aligned */
- const uint pre_padding = padding(
- imm.buffer_offset, imm.vertex_format.stride); /* might waste a little space, but it's safe */
+
+ /* 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) {
imm.buffer_offset += pre_padding;
}
diff --git a/source/blender/gpu/intern/gpu_matrix.c b/source/blender/gpu/intern/gpu_matrix.c
index 58ca800a92c..fb0dffb58d1 100644
--- a/source/blender/gpu/intern/gpu_matrix.c
+++ b/source/blender/gpu/intern/gpu_matrix.c
@@ -23,6 +23,9 @@
#include "GPU_shader_interface.h"
+#include "gpu_context_private.h"
+#include "gpu_matrix_private.h"
+
#define SUPPRESS_GENERIC_MATRIX_API
#define USE_GPU_PY_MATRIX_API /* only so values are declared */
#include "GPU_matrix.h"
@@ -32,6 +35,8 @@
#include "BLI_math_rotation.h"
#include "BLI_math_vector.h"
+#include "MEM_guardedalloc.h"
+
#define DEBUG_MATRIX_BIND 0
#define MATRIX_STACK_DEPTH 32
@@ -44,7 +49,7 @@ typedef struct MatrixStack {
uint top;
} MatrixStack;
-typedef struct {
+typedef struct GPUMatrixState {
MatrixStack model_view_stack;
MatrixStack projection_stack;
@@ -56,8 +61,16 @@ typedef struct {
* TODO: separate Model from View transform? Batches/objects have model,
* camera/eye has view & projection
*/
-} MatrixState;
+} GPUMatrixState;
+
+#define ModelViewStack gpu_context_active_matrix_state_get()->model_view_stack
+#define ModelView ModelViewStack.stack[ModelViewStack.top]
+#define ProjectionStack gpu_context_active_matrix_state_get()->projection_stack
+#define Projection ProjectionStack.stack[ProjectionStack.top]
+
+GPUMatrixState *GPU_matrix_state_create(void)
+{
#define MATRIX_4X4_IDENTITY \
{ \
{1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 0.0f}, \
@@ -66,27 +79,36 @@ typedef struct {
} \
}
-static MatrixState state = {
- .model_view_stack = {{MATRIX_4X4_IDENTITY}, 0},
- .projection_stack = {{MATRIX_4X4_IDENTITY}, 0},
- .dirty = true,
-};
+ GPUMatrixState *state = MEM_mallocN(sizeof(*state), __func__);
+ const MatrixStack identity_stack = {{MATRIX_4X4_IDENTITY}, 0};
+
+ state->model_view_stack = state->projection_stack = identity_stack;
+ state->dirty = true;
#undef MATRIX_4X4_IDENTITY
-#define ModelViewStack state.model_view_stack
-#define ModelView ModelViewStack.stack[ModelViewStack.top]
+ return state;
+}
-#define ProjectionStack state.projection_stack
-#define Projection ProjectionStack.stack[ProjectionStack.top]
+void GPU_matrix_state_discard(GPUMatrixState *state)
+{
+ MEM_freeN(state);
+}
+
+static void gpu_matrix_state_active_set_dirty(bool value)
+{
+ GPUMatrixState *state = gpu_context_active_matrix_state_get();
+ state->dirty = value;
+}
void GPU_matrix_reset(void)
{
- state.model_view_stack.top = 0;
- state.projection_stack.top = 0;
+ GPUMatrixState *state = gpu_context_active_matrix_state_get();
+ state->model_view_stack.top = 0;
+ state->projection_stack.top = 0;
unit_m4(ModelView);
unit_m4(Projection);
- state.dirty = true;
+ gpu_matrix_state_active_set_dirty(true);
}
#ifdef WITH_GPU_SAFETY
@@ -123,7 +145,7 @@ void GPU_matrix_pop(void)
{
BLI_assert(ModelViewStack.top > 0);
ModelViewStack.top--;
- state.dirty = true;
+ gpu_matrix_state_active_set_dirty(true);
}
void GPU_matrix_push_projection(void)
@@ -137,34 +159,34 @@ void GPU_matrix_pop_projection(void)
{
BLI_assert(ProjectionStack.top > 0);
ProjectionStack.top--;
- state.dirty = true;
+ gpu_matrix_state_active_set_dirty(true);
}
void GPU_matrix_set(const float m[4][4])
{
copy_m4_m4(ModelView, m);
CHECKMAT(ModelView3D);
- state.dirty = true;
+ gpu_matrix_state_active_set_dirty(true);
}
void GPU_matrix_identity_projection_set(void)
{
unit_m4(Projection);
CHECKMAT(Projection3D);
- state.dirty = true;
+ gpu_matrix_state_active_set_dirty(true);
}
void GPU_matrix_projection_set(const float m[4][4])
{
copy_m4_m4(Projection, m);
CHECKMAT(Projection3D);
- state.dirty = true;
+ gpu_matrix_state_active_set_dirty(true);
}
void GPU_matrix_identity_set(void)
{
unit_m4(ModelView);
- state.dirty = true;
+ gpu_matrix_state_active_set_dirty(true);
}
void GPU_matrix_translate_2f(float x, float y)
@@ -194,7 +216,7 @@ void GPU_matrix_translate_3f(float x, float y, float z)
m[3][2] = z;
GPU_matrix_mul(m);
#endif
- state.dirty = true;
+ gpu_matrix_state_active_set_dirty(true);
}
void GPU_matrix_translate_3fv(const float vec[3])
@@ -243,7 +265,7 @@ void GPU_matrix_mul(const float m[4][4])
{
mul_m4_m4_post(ModelView, m);
CHECKMAT(ModelView);
- state.dirty = true;
+ gpu_matrix_state_active_set_dirty(true);
}
void GPU_matrix_rotate_2d(float deg)
@@ -272,7 +294,7 @@ void GPU_matrix_rotate_axis(float deg, char axis)
/* rotate_m4 works in place */
rotate_m4(ModelView, axis, DEG2RADF(deg));
CHECKMAT(ModelView);
- state.dirty = true;
+ gpu_matrix_state_active_set_dirty(true);
}
static void mat4_ortho_set(
@@ -298,7 +320,7 @@ static void mat4_ortho_set(
m[2][3] = 0.0f;
m[3][3] = 1.0f;
- state.dirty = true;
+ gpu_matrix_state_active_set_dirty(true);
}
static void mat4_frustum_set(
@@ -324,7 +346,7 @@ static void mat4_frustum_set(
m[2][3] = -1.0f;
m[3][3] = 0.0f;
- state.dirty = true;
+ gpu_matrix_state_active_set_dirty(true);
}
static void mat4_look_from_origin(float m[4][4], float lookdir[3], float camup[3])
@@ -389,14 +411,14 @@ static void mat4_look_from_origin(float m[4][4], float lookdir[3], float camup[3
m[2][3] = 0.0f;
m[3][3] = 1.0f;
- state.dirty = true;
+ gpu_matrix_state_active_set_dirty(true);
}
void GPU_matrix_ortho_set(float left, float right, float bottom, float top, float near, float far)
{
mat4_ortho_set(Projection, left, right, bottom, top, near, far);
CHECKMAT(Projection);
- state.dirty = true;
+ gpu_matrix_state_active_set_dirty(true);
}
void GPU_matrix_ortho_2d_set(float left, float right, float bottom, float top)
@@ -404,7 +426,7 @@ void GPU_matrix_ortho_2d_set(float left, float right, float bottom, float top)
Mat4 m;
mat4_ortho_set(m, left, right, bottom, top, -1.0f, 1.0f);
CHECKMAT(Projection2D);
- state.dirty = true;
+ gpu_matrix_state_active_set_dirty(true);
}
void GPU_matrix_frustum_set(
@@ -412,7 +434,7 @@ void GPU_matrix_frustum_set(
{
mat4_frustum_set(Projection, left, right, bottom, top, near, far);
CHECKMAT(Projection);
- state.dirty = true;
+ gpu_matrix_state_active_set_dirty(true);
}
void GPU_matrix_perspective_set(float fovy, float aspect, float near, float far)
@@ -678,12 +700,13 @@ void GPU_matrix_bind(const GPUShaderInterface *shaderface)
glUniformMatrix4fv(P_inv->location, 1, GL_FALSE, (const float *)m);
}
- state.dirty = false;
+ gpu_matrix_state_active_set_dirty(false);
}
bool GPU_matrix_dirty_get(void)
{
- return state.dirty;
+ GPUMatrixState *state = gpu_context_active_matrix_state_get();
+ return state->dirty;
}
/* -------------------------------------------------------------------- */
@@ -695,12 +718,14 @@ BLI_STATIC_ASSERT(GPU_PY_MATRIX_STACK_LEN + 1 == MATRIX_STACK_DEPTH, "define mis
int GPU_matrix_stack_level_get_model_view(void)
{
- return (int)state.model_view_stack.top;
+ GPUMatrixState *state = gpu_context_active_matrix_state_get();
+ return (int)state->model_view_stack.top;
}
int GPU_matrix_stack_level_get_projection(void)
{
- return (int)state.projection_stack.top;
+ GPUMatrixState *state = gpu_context_active_matrix_state_get();
+ return (int)state->projection_stack.top;
}
/** \} */
diff --git a/source/blender/gpu/intern/gpu_matrix_private.h b/source/blender/gpu/intern/gpu_matrix_private.h
new file mode 100644
index 00000000000..862ef065481
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_matrix_private.h
@@ -0,0 +1,35 @@
+/*
+ * 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 gpu
+ */
+
+#ifndef __GPU_MATRIX_PRIVATE_H__
+#define __GPU_MATRIX_PRIVATE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct GPUMatrixState *GPU_matrix_state_create(void);
+void GPU_matrix_state_discard(struct GPUMatrixState *state);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GPU_MATRIX_PRIVATE_H__ */
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index dab17fcd72a..955b11036ef 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -1598,7 +1598,7 @@ void GPU_texture_generate_mipmap(GPUTexture *tex)
if (GPU_texture_depth(tex)) {
/* Some drivers have bugs when using glGenerateMipmap with depth textures (see T56789).
- * In this case we just create a complete texture with mipmaps manually without downsampling.
+ * In this case we just create a complete texture with mipmaps manually without down-sampling.
* You must initialize the texture levels using other methods like
* GPU_framebuffer_recursive_downsample(). */
int levels = 1 + floor(log2(max_ii(tex->w, tex->h)));
diff --git a/source/blender/gpu/intern/gpu_vertex_format.c b/source/blender/gpu/intern/gpu_vertex_format.c
index e745c525df6..66e5e254734 100644
--- a/source/blender/gpu/intern/gpu_vertex_format.c
+++ b/source/blender/gpu/intern/gpu_vertex_format.c
@@ -31,6 +31,8 @@
#include <string.h>
#include "BLI_utildefines.h"
+#include "BLI_string.h"
+#include "BLI_ghash.h"
#define PACK_DEBUG 0
@@ -149,9 +151,9 @@ uint GPU_vertformat_attr_add(GPUVertFormat *format,
GPUVertFetchMode fetch_mode)
{
#if TRUST_NO_ONE
- assert(format->name_len < GPU_VERT_ATTR_MAX_LEN); /* there's room for more */
- assert(format->attr_len < GPU_VERT_ATTR_MAX_LEN); /* there's room for more */
- assert(!format->packed); /* packed means frozen/locked */
+ assert(format->name_len < GPU_VERT_FORMAT_MAX_NAMES); /* there's room for more */
+ assert(format->attr_len < GPU_VERT_ATTR_MAX_LEN); /* there's room for more */
+ assert(!format->packed); /* packed means frozen/locked */
assert((comp_len >= 1 && comp_len <= 4) || comp_len == 8 || comp_len == 12 || comp_len == 16);
switch (comp_type) {
@@ -163,8 +165,10 @@ uint GPU_vertformat_attr_add(GPUVertFormat *format,
/* 10_10_10 format intended for normals (xyz) or colors (rgb)
* extra component packed.w can be manually set to { -2, -1, 0, 1 } */
assert(comp_len == 3 || comp_len == 4);
- assert(fetch_mode ==
- GPU_FETCH_INT_TO_FLOAT_UNIT); /* not strictly required, may relax later */
+
+ /* Not strictly required, may relax later. */
+ assert(fetch_mode == GPU_FETCH_INT_TO_FLOAT_UNIT);
+
break;
default:
/* integer types can be kept as int or converted/normalized to float */
@@ -195,7 +199,7 @@ void GPU_vertformat_alias_add(GPUVertFormat *format, const char *alias)
{
GPUVertAttr *attr = &format->attrs[format->attr_len - 1];
#if TRUST_NO_ONE
- assert(format->name_len < GPU_VERT_ATTR_MAX_LEN); /* there's room for more */
+ assert(format->name_len < GPU_VERT_FORMAT_MAX_NAMES); /* there's room for more */
assert(attr->name_len < GPU_VERT_ATTR_MAX_NAMES);
#endif
format->name_len++; /* multiname support */
@@ -216,6 +220,79 @@ int GPU_vertformat_attr_id_get(const GPUVertFormat *format, const char *name)
return -1;
}
+/* Encode 8 original bytes into 11 safe bytes. */
+static void safe_bytes(char out[11], const char data[8])
+{
+ char safe_chars[63] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
+
+ uint64_t in = *(uint64_t *)data;
+ for (int i = 0; i < 11; i++) {
+ /* Encoding in base63 */
+ out[i] = safe_chars[in % 63lu];
+ in /= 63lu;
+ }
+}
+
+/* Warning: Always add a prefix to the result of this function as
+ * the generated string can start with a number and not be a valid attribute name. */
+void GPU_vertformat_safe_attrib_name(const char *attrib_name,
+ char *r_safe_name,
+ uint UNUSED(max_len))
+{
+ char data[8] = {0};
+ uint len = strlen(attrib_name);
+
+ if (len > 8) {
+ /* Start with the first 4 chars of the name; */
+ for (int i = 0; i < 4; i++) {
+ data[i] = attrib_name[i];
+ }
+ /* We use a hash to identify each data layer based on its name.
+ * NOTE: This is still prone to hash collision but the risks are very low.*/
+ /* Start hashing after the first 2 chars. */
+ *(uint *)&data[4] = BLI_ghashutil_strhash_p_murmur(attrib_name + 4);
+ }
+ else {
+ /* Copy the whole name. Collision is barely possible
+ * (hash would have to be equal to the last 4 bytes). */
+ for (int i = 0; i < 8 && attrib_name[i] != '\0'; i++) {
+ data[i] = attrib_name[i];
+ }
+ }
+ /* Convert to safe bytes characters. */
+ safe_bytes(r_safe_name, data);
+ /* End the string */
+ r_safe_name[11] = '\0';
+
+ BLI_assert(GPU_MAX_SAFE_ATTRIB_NAME >= 12);
+#if 0 /* For debugging */
+ printf("%s > %lx > %s\n", attrib_name, *(uint64_t *)data, r_safe_name);
+#endif
+}
+
+/* Make attribute layout non-interleaved.
+ * Warning! This does not change data layout!
+ * Use direct buffer access to fill the data.
+ * This is for advanced usage.
+ *
+ * Deinterleaved data means all attrib data for each attrib
+ * is stored continuously like this :
+ * 000011112222
+ * instead of :
+ * 012012012012
+ *
+ * Note this is per attrib deinterleaving, NOT per component.
+ * */
+void GPU_vertformat_deinterleave(GPUVertFormat *format)
+{
+ /* Ideally we should change the stride and offset here. This would allow
+ * us to use GPU_vertbuf_attr_set / GPU_vertbuf_attr_fill. But since
+ * we use only 11 bits for attr->offset this limits the size of the
+ * buffer considerably. So instead we do the conversion when creating
+ * bindings in create_bindings(). */
+ format->deinterleaved = true;
+}
+
uint padding(uint offset, uint alignment)
{
const uint mod = offset % alignment;
@@ -389,58 +466,3 @@ void GPU_vertformat_from_interface(GPUVertFormat *format, const GPUShaderInterfa
}
}
}
-
-/* OpenGL ES packs in a different order as desktop GL but component conversion is the same.
- * Of the code here, only struct GPUPackedNormal needs to change. */
-
-#define SIGNED_INT_10_MAX 511
-#define SIGNED_INT_10_MIN -512
-
-static int clampi(int x, int min_allowed, int max_allowed)
-{
-#if TRUST_NO_ONE
- assert(min_allowed <= max_allowed);
-#endif
- if (x < min_allowed) {
- return min_allowed;
- }
- else if (x > max_allowed) {
- return max_allowed;
- }
- else {
- return x;
- }
-}
-
-static int quantize(float x)
-{
- int qx = x * 511.0f;
- return clampi(qx, SIGNED_INT_10_MIN, SIGNED_INT_10_MAX);
-}
-
-static int convert_i16(short x)
-{
- /* 16-bit signed --> 10-bit signed */
- /* TODO: round? */
- return x >> 6;
-}
-
-GPUPackedNormal GPU_normal_convert_i10_v3(const float data[3])
-{
- GPUPackedNormal n = {
- .x = quantize(data[0]),
- .y = quantize(data[1]),
- .z = quantize(data[2]),
- };
- return n;
-}
-
-GPUPackedNormal GPU_normal_convert_i10_s3(const short data[3])
-{
- GPUPackedNormal n = {
- .x = convert_i16(data[0]),
- .y = convert_i16(data[1]),
- .z = convert_i16(data[2]),
- };
- return n;
-}
diff --git a/source/blender/gpu/intern/gpu_vertex_format_private.h b/source/blender/gpu/intern/gpu_vertex_format_private.h
index a850d17a1dd..13459101669 100644
--- a/source/blender/gpu/intern/gpu_vertex_format_private.h
+++ b/source/blender/gpu/intern/gpu_vertex_format_private.h
@@ -27,6 +27,7 @@
#define __GPU_VERTEX_FORMAT_PRIVATE_H__
void VertexFormat_pack(GPUVertFormat *format);
+void VertexFormat_deinterleave(GPUVertFormat *format, uint vertex_len);
uint padding(uint offset, uint alignment);
uint vertex_buffer_size(const GPUVertFormat *format, uint vertex_len);
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 810784e2fbc..0ce5504dfa8 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
@@ -8,7 +8,7 @@ in vec2 pos;
in float stretch;
#else
-in vec4 uv_adj;
+in vec2 uv_angles;
in float angle;
#endif
@@ -52,6 +52,11 @@ vec3 weight_to_rgb(float weight)
#define M_PI 3.1415926535897932
+vec2 angle_to_v2(float angle)
+{
+ return vec2(cos(angle), sin(angle));
+}
+
/* Adapted from BLI_math_vector.h */
float angle_normalized_v2v2(vec2 v1, vec2 v2)
{
@@ -69,7 +74,9 @@ void main()
gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
#ifdef STRETCH_ANGLE
- float uv_angle = angle_normalized_v2v2(uv_adj.xy, uv_adj.zw) / M_PI;
+ vec2 v1 = angle_to_v2(uv_angles.x * M_PI);
+ vec2 v2 = angle_to_v2(uv_angles.y * M_PI);
+ float uv_angle = angle_normalized_v2v2(v1, v2) / M_PI;
float stretch = 1.0 - abs(uv_angle - angle);
stretch = stretch;
stretch = 1.0 - stretch * stretch;
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 00b8ce54eb3..1529279ca03 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -250,185 +250,156 @@ void camera(vec3 co, out vec3 outview, out float outdepth, out float outdist)
outview = normalize(co);
}
-void math_add(float val1, float val2, out float outval)
+void math_add(float a, float b, out float result)
{
- outval = val1 + val2;
+ result = a + b;
}
-void math_subtract(float val1, float val2, out float outval)
+void math_subtract(float a, float b, out float result)
{
- outval = val1 - val2;
+ result = a - b;
}
-void math_multiply(float val1, float val2, out float outval)
+void math_multiply(float a, float b, out float result)
{
- outval = val1 * val2;
+ result = a * b;
}
-void math_divide(float val1, float val2, out float outval)
+void math_divide(float a, float b, out float result)
{
- if (val2 == 0.0) {
- outval = 0.0;
+ 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 {
- outval = val1 / val2;
+ 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_sine(float val, out float outval)
+void math_logarithm(float a, float b, out float result)
{
- outval = sin(val);
+ result = (a > 0.0 && b > 0.0) ? log2(a) / log2(b) : 0.0;
}
-void math_cosine(float val, out float outval)
+void math_sqrt(float a, float b, out float result)
{
- outval = cos(val);
+ result = (a > 0.0) ? sqrt(a) : 0.0;
}
-void math_tangent(float val, out float outval)
+void math_absolute(float a, float b, out float result)
{
- outval = tan(val);
+ result = abs(a);
}
-void math_asin(float val, out float outval)
+void math_minimum(float a, float b, out float result)
{
- if (val <= 1.0 && val >= -1.0) {
- outval = asin(val);
- }
- else {
- outval = 0.0;
- }
+ result = min(a, b);
}
-void math_acos(float val, out float outval)
+void math_maximum(float a, float b, out float result)
{
- if (val <= 1.0 && val >= -1.0) {
- outval = acos(val);
- }
- else {
- outval = 0.0;
- }
+ result = max(a, b);
}
-void math_atan(float val, out float outval)
+void math_less_than(float a, float b, out float result)
{
- outval = atan(val);
+ result = (a < b) ? 1.0 : 0.0;
}
-void math_pow(float val1, float val2, out float outval)
+void math_greater_than(float a, float b, out float result)
{
- if (val1 >= 0.0) {
- outval = compatible_pow(val1, val2);
- }
- else {
- float val2_mod_1 = mod(abs(val2), 1.0);
+ result = (a > b) ? 1.0 : 0.0;
+}
- if (val2_mod_1 > 0.999 || val2_mod_1 < 0.001) {
- outval = compatible_pow(val1, floor(val2 + 0.5));
- }
- else {
- outval = 0.0;
- }
- }
+void math_round(float a, float b, out float result)
+{
+ result = floor(a + 0.5);
}
-void math_log(float val1, float val2, out float outval)
+void math_floor(float a, float b, out float result)
{
- if (val1 > 0.0 && val2 > 0.0) {
- outval = log2(val1) / log2(val2);
- }
- else {
- outval = 0.0;
- }
+ result = floor(a);
}
-void math_max(float val1, float val2, out float outval)
+void math_ceil(float a, float b, out float result)
{
- outval = max(val1, val2);
+ result = ceil(a);
}
-void math_min(float val1, float val2, out float outval)
+void math_fraction(float a, float b, out float result)
{
- outval = min(val1, val2);
+ result = a - floor(a);
}
-void math_round(float val, out float outval)
+/* 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)
{
- outval = floor(val + 0.5);
+ result = (b != 0.0) ? sign(a) * mod(abs(a), b) : 0.0;
}
-void math_less_than(float val1, float val2, out float outval)
+void math_sine(float a, float b, out float result)
{
- if (val1 < val2) {
- outval = 1.0;
- }
- else {
- outval = 0.0;
- }
+ result = sin(a);
}
-void math_greater_than(float val1, float val2, out float outval)
+void math_cosine(float a, float b, out float result)
{
- if (val1 > val2) {
- outval = 1.0;
- }
- else {
- outval = 0.0;
- }
+ result = cos(a);
}
-void math_modulo(float val1, float val2, out float outval)
+void math_tangent(float a, float b, out float result)
{
- if (val2 == 0.0) {
- outval = 0.0;
- }
- else {
- /* change sign to match C convention, mod in GLSL will take absolute for negative numbers,
- * see https://www.opengl.org/sdk/docs/man/html/mod.xhtml */
- outval = sign(val1) * mod(abs(val1), val2);
- }
+ result = tan(a);
}
-void math_abs(float val1, out float outval)
+void math_arcsine(float a, float b, out float result)
{
- outval = abs(val1);
+ result = (a <= 1.0 && a >= -1.0) ? asin(a) : 0.0;
}
-void math_atan2(float val1, float val2, out float outval)
+void math_arccosine(float a, float b, out float result)
{
- outval = atan(val1, val2);
+ result = (a <= 1.0 && a >= -1.0) ? acos(a) : 0.0;
}
-void math_floor(float val, out float outval)
+void math_arctangent(float a, float b, out float result)
{
- outval = floor(val);
+ result = atan(a);
}
-void math_ceil(float val, out float outval)
+void math_arctan2(float a, float b, out float result)
{
- outval = ceil(val);
+ result = atan(a, b);
}
-void math_fract(float val, out float outval)
+void squeeze(float val, float width, float center, out float outval)
{
- outval = val - floor(val);
+ outval = 1.0 / (1.0 + pow(2.71828183, -((val - center) * width)));
}
-void math_sqrt(float val, out float outval)
+void map_range(
+ float value, float fromMin, float fromMax, float toMin, float toMax, out float result)
{
- if (val > 0.0) {
- outval = sqrt(val);
+ if (fromMax != fromMin) {
+ result = toMin + ((value - fromMin) / (fromMax - fromMin)) * (toMax - toMin);
}
else {
- outval = 0.0;
+ result = 0.0;
}
}
-void squeeze(float val, float width, float center, out float outval)
-{
- outval = 1.0 / (1.0 + pow(2.71828183, -((val - center) * width)));
-}
-
void vec_math_add(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
{
outvec = v1 + v2;
@@ -960,9 +931,9 @@ void clamp_vec3(vec3 vec, vec3 min, vec3 max, out vec3 out_vec)
out_vec = clamp(vec, min, max);
}
-void clamp_val(float value, float min, float max, out float out_value)
+void clamp_value(float value, float min, float max, out float result)
{
- out_value = clamp(value, min, max);
+ result = clamp(value, min, max);
}
void hue_sat(float hue, float sat, float value, float fac, vec4 col, out vec4 outcol)
@@ -1228,10 +1199,9 @@ vec3 principled_sheen(float NV, vec3 basecol_tint, float sheen_tint)
void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
{
N = normalize(N);
- vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
- result.ssr_normal = normal_encode(vN, viewCameraVec);
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;
}
@@ -1243,9 +1213,7 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Clo
vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
result.radiance = out_spec * color.rgb;
- result.ssr_data = vec4(ssr_spec * color.rgb, roughness);
- result.ssr_normal = normal_encode(vN, viewCameraVec);
- result.ssr_id = int(ssr_id);
+ closure_load_ssr_data(ssr_spec * color.rgb, roughness, N, viewCameraVec, int(ssr_id), result);
}
void node_bsdf_anisotropic(vec4 color,
@@ -1274,9 +1242,8 @@ void node_bsdf_glass(
vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
result.radiance = mix(out_refr, out_spec, fresnel);
- result.ssr_data = vec4(ssr_spec * color.rgb * fresnel, roughness);
- result.ssr_normal = normal_encode(vN, viewCameraVec);
- result.ssr_id = int(ssr_id);
+ 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)
@@ -1341,7 +1308,7 @@ void node_bsdf_principled(vec4 base_color,
vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
- float sss_scalef = dot(sss_scale, vec3(1.0 / 3.0)) * subsurface;
+ float sss_scalef = avg(sss_scale) * subsurface;
eevee_closure_principled(N,
mixed_ss_base_color,
f0,
@@ -1365,28 +1332,34 @@ void node_bsdf_principled(vec4 base_color,
vec3(1.0); /* Simulate 2 transmission event */
out_refr *= refr_color * (1.0 - fresnel) * transmission;
- vec3 vN = mat3(ViewMatrix) * N;
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 += (out_diff + out_trans) * mixed_ss_base_color * (1.0 - transmission);
-# endif
- result.ssr_data = vec4(ssr_spec, roughness);
- result.ssr_normal = normal_encode(vN, viewCameraVec);
- result.ssr_id = int(ssr_id);
-# ifdef USE_SSS
- result.sss_data.a = sss_scalef;
- result.sss_data.rgb = out_diff + out_trans;
+ result.radiance += sss_radiance * mixed_ss_base_color * (1.0 - transmission);
+# else
# ifdef USE_SSS_ALBEDO
- result.sss_albedo.rgb = mixed_ss_base_color;
+ vec3 sss_albedo = mixed_ss_base_color;
# else
- result.sss_data.rgb *= mixed_ss_base_color;
+ sss_radiance *= mixed_ss_base_color;
# endif
- result.sss_data.rgb *= (1.0 - transmission);
-# 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.opacity = alpha;
+ result.radiance *= alpha;
+ result.transmittance = vec3(1.0 - alpha);
}
void node_bsdf_principled_dielectric(vec4 base_color,
@@ -1432,14 +1405,12 @@ void node_bsdf_principled_dielectric(vec4 base_color,
eevee_closure_default(
N, diffuse, f0, vec3(1.0), int(ssr_id), roughness, 1.0, out_diff, out_spec, ssr_spec);
- vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
result.radiance = out_spec + out_diff * (diffuse + out_sheen);
- result.ssr_data = vec4(ssr_spec, roughness);
- result.ssr_normal = normal_encode(vN, viewCameraVec);
- result.ssr_id = int(ssr_id);
+ closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
result.radiance += emission.rgb;
- result.opacity = alpha;
+ result.radiance *= alpha;
+ result.transmittance = vec3(1.0 - alpha);
}
void node_bsdf_principled_metallic(vec4 base_color,
@@ -1477,14 +1448,12 @@ void node_bsdf_principled_metallic(vec4 base_color,
eevee_closure_glossy(N, base_color.rgb, f90, int(ssr_id), roughness, 1.0, out_spec, ssr_spec);
- vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
result.radiance = out_spec;
- result.ssr_data = vec4(ssr_spec, roughness);
- result.ssr_normal = normal_encode(vN, viewCameraVec);
- result.ssr_id = int(ssr_id);
+ closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
result.radiance += emission.rgb;
- result.opacity = alpha;
+ result.radiance *= alpha;
+ result.transmittance = vec3(1.0 - alpha);
}
void node_bsdf_principled_clearcoat(vec4 base_color,
@@ -1532,14 +1501,12 @@ void node_bsdf_principled_clearcoat(vec4 base_color,
out_spec,
ssr_spec);
- vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
result.radiance = out_spec;
- result.ssr_data = vec4(ssr_spec, roughness);
- result.ssr_normal = normal_encode(vN, viewCameraVec);
- result.ssr_id = int(ssr_id);
+ closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
result.radiance += emission.rgb;
- result.opacity = alpha;
+ result.radiance *= alpha;
+ result.transmittance = vec3(1.0 - alpha);
}
void node_bsdf_principled_subsurface(vec4 base_color,
@@ -1580,7 +1547,7 @@ void node_bsdf_principled_subsurface(vec4 base_color,
subsurface_color = subsurface_color * (1.0 - metallic);
vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
- float sss_scalef = dot(sss_scale, vec3(1.0 / 3.0)) * subsurface;
+ float sss_scalef = avg(sss_scale) * subsurface;
float NV = dot(N, cameraVec);
vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
@@ -1600,26 +1567,33 @@ void node_bsdf_principled_subsurface(vec4 base_color,
out_spec,
ssr_spec);
- vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
result.radiance = out_spec;
- result.ssr_data = vec4(ssr_spec, roughness);
- result.ssr_normal = normal_encode(vN, viewCameraVec);
- result.ssr_id = int(ssr_id);
-# ifdef USE_SSS
- result.sss_data.a = sss_scalef;
- result.sss_data.rgb = out_diff + out_trans;
+ 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
- result.sss_albedo.rgb = mixed_ss_base_color;
+ vec3 sss_albedo = mixed_ss_base_color;
# else
- result.sss_data.rgb *= mixed_ss_base_color;
+ sss_radiance *= mixed_ss_base_color;
# endif
-# else
- result.radiance += (out_diff + out_trans) * 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.opacity = alpha;
+ result.radiance *= alpha;
+ result.transmittance = vec3(1.0 - alpha);
}
void node_bsdf_principled_glass(vec4 base_color,
@@ -1669,14 +1643,12 @@ void node_bsdf_principled_glass(vec4 base_color,
out_spec *= spec_col;
ssr_spec *= spec_col * fresnel;
- vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
result.radiance = mix(out_refr, out_spec, fresnel);
- result.ssr_data = vec4(ssr_spec, roughness);
- result.ssr_normal = normal_encode(vN, viewCameraVec);
- result.ssr_id = int(ssr_id);
+ closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
result.radiance += emission.rgb;
- result.opacity = alpha;
+ result.radiance *= alpha;
+ result.transmittance = vec3(1.0 - alpha);
}
void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
@@ -1686,11 +1658,9 @@ void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
void node_bsdf_transparent(vec4 color, out Closure result)
{
- /* this isn't right */
result = CLOSURE_DEFAULT;
result.radiance = vec3(0.0);
- result.opacity = clamp(1.0 - dot(color.rgb, vec3(0.3333334)), 0.0, 1.0);
- result.ssr_id = TRANSPARENT_CLOSURE_FLAG;
+ result.transmittance = abs(color.rgb);
}
void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out Closure result)
@@ -1712,19 +1682,25 @@ void node_subsurface_scattering(vec4 color,
vec3 out_diff, out_trans;
vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
- result.ssr_data = vec4(0.0);
- result.ssr_normal = normal_encode(vN, viewCameraVec);
- result.ssr_id = -1;
- result.sss_data.a = scale;
+ 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);
- result.sss_data.rgb = 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. */
- result.sss_albedo.rgb = mix(color.rgb, vec3(1.0), texture_blur);
- result.sss_data.rgb *= mix(vec3(1.0), color.rgb, texture_blur);
+ vec3 sss_albedo = mix(color.rgb, vec3(1.0), texture_blur);
+ sss_radiance *= mix(vec3(1.0), color.rgb, texture_blur);
# else
- result.sss_data.rgb *= color.rgb;
+ 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
@@ -1740,7 +1716,6 @@ void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Cl
result = CLOSURE_DEFAULT;
result.ssr_normal = normal_encode(vN, viewCameraVec);
result.radiance = out_refr * color.rgb;
- result.ssr_id = REFRACT_CLOSURE_FLAG;
}
void node_ambient_occlusion(
@@ -1841,7 +1816,7 @@ void node_background(vec4 color, float strength, out Closure result)
color *= strength;
result = CLOSURE_DEFAULT;
result.radiance = color.rgb;
- result.opacity = color.a;
+ result.transmittance = vec3(0.0);
#else
result = CLOSURE_DEFAULT;
#endif
@@ -1949,6 +1924,15 @@ void node_volume_principled(vec4 color,
#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)
@@ -2023,7 +2007,7 @@ void node_attribute_volume_density(sampler3D tex, out vec4 outcol, out vec3 outv
#endif
outvec = texture(tex, cos).aaa;
outcol = vec4(outvec, 1.0);
- outf = dot(vec3(1.0 / 3.0), outvec);
+ outf = avg(outvec);
}
uniform vec3 volumeColor = vec3(1.0);
@@ -2044,7 +2028,7 @@ void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec
outvec = value.rgb * volumeColor;
outcol = vec4(outvec, 1.0);
- outf = dot(vec3(1.0 / 3.0), outvec);
+ outf = avg(outvec);
}
void node_attribute_volume_flame(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
@@ -2078,7 +2062,7 @@ void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf)
{
outcol = vec4(attr, 1.0);
outvec = attr;
- outf = dot(vec3(1.0 / 3.0), attr);
+ outf = avg(attr);
}
void node_uvmap(vec3 attr_uv, out vec3 outvec)
@@ -3491,7 +3475,7 @@ void node_output_world(Closure surface, Closure volume, out Closure result)
{
#ifndef VOLUMETRICS
result.radiance = surface.radiance * backgroundAlpha;
- result.opacity = backgroundAlpha;
+ result.transmittance = vec3(1.0 - backgroundAlpha);
#else
result = volume;
#endif /* VOLUMETRICS */
@@ -3538,6 +3522,8 @@ void node_eevee_specular(vec4 diffuse,
float ssr_id,
out Closure result)
{
+ normal = normalize(normal);
+
vec3 out_diff, out_spec, ssr_spec;
eevee_closure_default_clearcoat(normal,
diffuse.rgb,
@@ -3553,19 +3539,19 @@ void node_eevee_specular(vec4 diffuse,
out_spec,
ssr_spec);
- vec3 vN = normalize(mat3(ViewMatrix) * normal);
+ float alpha = 1.0 - transp;
result = CLOSURE_DEFAULT;
result.radiance = out_diff * diffuse.rgb + out_spec + emissive.rgb;
- result.opacity = 1.0 - transp;
- result.ssr_data = vec4(ssr_spec, roughness);
- result.ssr_normal = normal_encode(vN, viewCameraVec);
- result.ssr_id = int(ssr_id);
+ 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 && cl.ssr_id == outputSsrId) {
+ 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);
@@ -3574,7 +3560,7 @@ void node_shader_to_rgba(Closure cl, out vec4 outcol, out float outalpha)
fallback_cubemap(N, V, worldPosition, viewPosition, roughness, roughnessSquared, spec_accum);
}
- outalpha = cl.opacity;
+ outalpha = avg(cl.transmittance);
outcol = vec4((spec_accum.rgb * cl.ssr_data.rgb) + cl.radiance, 1.0);
# ifdef USE_SSS
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 791e939db7f..571cac41399 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -46,8 +46,7 @@
*
* IMB needs:
* - \ref DNA module
- * The listbase types are used for handling the memory
- * management.
+ * The #ListBase types are used for handling the memory management.
* - \ref blenlib module
* blenlib handles guarded memory management in blender-style.
* BLI_winstuff.h makes a few windows specific behaviors
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index 1f180d0d9c1..49e9c4c54d2 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -110,8 +110,8 @@ void bicubic_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, in
return;
}
- pixel_from_buffer(
- out, &outI, &outF, xout, yout); /* gcc warns these could be uninitialized, but its ok */
+ /* gcc warns these could be uninitialized, but its ok. */
+ pixel_from_buffer(out, &outI, &outF, xout, yout);
bicubic_interpolation_color(in, outI, outF, u, v);
}
@@ -220,8 +220,8 @@ void bilinear_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, i
return;
}
- pixel_from_buffer(
- out, &outI, &outF, xout, yout); /* gcc warns these could be uninitialized, but its ok */
+ /* gcc warns these could be uninitialized, but its ok. */
+ pixel_from_buffer(out, &outI, &outF, xout, yout);
bilinear_interpolation_color(in, outI, outF, u, v);
}
@@ -332,8 +332,8 @@ void nearest_interpolation(ImBuf *in, ImBuf *out, float x, float y, int xout, in
return;
}
- pixel_from_buffer(
- out, &outI, &outF, xout, yout); /* gcc warns these could be uninitialized, but its ok */
+ /* gcc warns these could be uninitialized, but its ok. */
+ pixel_from_buffer(out, &outI, &outF, xout, yout);
nearest_interpolation_color(in, outI, outF, x, y);
}
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index c9883d5df86..f18eb2f7303 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -1215,9 +1215,9 @@ void IMB_exr_read_channels(void *handle)
/* check if exr was saved with previous versions of blender which flipped images */
const StringAttribute *ta = data->ifile->header(0).findTypedAttribute<StringAttribute>(
"BlenderMultiChannel");
- short flip = (ta && STREQLEN(ta->value().c_str(),
- "Blender V2.43",
- 13)); /* 'previous multilayer attribute, flipped */
+
+ /* 'previous multilayer attribute, flipped. */
+ short flip = (ta && STREQLEN(ta->value().c_str(), "Blender V2.43", 13));
exr_printf(
"\nIMB_exr_read_channels\n%s %-6s %-22s "
diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c
index 28557277d72..46ddee25b0f 100644
--- a/source/blender/imbuf/intern/scaling.c
+++ b/source/blender/imbuf/intern/scaling.c
@@ -1629,8 +1629,8 @@ bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
return false;
}
- /* scaleup / scaledown functions below change ibuf->x and ibuf->y
- * so we first scale the Z-buffer (if any) */
+ /* Scale-up / scale-down functions below change ibuf->x and ibuf->y
+ * so we first scale the Z-buffer (if any). */
scalefast_Z_ImBuf(ibuf, newx, newy);
/* try to scale common cases in a fast way */
diff --git a/source/blender/makesdna/DNA_documentation.h b/source/blender/makesdna/DNA_documentation.h
index be11b3d9040..0251625292c 100644
--- a/source/blender/makesdna/DNA_documentation.h
+++ b/source/blender/makesdna/DNA_documentation.h
@@ -27,7 +27,7 @@
* blender file. There is an executable that scans all files, looking
* for struct-s to serialize (hence sdna: Struct \ref DNA). From this
* information, it builds a file with numbers that encode the format,
- * the names of variables, and the plce to look for them.
+ * the names of variables, and the place to look for them.
*
* \section dnaissues Known issues with DNA
*
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index 82628065014..83ee8be7f68 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -502,8 +502,11 @@ typedef struct SimplifyGpencilModifierData {
short step;
/** Custom index for passes. */
int layer_pass;
- /* Sample length */
+ /** Sample length */
float length;
+ /** Merge distance */
+ float distance;
+ char _pad[4];
} SimplifyGpencilModifierData;
typedef enum eSimplifyGpencil_Flag {
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index bf72ce5e598..9682fa1d13b 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -651,6 +651,8 @@ typedef enum eGP_DrawMode {
((gpd) && (gpd->flag & \
(GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE)))
#define GPENCIL_PAINT_MODE(gpd) ((gpd) && (gpd->flag & (GP_DATA_STROKE_PAINTMODE)))
+#define GPENCIL_SCULPT_MODE(gpd) ((gpd) && (gpd->flag & GP_DATA_STROKE_SCULPTMODE))
+#define GPENCIL_WEIGHT_MODE(gpd) ((gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE))
#define GPENCIL_SCULPT_OR_WEIGHT_MODE(gpd) \
((gpd) && (gpd->flag & (GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE)))
#define GPENCIL_NONE_EDIT_MODE(gpd) \
diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h
index 152ecb85991..1d1ccef8846 100644
--- a/source/blender/makesdna/DNA_material_types.h
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -306,12 +306,12 @@ typedef struct Material {
/* blend_method */
enum {
- MA_BM_SOLID,
- MA_BM_ADD,
- MA_BM_MULTIPLY,
- MA_BM_CLIP,
- MA_BM_HASHED,
- MA_BM_BLEND,
+ MA_BM_SOLID = 0,
+ // MA_BM_ADD = 1, /* deprecated */
+ // MA_BM_MULTIPLY = 2, /* deprecated */
+ MA_BM_CLIP = 3,
+ MA_BM_HASHED = 4,
+ MA_BM_BLEND = 5,
};
/* blend_flag */
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 8a9a69ac178..caa7c98335a 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -193,9 +193,10 @@ typedef struct Mesh {
short totcol;
+ float remesh_voxel_size;
+ char _pad1[4];
/** Deprecated multiresolution modeling data, only keep for loading old files. */
struct Multires *mr DNA_DEPRECATED;
- void *_pad1;
Mesh_Runtime runtime;
} Mesh;
@@ -250,6 +251,8 @@ enum {
ME_FLAG_UNUSED_8 = 1 << 8, /* cleared */
ME_DS_EXPAND = 1 << 9,
ME_SCULPT_DYNAMIC_TOPOLOGY = 1 << 10,
+ ME_REMESH_SMOOTH_NORMALS = 1 << 11,
+ ME_REMESH_REPROJECT_PAINT_MASK = 1 << 12,
};
/* me->cd_flag */
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index 88eef05f8be..af350cfee48 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -188,10 +188,6 @@ typedef struct MVertTri {
unsigned int tri[3];
} MVertTri;
-// typedef struct MTexPoly {
-// void *_pad;
-//} MTexPoly;
-
typedef struct MLoopUV {
float uv[2];
int flag;
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 75c0721f72a..81b93ce6541 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -184,6 +184,8 @@ typedef enum eNodeSocketFlag {
/** socket hidden automatically, to distinguish from manually hidden */
SOCK_AUTO_HIDDEN__DEPRECATED = (1 << 8),
SOCK_NO_INTERNAL_LINK = (1 << 9),
+ /** Draw socket in a more compact form. */
+ SOCK_COMPACT = (1 << 10),
} eNodeSocketFlag;
/* limit data in bNode to what we want to see saved? */
@@ -1010,6 +1012,11 @@ typedef struct NodeCryptomatte {
char _pad[4];
} NodeCryptomatte;
+typedef struct NodeDenoise {
+ char hdr;
+ char _pad[7];
+} NodeDenoise;
+
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
@@ -1160,31 +1167,31 @@ typedef struct NodeCryptomatte {
/* math node clamp */
#define SHD_MATH_CLAMP 1
-/* Math node operation/ */
+/* Math node operations. */
enum {
NODE_MATH_ADD = 0,
- NODE_MATH_SUB = 1,
- NODE_MATH_MUL = 2,
+ NODE_MATH_SUBTRACT = 1,
+ NODE_MATH_MULTIPLY = 2,
NODE_MATH_DIVIDE = 3,
- NODE_MATH_SIN = 4,
- NODE_MATH_COS = 5,
- NODE_MATH_TAN = 6,
- NODE_MATH_ASIN = 7,
- NODE_MATH_ACOS = 8,
- NODE_MATH_ATAN = 9,
- NODE_MATH_POW = 10,
- NODE_MATH_LOG = 11,
- NODE_MATH_MIN = 12,
- NODE_MATH_MAX = 13,
+ NODE_MATH_SINE = 4,
+ NODE_MATH_COSINE = 5,
+ NODE_MATH_TANGENT = 6,
+ NODE_MATH_ARCSINE = 7,
+ NODE_MATH_ARCCOSINE = 8,
+ NODE_MATH_ARCTANGENT = 9,
+ NODE_MATH_POWER = 10,
+ NODE_MATH_LOGARITHM = 11,
+ NODE_MATH_MINIMUM = 12,
+ NODE_MATH_MAXIMUM = 13,
NODE_MATH_ROUND = 14,
- NODE_MATH_LESS = 15,
- NODE_MATH_GREATER = 16,
- NODE_MATH_MOD = 17,
- NODE_MATH_ABS = 18,
- NODE_MATH_ATAN2 = 19,
+ NODE_MATH_LESS_THAN = 15,
+ NODE_MATH_GREATER_THAN = 16,
+ NODE_MATH_MODULO = 17,
+ NODE_MATH_ABSOLUTE = 18,
+ NODE_MATH_ARCTAN2 = 19,
NODE_MATH_FLOOR = 20,
NODE_MATH_CEIL = 21,
- NODE_MATH_FRACT = 22,
+ NODE_MATH_FRACTION = 22,
NODE_MATH_SQRT = 23,
};
diff --git a/source/blender/makesdna/DNA_object_force_types.h b/source/blender/makesdna/DNA_object_force_types.h
index 2207e08558d..34a1b6d3e0b 100644
--- a/source/blender/makesdna/DNA_object_force_types.h
+++ b/source/blender/makesdna/DNA_object_force_types.h
@@ -271,7 +271,7 @@ typedef struct PointCache {
char name[64];
char prev_name[64];
- char info[64];
+ char info[128];
/** File path, 1024 = FILE_MAX. */
char path[1024];
@@ -497,6 +497,8 @@ typedef struct SoftBody {
#define PTCACHE_FAKE_SMOKE (1 << 12)
#define PTCACHE_IGNORE_CLEAR (1 << 13)
+#define PTCACHE_FLAG_INFO_DIRTY (1 << 14)
+
/* PTCACHE_OUTDATED + PTCACHE_FRAMES_SKIPPED */
#define PTCACHE_REDO_NEEDED 258
diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h
index 1462d955f81..9776063f220 100644
--- a/source/blender/makesdna/DNA_outliner_types.h
+++ b/source/blender/makesdna/DNA_outliner_types.h
@@ -60,6 +60,10 @@ enum {
TSE_DRAG_INTO = (1 << 6),
TSE_DRAG_BEFORE = (1 << 7),
TSE_DRAG_AFTER = (1 << 8),
+ /* Needed because outliner-only elements can be active */
+ TSE_ACTIVE = (1 << 9),
+ /* Needed because walk selection should not activate */
+ TSE_ACTIVE_WALK = (1 << 10),
TSE_DRAG_ANY = (TSE_DRAG_INTO | TSE_DRAG_BEFORE | TSE_DRAG_AFTER),
};
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index f50b345e402..45159af306c 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1125,7 +1125,7 @@ typedef struct GP_Sculpt_Settings {
/* GP_Sculpt_Settings.flag */
typedef enum eGP_Sculpt_SettingsFlag {
/* only affect selected points */
- GP_SCULPT_SETT_FLAG_SELECT_MASK = (1 << 0),
+ GP_SCULPT_SETT_FLAG_DEPRECATED = (1 << 0),
/* apply brush to position */
GP_SCULPT_SETT_FLAG_APPLY_POSITION = (1 << 1),
/* apply brush to strength */
@@ -1142,6 +1142,16 @@ typedef enum eGP_Sculpt_SettingsFlag {
GP_SCULPT_SETT_FLAG_PRIMITIVE_CURVE = (1 << 7),
} eGP_Sculpt_SettingsFlag;
+/* GP_Sculpt_Settings.gpencil_selectmode_sculpt */
+typedef enum eGP_Sculpt_SelectMaskFlag {
+ /* only affect selected points */
+ GP_SCULPT_MASK_SELECTMODE_POINT = (1 << 0),
+ /* only affect selected strokes */
+ GP_SCULPT_MASK_SELECTMODE_STROKE = (1 << 1),
+ /* only affect selected segmenst */
+ GP_SCULPT_MASK_SELECTMODE_SEGMENT = (1 << 2),
+} eGP_Sculpt_SelectMaskFlag;
+
/* Settings for GP Interpolation Operators */
typedef struct GP_Interpolate_Settings {
/** #eGP_Interpolate_SettingsFlag. */
@@ -1412,8 +1422,10 @@ typedef struct ToolSettings {
/** Default stroke thickness for annotation strokes. */
short annotate_thickness;
- /** Stroke selection mode. */
- short gpencil_selectmode;
+ /** Stroke selection mode for Edit. */
+ char gpencil_selectmode_edit;
+ /** Stroke selection mode for Sculpt. */
+ char gpencil_selectmode_sculpt;
/* Grease Pencil Sculpt */
struct GP_Sculpt_Settings gp_sculpt;
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index e37d72ff8af..fd421cd8304 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -375,6 +375,13 @@ typedef struct ScrArea {
typedef struct ARegion_Runtime {
/* Panel category to use between 'layout' and 'draw'. */
const char *category;
+
+ /**
+ * The visible part of the region, use with region overlap not to draw
+ * on top of the overlapping regions.
+ *
+ * Lazy initialize, zero'd when unset, relative to #ARegion.winrct x/y min. */
+ rcti visible_rect;
} ARegion_Runtime;
typedef struct ARegion {
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 41fc2244cce..030116ea5cc 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -244,7 +244,12 @@ typedef struct SpaceOutliner {
char search_string[64];
struct TreeStoreElem search_tse;
- short flag, outlinevis, storeflag, search_flags;
+ short flag, outlinevis, storeflag;
+ char search_flags;
+
+ /** Selection syncing flag (#WM_OUTLINER_SYNC_SELECT_FROM_OBJECT and similar flags). */
+ char sync_select_dirty;
+
int filter;
char filter_state;
char show_restrict_flags;
@@ -263,6 +268,7 @@ typedef enum eSpaceOutliner_Flag {
SO_FLAG_UNUSED_1 = (1 << 2), /* cleared */
SO_HIDE_KEYINGSETINFO = (1 << 3),
SO_SKIP_SORT_ALPHA = (1 << 4),
+ SO_SYNC_SELECT = (1 << 5),
} eSpaceOutliner_Flag;
/* SpaceOutliner.filter */
@@ -281,13 +287,14 @@ typedef enum eSpaceOutliner_Filter {
SO_FILTER_NO_OB_CAMERA = (1 << 10),
SO_FILTER_NO_OB_OTHERS = (1 << 11),
- SO_FILTER_UNUSED_12 = (1 << 12), /* cleared */
- SO_FILTER_OB_STATE_VISIBLE = (1 << 13), /* Not set via DNA. */
- SO_FILTER_OB_STATE_SELECTED = (1 << 14), /* Not set via DNA. */
- SO_FILTER_OB_STATE_ACTIVE = (1 << 15), /* Not set via DNA. */
- SO_FILTER_NO_COLLECTION = (1 << 16),
+ SO_FILTER_UNUSED_12 = (1 << 12), /* cleared */
+ SO_FILTER_OB_STATE_VISIBLE = (1 << 13), /* Not set via DNA. */
+ SO_FILTER_OB_STATE_INVISIBLE = (1 << 14), /* Not set via DNA. */
+ SO_FILTER_OB_STATE_SELECTED = (1 << 15), /* Not set via DNA. */
+ SO_FILTER_OB_STATE_ACTIVE = (1 << 16), /* Not set via DNA. */
+ SO_FILTER_NO_COLLECTION = (1 << 17),
- SO_FILTER_ID_TYPE = (1 << 17),
+ SO_FILTER_ID_TYPE = (1 << 18),
} eSpaceOutliner_Filter;
#define SO_FILTER_OB_TYPE \
@@ -295,7 +302,8 @@ typedef enum eSpaceOutliner_Filter {
SO_FILTER_NO_OB_LAMP | SO_FILTER_NO_OB_CAMERA | SO_FILTER_NO_OB_OTHERS)
#define SO_FILTER_OB_STATE \
- (SO_FILTER_OB_STATE_VISIBLE | SO_FILTER_OB_STATE_SELECTED | SO_FILTER_OB_STATE_ACTIVE)
+ (SO_FILTER_OB_STATE_VISIBLE | SO_FILTER_OB_STATE_INVISIBLE | SO_FILTER_OB_STATE_SELECTED | \
+ SO_FILTER_OB_STATE_ACTIVE)
#define SO_FILTER_ANY \
(SO_FILTER_NO_OB_CONTENT | SO_FILTER_NO_CHILDREN | SO_FILTER_OB_TYPE | SO_FILTER_OB_STATE | \
@@ -305,8 +313,9 @@ typedef enum eSpaceOutliner_Filter {
typedef enum eSpaceOutliner_StateFilter {
SO_FILTER_OB_ALL = 0,
SO_FILTER_OB_VISIBLE = 1,
- SO_FILTER_OB_SELECTED = 2,
- SO_FILTER_OB_ACTIVE = 3,
+ SO_FILTER_OB_INVISIBLE = 2,
+ SO_FILTER_OB_SELECTED = 3,
+ SO_FILTER_OB_ACTIVE = 4,
} eSpaceOutliner_StateFilter;
/* SpaceOutliner.show_restrict_flags */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index b8914c7a74f..3cb96ce8bf8 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -868,6 +868,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),
} eUserPref_Flag;
typedef enum eUserPref_PrefFlag {
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index 8dcae41aaa2..cacc79608ad 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -131,12 +131,15 @@ typedef struct wmWindowManager {
ListBase windows;
/** Set on file read. */
- int initialized;
+ short initialized;
/** Indicator whether data was saved. */
short file_saved;
/** Operator stack depth to avoid nested undo pushes. */
short op_undo_depth;
+ /** Set after selection to notify outliner to sync. Stores type of selection */
+ short outliner_sync_select_dirty;
+
/** Operator registry. */
ListBase operators;
@@ -186,6 +189,18 @@ enum {
WM_KEYCONFIG_IS_INITIALIZED = (1 << 1),
};
+/* wmWindowManager.outliner_sync_select_dirty */
+enum {
+ WM_OUTLINER_SYNC_SELECT_FROM_OBJECT = (1 << 0),
+ WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE = (1 << 1),
+ WM_OUTLINER_SYNC_SELECT_FROM_POSE_BONE = (1 << 2),
+ WM_OUTLINER_SYNC_SELECT_FROM_SEQUENCE = (1 << 3),
+};
+
+#define WM_OUTLINER_SYNC_SELECT_FROM_ALL \
+ (WM_OUTLINER_SYNC_SELECT_FROM_OBJECT | WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE | \
+ WM_OUTLINER_SYNC_SELECT_FROM_POSE_BONE | WM_OUTLINER_SYNC_SELECT_FROM_SEQUENCE)
+
#define WM_KEYCONFIG_STR_DEFAULT "blender"
/* IME is win32 only! */
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index 5252c8f3350..86ba306fc6a 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -339,7 +339,7 @@ static bool init_structDNA(SDNA *sdna, bool do_endian_swap, const char **r_error
data = (int *)sdna->data;
- /* clear pointers incase of error */
+ /* Clear pointers in case of error. */
sdna->names = NULL;
sdna->types = NULL;
sdna->structs = NULL;
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 30e24917b83..b0738b617f7 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -953,8 +953,10 @@ bool RNA_property_pointer_poll(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *v
bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char **r_info);
bool RNA_property_editable_index(PointerRNA *ptr, PropertyRNA *prop, int index);
-bool RNA_property_editable_flag(PointerRNA *ptr,
- PropertyRNA *prop); /* without lib check, only checks the flag */
+
+/* without lib check, only checks the flag */
+bool RNA_property_editable_flag(PointerRNA *ptr, PropertyRNA *prop);
+
bool RNA_property_animateable(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop);
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index 39889f77a96..38631d1acf2 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -105,7 +105,7 @@ typedef enum PropertyUnit {
#define RNA_STACK_ARRAY 32
/**
- * \note Also update enums in bpy_props.c when adding items here.
+ * \note Also update enums in bpy_props.c and rna_rna.c when adding items here.
* Watch it: these values are written to files as part of node socket button subtypes!
*/
typedef enum PropertySubType {
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 57cdbbadeb8..7996750a1b8 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -642,8 +642,7 @@ static void rna_IDMaterials_append_id(ID *id, Main *bmain, Material *ma)
WM_main_add_notifier(NC_OBJECT | ND_OB_SHADING, id);
}
-static Material *rna_IDMaterials_pop_id(
- ID *id, Main *bmain, ReportList *reports, int index_i, bool remove_material_slot)
+static Material *rna_IDMaterials_pop_id(ID *id, Main *bmain, ReportList *reports, int index_i)
{
Material *ma;
short *totcol = give_totcolp_id(id);
@@ -657,7 +656,7 @@ static Material *rna_IDMaterials_pop_id(
return NULL;
}
- ma = BKE_material_pop_id(bmain, id, index_i, remove_material_slot);
+ ma = BKE_material_pop_id(bmain, id, index_i);
if (*totcol == totcol_orig) {
BKE_report(reports, RPT_ERROR, "No material to removed");
@@ -671,9 +670,9 @@ static Material *rna_IDMaterials_pop_id(
return ma;
}
-static void rna_IDMaterials_clear_id(ID *id, Main *bmain, bool remove_material_slot)
+static void rna_IDMaterials_clear_id(ID *id, Main *bmain)
{
- BKE_material_clear_id(bmain, id, remove_material_slot);
+ BKE_material_clear_id(bmain, id);
DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, id);
@@ -1116,16 +1115,12 @@ static void rna_def_ID_materials(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Remove a material from the data-block");
parm = RNA_def_int(
func, "index", -1, -MAXMAT, MAXMAT, "", "Index of material to remove", 0, MAXMAT);
- RNA_def_boolean(
- func, "update_data", 0, "", "Update data by re-adjusting the material slots assigned");
parm = RNA_def_pointer(func, "material", "Material", "", "Material to remove");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "clear", "rna_IDMaterials_clear_id");
RNA_def_function_flag(func, FUNC_USE_MAIN);
RNA_def_function_ui_description(func, "Remove all materials from the data-block");
- RNA_def_boolean(
- func, "update_data", 0, "", "Update data by re-adjusting the material slots assigned");
}
static void rna_def_image_preview(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 731f549b497..b78a3304cc7 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -1136,12 +1136,34 @@ PropertyType RNA_property_type(PropertyRNA *prop)
PropertySubType RNA_property_subtype(PropertyRNA *prop)
{
- return rna_ensure_property(prop)->subtype;
+ PropertyRNA *rna_prop = rna_ensure_property(prop);
+
+ /* For custom properties, find and parse the 'subtype' metadata field. */
+ if (prop->magic != RNA_MAGIC) {
+ IDProperty *idprop = (IDProperty *)prop;
+
+ /* Restrict to arrays only for now for performance reasons. */
+ if (idprop->type == IDP_ARRAY && ELEM(idprop->subtype, IDP_INT, IDP_FLOAT, IDP_DOUBLE)) {
+ IDProperty *idp_ui = rna_idproperty_ui(prop);
+
+ if (idp_ui) {
+ IDProperty *item = IDP_GetPropertyTypeFromGroup(idp_ui, "subtype", IDP_STRING);
+
+ if (item) {
+ int result = PROP_NONE;
+ RNA_enum_value_from_id(rna_enum_property_subtype_items, IDP_String(item), &result);
+ return (PropertySubType)result;
+ }
+ }
+ }
+ }
+
+ return rna_prop->subtype;
}
PropertyUnit RNA_property_unit(PropertyRNA *prop)
{
- return RNA_SUBTYPE_UNIT(rna_ensure_property(prop)->subtype);
+ return RNA_SUBTYPE_UNIT(RNA_property_subtype(prop));
}
int RNA_property_flag(PropertyRNA *prop)
@@ -1212,7 +1234,7 @@ char RNA_property_array_item_char(PropertyRNA *prop, int index)
const char *vectoritem = "XYZW";
const char *quatitem = "WXYZ";
const char *coloritem = "RGBA";
- PropertySubType subtype = rna_ensure_property(prop)->subtype;
+ PropertySubType subtype = RNA_property_subtype(prop);
BLI_assert(index >= 0);
@@ -1240,6 +1262,7 @@ char RNA_property_array_item_char(PropertyRNA *prop, int index)
int RNA_property_array_item_index(PropertyRNA *prop, char name)
{
+ /* Don't use custom property subtypes in RNA path lookup. */
PropertySubType subtype = rna_ensure_property(prop)->subtype;
/* get index based on string name/alias */
@@ -2522,20 +2545,33 @@ void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
}
}
-static void rna_property_boolean_get_default_array_values(BoolPropertyRNA *bprop, bool *values)
+static void rna_property_boolean_fill_default_array_values(
+ const bool *defarr, int defarr_length, bool defvalue, int out_length, bool *r_values)
{
- unsigned int length = bprop->property.totarraylength;
-
- if (bprop->defaultarray) {
- memcpy(values, bprop->defaultarray, sizeof(bool) * length);
+ if (defarr && defarr_length > 0) {
+ defarr_length = MIN2(defarr_length, out_length);
+ memcpy(r_values, defarr, sizeof(bool) * defarr_length);
}
else {
- for (unsigned int i = 0; i < length; i++) {
- values[i] = bprop->defaultvalue;
- }
+ defarr_length = 0;
+ }
+
+ for (int i = defarr_length; i < out_length; i++) {
+ r_values[i] = defvalue;
}
}
+static void rna_property_boolean_get_default_array_values(PointerRNA *ptr,
+ BoolPropertyRNA *bprop,
+ bool *r_values)
+{
+ int length = bprop->property.totarraylength;
+ int out_length = RNA_property_array_length(ptr, (PropertyRNA *)bprop);
+
+ rna_property_boolean_fill_default_array_values(
+ bprop->defaultarray, length, bprop->defaultvalue, out_length, r_values);
+}
+
void RNA_property_boolean_get_array(PointerRNA *ptr, PropertyRNA *prop, bool *values)
{
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
@@ -2565,7 +2601,7 @@ void RNA_property_boolean_get_array(PointerRNA *ptr, PropertyRNA *prop, bool *va
bprop->getarray_ex(ptr, prop, values);
}
else {
- rna_property_boolean_get_default_array_values(bprop, values);
+ rna_property_boolean_get_default_array_values(ptr, bprop, values);
}
}
@@ -2684,9 +2720,7 @@ bool RNA_property_boolean_get_default(PointerRNA *UNUSED(ptr), PropertyRNA *prop
return bprop->defaultvalue;
}
-void RNA_property_boolean_get_default_array(PointerRNA *UNUSED(ptr),
- PropertyRNA *prop,
- bool *values)
+void RNA_property_boolean_get_default_array(PointerRNA *ptr, PropertyRNA *prop, bool *values)
{
BoolPropertyRNA *bprop = (BoolPropertyRNA *)rna_ensure_property(prop);
@@ -2697,7 +2731,7 @@ void RNA_property_boolean_get_default_array(PointerRNA *UNUSED(ptr),
values[0] = bprop->defaultvalue;
}
else {
- rna_property_boolean_get_default_array_values(bprop, values);
+ rna_property_boolean_get_default_array_values(ptr, bprop, values);
}
}
@@ -2709,7 +2743,7 @@ bool RNA_property_boolean_get_default_index(PointerRNA *ptr, PropertyRNA *prop,
BLI_assert(RNA_property_type(prop) == PROP_BOOLEAN);
BLI_assert(RNA_property_array_check(prop) != false);
BLI_assert(index >= 0);
- BLI_assert(index < prop->totarraylength);
+ BLI_assert(index < len);
if (len <= RNA_MAX_ARRAY_LENGTH) {
RNA_property_boolean_get_default_array(ptr, prop, tmp);
@@ -2785,20 +2819,33 @@ void RNA_property_int_set(PointerRNA *ptr, PropertyRNA *prop, int value)
}
}
-static void rna_property_int_get_default_array_values(IntPropertyRNA *iprop, int *values)
+static void rna_property_int_fill_default_array_values(
+ const int *defarr, int defarr_length, int defvalue, int out_length, int *r_values)
{
- unsigned int length = iprop->property.totarraylength;
-
- if (iprop->defaultarray) {
- memcpy(values, iprop->defaultarray, sizeof(int) * length);
+ if (defarr && defarr_length > 0) {
+ defarr_length = MIN2(defarr_length, out_length);
+ memcpy(r_values, defarr, sizeof(int) * defarr_length);
}
else {
- for (unsigned int i = 0; i < length; i++) {
- values[i] = iprop->defaultvalue;
- }
+ defarr_length = 0;
+ }
+
+ for (int i = defarr_length; i < out_length; i++) {
+ r_values[i] = defvalue;
}
}
+static void rna_property_int_get_default_array_values(PointerRNA *ptr,
+ IntPropertyRNA *iprop,
+ int *r_values)
+{
+ int length = iprop->property.totarraylength;
+ int out_length = RNA_property_array_length(ptr, (PropertyRNA *)iprop);
+
+ rna_property_int_fill_default_array_values(
+ iprop->defaultarray, length, iprop->defaultvalue, out_length, r_values);
+}
+
void RNA_property_int_get_array(PointerRNA *ptr, PropertyRNA *prop, int *values)
{
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
@@ -2827,7 +2874,7 @@ void RNA_property_int_get_array(PointerRNA *ptr, PropertyRNA *prop, int *values)
iprop->getarray_ex(ptr, prop, values);
}
else {
- rna_property_int_get_default_array_values(iprop, values);
+ rna_property_int_get_default_array_values(ptr, iprop, values);
}
}
@@ -2999,18 +3046,34 @@ bool RNA_property_int_set_default(PointerRNA *ptr, PropertyRNA *prop, int value)
}
}
-void RNA_property_int_get_default_array(PointerRNA *UNUSED(ptr), PropertyRNA *prop, int *values)
+void RNA_property_int_get_default_array(PointerRNA *ptr, PropertyRNA *prop, int *values)
{
IntPropertyRNA *iprop = (IntPropertyRNA *)rna_ensure_property(prop);
BLI_assert(RNA_property_type(prop) == PROP_INT);
BLI_assert(RNA_property_array_check(prop) != false);
- if (prop->arraydimension == 0) {
+ if (prop->magic != RNA_MAGIC) {
+ int length = rna_ensure_property_array_length(ptr, prop);
+
+ IDProperty *idp_ui = rna_idproperty_ui(prop);
+ IDProperty *item = idp_ui ? IDP_GetPropertyFromGroup(idp_ui, "default") : NULL;
+
+ int defval = (item && item->type == IDP_INT) ? IDP_Int(item) : iprop->defaultvalue;
+
+ if (item && item->type == IDP_ARRAY && item->subtype == IDP_INT) {
+ rna_property_int_fill_default_array_values(
+ IDP_Array(item), item->len, defval, length, values);
+ }
+ else {
+ rna_property_int_fill_default_array_values(NULL, 0, defval, length, values);
+ }
+ }
+ else if (prop->arraydimension == 0) {
values[0] = iprop->defaultvalue;
}
else {
- rna_property_int_get_default_array_values(iprop, values);
+ rna_property_int_get_default_array_values(ptr, iprop, values);
}
}
@@ -3022,7 +3085,7 @@ int RNA_property_int_get_default_index(PointerRNA *ptr, PropertyRNA *prop, int i
BLI_assert(RNA_property_type(prop) == PROP_INT);
BLI_assert(RNA_property_array_check(prop) != false);
BLI_assert(index >= 0);
- BLI_assert(index < prop->totarraylength);
+ BLI_assert(index < len);
if (len <= RNA_MAX_ARRAY_LENGTH) {
RNA_property_int_get_default_array(ptr, prop, tmp);
@@ -3109,20 +3172,33 @@ void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
}
}
-static void rna_property_float_get_default_array_values(FloatPropertyRNA *fprop, float *values)
+static void rna_property_float_fill_default_array_values(
+ const float *defarr, int defarr_length, float defvalue, int out_length, float *r_values)
{
- unsigned int length = fprop->property.totarraylength;
-
- if (fprop->defaultarray) {
- memcpy(values, fprop->defaultarray, sizeof(float) * length);
+ if (defarr && defarr_length > 0) {
+ defarr_length = MIN2(defarr_length, out_length);
+ memcpy(r_values, defarr, sizeof(float) * defarr_length);
}
else {
- for (unsigned int i = 0; i < length; i++) {
- values[i] = fprop->defaultvalue;
- }
+ defarr_length = 0;
+ }
+
+ for (int i = defarr_length; i < out_length; i++) {
+ r_values[i] = defvalue;
}
}
+static void rna_property_float_get_default_array_values(PointerRNA *ptr,
+ FloatPropertyRNA *fprop,
+ float *r_values)
+{
+ int length = fprop->property.totarraylength;
+ int out_length = RNA_property_array_length(ptr, (PropertyRNA *)fprop);
+
+ rna_property_float_fill_default_array_values(
+ fprop->defaultarray, length, fprop->defaultvalue, out_length, r_values);
+}
+
void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
{
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
@@ -3157,7 +3233,7 @@ void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *val
fprop->getarray_ex(ptr, prop, values);
}
else {
- rna_property_float_get_default_array_values(fprop, values);
+ rna_property_float_get_default_array_values(ptr, fprop, values);
}
}
@@ -3343,20 +3419,40 @@ bool RNA_property_float_set_default(PointerRNA *ptr, PropertyRNA *prop, float va
}
}
-void RNA_property_float_get_default_array(PointerRNA *UNUSED(ptr),
- PropertyRNA *prop,
- float *values)
+void RNA_property_float_get_default_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
{
FloatPropertyRNA *fprop = (FloatPropertyRNA *)rna_ensure_property(prop);
BLI_assert(RNA_property_type(prop) == PROP_FLOAT);
BLI_assert(RNA_property_array_check(prop) != false);
- if (prop->arraydimension == 0) {
+ if (prop->magic != RNA_MAGIC) {
+ int length = rna_ensure_property_array_length(ptr, prop);
+
+ IDProperty *idp_ui = rna_idproperty_ui(prop);
+ IDProperty *item = idp_ui ? IDP_GetPropertyFromGroup(idp_ui, "default") : NULL;
+
+ float defval = (item && item->type == IDP_DOUBLE) ? IDP_Double(item) : fprop->defaultvalue;
+
+ if (item && item->type == IDP_ARRAY && item->subtype == IDP_DOUBLE) {
+ double *defarr = IDP_Array(item);
+ for (int i = 0; i < length; i++) {
+ values[i] = (i < item->len) ? (float)defarr[i] : defval;
+ }
+ }
+ else if (item && item->type == IDP_ARRAY && item->subtype == IDP_FLOAT) {
+ rna_property_float_fill_default_array_values(
+ IDP_Array(item), item->len, defval, length, values);
+ }
+ else {
+ rna_property_float_fill_default_array_values(NULL, 0, defval, length, values);
+ }
+ }
+ else if (prop->arraydimension == 0) {
values[0] = fprop->defaultvalue;
}
else {
- rna_property_float_get_default_array_values(fprop, values);
+ rna_property_float_get_default_array_values(ptr, fprop, values);
}
}
@@ -3368,7 +3464,7 @@ float RNA_property_float_get_default_index(PointerRNA *ptr, PropertyRNA *prop, i
BLI_assert(RNA_property_type(prop) == PROP_FLOAT);
BLI_assert(RNA_property_array_check(prop) != false);
BLI_assert(index >= 0);
- BLI_assert(index < prop->totarraylength);
+ BLI_assert(index < len);
if (len <= RNA_MAX_ARRAY_LENGTH) {
RNA_property_float_get_default_array(ptr, prop, tmp);
@@ -6381,8 +6477,8 @@ char *RNA_string_get_alloc(PointerRNA *ptr, const char *name, char *fixedbuf, in
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
- return RNA_property_string_get_alloc(
- ptr, prop, fixedbuf, fixedlen, NULL); /* TODO, pass length */
+ /* TODO, pass length */
+ return RNA_property_string_get_alloc(ptr, prop, fixedbuf, fixedlen, NULL);
}
else {
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
@@ -7083,6 +7179,7 @@ ParameterList *RNA_parameter_list_create(ParameterList *parms,
FunctionRNA *func)
{
PropertyRNA *parm;
+ PointerRNA null_ptr = PointerRNA_NULL;
void *data;
int alloc_size = 0, size;
@@ -7122,7 +7219,8 @@ ParameterList *RNA_parameter_list_create(ParameterList *parms,
switch (parm->type) {
case PROP_BOOLEAN:
if (parm->arraydimension) {
- rna_property_boolean_get_default_array_values((BoolPropertyRNA *)parm, data);
+ rna_property_boolean_get_default_array_values(
+ &null_ptr, (BoolPropertyRNA *)parm, data);
}
else {
memcpy(data, &((BoolPropertyRNA *)parm)->defaultvalue, size);
@@ -7130,7 +7228,7 @@ ParameterList *RNA_parameter_list_create(ParameterList *parms,
break;
case PROP_INT:
if (parm->arraydimension) {
- rna_property_int_get_default_array_values((IntPropertyRNA *)parm, data);
+ rna_property_int_get_default_array_values(&null_ptr, (IntPropertyRNA *)parm, data);
}
else {
memcpy(data, &((IntPropertyRNA *)parm)->defaultvalue, size);
@@ -7138,7 +7236,7 @@ ParameterList *RNA_parameter_list_create(ParameterList *parms,
break;
case PROP_FLOAT:
if (parm->arraydimension) {
- rna_property_float_get_default_array_values((FloatPropertyRNA *)parm, data);
+ rna_property_float_get_default_array_values(&null_ptr, (FloatPropertyRNA *)parm, data);
}
else {
memcpy(data, &((FloatPropertyRNA *)parm)->defaultvalue, size);
@@ -8762,6 +8860,80 @@ static void rna_property_override_apply_ex(Main *bmain,
}
continue;
}
+
+ /* Note: will have to think about putting that logic into its own function maybe?
+ * Would be nice to have it in a single place... */
+ PointerRNA private_ptr_item_local, private_ptr_item_override, private_ptr_item_storage;
+ if (opop->subitem_local_name != NULL || opop->subitem_reference_name != NULL ||
+ opop->subitem_local_index != -1 || opop->subitem_reference_index != -1) {
+ RNA_POINTER_INVALIDATE(&private_ptr_item_local);
+ RNA_POINTER_INVALIDATE(&private_ptr_item_override);
+ RNA_POINTER_INVALIDATE(&private_ptr_item_storage);
+ if (opop->subitem_local_name != NULL) {
+ RNA_property_collection_lookup_string(
+ ptr_local, prop_local, opop->subitem_local_name, &private_ptr_item_local);
+ if (opop->subitem_reference_name != NULL) {
+ RNA_property_collection_lookup_string(ptr_override,
+ prop_override,
+ opop->subitem_reference_name,
+ &private_ptr_item_override);
+ }
+ else {
+ RNA_property_collection_lookup_string(
+ ptr_override, prop_override, opop->subitem_local_name, &private_ptr_item_override);
+ }
+ }
+ else if (opop->subitem_reference_name != NULL) {
+ RNA_property_collection_lookup_string(
+ ptr_local, prop_local, opop->subitem_reference_name, &private_ptr_item_local);
+ RNA_property_collection_lookup_string(
+ ptr_override, prop_override, opop->subitem_reference_name, &private_ptr_item_override);
+ }
+ else if (opop->subitem_local_index != -1) {
+ RNA_property_collection_lookup_int(
+ ptr_local, prop_local, opop->subitem_local_index, &private_ptr_item_local);
+ if (opop->subitem_reference_index != -1) {
+ RNA_property_collection_lookup_int(ptr_override,
+ prop_override,
+ opop->subitem_reference_index,
+ &private_ptr_item_override);
+ }
+ else {
+ RNA_property_collection_lookup_int(
+ ptr_override, prop_override, opop->subitem_local_index, &private_ptr_item_override);
+ }
+ }
+ else if (opop->subitem_reference_index != -1) {
+ RNA_property_collection_lookup_int(
+ ptr_local, prop_local, opop->subitem_reference_index, &private_ptr_item_local);
+ RNA_property_collection_lookup_int(ptr_override,
+ prop_override,
+ opop->subitem_reference_index,
+ &private_ptr_item_override);
+ }
+ if (prop_storage != NULL) {
+ if (opop->subitem_local_name != NULL) {
+ RNA_property_collection_lookup_string(
+ ptr_storage, prop_storage, opop->subitem_local_name, &private_ptr_item_storage);
+ }
+ else if (opop->subitem_reference_name != NULL) {
+ RNA_property_collection_lookup_string(
+ ptr_storage, prop_storage, opop->subitem_reference_name, &private_ptr_item_storage);
+ }
+ else if (opop->subitem_local_index != -1) {
+ RNA_property_collection_lookup_int(
+ ptr_storage, prop_storage, opop->subitem_local_index, &private_ptr_item_storage);
+ }
+ else if (opop->subitem_reference_index != -1) {
+ RNA_property_collection_lookup_int(
+ ptr_storage, prop_storage, opop->subitem_reference_index, &private_ptr_item_storage);
+ }
+ }
+ ptr_item_local = &private_ptr_item_local;
+ ptr_item_override = &private_ptr_item_override;
+ ptr_item_storage = &private_ptr_item_storage;
+ }
+
if (!rna_property_override_operation_apply(bmain,
ptr_local,
ptr_override,
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 6737363bae4..59e5c584811 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -922,13 +922,13 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
prop = RNA_def_property(srna, "bbone_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "xwidth");
- RNA_def_property_range(prop, 0.0f, 1000.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1000.0f, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_ui_text(prop, "B-Bone Display X Width", "B-Bone X size");
RNA_def_property_update(prop, 0, "rna_Armature_update_data");
prop = RNA_def_property(srna, "bbone_z", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "zwidth");
- RNA_def_property_range(prop, 0.0f, 1000.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1000.0f, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_ui_text(prop, "B-Bone Display Z Width", "B-Bone Z size");
RNA_def_property_update(prop, 0, "rna_Armature_update_data");
diff --git a/source/blender/makesrna/intern/rna_collection.c b/source/blender/makesrna/intern/rna_collection.c
index 5a37c4c0e6f..4700df5352f 100644
--- a/source/blender/makesrna/intern/rna_collection.c
+++ b/source/blender/makesrna/intern/rna_collection.c
@@ -130,9 +130,9 @@ static bool rna_Collection_objects_override_apply(Main *bmain,
PointerRNA *UNUSED(ptr_item_storage),
IDOverrideLibraryPropertyOperation *opop)
{
- (void)opop;
BLI_assert(opop->operation == IDOVERRIDE_LIBRARY_OP_REPLACE &&
"Unsupported RNA override operation on collections' objects");
+ UNUSED_VARS_NDEBUG(opop);
Collection *coll_dst = ptr_dst->id.data;
@@ -233,9 +233,9 @@ static bool rna_Collection_children_override_apply(Main *bmain,
PointerRNA *UNUSED(ptr_item_storage),
IDOverrideLibraryPropertyOperation *opop)
{
- (void)opop;
BLI_assert(opop->operation == IDOVERRIDE_LIBRARY_OP_REPLACE &&
"Unsupported RNA override operation on collections' objects");
+ UNUSED_VARS_NDEBUG(opop);
Collection *coll_dst = ptr_dst->id.data;
@@ -403,6 +403,7 @@ void RNA_def_collections(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "Object");
RNA_def_property_ui_text(
prop, "All Objects", "Objects that are in this collection and its child collections");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
RNA_def_property_collection_funcs(prop,
"rna_Collection_all_objects_begin",
"rna_iterator_listbase_next",
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 6e57d16df27..68a5a01dab8 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -1009,7 +1009,7 @@ static void rna_def_constraint_armature_deform(BlenderRNA *brna)
RNA_def_struct_ui_text(
srna, "Armature Constraint", "Applies transformations done by the Armature modifier");
RNA_def_struct_sdna_from(srna, "bArmatureConstraint", "data");
- RNA_def_struct_ui_icon(srna, ICON_MOD_ARMATURE);
+ RNA_def_struct_ui_icon(srna, ICON_CON_ARMATURE);
prop = RNA_def_property(srna, "targets", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "targets", NULL);
@@ -3026,6 +3026,7 @@ void RNA_def_constraint(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Disable", "Enable/Disable Constraint");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1);
prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE);
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index 310a335ba4c..644d0b712a2 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -1215,8 +1215,8 @@ static void rna_def_font(BlenderRNA *UNUSED(brna), StructRNA *srna)
RNA_def_property_ui_text(prop, "Body Text", "Content of this text object");
RNA_def_property_string_funcs(
prop, "rna_Curve_body_get", "rna_Curve_body_length", "rna_Curve_body_set");
- RNA_def_property_string_maxlength(prop,
- 8192); /* note that originally str did not have a limit! */
+ /* note that originally str did not have a limit! */
+ RNA_def_property_string_maxlength(prop, 8192);
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "body_format", PROP_COLLECTION, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 2cb7c62b028..03ab9da2eff 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -724,8 +724,10 @@ void RNA_struct_free_extension(StructRNA *srna, ExtensionRNA *ext)
#ifdef RNA_RUNTIME
ext->free(ext->data); /* decref's the PyObject that the srna owns */
RNA_struct_blender_type_set(srna, NULL); /* this gets accessed again - XXX fixme */
- RNA_struct_py_type_set(
- srna, NULL); /* NULL the srna's value so RNA_struct_free wont complain of a leak */
+
+ /* NULL the srna's value so RNA_struct_free wont complain of a leak */
+ RNA_struct_py_type_set(srna, NULL);
+
#else
(void)srna;
(void)ext;
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index dfe9e018e94..ea343406c81 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -611,22 +611,22 @@ static void rna_def_modifier_gpencilsimplify(BlenderRNA *brna)
"FIXED",
ICON_IPO_CONSTANT,
"Fixed",
- "Delete alternative vertices in the stroke, except extremes"},
+ "Delete alternating vertices in the stroke, except extremes"},
{GP_SIMPLIFY_ADAPTIVE,
"ADAPTIVE",
ICON_IPO_EASE_IN_OUT,
"Adaptive",
- "Use a RDP algorithm to simplify"},
+ "Use a RDP algorithm to simplify the stroke"},
{GP_SIMPLIFY_SAMPLE,
"SAMPLE",
ICON_IPO_EASE_IN_OUT,
"Sample",
- "Sample a curve using a fixed length"},
+ "Resample the stroke with segments of the specified length"},
{GP_SIMPLIFY_MERGE,
"MERGE",
ICON_IPO_EASE_IN_OUT,
"Merge",
- "Sample a curve using doing merge of vertex"},
+ "Simplify the stroke by merging vertices closer than a given distance"},
{0, NULL, 0, NULL, NULL},
};
@@ -689,9 +689,16 @@ static void rna_def_modifier_gpencilsimplify(BlenderRNA *brna)
/* Sample */
prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "length");
- RNA_def_property_range(prop, 0, 10);
+ RNA_def_property_range(prop, 0, 10.0f);
RNA_def_property_ui_text(prop, "Length", "Length of each segment");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ /* Distance */
+ prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "distance");
+ RNA_def_property_range(prop, 0, 100.0f);
+ RNA_def_property_ui_text(prop, "Distance", "Distance between points");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
}
static void rna_def_modifier_gpencilthick(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index 6378ee15279..8bfc4bf6313 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -719,16 +719,6 @@ void RNA_def_material(BlenderRNA *brna)
static EnumPropertyItem prop_eevee_blend_items[] = {
{MA_BM_SOLID, "OPAQUE", 0, "Opaque", "Render surface without transparency"},
- {MA_BM_ADD,
- "ADD",
- 0,
- "Additive",
- "Render surface and blend the result with additive blending"},
- {MA_BM_MULTIPLY,
- "MULTIPLY",
- 0,
- "Multiply",
- "Render surface and blend the result with multiplicative blending"},
{MA_BM_CLIP,
"CLIP",
0,
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 03173bcb3da..966dc071641 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -2998,6 +2998,30 @@ static void rna_def_mesh(BlenderRNA *brna)
rna_def_paint_mask(brna, prop);
/* End paint mask */
+ /* 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",
+ "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_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_update(prop, 0, "rna_Mesh_update_draw");
+
+ prop = RNA_def_property(srna, "remesh_preserve_paint_mask", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_REPROJECT_PAINT_MASK);
+ 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");
+ /* End remesh */
+
prop = RNA_def_property(srna, "use_auto_smooth", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_AUTOSMOOTH);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index b28403bf28c..a0c00db1a1e 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -100,34 +100,38 @@ static const EnumPropertyItem node_chunksize_items[] = {
#endif
const EnumPropertyItem rna_enum_node_math_items[] = {
- {NODE_MATH_ADD, "ADD", 0, "Add", ""},
- {NODE_MATH_SUB, "SUBTRACT", 0, "Subtract", ""},
- {NODE_MATH_MUL, "MULTIPLY", 0, "Multiply", ""},
- {NODE_MATH_DIVIDE, "DIVIDE", 0, "Divide", ""},
+ {NODE_MATH_ADD, "ADD", 0, "Add", "A + B"},
+ {NODE_MATH_SUBTRACT, "SUBTRACT", 0, "Subtract", "A - B"},
+ {NODE_MATH_MULTIPLY, "MULTIPLY", 0, "Multiply", "A * B"},
+ {NODE_MATH_DIVIDE, "DIVIDE", 0, "Divide", "A / B"},
{0, "", ICON_NONE, NULL, NULL},
- {NODE_MATH_POW, "POWER", 0, "Power", ""},
- {NODE_MATH_LOG, "LOGARITHM", 0, "Logarithm", ""},
- {NODE_MATH_SQRT, "SQRT", 0, "Square Root", ""},
- {NODE_MATH_ABS, "ABSOLUTE", 0, "Absolute", ""},
+ {NODE_MATH_POWER, "POWER", 0, "Power", "A power B"},
+ {NODE_MATH_LOGARITHM, "LOGARITHM", 0, "Logarithm", "Logarithm A base B"},
+ {NODE_MATH_SQRT, "SQRT", 0, "Square Root", "Square root of A"},
+ {NODE_MATH_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Magnitude of A"},
{0, "", ICON_NONE, NULL, NULL},
- {NODE_MATH_MIN, "MINIMUM", 0, "Minimum", ""},
- {NODE_MATH_MAX, "MAXIMUM", 0, "Maximum", ""},
- {NODE_MATH_LESS, "LESS_THAN", 0, "Less Than", ""},
- {NODE_MATH_GREATER, "GREATER_THAN", 0, "Greater Than", ""},
+ {NODE_MATH_MINIMUM, "MINIMUM", 0, "Minimum", "The minimum from A and B"},
+ {NODE_MATH_MAXIMUM, "MAXIMUM", 0, "Maximum", "The maximum from A and B"},
+ {NODE_MATH_LESS_THAN, "LESS_THAN", 0, "Less Than", "1 if A < B else 0"},
+ {NODE_MATH_GREATER_THAN, "GREATER_THAN", 0, "Greater Than", "1 if A > B else 0"},
{0, "", ICON_NONE, NULL, NULL},
- {NODE_MATH_ROUND, "ROUND", 0, "Round", ""},
- {NODE_MATH_FLOOR, "FLOOR", 0, "Floor", ""},
- {NODE_MATH_CEIL, "CEIL", 0, "Ceil", ""},
- {NODE_MATH_FRACT, "FRACT", 0, "Fract", ""},
- {NODE_MATH_MOD, "MODULO", 0, "Modulo", ""},
+ {NODE_MATH_ROUND,
+ "ROUND",
+ 0,
+ "Round",
+ "Round A to the nearest integer. Round upward if the fraction part is 0.5"},
+ {NODE_MATH_FLOOR, "FLOOR", 0, "Floor", "The largest integer smaller than or equal A"},
+ {NODE_MATH_CEIL, "CEIL", 0, "Ceil", "The smallest integer greater than or equal A"},
+ {NODE_MATH_FRACTION, "FRACT", 0, "Fraction", "The fraction part of A"},
+ {NODE_MATH_MODULO, "MODULO", 0, "Modulo", "A mod B"},
{0, "", ICON_NONE, NULL, NULL},
- {NODE_MATH_SIN, "SINE", 0, "Sine", ""},
- {NODE_MATH_COS, "COSINE", 0, "Cosine", ""},
- {NODE_MATH_TAN, "TANGENT", 0, "Tangent", ""},
- {NODE_MATH_ASIN, "ARCSINE", 0, "Arcsine", ""},
- {NODE_MATH_ACOS, "ARCCOSINE", 0, "Arccosine", ""},
- {NODE_MATH_ATAN, "ARCTANGENT", 0, "Arctangent", ""},
- {NODE_MATH_ATAN2, "ARCTAN2", 0, "Arctan2", ""},
+ {NODE_MATH_SINE, "SINE", 0, "Sine", "sin(A)"},
+ {NODE_MATH_COSINE, "COSINE", 0, "Cosine", "cos(A)"},
+ {NODE_MATH_TANGENT, "TANGENT", 0, "Tangent", "tan(A)"},
+ {NODE_MATH_ARCSINE, "ARCSINE", 0, "Arcsine", "arcsin(A)"},
+ {NODE_MATH_ARCCOSINE, "ARCCOSINE", 0, "Arccosine", "arccos(A)"},
+ {NODE_MATH_ARCTANGENT, "ARCTANGENT", 0, "Arctangent", "arctan(A)"},
+ {NODE_MATH_ARCTAN2, "ARCTAN2", 0, "Arctan2", "The signed angle arctan(A / B)"},
{0, NULL, 0, NULL, NULL},
};
@@ -3834,6 +3838,16 @@ static void def_frame(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL);
}
+static void def_map_range(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "clamp", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1);
+ RNA_def_property_ui_text(prop, "Clamp", "Clamp the result to the target range [To Min, To Max]");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_math(StructRNA *srna)
{
PropertyRNA *prop;
@@ -3842,7 +3856,7 @@ static void def_math(StructRNA *srna)
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, rna_enum_node_math_items);
RNA_def_property_ui_text(prop, "Operation", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
prop = RNA_def_property(srna, "use_clamp", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "custom2", SHD_MATH_CLAMP);
@@ -7590,6 +7604,18 @@ static void def_cmp_cryptomatte(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeCryptomatte_update_remove");
}
+static void def_cmp_denoise(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeDenoise", "storage");
+
+ prop = RNA_def_property(srna, "use_hdr", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "hdr", 0);
+ RNA_def_property_ui_text(prop, "HDR", "Process HDR images");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
/* -- Texture Nodes --------------------------------------------------------- */
static void def_tex_output(StructRNA *srna)
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 6069e78d874..bc433691cb4 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -546,6 +546,46 @@ 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)
+{
+ 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");
+ 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,
+ * which is evil in our case. */
+ Object *ob = (Object *)ptr_dst->data;
+ Object *parent_dst = RNA_property_pointer_get(ptr_dst, prop_dst).data;
+ Object *parent_src = RNA_property_pointer_get(ptr_src, prop_src).data;
+
+ if (parent_src == parent_dst) {
+ return false;
+ }
+
+ if (parent_src == NULL) {
+ /* The only case where we do want default behavior (with matrix reset). */
+ ED_object_parent(ob, parent_src, ob->partype, ob->parsubstr);
+ }
+ else {
+ ob->parent = parent_src;
+ }
+ return true;
+}
+
static void rna_Object_parent_type_set(PointerRNA *ptr, int value)
{
Object *ob = (Object *)ptr->data;
@@ -1392,8 +1432,8 @@ bool rna_Object_constraints_override_apply(Main *UNUSED(bmain),
Object *ob_src = (Object *)ptr_src->id.data;
/* Remember that insertion operations are defined and stored in correct order, which means that
- * even if we insert several items in a row, we alays insert first one, then second one, etc.
- * So we should always find 'anchor' constraint in both _src *and* _dst> */
+ * even if we insert several items in a row, we always insert first one, then second one, etc.
+ * So we should always find 'anchor' constraint in both _src *and* _dst. */
bConstraint *con_anchor = NULL;
if (opop->subitem_local_name && opop->subitem_local_name[0]) {
con_anchor = BLI_findstring(
@@ -1480,8 +1520,8 @@ bool rna_Object_modifiers_override_apply(Main *UNUSED(bmain),
Object *ob_src = (Object *)ptr_src->id.data;
/* Remember that insertion operations are defined and stored in correct order, which means that
- * even if we insert several items in a row, we alays insert first one, then second one, etc.
- * So we should always find 'anchor' constraint in both _src *and* _dst> */
+ * even if we insert several items in a row, we always insert first one, then second one, etc.
+ * So we should always find 'anchor' constraint in both _src *and* _dst. */
ModifierData *mod_anchor = NULL;
if (opop->subitem_local_name && opop->subitem_local_name[0]) {
mod_anchor = BLI_findstring(
@@ -2389,6 +2429,7 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, NULL, "rna_Object_parent_set", NULL, NULL);
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_Object_parent_override_apply");
RNA_def_property_ui_text(prop, "Parent", "Parent Object");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_dependency_update");
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index ab6cffe615d..4dd46281a42 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -140,7 +140,7 @@ static void rna_Cache_change(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerR
if (pid.type == PTCACHE_TYPE_SMOKE_DOMAIN) {
cache->step = 1;
}
- BKE_ptcache_update_info(&pid);
+ cache->flag |= PTCACHE_FLAG_INFO_DIRTY;
}
}
@@ -292,6 +292,24 @@ static void rna_PointCache_frame_step_range(
}
}
+int rna_Cache_info_length(PointerRNA *ptr)
+{
+ PointCache *cache = (PointCache *)ptr->data;
+ Object *ob = (Object *)ptr->id.data;
+
+ if (!ob) {
+ return 0;
+ }
+
+ PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
+
+ if (cache->flag & PTCACHE_FLAG_INFO_DIRTY) {
+ BKE_ptcache_update_info(&pid);
+ }
+
+ return (int)strlen(cache->info);
+}
+
static char *rna_CollisionSettings_path(PointerRNA *UNUSED(ptr))
{
/* both methods work ok, but return the shorter path */
@@ -870,6 +888,11 @@ static void rna_def_pointcache_common(StructRNA *srna)
prop = RNA_def_property(srna, "info", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "info");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ /* Note that we do not actually need a getter here, `rna_Cache_info_length` will update the info
+ * string just as well. */
+ RNA_def_property_string_funcs(prop, NULL, "rna_Cache_info_length", NULL);
+ RNA_def_property_string_maxlength(
+ prop, sizeof(((PointCache *)0)->info) / sizeof(*(((PointCache *)0)->info)));
RNA_def_property_ui_text(prop, "Cache Info", "Info on current cache status");
prop = RNA_def_property(srna, "use_external", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 4c50e0c19ae..86ce0ade96b 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -449,8 +449,10 @@ static int rna_ParticleSystem_tessfaceidx_on_emitter(ParticleSystem *particlesys
}
part = particlesystem->part;
- totpart = particlesystem->totcached;
- totchild = particlesystem->totchildcache;
+ /* Note: only hair, keyed and baked particles may have cached items... */
+ totpart = particlesystem->totcached != 0 ? particlesystem->totcached : particlesystem->totpart;
+ totchild = particlesystem->totchildcache != 0 ? particlesystem->totchildcache :
+ particlesystem->totchild;
/* can happen for disconnected/global hair */
if (part->type == PART_HAIR && !particlesystem->childcache) {
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index f17e9ce28fe..cb075884915 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -1241,6 +1241,10 @@ static int rna_property_override_diff_propptr(Main *bmain,
const bool no_prop_name,
IDOverrideLibrary *override,
const char *rna_path,
+ const char *rna_itemname_a,
+ const char *rna_itemname_b,
+ const int rna_itemindex_a,
+ const int rna_itemindex_b,
const int flags,
bool *r_override_changed)
{
@@ -1282,9 +1286,18 @@ static int rna_property_override_diff_propptr(Main *bmain,
IDOverrideLibraryProperty *op = BKE_override_library_property_get(
override, rna_path, &created);
- if (op != NULL && created) { /* If not yet overridden... */
- BKE_override_library_property_operation_get(
- op, IDOVERRIDE_LIBRARY_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ /* If not yet overridden, or if we are handling sub-items (inside a collection)... */
+ if (op != NULL && (created || rna_itemname_a != NULL || rna_itemname_b != NULL ||
+ rna_itemindex_a != -1 || rna_itemindex_b != -1)) {
+ BKE_override_library_property_operation_get(op,
+ IDOVERRIDE_LIBRARY_OP_REPLACE,
+ rna_itemname_b,
+ rna_itemname_a,
+ rna_itemindex_b,
+ rna_itemindex_a,
+ true,
+ NULL,
+ &created);
if (r_override_changed) {
*r_override_changed = created;
}
@@ -1294,12 +1307,56 @@ static int rna_property_override_diff_propptr(Main *bmain,
return comp;
}
else {
+ /* In case we got some array/collection like items identifiers, now is the time to generate a
+ * proper rna path from those. */
+# define RNA_PATH_BUFFSIZE 8192
+
+ char extended_rna_path_buffer[RNA_PATH_BUFFSIZE];
+ char *extended_rna_path = extended_rna_path_buffer;
+
+# define RNA_PATH_PRINTF(_str, ...) \
+ if (BLI_snprintf(extended_rna_path_buffer, RNA_PATH_BUFFSIZE, (_str), __VA_ARGS__) >= \
+ RNA_PATH_BUFFSIZE - 1) { \
+ extended_rna_path = BLI_sprintfN((_str), __VA_ARGS__); \
+ } \
+ (void)0
+# define RNA_PATH_FREE() \
+ if (extended_rna_path != extended_rna_path_buffer && extended_rna_path != rna_path) \
+ MEM_freeN(extended_rna_path)
+
+ /* There may be a propname defined in some cases, while no actual name set
+ * (e.g. happens with point cache), in that case too we want to fall back to index.
+ * Note that we do not need the RNA path for insertion operations. */
+ if (rna_path) {
+ if ((rna_itemname_a != NULL && rna_itemname_a[0] != '\0') &&
+ (rna_itemname_b != NULL && rna_itemname_b[0] != '\0')) {
+ BLI_assert(STREQ(rna_itemname_a, rna_itemname_b));
+ char esc_item_name[RNA_PATH_BUFFSIZE];
+ BLI_strescape(esc_item_name, rna_itemname_a, RNA_PATH_BUFFSIZE);
+ RNA_PATH_PRINTF("%s[\"%s\"]", rna_path, esc_item_name);
+ }
+ else if (rna_itemindex_a != -1) { /* Based on index... */
+ BLI_assert(rna_itemindex_a == rna_itemindex_b);
+ RNA_PATH_PRINTF("%s[%d]", rna_path, rna_itemindex_a);
+ }
+ else {
+ extended_rna_path = (char *)rna_path;
+ }
+ }
+
eRNAOverrideMatchResult report_flags = 0;
const bool match = RNA_struct_override_matches(
- bmain, propptr_a, propptr_b, rna_path, override, flags, &report_flags);
+ bmain, propptr_a, propptr_b, extended_rna_path, override, flags, &report_flags);
if (r_override_changed && (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) != 0) {
*r_override_changed = true;
}
+
+ RNA_PATH_FREE();
+
+# undef RNA_PATH_BUFFSIZE
+# undef RNA_PATH_PRINTF
+# undef RNA_PATH_FREE
+
return !match;
}
}
@@ -1616,6 +1673,10 @@ int rna_property_override_diff_default(Main *bmain,
no_prop_name,
override,
rna_path,
+ NULL,
+ NULL,
+ -1,
+ -1,
flags,
r_override_changed);
}
@@ -1636,21 +1697,6 @@ int rna_property_override_diff_default(Main *bmain,
int idx_a = 0;
int idx_b = 0;
-# define RNA_PATH_BUFFSIZE 8192
-
- char extended_rna_path_buffer[RNA_PATH_BUFFSIZE];
- char *extended_rna_path = extended_rna_path_buffer;
-
-# define RNA_PATH_PRINTF(_str, ...) \
- if (BLI_snprintf(extended_rna_path_buffer, RNA_PATH_BUFFSIZE, (_str), __VA_ARGS__) >= \
- RNA_PATH_BUFFSIZE - 1) { \
- extended_rna_path = BLI_sprintfN((_str), __VA_ARGS__); \
- } \
- (void)0
-# define RNA_PATH_FREE() \
- if (extended_rna_path != extended_rna_path_buffer) \
- MEM_freeN(extended_rna_path)
-
CollectionPropertyIterator iter_a, iter_b;
RNA_property_collection_begin(ptr_a, prop_a, &iter_a);
RNA_property_collection_begin(ptr_b, prop_b, &iter_b);
@@ -1730,41 +1776,15 @@ int rna_property_override_diff_default(Main *bmain,
# endif
if (!(is_id || is_valid_for_diffing || is_valid_for_insertion)) {
- /* Differences we cannot handle, we can break here
- * (we do not support replacing ID pointers in collections e.g.). */
+ /* Differences we cannot handle, we can break here. */
equals = false;
abort = true;
break;
}
- /* There may be a propname defined in some cases, while no actual name set
- * (e.g. happens with point cache), in that case too we want to fall back to index.
- * Note that we do not need the RNA path for insertion operations. */
- if (is_id || is_valid_for_diffing) {
- if ((propname_a != NULL && propname_a[0] != '\0') &&
- (propname_b != NULL && propname_b[0] != '\0')) {
- if (rna_path) {
- /* In case of name, either it is valid for diffing, and _a and _b are identical,
- * or it is valid for insertion, and we need to use _a. */
- char esc_item_name[RNA_PATH_BUFFSIZE];
- BLI_strescape(esc_item_name, propname_a, RNA_PATH_BUFFSIZE);
- RNA_PATH_PRINTF("%s[\"%s\"]", rna_path, esc_item_name);
- }
- }
- else { /* Based on index... */
- if (rna_path) {
- /* In case of indices, we need _a one for insertion,
- * but _b ones for in-depth diffing.
- * Insertion always happen once all 'replace' operations have been done,
- * otherwise local and reference paths for those would have to be different! */
- RNA_PATH_PRINTF("%s[%d]", rna_path, is_valid_for_insertion ? idx_a : idx_b);
- }
- }
- }
-
- /* Collections do not support replacement of their data
- * (since they do not support removing), only in *some* cases, insertion.
- * We also assume then that _a data is the one where things are inserted. */
+ /* Collections do not support replacement of their data (except for collections of ID
+ * pointers), since they do not support removing, only in *some* cases, insertion. We
+ * also assume then that _a data is the one where things are inserted. */
if (is_valid_for_insertion && use_insertion) {
bool created;
IDOverrideLibraryProperty *op = BKE_override_library_property_get(
@@ -1812,7 +1832,11 @@ int rna_property_override_diff_default(Main *bmain,
no_ownership,
no_prop_name,
override,
- extended_rna_path,
+ rna_path,
+ propname_a,
+ propname_b,
+ idx_a,
+ idx_b,
flags,
r_override_changed);
equals = equals && eq;
@@ -1839,7 +1863,6 @@ int rna_property_override_diff_default(Main *bmain,
propname_b = buff_b;
}
propname_b[0] = '\0';
- RNA_PATH_FREE();
if (!do_create && !equals) {
abort = true; /* Early out in case we do not want to loop over whole collection. */
@@ -1864,10 +1887,6 @@ int rna_property_override_diff_default(Main *bmain,
RNA_property_collection_next(&iter_b);
idx_b++;
}
-
-# undef RNA_PATH_BUFFSIZE
-# undef RNA_PATH_PRINTF
-# undef RNA_PATH_FREE
}
/* Not same number of items in both collections. */
@@ -2824,8 +2843,10 @@ static void rna_def_number_property(StructRNA *srna, PropertyType type)
prop = RNA_def_property(srna, "default_array", type, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_array(
- prop, RNA_MAX_ARRAY_DIMENSION); /* no fixed default length, important its not 0 though */
+
+ /* no fixed default length, important its not 0 though. */
+ RNA_def_property_array(prop, RNA_MAX_ARRAY_DIMENSION);
+
RNA_def_property_flag(prop, PROP_DYNAMIC);
RNA_def_property_dynamic_array_funcs(
prop, "rna_NumberProperty_default_array_get_length"); /* same for all types */
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 531ff27798d..e74e67fb83e 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -739,6 +739,36 @@ static void rna_GPencilInterpolateSettings_type_set(PointerRNA *ptr, int value)
}
}
+static void rna_Gpencil_mask_point_update(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ PointerRNA *ptr)
+{
+ ToolSettings *ts = (ToolSettings *)ptr->data;
+
+ ts->gpencil_selectmode_sculpt &= ~GP_SCULPT_MASK_SELECTMODE_STROKE;
+ ts->gpencil_selectmode_sculpt &= ~GP_SCULPT_MASK_SELECTMODE_SEGMENT;
+}
+
+static void rna_Gpencil_mask_stroke_update(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ PointerRNA *ptr)
+{
+ ToolSettings *ts = (ToolSettings *)ptr->data;
+
+ ts->gpencil_selectmode_sculpt &= ~GP_SCULPT_MASK_SELECTMODE_POINT;
+ ts->gpencil_selectmode_sculpt &= ~GP_SCULPT_MASK_SELECTMODE_SEGMENT;
+}
+
+static void rna_Gpencil_mask_segment_update(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ PointerRNA *ptr)
+{
+ ToolSettings *ts = (ToolSettings *)ptr->data;
+
+ ts->gpencil_selectmode_sculpt &= ~GP_SCULPT_MASK_SELECTMODE_POINT;
+ ts->gpencil_selectmode_sculpt &= ~GP_SCULPT_MASK_SELECTMODE_STROKE;
+}
+
/* Read-only Iterator of all the scene objects. */
static void rna_Scene_objects_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
@@ -821,8 +851,8 @@ static void rna_Scene_fps_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(p
{
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_FPS | ID_RECALC_SEQUENCER_STRIPS);
/* NOTE: Tag via dependency graph will take care of all the updates ion the evaluated domain,
- * however, changes in FPS actually modifies an original stip length, so this we take care about
- * here. */
+ * however, changes in FPS actually modifies an original skip length,
+ * so this we take care about here. */
BKE_sequencer_refresh_sound_length(bmain, scene);
}
@@ -3058,13 +3088,39 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop, "Only Endpoints", "Only use the first and last parts of the stroke for snapping");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
- /* Grease Pencil - Select mode */
- prop = RNA_def_property(srna, "gpencil_selectmode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "gpencil_selectmode");
+ /* Grease Pencil - Select mode Edit */
+ prop = RNA_def_property(srna, "gpencil_selectmode_edit", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "gpencil_selectmode_edit");
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);
+ /* Grease Pencil - Select mode Sculpt */
+ prop = RNA_def_property(srna, "use_gpencil_select_mask_point", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "gpencil_selectmode_sculpt", GP_SCULPT_MASK_SELECTMODE_POINT);
+ RNA_def_property_ui_text(prop, "Selection Mask", "Only sculpt selected stroke points");
+ RNA_def_property_ui_icon(prop, ICON_GP_SELECT_POINTS, 0);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_Gpencil_mask_point_update");
+
+ prop = RNA_def_property(srna, "use_gpencil_select_mask_stroke", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "gpencil_selectmode_sculpt", GP_SCULPT_MASK_SELECTMODE_STROKE);
+ RNA_def_property_ui_text(prop, "Selection Mask", "Only sculpt selected stroke");
+ RNA_def_property_ui_icon(prop, ICON_GP_SELECT_STROKES, 0);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_Gpencil_mask_stroke_update");
+
+ prop = RNA_def_property(srna, "use_gpencil_select_mask_segment", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "gpencil_selectmode_sculpt", GP_SCULPT_MASK_SELECTMODE_SEGMENT);
+ RNA_def_property_ui_text(
+ prop, "Selection Mask", "Only sculpt selected stroke points between other strokes");
+ RNA_def_property_ui_icon(prop, ICON_GP_SELECT_BETWEEN_STROKES, 0);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_Gpencil_mask_segment_update");
+
/* Annotations - 2D Views Stroke Placement */
prop = RNA_def_property(srna, "annotation_stroke_placement_view2d", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_v2d_align");
@@ -3467,7 +3523,7 @@ static void rna_def_statvis(BlenderRNA *brna)
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), 0.001, 3);
+ 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");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_EditMesh_update");
diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c
index 853017e6daf..c868c79e968 100644
--- a/source/blender/makesrna/intern/rna_screen.c
+++ b/source/blender/makesrna/intern/rna_screen.c
@@ -225,12 +225,15 @@ static const EnumPropertyItem *rna_Area_ui_type_itemf(bContext *C,
static int rna_Area_ui_type_get(PointerRNA *ptr)
{
- int value = rna_Area_type_get(ptr) << 16;
ScrArea *sa = ptr->data;
+ const int area_type = rna_Area_type_get(ptr);
+ const bool area_changing = sa->butspacetype != SPACE_EMPTY;
+ int value = area_type << 16;
+
/* sa->type can be NULL (when not yet initialized), try to do it now. */
/* Copied from `ED_area_initialize()`.*/
- if (sa->type == NULL) {
- sa->type = BKE_spacetype_from_id(sa->spacetype);
+ if (sa->type == NULL || area_changing) {
+ sa->type = BKE_spacetype_from_id(area_type);
if (sa->type == NULL) {
sa->spacetype = SPACE_VIEW3D;
sa->type = BKE_spacetype_from_id(sa->spacetype);
@@ -238,7 +241,7 @@ static int rna_Area_ui_type_get(PointerRNA *ptr)
BLI_assert(sa->type != NULL);
}
if (sa->type->space_subtype_item_extend != NULL) {
- value |= sa->type->space_subtype_get(sa);
+ value |= area_changing ? sa->butspacetype_subtype : sa->type->space_subtype_get(sa);
}
return value;
}
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 84f2cb7c1be..fab3585797a 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -1420,13 +1420,6 @@ static void rna_def_gpencil_sculpt(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Guide", "");
- prop = RNA_def_property(srna, "use_select_mask", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_SETT_FLAG_SELECT_MASK);
- RNA_def_property_ui_text(prop, "Selection Mask", "Only sculpt selected stroke points");
- RNA_def_property_ui_icon(prop, ICON_GP_ONLY_SELECTED, 0);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-
prop = RNA_def_property(srna, "use_edit_position", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_SETT_FLAG_APPLY_POSITION);
RNA_def_property_ui_text(prop, "Affect Position", "The brush affects the position of the point");
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 912e9599f14..a4f0715ca7b 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -32,6 +32,8 @@
#include "BKE_studiolight.h"
#include "BKE_sequencer.h"
+#include "ED_text.h"
+
#include "BLI_math.h"
#include "DNA_action_types.h"
@@ -1504,6 +1506,11 @@ static void rna_SpaceTextEditor_text_set(PointerRNA *ptr,
WM_main_add_notifier(NC_TEXT | NA_SELECTED, st->text);
}
+static bool rna_SpaceTextEditor_text_is_syntax_highlight_supported(struct SpaceText *space)
+{
+ return ED_text_is_syntax_highlight_supported(space->text);
+}
+
static void rna_SpaceTextEditor_updateEdited(Main *UNUSED(bmain),
Scene *UNUSED(scene),
PointerRNA *ptr)
@@ -2770,6 +2777,7 @@ static void rna_def_space_outliner(BlenderRNA *brna)
static const EnumPropertyItem filter_state_items[] = {
{SO_FILTER_OB_ALL, "ALL", 0, "All", "Show all objects in the view layer"},
{SO_FILTER_OB_VISIBLE, "VISIBLE", 0, "Visible", "Show visible objects"},
+ {SO_FILTER_OB_INVISIBLE, "INVISIBLE", 0, "Invisible", "Show invisible objects"},
{SO_FILTER_OB_SELECTED, "SELECTED", 0, "Selected", "Show selected objects"},
{SO_FILTER_OB_ACTIVE, "ACTIVE", 0, "Active", "Show only the active object"},
{0, NULL, 0, NULL, NULL},
@@ -2808,6 +2816,12 @@ static void rna_def_space_outliner(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Sort Alphabetically", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+ prop = RNA_def_property(srna, "use_sync_select", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SO_SYNC_SELECT);
+ RNA_def_property_ui_text(
+ prop, "Sync Outliner Selection", "Sync outliner selection with other editors");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
/* Granular restriction column option. */
prop = RNA_def_property(srna, "show_restrict_column_enable", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "show_restrict_flags", SO_RESTRICT_ENABLE);
@@ -4539,6 +4553,7 @@ static void rna_def_space_text(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+ FunctionRNA *func;
srna = RNA_def_struct(brna, "SpaceTextEditor", "Space");
RNA_def_struct_sdna(srna, "SpaceText");
@@ -4568,6 +4583,15 @@ static void rna_def_space_text(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_LINENUMBERS_ON, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL);
+ func = RNA_def_function(srna,
+ "is_syntax_highlight_supported",
+ "rna_SpaceTextEditor_text_is_syntax_highlight_supported");
+ RNA_def_function_return(func,
+ RNA_def_boolean(func, "is_syntax_highlight_supported", false, "", ""));
+ RNA_def_function_ui_description(func,
+ "Returns True if the editor supports syntax highlighting "
+ "for the current text datablock");
+
prop = RNA_def_property(srna, "show_syntax_highlight", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "showsyntax", 0);
RNA_def_property_ui_text(prop, "Syntax Highlight", "Syntax highlight for scripting");
diff --git a/source/blender/makesrna/intern/rna_text.c b/source/blender/makesrna/intern/rna_text.c
index b09b5327f57..64a23dfa985 100644
--- a/source/blender/makesrna/intern/rna_text.c
+++ b/source/blender/makesrna/intern/rna_text.c
@@ -27,6 +27,8 @@
#include "BKE_text.h"
+#include "ED_text.h"
+
#include "RNA_define.h"
#include "rna_internal.h"
diff --git a/source/blender/makesrna/intern/rna_text_api.c b/source/blender/makesrna/intern/rna_text_api.c
index 4ca48226ee9..524dcfa9ad7 100644
--- a/source/blender/makesrna/intern/rna_text_api.c
+++ b/source/blender/makesrna/intern/rna_text_api.c
@@ -23,6 +23,8 @@
#include "BLI_utildefines.h"
+#include "ED_text.h"
+
#include "RNA_define.h"
#include "rna_internal.h" /* own include */
@@ -59,6 +61,14 @@ void RNA_api_text(StructRNA *srna)
func, "write text at the cursor location and advance to the end of the text block");
parm = RNA_def_string(func, "text", "Text", 0, "", "New text for this data-block");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ func = RNA_def_function(
+ srna, "is_syntax_highlight_supported", "ED_text_is_syntax_highlight_supported");
+ RNA_def_function_return(func,
+ RNA_def_boolean(func, "is_syntax_highlight_supported", false, "", ""));
+ RNA_def_function_ui_description(func,
+ "Returns True if the editor supports syntax highlighting "
+ "for the current text datablock");
}
#endif
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index d50f97e88ca..c8b039bd2d6 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -796,6 +796,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_boolean(func, "emboss", true, "", "Draw the button itself, not just the icon/text");
RNA_def_int(func,
"index",
+ /* RNA_NO_INDEX == -1 */
-1,
-2,
INT_MAX,
@@ -803,7 +804,7 @@ void RNA_api_ui_layout(StructRNA *srna)
"The index of this button, when set a single member of an array can be accessed, "
"when set to -1 all array members are used",
-2,
- INT_MAX); /* RNA_NO_INDEX == -1 */
+ INT_MAX);
parm = RNA_def_property(func, "icon_value", PROP_INT, PROP_UNSIGNED);
RNA_def_property_ui_text(parm, "Icon Value", "Override automatic icon of the item");
RNA_def_boolean(func, "invert_checkbox", false, "", "Draw checkbox value inverted");
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 48eee713fc9..72a3455b120 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -2297,6 +2297,11 @@ static void rna_def_userdef_theme_space_outliner(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Selected Highlight", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+ prop = RNA_def_property(srna, "active", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Active Highlight", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
prop = RNA_def_property(srna, "selected_object", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Selected Objects", "");
@@ -4090,6 +4095,12 @@ static void rna_def_userdef_view(BlenderRNA *brna)
"Show the frames per second screen refresh rate, while animation is played back");
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_ui_text(prop,
+ "Enabled Add-ons Only",
+ "Only show enabled add-ons. Un-check to see all installed add-ons");
+
static const EnumPropertyItem factor_display_items[] = {
{USER_FACTOR_AS_FACTOR, "FACTOR", 0, "Factor", "Display factors as values between 0 and 1"},
{USER_FACTOR_AS_PERCENTAGE, "PERCENTAGE", 0, "Percentage", "Display factors as percentages"},
@@ -5820,7 +5831,10 @@ void RNA_def_userdef(BlenderRNA *brna)
/* Preferences Flags */
prop = RNA_def_property(srna, "use_preferences_save", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "pref_flag", USER_PREF_FLAG_SAVE);
- RNA_def_property_ui_text(prop, "Save on Exit", "Save preferences on exit when modified");
+ RNA_def_property_ui_text(prop,
+ "Save on Exit",
+ "Save preferences on exit when modified "
+ "(unless factory settings have been loaded)");
prop = RNA_def_property(srna, "is_dirty", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "runtime.is_dirty", 0);
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 1edda29a556..123ec9634c9 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -1514,8 +1514,10 @@ static StructRNA *rna_Operator_register(Main *bmain,
/* create a new operator type */
dummyot.ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummyot.idname, &RNA_Operator);
- RNA_def_struct_flag(dummyot.ext.srna,
- STRUCT_NO_IDPROPERTIES); /* operator properties are registered separately */
+
+ /* Operator properties are registered separately. */
+ RNA_def_struct_flag(dummyot.ext.srna, STRUCT_NO_IDPROPERTIES);
+
RNA_def_struct_property_tags(dummyot.ext.srna, rna_enum_operator_property_tags);
RNA_def_struct_translation_context(dummyot.ext.srna, dummyot.translation_context);
dummyot.ext.data = data;
diff --git a/source/blender/makesrna/intern/rna_wm_gizmo.c b/source/blender/makesrna/intern/rna_wm_gizmo.c
index 38b6ac9ac52..534e3042768 100644
--- a/source/blender/makesrna/intern/rna_wm_gizmo.c
+++ b/source/blender/makesrna/intern/rna_wm_gizmo.c
@@ -870,9 +870,10 @@ static StructRNA *rna_GizmoGroup_register(Main *bmain,
/* create a new gizmogroup type */
dummywgt.ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummywgt.idname, &RNA_GizmoGroup);
- RNA_def_struct_flag(
- dummywgt.ext.srna,
- STRUCT_NO_IDPROPERTIES); /* gizmogroup properties are registered separately */
+
+ /* Gizmo group properties are registered separately. */
+ RNA_def_struct_flag(dummywgt.ext.srna, STRUCT_NO_IDPROPERTIES);
+
dummywgt.ext.data = data;
dummywgt.ext.call = call;
dummywgt.ext.free = free;
diff --git a/source/blender/makesrna/intern/rna_wm_gizmo_api.c b/source/blender/makesrna/intern/rna_wm_gizmo_api.c
index f7335572a14..bc6c2e8a796 100644
--- a/source/blender/makesrna/intern/rna_wm_gizmo_api.c
+++ b/source/blender/makesrna/intern/rna_wm_gizmo_api.c
@@ -90,7 +90,7 @@ static void rna_gizmo_target_set_prop(wmGizmo *gz,
RPT_ERROR,
"Property '%s.%s' not found",
RNA_struct_identifier(ptr->type),
- target_propname);
+ propname);
return;
}
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index 309af4d4812..a05b7023392 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -214,8 +214,9 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
- BLI_assert(bm->vtoolflagpool == NULL && bm->etoolflagpool == NULL &&
- bm->ftoolflagpool == NULL); /* make sure we never alloc'd these */
+ /* Make sure we never alloc'd these. */
+ BLI_assert(bm->vtoolflagpool == NULL && bm->etoolflagpool == NULL && bm->ftoolflagpool == NULL);
+
BM_mesh_free(bm);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index 107622e33c0..dc4898c83ff 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -262,8 +262,9 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
mul_transposed_m3_v3(nmat, efa->no);
normalize_v3(efa->no);
- BM_elem_flag_enable(
- efa, BM_FACE_TAG); /* temp tag to test which side split faces are from */
+
+ /* Temp tag to test which side split faces are from. */
+ BM_elem_flag_enable(efa, BM_FACE_TAG);
/* remap material */
if (LIKELY(efa->mat_nr < ob_src_totcol)) {
diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c
index 3417aaeeb5c..f2f2b13b0df 100644
--- a/source/blender/modifiers/intern/MOD_mask.c
+++ b/source/blender/modifiers/intern/MOD_mask.c
@@ -138,10 +138,10 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
return mesh;
}
- /* Determine whether each vertexgroup is associated with a selected bone or not:
- * - Each cell is a boolean saying whether bone corresponding to the ith group is selected.
+ /* Determine whether each vertex-group is associated with a selected bone or not:
+ * - Each cell is a boolean saying whether bone corresponding to the i'th group selected.
* - Groups that don't match a bone are treated as not existing
- * (along with the corresponding ungrouped verts).
+ * (along with the corresponding un-grouped verts).
*/
bone_select_array = MEM_malloc_arrayN((size_t)defbase_tot, sizeof(char), "mask array");
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c
index 760830ffb24..0f57b759e38 100644
--- a/source/blender/modifiers/intern/MOD_meshsequencecache.c
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c
@@ -114,10 +114,20 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
}
+ /* If this invocation is for the ORCO mesh, and the mesh in Alembic hasn't changed topology, we
+ * must return the mesh as-is instead of deforming it. */
+ if (ctx->flag & MOD_APPLY_ORCO &&
+ !ABC_mesh_topology_changed(mcmd->reader, ctx->object, mesh, time, &err_str)) {
+ return mesh;
+ }
+
if (me != NULL) {
MVert *mvert = mesh->mvert;
MEdge *medge = mesh->medge;
MPoly *mpoly = mesh->mpoly;
+
+ /* TODO(sybren+bastien): possibly check relevant custom data layers (UV/color depending on
+ * flags) and duplicate those too. */
if ((me->mvert == mvert) || (me->medge == medge) || (me->mpoly == mpoly)) {
/* We need to duplicate data here, otherwise we'll modify org mesh, see T51701. */
BKE_id_copy_ex(NULL,
diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c
index 8d511207b9b..d10d74da453 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -351,10 +351,8 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd,
simpleDeform_callback(smd_factor, deform_axis, dcut_remap, co_remap); /* apply deform */
copy_v3_v3_unmap(co, co_remap, axis_map);
- interp_v3_v3v3(vertexCos[i],
- vertexCos[i],
- co,
- weight); /* Use vertex weight has coef of linear interpolation */
+ /* Use vertex weight has coef of linear interpolation */
+ interp_v3_v3v3(vertexCos[i], vertexCos[i], co, weight);
if (transf) {
BLI_space_transform_invert(transf, vertexCos[i]);
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 80afcada4b9..284eaa8b70b 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -62,6 +62,7 @@ set(SRC
composite/nodes/node_composite_cryptomatte.c
composite/nodes/node_composite_curves.c
composite/nodes/node_composite_defocus.c
+ composite/nodes/node_composite_denoise.c
composite/nodes/node_composite_despeckle.c
composite/nodes/node_composite_diffMatte.c
composite/nodes/node_composite_dilate.c
@@ -147,6 +148,7 @@ set(SRC
shader/nodes/node_shader_bsdf_velvet.c
shader/nodes/node_shader_bump.c
shader/nodes/node_shader_camera.c
+ shader/nodes/node_shader_clamp.c
shader/nodes/node_shader_common.c
shader/nodes/node_shader_curves.c
shader/nodes/node_shader_displacement.c
@@ -163,6 +165,7 @@ set(SRC
shader/nodes/node_shader_layer_weight.c
shader/nodes/node_shader_light_falloff.c
shader/nodes/node_shader_light_path.c
+ shader/nodes/node_shader_map_range.c
shader/nodes/node_shader_mapping.c
shader/nodes/node_shader_math.c
shader/nodes/node_shader_mixRgb.c
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index e6d9ed6f70e..534e9012693 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -74,6 +74,7 @@ void register_node_type_cmp_dilateerode(void);
void register_node_type_cmp_inpaint(void);
void register_node_type_cmp_despeckle(void);
void register_node_type_cmp_defocus(void);
+void register_node_type_cmp_denoise(void);
void register_node_type_cmp_valtorgb(void);
void register_node_type_cmp_rgbtobw(void);
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index ead42779bc0..9349a428021 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -48,6 +48,8 @@ void register_node_type_sh_brightcontrast(void);
void register_node_type_sh_mapping(void);
void register_node_type_sh_curve_vec(void);
void register_node_type_sh_curve_rgb(void);
+void register_node_type_sh_map_range(void);
+void register_node_type_sh_clamp(void);
void register_node_type_sh_math(void);
void register_node_type_sh_vect_math(void);
void register_node_type_sh_squeeze(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index f27c50ae736..c72e97642a2 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -50,6 +50,8 @@ DefNode(ShaderNode, SH_NODE_MAPPING, def_sh_mapping, "MAPPIN
DefNode(ShaderNode, SH_NODE_CURVE_VEC, def_vector_curve, "CURVE_VEC", VectorCurve, "Vector Curves", "" )
DefNode(ShaderNode, SH_NODE_CURVE_RGB, def_rgb_curve, "CURVE_RGB", RGBCurve, "RGB Curves", "" )
DefNode(ShaderNode, SH_NODE_CAMERA, 0, "CAMERA", CameraData, "Camera Data", "" )
+DefNode(ShaderNode, SH_NODE_MAP_RANGE, def_map_range, "MAP_RANGE", MapRange, "Map Range", "" )
+DefNode(ShaderNode, SH_NODE_CLAMP, 0, "CLAMP", Clamp, "Clamp", "" )
DefNode(ShaderNode, SH_NODE_MATH, def_math, "MATH", Math, "Math", "" )
DefNode(ShaderNode, SH_NODE_VECT_MATH, def_vector_math, "VECT_MATH", VectorMath, "Vector Math", "" )
DefNode(ShaderNode, SH_NODE_SQUEEZE, 0, "SQUEEZE", Squeeze, "Squeeze Value", "" )
@@ -214,6 +216,7 @@ DefNode(CompositorNode, CMP_NODE_PLANETRACKDEFORM,def_cmp_planetrackdeform,"PLAN
DefNode(CompositorNode, CMP_NODE_CORNERPIN, 0, "CORNERPIN", CornerPin, "Corner Pin", "" )
DefNode(CompositorNode, CMP_NODE_SUNBEAMS, def_cmp_sunbeams, "SUNBEAMS", SunBeams, "Sun Beams", "" )
DefNode(CompositorNode, CMP_NODE_CRYPTOMATTE, def_cmp_cryptomatte, "CRYPTOMATTE", Cryptomatte, "Cryptomatte", "" )
+DefNode(CompositorNode, CMP_NODE_DENOISE, def_cmp_denoise, "DENOISE", Denoise, "Denoise", "" )
DefNode(TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" )
DefNode(TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" )
diff --git a/source/blender/nodes/composite/nodes/node_composite_denoise.c b/source/blender/nodes/composite/nodes/node_composite_denoise.c
new file mode 100644
index 00000000000..e2fdb08816a
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_denoise.c
@@ -0,0 +1,58 @@
+/*
+ * ***** 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) 2019 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Stefan Werner
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_denoise.c
+ * \ingroup cmpnodes
+ */
+
+#include "node_composite_util.h"
+
+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},
+ {-1, 0, ""}};
+static bNodeSocketTemplate cmp_node_denoise_out[] = {{SOCK_RGBA, 0, N_("Image")}, {-1, 0, ""}};
+
+static void node_composit_init_denonise(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeDenoise *ndg = MEM_callocN(sizeof(NodeDenoise), "node denoise data");
+ ndg->hdr = true;
+ node->storage = ndg;
+}
+
+void register_node_type_cmp_denoise(void)
+{
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_DENOISE, "Denoise", NODE_CLASS_OP_FILTER, 0);
+ node_type_socket_templates(&ntype, cmp_node_denoise_in, cmp_node_denoise_out);
+ node_type_init(&ntype, node_composit_init_denonise);
+ node_type_storage(&ntype, "NodeDenoise", node_free_standard_storage, node_copy_standard_storage);
+
+ nodeRegisterType(&ntype);
+}
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 2a371b7d184..595ddf27d0a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
@@ -24,7 +24,17 @@
static bNodeSocketTemplate sh_node_bsdf_principled_in[] = {
{SOCK_RGBA, 1, N_("Base Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
{SOCK_FLOAT, 1, N_("Subsurface"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR, 1, N_("Subsurface Radius"), 1.0f, 0.2f, 0.1f, 0.0f, 0.0f, 100.0f},
+ {SOCK_VECTOR,
+ 1,
+ N_("Subsurface Radius"),
+ 1.0f,
+ 0.2f,
+ 0.1f,
+ 0.0f,
+ 0.0f,
+ 100.0f,
+ PROP_NONE,
+ SOCK_COMPACT},
{SOCK_RGBA, 1, N_("Subsurface Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
{SOCK_FLOAT, 1, N_("Metallic"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{SOCK_FLOAT, 1, N_("Specular"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
@@ -122,8 +132,13 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
&in[21].link);
}
+ bool use_diffuse = socket_not_one(4) && socket_not_one(15);
+ bool use_subsurf = socket_not_zero(1) && use_diffuse && node->sss_id > 0;
+ bool use_refract = socket_not_one(4) && socket_not_zero(15);
+ bool use_clear = socket_not_zero(12);
+
/* SSS Profile */
- if (node->sss_id == 1) {
+ if (use_subsurf) {
static short profile = SHD_SUBSURFACE_BURLEY;
bNodeSocket *socket = BLI_findlink(&node->original->inputs, 2);
bNodeSocketValueRGBA *socket_data = socket->default_value;
@@ -138,11 +153,6 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
GPU_link(mat, "set_rgb_one", &sss_scale);
}
- bool use_diffuse = socket_not_one(4) && socket_not_one(15);
- bool use_subsurf = socket_not_zero(1) && use_diffuse && node->sss_id == 1;
- bool use_refract = socket_not_one(4) && socket_not_zero(15);
- bool use_clear = socket_not_zero(12);
-
/* Due to the manual effort done per config, we only optimize the most common permutations. */
char *node_name;
uint flag = 0;
diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.c b/source/blender/nodes/shader/nodes/node_shader_clamp.c
new file mode 100644
index 00000000000..8e5b90436ea
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_clamp.c
@@ -0,0 +1,56 @@
+/*
+ * 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 shdnodes
+ */
+
+#include "node_shader_util.h"
+
+/* **************** Clamp ******************** */
+static bNodeSocketTemplate sh_node_clamp_in[] = {
+ {SOCK_FLOAT, 1, N_("Value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ {SOCK_FLOAT, 1, N_("Min"), 0.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_FLOAT, 1, N_("Max"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {-1, 0, ""},
+};
+static bNodeSocketTemplate sh_node_clamp_out[] = {
+ {SOCK_FLOAT, 0, N_("Result")},
+ {-1, 0, ""},
+};
+
+static int gpu_shader_clamp(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "clamp_value", in, out);
+}
+
+void register_node_type_sh_clamp(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_CLAMP, "Clamp", NODE_CLASS_CONVERTOR, 0);
+ node_type_socket_templates(&ntype, sh_node_clamp_in, sh_node_clamp_out);
+ node_type_gpu(&ntype, gpu_shader_clamp);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_holdout.c b/source/blender/nodes/shader/nodes/node_shader_holdout.c
index a4d1e77c736..2762e5ec1f5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_holdout.c
+++ b/source/blender/nodes/shader/nodes/node_shader_holdout.c
@@ -30,6 +30,15 @@ static bNodeSocketTemplate sh_node_holdout_out[] = {
{-1, 0, ""},
};
+static int gpu_shader_rgb(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "node_holdout", in, out);
+}
+
/* node type definition */
void register_node_type_sh_holdout(void)
{
@@ -39,6 +48,7 @@ void register_node_type_sh_holdout(void)
node_type_socket_templates(&ntype, sh_node_holdout_in, sh_node_holdout_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
+ node_type_gpu(&ntype, gpu_shader_rgb);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.c b/source/blender/nodes/shader/nodes/node_shader_map_range.c
new file mode 100644
index 00000000000..7ebf3faf1f3
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_map_range.c
@@ -0,0 +1,68 @@
+/*
+ * 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 shdnodes
+ */
+
+#include "node_shader_util.h"
+
+/* **************** Map Range ******************** */
+static bNodeSocketTemplate sh_node_map_range_in[] = {
+ {SOCK_FLOAT, 1, N_("Value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ {SOCK_FLOAT, 1, N_("From Min"), 0.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_FLOAT, 1, N_("From Max"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_FLOAT, 1, N_("To Min"), 0.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_FLOAT, 1, N_("To Max"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {-1, 0, ""},
+};
+static bNodeSocketTemplate sh_node_map_range_out[] = {
+ {SOCK_FLOAT, 0, N_("Result")},
+ {-1, 0, ""},
+};
+
+static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->custom1 = true;
+}
+
+static int gpu_shader_map_range(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ GPU_stack_link(mat, node, "map_range", in, out);
+ if (node->custom1) {
+ GPU_link(mat, "clamp_value", out[0].link, in[3].link, in[4].link, &out[0].link);
+ }
+ return 1;
+}
+
+void register_node_type_sh_map_range(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTOR, 0);
+ node_type_socket_templates(&ntype, sh_node_map_range_in, sh_node_map_range_out);
+ node_type_init(&ntype, node_shader_init_map_range);
+ node_type_gpu(&ntype, gpu_shader_map_range);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.c b/source/blender/nodes/shader/nodes/node_shader_math.c
index f0cd2273e67..aaedc4aa1b7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_math.c
+++ b/source/blender/nodes/shader/nodes/node_shader_math.c
@@ -31,272 +31,6 @@ static bNodeSocketTemplate sh_node_math_in[] = {
static bNodeSocketTemplate sh_node_math_out[] = {{SOCK_FLOAT, 0, N_("Value")}, {-1, 0, ""}};
-static void node_shader_exec_math(void *UNUSED(data),
- int UNUSED(thread),
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float a, b, r = 0.0f;
-
- nodestack_get_vec(&a, SOCK_FLOAT, in[0]);
- nodestack_get_vec(&b, SOCK_FLOAT, in[1]);
-
- switch (node->custom1) {
-
- case NODE_MATH_ADD:
- r = a + b;
- break;
- case NODE_MATH_SUB:
- r = a - b;
- break;
- case NODE_MATH_MUL:
- r = a * b;
- break;
- case NODE_MATH_DIVIDE: {
- if (b == 0) { /* We don't want to divide by zero. */
- r = 0.0;
- }
- else {
- r = a / b;
- }
- break;
- }
- case NODE_MATH_SIN: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- r = sinf(a);
- }
- else {
- r = sinf(b);
- }
- break;
- }
- case NODE_MATH_COS: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- r = cosf(a);
- }
- else {
- r = cosf(b);
- }
- break;
- }
- case NODE_MATH_TAN: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- r = tanf(a);
- }
- else {
- r = tanf(b);
- }
- break;
- }
- case NODE_MATH_ASIN: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- /* Can't do the impossible... */
- if (a <= 1 && a >= -1) {
- r = asinf(a);
- }
- else {
- r = 0.0;
- }
- }
- else {
- /* Can't do the impossible... */
- if (b <= 1 && b >= -1) {
- r = asinf(b);
- }
- else {
- r = 0.0;
- }
- }
- break;
- }
- case NODE_MATH_ACOS: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- /* Can't do the impossible... */
- if (a <= 1 && a >= -1) {
- r = acosf(a);
- }
- else {
- r = 0.0;
- }
- }
- else {
- /* Can't do the impossible... */
- if (b <= 1 && b >= -1) {
- r = acosf(b);
- }
- else {
- r = 0.0;
- }
- }
- break;
- }
- case NODE_MATH_ATAN: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- r = atan(a);
- }
- else {
- r = atan(b);
- }
- break;
- }
- case NODE_MATH_POW: {
- /* Only raise negative numbers by full integers */
- if (a >= 0) {
- r = pow(a, b);
- }
- else {
- float y_mod_1 = fabsf(fmodf(b, 1.0f));
-
- /* if input value is not nearly an integer,
- * fall back to zero, nicer than straight rounding. */
- if (y_mod_1 > 0.999f || y_mod_1 < 0.001f) {
- r = powf(a, floorf(b + 0.5f));
- }
- else {
- r = 0.0f;
- }
- }
-
- break;
- }
- case NODE_MATH_LOG: {
- /* Don't want any imaginary numbers... */
- if (a > 0 && b > 0) {
- r = log(a) / log(b);
- }
- else {
- r = 0.0;
- }
- break;
- }
- case NODE_MATH_MIN: {
- if (a < b) {
- r = a;
- }
- else {
- r = b;
- }
- break;
- }
- case NODE_MATH_MAX: {
- if (a > b) {
- r = a;
- }
- else {
- r = b;
- }
- break;
- }
- case NODE_MATH_ROUND: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- r = (a < 0) ? (int)(a - 0.5f) : (int)(a + 0.5f);
- }
- else {
- r = (b < 0) ? (int)(b - 0.5f) : (int)(b + 0.5f);
- }
- break;
- }
- case NODE_MATH_LESS: {
- if (a < b) {
- r = 1.0f;
- }
- else {
- r = 0.0f;
- }
- break;
- }
- case NODE_MATH_GREATER: {
- if (a > b) {
- r = 1.0f;
- }
- else {
- r = 0.0f;
- }
- break;
- }
- case NODE_MATH_MOD: {
- if (b == 0.0f) {
- r = 0.0f;
- }
- else {
- r = fmod(a, b);
- }
- break;
- }
- case NODE_MATH_ABS: {
- r = fabsf(a);
- break;
- }
- case NODE_MATH_ATAN2: {
- r = atan2(a, b);
- break;
- }
- case NODE_MATH_FLOOR: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- r = floorf(a);
- }
- else {
- r = floorf(b);
- }
- break;
- }
- case NODE_MATH_CEIL: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- r = ceilf(a);
- }
- else {
- r = ceilf(b);
- }
- break;
- }
- case NODE_MATH_FRACT: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- r = a - floorf(a);
- }
- else {
- r = b - floorf(b);
- }
- break;
- }
- case NODE_MATH_SQRT: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- if (a > 0) {
- r = sqrt(a);
- }
- else {
- r = 0.0;
- }
- }
- else {
- if (b > 0) {
- r = sqrt(b);
- }
- else {
- r = 0.0;
- }
- }
- break;
- }
- }
- if (node->custom2 & SHD_MATH_CLAMP) {
- CLAMP(r, 0.0f, 1.0f);
- }
- out[0]->vec[0] = r;
-}
-
static int gpu_shader_math(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
@@ -304,68 +38,65 @@ static int gpu_shader_math(GPUMaterial *mat,
GPUNodeStack *out)
{
static const char *names[] = {
- "math_add", "math_subtract", "math_multiply", "math_divide", "math_sine",
- "math_cosine", "math_tangent", "math_asin", "math_acos", "math_atan",
- "math_pow", "math_log", "math_min", "math_max", "math_round",
- "math_less_than", "math_greater_than", "math_modulo", "math_abs", "math_atan2",
- "math_floor", "math_ceil", "math_fract", "math_sqrt",
+ [NODE_MATH_ADD] = "math_add",
+ [NODE_MATH_SUBTRACT] = "math_subtract",
+ [NODE_MATH_MULTIPLY] = "math_multiply",
+ [NODE_MATH_DIVIDE] = "math_divide",
+
+ [NODE_MATH_POWER] = "math_power",
+ [NODE_MATH_LOGARITHM] = "math_logarithm",
+ [NODE_MATH_SQRT] = "math_sqrt",
+ [NODE_MATH_ABSOLUTE] = "math_absolute",
+
+ [NODE_MATH_MINIMUM] = "math_minimum",
+ [NODE_MATH_MAXIMUM] = "math_maximum",
+ [NODE_MATH_LESS_THAN] = "math_less_than",
+ [NODE_MATH_GREATER_THAN] = "math_greater_than",
+
+ [NODE_MATH_ROUND] = "math_round",
+ [NODE_MATH_FLOOR] = "math_floor",
+ [NODE_MATH_CEIL] = "math_ceil",
+ [NODE_MATH_FRACTION] = "math_fraction",
+ [NODE_MATH_MODULO] = "math_modulo",
+
+ [NODE_MATH_SINE] = "math_sine",
+ [NODE_MATH_COSINE] = "math_cosine",
+ [NODE_MATH_TANGENT] = "math_tangent",
+ [NODE_MATH_ARCSINE] = "math_arcsine",
+ [NODE_MATH_ARCCOSINE] = "math_arccosine",
+ [NODE_MATH_ARCTANGENT] = "math_arctangent",
+ [NODE_MATH_ARCTAN2] = "math_arctan2",
};
- switch (node->custom1) {
- case NODE_MATH_ADD:
- case NODE_MATH_SUB:
- case NODE_MATH_MUL:
- case NODE_MATH_DIVIDE:
- case NODE_MATH_POW:
- case NODE_MATH_LOG:
- case NODE_MATH_MIN:
- case NODE_MATH_MAX:
- case NODE_MATH_LESS:
- case NODE_MATH_GREATER:
- case NODE_MATH_MOD:
- case NODE_MATH_ATAN2:
- GPU_stack_link(mat, node, names[node->custom1], in, out);
- break;
- case NODE_MATH_SIN:
- case NODE_MATH_COS:
- case NODE_MATH_TAN:
- case NODE_MATH_ASIN:
- case NODE_MATH_ACOS:
- case NODE_MATH_ATAN:
- case NODE_MATH_ROUND:
- case NODE_MATH_ABS:
- case NODE_MATH_FLOOR:
- case NODE_MATH_FRACT:
- case NODE_MATH_CEIL:
- case NODE_MATH_SQRT:
- if (in[0].hasinput || !in[1].hasinput) {
- /* use only first item and terminator */
- GPUNodeStack tmp_in[2];
- memcpy(&tmp_in[0], &in[0], sizeof(GPUNodeStack));
- memcpy(&tmp_in[1], &in[2], sizeof(GPUNodeStack));
- GPU_stack_link(mat, node, names[node->custom1], tmp_in, out);
- }
- else {
- /* use only second item and terminator */
- GPUNodeStack tmp_in[2];
- memcpy(&tmp_in[0], &in[1], sizeof(GPUNodeStack));
- memcpy(&tmp_in[1], &in[2], sizeof(GPUNodeStack));
- GPU_stack_link(mat, node, names[node->custom1], tmp_in, out);
- }
- break;
- default:
- return 0;
- }
+ GPU_stack_link(mat, node, names[node->custom1], in, out);
if (node->custom2 & SHD_MATH_CLAMP) {
float min[3] = {0.0f, 0.0f, 0.0f};
float max[3] = {1.0f, 1.0f, 1.0f};
- GPU_link(mat, "clamp_val", out[0].link, GPU_constant(min), GPU_constant(max), &out[0].link);
+ GPU_link(mat, "clamp_value", out[0].link, GPU_constant(min), GPU_constant(max), &out[0].link);
}
-
return 1;
}
+static void node_shader_update_math(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sock = BLI_findlink(&node->inputs, 1);
+ nodeSetSocketAvailability(sock,
+ !ELEM(node->custom1,
+ NODE_MATH_SQRT,
+ NODE_MATH_CEIL,
+ NODE_MATH_SINE,
+ NODE_MATH_ROUND,
+ NODE_MATH_FLOOR,
+ NODE_MATH_COSINE,
+ NODE_MATH_ARCSINE,
+ NODE_MATH_TANGENT,
+ NODE_MATH_ABSOLUTE,
+ NODE_MATH_FRACTION,
+ NODE_MATH_ARCCOSINE,
+ NODE_MATH_ARCTANGENT));
+}
+
void register_node_type_sh_math(void)
{
static bNodeType ntype;
@@ -373,9 +104,8 @@ void register_node_type_sh_math(void)
sh_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_math_in, sh_node_math_out);
node_type_label(&ntype, node_math_label);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_math);
node_type_gpu(&ntype, gpu_shader_math);
+ node_type_update(&ntype, node_shader_update_math);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal.c b/source/blender/nodes/shader/nodes/node_shader_normal.c
index 074cc3dd87f..9dd89258446 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal.c
@@ -25,7 +25,7 @@
/* **************** NORMAL ******************** */
static bNodeSocketTemplate sh_node_normal_in[] = {
- {SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_DIRECTION},
+ {SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_DIRECTION},
{-1, 0, ""},
};
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 f1b4a0e9fe3..9a0a132b311 100644
--- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
+++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
@@ -24,7 +24,7 @@
static bNodeSocketTemplate sh_node_subsurface_scattering_in[] = {
{SOCK_RGBA, 1, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
{SOCK_FLOAT, 1, N_("Scale"), 1.0, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_VECTOR, 1, N_("Radius"), 1.0f, 0.2f, 0.1f, 0.0f, 0.0f, 100.0f},
+ {SOCK_VECTOR, 1, N_("Radius"), 1.0f, 0.2f, 0.1f, 0.0f, 0.0f, 100.0f, PROP_NONE, SOCK_COMPACT},
{SOCK_FLOAT, 1, N_("Sharpness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{SOCK_FLOAT, 1, N_("Texture Blur"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{SOCK_VECTOR,
@@ -63,7 +63,7 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat,
GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS);
- if (node->sss_id == 1) {
+ if (node->sss_id > 0) {
bNodeSocket *socket = BLI_findlink(&node->original->inputs, 2);
bNodeSocketValueRGBA *socket_data = socket->default_value;
bNodeSocket *socket_sharp = BLI_findlink(&node->original->inputs, 3);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tangent.c b/source/blender/nodes/shader/nodes/node_shader_tangent.c
index 6795f48edb3..478b9524737 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tangent.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tangent.c
@@ -42,7 +42,8 @@ static int node_shader_gpu_tangent(GPUMaterial *mat,
NodeShaderTangent *attr = node->storage;
if (attr->direction_type == SHD_TANGENT_UVMAP) {
- return GPU_stack_link(mat, node, "node_tangentmap", in, out, GPU_attribute(CD_TANGENT, ""));
+ return GPU_stack_link(
+ mat, node, "node_tangentmap", in, out, GPU_attribute(CD_TANGENT, attr->uv_map));
}
else {
GPUNodeLink *orco = GPU_attribute(CD_ORCO, "");
diff --git a/source/blender/nodes/texture/nodes/node_texture_math.c b/source/blender/nodes/texture/nodes/node_texture_math.c
index 2eb32e0addc..b1d67a5a953 100644
--- a/source/blender/nodes/texture/nodes/node_texture_math.c
+++ b/source/blender/nodes/texture/nodes/node_texture_math.c
@@ -46,10 +46,10 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
case NODE_MATH_ADD:
*out = in0 + in1;
break;
- case NODE_MATH_SUB:
+ case NODE_MATH_SUBTRACT:
*out = in0 - in1;
break;
- case NODE_MATH_MUL:
+ case NODE_MATH_MULTIPLY:
*out = in0 * in1;
break;
case NODE_MATH_DIVIDE: {
@@ -62,19 +62,19 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
}
break;
}
- case NODE_MATH_SIN: {
+ case NODE_MATH_SINE: {
*out = sinf(in0);
break;
}
- case NODE_MATH_COS: {
+ case NODE_MATH_COSINE: {
*out = cosf(in0);
break;
}
- case NODE_MATH_TAN: {
+ case NODE_MATH_TANGENT: {
*out = tanf(in0);
break;
}
- case NODE_MATH_ASIN: {
+ case NODE_MATH_ARCSINE: {
/* Can't do the impossible... */
if (in0 <= 1 && in0 >= -1) {
*out = asinf(in0);
@@ -84,7 +84,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
}
break;
}
- case NODE_MATH_ACOS: {
+ case NODE_MATH_ARCCOSINE: {
/* Can't do the impossible... */
if (in0 <= 1 && in0 >= -1) {
*out = acosf(in0);
@@ -94,11 +94,11 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
}
break;
}
- case NODE_MATH_ATAN: {
+ case NODE_MATH_ARCTANGENT: {
*out = atan(in0);
break;
}
- case NODE_MATH_POW: {
+ case NODE_MATH_POWER: {
/* Only raise negative numbers by full integers */
if (in0 >= 0) {
out[0] = pow(in0, in1);
@@ -114,7 +114,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
}
break;
}
- case NODE_MATH_LOG: {
+ case NODE_MATH_LOGARITHM: {
/* Don't want any imaginary numbers... */
if (in0 > 0 && in1 > 0) {
*out = log(in0) / log(in1);
@@ -124,7 +124,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
}
break;
}
- case NODE_MATH_MIN: {
+ case NODE_MATH_MINIMUM: {
if (in0 < in1) {
*out = in0;
}
@@ -133,7 +133,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
}
break;
}
- case NODE_MATH_MAX: {
+ case NODE_MATH_MAXIMUM: {
if (in0 > in1) {
*out = in0;
}
@@ -147,7 +147,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
break;
}
- case NODE_MATH_LESS: {
+ case NODE_MATH_LESS_THAN: {
if (in0 < in1) {
*out = 1.0f;
}
@@ -157,7 +157,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
break;
}
- case NODE_MATH_GREATER: {
+ case NODE_MATH_GREATER_THAN: {
if (in0 > in1) {
*out = 1.0f;
}
@@ -167,7 +167,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
break;
}
- case NODE_MATH_MOD: {
+ case NODE_MATH_MODULO: {
if (in1 == 0.0f) {
*out = 0.0f;
}
@@ -177,12 +177,12 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
break;
}
- case NODE_MATH_ABS: {
+ case NODE_MATH_ABSOLUTE: {
*out = fabsf(in0);
break;
}
- case NODE_MATH_ATAN2: {
+ case NODE_MATH_ARCTAN2: {
*out = atan2(in0, in1);
break;
}
@@ -197,7 +197,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
break;
}
- case NODE_MATH_FRACT: {
+ case NODE_MATH_FRACTION: {
*out = in0 - floorf(in0);
break;
}
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index 95c16c2f033..07cb3370eec 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -393,7 +393,7 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s)
if (s->type & CLOTH_SPRING_TYPE_SEWING) {
/* TODO: verify, half verified (couldn't see error)
* sewing springs usually have a large distance at first so clamp the force so we don't get
- * tunnelling through collision objects. */
+ * tunneling through collision objects. */
BPH_mass_spring_force_spring_linear(data,
s->ij,
s->kl,
diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c
index 93df51ce58d..c2eb7b465e1 100644
--- a/source/blender/physics/intern/implicit_blender.c
+++ b/source/blender/physics/intern/implicit_blender.c
@@ -1158,12 +1158,9 @@ bool BPH_mass_spring_solve_velocities(Implicit_Data *data, float dt, ImplicitSol
double start = PIL_check_seconds_timer();
# endif
- cg_filtered(data->dV,
- data->A,
- data->B,
- data->z,
- data->S,
- result); /* conjugate gradient algorithm to solve Ax=b */
+ /* Conjugate gradient algorithm to solve Ax=b. */
+ cg_filtered(data->dV, data->A, data->B, data->z, data->S, result);
+
// cg_filtered_pre(id->dV, id->A, id->B, id->z, id->S, id->P, id->Pinv, id->bigI);
# ifdef DEBUG_TIME
diff --git a/source/blender/python/bmesh/bmesh_py_types.h b/source/blender/python/bmesh/bmesh_py_types.h
index 460e7f82222..c61fdeab4b0 100644
--- a/source/blender/python/bmesh/bmesh_py_types.h
+++ b/source/blender/python/bmesh/bmesh_py_types.h
@@ -140,8 +140,8 @@ PyObject *BPy_BMFaceSeq_CreatePyObject(BMesh *bm);
PyObject *BPy_BMLoopSeq_CreatePyObject(BMesh *bm);
PyObject *BPy_BMIter_CreatePyObject(BMesh *bm);
-PyObject *BPy_BMElem_CreatePyObject(BMesh *bm,
- BMHeader *ele); /* just checks type and creates v/e/f/l */
+/* Just checks type and creates v/e/f/l. */
+PyObject *BPy_BMElem_CreatePyObject(BMesh *bm, BMHeader *ele);
void *BPy_BMElem_PySeq_As_Array_FAST(BMesh **r_bm,
PyObject *seq_fast,
diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c
index 56c25edb7e4..a7f4e30b494 100644
--- a/source/blender/python/bmesh/bmesh_py_types_customdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c
@@ -516,8 +516,10 @@ static PyObject *bpy_bmlayercollection_keys(BPy_BMLayerCollection *self)
BPY_BM_CHECK_OBJ(self);
data = bpy_bm_customdata_get(self->bm, self->htype);
- index = CustomData_get_layer_index(data,
- self->type); /* absolute, but no need to make relative */
+
+ /* Absolute, but no need to make relative. */
+ index = CustomData_get_layer_index(data, self->type);
+
tot = (index != -1) ? CustomData_number_of_layers(data, self->type) : 0;
ret = PyList_New(tot);
diff --git a/source/blender/python/bmesh/bmesh_py_types_meshdata.c b/source/blender/python/bmesh/bmesh_py_types_meshdata.c
index 0aa01ddb594..2e15c1d9ce0 100644
--- a/source/blender/python/bmesh/bmesh_py_types_meshdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.c
@@ -20,8 +20,8 @@
/** \file
* \ingroup pybmesh
*
- * This file defines customdata types which can't be accessed as primitive
- * python types such as MDeformVert, MLoopUV, MTexPoly
+ * This file defines custom-data types which can't be accessed as primitive
+ * python types such as #MDeformVert, #MLoopUV.
*/
#include <Python.h>
@@ -515,8 +515,8 @@ static PySequenceMethods bpy_bmdeformvert_as_sequence = {
NULL, /* sq_concat */
NULL, /* sq_repeat */
- /* note: if this is set PySequence_Check() returns True,
- * but in this case we dont want to be treated as a seq */
+ /* Note: if this is set #PySequence_Check() returns True,
+ * but in this case we don't want to be treated as a seq. */
NULL, /* sq_item */
NULL, /* sq_slice */
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index 30cad991b55..d10d281c1f9 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -1428,8 +1428,9 @@ static int BPy_IDArray_ass_slice(BPy_IDArray *self, int begin, int end, PyObject
size = (end - begin);
alloc_len = size * elem_size;
- vec = MEM_mallocN(alloc_len,
- "array assignment"); /* NOTE: we count on int/float being the same size here */
+ /* NOTE: we count on int/float being the same size here */
+ vec = MEM_mallocN(alloc_len, "array assignment");
+
if (PyC_AsArray(vec, seq, size, py_type, is_double, "slice assignment: ") == -1) {
MEM_freeN(vec);
return -1;
diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c
index a48cd742448..3c1dbfba72e 100644
--- a/source/blender/python/intern/bpy_app_translations.c
+++ b/source/blender/python/intern/bpy_app_translations.c
@@ -890,7 +890,7 @@ PyObject *BPY_app_translations_struct(void)
void BPY_app_translations_end(void)
{
- /* Incase the object remains in a module's namespace, see T44127. */
+ /* In case the object remains in a module's name-space, see T44127. */
#ifdef WITH_INTERNATIONAL
_clear_translations_cache();
#endif
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index aef4ab6667a..5e3b000c604 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -252,8 +252,9 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
ReportList *reports;
reports = MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
- BKE_reports_init(reports,
- RPT_STORE | RPT_OP_HOLD); /* own so these don't move into global reports */
+
+ /* Own so these don't move into global reports. */
+ BKE_reports_init(reports, RPT_STORE | RPT_OP_HOLD);
#ifdef BPY_RELEASE_GIL
/* release GIL, since a thread could be started from an operator
diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c
index 8f2f08c7c37..2e88a2a5b06 100644
--- a/source/blender/python/intern/bpy_operator_wrap.c
+++ b/source/blender/python/intern/bpy_operator_wrap.c
@@ -58,7 +58,7 @@ static void operator_properties_init(wmOperatorType *ot)
/* set the default property: ot->prop */
{
/* Picky developers will notice that 'bl_property' won't work with inheritance
- * get direct from the dict to avoid raising a load of attribute errors (yes this isnt ideal)
+ * get direct from the dict to avoid raising a load of attribute errors (yes this isn't ideal)
* - campbell. */
PyObject *py_class_dict = py_class->tp_dict;
PyObject *bl_property = PyDict_GetItem(py_class_dict, bpy_intern_str_bl_property);
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 70bfa76e344..9e734123caa 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -2931,8 +2931,8 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
prop = RNA_def_property(srna, id, PROP_STRING, subtype);
if (maxlen != 0) {
- RNA_def_property_string_maxlength(prop,
- maxlen + 1); /* +1 since it includes null terminator */
+ /* +1 since it includes null terminator. */
+ RNA_def_property_string_maxlength(prop, maxlen + 1);
}
if (def && def[0]) {
RNA_def_property_string_default(prop, def);
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 9a8d8c5ec21..e7fed02fe79 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -8557,9 +8557,10 @@ static PyObject *pyrna_register_class(PyObject *UNUSED(self), PyObject *py_class
}
if (PyDict_GetItem(((PyTypeObject *)py_class)->tp_dict, bpy_intern_str_bl_rna)) {
- PyErr_SetString(PyExc_ValueError,
- "register_class(...): "
- "already registered as a subclass");
+ PyErr_Format(PyExc_ValueError,
+ "register_class(...): "
+ "already registered as a subclass '%.200s'",
+ ((PyTypeObject *)py_class)->tp_name);
return NULL;
}
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index fb9454bf108..7a3499d0295 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -455,8 +455,8 @@ PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyOb
NlaStrip *strip = (NlaStrip *)ptr.data;
FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index);
- BLI_assert(fcu !=
- NULL); /* NOTE: This should be true, or else we wouldn't be able to get here */
+ /* NOTE: This should be true, or else we wouldn't be able to get here. */
+ BLI_assert(fcu != NULL);
if (BKE_fcurve_is_protected(fcu)) {
BKE_reportf(
diff --git a/source/blender/python/intern/bpy_rna_array.c b/source/blender/python/intern/bpy_rna_array.c
index 9d8fff5dfe4..a8312d89ef8 100644
--- a/source/blender/python/intern/bpy_rna_array.c
+++ b/source/blender/python/intern/bpy_rna_array.c
@@ -554,8 +554,9 @@ static int py_to_array(PyObject *seq,
/* not freeing allocated mem, RNA_parameter_list_free() will do this */
ParameterDynAlloc *param_alloc = (ParameterDynAlloc *)param_data;
param_alloc->array_tot = (int)totitem;
- param_alloc->array = MEM_callocN(item_size * totitem,
- "py_to_array dyn"); /* freeing param list will free */
+
+ /* freeing param list will free */
+ param_alloc->array = MEM_callocN(item_size * totitem, "py_to_array dyn");
data = param_alloc->array;
}
diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c
index befa6532e97..2b1ddbbb03a 100644
--- a/source/blender/python/mathutils/mathutils.c
+++ b/source/blender/python/mathutils/mathutils.c
@@ -25,6 +25,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "../generic/py_capi_utils.h"
#include "../generic/python_utildefines.h"
#ifndef MATH_STANDALONE
@@ -328,6 +329,153 @@ int mathutils_array_parse_alloc_v(float **array,
return size;
}
+/* Parse an sequence array_dim integers into array. */
+int mathutils_int_array_parse(int *array, int array_dim, PyObject *value, const char *error_prefix)
+{
+ int size, i;
+ PyObject *value_fast, **value_fast_items, *item;
+
+ if (!(value_fast = PySequence_Fast(value, error_prefix))) {
+ /* PySequence_Fast sets the error */
+ return -1;
+ }
+
+ if ((size = PySequence_Fast_GET_SIZE(value_fast)) != array_dim) {
+ PyErr_Format(PyExc_ValueError,
+ "%.200s: sequence size is %d, expected %d",
+ error_prefix,
+ size,
+ array_dim);
+ Py_DECREF(value_fast);
+ return -1;
+ }
+
+ value_fast_items = PySequence_Fast_ITEMS(value_fast);
+ i = size;
+ while (i > 0) {
+ i--;
+ if (((array[i] = PyC_Long_AsI32((item = value_fast_items[i]))) == -1) && PyErr_Occurred()) {
+ PyErr_Format(PyExc_TypeError, "%.200s: sequence index %d expected an int", error_prefix, i);
+ size = -1;
+ break;
+ }
+ }
+ Py_DECREF(value_fast);
+
+ return size;
+}
+
+/* Parse sequence of array_dim sequences of integers and return allocated result. */
+int mathutils_array_parse_alloc_vi(int **array,
+ int array_dim,
+ PyObject *value,
+ const char *error_prefix)
+{
+ PyObject *value_fast;
+ int i, size;
+
+ if (!(value_fast = PySequence_Fast(value, error_prefix))) {
+ /* PySequence_Fast sets the error */
+ return -1;
+ }
+
+ size = PySequence_Fast_GET_SIZE(value_fast);
+
+ if (size != 0) {
+ PyObject **value_fast_items = PySequence_Fast_ITEMS(value_fast);
+ int *ip;
+
+ ip = *array = PyMem_Malloc(size * array_dim * sizeof(int));
+
+ for (i = 0; i < size; i++, ip += array_dim) {
+ PyObject *item = value_fast_items[i];
+
+ if (mathutils_int_array_parse(ip, array_dim, item, error_prefix) == -1) {
+ PyMem_Free(*array);
+ *array = NULL;
+ size = -1;
+ break;
+ }
+ }
+ }
+
+ Py_DECREF(value_fast);
+ return size;
+}
+
+/* Parse sequence of variable-length sequences of int and return allocated
+ * triple of arrays to represent the result:
+ * The flattened sequences are put into *array.
+ * The start index of each sequence goes into start_table.
+ * The length of each index goes into len_table.
+ */
+int mathutils_array_parse_alloc_viseq(
+ int **array, int **start_table, int **len_table, PyObject *value, const char *error_prefix)
+{
+ PyObject *value_fast, *subseq;
+ int i, size, start, subseq_len;
+ int *ip;
+
+ *array = NULL;
+ *start_table = NULL;
+ *len_table = NULL;
+ if (!(value_fast = PySequence_Fast(value, error_prefix))) {
+ /* PySequence_Fast sets the error */
+ return -1;
+ }
+
+ size = PySequence_Fast_GET_SIZE(value_fast);
+
+ if (size != 0) {
+ PyObject **value_fast_items = PySequence_Fast_ITEMS(value_fast);
+
+ *start_table = PyMem_Malloc(size * sizeof(int));
+ *len_table = PyMem_Malloc(size * sizeof(int));
+
+ /* First pass to set starts and len, and calculate size of array needed */
+ start = 0;
+ for (i = 0; i < size; i++) {
+ subseq = value_fast_items[i];
+ if ((subseq_len = (int)PySequence_Size(subseq)) == -1) {
+ PyErr_Format(
+ PyExc_ValueError, "%.200s: sequence expected to have subsequences", error_prefix);
+ PyMem_Free(*start_table);
+ PyMem_Free(*len_table);
+ Py_DECREF(value_fast);
+ *start_table = NULL;
+ *len_table = NULL;
+ return -1;
+ }
+ (*start_table)[i] = start;
+ (*len_table)[i] = subseq_len;
+ start += subseq_len;
+ }
+
+ ip = *array = PyMem_Malloc(start * sizeof(int));
+
+ /* Second pass to parse the subsequences into array */
+ for (i = 0; i < size; i++) {
+ subseq = value_fast_items[i];
+ subseq_len = (*len_table)[i];
+
+ if (mathutils_int_array_parse(ip, subseq_len, subseq, error_prefix) == -1) {
+ PyMem_Free(*array);
+ PyMem_Free(*start_table);
+ PyMem_Free(*len_table);
+ *array = NULL;
+ *len_table = NULL;
+ *start_table = NULL;
+ size = -1;
+ break;
+ }
+ ip += subseq_len;
+ }
+ }
+
+ Py_DECREF(value_fast);
+ return size;
+}
+
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix)
{
if (EulerObject_Check(value)) {
diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h
index 8afd60a7324..70bd3a64481 100644
--- a/source/blender/python/mathutils/mathutils.h
+++ b/source/blender/python/mathutils/mathutils.h
@@ -96,16 +96,16 @@ int EXPP_VectorsAreEqual(const float *vecA, const float *vecB, int size, int flo
typedef struct Mathutils_Callback Mathutils_Callback;
-typedef int (*BaseMathCheckFunc)(BaseMathObject *); /* checks the user is still valid */
-typedef int (*BaseMathGetFunc)(BaseMathObject *, int); /* gets the vector from the user */
-typedef int (*BaseMathSetFunc)(BaseMathObject *,
- int); /* sets the users vector values once its modified */
-typedef int (*BaseMathGetIndexFunc)(BaseMathObject *,
- int,
- int); /* same as above but only for an index */
-typedef int (*BaseMathSetIndexFunc)(BaseMathObject *,
- int,
- int); /* same as above but only for an index */
+/** Checks the user is still valid. */
+typedef int (*BaseMathCheckFunc)(BaseMathObject *);
+/** Gets the vector from the user. */
+typedef int (*BaseMathGetFunc)(BaseMathObject *, int);
+/** Sets the users vector values once its modified. */
+typedef int (*BaseMathSetFunc)(BaseMathObject *, int);
+/** Same as above but only for an index. */
+typedef int (*BaseMathGetIndexFunc)(BaseMathObject *, int, int);
+/** Same as above but only for an index. */
+typedef int (*BaseMathSetIndexFunc)(BaseMathObject *, int, int);
struct Mathutils_Callback {
BaseMathCheckFunc check;
@@ -167,6 +167,16 @@ int mathutils_array_parse_alloc_v(float **array,
int array_dim,
PyObject *value,
const char *error_prefix);
+int mathutils_int_array_parse(int *array,
+ int array_dim,
+ PyObject *value,
+ const char *error_prefix);
+int mathutils_array_parse_alloc_vi(int **array,
+ int array_dim,
+ PyObject *value,
+ const char *error_prefix);
+int mathutils_array_parse_alloc_viseq(
+ int **array, int **start_table, int **len_table, PyObject *value, const char *error_prefix);
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix);
Py_hash_t mathutils_array_hash(const float *float_array, size_t array_len);
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
index 23fd65319a6..267971408bf 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.c
+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
@@ -1015,7 +1015,7 @@ static PyObject *Quaternion_matmul(PyObject *q1, PyObject *q2)
return NULL;
}
/*------------------------obj @= obj------------------------------
- * inplace quaternion multiplication */
+ * in-place quaternion multiplication */
static PyObject *Quaternion_imatmul(PyObject *q1, PyObject *q2)
{
float quat[QUAT_SIZE];
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index 490a1d9dd76..aa7cbadde14 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -786,10 +786,8 @@ static PyObject *Vector_to_track_quat(VectorObject *self, PyObject *args)
return NULL;
}
- /*
- * flip vector around, since vectoquat expect a vector from target to tracking object
- * and the python function expects the inverse (a vector to the target).
- */
+ /* Flip vector around, since #vec_to_quat expect a vector from target to tracking object
+ * and the python function expects the inverse (a vector to the target). */
negate_v3_v3(vec, self->vec);
vec_to_quat(quat, vec, track, up);
diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c
index d4f56490627..13d36e5af91 100644
--- a/source/blender/python/mathutils/mathutils_geometry.c
+++ b/source/blender/python/mathutils/mathutils_geometry.c
@@ -29,6 +29,7 @@
# include "BLI_blenlib.h"
# include "BLI_boxpack_2d.h"
# include "BLI_convexhull_2d.h"
+# include "BLI_delaunay_2d.h"
# include "BKE_displist.h"
# include "BKE_curve.h"
#endif
@@ -283,6 +284,42 @@ static PyObject *M_Geometry_intersect_sphere_sphere_2d(PyObject *UNUSED(self), P
return ret;
}
+PyDoc_STRVAR(M_Geometry_intersect_tri_tri_2d_doc,
+ ".. function:: intersect_tri_tri_2d(tri_a1, tri_a2, tri_a3, tri_b1, tri_b2, tri_b3)\n"
+ "\n"
+ " Check if two 2D triangles intersect.\n"
+ "\n"
+ " :rtype: bool\n");
+static PyObject *M_Geometry_intersect_tri_tri_2d(PyObject *UNUSED(self), PyObject *args)
+{
+ const char *error_prefix = "intersect_tri_tri_2d";
+ PyObject *tri_pair_py[2][3];
+ float tri_pair[2][3][2];
+
+ if (!PyArg_ParseTuple(args,
+ "OOOOOO:intersect_tri_tri_2d",
+ &tri_pair_py[0][0],
+ &tri_pair_py[0][1],
+ &tri_pair_py[0][2],
+ &tri_pair_py[1][0],
+ &tri_pair_py[1][1],
+ &tri_pair_py[1][2])) {
+ return NULL;
+ }
+
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 3; j++) {
+ if (mathutils_array_parse(
+ tri_pair[i][j], 2, 2 | MU_ARRAY_SPILL, tri_pair_py[i][j], error_prefix) == -1) {
+ return NULL;
+ }
+ }
+ }
+
+ bool ret = isect_tri_tri_v2(UNPACK3(tri_pair[0]), UNPACK3(tri_pair[1]));
+ return PyBool_FromLong(ret);
+}
+
PyDoc_STRVAR(M_Geometry_normal_doc,
".. function:: normal(vectors)\n"
"\n"
@@ -1176,7 +1213,7 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject
PyObject *polyLine, *polyVec;
int i, len_polylines, len_polypoints, ls_error = 0;
- /* display listbase */
+ /* Display #ListBase. */
ListBase dispbase = {NULL, NULL};
DispList *dl;
float *fp; /*pointer to the array of malloced dl->verts to set the points from the vectors */
@@ -1262,7 +1299,7 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject
BKE_displist_fill(&dispbase, &dispbase, NULL, false);
/* The faces are stored in a new DisplayList
- * that's added to the head of the listbase */
+ * that's added to the head of the #ListBase. */
dl = dispbase.first;
tri_list = PyList_New(dl->parts);
@@ -1471,6 +1508,186 @@ static PyObject *M_Geometry_convex_hull_2d(PyObject *UNUSED(self), PyObject *poi
return ret;
}
+/* Return a PyObject that is a list of lists, using the flattened list array
+ * to fill values, with start_table and len_table giving the start index
+ * and length of the toplevel_len sub-lists.
+ */
+static PyObject *list_of_lists_from_arrays(int *array,
+ int *start_table,
+ int *len_table,
+ int toplevel_len)
+{
+ PyObject *ret, *sublist;
+ int i, j, sublist_len, sublist_start, val;
+
+ ret = PyList_New(toplevel_len);
+ for (i = 0; i < toplevel_len; i++) {
+ sublist_len = len_table[i];
+ sublist = PyList_New(sublist_len);
+ sublist_start = start_table[i];
+ for (j = 0; j < sublist_len; j++) {
+ val = array[sublist_start + j];
+ PyList_SET_ITEM(sublist, j, PyLong_FromLong(val));
+ }
+ PyList_SET_ITEM(ret, i, sublist);
+ }
+ return ret;
+}
+
+PyDoc_STRVAR(
+ M_Geometry_delaunay_2d_cdt_doc,
+ ".. function:: delaunay_2d_cdt(vert_coords, edges, faces, output_type, epsilon)\n"
+ "\n"
+ "Computes the Constrained Delaunay Triangulation of a set of vertices, "
+ "with edges and faces that must appear in the triangulation. "
+ "Some triangles may be eaten away, or combined with other triangles, "
+ "according to output type. "
+ "The returned verts may be in a different order from input verts, may be moved "
+ "slightly, and may be merged with other nearby verts. "
+ "The three returned orig lists give, for each of verts, edges, and faces, the list of "
+ "input element indices corresponding to the positionally same output element. "
+ "For edges, the orig indices start with the input edges and then continue "
+ "with the edges implied by each of the faces (n of them for an n-gon).\n"
+ "\n"
+ " :arg vert_coords: Vertex coordinates (2d)\n"
+ " :type vert_coords: list of :class:`mathutils.Vector`\n"
+ " :arg edges: Edges, as pairs of indices in `vert_coords`\n"
+ " :type edges: list of (int, int)\n"
+ " :arg faces: Faces, each sublist is a face, as indices in `vert_coords` (CCW oriented)\n"
+ " :type faces: list of list of int\n"
+ " :arg output_type: What output looks like. 0 => triangles with convex hull. "
+ "1 => triangles inside constraints. "
+ "2 => the input constraints, intersected. "
+ "3 => like 2 but with extra edges to make valid BMesh faces.\n"
+ " :type output_type: int\\n"
+ " :arg epsilon: For nearness tests; should not be zero\n"
+ " :type epsilon: float\n"
+ " :return: Output tuple, (vert_coords, edges, faces, orig_verts, orig_edges, orig_faces)\n"
+ " :rtype: (list of `mathutils.Vector`, "
+ "list of (int, int), "
+ "list of list of int, "
+ "list of list of int, "
+ "list of list of int, "
+ "list of list of int)\n"
+ "\n");
+static PyObject *M_Geometry_delaunay_2d_cdt(PyObject *UNUSED(self), PyObject *args)
+{
+ const char *error_prefix = "delaunay_2d_cdt";
+ PyObject *vert_coords, *edges, *faces, *item;
+ int output_type;
+ float epsilon;
+ float(*in_coords)[2] = NULL;
+ int(*in_edges)[2] = NULL;
+ int *in_faces = NULL;
+ int *in_faces_start_table = NULL;
+ int *in_faces_len_table = NULL;
+ Py_ssize_t vert_coords_len, edges_len, faces_len;
+ CDT_input in;
+ CDT_result *res = NULL;
+ PyObject *out_vert_coords = NULL;
+ PyObject *out_edges = NULL;
+ PyObject *out_faces = NULL;
+ PyObject *out_orig_verts = NULL;
+ PyObject *out_orig_edges = NULL;
+ PyObject *out_orig_faces = NULL;
+ PyObject *ret_value = NULL;
+ int i;
+
+ if (!PyArg_ParseTuple(
+ args, "OOOif:delaunay_2d_cdt", &vert_coords, &edges, &faces, &output_type, &epsilon)) {
+ return NULL;
+ }
+
+ vert_coords_len = mathutils_array_parse_alloc_v(
+ (float **)&in_coords, 2, vert_coords, error_prefix);
+ if (vert_coords_len == -1) {
+ return NULL;
+ }
+
+ edges_len = mathutils_array_parse_alloc_vi((int **)&in_edges, 2, edges, error_prefix);
+ if (edges_len == -1) {
+ goto exit_cdt;
+ }
+
+ faces_len = mathutils_array_parse_alloc_viseq(
+ &in_faces, &in_faces_start_table, &in_faces_len_table, faces, error_prefix);
+ if (faces_len == -1) {
+ goto exit_cdt;
+ }
+
+ in.verts_len = (int)vert_coords_len;
+ in.vert_coords = in_coords;
+ in.edges_len = edges_len;
+ in.faces_len = faces_len;
+ in.edges = in_edges;
+ in.faces = in_faces;
+ in.faces_start_table = in_faces_start_table;
+ in.faces_len_table = in_faces_len_table;
+ in.epsilon = epsilon;
+
+ res = BLI_delaunay_2d_cdt_calc(&in, output_type);
+
+ ret_value = PyTuple_New(6);
+
+ out_vert_coords = PyList_New(res->verts_len);
+ for (i = 0; i < res->verts_len; i++) {
+ item = Vector_CreatePyObject(res->vert_coords[i], 2, NULL);
+ if (item == NULL) {
+ Py_DECREF(ret_value);
+ Py_DECREF(out_vert_coords);
+ goto exit_cdt;
+ }
+ PyList_SET_ITEM(out_vert_coords, i, item);
+ }
+ PyTuple_SET_ITEM(ret_value, 0, out_vert_coords);
+
+ out_edges = PyList_New(res->edges_len);
+ for (i = 0; i < res->edges_len; i++) {
+ item = PyTuple_New(2);
+ PyTuple_SET_ITEM(item, 0, PyLong_FromLong((long)res->edges[i][0]));
+ PyTuple_SET_ITEM(item, 1, PyLong_FromLong((long)res->edges[i][1]));
+ PyList_SET_ITEM(out_edges, i, item);
+ }
+ PyTuple_SET_ITEM(ret_value, 1, out_edges);
+
+ out_faces = list_of_lists_from_arrays(
+ res->faces, res->faces_start_table, res->faces_len_table, res->faces_len);
+ PyTuple_SET_ITEM(ret_value, 2, out_faces);
+
+ out_orig_verts = list_of_lists_from_arrays(
+ res->verts_orig, res->verts_orig_start_table, res->verts_orig_len_table, res->verts_len);
+ PyTuple_SET_ITEM(ret_value, 3, out_orig_verts);
+
+ out_orig_edges = list_of_lists_from_arrays(
+ res->edges_orig, res->edges_orig_start_table, res->edges_orig_len_table, res->edges_len);
+ PyTuple_SET_ITEM(ret_value, 4, out_orig_edges);
+
+ out_orig_faces = list_of_lists_from_arrays(
+ res->faces_orig, res->faces_orig_start_table, res->faces_orig_len_table, res->faces_len);
+ PyTuple_SET_ITEM(ret_value, 5, out_orig_faces);
+
+exit_cdt:
+ if (in_coords != NULL) {
+ PyMem_Free(in_coords);
+ }
+ if (in_edges != NULL) {
+ PyMem_Free(in_edges);
+ }
+ if (in_faces != NULL) {
+ PyMem_Free(in_faces);
+ }
+ if (in_faces_start_table != NULL) {
+ PyMem_Free(in_faces_start_table);
+ }
+ if (in_faces_len_table != NULL) {
+ PyMem_Free(in_faces_len_table);
+ }
+ if (res) {
+ BLI_delaunay_2d_cdt_free(res);
+ }
+ return ret_value;
+}
+
#endif /* MATH_STANDALONE */
static PyMethodDef M_Geometry_methods[] = {
@@ -1526,6 +1743,10 @@ static PyMethodDef M_Geometry_methods[] = {
(PyCFunction)M_Geometry_intersect_sphere_sphere_2d,
METH_VARARGS,
M_Geometry_intersect_sphere_sphere_2d_doc},
+ {"intersect_tri_tri_2d",
+ (PyCFunction)M_Geometry_intersect_tri_tri_2d,
+ METH_VARARGS,
+ M_Geometry_intersect_tri_tri_2d_doc},
{"area_tri", (PyCFunction)M_Geometry_area_tri, METH_VARARGS, M_Geometry_area_tri_doc},
{"volume_tetrahedron",
(PyCFunction)M_Geometry_volume_tetrahedron,
@@ -1553,6 +1774,10 @@ static PyMethodDef M_Geometry_methods[] = {
(PyCFunction)M_Geometry_convex_hull_2d,
METH_O,
M_Geometry_convex_hull_2d_doc},
+ {"delaunay_2d_cdt",
+ (PyCFunction)M_Geometry_delaunay_2d_cdt,
+ METH_VARARGS,
+ M_Geometry_delaunay_2d_cdt_doc},
{"box_fit_2d", (PyCFunction)M_Geometry_box_fit_2d, METH_O, M_Geometry_box_fit_2d_doc},
{"box_pack_2d", (PyCFunction)M_Geometry_box_pack_2d, METH_O, M_Geometry_box_pack_2d_doc},
#endif
diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h
index 93b85b6b96a..01a9e1a538b 100644
--- a/source/blender/render/extern/include/RE_pipeline.h
+++ b/source/blender/render/extern/include/RE_pipeline.h
@@ -256,7 +256,7 @@ void RE_SetView(struct Render *re, float mat[4][4]);
/* get current view and window transform */
void RE_GetViewPlane(struct Render *re, rctf *r_viewplane, rcti *r_disprect);
-/* set the render threads based on the commandline and autothreads setting */
+/* set the render threads based on the command-line and autothreads setting */
void RE_init_threadcount(Render *re);
bool RE_WriteRenderViewsImage(struct ReportList *reports,
diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c
index e9175d8d024..9672184cec8 100644
--- a/source/blender/render/intern/source/imagetexture.c
+++ b/source/blender/render/intern/source/imagetexture.c
@@ -267,7 +267,7 @@ int imagewrap(Tex *tex,
if (texres->nor) {
if (tex->imaflag & TEX_NORMALMAP) {
- /* qdn: normal from color
+ /* Normal from color:
* The invert of the red channel is to make
* the normal map compliant with the outside world.
* It needs to be done because in Blender
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index d620cd38b76..b4d0c2147f2 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -1680,7 +1680,6 @@ static void do_render_all_options(Render *re)
{
Object *camera;
bool render_seq = false;
- int cfra = re->r.cfra;
re->current_scene_update(re->suh, re->scene);
@@ -1692,16 +1691,6 @@ static void do_render_all_options(Render *re)
BKE_image_all_free_anim_ibufs(re->main, re->r.cfra);
BKE_sequencer_all_free_anim_ibufs(re->scene, re->r.cfra);
- /* Update for sequencer and compositing animation.
- * TODO: ideally we would create a depsgraph with a copy of the scene
- * like the render engine, but sequencer and compositing do not (yet?)
- * work with copy-on-write. */
- BKE_animsys_evaluate_all_animation(re->main, NULL, re->scene, (float)cfra);
-
- /* Update for masks
- * (these do not use animsys but own lighter weight structure to define animation). */
- BKE_mask_evaluate_all_masks(re->main, (float)cfra, true);
-
if (RE_engine_render(re, 1)) {
/* in this case external render overrides all */
}
@@ -2003,8 +1992,8 @@ static int render_initialize_from_main(Render *re,
winx = (rd->size * rd->xsch) / 100;
winy = (rd->size * rd->ysch) / 100;
- /* We always render smaller part, inserting it in larger image is compositor bizz,
- * it uses disprect for it. */
+ /* We always render smaller part, inserting it in larger image is compositor business,
+ * it uses 'disprect' for it. */
if (scene->r.mode & R_BORDER) {
disprect.xmin = rd->border.xmin * winx;
disprect.xmax = rd->border.xmax * winx;
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 64f506f03a8..ddd0ddb46da 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -69,6 +69,7 @@ set(SRC
intern/wm_operators.c
intern/wm_panel_type.c
intern/wm_playanim.c
+ intern/wm_splash_screen.c
intern/wm_stereo.c
intern/wm_subwindow.c
intern/wm_toolsystem.c
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index a479ab62b88..6ff2f11226a 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -162,6 +162,7 @@ enum {
WM_WINDOW_RENDER = 1,
WM_WINDOW_USERPREFS,
WM_WINDOW_DRIVERS,
+ WM_WINDOW_INFO,
WM_WINDOW_FILESEL,
};
@@ -420,11 +421,14 @@ int WM_operator_call_py(struct bContext *C,
struct ReportList *reports,
const bool is_undo);
+/* Used for keymap and macro items. */
void WM_operator_properties_alloc(struct PointerRNA **ptr,
struct IDProperty **properties,
- const char *opstring); /* used for keymap and macro items */
-void WM_operator_properties_sanitize(
- struct PointerRNA *ptr, const bool no_context); /* make props context sensitive or not */
+ const char *opstring);
+
+/* Make props context sensitive or not. */
+void WM_operator_properties_sanitize(struct PointerRNA *ptr, const bool no_context);
+
bool WM_operator_properties_default(struct PointerRNA *ptr, const bool do_update);
void WM_operator_properties_reset(struct wmOperator *op);
void WM_operator_properties_create(struct PointerRNA *ptr, const char *opstring);
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 4e9604545ca..93df9acf6b1 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -1406,8 +1406,10 @@ static int wm_operator_invoke(bContext *C,
if (WM_operator_poll(C, ot)) {
wmWindowManager *wm = CTX_wm_manager(C);
- wmOperator *op = wm_operator_create(
- wm, ot, properties, reports); /* if reports == NULL, they'll be initialized */
+
+ /* if reports == NULL, they'll be initialized */
+ wmOperator *op = wm_operator_create(wm, ot, properties, reports);
+
const bool is_nested_call = (wm->op_undo_depth != 0);
if (event != NULL) {
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index eeec78729ea..68ea38287e4 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -1351,7 +1351,7 @@ static bool wm_file_write(bContext *C, const char *filepath, int fileflags, Repo
}
}
- /* Call pre-save callbacks befores writing preview,
+ /* 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);
@@ -1804,7 +1804,9 @@ static void wm_userpref_update_when_changed(bContext *C,
BPY_execute_string(C, (const char *[]){"addon_utils", NULL}, "addon_utils.reset_all()");
#endif
+ WM_reinit_gizmomap_all(bmain);
WM_keyconfig_reload(C);
+
userdef_curr->runtime.is_dirty = is_dirty;
}
@@ -1959,6 +1961,10 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op)
if (use_userdef) {
wm_userpref_read_exceptions(&U, &U_backup);
SET_FLAG_FROM_TEST(G.f, use_factory_settings, G_FLAG_USERPREF_NO_SAVE_ON_EXIT);
+
+ if (use_factory_settings) {
+ U.runtime.is_dirty = true;
+ }
}
return OPERATOR_FINISHED;
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index f2db68ec6b8..058348ca4b9 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -512,8 +512,9 @@ void WM_operator_properties_checker_interval_from_op(struct wmOperator *op,
op_params->nth = nth;
op_params->skip = skip;
- op_params->offset = mod_i(offset,
- nth + skip); /* so input of offset zero ends up being (nth - 1) */
+
+ /* So input of offset zero ends up being (nth - 1). */
+ op_params->offset = mod_i(offset, nth + skip);
}
bool WM_operator_properties_checker_interval_test(const struct CheckerIntervalParams *op_params,
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index c984191076c..75d262f48a0 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -46,7 +46,6 @@
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
-#include "DNA_workspace_types.h"
#include "BLT_translation.h"
@@ -58,10 +57,6 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BLO_readfile.h"
-
-#include "BKE_appdir.h"
-#include "BKE_blender_version.h"
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -87,7 +82,6 @@
#include "GPU_state.h"
#include "IMB_imbuf_types.h"
-#include "IMB_imbuf.h"
#include "ED_numinput.h"
#include "ED_screen.h"
@@ -107,14 +101,17 @@
#include "wm.h"
#include "wm_draw.h"
-#include "wm_event_system.h"
#include "wm_event_types.h"
#include "wm_files.h"
#include "wm_window.h"
#define UNDOCUMENTED_OPERATOR_TIP N_("(undocumented operator)")
-/* ************ operator API, exported ********** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator API
+ * \{ */
/* SOME_OT_op -> some.op */
void WM_operator_py_idname(char *to, const char *from)
@@ -695,7 +692,11 @@ void WM_operator_properties_free(PointerRNA *ptr)
}
}
-/* ************ default op callbacks, exported *********** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Default Operator Callbacks
+ * \{ */
void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op)
{
@@ -1395,7 +1396,13 @@ int WM_operator_redo_popup(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-/* ***************** Debug menu ************************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Debug Menu Operator
+ *
+ * Set internal debug value, mainly for developers.
+ * \{ */
static int wm_debug_menu_exec(bContext *C, wmOperator *op)
{
@@ -1425,7 +1432,12 @@ static void WM_OT_debug_menu(wmOperatorType *ot)
RNA_def_int(ot->srna, "debug_value", 0, SHRT_MIN, SHRT_MAX, "Debug Value", "", -10000, 10000);
}
-/* ***************** Operator defaults ************************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reset Defaults Operator
+ * \{ */
+
static int wm_operator_defaults_exec(bContext *C, wmOperator *op)
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "active_operator", &RNA_Operator);
@@ -1451,260 +1463,11 @@ static void WM_OT_operator_defaults(wmOperatorType *ot)
ot->flag = OPTYPE_INTERNAL;
}
-/* ***************** Splash Screen ************************* */
-
-static void wm_block_splash_close(bContext *C, void *arg_block, void *UNUSED(arg))
-{
- wmWindow *win = CTX_wm_window(C);
- UI_popup_block_close(C, win, arg_block);
-}
-
-static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *arg_unused);
-
-static void wm_block_splash_refreshmenu(bContext *C, void *UNUSED(arg_block), void *UNUSED(arg))
-{
- ARegion *ar_menu = CTX_wm_menu(C);
- ED_region_tag_refresh_ui(ar_menu);
-}
-
-static void wm_block_splash_add_label(uiBlock *block, const char *label, int x, int *y)
-{
- if (!(label && label[0])) {
- return;
- }
-
- uiStyle *style = UI_style_get();
-
- BLF_size(style->widgetlabel.uifont_id, style->widgetlabel.points, U.pixelsize * U.dpi);
- int label_width = BLF_width(style->widgetlabel.uifont_id, label, strlen(label));
- label_width = label_width + U.widget_unit;
-
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
-
- uiBut *but = uiDefBut(block,
- UI_BTYPE_LABEL,
- 0,
- label,
- x - label_width,
- *y,
- label_width,
- UI_UNIT_Y,
- NULL,
- 0,
- 0,
- 0,
- 0,
- NULL);
-
- /* 1 = UI_SELECT, internal flag to draw in white. */
- UI_but_flag_enable(but, 1);
- UI_block_emboss_set(block, UI_EMBOSS);
- *y -= 12 * U.dpi_fac;
-}
-
-static void wm_block_splash_add_labels(uiBlock *block, int x, int y)
-{
- /* Version number. */
- const char *version_suffix = NULL;
- bool show_build_info = true;
-
- if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "alpha")) {
- version_suffix = " Alpha";
- }
- else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "beta")) {
- version_suffix = " Beta";
- }
- else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "rc")) {
- version_suffix = " Release Candidate";
- show_build_info = false;
- }
- else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) {
- version_suffix = STRINGIFY(BLENDER_VERSION_CHAR);
- show_build_info = false;
- }
-
- char version_buf[256] = "\0";
- BLI_snprintf(version_buf,
- sizeof(version_buf),
- "v %d.%d%s",
- BLENDER_VERSION / 100,
- BLENDER_VERSION % 100,
- version_suffix);
-
- wm_block_splash_add_label(block, version_buf, x, &y);
-
-#ifdef WITH_BUILDINFO
- if (show_build_info) {
- extern unsigned long build_commit_timestamp;
- extern char build_hash[], build_commit_date[], build_commit_time[], build_branch[];
-
- /* Date, hidden for builds made from tag. */
- if (build_commit_timestamp != 0) {
- char date_buf[256] = "\0";
- BLI_snprintf(
- date_buf, sizeof(date_buf), "Date: %s %s", build_commit_date, build_commit_time);
- wm_block_splash_add_label(block, date_buf, x, &y);
- }
-
- /* Hash. */
- char hash_buf[256] = "\0";
- BLI_snprintf(hash_buf, sizeof(hash_buf), "Hash: %s", build_hash);
- wm_block_splash_add_label(block, hash_buf, x, &y);
-
- /* Branch. */
- if (!STREQ(build_branch, "master")) {
- char branch_buf[256] = "\0";
- BLI_snprintf(branch_buf, sizeof(branch_buf), "Branch: %s", build_branch);
-
- wm_block_splash_add_label(block, branch_buf, x, &y);
- }
- }
-#else
- UNUSED_VARS(show_build_info);
-#endif /* WITH_BUILDINFO */
-}
-
-static ImBuf *wm_block_splash_image(void)
-{
-#ifndef WITH_HEADLESS
- extern char datatoc_splash_png[];
- extern int datatoc_splash_png_size;
- extern char datatoc_splash_2x_png[];
- extern int datatoc_splash_2x_png_size;
-
- ImBuf *ibuf = NULL;
-
- if (U.dpi_fac > 1.0) {
- ibuf = IMB_ibImageFromMemory((const uchar *)datatoc_splash_2x_png,
- datatoc_splash_2x_png_size,
- IB_rect,
- NULL,
- "<splash screen>");
- }
- else {
- ibuf = IMB_ibImageFromMemory((const uchar *)datatoc_splash_png,
- datatoc_splash_png_size,
- IB_rect,
- NULL,
- "<splash screen>");
- }
-
- /* overwrite splash with template image */
- if (U.app_template[0] != '\0') {
- ImBuf *ibuf_template = NULL;
- char splash_filepath[FILE_MAX];
- char template_directory[FILE_MAX];
-
- if (BKE_appdir_app_template_id_search(
- U.app_template, template_directory, sizeof(template_directory))) {
- BLI_join_dirfile(splash_filepath,
- sizeof(splash_filepath),
- template_directory,
- (U.dpi_fac > 1.0) ? "splash_2x.png" : "splash.png");
- ibuf_template = IMB_loadiffname(splash_filepath, IB_rect, NULL);
- if (ibuf_template) {
- const int x_expect = ibuf->x;
- const int y_expect = 250 * (int)U.dpi_fac;
- /* don't cover the header text */
- if (ibuf_template->x == x_expect && ibuf_template->y == y_expect) {
- memcpy(ibuf->rect,
- ibuf_template->rect,
- ibuf_template->x * ibuf_template->y * sizeof(char[4]));
- }
- else {
- CLOG_ERROR(WM_LOG_OPERATORS,
- "Splash expected %dx%d found %dx%d, ignoring: %s\n",
- x_expect,
- y_expect,
- ibuf_template->x,
- ibuf_template->y,
- splash_filepath);
- }
- IMB_freeImBuf(ibuf_template);
- }
- }
- }
- return ibuf;
-#else
- return NULL;
-#endif
-}
-
-static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(arg))
-{
- uiBlock *block;
- uiBut *but;
- uiStyle *style = UI_style_get();
-
- block = UI_block_begin(C, ar, "splash", UI_EMBOSS);
-
- /* note on UI_BLOCK_NO_WIN_CLIP, the window size is not always synchronized
- * with the OS when the splash shows, window clipping in this case gives
- * ugly results and clipping the splash isn't useful anyway, just disable it [#32938] */
- UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_KEEP_OPEN | UI_BLOCK_NO_WIN_CLIP);
- UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
-
- ImBuf *ibuf = wm_block_splash_image();
- but = uiDefBut(block,
- UI_BTYPE_IMAGE,
- 0,
- "",
- 0,
- 0.5f * U.widget_unit,
- U.dpi_fac * 501,
- U.dpi_fac * 250,
- ibuf,
- 0.0,
- 0.0,
- 0,
- 0,
- ""); /* button owns the imbuf now */
- UI_but_func_set(but, wm_block_splash_close, block, NULL);
- UI_block_func_set(block, wm_block_splash_refreshmenu, block, NULL);
-
- int x = U.dpi_fac * 502;
- int y = U.dpi_fac * 237;
-
- wm_block_splash_add_labels(block, x, y);
-
- uiLayout *layout = UI_block_layout(block,
- UI_LAYOUT_VERTICAL,
- UI_LAYOUT_PANEL,
- U.dpi_fac * 26,
- 0,
- U.dpi_fac * 450,
- U.dpi_fac * 110,
- 0,
- style);
-
- MenuType *mt = WM_menutype_find("WM_MT_splash", true);
- if (mt) {
- UI_menutype_draw(C, mt, layout);
- }
-
- UI_block_bounds_set_centered(block, 0);
-
- return block;
-}
-
-static int wm_splash_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
-{
- UI_popup_block_invoke(C, wm_block_create_splash, NULL, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-static void WM_OT_splash(wmOperatorType *ot)
-{
- ot->name = "Splash Screen";
- ot->idname = "WM_OT_splash";
- ot->description = "Open the splash screen with release info";
-
- ot->invoke = wm_splash_invoke;
- ot->poll = WM_operator_winactive;
-}
+/** \} */
-/* ***************** Search menu ************************* */
+/* -------------------------------------------------------------------- */
+/** \name Operator Search Menu
+ * \{ */
struct SearchPopupInit_Data {
int size[2];
@@ -1913,7 +1676,11 @@ static void WM_OT_call_panel(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* ************ window / screen operator definitions ************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Window/Screen Operators
+ * \{ */
/* this poll functions is needed in place of WM_operator_winactive
* while it crashes on full screen */
@@ -2002,7 +1769,11 @@ static void WM_OT_quit_blender(wmOperatorType *ot)
ot->exec = wm_exit_blender_exec;
}
-/* *********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Console Toggle Operator (WIN32 only)
+ * \{ */
#if defined(WIN32)
@@ -2025,12 +1796,16 @@ static void WM_OT_console_toggle(wmOperatorType *ot)
#endif
-/* ************ default paint cursors, draw always around cursor *********** */
-/*
- * - returns handler to free
- * - poll(bContext): returns 1 if draw should happen
- * - draw(bContext): drawing callback for paint cursor
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name default paint cursors, draw always around cursor
+ *
+ * - Returns handler to free.
+ * - `poll(bContext)`: returns 1 if draw should happen.
+ * - `draw(bContext)`: drawing callback for paint cursor.
+ *
+ * \{ */
wmPaintCursor *WM_paint_cursor_activate(wmWindowManager *wm,
short space_type,
@@ -2067,7 +1842,11 @@ bool WM_paint_cursor_end(wmWindowManager *wm, wmPaintCursor *handle)
return false;
}
-/* *********************** radial control ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Radial Control Operator
+ * \{ */
#define WM_RADIAL_CONTROL_DISPLAY_SIZE (200 * UI_DPI_FAC)
#define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE (35 * UI_DPI_FAC)
@@ -3031,7 +2810,13 @@ static void WM_OT_radial_control(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* ************************** timer for testing ***************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Redraw Timer Operator
+ *
+ * Use for simple benchmarks.
+ * \{ */
/* uses no type defines, fully local testing function anyway... ;) */
@@ -3223,7 +3008,13 @@ static void WM_OT_redraw_timer(wmOperatorType *ot)
60.0);
}
-/* ************************** memory statistics for testing ***************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Report Memory Statistics
+ *
+ * Use for testing/debugging.
+ * \{ */
static int memory_statistics_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
{
@@ -3240,7 +3031,13 @@ static void WM_OT_memory_statistics(wmOperatorType *ot)
ot->exec = memory_statistics_exec;
}
-/* *************************** Mat/tex/etc. previews generation ************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Data-Block Preview Generation Operator
+ *
+ * Use for material/texture/light ... etc.
+ * \{ */
typedef struct PreviewsIDEnsureData {
bContext *C;
@@ -3330,7 +3127,11 @@ static void WM_OT_previews_ensure(wmOperatorType *ot)
ot->exec = previews_ensure_exec;
}
-/* *************************** Datablocks previews clear ************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Data-Block Preview Clear Operator
+ * \{ */
/* Only types supporting previews currently. */
static const EnumPropertyItem preview_id_type_items[] = {
@@ -3429,7 +3230,11 @@ static void WM_OT_previews_clear(wmOperatorType *ot)
"Which data-block previews to clear");
}
-/* *************************** Doc from UI ************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Doc from UI Operator
+ * \{ */
static int doc_view_manual_ui_context_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3462,8 +3267,14 @@ static void WM_OT_doc_view_manual_ui_context(wmOperatorType *ot)
ot->exec = doc_view_manual_ui_context_exec;
}
-/* ******************************************************* */
-/* toggle 3D for current window, turning it fullscreen if needed */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Stereo 3D Operator
+ *
+ * Turning it fullscreen if needed.
+ * \{ */
+
static void WM_OT_stereo3d_set(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -3514,6 +3325,12 @@ static void WM_OT_stereo3d_set(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Registration & Keymaps
+ * \{ */
+
void wm_operatortypes_register(void)
{
WM_operatortype_append(WM_OT_window_close);
@@ -3717,10 +3534,16 @@ void wm_window_keymap(wmKeyConfig *keyconf)
WM_keymap_fix_linking();
}
-/**
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Enum Filter Functions
+ *
* Filter functions that can be used with rna_id_itemf() below.
* Should return false if 'id' should be excluded.
- */
+ *
+ * \{ */
+
static bool rna_id_enum_filter_single(ID *id, void *user_data)
{
return (id != user_data);
@@ -3873,3 +3696,5 @@ const EnumPropertyItem *RNA_mask_local_itemf(bContext *C,
return rna_id_itemf(
C, ptr, r_free, C ? (ID *)CTX_data_main(C)->masks.first : NULL, true, NULL, NULL);
}
+
+/** \} */
diff --git a/source/blender/windowmanager/intern/wm_splash_screen.c b/source/blender/windowmanager/intern/wm_splash_screen.c
new file mode 100644
index 00000000000..8629997030f
--- /dev/null
+++ b/source/blender/windowmanager/intern/wm_splash_screen.c
@@ -0,0 +1,314 @@
+/*
+ * 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) 2007 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup wm
+ *
+ * This file contains the splash screen logic (the `WM_OT_splash` operator).
+ *
+ * - Loads the splash image.
+ * - Displaying version information.
+ * - Lists New Files (application templates).
+ * - Lists Recent files.
+ * - Links to web sites.
+ */
+
+#include <string.h>
+
+#include "CLG_log.h"
+
+#include "DNA_ID.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_appdir.h"
+#include "BKE_blender_version.h"
+#include "BKE_context.h"
+#include "BKE_screen.h"
+
+#include "BLF_api.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "wm.h"
+
+static void wm_block_splash_close(bContext *C, void *arg_block, void *UNUSED(arg))
+{
+ wmWindow *win = CTX_wm_window(C);
+ UI_popup_block_close(C, win, arg_block);
+}
+
+static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *arg_unused);
+
+static void wm_block_splash_refreshmenu(bContext *C, void *UNUSED(arg_block), void *UNUSED(arg))
+{
+ ARegion *ar_menu = CTX_wm_menu(C);
+ ED_region_tag_refresh_ui(ar_menu);
+}
+
+static void wm_block_splash_add_label(uiBlock *block, const char *label, int x, int *y)
+{
+ if (!(label && label[0])) {
+ return;
+ }
+
+ uiStyle *style = UI_style_get();
+
+ BLF_size(style->widgetlabel.uifont_id, style->widgetlabel.points, U.pixelsize * U.dpi);
+ int label_width = BLF_width(style->widgetlabel.uifont_id, label, strlen(label));
+ label_width = label_width + U.widget_unit;
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+
+ uiBut *but = uiDefBut(block,
+ UI_BTYPE_LABEL,
+ 0,
+ label,
+ x - label_width,
+ *y,
+ label_width,
+ UI_UNIT_Y,
+ NULL,
+ 0,
+ 0,
+ 0,
+ 0,
+ NULL);
+
+ /* 1 = UI_SELECT, internal flag to draw in white. */
+ UI_but_flag_enable(but, 1);
+ UI_block_emboss_set(block, UI_EMBOSS);
+ *y -= 12 * U.dpi_fac;
+}
+
+static void wm_block_splash_add_labels(uiBlock *block, int x, int y)
+{
+ /* Version number. */
+ const char *version_suffix = NULL;
+ bool show_build_info = true;
+
+ if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "alpha")) {
+ version_suffix = " Alpha";
+ }
+ else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "beta")) {
+ version_suffix = " Beta";
+ }
+ else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "rc")) {
+ version_suffix = " Release Candidate";
+ show_build_info = false;
+ }
+ else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) {
+ version_suffix = STRINGIFY(BLENDER_VERSION_CHAR);
+ show_build_info = false;
+ }
+
+ char version_buf[256] = "\0";
+ BLI_snprintf(version_buf,
+ sizeof(version_buf),
+ "v %d.%d%s",
+ BLENDER_VERSION / 100,
+ BLENDER_VERSION % 100,
+ version_suffix);
+
+ wm_block_splash_add_label(block, version_buf, x, &y);
+
+#ifdef WITH_BUILDINFO
+ if (show_build_info) {
+ extern unsigned long build_commit_timestamp;
+ extern char build_hash[], build_commit_date[], build_commit_time[], build_branch[];
+
+ /* Date, hidden for builds made from tag. */
+ if (build_commit_timestamp != 0) {
+ char date_buf[256] = "\0";
+ BLI_snprintf(
+ date_buf, sizeof(date_buf), "Date: %s %s", build_commit_date, build_commit_time);
+ wm_block_splash_add_label(block, date_buf, x, &y);
+ }
+
+ /* Hash. */
+ char hash_buf[256] = "\0";
+ BLI_snprintf(hash_buf, sizeof(hash_buf), "Hash: %s", build_hash);
+ wm_block_splash_add_label(block, hash_buf, x, &y);
+
+ /* Branch. */
+ if (!STREQ(build_branch, "master")) {
+ char branch_buf[256] = "\0";
+ BLI_snprintf(branch_buf, sizeof(branch_buf), "Branch: %s", build_branch);
+
+ wm_block_splash_add_label(block, branch_buf, x, &y);
+ }
+ }
+#else
+ UNUSED_VARS(show_build_info);
+#endif /* WITH_BUILDINFO */
+}
+
+static ImBuf *wm_block_splash_image(void)
+{
+#ifndef WITH_HEADLESS
+ extern char datatoc_splash_png[];
+ extern int datatoc_splash_png_size;
+ extern char datatoc_splash_2x_png[];
+ extern int datatoc_splash_2x_png_size;
+
+ ImBuf *ibuf = NULL;
+
+ if (U.dpi_fac > 1.0) {
+ ibuf = IMB_ibImageFromMemory((const uchar *)datatoc_splash_2x_png,
+ datatoc_splash_2x_png_size,
+ IB_rect,
+ NULL,
+ "<splash screen>");
+ }
+ else {
+ ibuf = IMB_ibImageFromMemory((const uchar *)datatoc_splash_png,
+ datatoc_splash_png_size,
+ IB_rect,
+ NULL,
+ "<splash screen>");
+ }
+
+ /* overwrite splash with template image */
+ if (U.app_template[0] != '\0') {
+ ImBuf *ibuf_template = NULL;
+ char splash_filepath[FILE_MAX];
+ char template_directory[FILE_MAX];
+
+ if (BKE_appdir_app_template_id_search(
+ U.app_template, template_directory, sizeof(template_directory))) {
+ BLI_join_dirfile(splash_filepath,
+ sizeof(splash_filepath),
+ template_directory,
+ (U.dpi_fac > 1.0) ? "splash_2x.png" : "splash.png");
+ ibuf_template = IMB_loadiffname(splash_filepath, IB_rect, NULL);
+ if (ibuf_template) {
+ const int x_expect = ibuf->x;
+ const int y_expect = 250 * (int)U.dpi_fac;
+ /* don't cover the header text */
+ if (ibuf_template->x == x_expect && ibuf_template->y == y_expect) {
+ memcpy(ibuf->rect,
+ ibuf_template->rect,
+ ibuf_template->x * ibuf_template->y * sizeof(char[4]));
+ }
+ else {
+ CLOG_ERROR(WM_LOG_OPERATORS,
+ "Splash expected %dx%d found %dx%d, ignoring: %s\n",
+ x_expect,
+ y_expect,
+ ibuf_template->x,
+ ibuf_template->y,
+ splash_filepath);
+ }
+ IMB_freeImBuf(ibuf_template);
+ }
+ }
+ }
+ return ibuf;
+#else
+ return NULL;
+#endif
+}
+
+static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(arg))
+{
+ uiBlock *block;
+ uiBut *but;
+ uiStyle *style = UI_style_get();
+
+ block = UI_block_begin(C, ar, "splash", UI_EMBOSS);
+
+ /* note on UI_BLOCK_NO_WIN_CLIP, the window size is not always synchronized
+ * with the OS when the splash shows, window clipping in this case gives
+ * ugly results and clipping the splash isn't useful anyway, just disable it [#32938] */
+ UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_KEEP_OPEN | UI_BLOCK_NO_WIN_CLIP);
+ UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
+
+ ImBuf *ibuf = wm_block_splash_image();
+ but = uiDefBut(block,
+ UI_BTYPE_IMAGE,
+ 0,
+ "",
+ 0,
+ 0.5f * U.widget_unit,
+ U.dpi_fac * 501,
+ U.dpi_fac * 250,
+ /* Button owns the imbuf now. */
+ ibuf,
+ 0.0,
+ 0.0,
+ 0,
+ 0,
+ "");
+ UI_but_func_set(but, wm_block_splash_close, block, NULL);
+ UI_block_func_set(block, wm_block_splash_refreshmenu, block, NULL);
+
+ int x = U.dpi_fac * 502;
+ int y = U.dpi_fac * 237;
+
+ wm_block_splash_add_labels(block, x, y);
+
+ uiLayout *layout = UI_block_layout(block,
+ UI_LAYOUT_VERTICAL,
+ UI_LAYOUT_PANEL,
+ U.dpi_fac * 26,
+ 0,
+ U.dpi_fac * 450,
+ U.dpi_fac * 110,
+ 0,
+ style);
+
+ MenuType *mt = WM_menutype_find("WM_MT_splash", true);
+ if (mt) {
+ UI_menutype_draw(C, mt, layout);
+ }
+
+ UI_block_bounds_set_centered(block, 0);
+
+ return block;
+}
+
+static int wm_splash_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
+{
+ UI_popup_block_invoke(C, wm_block_create_splash, NULL, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void WM_OT_splash(wmOperatorType *ot)
+{
+ ot->name = "Splash Screen";
+ ot->idname = "WM_OT_splash";
+ ot->description = "Open the splash screen with release info";
+
+ ot->invoke = wm_splash_invoke;
+ ot->poll = WM_operator_winactive;
+}
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 4c095e0dca0..00ed203c208 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -482,8 +482,8 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win)
}
/* Informs GHOST of unsaved changes, to set window modified visual indicator (macOS)
- * and to give hint of unsaved changes for a user warning mechanism in case of OS
- * application terminate request (e.g. OS Shortcut Alt+F4, Cmd+Q, (...), or session end). */
+ * and to give hint of unsaved changes for a user warning mechanism in case of OS application
+ * terminate request (e.g. OS Shortcut Alt+F4, Command+Q, (...), or session end). */
GHOST_SetWindowModifiedState(win->ghostwin, (GHOST_TUns8)!wm->file_saved);
}
}
@@ -658,7 +658,7 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm)
BLI_assert(G.background == false);
- /* no commandline prefsize? then we set this.
+ /* No command-line prefsize? then we set this.
* Note that these values will be used only
* when there is no startup.blend yet.
*/
@@ -900,6 +900,9 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
else if (type == WM_WINDOW_FILESEL) {
space_type = SPACE_FILE;
}
+ else if (type == WM_WINDOW_INFO) {
+ ED_area_newspace(C, sa, SPACE_INFO, false);
+ }
else {
BLI_assert(false);
}
@@ -925,6 +928,9 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
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";
}
diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h
index fa375efb469..00d9a8a2fab 100644
--- a/source/blender/windowmanager/wm.h
+++ b/source/blender/windowmanager/wm.h
@@ -78,6 +78,9 @@ void wm_autosave_delete(void);
void wm_autosave_read(bContext *C, struct ReportList *reports);
void wm_autosave_location(char *filepath);
+/* wm_splash_screen.c */
+void WM_OT_splash(wmOperatorType *ot);
+
/* wm_stereo.c */
void wm_stereo3d_draw_interlace(wmWindow *win, struct ARegion *ar);
void wm_stereo3d_draw_anaglyph(wmWindow *win, struct ARegion *ar);
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index e911a591881..f74fd57252d 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -678,13 +678,13 @@ elseif(WIN32)
if(NOT CMAKE_COMPILER_IS_GNUCC)
install(
- FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.dll
+ FILES ${LIBDIR}/python/${_PYTHON_VERSION_NO_DOTS}/bin/python${_PYTHON_VERSION_NO_DOTS}.dll
DESTINATION "."
CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel
)
install(
- FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}_d.dll
+ FILES ${LIBDIR}/python/${_PYTHON_VERSION_NO_DOTS}/bin/python${_PYTHON_VERSION_NO_DOTS}_d.dll
DESTINATION "."
CONFIGURATIONS Debug
)
@@ -696,75 +696,55 @@ elseif(WIN32)
install(DIRECTORY DESTINATION ${TARGETDIR_VER}/python)
install(DIRECTORY DESTINATION ${TARGETDIR_VER}/python/lib)
- # WARNING: its important that 'CMAKE_INSTALL_CONFIG_NAME' is evaluated at build time
- # and _NOT_ configuration time, when modifying the lines below,
- # check it works in both Release & Debug mode.
- #
- # Edit with extreme care! - Campbell
-
- # extract python
install(
- CODE
- "
- message(STATUS \"Extracting Python to: \${CMAKE_INSTALL_PREFIX}/${BLENDER_VERSION}/python\")
- if(\"\${CMAKE_INSTALL_CONFIG_NAME}\" MATCHES \"^([Dd][Ee][Bb][Uu][Gg])$\")
- set(PYTHON_ZIP \"${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_d.tar.gz\")
- else()
- set(PYTHON_ZIP \"${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}.tar.gz\")
- endif()
-
- execute_process(
- COMMAND \${CMAKE_COMMAND} -E make_directory
- \"\${CMAKE_INSTALL_PREFIX}/${BLENDER_VERSION}/python\"
- COMMAND \${CMAKE_COMMAND} -E
- chdir \"\${CMAKE_INSTALL_PREFIX}/${BLENDER_VERSION}/python\"
- \${CMAKE_COMMAND} -E
- tar xzfv \"\${PYTHON_ZIP}\"
- )
- unset(PYTHON_ZIP)
- "
+ DIRECTORY ${LIBDIR}/python/${_PYTHON_VERSION_NO_DOTS}/lib
+ DESTINATION ${BLENDER_VERSION}/python/
+ CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel
+ PATTERN ".svn" EXCLUDE
+ PATTERN "*_d.*" EXCLUDE # * debug libraries *
+ PATTERN "__pycache__" EXCLUDE # * any cache *
+ PATTERN "*.pyc" EXCLUDE # * any cache *
+ PATTERN "*.pyo" EXCLUDE # * any cache *
)
- # release/site-packages
- install(
- DIRECTORY ${LIBDIR}/release/site-packages
- DESTINATION ${BLENDER_VERSION}/python/lib
+ install(
+ DIRECTORY ${LIBDIR}/python/${_PYTHON_VERSION_NO_DOTS}/lib
+ DESTINATION ${BLENDER_VERSION}/python/
+ CONFIGURATIONS Debug
PATTERN ".svn" EXCLUDE
PATTERN "__pycache__" EXCLUDE # * any cache *
PATTERN "*.pyc" EXCLUDE # * any cache *
PATTERN "*.pyo" EXCLUDE # * any cache *)
+
)
- if(WITH_PYTHON_INSTALL_NUMPY)
- set(PYTHON_NUMPY_VERSION 1.15)
- add_custom_command(
- OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages/numpy/__init__.py
- COMMAND ${CMAKE_COMMAND} -E
- tar xzvf "${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_${PYTHON_NUMPY_VERSION}$<$<CONFIG:Debug>:d>.tar.gz"
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages
- )
- add_custom_target(
- python_numpy ALL
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages/numpy/__init__.py
- )
- install(
- DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages/numpy
- DESTINATION ${BLENDER_VERSION}/python/lib/site-packages
- )
- endif()
+ install(
+ DIRECTORY ${LIBDIR}/python/${_PYTHON_VERSION_NO_DOTS}/DLLs
+ DESTINATION ${BLENDER_VERSION}/python
+ CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel
+ PATTERN "*.pdb" EXCLUDE
+ PATTERN "*_d.*" EXCLUDE
+ )
+ install(
+ DIRECTORY ${LIBDIR}/python/${_PYTHON_VERSION_NO_DOTS}/DLLs
+ DESTINATION ${BLENDER_VERSION}/python
+ CONFIGURATIONS Debug
+ )
- # TODO(sergey): For unti we've got better way to deal with python binary
install(
- FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.dll
+ FILES ${LIBDIR}/python/${_PYTHON_VERSION_NO_DOTS}/bin/python${_PYTHON_VERSION_NO_DOTS}.dll
+ ${LIBDIR}/python/${_PYTHON_VERSION_NO_DOTS}/bin/python.exe
DESTINATION ${BLENDER_VERSION}/python/bin
CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel
)
install(
- FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}_d.dll
+ FILES ${LIBDIR}/python/${_PYTHON_VERSION_NO_DOTS}/bin/python${_PYTHON_VERSION_NO_DOTS}_d.dll
+ ${LIBDIR}/python/${_PYTHON_VERSION_NO_DOTS}/bin/python_d.exe
DESTINATION ${BLENDER_VERSION}/python/bin
CONFIGURATIONS Debug
)
+
if(WINDOWS_PYTHON_DEBUG)
install(
FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.pdb
diff --git a/source/creator/creator.c b/source/creator/creator.c
index d6e1d7e7f5f..6fd472d24c5 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -400,8 +400,8 @@ int main(int argc,
/* background render uses this font too */
BKE_vfont_builtin_register(datatoc_bfont_pfb, datatoc_bfont_pfb_size);
- /* Initialize ffmpeg if built in, also needed for bg mode if videos are
- * rendered via ffmpeg */
+ /* Initialize ffmpeg if built in, also needed for background-mode if videos are
+ * rendered via ffmpeg. */
BKE_sound_init_once();
init_def_material();
@@ -442,7 +442,7 @@ int main(int argc,
"this is not intended for typical usage\n\n");
#endif
- CTX_py_init_set(C, 1);
+ CTX_py_init_set(C, true);
WM_keyconfig_init(C);
#ifdef WITH_FREESTYLE