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:
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_attribute_math.hh80
-rw-r--r--source/blender/blenkernel/BKE_curves.hh2
-rw-r--r--source/blender/blenkernel/BKE_global.h4
-rw-r--r--source/blender/blenkernel/BKE_image.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh_remap.h2
-rw-r--r--source/blender/blenkernel/BKE_paint.h4
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h3
-rw-r--r--source/blender/blenkernel/BKE_pbvh_pixels.hh2
-rw-r--r--source/blender/blenkernel/BKE_type_conversions.hh3
-rw-r--r--source/blender/blenkernel/BKE_volume.h5
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc25
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c21
-rw-r--r--source/blender/blenkernel/intern/attribute.c18
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc6
-rw-r--r--source/blender/blenkernel/intern/attribute_access_intern.hh2
-rw-r--r--source/blender/blenkernel/intern/attribute_math.cc51
-rw-r--r--source/blender/blenkernel/intern/brush.c6
-rw-r--r--source/blender/blenkernel/intern/cloth.c2
-rw-r--r--source/blender/blenkernel/intern/curve.cc7
-rw-r--r--source/blender/blenkernel/intern/curve_to_mesh_convert.cc1
-rw-r--r--source/blender/blenkernel/intern/customdata.cc68
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c4
-rw-r--r--source/blender/blenkernel/intern/displist.cc41
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c35
-rw-r--r--source/blender/blenkernel/intern/fluid.c4
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc25
-rw-r--r--source/blender/blenkernel/intern/image.cc27
-rw-r--r--source/blender/blenkernel/intern/material.c6
-rw-r--r--source/blender/blenkernel/intern/mesh.cc18
-rw-r--r--source/blender/blenkernel/intern/mesh_boolean_convert.cc1
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc4
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.cc2
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c8
-rw-r--r--source/blender/blenkernel/intern/mesh_remesh_voxel.cc2
-rw-r--r--source/blender/blenkernel/intern/mesh_tessellate.c4
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.cc2
-rw-r--r--source/blender/blenkernel/intern/modifier.c6
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_apply_base.c2
-rw-r--r--source/blender/blenkernel/intern/object.cc30
-rw-r--r--source/blender/blenkernel/intern/object_update.c2
-rw-r--r--source/blender/blenkernel/intern/paint.c5
-rw-r--r--source/blender/blenkernel/intern/pbvh.c2
-rw-r--r--source/blender/blenkernel/intern/pbvh.cc2
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c2
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h1
-rw-r--r--source/blender/blenkernel/intern/pbvh_pixels.cc26
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c2
-rw-r--r--source/blender/blenkernel/intern/type_conversions.cc89
-rw-r--r--source/blender/blenkernel/intern/volume.cc62
-rw-r--r--source/blender/blenkernel/intern/volume_to_mesh.cc1
-rw-r--r--source/blender/blenlib/BLI_color.hh2
-rw-r--r--source/blender/blenlib/BLI_color_mix.hh1051
-rw-r--r--source/blender/blenlib/BLI_generic_virtual_array.hh16
-rw-r--r--source/blender/blenlib/BLI_math_base.hh5
-rw-r--r--source/blender/blenlib/BLI_math_color.hh19
-rw-r--r--source/blender/blenlib/BLI_math_vec_types.hh8
-rw-r--r--source/blender/blenlib/BLI_virtual_array.hh6
-rw-r--r--source/blender/blenlib/CMakeLists.txt1
-rw-r--r--source/blender/blenlib/intern/fileops.c92
-rw-r--r--source/blender/blenloader/intern/versioning_260.c2
-rw-r--r--source/blender/blenloader/intern/versioning_280.c7
-rw-r--r--source/blender/blenloader/intern/versioning_300.c68
-rw-r--r--source/blender/bmesh/bmesh_class.h69
-rw-r--r--source/blender/bmesh/operators/bmo_join_triangles.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c543
-rw-r--r--source/blender/draw/CMakeLists.txt3
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c3
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.c5
-rw-r--r--source/blender/draw/engines/eevee/eevee_motion_blur.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/eevee_shaders.c4
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders_extra.cc24
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c252
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_vert.glsl10
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_frag.glsl10
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_vert.glsl10
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl89
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl6
-rw-r--r--source/blender/draw/engines/overlay/overlay_extra.c19
-rw-r--r--source/blender/draw/engines/overlay/overlay_private.h1
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh1
-rw-r--r--source/blender/draw/engines/workbench/workbench_data.c1
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.c26
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.h5
-rw-r--r--source/blender/draw/engines/workbench/workbench_render.c4
-rw-r--r--source/blender/draw/engines/workbench/workbench_volume.c19
-rw-r--r--source/blender/draw/intern/DRW_gpu_wrapper.hh3
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curves.cc65
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c22
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c22
-rw-r--r--source/blender/draw/intern/draw_common.h41
-rw-r--r--source/blender/draw/intern/draw_curves.cc325
-rw-r--r--source/blender/draw/intern/draw_curves_private.h75
-rw-r--r--source/blender/draw/intern/draw_fluid.c97
-rw-r--r--source/blender/draw/intern/draw_hair.c97
-rw-r--r--source/blender/draw/intern/draw_hair_private.h11
-rw-r--r--source/blender/draw/intern/draw_manager.c46
-rw-r--r--source/blender/draw/intern/draw_manager.h4
-rw-r--r--source/blender/draw/intern/draw_manager_data.c10
-rw-r--r--source/blender/draw/intern/draw_shader.c24
-rw-r--r--source/blender/draw/intern/draw_shader.h5
-rw-r--r--source/blender/draw/intern/draw_shader_shared.h16
-rw-r--r--source/blender/draw/intern/draw_volume.cc263
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc4
-rw-r--r--source/blender/draw/intern/shaders/common_attribute_lib.glsl12
-rw-r--r--source/blender/draw/intern/shaders/draw_object_infos_info.hh4
-rw-r--r--source/blender/editors/animation/keyframing.c6
-rw-r--r--source/blender/editors/geometry/geometry_attributes.cc24
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c10
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c2
-rw-r--r--source/blender/editors/include/ED_space_api.h2
-rw-r--r--source/blender/editors/interface/interface_templates.c279
-rw-r--r--source/blender/editors/io/io_obj.c2
-rw-r--r--source/blender/editors/mask/mask_select.c10
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c4
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c2
-rw-r--r--source/blender/editors/mesh/mesh_data.c46
-rw-r--r--source/blender/editors/mesh/meshtools.c4
-rw-r--r--source/blender/editors/object/object_add.cc2
-rw-r--r--source/blender/editors/object/object_bake.c67
-rw-r--r--source/blender/editors/object/object_bake_api.c144
-rw-r--r--source/blender/editors/object/object_data_transfer.c6
-rw-r--r--source/blender/editors/object/object_modifier.cc2
-rw-r--r--source/blender/editors/object/object_remesh.cc17
-rw-r--r--source/blender/editors/object/object_transform.cc11
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt2
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_add.cc10
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_comb.cc3
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc3
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc3
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h2
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.cc (renamed from source/blender/editors/sculpt_paint/paint_vertex.c)1992
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_ops.c69
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_utils.c567
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c40
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_color.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h14
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c49
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_image.cc2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c2
-rw-r--r--source/blender/editors/space_nla/nla_draw.c2
-rw-r--r--source/blender/editors/space_node/node_geometry_attribute_search.cc2
-rw-r--r--source/blender/editors/space_node/node_view.cc18
-rw-r--r--source/blender/editors/space_sequencer/sequencer_channels_draw.c3
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c3
-rw-r--r--source/blender/editors/space_sequencer/sequencer_thumbnails.c65
-rw-r--r--source/blender/editors/space_sequencer/sequencer_view.c106
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c25
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc3
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.cc3
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.cc32
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc40
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc15
-rw-r--r--source/blender/editors/space_text/text_format_py.c35
-rw-r--r--source/blender/editors/space_text/text_ops.c20
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_placement.c4
-rw-r--r--source/blender/editors/transform/transform_gizmo_2d.c12
-rw-r--r--source/blender/editors/transform/transform_mode_bend.c2
-rw-r--r--source/blender/editors/transform/transform_snap_object.cc4
-rw-r--r--source/blender/editors/transform/transform_snap_sequencer.c4
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp4
-rw-r--r--source/blender/functions/FN_field.hh2
-rw-r--r--source/blender/functions/intern/cpp_types.cc1
-rw-r--r--source/blender/functions/intern/field.cc1
-rw-r--r--source/blender/functions/intern/multi_function_procedure_executor.cc27
-rw-r--r--source/blender/functions/tests/FN_multi_function_procedure_test.cc30
-rw-r--r--source/blender/geometry/intern/mesh_merge_by_distance.cc4
-rw-r--r--source/blender/geometry/intern/realize_instances.cc2
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c2
-rw-r--r--source/blender/gpu/CMakeLists.txt1
-rw-r--r--source/blender/gpu/GPU_material.h35
-rw-r--r--source/blender/gpu/GPU_shader.h6
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c2
-rw-r--r--source/blender/gpu/intern/gpu_codegen.cc50
-rw-r--r--source/blender/gpu/intern/gpu_material.c10
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c138
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.h9
-rw-r--r--source/blender/gpu/intern/gpu_shader_builtin.c13
-rw-r--r--source/blender/gpu/intern/gpu_shader_create_info.hh4
-rw-r--r--source/blender/gpu/opengl/gl_shader.cc4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl14
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl1
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl1
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl1
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl51
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl8
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_mesh.cc2
-rw-r--r--source/blender/io/alembic/intern/abc_customdata.cc4
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.cc4
-rw-r--r--source/blender/io/collada/GeometryExporter.cpp10
-rw-r--r--source/blender/io/collada/MeshImporter.cpp7
-rw-r--r--source/blender/io/common/intern/string_utils.cc2
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.cc4
-rw-r--r--source/blender/io/usd/tests/usd_tests_common.h2
-rw-r--r--source/blender/makesdna/DNA_brush_enums.h2
-rw-r--r--source/blender/makesdna/DNA_brush_types.h2
-rw-r--r--source/blender/makesdna/DNA_curve_types.h7
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h8
-rw-r--r--source/blender/makesdna/DNA_fluid_defaults.h1
-rw-r--r--source/blender/makesdna/DNA_fluid_types.h5
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h2
-rw-r--r--source/blender/makesdna/DNA_scene_types.h15
-rw-r--r--source/blender/makesdna/DNA_space_types.h4
-rw-r--r--source/blender/makesdna/DNA_volume_defaults.h3
-rw-r--r--source/blender/makesdna/DNA_volume_types.h17
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h2
-rw-r--r--source/blender/makesrna/RNA_enum_items.h2
-rw-r--r--source/blender/makesrna/intern/rna_armature.c2
-rw-r--r--source/blender/makesrna/intern/rna_attribute.c20
-rw-r--r--source/blender/makesrna/intern/rna_brush.c19
-rw-r--r--source/blender/makesrna/intern/rna_cachefile.c14
-rw-r--r--source/blender/makesrna/intern/rna_fluid.c6
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c18
-rw-r--r--source/blender/makesrna/intern/rna_mesh_api.c1
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c16
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c54
-rw-r--r--source/blender/makesrna/intern/rna_particle.c2
-rw-r--r--source/blender/makesrna/intern/rna_pose.c2
-rw-r--r--source/blender/makesrna/intern/rna_rna.c58
-rw-r--r--source/blender/makesrna/intern/rna_scene.c7
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c29
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c3
-rw-r--r--source/blender/makesrna/intern/rna_space.c8
-rw-r--r--source/blender/makesrna/intern/rna_volume.c59
-rw-r--r--source/blender/modifiers/intern/MOD_array.c7
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c2
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.cc2
-rw-r--r--source/blender/modifiers/intern/MOD_build.c2
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c2
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c2
-rw-r--r--source/blender/modifiers/intern/MOD_dynamicpaint.c2
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c1
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c1
-rw-r--r--source/blender/modifiers/intern/MOD_mask.cc1
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc120
-rw-r--r--source/blender/modifiers/intern/MOD_nodes_evaluator.cc6
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c21
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c8
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c1
-rw-r--r--source/blender/modifiers/intern/MOD_remesh.c1
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c9
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c2
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_nonmanifold.c2
-rw-r--r--source/blender/modifiers/intern/MOD_surface.c2
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c2
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc1
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_edge_split.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc1
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc1
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_material.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc11
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc1
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transform.cc1
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_triangulate.cc1
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc1
-rw-r--r--source/blender/nodes/shader/node_shader_tree.cc16
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_attribute.cc25
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.cc6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_info.cc10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_principled.cc29
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_customdata.c12
-rw-r--r--source/blender/python/gpu/gpu_py_batch.c12
-rw-r--r--source/blender/python/gpu/gpu_py_shader.c125
-rw-r--r--source/blender/python/intern/CMakeLists.txt2
-rw-r--r--source/blender/python/intern/bpy_operator.c27
-rw-r--r--source/blender/python/intern/bpy_rna.c46
-rw-r--r--source/blender/python/intern/bpy_rna.h27
-rw-r--r--source/blender/python/intern/bpy_rna_context.c306
-rw-r--r--source/blender/python/intern/bpy_rna_context.h17
-rw-r--r--source/blender/python/intern/bpy_rna_types_capi.c16
-rw-r--r--source/blender/render/RE_bake.h7
-rw-r--r--source/blender/render/RE_texture_margin.h11
-rw-r--r--source/blender/render/intern/bake.c49
-rw-r--r--source/blender/render/intern/multires_bake.c193
-rw-r--r--source/blender/render/intern/texture_margin.cc38
-rw-r--r--source/blender/render/intern/texture_pointdensity.c9
-rw-r--r--source/blender/sequencer/SEQ_channels.h2
-rw-r--r--source/blender/sequencer/SEQ_relations.h5
-rw-r--r--source/blender/sequencer/SEQ_render.h14
-rw-r--r--source/blender/sequencer/SEQ_transform.h16
-rw-r--r--source/blender/sequencer/intern/channels.c16
-rw-r--r--source/blender/sequencer/intern/effects.c11
-rw-r--r--source/blender/sequencer/intern/iterator.c13
-rw-r--r--source/blender/sequencer/intern/render.c41
-rw-r--r--source/blender/sequencer/intern/strip_edit.c3
-rw-r--r--source/blender/sequencer/intern/strip_relations.c7
-rw-r--r--source/blender/sequencer/intern/strip_transform.c18
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h2
-rw-r--r--source/creator/CMakeLists.txt36
m---------source/tools0
297 files changed, 6747 insertions, 3569 deletions
diff --git a/source/blender/blenkernel/BKE_attribute_math.hh b/source/blender/blenkernel/BKE_attribute_math.hh
index 9efa64d1474..4482e13e1cf 100644
--- a/source/blender/blenkernel/BKE_attribute_math.hh
+++ b/source/blender/blenkernel/BKE_attribute_math.hh
@@ -5,6 +5,7 @@
#include "BLI_array.hh"
#include "BLI_color.hh"
#include "BLI_cpp_type.hh"
+#include "BLI_math_color.hh"
#include "BLI_math_vector.h"
#include "BLI_math_vector.hh"
@@ -18,17 +19,23 @@ namespace blender::attribute_math {
template<typename Func>
inline void convert_to_static_type(const CPPType &cpp_type, const Func &func)
{
- cpp_type.to_static_type_tag<float, float2, float3, int, bool, int8_t, ColorGeometry4f>(
- [&](auto type_tag) {
- using T = typename decltype(type_tag)::type;
- if constexpr (std::is_same_v<T, void>) {
- /* It's expected that the given cpp type is one of the supported ones. */
- BLI_assert_unreachable();
- }
- else {
- func(T());
- }
- });
+ cpp_type.to_static_type_tag<float,
+ float2,
+ float3,
+ int,
+ bool,
+ int8_t,
+ ColorGeometry4f,
+ ColorGeometry4b>([&](auto type_tag) {
+ using T = typename decltype(type_tag)::type;
+ if constexpr (std::is_same_v<T, void>) {
+ /* It's expected that the given cpp type is one of the supported ones. */
+ BLI_assert_unreachable();
+ }
+ else {
+ func(T());
+ }
+ });
}
template<typename Func>
@@ -91,6 +98,22 @@ inline ColorGeometry4f mix3(const float3 &weights,
return result;
}
+template<>
+inline ColorGeometry4b mix3(const float3 &weights,
+ const ColorGeometry4b &v0,
+ const ColorGeometry4b &v1,
+ const ColorGeometry4b &v2)
+{
+ const float4 v0_f{&v0.r};
+ const float4 v1_f{&v1.r};
+ const float4 v2_f{&v2.r};
+ const float4 mixed = v0_f * weights[0] + v1_f * weights[1] + v2_f * weights[2];
+ return ColorGeometry4b{static_cast<uint8_t>(mixed[0]),
+ static_cast<uint8_t>(mixed[1]),
+ static_cast<uint8_t>(mixed[2]),
+ static_cast<uint8_t>(mixed[3])};
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -134,9 +157,13 @@ template<> inline float3 mix2(const float factor, const float3 &a, const float3
template<>
inline ColorGeometry4f mix2(const float factor, const ColorGeometry4f &a, const ColorGeometry4f &b)
{
- ColorGeometry4f result;
- interp_v4_v4v4(result, a, b, factor);
- return result;
+ return math::interpolate(a, b, factor);
+}
+
+template<>
+inline ColorGeometry4b mix2(const float factor, const ColorGeometry4b &a, const ColorGeometry4b &b)
+{
+ return math::interpolate(a, b, factor);
}
/** \} */
@@ -278,19 +305,33 @@ class SimpleMixerWithAccumulationType {
}
};
-class ColorGeometryMixer {
+class ColorGeometry4fMixer {
private:
MutableSpan<ColorGeometry4f> buffer_;
ColorGeometry4f default_color_;
Array<float> total_weights_;
public:
- ColorGeometryMixer(MutableSpan<ColorGeometry4f> buffer,
- ColorGeometry4f default_color = ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f));
+ ColorGeometry4fMixer(MutableSpan<ColorGeometry4f> buffer,
+ ColorGeometry4f default_color = ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f));
void mix_in(int64_t index, const ColorGeometry4f &color, float weight = 1.0f);
void finalize();
};
+class ColorGeometry4bMixer {
+ private:
+ MutableSpan<ColorGeometry4b> buffer_;
+ ColorGeometry4b default_color_;
+ Array<float> total_weights_;
+ Array<float4> accumulation_buffer_;
+
+ public:
+ ColorGeometry4bMixer(MutableSpan<ColorGeometry4b> buffer,
+ ColorGeometry4b default_color = ColorGeometry4b(0, 0, 0, 255));
+ void mix_in(int64_t index, const ColorGeometry4b &color, float weight = 1.0f);
+ void finalize();
+};
+
template<typename T> struct DefaultMixerStruct {
/* Use void by default. This can be checked for in `if constexpr` statements. */
using type = void;
@@ -307,7 +348,10 @@ template<> struct DefaultMixerStruct<float3> {
template<> struct DefaultMixerStruct<ColorGeometry4f> {
/* Use a special mixer for colors. ColorGeometry4f can't be added/multiplied, because this is not
* something one should usually do with colors. */
- using type = ColorGeometryMixer;
+ using type = ColorGeometry4fMixer;
+};
+template<> struct DefaultMixerStruct<ColorGeometry4b> {
+ using type = ColorGeometry4bMixer;
};
template<> struct DefaultMixerStruct<int> {
static int double_to_int(const double &value)
diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh
index 282e2a40bd0..6e4d4d560f7 100644
--- a/source/blender/blenkernel/BKE_curves.hh
+++ b/source/blender/blenkernel/BKE_curves.hh
@@ -451,7 +451,7 @@ bool last_cylic_segment_is_vector(Span<int8_t> handle_types_left, Span<int8_t> h
/**
* Return true if the handle types at the index are free (#BEZIER_HANDLE_FREE) or vector
- * (#BEZIER_HANDLE_VECTOR). In these cases, directional continuitity from the previous and next
+ * (#BEZIER_HANDLE_VECTOR). In these cases, directional continuities from the previous and next
* evaluated segments is assumed not to be desired.
*/
bool point_is_sharp(Span<int8_t> handle_types_left, Span<int8_t> handle_types_right, int index);
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 2070584a8a0..06feb07aef2 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -195,8 +195,8 @@ enum {
G_DEBUG_XR = (1 << 19), /* XR/OpenXR messages */
G_DEBUG_XR_TIME = (1 << 20), /* XR/OpenXR timing messages */
- G_DEBUG_GHOST = (1 << 21), /* Debug GHOST module. */
- G_DEBUG_WINTAB = (1 << 22), /* Debug Wintab. */
+ G_DEBUG_GHOST = (1 << 21), /* Debug GHOST module. */
+ G_DEBUG_WINTAB = (1 << 22), /* Debug Wintab. */
};
#define G_DEBUG_ALL \
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index fff3b2a8f89..42d0e66cf49 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -414,6 +414,8 @@ int BKE_image_get_tile_from_pos(struct Image *ima,
const float uv[2],
float r_uv[2],
float r_ofs[2]);
+void BKE_image_get_tile_uv(const struct Image *ima, const int tile_number, float r_uv[2]);
+
/**
* Return the tile_number for the closest UDIM tile.
*/
diff --git a/source/blender/blenkernel/BKE_mesh_remap.h b/source/blender/blenkernel/BKE_mesh_remap.h
index 395fc5c7eba..e2b16a7681d 100644
--- a/source/blender/blenkernel/BKE_mesh_remap.h
+++ b/source/blender/blenkernel/BKE_mesh_remap.h
@@ -178,6 +178,7 @@ void BKE_mesh_remap_calc_verts_from_mesh(int mode,
int numverts_dst,
bool dirty_nors_dst,
struct Mesh *me_src,
+ struct Mesh *me_dst,
MeshPairRemap *r_map);
void BKE_mesh_remap_calc_edges_from_mesh(int mode,
@@ -190,6 +191,7 @@ void BKE_mesh_remap_calc_edges_from_mesh(int mode,
int numedges_dst,
bool dirty_nors_dst,
struct Mesh *me_src,
+ struct Mesh *me_dst,
MeshPairRemap *r_map);
void BKE_mesh_remap_calc_loops_from_mesh(int mode,
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 4ae37095411..f0488e84091 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -615,9 +615,6 @@ typedef struct SculptSession {
union {
struct {
struct SculptVertexPaintGeomMap gmap;
-
- /* For non-airbrush painting to re-apply from the original (MLoop aligned). */
- unsigned int *previous_color;
} vpaint;
struct {
@@ -734,6 +731,7 @@ enum {
};
/* paint_canvas.cc */
+
/**
* Create a key that can be used to compare with previous ones to identify changes.
* The resulting 'string' is owned by the caller.
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index bb918fcfdcb..978e52d8003 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -143,8 +143,7 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
int cd_face_node_offset);
void BKE_pbvh_build_pixels(PBVH *pbvh,
- const struct MLoop *mloop,
- struct CustomData *ldata,
+ struct Mesh *mesh,
struct Image *image,
struct ImageUser *image_user);
void BKE_pbvh_free(PBVH *pbvh);
diff --git a/source/blender/blenkernel/BKE_pbvh_pixels.hh b/source/blender/blenkernel/BKE_pbvh_pixels.hh
index 35eb340d0a1..fdfb5fa037e 100644
--- a/source/blender/blenkernel/BKE_pbvh_pixels.hh
+++ b/source/blender/blenkernel/BKE_pbvh_pixels.hh
@@ -21,7 +21,7 @@ namespace blender::bke::pbvh::pixels {
struct TrianglePaintInput {
int3 vert_indices;
/**
- * Delta barycentric coordinates between 2 neighbouring UV's in the U direction.
+ * Delta barycentric coordinates between 2 neighboring UV's in the U direction.
*
* Only the first two coordinates are stored. The third should be recalculated
*/
diff --git a/source/blender/blenkernel/BKE_type_conversions.hh b/source/blender/blenkernel/BKE_type_conversions.hh
index 5152989d137..1cca172e188 100644
--- a/source/blender/blenkernel/BKE_type_conversions.hh
+++ b/source/blender/blenkernel/BKE_type_conversions.hh
@@ -2,6 +2,7 @@
#pragma once
+#include "FN_field.hh"
#include "FN_multi_function.hh"
namespace blender::bke {
@@ -59,8 +60,8 @@ class DataTypeConversions {
void convert_to_initialized_n(GSpan from_span, GMutableSpan to_span) const;
GVArray try_convert(GVArray varray, const CPPType &to_type) const;
-
GVMutableArray try_convert(GVMutableArray varray, const CPPType &to_type) const;
+ fn::GField try_convert(fn::GField field, const CPPType &to_type) const;
};
const DataTypeConversions &get_implicit_type_conversions();
diff --git a/source/blender/blenkernel/BKE_volume.h b/source/blender/blenkernel/BKE_volume.h
index 77f01e7919d..bc578ef8b28 100644
--- a/source/blender/blenkernel/BKE_volume.h
+++ b/source/blender/blenkernel/BKE_volume.h
@@ -77,6 +77,11 @@ const VolumeGrid *BKE_volume_grid_active_get_for_read(const struct Volume *volum
/* Tries to find a grid with the given name. Make sure that the volume has been loaded. */
const VolumeGrid *BKE_volume_grid_find_for_read(const struct Volume *volume, const char *name);
+/* Tries to set the name of the velocity field. If no such grid exists with the given base name,
+ * this will try common post-fixes in order to detect velocity fields split into multiple grids.
+ * Return false if neither finding with the base name nor with the post-fixes succeeded. */
+bool BKE_volume_set_velocity_grid_by_name(struct Volume *volume, const char *base_name);
+
/* Grid
*
* By default only grid metadata is loaded, for access to the tree and voxels
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index 33f0c331e46..8a0ad4b724b 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -734,7 +734,6 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
const bool use_deform,
const bool need_mapping,
const CustomData_MeshMasks *dataMask,
- const int index,
const bool use_cache,
const bool allow_shared_mesh,
/* return args */
@@ -848,12 +847,6 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
else {
break;
}
-
- /* grab modifiers until index i */
- if ((index != -1) && (BLI_findindex(&ob->modifiers, md) >= index)) {
- md = nullptr;
- break;
- }
}
/* Result of all leading deforming modifiers is cached for
@@ -1129,11 +1122,6 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
isPrevDeform = (mti->type == eModifierTypeType_OnlyDeform);
- /* grab modifiers until index i */
- if ((index != -1) && (BLI_findindex(&ob->modifiers, md) >= index)) {
- break;
- }
-
if (sculpt_mode && md->type == eModifierType_Multires) {
multires_applied = true;
}
@@ -1611,7 +1599,7 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
const CustomData_MeshMasks *dataMask,
const bool need_mapping)
{
-#if 0 /* XXX This is already taken care of in mesh_calc_modifiers()... */
+#if 0 /* XXX This is already taken care of in #mesh_calc_modifiers... */
if (need_mapping) {
/* Also add the flag so that it is recorded in lastDataMask. */
dataMask->vmask |= CD_MASK_ORIGINDEX;
@@ -1628,7 +1616,6 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
true,
need_mapping,
dataMask,
- -1,
true,
true,
&mesh_deform_eval,
@@ -1745,13 +1732,13 @@ static void object_get_datamask(const Depsgraph *depsgraph,
/* check if we need tfaces & mcols due to face select or texture paint */
if ((ob->mode & OB_MODE_TEXTURE_PAINT) || editing) {
- r_mask->lmask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
+ r_mask->lmask |= CD_MASK_MLOOPUV | CD_MASK_PROP_BYTE_COLOR;
r_mask->fmask |= CD_MASK_MTFACE;
}
/* check if we need mcols due to vertex paint or weightpaint */
if (ob->mode & OB_MODE_VERTEX_PAINT) {
- r_mask->lmask |= CD_MASK_MLOOPCOL;
+ r_mask->lmask |= CD_MASK_PROP_BYTE_COLOR;
}
if (ob->mode & OB_MODE_WEIGHT_PAINT) {
@@ -1882,7 +1869,7 @@ Mesh *mesh_create_eval_final(Depsgraph *depsgraph,
{
Mesh *result;
mesh_calc_modifiers(
- depsgraph, scene, ob, true, false, dataMask, -1, false, false, nullptr, &result, nullptr);
+ depsgraph, scene, ob, true, false, dataMask, false, false, nullptr, &result, nullptr);
return result;
}
@@ -1893,7 +1880,7 @@ Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph,
{
Mesh *result;
mesh_calc_modifiers(
- depsgraph, scene, ob, false, false, dataMask, -1, false, false, nullptr, &result, nullptr);
+ depsgraph, scene, ob, false, false, dataMask, false, false, nullptr, &result, nullptr);
return result;
}
@@ -1904,7 +1891,7 @@ Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
{
Mesh *result;
mesh_calc_modifiers(
- depsgraph, scene, ob, false, false, dataMask, -1, false, false, nullptr, &result, nullptr);
+ depsgraph, scene, ob, false, false, dataMask, false, false, nullptr, &result, nullptr);
return result;
}
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 54fee079947..b886722676b 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -1958,11 +1958,12 @@ static void nlaevalchan_assert_blendOrcombine_compatible(NlaEvalChannelSnapshot
BLI_assert(lower_necs->length == blended_necs->length);
}
-/** Check each remap domain of blended values individually in case animator had a non-combine NLA
+/**
+ * Check each remap domain of blended values individually in case animator had a non-combine NLA
* strip with a subset of quaternion channels and remapping through any of them failed and thus
* potentially has undefined values.
*
- * \returns true if case occured and handled. Returns false if case didn't occur.
+ * \returns true if case occurred and handled. Returns false if case didn't occur.
*/
static bool nlaevalchan_combine_quaternion_handle_undefined_blend_values(
NlaEvalChannelSnapshot *blended_necs, NlaEvalChannelSnapshot *upper_or_lower_necs)
@@ -1992,8 +1993,10 @@ static void nlaevalchan_copy_values(NlaEvalChannelSnapshot *dst, NlaEvalChannelS
memcpy(dst->values, src->values, src->length * sizeof(float));
}
-/** Copies from lower necs to blended necs if upper necs is NULL or has zero influence.
- * \return true if copied. */
+/**
+ * Copies from lower necs to blended necs if upper necs is NULL or has zero influence.
+ * \return true if copied.
+ */
static bool nlaevalchan_blendOrcombine_try_copy_from_lower(NlaEvalChannelSnapshot *lower_necs,
NlaEvalChannelSnapshot *upper_necs,
const float upper_influence,
@@ -2008,12 +2011,14 @@ static bool nlaevalchan_blendOrcombine_try_copy_from_lower(NlaEvalChannelSnapsho
return true;
}
-/** Copies to lower necs from blended necs if upper necs is NULL or has zero influence. If
+/**
+ * Copies to lower necs from blended necs if upper necs is NULL or has zero influence. If
* successful, copies blended_necs remap domains to lower_necs.
*
* Does not check upper value blend domains.
*
- * \return true if copied. */
+ * \return true if copied.
+ */
static bool nlaevalchan_blendOrcombine_try_copy_to_lower(NlaEvalChannelSnapshot *blended_necs,
NlaEvalChannelSnapshot *upper_necs,
const float upper_influence,
@@ -2033,7 +2038,8 @@ static bool nlaevalchan_blendOrcombine_try_copy_to_lower(NlaEvalChannelSnapshot
return true;
}
-/** Based on blendmode, blend lower necs with upper necs into blended necs.
+/**
+ * Based on blendmode, blend lower necs with upper necs into blended necs.
*
* Each upper value's blend domain determines whether to blend or to copy directly
* from lower.
@@ -2133,7 +2139,6 @@ static void nlaevalchan_combine_quaternion(NlaEvalChannelSnapshot *lower_necs,
* \param upper_blendmode: Enum value in eNlaStrip_Blend_Mode.
* \param upper_influence: Value in range [0, 1].
* \param upper_necs: Never NULL.
- *
*/
static void nlaevalchan_blendOrcombine(NlaEvalChannelSnapshot *lower_necs,
NlaEvalChannelSnapshot *upper_necs,
diff --git a/source/blender/blenkernel/intern/attribute.c b/source/blender/blenkernel/intern/attribute.c
index 307868ce6d9..0cb0704ff80 100644
--- a/source/blender/blenkernel/intern/attribute.c
+++ b/source/blender/blenkernel/intern/attribute.c
@@ -311,6 +311,20 @@ AttributeDomain BKE_id_attribute_domain(const ID *id, const CustomDataLayer *lay
int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer)
{
+ /* When in mesh editmode, attributes point to bmesh customdata layers, the attribute data is
+ * empty since custom data is stored per element instead of a single array there (same es UVs
+ * etc.), see D11998. */
+ switch (GS(id->name)) {
+ case ID_ME: {
+ Mesh *mesh = (Mesh *)id;
+ if (mesh->edit_mesh != NULL) {
+ return 0;
+ }
+ }
+ default:
+ break;
+ }
+
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
@@ -622,10 +636,10 @@ CustomDataLayer *BKE_id_attributes_color_find(const ID *id, const char *name)
layer = BKE_id_attribute_find(id, name, CD_PROP_COLOR, ATTR_DOMAIN_CORNER);
}
if (layer == NULL) {
- layer = BKE_id_attribute_find(id, name, CD_MLOOPCOL, ATTR_DOMAIN_POINT);
+ layer = BKE_id_attribute_find(id, name, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_POINT);
}
if (layer == NULL) {
- layer = BKE_id_attribute_find(id, name, CD_MLOOPCOL, ATTR_DOMAIN_CORNER);
+ layer = BKE_id_attribute_find(id, name, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_CORNER);
}
return layer;
}
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index 0ae9fa4356b..77c7857a528 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -70,11 +70,11 @@ static int attribute_data_type_complexity(const CustomDataType data_type)
return 4;
case CD_PROP_FLOAT3:
return 5;
- case CD_PROP_COLOR:
+ case CD_PROP_BYTE_COLOR:
return 6;
+ case CD_PROP_COLOR:
+ return 7;
#if 0 /* These attribute types are not supported yet. */
- case CD_MLOOPCOL:
- return 3;
case CD_PROP_STRING:
return 6;
#endif
diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh
index bfc4c8fcde0..8c021ed0e21 100644
--- a/source/blender/blenkernel/intern/attribute_access_intern.hh
+++ b/source/blender/blenkernel/intern/attribute_access_intern.hh
@@ -127,7 +127,7 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
static constexpr uint64_t supported_types_mask = CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 |
CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 |
CD_MASK_PROP_COLOR | CD_MASK_PROP_BOOL |
- CD_MASK_PROP_INT8;
+ CD_MASK_PROP_INT8 | CD_MASK_PROP_BYTE_COLOR;
const AttributeDomain domain_;
const CustomDataAccessInfo custom_data_access_;
diff --git a/source/blender/blenkernel/intern/attribute_math.cc b/source/blender/blenkernel/intern/attribute_math.cc
index df3cab474cd..c38df2a2969 100644
--- a/source/blender/blenkernel/intern/attribute_math.cc
+++ b/source/blender/blenkernel/intern/attribute_math.cc
@@ -4,8 +4,8 @@
namespace blender::attribute_math {
-ColorGeometryMixer::ColorGeometryMixer(MutableSpan<ColorGeometry4f> output_buffer,
- ColorGeometry4f default_color)
+ColorGeometry4fMixer::ColorGeometry4fMixer(MutableSpan<ColorGeometry4f> output_buffer,
+ ColorGeometry4f default_color)
: buffer_(output_buffer),
default_color_(default_color),
total_weights_(output_buffer.size(), 0.0f)
@@ -13,9 +13,9 @@ ColorGeometryMixer::ColorGeometryMixer(MutableSpan<ColorGeometry4f> output_buffe
buffer_.fill(ColorGeometry4f(0.0f, 0.0f, 0.0f, 0.0f));
}
-void ColorGeometryMixer::mix_in(const int64_t index,
- const ColorGeometry4f &color,
- const float weight)
+void ColorGeometry4fMixer::mix_in(const int64_t index,
+ const ColorGeometry4f &color,
+ const float weight)
{
BLI_assert(weight >= 0.0f);
ColorGeometry4f &output_color = buffer_[index];
@@ -26,7 +26,7 @@ void ColorGeometryMixer::mix_in(const int64_t index,
total_weights_[index] += weight;
}
-void ColorGeometryMixer::finalize()
+void ColorGeometry4fMixer::finalize()
{
for (const int64_t i : buffer_.index_range()) {
const float weight = total_weights_[i];
@@ -44,4 +44,43 @@ void ColorGeometryMixer::finalize()
}
}
+ColorGeometry4bMixer::ColorGeometry4bMixer(MutableSpan<ColorGeometry4b> buffer,
+ ColorGeometry4b default_color)
+ : buffer_(buffer),
+ default_color_(default_color),
+ total_weights_(buffer.size(), 0.0f),
+ accumulation_buffer_(buffer.size(), float4(0, 0, 0, 0))
+{
+}
+
+void ColorGeometry4bMixer::mix_in(int64_t index, const ColorGeometry4b &color, float weight)
+{
+ BLI_assert(weight >= 0.0f);
+ float4 &accum_value = accumulation_buffer_[index];
+ accum_value[0] += color.r * weight;
+ accum_value[1] += color.g * weight;
+ accum_value[2] += color.b * weight;
+ accum_value[3] += color.a * weight;
+ total_weights_[index] += weight;
+}
+
+void ColorGeometry4bMixer::finalize()
+{
+ for (const int64_t i : buffer_.index_range()) {
+ const float weight = total_weights_[i];
+ const float4 &accum_value = accumulation_buffer_[i];
+ ColorGeometry4b &output_color = buffer_[i];
+ if (weight > 0.0f) {
+ const float weight_inv = 1.0f / weight;
+ output_color.r = accum_value[0] * weight_inv;
+ output_color.g = accum_value[1] * weight_inv;
+ output_color.b = accum_value[2] * weight_inv;
+ output_color.a = accum_value[3] * weight_inv;
+ }
+ else {
+ output_color = default_color_;
+ }
+ }
+}
+
} // namespace blender::attribute_math
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index b9cd9e1ee59..0593db34e20 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -1557,8 +1557,10 @@ void BKE_brush_init_curves_sculpt_settings(Brush *brush)
if (brush->curves_sculpt_settings == NULL) {
brush->curves_sculpt_settings = MEM_callocN(sizeof(BrushCurvesSculptSettings), __func__);
}
- brush->curves_sculpt_settings->add_amount = 1;
- brush->curves_sculpt_settings->minimum_length = 0.01f;
+ BrushCurvesSculptSettings *settings = brush->curves_sculpt_settings;
+ settings->add_amount = 1;
+ settings->minimum_length = 0.01f;
+ settings->curve_length = 0.3f;
}
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode)
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index f7454a02de6..0d6a0c045a5 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -1171,6 +1171,7 @@ static Mesh *cloth_make_rest_mesh(ClothModifierData *clmd, Mesh *mesh)
for (unsigned i = 0; i < mesh->totvert; i++, verts++) {
copy_v3_v3(mvert[i].co, verts->xrest);
}
+ BKE_mesh_normals_tag_dirty(new_mesh);
return new_mesh;
}
@@ -1507,7 +1508,6 @@ static bool cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
if (clmd->sim_parms->shapekey_rest &&
!(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH)) {
tmp_mesh = cloth_make_rest_mesh(clmd, mesh);
- BKE_mesh_calc_normals(tmp_mesh);
}
EdgeSet *existing_vert_pairs = BLI_edgeset_new("cloth_sewing_edges_graph");
diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc
index bad70d4ccc6..4338883853d 100644
--- a/source/blender/blenkernel/intern/curve.cc
+++ b/source/blender/blenkernel/intern/curve.cc
@@ -113,9 +113,12 @@ static void curve_free_data(ID *id)
BKE_curve_batch_cache_free(curve);
BKE_nurbList_free(&curve->nurb);
- BKE_curve_editfont_free(curve);
- BKE_curve_editNurb_free(curve);
+ if (!curve->edit_data_from_original) {
+ BKE_curve_editfont_free(curve);
+
+ BKE_curve_editNurb_free(curve);
+ }
BKE_curveprofile_free(curve->bevel_profile);
diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
index c48d155f5ce..d7fd8f7a2b6 100644
--- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
+++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
@@ -649,7 +649,6 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
offsets.vert.last(), offsets.edge.last(), 0, offsets.loop.last(), offsets.poly.last());
mesh->flag |= ME_AUTOSMOOTH;
mesh->smoothresh = DEG2RADF(180.0f);
- BKE_mesh_normals_tag_dirty(mesh);
MutableSpan<MVert> verts(mesh->mvert, mesh->totvert);
MutableSpan<MEdge> edges(mesh->medge, mesh->totedge);
MutableSpan<MLoop> loops(mesh->mloop, mesh->totloop);
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index 6dd9460aaa9..22db90a06b0 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -765,7 +765,12 @@ static void layerFree_grid_paint_mask(void *data, int count, int UNUSED(size))
}
}
-/* --------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for (#MLoopCol, #CD_PROP_BYTE_COLOR)
+ * \{ */
+
static void layerCopyValue_mloopcol(const void *source,
void *dest,
const int mixmode,
@@ -954,6 +959,12 @@ static int layerMaxNum_mloopcol()
return MAX_MCOL;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for (#MLoopUV, #CD_MLOOPUV)
+ * \{ */
+
static void layerCopyValue_mloopuv(const void *source,
void *dest,
const int mixmode,
@@ -1716,7 +1727,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
nullptr,
nullptr,
layerMaxNum_tface},
- /* 17: CD_MLOOPCOL */
+ /* 17: CD_PROP_BYTE_COLOR */
{sizeof(MLoopCol),
"MLoopCol",
1,
@@ -2052,46 +2063,45 @@ const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX = {
};
const CustomData_MeshMasks CD_MASK_MESH = {
/* vmask */ (CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PAINT_MASK |
- CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_CREASE),
+ CD_MASK_PROP_ALL | CD_MASK_CREASE),
/* emask */ (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
/* fmask */ 0,
/* pmask */
(CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL |
CD_MASK_SCULPT_FACE_SETS),
/* lmask */
- (CD_MASK_MLOOP | CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL |
- CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
+ (CD_MASK_MLOOP | CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_CUSTOMLOOPNORMAL |
+ CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
};
const CustomData_MeshMasks CD_MASK_DERIVEDMESH = {
/* vmask */ (CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_SHAPEKEY | CD_MASK_MVERT_SKIN |
CD_MASK_PAINT_MASK | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_PROP_ALL |
- CD_MASK_PROP_COLOR | CD_MASK_CREASE),
+ CD_MASK_CREASE),
/* emask */ (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
/* fmask */ (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT),
/* pmask */
(CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL |
CD_MASK_SCULPT_FACE_SETS),
/* lmask */
- (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_PREVIEW_MLOOPCOL |
+ (CD_MASK_MLOOPUV | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_PREVIEW_MLOOPCOL |
CD_MASK_ORIGSPACE_MLOOP | CD_MASK_PROP_ALL), /* XXX MISSING CD_MASK_MLOOPTANGENT ? */
};
const CustomData_MeshMasks CD_MASK_BMESH = {
/* vmask */ (CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
- CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL |
- CD_MASK_PROP_COLOR | CD_MASK_CREASE),
+ CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_CREASE),
/* emask */ (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
/* fmask */ 0,
/* pmask */
(CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS),
/* lmask */
- (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
- CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
+ (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_GRID_PAINT_MASK |
+ CD_MASK_PROP_ALL),
};
const CustomData_MeshMasks CD_MASK_EVERYTHING = {
/* vmask */ (CD_MASK_MVERT | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT |
CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO |
CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK |
- CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_CREASE),
+ CD_MASK_PROP_ALL | CD_MASK_CREASE),
/* emask */
(CD_MASK_MEDGE | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_BWEIGHT | CD_MASK_CREASE |
CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
@@ -2104,9 +2114,8 @@ const CustomData_MeshMasks CD_MASK_EVERYTHING = {
CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS),
/* lmask */
(CD_MASK_MLOOP | CD_MASK_BM_ELEM_PYPTR | CD_MASK_MDISPS | CD_MASK_NORMAL | CD_MASK_MLOOPUV |
- CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_MLOOPTANGENT |
- CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP | CD_MASK_GRID_PAINT_MASK |
- CD_MASK_PROP_ALL),
+ CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_MLOOPTANGENT | CD_MASK_PREVIEW_MLOOPCOL |
+ CD_MASK_ORIGSPACE_MLOOP | CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
};
static const LayerTypeInfo *layerType_getInfo(int type)
@@ -3486,7 +3495,7 @@ void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *ldata, int totloop)
}
else if (fdata->layers[i].type == CD_MCOL) {
CustomData_add_layer_named(
- ldata, CD_MLOOPCOL, CD_CALLOC, nullptr, totloop, fdata->layers[i].name);
+ ldata, CD_PROP_BYTE_COLOR, CD_CALLOC, nullptr, totloop, fdata->layers[i].name);
}
else if (fdata->layers[i].type == CD_MDISPS) {
CustomData_add_layer_named(
@@ -3509,7 +3518,7 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *ldata, int total)
CustomData_add_layer_named(
fdata, CD_MTFACE, CD_CALLOC, nullptr, total, ldata->layers[i].name);
}
- if (ldata->layers[i].type == CD_MLOOPCOL) {
+ if (ldata->layers[i].type == CD_PROP_BYTE_COLOR) {
CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, nullptr, total, ldata->layers[i].name);
}
else if (ldata->layers[i].type == CD_PREVIEW_MLOOPCOL) {
@@ -3544,7 +3553,7 @@ bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool f
if (!LAYER_CMP(ldata, CD_MLOOPUV, fdata, CD_MTFACE)) {
return false;
}
- if (!LAYER_CMP(ldata, CD_MLOOPCOL, fdata, CD_MCOL)) {
+ if (!LAYER_CMP(ldata, CD_PROP_BYTE_COLOR, fdata, CD_MCOL)) {
return false;
}
if (!LAYER_CMP(ldata, CD_PREVIEW_MLOOPCOL, fdata, CD_PREVIEW_MCOL)) {
@@ -3586,17 +3595,17 @@ void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *ldata)
CustomData_set_layer_stencil(fdata, CD_MTFACE, act);
}
- if (CustomData_has_layer(ldata, CD_MLOOPCOL)) {
- act = CustomData_get_active_layer(ldata, CD_MLOOPCOL);
+ if (CustomData_has_layer(ldata, CD_PROP_BYTE_COLOR)) {
+ act = CustomData_get_active_layer(ldata, CD_PROP_BYTE_COLOR);
CustomData_set_layer_active(fdata, CD_MCOL, act);
- act = CustomData_get_render_layer(ldata, CD_MLOOPCOL);
+ act = CustomData_get_render_layer(ldata, CD_PROP_BYTE_COLOR);
CustomData_set_layer_render(fdata, CD_MCOL, act);
- act = CustomData_get_clone_layer(ldata, CD_MLOOPCOL);
+ act = CustomData_get_clone_layer(ldata, CD_PROP_BYTE_COLOR);
CustomData_set_layer_clone(fdata, CD_MCOL, act);
- act = CustomData_get_stencil_layer(ldata, CD_MLOOPCOL);
+ act = CustomData_get_stencil_layer(ldata, CD_PROP_BYTE_COLOR);
CustomData_set_layer_stencil(fdata, CD_MCOL, act);
}
}
@@ -3621,16 +3630,16 @@ void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, Custom
if (CustomData_has_layer(fdata, CD_MCOL)) {
act = CustomData_get_active_layer(fdata, CD_MCOL);
- CustomData_set_layer_active(ldata, CD_MLOOPCOL, act);
+ CustomData_set_layer_active(ldata, CD_PROP_BYTE_COLOR, act);
act = CustomData_get_render_layer(fdata, CD_MCOL);
- CustomData_set_layer_render(ldata, CD_MLOOPCOL, act);
+ CustomData_set_layer_render(ldata, CD_PROP_BYTE_COLOR, act);
act = CustomData_get_clone_layer(fdata, CD_MCOL);
- CustomData_set_layer_clone(ldata, CD_MLOOPCOL, act);
+ CustomData_set_layer_clone(ldata, CD_PROP_BYTE_COLOR, act);
act = CustomData_get_stencil_layer(fdata, CD_MCOL);
- CustomData_set_layer_stencil(ldata, CD_MLOOPCOL, act);
+ CustomData_set_layer_stencil(ldata, CD_PROP_BYTE_COLOR, act);
}
}
@@ -5401,6 +5410,8 @@ const blender::CPPType *custom_data_type_to_cpp_type(const CustomDataType type)
return &CPPType::get<bool>();
case CD_PROP_INT8:
return &CPPType::get<int8_t>();
+ case CD_PROP_BYTE_COLOR:
+ return &CPPType::get<ColorGeometry4b>();
default:
return nullptr;
}
@@ -5430,6 +5441,9 @@ CustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
if (type.is<int8_t>()) {
return CD_PROP_INT8;
}
+ if (type.is<ColorGeometry4b>()) {
+ return CD_PROP_BYTE_COLOR;
+ }
return static_cast<CustomDataType>(-1);
}
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 2369ce88ebc..6a3f6a47f5e 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -217,7 +217,7 @@ int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type)
return CD_FAKE_LNOR;
case DT_TYPE_MLOOPCOL_VERT:
case DT_TYPE_MLOOPCOL_LOOP:
- return CD_MLOOPCOL;
+ return CD_PROP_BYTE_COLOR;
case DT_TYPE_MPROPCOL_VERT:
case DT_TYPE_MPROPCOL_LOOP:
return CD_PROP_COLOR;
@@ -1501,6 +1501,7 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
num_verts_dst,
dirty_nors_dst,
me_src,
+ me_dst,
&geom_map[VDATA]);
geom_map_init[VDATA] = true;
}
@@ -1579,6 +1580,7 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
num_edges_dst,
dirty_nors_dst,
me_src,
+ me_dst,
&geom_map[EDATA]);
geom_map_init[EDATA] = true;
}
diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc
index 8c1161d6ff6..63aa03483b2 100644
--- a/source/blender/blenkernel/intern/displist.cc
+++ b/source/blender/blenkernel/intern/displist.cc
@@ -887,17 +887,11 @@ static GeometrySet curve_calc_modifiers_post(Depsgraph *depsgraph,
if (mti->type == eModifierTypeType_OnlyDeform) {
int totvert;
float(*vertex_coords)[3] = BKE_mesh_vert_coords_alloc(mesh, &totvert);
- if (mti->dependsOnNormals != nullptr && mti->dependsOnNormals(md)) {
- BKE_mesh_vertex_normals_ensure(mesh);
- }
mti->deformVerts(md, &mectx_deform, mesh, vertex_coords, totvert);
BKE_mesh_vert_coords_apply(mesh, vertex_coords);
MEM_freeN(vertex_coords);
}
else {
- if (mti->dependsOnNormals != nullptr && mti->dependsOnNormals(md)) {
- BKE_mesh_vertex_normals_ensure(mesh);
- }
Mesh *output_mesh = mti->modifyMesh(md, &mectx_apply, mesh);
if (mesh != output_mesh) {
geometry_set.replace_mesh(output_mesh);
@@ -1472,10 +1466,12 @@ void BKE_displist_make_curveTypes(Depsgraph *depsgraph,
const bool for_render)
{
BLI_assert(ELEM(ob->type, OB_SURF, OB_CURVES_LEGACY, OB_FONT));
- Curve &cow_curve = *(Curve *)ob->data;
BKE_object_free_derived_caches(ob);
- cow_curve.curve_eval = nullptr;
+
+ /* It's important to retrieve this after calling #BKE_object_free_derived_caches,
+ * which may reset the object data pointer in some cases. */
+ const Curve &original_curve = *static_cast<const Curve *>(ob->data);
ob->runtime.curve_cache = MEM_cnew<CurveCache>(__func__);
ListBase *dispbase = &ob->runtime.curve_cache->disp;
@@ -1488,14 +1484,27 @@ void BKE_displist_make_curveTypes(Depsgraph *depsgraph,
GeometrySet geometry = evaluate_curve_type_object(depsgraph, scene, ob, for_render, dispbase);
if (geometry.has_curves()) {
- /* Assign the evaluated curve to the object's "data_eval". In addition to the curve_eval
- * added to the curve here, it will also contain a copy of the original curve's data. This is
- * essential, because it maintains the expected behavior for evaluated curve data from before
- * the CurveEval data type was introduced, when an evaluated object's curve data was just a
- * copy of the original curve and everything else ended up in #CurveCache. */
- CurveComponent &curve_component = geometry.get_component_for_write<CurveComponent>();
- cow_curve.curve_eval = curve_component.get_for_read();
- BKE_object_eval_assign_data(ob, &cow_curve.id, false);
+ /* Create a copy of the original curve and add necessary pointers to evaluated and edit mode
+ * data. This is needed for a few reasons:
+ * - Existing code from before curve evaluation was changed to use #GeometrySet expected to
+ * have a copy of the original curve data. (Any evaluated data was placed in
+ * #Object.runtime.curve_cache).
+ * - The result of modifier evaluation is not a #Curve data-block but a #Curves data-block,
+ * which can support constructive modifiers and geometry nodes.
+ * - The dependency graph has handling of edit mode pointers (see #update_edit_mode_pointers)
+ * but it doesn't seem to work in this case.
+ *
+ * Since the the plan is to replace this legacy curve object with the curves data-block
+ * (see T95355), this somewhat hacky inefficient solution is relatively temporary.
+ */
+ Curve &cow_curve = *reinterpret_cast<Curve *>(
+ BKE_id_copy_ex(nullptr, &original_curve.id, nullptr, LIB_ID_COPY_LOCALIZE));
+ cow_curve.curve_eval = geometry.get_curves_for_read();
+ /* Copy edit mode pointers necessary for drawing to the duplicated curve. */
+ cow_curve.editnurb = original_curve.editnurb;
+ cow_curve.editfont = original_curve.editfont;
+ cow_curve.edit_data_from_original = true;
+ BKE_object_eval_assign_data(ob, &cow_curve.id, true);
}
ob->runtime.geometry_set_eval = new GeometrySet(std::move(geometry));
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index b85b2b3157c..22341f98375 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -336,7 +336,7 @@ bool dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface, Object
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
Mesh *me = ob->data;
- return (CustomData_get_named_layer_index(&me->ldata, CD_MLOOPCOL, name) != -1);
+ return (CustomData_get_named_layer_index(&me->ldata, CD_PROP_BYTE_COLOR, name) != -1);
}
if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
return (BKE_object_defgroup_name_index(ob, name) != -1);
@@ -1664,7 +1664,7 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
const MLoop *mloop = mesh->mloop;
const int totloop = mesh->totloop;
const MLoopCol *col = CustomData_get_layer_named(
- &mesh->ldata, CD_MLOOPCOL, surface->init_layername);
+ &mesh->ldata, CD_PROP_BYTE_COLOR, surface->init_layername);
if (!col) {
return;
}
@@ -1676,7 +1676,7 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
MLoopCol *col = CustomData_get_layer_named(
- &mesh->ldata, CD_MLOOPCOL, surface->init_layername);
+ &mesh->ldata, CD_PROP_BYTE_COLOR, surface->init_layername);
if (!col) {
return;
}
@@ -1899,7 +1899,6 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *
pmd->type == MOD_DYNAMICPAINT_TYPE_CANVAS) {
DynamicPaintSurface *surface;
- bool update_normals = false;
/* loop through surfaces */
for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
@@ -1941,20 +1940,28 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *
/* paint layer */
MLoopCol *mloopcol = CustomData_get_layer_named(
- &result->ldata, CD_MLOOPCOL, surface->output_name);
+ &result->ldata, CD_PROP_BYTE_COLOR, surface->output_name);
/* if output layer is lost from a constructive modifier, re-add it */
if (!mloopcol && dynamicPaint_outputLayerExists(surface, ob, 0)) {
- mloopcol = CustomData_add_layer_named(
- &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
+ mloopcol = CustomData_add_layer_named(&result->ldata,
+ CD_PROP_BYTE_COLOR,
+ CD_CALLOC,
+ NULL,
+ totloop,
+ surface->output_name);
}
/* wet layer */
MLoopCol *mloopcol_wet = CustomData_get_layer_named(
- &result->ldata, CD_MLOOPCOL, surface->output_name2);
+ &result->ldata, CD_PROP_BYTE_COLOR, surface->output_name2);
/* if output layer is lost from a constructive modifier, re-add it */
if (!mloopcol_wet && dynamicPaint_outputLayerExists(surface, ob, 1)) {
- mloopcol_wet = CustomData_add_layer_named(
- &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
+ mloopcol_wet = CustomData_add_layer_named(&result->ldata,
+ CD_PROP_BYTE_COLOR,
+ CD_CALLOC,
+ NULL,
+ totloop,
+ surface->output_name2);
}
data.ob = ob;
@@ -2018,21 +2025,17 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *
settings.use_threading = (sData->total_points > 1000);
BLI_task_parallel_range(
0, sData->total_points, &data, dynamic_paint_apply_surface_wave_cb, &settings);
- update_normals = true;
+ BKE_mesh_normals_tag_dirty(mesh);
}
/* displace */
if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
dynamicPaint_applySurfaceDisplace(surface, result);
- update_normals = true;
+ BKE_mesh_normals_tag_dirty(mesh);
}
}
}
}
-
- if (update_normals) {
- BKE_mesh_normals_tag_dirty(result);
- }
}
/* make a copy of mesh to use as brush data */
else if (pmd->brush && pmd->type == MOD_DYNAMICPAINT_TYPE_BRUSH) {
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 81e73b6cf2c..5de13fbdbed 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -3537,7 +3537,6 @@ static Mesh *create_smoke_geometry(FluidDomainSettings *fds, Mesh *orgmesh, Obje
}
BKE_mesh_calc_edges(result, false, false);
- BKE_mesh_normals_tag_dirty(result);
return result;
}
@@ -5071,6 +5070,9 @@ void BKE_fluid_modifier_copy(const struct FluidModifierData *fmd,
tfds->openvdb_compression = fds->openvdb_compression;
tfds->clipping = fds->clipping;
tfds->openvdb_data_depth = fds->openvdb_data_depth;
+
+ /* Render options. */
+ tfds->velocity_scale = fds->velocity_scale;
}
else if (tfmd->flow) {
FluidFlowSettings *tffs = tfmd->flow;
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index 47f7bb00b8f..fb39861d3e7 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -903,22 +903,6 @@ static void set_loop_uv(MLoopUV &uv, float2 co)
copy_v2_v2(uv.uv, co);
}
-static ColorGeometry4f get_loop_color(const MLoopCol &col)
-{
- ColorGeometry4b encoded_color = ColorGeometry4b(col.r, col.g, col.b, col.a);
- ColorGeometry4f linear_color = encoded_color.decode();
- return linear_color;
-}
-
-static void set_loop_color(MLoopCol &col, ColorGeometry4f linear_color)
-{
- ColorGeometry4b encoded_color = linear_color.encode();
- col.r = encoded_color.r;
- col.g = encoded_color.g;
- col.b = encoded_color.b;
- col.a = encoded_color.a;
-}
-
static float get_crease(const MEdge &edge)
{
return edge.crease / 255.0f;
@@ -1293,14 +1277,6 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
make_derived_read_attribute<MLoopUV, float2, get_loop_uv>,
make_derived_write_attribute<MLoopUV, float2, get_loop_uv, set_loop_uv>);
- static NamedLegacyCustomDataProvider vertex_colors(
- ATTR_DOMAIN_CORNER,
- CD_PROP_COLOR,
- CD_MLOOPCOL,
- corner_access,
- make_derived_read_attribute<MLoopCol, ColorGeometry4f, get_loop_color>,
- make_derived_write_attribute<MLoopCol, ColorGeometry4f, get_loop_color, set_loop_color>);
-
static VertexGroupsAttributeProvider vertex_groups;
static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access);
static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access);
@@ -1310,7 +1286,6 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
return ComponentAttributeProviders(
{&position, &id, &material_index, &shade_smooth, &normal, &crease},
{&uvs,
- &vertex_colors,
&corner_custom_data,
&vertex_groups,
&point_custom_data,
diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc
index 53ec148fd2d..dfa820519a5 100644
--- a/source/blender/blenkernel/intern/image.cc
+++ b/source/blender/blenkernel/intern/image.cc
@@ -829,10 +829,7 @@ ImageTile *BKE_image_get_tile_from_iuser(Image *ima, const ImageUser *iuser)
return BKE_image_get_tile(ima, image_get_tile_number_from_iuser(ima, iuser));
}
-int BKE_image_get_tile_from_pos(struct Image *ima,
- const float uv[2],
- float r_uv[2],
- float r_ofs[2])
+int BKE_image_get_tile_from_pos(Image *ima, const float uv[2], float r_uv[2], float r_ofs[2])
{
float local_ofs[2];
if (r_ofs == nullptr) {
@@ -860,6 +857,18 @@ int BKE_image_get_tile_from_pos(struct Image *ima,
return tile_number;
}
+void BKE_image_get_tile_uv(const Image *ima, const int tile_number, float r_uv[2])
+{
+ if (ima->source != IMA_SRC_TILED) {
+ zero_v2(r_uv);
+ }
+ else {
+ const int tile_index = tile_number - 1001;
+ r_uv[0] = static_cast<float>(tile_index % 10);
+ r_uv[1] = static_cast<float>(tile_index / 10);
+ }
+}
+
int BKE_image_find_nearest_tile(const Image *image, const float co[2])
{
const float co_floor[2] = {floorf(co[0]), floorf(co[1])};
@@ -868,17 +877,15 @@ int BKE_image_find_nearest_tile(const Image *image, const float co[2])
int tile_number_best = -1;
LISTBASE_FOREACH (const ImageTile *, tile, &image->tiles) {
- const int tile_index = tile->tile_number - 1001;
- /* Coordinates of the current tile. */
- const float tile_index_co[2] = {static_cast<float>(tile_index % 10),
- static_cast<float>(tile_index / 10)};
+ float uv_offset[2];
+ BKE_image_get_tile_uv(image, tile->tile_number, uv_offset);
- if (equals_v2v2(co_floor, tile_index_co)) {
+ if (equals_v2v2(co_floor, uv_offset)) {
return tile->tile_number;
}
/* Distance between co[2] and UDIM tile. */
- const float dist_sq = len_squared_v2v2(tile_index_co, co);
+ const float dist_sq = len_squared_v2v2(uv_offset, co);
if (dist_sq < dist_best_sq) {
dist_best_sq = dist_sq;
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 4caaf314888..002b496393f 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -1943,6 +1943,8 @@ static void material_default_gpencil_init(Material *ma)
static void material_default_surface_init(Material *ma)
{
+ strcpy(ma->id.name, "MADefault Surface");
+
bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname);
ma->nodetree = ntree;
ma->use_nodes = true;
@@ -1969,6 +1971,8 @@ static void material_default_surface_init(Material *ma)
static void material_default_volume_init(Material *ma)
{
+ strcpy(ma->id.name, "MADefault Volume");
+
bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname);
ma->nodetree = ntree;
ma->use_nodes = true;
@@ -1992,6 +1996,8 @@ static void material_default_volume_init(Material *ma)
static void material_default_holdout_init(Material *ma)
{
+ strcpy(ma->id.name, "MADefault Holdout");
+
bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname);
ma->nodetree = ntree;
ma->use_nodes = true;
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index 25d97d0bd3c..c13a2bc794a 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -463,7 +463,8 @@ static int customdata_compare(
CustomDataLayer *l1, *l2;
int layer_count1 = 0, layer_count2 = 0, j;
const uint64_t cd_mask_non_generic = CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MPOLY |
- CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MDEFORMVERT;
+ CD_MASK_MLOOPUV | CD_MASK_PROP_BYTE_COLOR |
+ CD_MASK_MDEFORMVERT;
const uint64_t cd_mask_all_attr = CD_MASK_PROP_ALL | cd_mask_non_generic;
for (int i = 0; i < c1->totlayer; i++) {
@@ -581,7 +582,7 @@ static int customdata_compare(
}
break;
}
- case CD_MLOOPCOL: {
+ case CD_PROP_BYTE_COLOR: {
MLoopCol *lp1 = (MLoopCol *)l1->data;
MLoopCol *lp2 = (MLoopCol *)l2->data;
int ltot = m1->totloop;
@@ -768,7 +769,7 @@ static void mesh_ensure_tessellation_customdata(Mesh *me)
}
else {
const int tottex_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
- const int totcol_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
+ const int totcol_original = CustomData_number_of_layers(&me->ldata, CD_PROP_BYTE_COLOR);
const int tottex_tessface = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
const int totcol_tessface = CustomData_number_of_layers(&me->fdata, CD_MCOL);
@@ -786,7 +787,8 @@ static void mesh_ensure_tessellation_customdata(Mesh *me)
* some info to help troubleshoot what's going on. */
printf(
"%s: warning! Tessellation uvs or vcol data got out of sync, "
- "had to reset!\n CD_MTFACE: %d != CD_MLOOPUV: %d || CD_MCOL: %d != CD_MLOOPCOL: "
+ "had to reset!\n CD_MTFACE: %d != CD_MLOOPUV: %d || CD_MCOL: %d != "
+ "CD_PROP_BYTE_COLOR: "
"%d\n",
__func__,
tottex_tessface,
@@ -871,7 +873,7 @@ bool BKE_mesh_clear_facemap_customdata(struct Mesh *me)
/**
* This ensures grouped custom-data (e.g. #CD_MLOOPUV and #CD_MTFACE, or
- * #CD_MLOOPCOL and #CD_MCOL) have the same relative active/render/clone/mask indices.
+ * #CD_PROP_BYTE_COLOR and #CD_MCOL) have the same relative active/render/clone/mask indices.
*
* NOTE(@campbellbarton): that for undo mesh data we want to skip 'ensure_tess_cd' call since
* we don't want to store memory for #MFace data when its only used for older
@@ -902,7 +904,7 @@ void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd)
me->mpoly = (MPoly *)CustomData_get_layer(&me->pdata, CD_MPOLY);
me->mloop = (MLoop *)CustomData_get_layer(&me->ldata, CD_MLOOP);
- me->mloopcol = (MLoopCol *)CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
+ me->mloopcol = (MLoopCol *)CustomData_get_layer(&me->ldata, CD_PROP_BYTE_COLOR);
me->mloopuv = (MLoopUV *)CustomData_get_layer(&me->ldata, CD_MLOOPUV);
}
@@ -1112,6 +1114,9 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src,
mesh_ensure_cdlayers_primary(me_dst, do_tessface);
BKE_mesh_update_customdata_pointers(me_dst, false);
+ /* Expect that normals aren't copied at all, since the destination mesh is new. */
+ BLI_assert(BKE_mesh_vertex_normals_are_dirty(me_dst));
+
return me_dst;
}
@@ -1688,6 +1693,7 @@ void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys)
mul_m3_v3(m3, *lnors);
}
}
+ BKE_mesh_normals_tag_dirty(me);
}
void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys)
diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
index eee1d3b9eec..3fcacb31b24 100644
--- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
@@ -782,7 +782,6 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
}
}
- BKE_mesh_calc_normals(result);
if (dbg_level > 0) {
BKE_mesh_validate(result, true, true);
}
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index ff953ef5b46..a289d208684 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -120,9 +120,6 @@ void BKE_mesh_from_metaball(ListBase *lb, Mesh *me)
}
BKE_mesh_update_customdata_pointers(me, true);
-
- BKE_mesh_normals_tag_dirty(me);
-
BKE_mesh_calc_edges(me, true, false);
}
}
@@ -514,7 +511,6 @@ Mesh *BKE_mesh_new_nomain_from_curve_displist(const Object *ob, const ListBase *
}
mesh = BKE_mesh_new_nomain(totvert, totedge, 0, totloop, totpoly);
- BKE_mesh_normals_tag_dirty(mesh);
if (totvert != 0) {
memcpy(mesh->mvert, allvert, totvert * sizeof(MVert));
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.cc b/source/blender/blenkernel/intern/mesh_evaluate.cc
index 6c5a5de31fc..ec2660a0145 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.cc
+++ b/source/blender/blenkernel/intern/mesh_evaluate.cc
@@ -661,7 +661,7 @@ static void bm_corners_to_loops_ex(ID *id,
}
for (int i = 0; i < numCol; i++) {
- MLoopCol *mloopcol = (MLoopCol *)CustomData_get_n(ldata, CD_MLOOPCOL, loopstart, i);
+ MLoopCol *mloopcol = (MLoopCol *)CustomData_get_n(ldata, CD_PROP_BYTE_COLOR, loopstart, i);
MCol *mcol = (MCol *)CustomData_get_n(fdata, CD_MCOL, findex, i);
MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[0]);
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index 2e634a14872..3a37c29c1d0 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -478,6 +478,7 @@ void BKE_mesh_remap_calc_verts_from_mesh(const int mode,
const int numverts_dst,
const bool UNUSED(dirty_nors_dst),
Mesh *me_src,
+ Mesh *me_dst,
MeshPairRemap *r_map)
{
const float full_weight = 1.0f;
@@ -580,7 +581,7 @@ void BKE_mesh_remap_calc_verts_from_mesh(const int mode,
MPoly *polys_src = me_src->mpoly;
MLoop *loops_src = me_src->mloop;
float(*vcos_src)[3] = BKE_mesh_vert_coords_alloc(me_src, NULL);
- const float(*vert_normals_src)[3] = BKE_mesh_vertex_normals_ensure(me_src);
+ const float(*vert_normals_dst)[3] = BKE_mesh_vertex_normals_ensure(me_dst);
size_t tmp_buff_size = MREMAP_DEFAULT_BUFSIZE;
float(*vcos)[3] = MEM_mallocN(sizeof(*vcos) * tmp_buff_size, __func__);
@@ -592,7 +593,7 @@ void BKE_mesh_remap_calc_verts_from_mesh(const int mode,
if (mode == MREMAP_MODE_VERT_POLYINTERP_VNORPROJ) {
for (i = 0; i < numverts_dst; i++) {
copy_v3_v3(tmp_co, verts_dst[i].co);
- copy_v3_v3(tmp_no, vert_normals_src[i]);
+ copy_v3_v3(tmp_no, vert_normals_dst[i]);
/* Convert the vertex to tree coordinates, if needed. */
if (space_transform) {
@@ -703,6 +704,7 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode,
const int numedges_dst,
const bool UNUSED(dirty_nors_dst),
Mesh *me_src,
+ Mesh *me_dst,
MeshPairRemap *r_map)
{
const float full_weight = 1.0f;
@@ -938,7 +940,7 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode,
BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
- const float(*vert_normals_dst)[3] = BKE_mesh_vertex_normals_ensure(me_src);
+ const float(*vert_normals_dst)[3] = BKE_mesh_vertex_normals_ensure(me_dst);
for (i = 0; i < numedges_dst; i++) {
/* For each dst edge, we sample some rays from it (interpolated from its vertices)
diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
index 7be4a6f2f94..02c9f61957d 100644
--- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
+++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
@@ -140,7 +140,6 @@ static Mesh *remesh_quadriflow(const Mesh *input_mesh,
}
BKE_mesh_calc_edges(mesh, false, false);
- BKE_mesh_calc_normals(mesh);
MEM_freeN(qrd.out_faces);
MEM_freeN(qrd.out_verts);
@@ -257,7 +256,6 @@ static Mesh *remesh_voxel_volume_to_mesh(const openvdb::FloatGrid::Ptr level_set
}
BKE_mesh_calc_edges(mesh, false, false);
- BKE_mesh_normals_tag_dirty(mesh);
return mesh;
}
diff --git a/source/blender/blenkernel/intern/mesh_tessellate.c b/source/blender/blenkernel/intern/mesh_tessellate.c
index ae52e31cb9b..ea3cc043267 100644
--- a/source/blender/blenkernel/intern/mesh_tessellate.c
+++ b/source/blender/blenkernel/intern/mesh_tessellate.c
@@ -58,7 +58,7 @@ static void mesh_loops_to_tessdata(CustomData *fdata,
* The issue is, unless having two different functions with nearly the same code,
* there's not much ways to solve this. Better IMHO to live with it for now (sigh). */
const int numUV = CustomData_number_of_layers(ldata, CD_MLOOPUV);
- const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
+ const int numCol = CustomData_number_of_layers(ldata, CD_PROP_BYTE_COLOR);
const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL);
const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP);
const bool hasLoopNormal = CustomData_has_layer(ldata, CD_NORMAL);
@@ -81,7 +81,7 @@ static void mesh_loops_to_tessdata(CustomData *fdata,
for (i = 0; i < numCol; i++) {
MCol(*mcol)[4] = CustomData_get_layer_n(fdata, CD_MCOL, i);
- MLoopCol *mloopcol = CustomData_get_layer_n(ldata, CD_MLOOPCOL, i);
+ MLoopCol *mloopcol = CustomData_get_layer_n(ldata, CD_PROP_BYTE_COLOR, i);
for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) {
for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
diff --git a/source/blender/blenkernel/intern/mesh_validate.cc b/source/blender/blenkernel/intern/mesh_validate.cc
index 6af765d7de5..d16f7eaf588 100644
--- a/source/blender/blenkernel/intern/mesh_validate.cc
+++ b/source/blender/blenkernel/intern/mesh_validate.cc
@@ -1017,7 +1017,7 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata,
pdata, mask.pmask, totpoly, do_verbose, do_fixes, &is_change_p);
const int tot_uvloop = CustomData_number_of_layers(ldata, CD_MLOOPUV);
- const int tot_vcolloop = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
+ const int tot_vcolloop = CustomData_number_of_layers(ldata, CD_PROP_BYTE_COLOR);
if (tot_uvloop > MAX_MTFACE) {
PRINT_ERR(
"\tMore UV layers than %d allowed, %d last ones won't be available for render, shaders, "
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index f4703b32582..e7ee8caf0eb 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -944,8 +944,10 @@ static void modwrap_dependsOnNormals(Mesh *me)
break;
}
case ME_WRAPPER_TYPE_SUBD:
+ /* Not an expected case. */
+ break;
case ME_WRAPPER_TYPE_MDATA:
- BKE_mesh_calc_normals(me);
+ /* Normals are calculated lazily. */
break;
}
}
@@ -992,7 +994,7 @@ void BKE_modifier_deform_vertsEM(ModifierData *md,
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- BKE_mesh_calc_normals(me);
+ modwrap_dependsOnNormals(me);
}
mti->deformVertsEM(md, ctx, em, me, vertexCos, numVerts);
}
diff --git a/source/blender/blenkernel/intern/multires_reshape_apply_base.c b/source/blender/blenkernel/intern/multires_reshape_apply_base.c
index 65ba7b64d83..837b64affa8 100644
--- a/source/blender/blenkernel/intern/multires_reshape_apply_base.c
+++ b/source/blender/blenkernel/intern/multires_reshape_apply_base.c
@@ -156,7 +156,7 @@ void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape
/* Vertices were moved around, need to update normals after all the vertices are updated
* Probably this is possible to do in the loop above, but this is rather tricky because
* we don't know all needed vertices' coordinates there yet. */
- BKE_mesh_calc_normals(base_mesh);
+ BKE_mesh_normals_tag_dirty(base_mesh);
}
void multires_reshape_apply_base_refine_from_base(MultiresReshapeContext *reshape_context)
diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc
index 5ff1f6b950f..948064ad170 100644
--- a/source/blender/blenkernel/intern/object.cc
+++ b/source/blender/blenkernel/intern/object.cc
@@ -1789,6 +1789,7 @@ void BKE_object_free_derived_caches(Object *ob)
BKE_mesh_eval_delete((Mesh *)data_eval);
}
else {
+ BKE_libblock_free_data(data_eval, false);
BKE_libblock_free_datablock(data_eval, 0);
MEM_freeN(data_eval);
}
@@ -3564,19 +3565,19 @@ void BKE_object_apply_parent_inverse(struct Object *ob)
* Use parent's world transform as the child's origin.
*
* Let:
- * local = identity
- * world = orthonormalized(parent)
+ * `local = identity`
+ * `world = orthonormalized(parent)`
*
* Then:
- * world = parent @ parentinv @ local
- * inv(parent) @ world = parentinv
- * parentinv = inv(parent) @ world
+ * `world = parent @ parentinv @ local`
+ * `inv(parent) @ world = parentinv`
+ * `parentinv = inv(parent) @ world`
*
- * NOTE: If ob->obmat has shear, then this `parentinv` is insufficient because
- * parent @ parentinv => shearless result
+ * NOTE: If `ob->obmat` has shear, then this `parentinv` is insufficient because
+ * `parent @ parentinv => shearless result`
*
* Thus, local will have shear which cannot be decomposed into TRS:
- * local = inv(parent @ parentinv) @ world
+ * `local = inv(parent @ parentinv) @ world`
*
* This is currently not supported for consistency in the handling of shear during the other
* parenting ops: Parent (Keep Transform), Clear [Parent] and Keep Transform.
@@ -3591,11 +3592,11 @@ void BKE_object_apply_parent_inverse(struct Object *ob)
/* Now, preserve `world` given the new `parentinv`.
*
- * world = parent @ parentinv @ local
- * inv(parent) @ world = parentinv @ local
- * inv(parentinv) @ inv(parent) @ world = local
+ * `world = parent @ parentinv @ local`
+ * `inv(parent) @ world = parentinv @ local`
+ * `inv(parentinv) @ inv(parent) @ world = local`
*
- * local = inv(parentinv) @ inv(parent) @ world
+ * `local = inv(parentinv) @ inv(parent) @ world`
*/
float ob_local[4][4];
copy_m4_m4(ob_local, ob->parentinv);
@@ -3974,8 +3975,9 @@ bool BKE_object_empty_image_data_is_visible_in_view3d(const Object *ob, const Re
}
if (visibility_flag & OB_EMPTY_IMAGE_HIDE_NON_AXIS_ALIGNED) {
- float3 proj;
- project_plane_v3_v3v3(proj, ob->obmat[2], rv3d->viewinv[2]);
+ float3 proj, ob_z_axis;
+ normalize_v3_v3(ob_z_axis, ob->obmat[2]);
+ project_plane_v3_v3v3(proj, ob_z_axis, rv3d->viewinv[2]);
const float proj_length_sq = len_squared_v3(proj);
if (proj_length_sq > 1e-5f) {
return false;
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index fbbd429f58a..f41d59c77ba 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -167,7 +167,7 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
#endif
if (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER) {
/* Always compute UVs, vertex colors as orcos for render. */
- cddata_masks.lmask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
+ cddata_masks.lmask |= CD_MASK_MLOOPUV | CD_MASK_PROP_BYTE_COLOR;
cddata_masks.vmask |= CD_MASK_ORCO | CD_MASK_PROP_COLOR;
}
makeDerivedMesh(depsgraph, scene, ob, &cddata_masks); /* was CD_MASK_BAREMESH */
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 5fd7984ea90..0f523d87d9b 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -1101,7 +1101,6 @@ bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint)
}
else if ((CurvesSculpt **)r_paint == &ts->curves_sculpt) {
CurvesSculpt *data = MEM_callocN(sizeof(*data), __func__);
- data->curve_length = 0.3f;
paint = &data->paint;
}
else if (*r_paint == &ts->imapaint.paint) {
@@ -1341,8 +1340,6 @@ void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss)
struct SculptVertexPaintGeomMap *gmap = NULL;
if (ss->mode_type == OB_MODE_VERTEX_PAINT) {
gmap = &ss->mode.vpaint.gmap;
-
- MEM_SAFE_FREE(ss->mode.vpaint.previous_color);
}
else if (ss->mode_type == OB_MODE_WEIGHT_PAINT) {
gmap = &ss->mode.wpaint.gmap;
@@ -1845,7 +1842,7 @@ void BKE_sculpt_color_layer_create_if_needed(struct Object *object)
{
Mesh *orig_me = BKE_object_get_original_mesh(object);
- int types[] = {CD_PROP_COLOR, CD_MLOOPCOL};
+ int types[] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR};
bool has_color = false;
for (int i = 0; i < ARRAY_SIZE(types); i++) {
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index e91f360ef22..1fb1570b3ff 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -1267,7 +1267,7 @@ bool BKE_pbvh_get_color_layer(const Mesh *me, CustomDataLayer **r_layer, Attribu
{
CustomDataLayer *layer = BKE_id_attributes_active_color_get((ID *)me);
- if (!layer || !ELEM(layer->type, CD_PROP_COLOR, CD_MLOOPCOL)) {
+ if (!layer || !ELEM(layer->type, CD_PROP_COLOR, CD_PROP_BYTE_COLOR)) {
*r_layer = NULL;
*r_attr = ATTR_DOMAIN_NUM;
return false;
diff --git a/source/blender/blenkernel/intern/pbvh.cc b/source/blender/blenkernel/intern/pbvh.cc
index d32a03186e3..be6e95426c2 100644
--- a/source/blender/blenkernel/intern/pbvh.cc
+++ b/source/blender/blenkernel/intern/pbvh.cc
@@ -50,7 +50,7 @@ inline void to_static_color_type(const CustomDataType type, const Func &func)
case CD_PROP_COLOR:
func(MPropCol());
break;
- case CD_MLOOPCOL:
+ case CD_PROP_BYTE_COLOR:
func(MLoopCol());
break;
default:
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 6a135c248ce..55d76938ad3 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -1240,7 +1240,7 @@ static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx,
EDGE_QUEUE_DISABLE(e);
#endif
- /* At the moment edges never get shorter (subdiv will make new edges)
+ /* At the moment edges never get shorter (subdivision will make new edges)
* unlike collapse where edges can become longer. */
#if 0
if (len_squared_v3v3(v1->co, v2->co) <= eq_ctx->q->limit_len_squared) {
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 77bd00da50a..b7a2b578a1c 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -267,6 +267,7 @@ bool pbvh_bmesh_node_nearest_to_ray(PBVHNode *node,
void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode);
/* pbvh_pixels.hh */
+
void pbvh_pixels_free(PBVHNode *node);
void pbvh_pixels_free_brush_test(PBVHNode *node);
diff --git a/source/blender/blenkernel/intern/pbvh_pixels.cc b/source/blender/blenkernel/intern/pbvh_pixels.cc
index d8dd2f4b382..5623cac44ac 100644
--- a/source/blender/blenkernel/intern/pbvh_pixels.cc
+++ b/source/blender/blenkernel/intern/pbvh_pixels.cc
@@ -22,12 +22,14 @@
namespace blender::bke::pbvh::pixels {
-/** Durind debugging this check could be enabled. It will write to each image pixel that is covered
- * by the pbvh. */
+/**
+ * During debugging this check could be enabled.
+ * It will write to each image pixel that is covered by the PBVH.
+ */
constexpr bool USE_WATERTIGHT_CHECK = false;
/**
- * Calculate the delta of two neighbour uv coordinates in the given image buffer.
+ * Calculate the delta of two neighbor UV coordinates in the given image buffer.
*/
static float2 calc_barycentric_delta(const float2 uvs[3],
const float2 start_uv,
@@ -273,11 +275,7 @@ static void apply_watertight_check(PBVH *pbvh, Image *image, ImageUser *image_us
BKE_image_partial_update_mark_full_update(image);
}
-static void update_pixels(PBVH *pbvh,
- const struct MLoop *mloop,
- struct CustomData *ldata,
- struct Image *image,
- struct ImageUser *image_user)
+static void update_pixels(PBVH *pbvh, Mesh *mesh, Image *image, ImageUser *image_user)
{
Vector<PBVHNode *> nodes_to_update;
@@ -285,14 +283,14 @@ static void update_pixels(PBVH *pbvh,
return;
}
- MLoopUV *ldata_uv = static_cast<MLoopUV *>(CustomData_get_layer(ldata, CD_MLOOPUV));
+ MLoopUV *ldata_uv = static_cast<MLoopUV *>(CustomData_get_layer(&mesh->ldata, CD_MLOOPUV));
if (ldata_uv == nullptr) {
return;
}
for (PBVHNode *node : nodes_to_update) {
NodeData *node_data = static_cast<NodeData *>(node->pixels.node_data);
- init_triangles(pbvh, node, node_data, mloop);
+ init_triangles(pbvh, node, node_data, mesh->mloop);
}
EncodePixelsUserData user_data;
@@ -375,13 +373,9 @@ void BKE_pbvh_pixels_mark_image_dirty(PBVHNode &node, Image &image, ImageUser &i
extern "C" {
using namespace blender::bke::pbvh::pixels;
-void BKE_pbvh_build_pixels(PBVH *pbvh,
- const struct MLoop *mloop,
- struct CustomData *ldata,
- struct Image *image,
- struct ImageUser *image_user)
+void BKE_pbvh_build_pixels(PBVH *pbvh, Mesh *mesh, Image *image, ImageUser *image_user)
{
- update_pixels(pbvh, mloop, ldata, image, image_user);
+ update_pixels(pbvh, mesh, image, image_user);
}
void pbvh_pixels_free(PBVHNode *node)
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
index 83e4336e3b1..83427adcb43 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -1155,7 +1155,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
* calculation. Since vertex normals are supposed to be a consistent cache, don't bother
* calculating them here. The work may have been pointless anyway if the mesh is deformed or
* changed afterwards. */
- BKE_mesh_normals_tag_dirty(result);
+ BLI_assert(BKE_mesh_vertex_normals_are_dirty(result) || BKE_mesh_poly_normals_are_dirty(result));
/* Free used memory. */
subdiv_mesh_context_free(&subdiv_context);
return result;
diff --git a/source/blender/blenkernel/intern/type_conversions.cc b/source/blender/blenkernel/intern/type_conversions.cc
index e84ec5b3890..1c2665769db 100644
--- a/source/blender/blenkernel/intern/type_conversions.cc
+++ b/source/blender/blenkernel/intern/type_conversions.cc
@@ -2,6 +2,8 @@
#include "BKE_type_conversions.hh"
+#include "DNA_meshdata_types.h"
+
#include "FN_multi_function_builder.hh"
#include "BLI_color.hh"
@@ -61,6 +63,10 @@ static ColorGeometry4f float_to_color(const float &a)
{
return ColorGeometry4f(a, a, a, 1.0f);
}
+static ColorGeometry4b float_to_byte_color(const float &a)
+{
+ return float_to_color(a).encode();
+}
static float3 float2_to_float3(const float2 &a)
{
@@ -86,6 +92,10 @@ static ColorGeometry4f float2_to_color(const float2 &a)
{
return ColorGeometry4f(a.x, a.y, 0.0f, 1.0f);
}
+static ColorGeometry4b float2_to_byte_color(const float2 &a)
+{
+ return float2_to_color(a).encode();
+}
static bool float3_to_bool(const float3 &a)
{
@@ -111,6 +121,10 @@ static ColorGeometry4f float3_to_color(const float3 &a)
{
return ColorGeometry4f(a.x, a.y, a.z, 1.0f);
}
+static ColorGeometry4b float3_to_byte_color(const float3 &a)
+{
+ return float3_to_color(a).encode();
+}
static bool int_to_bool(const int32_t &a)
{
@@ -137,6 +151,10 @@ static ColorGeometry4f int_to_color(const int32_t &a)
{
return ColorGeometry4f((float)a, (float)a, (float)a, 1.0f);
}
+static ColorGeometry4b int_to_byte_color(const int32_t &a)
+{
+ return int_to_color(a).encode();
+}
static bool int8_to_bool(const int8_t &a)
{
@@ -162,6 +180,10 @@ static ColorGeometry4f int8_to_color(const int8_t &a)
{
return ColorGeometry4f((float)a, (float)a, (float)a, 1.0f);
}
+static ColorGeometry4b int8_to_byte_color(const int8_t &a)
+{
+ return int8_to_color(a).encode();
+}
static float bool_to_float(const bool &a)
{
@@ -187,6 +209,10 @@ static ColorGeometry4f bool_to_color(const bool &a)
{
return (a) ? ColorGeometry4f(1.0f, 1.0f, 1.0f, 1.0f) : ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f);
}
+static ColorGeometry4b bool_to_byte_color(const bool &a)
+{
+ return bool_to_color(a).encode();
+}
static bool color_to_bool(const ColorGeometry4f &a)
{
@@ -212,6 +238,39 @@ static float3 color_to_float3(const ColorGeometry4f &a)
{
return float3(a.r, a.g, a.b);
}
+static ColorGeometry4b color_to_byte_color(const ColorGeometry4f &a)
+{
+ return a.encode();
+}
+
+static bool byte_color_to_bool(const ColorGeometry4b &a)
+{
+ return a.r > 0 || a.g > 0 || a.b > 0;
+}
+static float byte_color_to_float(const ColorGeometry4b &a)
+{
+ return color_to_float(a.decode());
+}
+static int32_t byte_color_to_int(const ColorGeometry4b &a)
+{
+ return color_to_int(a.decode());
+}
+static int8_t byte_color_to_int8(const ColorGeometry4b &a)
+{
+ return color_to_int8(a.decode());
+}
+static float2 byte_color_to_float2(const ColorGeometry4b &a)
+{
+ return color_to_float2(a.decode());
+}
+static float3 byte_color_to_float3(const ColorGeometry4b &a)
+{
+ return color_to_float3(a.decode());
+}
+static ColorGeometry4f byte_color_to_color(const ColorGeometry4b &a)
+{
+ return a.decode();
+}
static DataTypeConversions create_implicit_conversions()
{
@@ -223,6 +282,7 @@ static DataTypeConversions create_implicit_conversions()
add_implicit_conversion<float, bool, float_to_bool>(conversions);
add_implicit_conversion<float, int8_t, float_to_int8>(conversions);
add_implicit_conversion<float, ColorGeometry4f, float_to_color>(conversions);
+ add_implicit_conversion<float, ColorGeometry4b, float_to_byte_color>(conversions);
add_implicit_conversion<float2, float3, float2_to_float3>(conversions);
add_implicit_conversion<float2, float, float2_to_float>(conversions);
@@ -230,6 +290,7 @@ static DataTypeConversions create_implicit_conversions()
add_implicit_conversion<float2, bool, float2_to_bool>(conversions);
add_implicit_conversion<float2, int8_t, float2_to_int8>(conversions);
add_implicit_conversion<float2, ColorGeometry4f, float2_to_color>(conversions);
+ add_implicit_conversion<float2, ColorGeometry4b, float2_to_byte_color>(conversions);
add_implicit_conversion<float3, bool, float3_to_bool>(conversions);
add_implicit_conversion<float3, int8_t, float3_to_int8>(conversions);
@@ -237,6 +298,7 @@ static DataTypeConversions create_implicit_conversions()
add_implicit_conversion<float3, int32_t, float3_to_int>(conversions);
add_implicit_conversion<float3, float2, float3_to_float2>(conversions);
add_implicit_conversion<float3, ColorGeometry4f, float3_to_color>(conversions);
+ add_implicit_conversion<float3, ColorGeometry4b, float3_to_byte_color>(conversions);
add_implicit_conversion<int32_t, bool, int_to_bool>(conversions);
add_implicit_conversion<int32_t, int8_t, int_to_int8>(conversions);
@@ -244,6 +306,7 @@ static DataTypeConversions create_implicit_conversions()
add_implicit_conversion<int32_t, float2, int_to_float2>(conversions);
add_implicit_conversion<int32_t, float3, int_to_float3>(conversions);
add_implicit_conversion<int32_t, ColorGeometry4f, int_to_color>(conversions);
+ add_implicit_conversion<int32_t, ColorGeometry4b, int_to_byte_color>(conversions);
add_implicit_conversion<int8_t, bool, int8_to_bool>(conversions);
add_implicit_conversion<int8_t, int32_t, int8_to_int>(conversions);
@@ -251,6 +314,7 @@ static DataTypeConversions create_implicit_conversions()
add_implicit_conversion<int8_t, float2, int8_to_float2>(conversions);
add_implicit_conversion<int8_t, float3, int8_to_float3>(conversions);
add_implicit_conversion<int8_t, ColorGeometry4f, int8_to_color>(conversions);
+ add_implicit_conversion<int8_t, ColorGeometry4b, int8_to_byte_color>(conversions);
add_implicit_conversion<bool, float, bool_to_float>(conversions);
add_implicit_conversion<bool, int8_t, bool_to_int8>(conversions);
@@ -258,6 +322,7 @@ static DataTypeConversions create_implicit_conversions()
add_implicit_conversion<bool, float2, bool_to_float2>(conversions);
add_implicit_conversion<bool, float3, bool_to_float3>(conversions);
add_implicit_conversion<bool, ColorGeometry4f, bool_to_color>(conversions);
+ add_implicit_conversion<bool, ColorGeometry4b, bool_to_byte_color>(conversions);
add_implicit_conversion<ColorGeometry4f, bool, color_to_bool>(conversions);
add_implicit_conversion<ColorGeometry4f, int8_t, color_to_int8>(conversions);
@@ -265,6 +330,15 @@ static DataTypeConversions create_implicit_conversions()
add_implicit_conversion<ColorGeometry4f, int32_t, color_to_int>(conversions);
add_implicit_conversion<ColorGeometry4f, float2, color_to_float2>(conversions);
add_implicit_conversion<ColorGeometry4f, float3, color_to_float3>(conversions);
+ add_implicit_conversion<ColorGeometry4f, ColorGeometry4b, color_to_byte_color>(conversions);
+
+ add_implicit_conversion<ColorGeometry4b, bool, byte_color_to_bool>(conversions);
+ add_implicit_conversion<ColorGeometry4b, int8_t, byte_color_to_int8>(conversions);
+ add_implicit_conversion<ColorGeometry4b, float, byte_color_to_float>(conversions);
+ add_implicit_conversion<ColorGeometry4b, int32_t, byte_color_to_int>(conversions);
+ add_implicit_conversion<ColorGeometry4b, float2, byte_color_to_float2>(conversions);
+ add_implicit_conversion<ColorGeometry4b, float3, byte_color_to_float3>(conversions);
+ add_implicit_conversion<ColorGeometry4b, ColorGeometry4f, byte_color_to_color>(conversions);
return conversions;
}
@@ -411,4 +485,19 @@ GVMutableArray DataTypeConversions::try_convert(GVMutableArray varray,
std::move(varray), to_type, *this);
}
+fn::GField DataTypeConversions::try_convert(fn::GField field, const CPPType &to_type) const
+{
+ const CPPType &from_type = field.cpp_type();
+ if (from_type == to_type) {
+ return field;
+ }
+ if (!this->is_convertible(from_type, to_type)) {
+ return {};
+ }
+ const fn::MultiFunction &fn =
+ *bke::get_implicit_type_conversions().get_conversion_multi_function(
+ fn::MFDataType::ForSingle(from_type), fn::MFDataType::ForSingle(to_type));
+ return {std::make_shared<fn::FieldOperation>(fn, Vector<fn::GField>{std::move(field)})};
+}
+
} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 0c131863edd..307466d7dc9 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -60,6 +60,7 @@ using blender::float3;
using blender::float4x4;
using blender::IndexRange;
using blender::StringRef;
+using blender::StringRefNull;
#ifdef WITH_OPENVDB
# include <atomic>
@@ -517,6 +518,8 @@ static void volume_init_data(ID *id)
MEMCPY_STRUCT_AFTER(volume, DNA_struct_default_get(Volume), id);
BKE_volume_init_grids(volume);
+
+ BLI_strncpy(volume->velocity_grid, "velocity", sizeof(volume->velocity_grid));
}
static void volume_copy_data(Main *UNUSED(bmain),
@@ -794,6 +797,57 @@ bool BKE_volume_is_loaded(const Volume *volume)
#endif
}
+bool BKE_volume_set_velocity_grid_by_name(Volume *volume, const char *base_name)
+{
+ const StringRefNull ref_base_name = base_name;
+
+ if (BKE_volume_grid_find_for_read(volume, base_name)) {
+ BLI_strncpy(volume->velocity_grid, base_name, sizeof(volume->velocity_grid));
+ volume->runtime.velocity_x_grid[0] = '\0';
+ volume->runtime.velocity_y_grid[0] = '\0';
+ volume->runtime.velocity_z_grid[0] = '\0';
+ return true;
+ }
+
+ /* It could be that the velocity grid is split in multiple grids, try with known postfixes. */
+ const StringRefNull postfixes[][3] = {{"x", "y", "z"}, {".x", ".y", ".z"}, {"_x", "_y", "_z"}};
+
+ for (const StringRefNull *postfix : postfixes) {
+ bool found = true;
+ for (int i = 0; i < 3; i++) {
+ std::string post_fixed_name = ref_base_name + postfix[i];
+ if (!BKE_volume_grid_find_for_read(volume, post_fixed_name.c_str())) {
+ found = false;
+ break;
+ }
+ }
+
+ if (!found) {
+ continue;
+ }
+
+ /* Save the base name as well. */
+ BLI_strncpy(volume->velocity_grid, base_name, sizeof(volume->velocity_grid));
+ BLI_strncpy(volume->runtime.velocity_x_grid,
+ (ref_base_name + postfix[0]).c_str(),
+ sizeof(volume->runtime.velocity_x_grid));
+ BLI_strncpy(volume->runtime.velocity_y_grid,
+ (ref_base_name + postfix[1]).c_str(),
+ sizeof(volume->runtime.velocity_y_grid));
+ BLI_strncpy(volume->runtime.velocity_z_grid,
+ (ref_base_name + postfix[2]).c_str(),
+ sizeof(volume->runtime.velocity_z_grid));
+ return true;
+ }
+
+ /* Reset to avoid potential issues. */
+ volume->velocity_grid[0] = '\0';
+ volume->runtime.velocity_x_grid[0] = '\0';
+ volume->runtime.velocity_y_grid[0] = '\0';
+ volume->runtime.velocity_z_grid[0] = '\0';
+ return false;
+}
+
bool BKE_volume_load(const Volume *volume, const Main *bmain)
{
#ifdef WITH_OPENVDB
@@ -857,6 +911,14 @@ bool BKE_volume_load(const Volume *volume, const Main *bmain)
}
}
+ /* Try to detect the velocity grid. */
+ const char *common_velocity_names[] = {"velocity", "vel", "v"};
+ for (const char *common_velocity_name : common_velocity_names) {
+ if (BKE_volume_set_velocity_grid_by_name(const_cast<Volume *>(volume), common_velocity_name)) {
+ break;
+ }
+ }
+
BLI_strncpy(grids.filepath, filepath, FILE_MAX);
return grids.error_msg.empty();
diff --git a/source/blender/blenkernel/intern/volume_to_mesh.cc b/source/blender/blenkernel/intern/volume_to_mesh.cc
index 8544d6c9c77..ef75d3d2482 100644
--- a/source/blender/blenkernel/intern/volume_to_mesh.cc
+++ b/source/blender/blenkernel/intern/volume_to_mesh.cc
@@ -183,7 +183,6 @@ Mesh *volume_to_mesh(const openvdb::GridBase &grid,
{mesh->mloop, mesh->totloop});
BKE_mesh_calc_edges(mesh, false, false);
- BKE_mesh_normals_tag_dirty(mesh);
return mesh;
}
diff --git a/source/blender/blenlib/BLI_color.hh b/source/blender/blenlib/BLI_color.hh
index 0754221eb65..98fd7d0f15d 100644
--- a/source/blender/blenlib/BLI_color.hh
+++ b/source/blender/blenlib/BLI_color.hh
@@ -345,5 +345,7 @@ BLI_color_convert_to_theme4b(const ColorSceneLinear4f<eAlpha::Straight> &scene_l
using ColorGeometry4f = ColorSceneLinear4f<eAlpha::Premultiplied>;
using ColorGeometry4b = ColorSceneLinearByteEncoded4b<eAlpha::Premultiplied>;
+using ColorPaint4f = ColorSceneLinear4f<eAlpha::Straight>;
+using ColorPaint4b = ColorSceneLinearByteEncoded4b<eAlpha::Straight>;
} // namespace blender
diff --git a/source/blender/blenlib/BLI_color_mix.hh b/source/blender/blenlib/BLI_color_mix.hh
new file mode 100644
index 00000000000..4989ddc609e
--- /dev/null
+++ b/source/blender/blenlib/BLI_color_mix.hh
@@ -0,0 +1,1051 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
+
+/** \file
+ * \ingroup blenlib
+ *
+ * Contains color mixing utilities.
+ */
+
+#include "BLI_color.hh"
+#include "BLI_math_base.h"
+#include "BLI_math_color.h"
+#include "BLI_sys_types.h"
+
+#include "IMB_colormanagement.h"
+#include "IMB_imbuf.h"
+
+#include <type_traits>
+
+namespace blender::color {
+
+struct ByteTraits {
+ using ValueType = uchar;
+ using BlendType = int;
+
+ inline static const uchar range = 255; /* Zero-based maximum value. */
+ inline static const float frange = 255.0f; /* Convenient floating-point version of range. */
+ inline static const int cmpRange = 254;
+ inline static const int expandedRange = 256; /* One-based maximum value. */
+
+ inline static const int bytes = 1;
+ inline static const float unit = 255.0f;
+
+ static inline BlendType divide_round(BlendType a, BlendType b)
+ {
+ return divide_round_i(a, b);
+ }
+
+ static inline BlendType min(BlendType a, BlendType b)
+ {
+ return min_ii(a, b);
+ }
+
+ static inline BlendType max(BlendType a, BlendType b)
+ {
+ return max_ii(a, b);
+ }
+ /* Discretizes in steps of 1.0 / range */
+ static inline ValueType round(float f)
+ {
+ return round_fl_to_uchar(f);
+ }
+};
+
+struct FloatTraits {
+ using ValueType = float;
+ using BlendType = float;
+
+ inline const static float range = 1.0f;
+ inline const static float frange = 1.0f;
+ inline const static float cmpRange = 0.9999f;
+ inline static const int expandedRange = 1.0f;
+
+ inline const static float unit = 1.0f;
+ inline const static int bytes = 4;
+
+ static inline BlendType divide_round(BlendType a, BlendType b)
+ {
+ return a / b;
+ }
+
+ static inline BlendType min(BlendType a, BlendType b)
+ {
+ return min_ff(a, b);
+ }
+
+ static inline BlendType max(BlendType a, BlendType b)
+ {
+ return min_ff(a, b);
+ }
+
+ /* Discretizes in steps of 1.0 / range */
+ static inline ValueType round(float f)
+ {
+ return f;
+ }
+};
+
+static float get_luminance(ColorPaint4f c)
+{
+ return IMB_colormanagement_get_luminance(&c.r);
+}
+
+static int get_luminance(ColorPaint4b c)
+{
+ return IMB_colormanagement_get_luminance_byte(&c.r);
+}
+
+#define EPS_SATURATION 0.0005f
+
+/* -------------------------------------------------------------------- */
+/** \name Color Blending Modes
+ * \{ */
+
+template<typename Color, typename Traits>
+static Color mix_blend(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Color col_mix(0, 0, 0, 0);
+ Blend mfac;
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ if (fac >= Traits::range) {
+ return col_dst;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = &col_src.r;
+ cp_dst = &col_dst.r;
+ cp_mix = &col_mix.r;
+
+ /* Updated to use the rgb squared color model which blends nicer. */
+ Blend r1 = cp_src[0] * cp_src[0];
+ Blend g1 = cp_src[1] * cp_src[1];
+ Blend b1 = cp_src[2] * cp_src[2];
+ Blend a1 = cp_src[3] * cp_src[3];
+
+ Blend r2 = cp_dst[0] * cp_dst[0];
+ Blend g2 = cp_dst[1] * cp_dst[1];
+ Blend b2 = cp_dst[2] * cp_dst[2];
+ Blend a2 = cp_dst[3] * cp_dst[3];
+
+ cp_mix[0] = Traits::round(sqrtf(Traits::divide_round((mfac * r1 + fac * r2), Traits::range)));
+ cp_mix[1] = Traits::round(sqrtf(Traits::divide_round((mfac * g1 + fac * g2), Traits::range)));
+ cp_mix[2] = Traits::round(sqrtf(Traits::divide_round((mfac * b1 + fac * b2), Traits::range)));
+ cp_mix[3] = Traits::round(sqrtf(Traits::divide_round((mfac * a1 + fac * a2), Traits::range)));
+ return Color(col_mix[0], col_mix[1], col_mix[2], col_mix[3]);
+
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_add(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend temp;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ cp_src = (Value *)&col_src.r;
+ cp_dst = (Value *)&col_dst.r;
+ cp_mix = (Value *)&col_mix.r;
+
+ temp = cp_src[0] + Traits::divide_round((fac * cp_dst[0]), Traits::range);
+ cp_mix[0] = (temp > Traits::cmpRange) ? Traits::range : temp;
+ temp = cp_src[1] + Traits::divide_round((fac * cp_dst[1]), Traits::range);
+ cp_mix[1] = (temp > Traits::cmpRange) ? Traits::range : temp;
+ temp = cp_src[2] + Traits::divide_round((fac * cp_dst[2]), Traits::range);
+ cp_mix[2] = (temp > Traits::cmpRange) ? Traits::range : temp;
+ temp = cp_src[3] + Traits::divide_round((fac * cp_dst[3]), Traits::range);
+ cp_mix[3] = (temp > Traits::cmpRange) ? Traits::range : temp;
+
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_sub(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend temp;
+ Color col_mix(0, 0, 0, 0);
+
+ cp_src = (Value *)&col_src.r;
+ cp_dst = (Value *)&col_dst.r;
+ cp_mix = (Value *)&col_mix.r;
+
+ temp = cp_src[0] - Traits::divide_round((fac * cp_dst[0]), Traits::range);
+ cp_mix[0] = (temp < 0) ? 0 : temp;
+ temp = cp_src[1] - Traits::divide_round((fac * cp_dst[1]), Traits::range);
+ cp_mix[1] = (temp < 0) ? 0 : temp;
+ temp = cp_src[2] - Traits::divide_round((fac * cp_dst[2]), Traits::range);
+ cp_mix[2] = (temp < 0) ? 0 : temp;
+ temp = cp_src[3] - Traits::divide_round((fac * cp_dst[3]), Traits::range);
+ cp_mix[3] = (temp < 0) ? 0 : temp;
+
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_mul(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ /* first mul, then blend the fac */
+ cp_mix[0] = Traits::divide_round(mfac * cp_src[0] * Traits::range + fac * cp_dst[0] * cp_src[0],
+ Traits::range * Traits::range);
+ cp_mix[1] = Traits::divide_round(mfac * cp_src[1] * Traits::range + fac * cp_dst[1] * cp_src[1],
+ Traits::range * Traits::range);
+ cp_mix[2] = Traits::divide_round(mfac * cp_src[2] * Traits::range + fac * cp_dst[2] * cp_src[2],
+ Traits::range * Traits::range);
+ cp_mix[3] = Traits::divide_round(mfac * cp_src[3] * Traits::range + fac * cp_dst[3] * cp_src[3],
+ Traits::range * Traits::range);
+
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_lighten(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+ if (fac >= Traits::range) {
+ return col_dst;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ /* See if we're lighter, if so mix, else don't do anything.
+ * if the paint color is darker then the original, then ignore */
+ if (get_luminance(cp_src) > get_luminance(cp_dst)) {
+ return col_src;
+ }
+
+ cp_mix[0] = Traits::divide_round(mfac * cp_src[0] + fac * cp_dst[0], Traits::range);
+ cp_mix[1] = Traits::divide_round(mfac * cp_src[1] + fac * cp_dst[1], Traits::range);
+ cp_mix[2] = Traits::divide_round(mfac * cp_src[2] + fac * cp_dst[2], Traits::range);
+ cp_mix[3] = Traits::divide_round(mfac * cp_src[3] + fac * cp_dst[3], Traits::range);
+
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_darken(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+ if (fac >= Traits::range) {
+ return col_dst;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ /* See if we're darker, if so mix, else don't do anything.
+ * if the paint color is brighter then the original, then ignore */
+ if (get_luminance(cp_src) < get_luminance(cp_dst)) {
+ return col_src;
+ }
+
+ cp_mix[0] = Traits::divide_round((mfac * cp_src[0] + fac * cp_dst[0]), Traits::range);
+ cp_mix[1] = Traits::divide_round((mfac * cp_src[1] + fac * cp_dst[1]), Traits::range);
+ cp_mix[2] = Traits::divide_round((mfac * cp_src[2] + fac * cp_dst[2]), Traits::range);
+ cp_mix[3] = Traits::divide_round((mfac * cp_src[3] + fac * cp_dst[3]), Traits::range);
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_colordodge(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac, temp;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ Blend dodgefac = (Blend)((float)Traits::range * 0.885f); /* ~225/255 */
+
+ temp = (cp_dst[0] == Traits::range) ?
+ Traits::range :
+ Traits::min((cp_src[0] * dodgefac) / (Traits::range - cp_dst[0]), Traits::range);
+ cp_mix[0] = (mfac * cp_src[0] + temp * fac) / Traits::range;
+ temp = (cp_dst[1] == Traits::range) ?
+ Traits::range :
+ Traits::min((cp_src[1] * dodgefac) / (Traits::range - cp_dst[1]), Traits::range);
+ cp_mix[1] = (mfac * cp_src[1] + temp * fac) / Traits::range;
+ temp = (cp_dst[2] == Traits::range) ?
+ Traits::range :
+ Traits::min((cp_src[2] * dodgefac) / (Traits::range - cp_dst[2]), Traits::range);
+ cp_mix[2] = (mfac * cp_src[2] + temp * fac) / Traits::range;
+ temp = (cp_dst[3] == Traits::range) ?
+ Traits::range :
+ Traits::min((cp_src[3] * dodgefac) / (Traits::range - cp_dst[3]), Traits::range);
+ cp_mix[3] = (mfac * cp_src[3] + temp * fac) / Traits::range;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_difference(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac, temp;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ temp = abs(cp_src[0] - cp_dst[0]);
+ cp_mix[0] = (mfac * cp_src[0] + temp * fac) / Traits::range;
+ temp = abs(cp_src[1] - cp_dst[1]);
+ cp_mix[1] = (mfac * cp_src[1] + temp * fac) / Traits::range;
+ temp = abs(cp_src[2] - cp_dst[2]);
+ cp_mix[2] = (mfac * cp_src[2] + temp * fac) / Traits::range;
+ temp = abs(cp_src[3] - cp_dst[3]);
+ cp_mix[3] = (mfac * cp_src[3] + temp * fac) / Traits::range;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_screen(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac, temp;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ temp = Traits::max(Traits::range - (((Traits::range - cp_src[0]) * (Traits::range - cp_dst[0])) /
+ Traits::range),
+ 0);
+ cp_mix[0] = (mfac * cp_src[0] + temp * fac) / Traits::range;
+ temp = Traits::max(Traits::range - (((Traits::range - cp_src[1]) * (Traits::range - cp_dst[1])) /
+ Traits::range),
+ 0);
+ cp_mix[1] = (mfac * cp_src[1] + temp * fac) / Traits::range;
+ temp = Traits::max(Traits::range - (((Traits::range - cp_src[2]) * (Traits::range - cp_dst[2])) /
+ Traits::range),
+ 0);
+ cp_mix[2] = (mfac * cp_src[2] + temp * fac) / Traits::range;
+ temp = Traits::max(Traits::range - (((Traits::range - cp_src[3]) * (Traits::range - cp_dst[3])) /
+ Traits::range),
+ 0);
+ cp_mix[3] = (mfac * cp_src[3] + temp * fac) / Traits::range;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_hardlight(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac, temp;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ int i = 0;
+
+ for (i = 0; i < 4; i++) {
+ if (cp_dst[i] > (Traits::range / 2)) {
+ temp = Traits::range - ((Traits::range - 2 * (cp_dst[i] - (Traits::range / 2))) *
+ (Traits::range - cp_src[i]) / Traits::range);
+ }
+ else {
+ temp = (2 * cp_dst[i] * cp_src[i]) / Traits::expandedRange;
+ }
+ cp_mix[i] = Traits::min((mfac * cp_src[i] + temp * fac) / Traits::range, Traits::range);
+ }
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_overlay(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac, temp;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ int i = 0;
+
+ for (i = 0; i < 4; i++) {
+ if (cp_src[i] > (Traits::range / 2)) {
+ temp = Traits::range - ((Traits::range - 2 * (cp_src[i] - (Traits::range / 2))) *
+ (Traits::range - cp_dst[i]) / Traits::range);
+ }
+ else {
+ temp = (2 * cp_dst[i] * cp_src[i]) / Traits::expandedRange;
+ }
+ cp_mix[i] = Traits::min((mfac * cp_src[i] + temp * fac) / Traits::range, Traits::range);
+ }
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_softlight(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac, temp;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ /* Use divide_round so we don't alter original byte equations. */
+ const int add = Traits::divide_round(Traits::range, 4);
+
+ for (int i = 0; i < 4; i++) {
+ if (cp_src[i] < (Traits::range / 2)) {
+ temp = ((2 * ((cp_dst[i] / 2) + add)) * cp_src[i]) / Traits::range;
+ }
+ else {
+ temp = Traits::range - (2 * (Traits::range - ((cp_dst[i] / 2) + add)) *
+ (Traits::range - cp_src[i]) / Traits::range);
+ }
+ cp_mix[i] = (temp * fac + cp_src[i] * mfac) / Traits::range;
+ }
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_exclusion(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac, temp;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ int i = 0;
+
+ for (i = 0; i < 4; i++) {
+ temp = (Traits::range / 2) -
+ ((2 * (cp_src[i] - (Traits::range / 2)) * (cp_dst[i] - (Traits::range / 2))) /
+ Traits::range);
+ cp_mix[i] = (temp * fac + cp_src[i] * mfac) / Traits::range;
+ }
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_luminosity(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+ rgb_to_hsv(cp_src[0] / Traits::frange,
+ cp_src[1] / Traits::frange,
+ cp_src[2] / Traits::frange,
+ &h1,
+ &s1,
+ &v1);
+ rgb_to_hsv(cp_dst[0] / Traits::frange,
+ cp_dst[1] / Traits::frange,
+ cp_dst[2] / Traits::frange,
+ &h2,
+ &s2,
+ &v2);
+
+ v1 = v2;
+
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+ cp_mix[0] = ((Blend)(r * Traits::frange) * fac + mfac * cp_src[0]) / Traits::range;
+ cp_mix[1] = ((Blend)(g * Traits::frange) * fac + mfac * cp_src[1]) / Traits::range;
+ cp_mix[2] = ((Blend)(b * Traits::frange) * fac + mfac * cp_src[2]) / Traits::range;
+ cp_mix[3] = ((Blend)(cp_dst[3]) * fac + mfac * cp_src[3]) / Traits::range;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_saturation(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+ rgb_to_hsv(cp_src[0] / Traits::frange,
+ cp_src[1] / Traits::frange,
+ cp_src[2] / Traits::frange,
+ &h1,
+ &s1,
+ &v1);
+ rgb_to_hsv(cp_dst[0] / Traits::frange,
+ cp_dst[1] / Traits::frange,
+ cp_dst[2] / Traits::frange,
+ &h2,
+ &s2,
+ &v2);
+
+ if (s1 > EPS_SATURATION) {
+ s1 = s2;
+ }
+
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+ cp_mix[0] = ((Blend)(r * Traits::frange) * fac + mfac * cp_src[0]) / Traits::range;
+ cp_mix[1] = ((Blend)(g * Traits::frange) * fac + mfac * cp_src[1]) / Traits::range;
+ cp_mix[2] = ((Blend)(b * Traits::frange) * fac + mfac * cp_src[2]) / Traits::range;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_hue(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+ rgb_to_hsv(cp_src[0] / Traits::frange,
+ cp_src[1] / Traits::frange,
+ cp_src[2] / Traits::frange,
+ &h1,
+ &s1,
+ &v1);
+ rgb_to_hsv(cp_dst[0] / Traits::frange,
+ cp_dst[1] / Traits::frange,
+ cp_dst[2] / Traits::frange,
+ &h2,
+ &s2,
+ &v2);
+
+ h1 = h2;
+
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+ cp_mix[0] = ((Blend)(r * Traits::frange) * fac + mfac * cp_src[0]) / Traits::range;
+ cp_mix[1] = ((Blend)(g * Traits::frange) * fac + mfac * cp_src[1]) / Traits::range;
+ cp_mix[2] = ((Blend)(b * Traits::frange) * fac + mfac * cp_src[2]) / Traits::range;
+ cp_mix[3] = ((Blend)(cp_dst[3]) * fac + mfac * cp_src[3]) / Traits::range;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_alpha_add(Color col_src, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_mix;
+ Blend temp;
+ Color col_mix = col_src;
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ cp_src = (Value *)&col_src;
+ cp_mix = (Value *)&col_mix;
+
+ temp = cp_src[3] + fac;
+ cp_mix[3] = (temp > Traits::cmpRange) ? Traits::range : temp;
+
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_alpha_sub(Color col_src, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_mix;
+ Blend temp;
+ Color col_mix = col_src;
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ cp_src = (Value *)&col_src;
+ cp_mix = (Value *)&col_mix;
+
+ temp = cp_src[3] - fac;
+ cp_mix[3] = temp < 0 ? 0 : temp;
+
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_pinlight(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ const Blend cmp = Traits::range / 2;
+
+ int i = 3;
+ Blend temp;
+
+ while (i--) {
+ if (cp_dst[i] > cmp) {
+ temp = Traits::max(2 * (cp_dst[i] - cmp), cp_src[i]);
+ }
+ else {
+ temp = Traits::min(2 * cp_dst[i], cp_src[i]);
+ }
+ cp_mix[i] = (Value)((Traits::min(temp, Traits::range) * fac + cp_src[i] * mfac) /
+ Traits::range);
+ }
+
+ col_mix.a = col_src.a;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_linearlight(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ const Blend cmp = Traits::range / 2;
+
+ int i = 3;
+ while (i--) {
+ Blend temp;
+
+ if (cp_dst[i] > cmp) {
+ temp = Traits::min(cp_src[i] + 2 * (cp_dst[i] - cmp), Traits::range);
+ }
+ else {
+ temp = Traits::max(cp_src[i] + 2 * cp_dst[i] - Traits::range, 0);
+ }
+
+ cp_mix[i] = (Value)((temp * fac + cp_src[i] * mfac) / Traits::range);
+ }
+
+ col_mix.a = col_src.a;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_vividlight(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+
+ const Blend cmp = Traits::range / 2;
+
+ int i = 3;
+
+ while (i--) {
+ Blend temp;
+
+ if (cp_dst[i] == Traits::range) {
+ temp = (cp_src[i] == 0) ? cmp : Traits::range;
+ }
+ else if (cp_dst[i] == 0) {
+ temp = (cp_src[i] == Traits::range) ? cmp : 0;
+ }
+ else if (cp_dst[i] > cmp) {
+ temp = Traits::min(((cp_src[i]) * Traits::range) / (2 * (Traits::range - cp_dst[i])),
+ Traits::range);
+ }
+ else {
+ temp = Traits::max(
+ Traits::range - ((Traits::range - cp_src[i]) * Traits::range / (2 * cp_dst[i])), 0);
+ }
+ col_mix[i] = (Value)((temp * fac + cp_src[i] * mfac) / Traits::range);
+ }
+
+ col_mix.a = col_src.a;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_color(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+
+ rgb_to_hsv(cp_src[0] / Traits::frange,
+ cp_src[1] / Traits::frange,
+ cp_src[2] / Traits::frange,
+ &h1,
+ &s1,
+ &v1);
+ rgb_to_hsv(cp_dst[0] / Traits::frange,
+ cp_dst[1] / Traits::frange,
+ cp_dst[2] / Traits::frange,
+ &h2,
+ &s2,
+ &v2);
+
+ h1 = h2;
+ s1 = s2;
+
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+ cp_mix[0] = (Value)(((Blend)(r * Traits::frange) * fac + cp_src[0] * mfac) / Traits::range);
+ cp_mix[1] = (Value)(((Blend)(g * Traits::frange) * fac + cp_src[1] * mfac) / Traits::range);
+ cp_mix[2] = (Value)(((Blend)(b * Traits::frange) * fac + cp_src[2] * mfac) / Traits::range);
+
+ col_mix.a = col_src.a;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_colorburn(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ int i = 3;
+
+ while (i--) {
+ const Blend temp =
+ (cp_dst[i] == 0) ?
+ 0 :
+ Traits::max(Traits::range - ((Traits::range - cp_src[i]) * Traits::range) / cp_dst[i],
+ 0);
+ cp_mix[i] = (Value)((temp * fac + cp_src[i] * mfac) / Traits::range);
+ }
+
+ col_mix.a = col_src.a;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_linearburn(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ int i = 3;
+
+ while (i--) {
+ const Blend temp = Traits::max(cp_src[i] + cp_dst[i] - Traits::range, 0);
+ cp_mix[i] = (Value)((temp * fac + cp_src[i] * mfac) / Traits::range);
+ }
+
+ col_mix.a = col_src.a;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+BLI_INLINE Color BLI_mix_colors(const IMB_BlendMode tool,
+ const Color a,
+ const Color b,
+ const typename Traits::BlendType alpha)
+{
+ switch ((IMB_BlendMode)tool) {
+ case IMB_BLEND_MIX:
+ return mix_blend<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_ADD:
+ return mix_add<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_SUB:
+ return mix_sub<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_MUL:
+ return mix_mul<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_LIGHTEN:
+ return mix_lighten<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_DARKEN:
+ return mix_darken<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_COLORDODGE:
+ return mix_colordodge<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_COLORBURN:
+ return mix_colorburn<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_DIFFERENCE:
+ return mix_difference<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_SCREEN:
+ return mix_screen<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_HARDLIGHT:
+ return mix_hardlight<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_OVERLAY:
+ return mix_overlay<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_SOFTLIGHT:
+ return mix_softlight<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_EXCLUSION:
+ return mix_exclusion<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_LUMINOSITY:
+ return mix_luminosity<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_SATURATION:
+ return mix_saturation<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_HUE:
+ return mix_hue<Color, Traits>(a, b, alpha);
+ /* non-color */
+ case IMB_BLEND_ERASE_ALPHA:
+ return mix_alpha_sub<Color, Traits>(a, alpha);
+ case IMB_BLEND_ADD_ALPHA:
+ return mix_alpha_add<Color, Traits>(a, alpha);
+ case IMB_BLEND_PINLIGHT:
+ return mix_pinlight<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_LINEARLIGHT:
+ return mix_linearlight<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_VIVIDLIGHT:
+ return mix_vividlight<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_COLOR:
+ return mix_color<Color, Traits>(a, b, alpha);
+ default:
+ BLI_assert(0);
+ return Color(0, 0, 0, 0);
+ }
+}
+/** \} */
+
+} // namespace blender::color
diff --git a/source/blender/blenlib/BLI_generic_virtual_array.hh b/source/blender/blenlib/BLI_generic_virtual_array.hh
index 4aed1caf796..2e756e912f9 100644
--- a/source/blender/blenlib/BLI_generic_virtual_array.hh
+++ b/source/blender/blenlib/BLI_generic_virtual_array.hh
@@ -854,14 +854,14 @@ template<typename T> inline GVArray::GVArray(const VArray<T> &varray)
if (varray.may_have_ownership()) {
*this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray);
}
- else if (varray.is_span()) {
- Span<T> data = varray.get_internal_span();
- *this = GVArray::ForSpan(data);
- }
else if (varray.is_single()) {
T value = varray.get_internal_single();
*this = GVArray::ForSingle(CPPType::get<T>(), varray.size(), &value);
}
+ else if (varray.is_span()) {
+ Span<T> data = varray.get_internal_span();
+ *this = GVArray::ForSpan(data);
+ }
else {
*this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray);
}
@@ -880,15 +880,15 @@ template<typename T> inline VArray<T> GVArray::typed() const
if (this->may_have_ownership()) {
return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this);
}
- if (this->is_span()) {
- const Span<T> span = this->get_internal_span().typed<T>();
- return VArray<T>::ForSpan(span);
- }
if (this->is_single()) {
T value;
this->get_internal_single(&value);
return VArray<T>::ForSingle(value, this->size());
}
+ if (this->is_span()) {
+ const Span<T> span = this->get_internal_span().typed<T>();
+ return VArray<T>::ForSpan(span);
+ }
return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this);
}
diff --git a/source/blender/blenlib/BLI_math_base.hh b/source/blender/blenlib/BLI_math_base.hh
index 83f414f853a..81f5343056e 100644
--- a/source/blender/blenlib/BLI_math_base.hh
+++ b/source/blender/blenlib/BLI_math_base.hh
@@ -102,7 +102,10 @@ template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))> inline T fract(cons
return a - std::floor(a);
}
-template<typename T, typename FactorT, BLI_ENABLE_IF((is_math_float_type<FactorT>))>
+template<typename T,
+ typename FactorT,
+ BLI_ENABLE_IF((std::is_arithmetic_v<T>)),
+ BLI_ENABLE_IF((is_math_float_type<FactorT>))>
inline T interpolate(const T &a, const T &b, const FactorT &t)
{
return a * (1 - t) + b * t;
diff --git a/source/blender/blenlib/BLI_math_color.hh b/source/blender/blenlib/BLI_math_color.hh
index 5195cfb6238..b16053509cf 100644
--- a/source/blender/blenlib/BLI_math_color.hh
+++ b/source/blender/blenlib/BLI_math_color.hh
@@ -15,9 +15,22 @@
namespace blender::math {
-inline ColorGeometry4f interpolate(const ColorGeometry4f &a,
- const ColorGeometry4f &b,
- const float t)
+template<eAlpha Alpha>
+inline ColorSceneLinear4f<Alpha> interpolate(const ColorSceneLinear4f<Alpha> &a,
+ const ColorSceneLinear4f<Alpha> &b,
+ const float t)
+{
+ return {math::interpolate(a.r, b.r, t),
+ math::interpolate(a.g, b.g, t),
+ math::interpolate(a.b, b.b, t),
+ math::interpolate(a.a, b.a, t)};
+}
+
+template<eAlpha Alpha>
+inline ColorSceneLinearByteEncoded4b<Alpha> interpolate(
+ const ColorSceneLinearByteEncoded4b<Alpha> &a,
+ const ColorSceneLinearByteEncoded4b<Alpha> &b,
+ const float t)
{
return {math::interpolate(a.r, b.r, t),
math::interpolate(a.g, b.g, t),
diff --git a/source/blender/blenlib/BLI_math_vec_types.hh b/source/blender/blenlib/BLI_math_vec_types.hh
index 0850864d86f..e36bbedee32 100644
--- a/source/blender/blenlib/BLI_math_vec_types.hh
+++ b/source/blender/blenlib/BLI_math_vec_types.hh
@@ -201,6 +201,14 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size>
}
}
+ template<typename U, BLI_ENABLE_IF((std::is_convertible_v<U, T>))>
+ explicit vec_base(const U *ptr)
+ {
+ for (int i = 0; i < Size; i++) {
+ (*this)[i] = ptr[i];
+ }
+ }
+
vec_base(const T (*ptr)[Size]) : vec_base(static_cast<const T *>(ptr[0]))
{
}
diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh
index 27bb04f5796..453ca67b1e0 100644
--- a/source/blender/blenlib/BLI_virtual_array.hh
+++ b/source/blender/blenlib/BLI_virtual_array.hh
@@ -780,9 +780,6 @@ template<typename T> class VArrayCommon {
Span<T> get_internal_span() const
{
BLI_assert(this->is_span());
- if (this->is_empty()) {
- return {};
- }
return impl_->get_internal_span();
}
@@ -800,9 +797,6 @@ template<typename T> class VArrayCommon {
T get_internal_single() const
{
BLI_assert(this->is_single());
- if (impl_->size() == 1) {
- return impl_->get(0);
- }
return impl_->get_internal_single();
}
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index e8a3851e082..446a027b03b 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -171,6 +171,7 @@ set(SRC
BLI_boxpack_2d.h
BLI_buffer.h
BLI_color.hh
+ BLI_color_mix.hh
BLI_compiler_attrs.h
BLI_compiler_compat.h
BLI_compiler_typecheck.h
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index 26a0479f445..5ca6fe2efd0 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -301,56 +301,60 @@ static bool delete_soft(const wchar_t *path_16, const char **error_message)
/* Deletes file or directory to recycling bin. The latter moves all contained files and
* directories recursively to the recycling bin as well. */
IFileOperation *pfo;
- IShellItem *pSI;
+ IShellItem *psi;
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
- if (FAILED(hr)) {
- *error_message = "Failed to initialize COM";
- goto error_1;
- }
-
- hr = CoCreateInstance(
- &CLSID_FileOperation, NULL, CLSCTX_ALL, &IID_IFileOperation, (void **)&pfo);
- if (FAILED(hr)) {
- *error_message = "Failed to create FileOperation instance";
- goto error_2;
- }
-
- /* Flags for deletion:
- * FOF_ALLOWUNDO: Enables moving file to recycling bin.
- * FOF_SILENT: Don't show progress dialog box.
- * FOF_WANTNUKEWARNING: Show dialog box if file can't be moved to recycling bin. */
- hr = pfo->lpVtbl->SetOperationFlags(pfo, FOF_ALLOWUNDO | FOF_SILENT | FOF_WANTNUKEWARNING);
-
- if (FAILED(hr)) {
- *error_message = "Failed to set operation flags";
- goto error_2;
- }
-
- hr = SHCreateItemFromParsingName(path_16, NULL, &IID_IShellItem, (void **)&pSI);
- if (FAILED(hr)) {
- *error_message = "Failed to parse path";
- goto error_2;
- }
-
- hr = pfo->lpVtbl->DeleteItem(pfo, pSI, NULL);
- if (FAILED(hr)) {
- *error_message = "Failed to prepare delete operation";
- goto error_2;
+ if (SUCCEEDED(hr)) {
+ /* This is also the case when COM was previously initialized and CoInitializeEx returns
+ * S_FALSE, which is not an error. Both HRESULT values S_OK and S_FALSE indicate success. */
+
+ hr = CoCreateInstance(
+ &CLSID_FileOperation, NULL, CLSCTX_ALL, &IID_IFileOperation, (void **)&pfo);
+
+ if (SUCCEEDED(hr)) {
+ /* Flags for deletion:
+ * FOF_ALLOWUNDO: Enables moving file to recycling bin.
+ * FOF_SILENT: Don't show progress dialog box.
+ * FOF_WANTNUKEWARNING: Show dialog box if file can't be moved to recycling bin. */
+ hr = pfo->lpVtbl->SetOperationFlags(pfo, FOF_ALLOWUNDO | FOF_SILENT | FOF_WANTNUKEWARNING);
+
+ if (SUCCEEDED(hr)) {
+ hr = SHCreateItemFromParsingName(path_16, NULL, &IID_IShellItem, (void **)&psi);
+
+ if (SUCCEEDED(hr)) {
+ hr = pfo->lpVtbl->DeleteItem(pfo, psi, NULL);
+
+ if (SUCCEEDED(hr)) {
+ hr = pfo->lpVtbl->PerformOperations(pfo);
+
+ if (FAILED(hr)) {
+ *error_message = "Failed to prepare delete operation";
+ }
+ }
+ else {
+ *error_message = "Failed to prepare delete operation";
+ }
+ psi->lpVtbl->Release(psi);
+ }
+ else {
+ *error_message = "Failed to parse path";
+ }
+ }
+ else {
+ *error_message = "Failed to set operation flags";
+ }
+ pfo->lpVtbl->Release(pfo);
+ }
+ else {
+ *error_message = "Failed to create FileOperation instance";
+ }
+ CoUninitialize();
}
-
- hr = pfo->lpVtbl->PerformOperations(pfo);
-
- if (FAILED(hr)) {
- *error_message = "Failed to delete file or directory";
+ else {
+ *error_message = "Failed to initialize COM";
}
-error_2:
- pfo->lpVtbl->Release(pfo);
- CoUninitialize(); /* Has to be uninitialized when CoInitializeEx returns either S_OK or S_FALSE
- */
-error_1:
return FAILED(hr);
}
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 655dc297c35..e4a93762da4 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -357,7 +357,7 @@ static void do_versions_mesh_mloopcol_swap_2_62_1(Mesh *me)
for (a = 0; a < me->ldata.totlayer; a++) {
layer = &me->ldata.layers[a];
- if (layer->type == CD_MLOOPCOL) {
+ if (layer->type == CD_PROP_BYTE_COLOR) {
mloopcol = (MLoopCol *)layer->data;
for (i = 0; i < me->totloop; i++, mloopcol++) {
SWAP(uchar, mloopcol->r, mloopcol->b);
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 0996b35c8ea..d992d426b9a 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -1620,11 +1620,6 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
/* Deprecated, only kept for conversion. */
BKE_mesh_tessface_clear(me);
-
- /* Moved from do_versions because we need updated polygons for calculating normals. */
- if (!MAIN_VERSION_ATLEAST(bmain, 256, 6)) {
- BKE_mesh_calc_normals(me);
- }
}
}
@@ -1931,7 +1926,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- /* Grease pencil multiframe falloff curve */
+ /* Grease pencil multi-frame falloff curve. */
if (!DNA_struct_elem_find(
fd->filesdna, "GP_Sculpt_Settings", "CurveMapping", "cur_falloff")) {
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index ec60183218c..f0055fb73ac 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -2448,6 +2448,54 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
+ /* Rebuild active/render color attribute references. */
+ if (!MAIN_VERSION_ATLEAST(bmain, 302, 6)) {
+ LISTBASE_FOREACH (Brush *, br, &bmain->brushes) {
+ /* buggy code in wm_toolsystem broke smear in old files,
+ reset to defaults */
+ if (br->sculpt_tool == SCULPT_TOOL_SMEAR) {
+ br->alpha = 1.0f;
+ br->spacing = 5;
+ br->flag &= ~BRUSH_ALPHA_PRESSURE;
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ br->curve_preset = BRUSH_CURVE_SPHERE;
+ }
+ }
+
+ LISTBASE_FOREACH (Mesh *, me, &bmain->meshes) {
+ for (int step = 0; step < 2; step++) {
+ CustomDataLayer *actlayer = NULL;
+
+ int vact1, vact2;
+
+ if (step) {
+ vact1 = CustomData_get_render_layer_index(&me->vdata, CD_PROP_COLOR);
+ vact2 = CustomData_get_render_layer_index(&me->ldata, CD_PROP_BYTE_COLOR);
+ }
+ else {
+ vact1 = CustomData_get_active_layer_index(&me->vdata, CD_PROP_COLOR);
+ vact2 = CustomData_get_active_layer_index(&me->ldata, CD_PROP_BYTE_COLOR);
+ }
+
+ if (vact1 != -1) {
+ actlayer = me->vdata.layers + vact1;
+ }
+ else if (vact2 != -1) {
+ actlayer = me->ldata.layers + vact2;
+ }
+
+ if (actlayer) {
+ if (step) {
+ BKE_id_attributes_render_color_set(&me->id, actlayer);
+ }
+ else {
+ BKE_id_attributes_active_color_set(&me->id, actlayer);
+ }
+ }
+ }
+ }
+ }
+
if (!MAIN_VERSION_ATLEAST(bmain, 302, 7)) {
/* Generate 'system' liboverrides IDs.
* NOTE: This is a fairly rough process, based on very basic heuristics. Should be enough for a
@@ -2481,12 +2529,6 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
brush->curves_sculpt_settings = MEM_callocN(sizeof(BrushCurvesSculptSettings), __func__);
brush->curves_sculpt_settings->add_amount = 1;
}
- LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
- if (scene->toolsettings && scene->toolsettings->curves_sculpt &&
- scene->toolsettings->curves_sculpt->curve_length == 0.0f) {
- scene->toolsettings->curves_sculpt->curve_length = 0.3f;
- }
- }
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
@@ -2590,11 +2632,11 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (step) {
vact1 = CustomData_get_render_layer_index(&me->vdata, CD_PROP_COLOR);
- vact2 = CustomData_get_render_layer_index(&me->ldata, CD_MLOOPCOL);
+ vact2 = CustomData_get_render_layer_index(&me->ldata, CD_PROP_BYTE_COLOR);
}
else {
vact1 = CustomData_get_active_layer_index(&me->vdata, CD_PROP_COLOR);
- vact2 = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPCOL);
+ vact2 = CustomData_get_active_layer_index(&me->ldata, CD_PROP_BYTE_COLOR);
}
if (vact1 != -1) {
@@ -2689,5 +2731,15 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
+
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
+ BrushCurvesSculptSettings *settings = brush->curves_sculpt_settings;
+ if (settings == NULL) {
+ continue;
+ }
+ if (settings->curve_length == 0.0f) {
+ settings->curve_length = 0.3f;
+ }
+ }
}
}
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index b9491a4913b..0246850123a 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -506,6 +506,17 @@ typedef bool (*BMLoopPairFilterFunc)(const BMLoop *, const BMLoop *, void *user_
#define BM_ELEM_CD_GET_INT(ele, offset) \
(BLI_assert(offset != -1), *((int *)((char *)(ele)->head.data + (offset))))
+#define BM_ELEM_CD_SET_BOOL(ele, offset, f) \
+ { \
+ CHECK_TYPE_NONCONST(ele); \
+ BLI_assert(offset != -1); \
+ *((bool *)((char *)(ele)->head.data + (offset))) = (f); \
+ } \
+ (void)0
+
+#define BM_ELEM_CD_GET_BOOL(ele, offset) \
+ (BLI_assert(offset != -1), *((bool *)((char *)(ele)->head.data + (offset))))
+
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
# define BM_ELEM_CD_GET_VOID_P(ele, offset) \
(BLI_assert(offset != -1), \
@@ -530,6 +541,64 @@ typedef bool (*BMLoopPairFilterFunc)(const BMLoop *, const BMLoop *, void *user_
#define BM_ELEM_CD_GET_FLOAT(ele, offset) \
(BLI_assert(offset != -1), *((float *)((char *)(ele)->head.data + (offset))))
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+
+# define BM_ELEM_CD_GET_FLOAT_P(ele, offset) \
+ (BLI_assert(offset != -1), \
+ _Generic(ele, \
+ GENERIC_TYPE_ANY((float *)POINTER_OFFSET((ele)->head.data, offset), \
+ _BM_GENERIC_TYPE_ELEM_NONCONST), \
+ GENERIC_TYPE_ANY((const float *)POINTER_OFFSET((ele)->head.data, offset), \
+ _BM_GENERIC_TYPE_ELEM_CONST)))
+
+# define BM_ELEM_CD_GET_FLOAT2_P(ele, offset) \
+ (BLI_assert(offset != -1), \
+ _Generic(ele, \
+ GENERIC_TYPE_ANY((float(*)[2])POINTER_OFFSET((ele)->head.data, offset), \
+ _BM_GENERIC_TYPE_ELEM_NONCONST), \
+ GENERIC_TYPE_ANY((const float(*)[2])POINTER_OFFSET((ele)->head.data, offset), \
+ _BM_GENERIC_TYPE_ELEM_CONST)))
+
+# define BM_ELEM_CD_GET_FLOAT3_P(ele, offset) \
+ (BLI_assert(offset != -1), \
+ _Generic(ele, \
+ GENERIC_TYPE_ANY((float(*)[3])POINTER_OFFSET((ele)->head.data, offset), \
+ _BM_GENERIC_TYPE_ELEM_NONCONST), \
+ GENERIC_TYPE_ANY((const float(*)[3])POINTER_OFFSET((ele)->head.data, offset), \
+ _BM_GENERIC_TYPE_ELEM_CONST)))
+
+#else
+
+# define BM_ELEM_CD_GET_FLOAT_P(ele, offset) \
+ (BLI_assert(offset != -1), (float *)((char *)(ele)->head.data + (offset)))
+
+# define BM_ELEM_CD_GET_FLOAT2_P(ele, offset) \
+ (BLI_assert(offset != -1), (float(*)[2])((char *)(ele)->head.data + (offset)))
+
+# define BM_ELEM_CD_GET_FLOAT3_P(ele, offset) \
+ (BLI_assert(offset != -1), (float(*)[3])((char *)(ele)->head.data + (offset)))
+
+#endif
+
+#define BM_ELEM_CD_SET_FLOAT2(ele, offset, f) \
+ { \
+ CHECK_TYPE_NONCONST(ele); \
+ BLI_assert(offset != -1); \
+ ((float *)((char *)(ele)->head.data + (offset)))[0] = (f)[0]; \
+ ((float *)((char *)(ele)->head.data + (offset)))[1] = (f)[1]; \
+ } \
+ (void)0
+
+#define BM_ELEM_CD_SET_FLOAT3(ele, offset, f) \
+ { \
+ CHECK_TYPE_NONCONST(ele); \
+ BLI_assert(offset != -1); \
+ ((float *)((char *)(ele)->head.data + (offset)))[0] = (f)[0]; \
+ ((float *)((char *)(ele)->head.data + (offset)))[1] = (f)[1]; \
+ ((float *)((char *)(ele)->head.data + (offset)))[2] = (f)[2]; \
+ } \
+ (void)0
+
#define BM_ELEM_CD_GET_FLOAT_AS_UCHAR(ele, offset) \
(BLI_assert(offset != -1), (uchar)(BM_ELEM_CD_GET_FLOAT(ele, offset) * 255.0f))
diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c
index 35614069f96..aa7f0f511ec 100644
--- a/source/blender/bmesh/operators/bmo_join_triangles.c
+++ b/source/blender/bmesh/operators/bmo_join_triangles.c
@@ -282,7 +282,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
delimit_data.cdata[delimit_data.cdata_len].cd_offset = -1;
if (BMO_slot_bool_get(op->slots_in, "cmp_vcols") &&
bm_edge_delimit_cdata(
- &bm->ldata, CD_MLOOPCOL, &delimit_data.cdata[delimit_data.cdata_len])) {
+ &bm->ldata, CD_PROP_BYTE_COLOR, &delimit_data.cdata[delimit_data.cdata_len])) {
delimit_data.cdata_len += 1;
}
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index be5521d45ab..8f32f878c58 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -675,7 +675,7 @@ static BMFace *bev_create_ngon(BMesh *bm,
const int totv,
BMFace **face_arr,
BMFace *facerep,
- BMEdge **edge_arr,
+ BMEdge **snap_edge_arr,
int mat_nr,
bool do_interp)
{
@@ -699,8 +699,8 @@ static BMFace *bev_create_ngon(BMesh *bm,
}
if (interp_f) {
BMEdge *bme = NULL;
- if (edge_arr) {
- bme = edge_arr[i];
+ if (snap_edge_arr) {
+ bme = snap_edge_arr[i];
}
float save_co[3];
if (bme) {
@@ -734,44 +734,6 @@ static BMFace *bev_create_ngon(BMesh *bm,
return f;
}
-static BMFace *bev_create_quad(BMesh *bm,
- BMVert *v1,
- BMVert *v2,
- BMVert *v3,
- BMVert *v4,
- BMFace *f1,
- BMFace *f2,
- BMFace *f3,
- BMFace *f4,
- int mat_nr)
-{
- BMVert *varr[4] = {v1, v2, v3, v4};
- BMFace *farr[4] = {f1, f2, f3, f4};
- return bev_create_ngon(bm, varr, 4, farr, f1, NULL, mat_nr, true);
-}
-
-static BMFace *bev_create_quad_ex(BMesh *bm,
- BMVert *v1,
- BMVert *v2,
- BMVert *v3,
- BMVert *v4,
- BMFace *f1,
- BMFace *f2,
- BMFace *f3,
- BMFace *f4,
- BMEdge *e1,
- BMEdge *e2,
- BMEdge *e3,
- BMEdge *e4,
- BMFace *frep,
- int mat_nr)
-{
- BMVert *varr[4] = {v1, v2, v3, v4};
- BMFace *farr[4] = {f1, f2, f3, f4};
- BMEdge *earr[4] = {e1, e2, e3, e4};
- return bev_create_ngon(bm, varr, 4, farr, frep, earr, mat_nr, true);
-}
-
/* Is Loop layer layer_index contiguous across shared vertex of l1 and l2? */
static bool contig_ldata_across_loops(BMesh *bm, BMLoop *l1, BMLoop *l2, int layer_index)
{
@@ -828,6 +790,25 @@ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f
return true;
}
+/**
+ * In array face_component of total `totface` elements, swap values c1 and c2
+ * wherever they occur.
+ */
+static void swap_face_components(int *face_component, int totface, int c1, int c2)
+{
+ if (c1 == c2) {
+ return; /* Nothing to do. */
+ }
+ for (int f = 0; f < totface; f++) {
+ if (face_component[f] == c1) {
+ face_component[f] = c2;
+ }
+ else if (face_component[f] == c2) {
+ face_component[f] = c1;
+ }
+ }
+}
+
/*
* Set up the fields of bp->math_layer_info.
* We always set has_math_layers to the correct value.
@@ -836,6 +817,7 @@ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f
*/
static void math_layer_info_init(BevelParams *bp, BMesh *bm)
{
+ int f;
bp->math_layer_info.has_math_layers = false;
bp->math_layer_info.face_component = NULL;
for (int i = 0; i < bm->ldata.totlayer; i++) {
@@ -860,12 +842,12 @@ static void math_layer_info_init(BevelParams *bp, BMesh *bm)
bool *in_stack = MEM_malloc_arrayN(totface, sizeof(bool), __func__);
/* Set all component ids by DFS from faces with unassigned components. */
- for (int f = 0; f < totface; f++) {
+ for (f = 0; f < totface; f++) {
face_component[f] = -1;
in_stack[f] = false;
}
int current_component = -1;
- for (int f = 0; f < totface; f++) {
+ for (f = 0; f < totface; f++) {
if (face_component[f] == -1 && !in_stack[f]) {
int stack_top = 0;
current_component++;
@@ -910,6 +892,44 @@ static void math_layer_info_init(BevelParams *bp, BMesh *bm)
}
MEM_freeN(stack);
MEM_freeN(in_stack);
+ /* We can usually get more pleasing result if components 0 and 1
+ * are the topmost and bottom-most (in z-coordinate) components,
+ * so adjust component indices to make that so. */
+ if (current_component <= 0) {
+ return; /* Only one component, so no need to do this. */
+ }
+ BMFace *top_face = NULL;
+ float top_face_z = -1e30f;
+ int top_face_component = -1;
+ BMFace *bot_face = NULL;
+ float bot_face_z = 1e30f;
+ int bot_face_component = -1;
+ for (f = 0; f < totface; f++) {
+ float cent[3];
+ BMFace *bmf = BM_face_at_index(bm, f);
+ BM_face_calc_center_bounds(bmf, cent);
+ float fz = cent[2];
+ if (fz > top_face_z) {
+ top_face_z = fz;
+ top_face = bmf;
+ top_face_component = face_component[f];
+ }
+ if (fz < bot_face_z) {
+ bot_face_z = fz;
+ bot_face = bmf;
+ bot_face_component = face_component[f];
+ }
+ }
+ BLI_assert(top_face != NULL && bot_face != NULL);
+ UNUSED_VARS_NDEBUG(top_face, bot_face);
+ swap_face_components(face_component, totface, face_component[0], top_face_component);
+ if (bot_face_component != top_face_component) {
+ if (bot_face_component == 0) {
+ /* It was swapped with old top_face_component. */
+ bot_face_component = top_face_component;
+ }
+ swap_face_components(face_component, totface, face_component[1], bot_face_component);
+ }
}
/**
@@ -3843,8 +3863,8 @@ static VMesh *new_adj_vmesh(MemArena *mem_arena, int count, int seg, BoundVert *
* where ns2 = floor(nseg / 2).
* But these overlap data from previous and next i: there are some forced equivalences.
* Let's call these indices the canonical ones: we will just calculate data for these
- * 0 <= j <= ns2, 0 <= k < ns2 (for odd ns2)
- * 0 <= j < ns2, 0 <= k <= ns2 (for even ns2)
+ * 0 <= j <= ns2, 0 <= k <= ns2 (for odd ns)
+ * 0 <= j < ns2, 0 <= k <= ns2 (for even ns)
* also (j=ns2, k=ns2) at i=0 (for even ns2)
* This function returns the canonical one for any i, j, k in [0,n],[0,ns],[0,ns].
*/
@@ -4799,46 +4819,85 @@ static BMEdge *find_closer_edge(float *co, BMEdge *e1, BMEdge *e2)
return e2;
}
-/* Snap co to the closest edge of face f. Return the edge in *r_snap_e,
- * the coordinates of snap point in r_ snap_co,
- * and the distance squared to the snap point as function return */
-static float snap_face_dist_squared(float *co, BMFace *f, BMEdge **r_snap_e, float *r_snap_co)
+/**
+ * Find which BoundVerts of \a bv are internal to face \a f.
+ * That is, when both the face and the point are projected to 2d,
+ * the point is on the boundary of or inside the projected face.
+ * There can only be up to three of then, since, including miters,
+ * that is the maximum number of BoundVerts that can be between two edges.
+ * Return the number of face-internal vertices found.
+ */
+static int find_face_internal_boundverts(const BevVert *bv,
+ const BMFace *f,
+ BoundVert *(r_internal[3]))
{
- BMEdge *beste = NULL;
- float beste_d2 = 1e20f;
- BMIter iter;
- BMEdge *e;
- BM_ITER_ELEM (e, &iter, f, BM_EDGES_OF_FACE) {
- float closest[3];
- closest_to_line_segment_v3(closest, co, e->v1->co, e->v2->co);
- float d2 = len_squared_v3v3(closest, co);
- if (d2 < beste_d2) {
- beste_d2 = d2;
- beste = e;
- copy_v3_v3(r_snap_co, closest);
+ if (f == NULL) {
+ return 0;
+ }
+ int n_internal = 0;
+ VMesh *vm = bv->vmesh;
+ BLI_assert(vm != NULL);
+ BoundVert *v = vm->boundstart;
+ do {
+ /* Possible speedup: do the matrix projection done by the following
+ * once, outside the loop, or even better, cache it if ever done
+ * in the course of Bevel. */
+ if (BM_face_point_inside_test(f, v->nv.co)) {
+ r_internal[n_internal++] = v;
+ if (n_internal == 3) {
+ break;
+ }
}
+ } while ((v = v->next) != vm->boundstart);
+ for (int i = n_internal; i < 3; i++) {
+ r_internal[i] = NULL;
}
- *r_snap_e = beste;
- return beste_d2;
+ return n_internal;
}
-/* What would be the area of the polygon around bv if interpolated in face frep?
+/**
+ * Find where the coordinates of the BndVerts in \a bv should snap to in face \a f.
+ * Face \a f should contain vertex `bv->v`.
+ * Project the snapped verts to 2d, then return the area of the resulting polygon.
+ * Usually one BndVert is inside the face, sometimes up to 3 (if there are miters),
+ * so don't snap those to an edge; all the rest snap to one of the edges of \a bmf
+ * incident on `bv->v`.
*/
-static float interp_poly_area(BevVert *bv, BMFace *frep)
+static float projected_boundary_area(BevVert *bv, BMFace *f)
{
+ BMEdge *e1, *e2;
VMesh *vm = bv->vmesh;
-
+ float(*proj_co)[2] = BLI_array_alloca(proj_co, vm->count);
+ float axis_mat[3][3];
+ axis_dominant_v3_to_m3(axis_mat, f->no);
+ get_incident_edges(f, bv->v, &e1, &e2);
+ BLI_assert(e1 != NULL && e2 != NULL);
BLI_assert(vm != NULL);
- float(*uv_co)[3] = BLI_array_alloca(uv_co, vm->count);
BoundVert *v = vm->boundstart;
- int n = 0;
+ int i = 0;
+ BoundVert *unsnapped[3];
+ find_face_internal_boundverts(bv, f, unsnapped);
do {
- BLI_assert(n < vm->count);
- BMEdge *snape;
- snap_face_dist_squared(v->nv.v->co, frep, &snape, uv_co[n]);
- n++;
+ float *co = v->nv.v->co;
+ if (v == unsnapped[0] || v == unsnapped[1] || v == unsnapped[2]) {
+ mul_v2_m3v3(proj_co[i], axis_mat, co);
+ }
+ else {
+ float snap1[3], snap2[3];
+ closest_to_line_segment_v3(snap1, co, e1->v1->co, e1->v2->co);
+ closest_to_line_segment_v3(snap2, co, e2->v1->co, e2->v2->co);
+ float d1_sq = len_squared_v3v3(snap1, co);
+ float d2_sq = len_squared_v3v3(snap2, co);
+ if (d1_sq <= d2_sq) {
+ mul_v2_m3v3(proj_co[i], axis_mat, snap1);
+ }
+ else {
+ mul_v2_m3v3(proj_co[i], axis_mat, snap2);
+ }
+ }
+ ++i;
} while ((v = v->next) != vm->boundstart);
- float area = fabsf(area_poly_v3(uv_co, n));
+ float area = area_poly_v2(proj_co, vm->count);
return area;
}
@@ -4851,7 +4910,8 @@ static float interp_poly_area(BevVert *bv, BMFace *frep)
*/
static bool is_bad_uv_poly(BevVert *bv, BMFace *frep)
{
- float area = interp_poly_area(bv, frep);
+ BLI_assert(bv->vmesh != NULL);
+ float area = projected_boundary_area(bv, frep);
return area < BEVEL_EPSILON_BIG;
}
@@ -4876,6 +4936,8 @@ static BMFace *frep_for_center_poly(BevelParams *bp, BevVert *bv)
bool consider_all_faces = bv->selcount == 1;
/* Make an array that can hold maximum possible number of choices. */
BMFace **fchoices = BLI_array_alloca(fchoices, bv->edgecount);
+ /* For each choice, need to remember the unsnapped BoundVerts. */
+
for (int i = 0; i < bv->edgecount; i++) {
if (!bv->edges[i].is_bev && !consider_all_faces) {
continue;
@@ -4924,9 +4986,11 @@ static void build_center_ngon(BevelParams *bp, BMesh *bm, BevVert *bv, int mat_n
int ns2 = vm->seg / 2;
BMFace *frep;
BMEdge *frep_e1, *frep_e2;
+ BoundVert *frep_unsnapped[3];
if (bv->any_seam) {
frep = frep_for_center_poly(bp, bv);
get_incident_edges(frep, bv->v, &frep_e1, &frep_e2);
+ find_face_internal_boundverts(bv, frep, frep_unsnapped);
}
else {
frep = NULL;
@@ -4938,8 +5002,13 @@ static void build_center_ngon(BevelParams *bp, BMesh *bm, BevVert *bv, int mat_n
BLI_array_append(vv, mesh_vert(vm, i, ns2, ns2)->v);
if (frep) {
BLI_array_append(vf, frep);
- BMEdge *frep_e = find_closer_edge(mesh_vert(vm, i, ns2, ns2)->v->co, frep_e1, frep_e2);
- BLI_array_append(ve, v == vm->boundstart ? NULL : frep_e);
+ if (v == frep_unsnapped[0] || v == frep_unsnapped[1] || v == frep_unsnapped[2]) {
+ BLI_array_append(ve, NULL);
+ }
+ else {
+ BMEdge *frep_e = find_closer_edge(mesh_vert(vm, i, ns2, ns2)->v->co, frep_e1, frep_e2);
+ BLI_array_append(ve, frep_e);
+ }
}
else {
BLI_array_append(vf, boundvert_rep_face(v, NULL));
@@ -5242,6 +5311,110 @@ static VMesh *square_out_adj_vmesh(BevelParams *bp, BevVert *bv)
return vm;
}
+static BMEdge *snap_edge_for_center_vmesh_vert(int i,
+ int n_bndv,
+ BMEdge *eprev,
+ BMEdge *enext,
+ BMFace **bndv_rep_faces,
+ BMFace *center_frep,
+ const bool *frep_beats_next)
+{
+ int previ = (i + n_bndv - 1) % n_bndv;
+ int nexti = (i + 1) % n_bndv;
+
+ if (frep_beats_next[previ] && bndv_rep_faces[previ] == center_frep) {
+ return eprev;
+ }
+ if (!frep_beats_next[i] && bndv_rep_faces[nexti] == center_frep) {
+ return enext;
+ }
+ /* If n_bndv > 3 then we won't snap in the boundvert regions
+ * that are not directly adjacent to the center-winning boundvert.
+ * This is probably wrong, maybe getting UV positions outside the
+ * original area, but the alternative may be even worse. */
+ return NULL;
+}
+
+/**
+ * Fill the r_snap_edges array with the edges to snap to (or NUL, if no snapping)
+ * for the adj mesh face with lower left corner at (i, ring j, segment k).
+ * The indices of the four corners are (i,j,k), (i,j,k+1), (i,j+1,k+1), (i,j+1,k).
+ * The answer will be one of NULL (don't snap), eprev (the edge between
+ * boundvert i and boundvert i-1), or enext (the edge between boundvert i
+ * and boundvert i+1).
+ * When n is odd, the center column (seg ns2) is ambiguous as to whether it
+ * interpolates in the current boundvert's frep [= interpolation face] or the next one's.
+ * Similarly, when n is odd, the center row (ring ns2) is ambiguous as to
+ * whether it interpolates in the current boundvert's frep or the previous one's.
+ * Parameter frep_beats_next should have an array of size n_bndv of bools
+ * that say whether the tie should be broken in favor of the next boundvert's
+ * frep (if true) or the current one's.
+ * For vertices in the center polygon (when ns is odd), the snapping edge depends
+ * on where the boundvert is in relation to the boundvert that has the center face's frep,
+ * so the arguments bndv_rep_faces is an array of size n_bndv give the freps for each i,
+ * and center_frep is the frep for the center.
+ *
+ * Note: this function is for edge bevels only, at the moment.
+ */
+static void snap_edges_for_vmesh_vert(int i,
+ int j,
+ int k,
+ int ns,
+ int ns2,
+ int n_bndv,
+ BMEdge *eprev,
+ BMEdge *enext,
+ BMEdge *enextnext,
+ BMFace **bndv_rep_faces,
+ BMFace *center_frep,
+ const bool *frep_beats_next,
+ BMEdge *r_snap_edges[4])
+{
+ BLI_assert(0 <= i && i < n_bndv && 0 <= j && j < ns2 && 0 <= k && k <= ns2);
+ for (int corner = 0; corner < 4; corner++) {
+ r_snap_edges[corner] = NULL;
+ if (ns % 2 == 0) {
+ continue;
+ }
+ int previ = (i + n_bndv - 1) % n_bndv;
+ /* Make jj and kk be the j and k indices for this corner. */
+ int jj = corner < 2 ? j : j + 1;
+ int kk = (corner == 0 || corner == 3) ? k : k + 1;
+ if (jj < ns2 && kk < ns2) {
+ ; /* No snap. */
+ }
+ else if (jj < ns2 && kk == ns2) {
+ /* On the left side of the center strip quads, but not on center poly. */
+ if (!frep_beats_next[i]) {
+ r_snap_edges[corner] = enext;
+ }
+ }
+ else if (jj < ns2 && kk == ns2 + 1) {
+ /* On the right side of the center strip quads, but not on center poly. */
+ if (frep_beats_next[i]) {
+ r_snap_edges[corner] = enext;
+ }
+ }
+ else if (jj == ns2 && kk < ns2) {
+ /* On the top of the top strip quads, but not on center poly. */
+ if (frep_beats_next[previ]) {
+ r_snap_edges[corner] = eprev;
+ }
+ }
+ else if (jj == ns2 && kk == ns2) {
+ /* Center poly vert for boundvert i. */
+ r_snap_edges[corner] = snap_edge_for_center_vmesh_vert(
+ i, n_bndv, eprev, enext, bndv_rep_faces, center_frep, frep_beats_next);
+ }
+ else if (jj == ns2 && kk == ns2 + 1) {
+ /* Center poly vert for boundvert i+1. */
+ int nexti = (i + 1) % n_bndv;
+ r_snap_edges[corner] = snap_edge_for_center_vmesh_vert(
+ nexti, n_bndv, enext, enextnext, bndv_rep_faces, center_frep, frep_beats_next);
+ }
+ }
+}
+
/**
* Given that the boundary is built and the boundary #BMVert's have been made,
* calculate the positions of the interior mesh points for the M_ADJ pattern,
@@ -5295,17 +5468,62 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert
}
}
vmesh_copy_equiv_verts(vm);
- /* Make the polygons. */
+
+ /* Find and store the interpolation face for each BoundVert. */
+ BMFace **bndv_rep_faces = BLI_array_alloca(bndv_rep_faces, n_bndv);
BoundVert *bndv = vm->boundstart;
do {
int i = bndv->index;
- BMFace *f = boundvert_rep_face(bndv, NULL);
- BMFace *f2 = boundvert_rep_face(bndv->next, NULL);
- BMFace *fchoices[2] = {f, f2};
- BMFace *fc = odd ? choose_rep_face(bp, fchoices, 2) : NULL;
+ bndv_rep_faces[i] = boundvert_rep_face(bndv, NULL);
+ } while ((bndv = bndv->next) != vm->boundstart);
- EdgeHalf *e = (bp->affect_type == BEVEL_AFFECT_VERTICES) ? bndv->efirst : bndv->ebev;
+ /* If odd number of segments, need data to break interpolation ties. */
+ BMVert **center_verts = NULL;
+ BMEdge **center_edge_snaps = NULL;
+ BMFace **center_face_interps = NULL;
+ bool *frep_beats_next = NULL;
+ BMFace *center_frep = NULL;
+ if (odd && bp->affect_type == BEVEL_AFFECT_EDGES) {
+ center_verts = BLI_array_alloca(center_verts, n_bndv);
+ center_edge_snaps = BLI_array_alloca(center_edge_snaps, n_bndv);
+ center_face_interps = BLI_array_alloca(center_face_interps, n_bndv);
+ frep_beats_next = BLI_array_alloca(frep_beats_next, n_bndv);
+ center_frep = frep_for_center_poly(bp, bv);
+ for (int i = 0; i < n_bndv; i++) {
+ center_edge_snaps[i] = NULL;
+ /* frep_beats_next[i] == true if frep for i is chosen over that for i + 1. */
+ int inext = (i + 1) % n_bndv;
+ BMFace *fchoices[2] = {bndv_rep_faces[i], bndv_rep_faces[inext]};
+ BMFace *fwinner = choose_rep_face(bp, fchoices, 2);
+ frep_beats_next[i] = fwinner == bndv_rep_faces[i];
+ }
+ }
+ /* Make the polygons. */
+ bndv = vm->boundstart;
+ do {
+ int i = bndv->index;
+ int inext = bndv->next->index;
+ BMFace *f = bndv_rep_faces[i];
+ BMFace *f2 = bndv_rep_faces[inext];
+ BMFace *fc = NULL;
+ if (odd && bp->affect_type == BEVEL_AFFECT_EDGES) {
+ fc = frep_beats_next[i] ? f : f2;
+ }
+
+ EdgeHalf *e, *eprev, *enext;
+ if (bp->affect_type == BEVEL_AFFECT_VERTICES) {
+ e = bndv->efirst;
+ eprev = bndv->prev->efirst;
+ enext = bndv->next->efirst;
+ }
+ else {
+ e = bndv->ebev;
+ eprev = bndv->prev->ebev;
+ enext = bndv->next->ebev;
+ }
BMEdge *bme = e ? e->e : NULL;
+ BMEdge *bmeprev = eprev ? eprev->e : NULL;
+ BMEdge *bmenext = enext ? enext->e : NULL;
/* For odd ns, make polys with lower left corner at (i,j,k) for
* j in [0, ns2-1], k in [0, ns2]. And then the center ngon.
* For even ns,
@@ -5315,77 +5533,84 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert
*/
for (int j = 0; j < ns2; j++) {
for (int k = 0; k < ns2 + odd; k++) {
+ /* We will create a quad with these four corners. */
BMVert *bmv1 = mesh_vert(vm, i, j, k)->v;
BMVert *bmv2 = mesh_vert(vm, i, j, k + 1)->v;
BMVert *bmv3 = mesh_vert(vm, i, j + 1, k + 1)->v;
BMVert *bmv4 = mesh_vert(vm, i, j + 1, k)->v;
+ BMVert *bmvs[4] = {bmv1, bmv2, bmv3, bmv4};
BLI_assert(bmv1 && bmv2 && bmv3 && bmv4);
- BMFace *r_f;
+ /* For each created quad, the UV's etc. will be interpolated
+ * in potentially a different face for each corner and may need
+ * to snap to a particular edge before interpolating.
+ * The fr and se arrays will be filled with the interpolation faces
+ * and snapping edges for the for corners in the order given
+ * in the bmvs array.
+ */
+ BMFace *fr[4];
+ BMEdge *se[4] = {NULL, NULL, NULL, NULL};
if (bp->affect_type == BEVEL_AFFECT_VERTICES) {
+ fr[0] = fr[1] = fr[2] = fr[3] = f2;
if (j < k) {
if (k == ns2 && j == ns2 - 1) {
- r_f = bev_create_quad_ex(bm,
- bmv1,
- bmv2,
- bmv3,
- bmv4,
- f2,
- f2,
- f2,
- f2,
- NULL,
- NULL,
- bndv->next->efirst->e,
- bme,
- f2,
- mat_nr);
- }
- else {
- r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, mat_nr);
+ se[2] = bndv->next->efirst->e;
+ se[3] = bme;
}
}
- else if (j > k) {
- r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, mat_nr);
- }
- else { /* j == k */
+ else if (j == k) {
/* Only one edge attached to v, since vertex only. */
- if (e->is_seam) {
- r_f = bev_create_quad_ex(
- bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, bme, NULL, bme, NULL, f2, mat_nr);
- }
- else {
- r_f = bev_create_quad_ex(
- bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f, bme, NULL, bme, NULL, f2, mat_nr);
+ se[0] = se[2] = bme;
+ if (!e->is_seam) {
+ fr[3] = f;
}
}
}
else { /* Edge bevel. */
+ fr[0] = fr[1] = fr[2] = fr[3] = f;
if (odd) {
+ BMEdge *b1 = (eprev && eprev->is_seam) ? bmeprev : NULL;
+ BMEdge *b2 = (e && e->is_seam) ? bme : NULL;
+ BMEdge *b3 = (enext && enext->is_seam) ? bmenext : NULL;
+ snap_edges_for_vmesh_vert(i,
+ j,
+ k,
+ ns,
+ ns2,
+ n_bndv,
+ b1,
+ b2,
+ b3,
+ bndv_rep_faces,
+ center_frep,
+ frep_beats_next,
+ se);
if (k == ns2) {
- if (e && e->is_seam) {
- r_f = bev_create_quad_ex(
- bm, bmv1, bmv2, bmv3, bmv4, fc, fc, fc, fc, NULL, bme, bme, NULL, fc, mat_nr);
+ if (!e || e->is_seam) {
+ fr[0] = fr[1] = fr[2] = fr[3] = fc;
}
else {
- r_f = bev_create_quad_ex(
- bm, bmv1, bmv2, bmv3, bmv4, f, f2, f2, f, NULL, bme, bme, NULL, fc, mat_nr);
+ fr[0] = fr[3] = f;
+ fr[1] = fr[2] = f2;
+ }
+ if (j == ns2 - 1) {
+ /* Use the 4th vertex of these faces as the ones used for the center polygon. */
+ center_verts[i] = bmvs[3];
+ center_edge_snaps[i] = se[3];
+ center_face_interps[i] = bv->any_seam ? center_frep : f;
}
- }
- else {
- r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f, mat_nr);
}
}
- else {
- BMEdge *bme1 = k == ns2 - 1 ? bme : NULL;
- BMEdge *bme3 = NULL;
+ else { /* Edge bevel, Even number of segments. */
+ if (k == ns2 - 1) {
+ se[1] = bme;
+ }
if (j == ns2 - 1 && bndv->prev->ebev) {
- bme3 = bndv->prev->ebev->e;
+ se[3] = bmeprev;
}
- BMEdge *bme2 = bme1 != NULL ? bme1 : bme3;
- r_f = bev_create_quad_ex(
- bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f, NULL, bme1, bme2, bme3, f, mat_nr);
+ se[2] = se[1] != NULL ? se[1] : se[3];
}
}
+ BMFace *r_f = bev_create_ngon(bm, bmvs, 4, fr, NULL, se, mat_nr, true);
record_face_kind(bp, r_f, F_VERT);
}
}
@@ -5413,7 +5638,18 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert
/* Center ngon. */
if (odd) {
- build_center_ngon(bp, bm, bv, mat_nr);
+ if (bp->affect_type == BEVEL_AFFECT_EDGES) {
+ BMFace *frep = NULL;
+ if (bv->any_seam) {
+ frep = frep_for_center_poly(bp, bv);
+ }
+ BMFace *cen_f = bev_create_ngon(
+ bm, center_verts, n_bndv, center_face_interps, frep, center_edge_snaps, mat_nr, true);
+ record_face_kind(bp, cen_f, F_VERT);
+ }
+ else {
+ build_center_ngon(bp, bm, bv, mat_nr);
+ }
}
}
@@ -5425,7 +5661,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert
* are two problems currently:
* - Miter profiles don't have plane_no filled, so down direction is incorrect.
* - Indexing profile points of miters with (i, 0, k) seems to return zero except for the first
- * and last profile point.
+ * and last profile point.
* TODO(Hans): Use repface / edge arrays for UV interpolation properly.
*/
static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv)
@@ -5591,9 +5827,11 @@ static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv)
BMFace *repface;
BMEdge *repface_e1, *repface_e2;
+ BoundVert *unsnapped[3];
if (bv->any_seam) {
repface = frep_for_center_poly(bp, bv);
get_incident_edges(repface, bv->v, &repface_e1, &repface_e2);
+ find_face_internal_boundverts(bv, repface, unsnapped);
}
else {
repface = NULL;
@@ -5607,8 +5845,13 @@ static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv)
BLI_array_append(bmverts, bndv->nv.v);
if (repface) {
BLI_array_append(bmfaces, repface);
- BMEdge *frep_e = find_closer_edge(bndv->nv.v->co, repface_e1, repface_e2);
- BLI_array_append(bmedges, n > 0 ? frep_e : NULL);
+ if (bndv == unsnapped[0] || bndv == unsnapped[1] || bndv == unsnapped[2]) {
+ BLI_array_append(bmedges, NULL);
+ }
+ else {
+ BMEdge *frep_e = find_closer_edge(bndv->nv.v->co, repface_e1, repface_e2);
+ BLI_array_append(bmedges, frep_e);
+ }
}
else {
BLI_array_append(bmfaces, boundvert_rep_face(bndv, NULL));
@@ -6359,10 +6602,10 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
sub_v3_v3v3(edge_dir, bv->v->co, v2->co);
float z = fabsf(2.0f * sinf(angle_v3v3(vert_axis, edge_dir)));
if (z < BEVEL_EPSILON) {
- e->offset_l_spec = 0.01f * bv->offset; /* Undefined behavior, so tiny bevel. */
+ e->offset_l_spec = 0.01f * bp->offset; /* Undefined behavior, so tiny bevel. */
}
else {
- e->offset_l_spec = bv->offset / z;
+ e->offset_l_spec = bp->offset / z;
}
break;
}
@@ -6371,10 +6614,10 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
sub_v3_v3v3(edge_dir, bv->v->co, v2->co);
float z = fabsf(cosf(angle_v3v3(vert_axis, edge_dir)));
if (z < BEVEL_EPSILON) {
- e->offset_l_spec = 0.01f * bv->offset; /* Undefined behavior, so tiny bevel. */
+ e->offset_l_spec = 0.01f * bp->offset; /* Undefined behavior, so tiny bevel. */
}
else {
- e->offset_l_spec = bv->offset / z;
+ e->offset_l_spec = bp->offset / z;
}
break;
}
@@ -6829,13 +7072,20 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
int odd = nseg % 2;
int mid = nseg / 2;
BMEdge *center_bme = NULL;
+ BMFace *fchoices[2] = {f1, f2};
+ BMFace *f_choice = NULL;
+ int center_adj_k = -1;
+ if (odd & e1->is_seam) {
+ f_choice = choose_rep_face(bp, fchoices, 2);
+ if (nseg > 1) {
+ center_adj_k = f_choice == f1 ? mid + 2 : mid;
+ }
+ }
for (int k = 1; k <= nseg; k++) {
verts[3] = mesh_vert(vm1, i1, 0, k)->v;
verts[2] = mesh_vert(vm2, i2, 0, nseg - k)->v;
BMFace *r_f;
if (odd && k == mid + 1) {
- BMFace *fchoices[2] = {f1, f2};
- BMFace *f_choice = choose_rep_face(bp, fchoices, 2);
if (e1->is_seam) {
/* Straddles a seam: choose to interpolate in f_choice and snap the loops whose verts
* are in the non-chosen face to bme for interpolation purposes.
@@ -6856,6 +7106,25 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
r_f = bev_create_ngon(bm, verts, 4, faces, f_choice, NULL, mat_nr, true);
}
}
+ else if (odd && k == center_adj_k && e1->is_seam) {
+ /* The strip adjacent to the center one, in another UV island.
+ * Snap the edge near the seam to bme to match what happens in
+ * the bevel rings.
+ */
+ BMEdge *edges[4];
+ BMFace *f_interp;
+ if (k == mid) {
+ edges[0] = edges[1] = NULL;
+ edges[2] = edges[3] = bme;
+ f_interp = f1;
+ }
+ else {
+ edges[0] = edges[1] = bme;
+ edges[2] = edges[3] = NULL;
+ f_interp = f2;
+ }
+ r_f = bev_create_ngon(bm, verts, 4, NULL, f_interp, edges, mat_nr, true);
+ }
else if (!odd && k == mid) {
/* Left poly that touches an even center line on right. */
BMEdge *edges[4] = {NULL, NULL, bme, bme};
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 6d3c203b076..8c54c923476 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -82,6 +82,7 @@ set(SRC
intern/draw_cache_impl_volume.c
intern/draw_color_management.cc
intern/draw_common.c
+ intern/draw_curves.cc
intern/draw_debug.c
intern/draw_fluid.c
intern/draw_hair.c
@@ -98,6 +99,7 @@ set(SRC
intern/draw_texture_pool.cc
intern/draw_view.c
intern/draw_view_data.cc
+ intern/draw_volume.cc
intern/smaa_textures.c
engines/basic/basic_engine.c
engines/basic/basic_shader.c
@@ -194,6 +196,7 @@ set(SRC
intern/draw_color_management.h
intern/draw_common.h
intern/draw_common_shader_shared.h
+ intern/draw_curves_private.h
intern/draw_debug.h
intern/draw_hair_private.h
intern/draw_instance_data.h
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index 81edee17c76..47e8f234a01 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -353,8 +353,6 @@ static void eevee_draw_scene(void *vedata)
EEVEE_renderpasses_draw_debug(vedata);
- EEVEE_volumes_free_smoke_textures();
-
stl->g_data->view_updated = false;
DRW_view_set_active(NULL);
@@ -574,7 +572,6 @@ static void eevee_render_to_image(void *vedata,
}
}
- EEVEE_volumes_free_smoke_textures();
EEVEE_motion_blur_data_free(&ved->stl->effects->motion_blur);
if (RE_engine_test_break(engine)) {
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c
index 2e1b92de068..4f562dd9804 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.c
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.c
@@ -965,7 +965,7 @@ static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lb
txl->color = NULL;
DRW_render_instance_buffer_finish();
- DRW_hair_update();
+ DRW_curves_update();
}
static void eevee_lightbake_copy_irradiance(EEVEE_LightBake *lbake, LightCache *lcache)
@@ -1463,9 +1463,6 @@ void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float
}
eevee_lightbake_delete_resources(lbake);
-
- /* Free GPU smoke textures and the smoke domain list correctly: See also T73921. */
- EEVEE_volumes_free_smoke_textures();
}
void EEVEE_lightbake_update_world_quick(EEVEE_ViewLayerData *sldata,
diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c
index e3342508a14..2e0937dbe49 100644
--- a/source/blender/draw/engines/eevee/eevee_motion_blur.c
+++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c
@@ -440,9 +440,9 @@ void EEVEE_motion_blur_cache_finish(EEVEE_Data *vedata)
DRW_render_instance_buffer_finish();
/* Need to be called after #DRW_render_instance_buffer_finish() */
- /* Also we weed to have a correct FBO bound for #DRW_hair_update. */
+ /* Also we weed to have a correct FBO bound for #DRW_curves_update. */
GPU_framebuffer_bind(vedata->fbl->main_fb);
- DRW_hair_update();
+ DRW_curves_update();
DRW_cache_restart();
}
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 9f97dacf9fe..ee336326166 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -1558,7 +1558,6 @@ void EEVEE_volumes_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_volumes_resolve(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_volumes_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples);
void EEVEE_volumes_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
-void EEVEE_volumes_free_smoke_textures(void);
void EEVEE_volumes_free(void);
/* eevee_effects.c */
diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c
index 47e2b95f367..bef19c589c2 100644
--- a/source/blender/draw/engines/eevee/eevee_render.c
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -538,9 +538,9 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
DRW_render_instance_buffer_finish();
/* Need to be called after DRW_render_instance_buffer_finish() */
- /* Also we weed to have a correct FBO bound for DRW_hair_update */
+ /* Also we weed to have a correct FBO bound for DRW_curves_update */
GPU_framebuffer_bind(fbl->main_fb);
- DRW_hair_update();
+ DRW_curves_update();
/* Sort transparents before the loop. */
DRW_pass_sort_shgroup_z(psl->transparent_pass);
diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c
index 4e4a2a9eb8e..85cc7f65126 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders.c
+++ b/source/blender/draw/engines/eevee/eevee_shaders.c
@@ -1487,6 +1487,10 @@ struct GPUMaterial *EEVEE_material_get(
GPUMaterial *mat = eevee_material_get_ex(scene, ma, wo, options, deferred);
int status = GPU_material_status(mat);
+ /* Return null material and bypass drawing for volume shaders. */
+ if ((options & VAR_MAT_VOLUME) && status != GPU_MAT_SUCCESS) {
+ return NULL;
+ }
switch (status) {
case GPU_MAT_SUCCESS:
break;
diff --git a/source/blender/draw/engines/eevee/eevee_shaders_extra.cc b/source/blender/draw/engines/eevee/eevee_shaders_extra.cc
index bb1a0b0abe4..05577944140 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders_extra.cc
+++ b/source/blender/draw/engines/eevee/eevee_shaders_extra.cc
@@ -81,7 +81,7 @@ void eevee_shader_material_create_info_amend(GPUMaterial *gpumat,
const bool do_fragment_attrib_load = is_background || is_volume;
if (is_hair && !info.vertex_out_interfaces_.is_empty()) {
- /** Hair attributes comme from sampler buffer. Transfer attributes to sampler. */
+ /** Hair attributes come from sampler buffer. Transfer attributes to sampler. */
for (auto &input : info.vertex_inputs_) {
info.sampler(0, ImageType::FLOAT_BUFFER, input.name, Frequency::BATCH);
}
@@ -97,12 +97,26 @@ void eevee_shader_material_create_info_amend(GPUMaterial *gpumat,
}
attr_load << "};\n";
attr_load << iface.name << " " << iface.instance_name << ";\n";
- /* Global vars just to make code valid. Only Orco is supported. */
- for (const ShaderCreateInfo::VertIn &in : info.vertex_inputs_) {
- attr_load << in.type << " " << in.name << ";\n";
+ if (!is_volume) {
+ /* Global vars just to make code valid. Only Orco is supported. */
+ for (const ShaderCreateInfo::VertIn &in : info.vertex_inputs_) {
+ attr_load << in.type << " " << in.name << ";\n";
+ }
}
info.vertex_out_interfaces_.clear();
}
+ if (is_volume) {
+ /** Volume grid attributes come from 3D textures. Transfer attributes to samplers. */
+ for (auto &input : info.vertex_inputs_) {
+ info.sampler(0, ImageType::FLOAT_3D, input.name, Frequency::BATCH);
+ }
+ info.additional_info("draw_volume_infos");
+ /* Do not add twice. */
+ if (!GPU_material_flag_get(gpumat, GPU_MATFLAG_OBJECT_INFO)) {
+ info.additional_info("draw_object_infos");
+ }
+ info.vertex_inputs_.clear();
+ }
if (!is_volume) {
info.define("EEVEE_GENERATED_INTERFACE");
@@ -137,7 +151,7 @@ void eevee_shader_material_create_info_amend(GPUMaterial *gpumat,
}
frag_gen << "Closure nodetree_exec()\n";
frag_gen << "{\n";
- if (GPU_material_is_volume_shader(gpumat)) {
+ if (is_volume) {
frag_gen << ((codegen.volume) ? codegen.volume : "return CLOSURE_DEFAULT;\n");
}
else {
diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c
index 6a0c9fb36df..b8bef61f8b1 100644
--- a/source/blender/draw/engines/eevee/eevee_volumes.c
+++ b/source/blender/draw/engines/eevee/eevee_volumes.c
@@ -43,35 +43,8 @@ static struct {
GPUTexture *dummy_scatter;
GPUTexture *dummy_transmit;
-
- /* List of all fluid simulation / smoke domains rendered within this frame. */
- ListBase smoke_domains;
} e_data = {NULL}; /* Engine data */
-static void eevee_create_textures_volumes(void)
-{
- const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- e_data.dummy_zero = DRW_texture_create_3d(1, 1, 1, GPU_RGBA8, DRW_TEX_WRAP, zero);
-
- const float one[4] = {1.0f, 1.0f, 1.0f, 1.0f};
- e_data.dummy_one = DRW_texture_create_3d(1, 1, 1, GPU_RGBA8, DRW_TEX_WRAP, one);
-
- const float flame = 0.0f;
- e_data.dummy_flame = DRW_texture_create_3d(1, 1, 1, GPU_R8, DRW_TEX_WRAP, &flame);
-}
-
-static GPUTexture *eevee_volume_default_texture(eGPUVolumeDefaultValue default_value)
-{
- switch (default_value) {
- case GPU_VOLUME_DEFAULT_0:
- return e_data.dummy_zero;
- case GPU_VOLUME_DEFAULT_1:
- return e_data.dummy_one;
- }
-
- return e_data.dummy_zero;
-}
-
void EEVEE_volumes_set_jitter(EEVEE_ViewLayerData *sldata, uint current_sample)
{
EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
@@ -227,11 +200,6 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
Scene *scene = draw_ctx->scene;
DRWShadingGroup *grp = NULL;
- /* Textures */
- if (!e_data.dummy_zero) {
- eevee_create_textures_volumes();
- }
-
/* Quick breakdown of the Volumetric rendering:
*
* The rendering is separated in 4 stages:
@@ -268,7 +236,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
!LOOK_DEV_STUDIO_LIGHT_ENABLED(draw_ctx->v3d)) {
struct GPUMaterial *mat = EEVEE_material_get(vedata, scene, NULL, wo, VAR_MAT_VOLUME);
- if (GPU_material_has_volume_output(mat)) {
+ if (mat && GPU_material_has_volume_output(mat)) {
grp = DRW_shgroup_material_create(mat, psl->volumetric_world_ps);
}
@@ -283,11 +251,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
/* Fix principle volumetric not working with world materials. */
- ListBase gpu_grids = GPU_material_volume_grids(mat);
- LISTBASE_FOREACH (GPUMaterialVolumeGrid *, gpu_grid, &gpu_grids) {
- DRW_shgroup_uniform_texture(
- grp, gpu_grid->sampler_name, eevee_volume_default_texture(gpu_grid->default_value));
- }
+ grp = DRW_shgroup_volume_create_sub(NULL, NULL, grp, mat);
DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]);
@@ -299,187 +263,17 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
/* If no world or volume material is present just clear the buffer with this drawcall */
grp = DRW_shgroup_create(EEVEE_shaders_volumes_clear_sh_get(), psl->volumetric_world_ps);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]);
}
}
-static bool eevee_volume_object_grids_init(Object *ob, ListBase *gpu_grids, DRWShadingGroup *grp)
-{
- Volume *volume = ob->data;
- BKE_volume_load(volume, G.main);
-
- /* Test if we need to use multiple transforms. */
- DRWVolumeGrid *first_drw_grid = NULL;
- bool multiple_transforms = true;
-
- LISTBASE_FOREACH (GPUMaterialVolumeGrid *, gpu_grid, gpu_grids) {
- const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, gpu_grid->name);
- DRWVolumeGrid *drw_grid = (volume_grid) ?
- DRW_volume_batch_cache_get_grid(volume, volume_grid) :
- NULL;
-
- if (drw_grid) {
- if (first_drw_grid == NULL) {
- first_drw_grid = drw_grid;
- }
- else if (drw_grid &&
- !equals_m4m4(drw_grid->object_to_texture, first_drw_grid->object_to_texture)) {
- multiple_transforms = true;
- break;
- }
- }
- }
-
- /* Bail out of no grids to render. */
- if (first_drw_grid == NULL) {
- return false;
- }
-
- /* Set transform matrix for the volume as a whole. This one is also used for
- * clipping so must map the entire bounding box to 0..1. */
- float bounds_to_object[4][4];
-
- if (multiple_transforms) {
- /* For multiple grids with different transform, we first transform from object space
- * to bounds, then for each individual grid from bounds to texture. */
- const BoundBox *bb = BKE_volume_boundbox_get(ob);
- float bb_size[3];
- sub_v3_v3v3(bb_size, bb->vec[6], bb->vec[0]);
- size_to_mat4(bounds_to_object, bb_size);
- copy_v3_v3(bounds_to_object[3], bb->vec[0]);
-
- invert_m4_m4(first_drw_grid->object_to_bounds, bounds_to_object);
- DRW_shgroup_uniform_mat4(grp, "volumeObjectToTexture", first_drw_grid->object_to_bounds);
- }
- else {
- /* All grid transforms are equal, we can transform to texture space immediately. */
- DRW_shgroup_uniform_mat4(grp, "volumeObjectToTexture", first_drw_grid->object_to_texture);
- }
-
- /* Don't use orco transform here, only matrix. */
- DRW_shgroup_uniform_vec3_copy(grp, "volumeOrcoLoc", (float[3]){0.5f, 0.5f, 0.5f});
- DRW_shgroup_uniform_vec3_copy(grp, "volumeOrcoSize", (float[3]){0.5f, 0.5f, 0.5f});
-
- /* Set density scale. */
- const float density_scale = BKE_volume_density_scale(volume, ob->obmat);
- DRW_shgroup_uniform_float_copy(grp, "volumeDensityScale", density_scale);
-
- /* Bind volume grid textures. */
- LISTBASE_FOREACH (GPUMaterialVolumeGrid *, gpu_grid, gpu_grids) {
- const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, gpu_grid->name);
- DRWVolumeGrid *drw_grid = (volume_grid) ?
- DRW_volume_batch_cache_get_grid(volume, volume_grid) :
- NULL;
-
- /* Handle 3 cases here:
- * - Grid exists and texture was loaded -> use texture.
- * - Grid exists but has zero size or failed to load -> use zero.
- * - Grid does not exist -> use default value. */
- GPUTexture *grid_tex = (drw_grid) ? drw_grid->texture :
- (volume_grid) ? e_data.dummy_zero :
- eevee_volume_default_texture(gpu_grid->default_value);
-
- DRW_shgroup_uniform_texture(grp, gpu_grid->sampler_name, grid_tex);
-
- if (drw_grid && multiple_transforms) {
- /* Specify per-volume transform matrix that is applied after the
- * transform from object to bounds. */
- mul_m4_m4m4(drw_grid->bounds_to_texture, drw_grid->object_to_texture, bounds_to_object);
- DRW_shgroup_uniform_mat4(grp, gpu_grid->transform_name, drw_grid->bounds_to_texture);
- }
- }
-
- return true;
-}
-
-static bool eevee_volume_object_mesh_init(Scene *scene,
- Object *ob,
- ListBase *gpu_grids,
- DRWShadingGroup *grp)
-{
- static const float white[3] = {1.0f, 1.0f, 1.0f};
- ModifierData *md = NULL;
-
- /* Smoke Simulation */
- if ((md = BKE_modifiers_findby_type(ob, eModifierType_Fluid)) &&
- (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) &&
- ((FluidModifierData *)md)->domain != NULL) {
- FluidModifierData *fmd = (FluidModifierData *)md;
- FluidDomainSettings *fds = fmd->domain;
-
- /* Don't try to show liquid domains here. */
- if (!fds->fluid || !(fds->type == FLUID_DOMAIN_TYPE_GAS)) {
- return false;
- }
-
- /* Don't show smoke before simulation starts, this could be made an option in the future. */
- /* (sebbas): Always show smoke for manta */
-#if 0
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const bool show_smoke = ((int)DEG_get_ctime(draw_ctx->depsgraph) >=
- *fds->point_cache[0]->startframe);
-#endif
-
- if (fds->fluid && (fds->type == FLUID_DOMAIN_TYPE_GAS) /* && show_smoke */) {
- DRW_smoke_ensure(fmd, fds->flags & FLUID_DOMAIN_USE_NOISE);
- BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(fmd));
- }
-
- LISTBASE_FOREACH (GPUMaterialVolumeGrid *, gpu_grid, gpu_grids) {
- if (STREQ(gpu_grid->name, "density")) {
- DRW_shgroup_uniform_texture_ref(
- grp, gpu_grid->sampler_name, fds->tex_density ? &fds->tex_density : &e_data.dummy_one);
- }
- else if (STREQ(gpu_grid->name, "color")) {
- DRW_shgroup_uniform_texture_ref(
- grp, gpu_grid->sampler_name, fds->tex_color ? &fds->tex_color : &e_data.dummy_one);
- }
- else if (STR_ELEM(gpu_grid->name, "flame", "temperature")) {
- DRW_shgroup_uniform_texture_ref(
- grp, gpu_grid->sampler_name, fds->tex_flame ? &fds->tex_flame : &e_data.dummy_flame);
- }
- else {
- DRW_shgroup_uniform_texture(
- grp, gpu_grid->sampler_name, eevee_volume_default_texture(gpu_grid->default_value));
- }
- }
-
- /* Constant Volume color. */
- bool use_constant_color = ((fds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 &&
- (fds->active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0);
-
- DRW_shgroup_uniform_vec3(
- grp, "volumeColor", (use_constant_color) ? fds->active_color : white, 1);
-
- /* Output is such that 0..1 maps to 0..1000K */
- DRW_shgroup_uniform_vec2(grp, "volumeTemperature", &fds->flame_ignition, 1);
- }
- else {
- LISTBASE_FOREACH (GPUMaterialVolumeGrid *, gpu_grid, gpu_grids) {
- DRW_shgroup_uniform_texture(
- grp, gpu_grid->sampler_name, eevee_volume_default_texture(gpu_grid->default_value));
- }
- }
-
- /* Transform for mesh volumes. */
- static const float unit_mat[4][4] = {{1.0f, 0.0f, 0.0f, 0.0f},
- {0.0f, 1.0f, 0.0f, 0.0f},
- {0.0f, 0.0f, 1.0f, 0.0f},
- {0.0f, 0.0f, 0.0f, 1.0f}};
- float *texco_loc, *texco_size;
- BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texco_loc, &texco_size);
-
- DRW_shgroup_uniform_mat4(grp, "volumeObjectToTexture", unit_mat);
- DRW_shgroup_uniform_vec3(grp, "volumeOrcoLoc", texco_loc, 1);
- DRW_shgroup_uniform_vec3(grp, "volumeOrcoSize", texco_size, 1);
-
- return true;
-}
-
void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
Scene *scene,
@@ -506,15 +300,22 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
int mat_options = VAR_MAT_VOLUME | VAR_MAT_MESH;
struct GPUMaterial *mat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options);
- eGPUMaterialStatus status = GPU_material_status(mat);
/* If shader failed to compile or is currently compiling. */
- if (status != GPU_MAT_SUCCESS) {
+ if (mat == NULL) {
return;
}
+ /* TODO(fclem): Reuse main shading group to avoid shading binding cost just like for surface
+ * shaders. */
DRWShadingGroup *grp = DRW_shgroup_material_create(mat, vedata->psl->volumetric_objects_ps);
+ grp = DRW_shgroup_volume_create_sub(scene, ob, grp, mat);
+
+ if (grp == NULL) {
+ return;
+ }
+
/* TODO(fclem): remove those "unnecessary" UBOs */
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
@@ -522,22 +323,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
-
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
-
- ListBase gpu_grids = GPU_material_volume_grids(mat);
-
- if (ob->type == OB_VOLUME) {
- if (!eevee_volume_object_grids_init(ob, &gpu_grids, grp)) {
- return;
- }
- }
- else {
- if (!eevee_volume_object_mesh_init(scene, ob, &gpu_grids, grp)) {
- return;
- }
- }
-
/* TODO: Reduce to number of slices intersecting. */
/* TODO: Preemptive culling. */
DRW_shgroup_call_procedural_triangles(grp, ob, sldata->common_data.vol_tex_size[2]);
@@ -753,16 +539,6 @@ void EEVEE_volumes_resolve(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda
}
}
-void EEVEE_volumes_free_smoke_textures(void)
-{
- /* Free Smoke Textures after rendering */
- LISTBASE_FOREACH (LinkData *, link, &e_data.smoke_domains) {
- FluidModifierData *fmd = (FluidModifierData *)link->data;
- DRW_smoke_free(fmd);
- }
- BLI_freelistN(&e_data.smoke_domains);
-}
-
void EEVEE_volumes_free(void)
{
DRW_TEXTURE_FREE_SAFE(e_data.dummy_scatter);
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
index 0e8e8dd9d01..ab0f4d6bec8 100644
--- a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
@@ -144,3 +144,13 @@ vec3 attr_load_uv(vec3 attr)
return attr;
}
#endif
+
+/* Passthrough. */
+float attr_load_temperature_post(float attr)
+{
+ return attr;
+}
+vec4 attr_load_color_post(vec4 attr)
+{
+ return attr;
+}
diff --git a/source/blender/draw/engines/eevee/shaders/surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/surface_frag.glsl
index 9ad7a4fdbc1..79ec3807d0b 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_frag.glsl
@@ -179,3 +179,13 @@ vec3 attr_load_uv(vec3 attr)
{
return vec3(0);
}
+
+/* Passthrough. */
+float attr_load_temperature_post(float attr)
+{
+ return attr;
+}
+vec4 attr_load_color_post(vec4 attr)
+{
+ return attr;
+}
diff --git a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
index 6c6b810422b..49c18832f72 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
@@ -157,3 +157,13 @@ vec3 attr_load_uv(vec3 attr)
return attr;
}
#endif
+
+/* Passthrough. */
+float attr_load_temperature_post(float attr)
+{
+ return attr;
+}
+vec4 attr_load_color_post(vec4 attr)
+{
+ return attr;
+}
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
index e0a79872928..914261d7f59 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
@@ -4,17 +4,13 @@
/* Based on Frosbite Unified Volumetric.
* https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */
-#ifdef MESH_SHADER
-uniform vec3 volumeOrcoLoc;
-uniform vec3 volumeOrcoSize;
-uniform mat4 volumeObjectToTexture;
-uniform float volumeDensityScale = 1.0;
-#endif
+/* Store volumetric properties into the froxel textures. */
flat in int slice;
/* Warning: these are not attributes, these are global vars. */
vec3 worldPosition = vec3(0.0);
+vec3 objectPosition = vec3(0.0);
vec3 viewPosition = vec3(0.0);
vec3 viewNormal = vec3(0.0);
vec3 volumeOrco = vec3(0.0);
@@ -24,9 +20,9 @@ layout(location = 1) out vec4 volumeExtinction;
layout(location = 2) out vec4 volumeEmissive;
layout(location = 3) out vec4 volumePhase;
-/* Store volumetric properties into the froxel textures. */
+int attr_id;
-#ifdef MESH_SHADER
+#ifndef CLEAR
GlobalData init_globals(void)
{
GlobalData surf;
@@ -80,10 +76,8 @@ void main()
viewPosition = get_view_space_from_depth(ndc_cell.xy, ndc_cell.z);
worldPosition = point_view_to_world(viewPosition);
#ifdef MESH_SHADER
- volumeOrco = point_world_to_object(worldPosition);
- /* TODO: redundant transform */
- volumeOrco = (volumeOrco - volumeOrcoLoc + volumeOrcoSize) / (volumeOrcoSize * 2.0);
- volumeOrco = (volumeObjectToTexture * vec4(volumeOrco, 1.0)).xyz;
+ objectPosition = point_world_to_object(worldPosition);
+ volumeOrco = OrcoTexCoFactors[0].xyz + objectPosition * OrcoTexCoFactors[1].xyz;
if (any(lessThan(volumeOrco, vec3(0.0))) || any(greaterThan(volumeOrco, vec3(1.0)))) {
/* Note: Discard is not an explicit return in Metal prior to versions 2.3.
@@ -100,15 +94,13 @@ void main()
volumeEmissive = vec4(0.0, 0.0, 0.0, 1.0);
volumePhase = vec4(0.0, 0.0, 0.0, 0.0);
#else
-# ifdef MESH_SHADER
g_data = init_globals();
attrib_load();
-# endif
Closure cl = nodetree_exec();
# ifdef MESH_SHADER
- cl.scatter *= volumeDensityScale;
- cl.absorption *= volumeDensityScale;
- cl.emission *= volumeDensityScale;
+ cl.scatter *= drw_volume.density_scale;
+ cl.absorption *= drw_volume.density_scale;
+ cl.emission *= drw_volume.density_scale;
# endif
volumeScattering = vec4(cl.scatter, 1.0);
@@ -124,35 +116,72 @@ void main()
#endif
}
-vec3 attr_load_orco(vec4 orco)
+vec3 grid_coordinates()
+{
+ vec3 co = volumeOrco;
+#ifdef MESH_SHADER
+ /* Optional per-grid transform. */
+ if (drw_volume.grids_xform[attr_id][3][3] != 0.0) {
+ co = (drw_volume.grids_xform[attr_id] * vec4(objectPosition, 1.0)).xyz;
+ }
+#endif
+ attr_id += 1;
+ return co;
+}
+
+vec3 attr_load_orco(sampler3D orco)
{
+ attr_id += 1;
return volumeOrco;
}
-vec4 attr_load_tangent(vec4 tangent)
+vec4 attr_load_tangent(sampler3D tangent)
{
+ attr_id += 1;
return vec4(0);
}
-vec4 attr_load_vec4(vec4 attr)
+vec4 attr_load_vec4(sampler3D tex)
{
- return vec4(0);
+ return texture(tex, grid_coordinates());
}
-vec3 attr_load_vec3(vec3 attr)
+vec3 attr_load_vec3(sampler3D tex)
{
- return vec3(0);
+ return texture(tex, grid_coordinates()).rgb;
}
-vec2 attr_load_vec2(vec2 attr)
+vec2 attr_load_vec2(sampler3D tex)
{
- return vec2(0);
+ return texture(tex, grid_coordinates()).rg;
}
-float attr_load_float(float attr)
+float attr_load_float(sampler3D tex)
{
- return 0.0;
+ return texture(tex, grid_coordinates()).r;
}
-vec4 attr_load_color(vec4 attr)
+vec4 attr_load_color(sampler3D tex)
{
- return vec4(0);
+ return texture(tex, grid_coordinates());
}
-vec3 attr_load_uv(vec3 attr)
+vec3 attr_load_uv(sampler3D attr)
{
+ attr_id += 1;
return vec3(0);
}
+
+/* TODO(@fclem): These implementation details should concern the DRWManager and not be a fix on
+ * the engine side. But as of now, the engines are reponsible for loading the attributes. */
+float attr_load_temperature_post(float attr)
+{
+#ifdef MESH_SHADER
+ /* Bring the into standard range without having to modify the grid values */
+ attr = (attr > 0.01) ? (attr * drw_volume.temperature_mul + drw_volume.temperature_bias) : 0.0;
+#endif
+ return attr;
+}
+vec4 attr_load_color_post(vec4 attr)
+{
+#ifdef MESH_SHADER
+ /* Density is premultiplied for interpolation, divide it out here. */
+ attr.rgb *= safe_rcp(attr.a);
+ attr.rgb *= drw_volume.color_mul.rgb;
+ attr.a = 1.0;
+#endif
+ return attr;
+}
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
index 26b60c992e1..527bbd18896 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
@@ -11,10 +11,8 @@ uniform sampler3D volumeScattering; /* Result of the scatter step */
uniform sampler3D volumeExtinction;
#ifdef USE_VOLUME_OPTI
-uniform layout(r11f_g11f_b10f)
-writeonly restrict image3D finalScattering_img;
-uniform layout(r11f_g11f_b10f)
-writeonly restrict image3D finalTransmittance_img;
+uniform layout(r11f_g11f_b10f) writeonly restrict image3D finalScattering_img;
+uniform layout(r11f_g11f_b10f) writeonly restrict image3D finalTransmittance_img;
vec3 finalScattering;
vec3 finalTransmittance;
diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c
index abcca5525c7..5d8ba06e181 100644
--- a/source/blender/draw/engines/overlay/overlay_extra.c
+++ b/source/blender/draw/engines/overlay/overlay_extra.c
@@ -1474,23 +1474,6 @@ static void OVERLAY_volume_extra(OVERLAY_ExtraCallBuffers *cb,
}
if (draw_velocity || show_gridlines) {
- BLI_addtail(&data->stl->pd->smoke_domains, BLI_genericNodeN(fmd));
- }
-}
-
-static void OVERLAY_volume_free_smoke_textures(OVERLAY_Data *data)
-{
- /* Free Smoke Textures after rendering */
- /* XXX This is a waste of processing and GPU bandwidth if nothing
- * is updated. But the problem is since Textures are stored in the
- * modifier we don't want them to take precious VRAM if the
- * modifier is not used for display. We should share them for
- * all viewport in a redraw at least. */
- LinkData *link;
- while ((link = BLI_pophead(&data->stl->pd->smoke_domains))) {
- FluidModifierData *fmd = (FluidModifierData *)link->data;
- DRW_smoke_free_velocity(fmd);
- MEM_freeN(link);
}
}
@@ -1624,8 +1607,6 @@ void OVERLAY_extra_draw(OVERLAY_Data *vedata)
void OVERLAY_extra_in_front_draw(OVERLAY_Data *vedata)
{
DRW_draw_pass(vedata->psl->extra_ps[1]);
-
- OVERLAY_volume_free_smoke_textures(vedata);
}
void OVERLAY_extra_centers_draw(OVERLAY_Data *vedata)
diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h
index 71b6c9424e6..4c933e08a57 100644
--- a/source/blender/draw/engines/overlay/overlay_private.h
+++ b/source/blender/draw/engines/overlay/overlay_private.h
@@ -304,7 +304,6 @@ typedef struct OVERLAY_PrivateData {
DRWView *view_edit_curves_points;
/** TODO: get rid of this. */
- ListBase smoke_domains;
ListBase bg_movie_clips;
/** Two instances for in_front option and without. */
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh
index 5d098d61dbf..698c7d1a8b7 100644
--- a/source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh
@@ -55,7 +55,6 @@ GPU_SHADER_CREATE_INFO(workbench_volume_coba)
GPU_SHADER_CREATE_INFO(workbench_volume_no_coba)
.sampler(4, ImageType::FLOAT_3D, "shadowTexture")
- .sampler(5, ImageType::UINT_2D, "transferTexture")
.push_constant(Type::VEC3, "activeColor");
/** \} */
diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c
index f4e042933d1..f7f156e5297 100644
--- a/source/blender/draw/engines/workbench/workbench_data.c
+++ b/source/blender/draw/engines/workbench/workbench_data.c
@@ -163,7 +163,6 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
wpd->taa_sample_len = workbench_antialiasing_sample_count_get(wpd);
wpd->volumes_do = false;
- BLI_listbase_clear(&wpd->smoke_domains);
/* FIXME: This reproduce old behavior when workbench was separated in 2 engines.
* But this is a workaround for a missing update tagging. */
diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c
index 566fd30096d..fb20bde2f65 100644
--- a/source/blender/draw/engines/workbench/workbench_engine.c
+++ b/source/blender/draw/engines/workbench/workbench_engine.c
@@ -271,6 +271,18 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd,
BKE_pbvh_is_drawing_set(ob->sculpt->pbvh, is_sculpt_pbvh);
}
+ bool has_color = false;
+
+ if (me) {
+ const CustomData *cd_vdata = workbench_mesh_get_vert_custom_data(me);
+ const CustomData *cd_ldata = workbench_mesh_get_loop_custom_data(me);
+
+ has_color = (CustomData_has_layer(cd_vdata, CD_PROP_COLOR) ||
+ CustomData_has_layer(cd_vdata, CD_PROP_BYTE_COLOR) ||
+ CustomData_has_layer(cd_ldata, CD_PROP_COLOR) ||
+ CustomData_has_layer(cd_ldata, CD_PROP_BYTE_COLOR));
+ }
+
if (color_type == V3D_SHADING_TEXTURE_COLOR) {
if (ob->dt < OB_TEXTURE) {
color_type = V3D_SHADING_MATERIAL_COLOR;
@@ -285,14 +297,6 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd,
color_type = V3D_SHADING_OBJECT_COLOR;
}
else {
- const CustomData *cd_vdata = workbench_mesh_get_vert_custom_data(me);
- const CustomData *cd_ldata = workbench_mesh_get_loop_custom_data(me);
-
- bool has_color = (CustomData_has_layer(cd_vdata, CD_PROP_COLOR) ||
- CustomData_has_layer(cd_vdata, CD_MLOOPCOL) ||
- CustomData_has_layer(cd_ldata, CD_PROP_COLOR) ||
- CustomData_has_layer(cd_ldata, CD_MLOOPCOL));
-
if (!has_color) {
color_type = V3D_SHADING_OBJECT_COLOR;
}
@@ -314,7 +318,7 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd,
*r_texpaint_mode = true;
}
}
- else if (is_vertpaint_mode && me && CustomData_has_layer(ldata, CD_MLOOPCOL)) {
+ else if (is_vertpaint_mode && me && has_color) {
color_type = V3D_SHADING_VERTEX_COLOR;
}
}
@@ -613,10 +617,8 @@ static void workbench_draw_scene(void *ved)
workbench_draw_finish(vedata);
}
-void workbench_draw_finish(void *ved)
+void workbench_draw_finish(void *UNUSED(ved))
{
- WORKBENCH_Data *vedata = ved;
- workbench_volume_draw_finish(vedata);
/* Reset default view. */
DRW_view_set_active(NULL);
}
diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h
index 727b771ee08..492bce1e571 100644
--- a/source/blender/draw/engines/workbench/workbench_private.h
+++ b/source/blender/draw/engines/workbench/workbench_private.h
@@ -324,10 +324,6 @@ typedef struct WORKBENCH_PrivateData {
/** Index of current material inside the material chunk. Only for material coloring mode. */
int material_index;
- /* Volumes */
- /** List of smoke domain textures to free after drawing. */
- ListBase smoke_domains;
-
/* Depth of Field */
/** Depth of field temp buffers. */
struct GPUTexture *dof_blur_tx;
@@ -533,7 +529,6 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
struct ModifierData *md,
eV3DShadingColorType color_type);
void workbench_volume_draw_pass(WORKBENCH_Data *vedata);
-void workbench_volume_draw_finish(WORKBENCH_Data *vedata);
/* workbench_engine.c */
diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c
index 72de3fe298a..1279682e899 100644
--- a/source/blender/draw/engines/workbench/workbench_render.c
+++ b/source/blender/draw/engines/workbench/workbench_render.c
@@ -170,9 +170,9 @@ void workbench_render(void *ved, RenderEngine *engine, RenderLayer *render_layer
DRW_render_instance_buffer_finish();
- /* Also we weed to have a correct FBO bound for #DRW_hair_update */
+ /* Also we weed to have a correct FBO bound for #DRW_curves_update */
GPU_framebuffer_bind(dfbl->default_fb);
- DRW_hair_update();
+ DRW_curves_update();
GPU_framebuffer_bind(dfbl->default_fb);
GPU_framebuffer_clear_depth(dfbl->default_fb, 1.0f);
diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c
index c6f40c5d6bb..2c902e9b627 100644
--- a/source/blender/draw/engines/workbench/workbench_volume.c
+++ b/source/blender/draw/engines/workbench/workbench_volume.c
@@ -178,8 +178,6 @@ static void workbench_volume_modifier_cache_populate(WORKBENCH_Data *vedata,
else {
DRW_shgroup_call(grp, DRW_cache_cube_get(), ob);
}
-
- BLI_addtail(&wpd->smoke_domains, BLI_genericNodeN(fmd));
}
static void workbench_volume_material_color(WORKBENCH_PrivateData *wpd,
@@ -334,20 +332,3 @@ void workbench_volume_draw_pass(WORKBENCH_Data *vedata)
DRW_draw_pass(psl->volume_ps);
}
}
-
-void workbench_volume_draw_finish(WORKBENCH_Data *vedata)
-{
- WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
-
- /* Free Smoke Textures after rendering */
- /* XXX This is a waste of processing and GPU bandwidth if nothing
- * is updated. But the problem is since Textures are stored in the
- * modifier we don't want them to take precious VRAM if the
- * modifier is not used for display. We should share them for
- * all viewport in a redraw at least. */
- LISTBASE_FOREACH (LinkData *, link, &wpd->smoke_domains) {
- FluidModifierData *fmd = (FluidModifierData *)link->data;
- DRW_smoke_free(fmd);
- }
- BLI_freelistN(&wpd->smoke_domains);
-}
diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh
index ed94c485b32..d7e752a43f4 100644
--- a/source/blender/draw/intern/DRW_gpu_wrapper.hh
+++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh
@@ -53,6 +53,8 @@
*
*/
+#include "DRW_render.h"
+
#include "MEM_guardedalloc.h"
#include "draw_texture_pool.h"
@@ -61,6 +63,7 @@
#include "BLI_span.hh"
#include "BLI_utildefines.h"
#include "BLI_utility_mixins.hh"
+#include "BLI_vector.hh"
#include "GPU_framebuffer.h"
#include "GPU_storage_buffer.h"
diff --git a/source/blender/draw/intern/draw_cache_impl_curves.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc
index b084a5e5945..f2742f3bcc7 100644
--- a/source/blender/draw/intern/draw_cache_impl_curves.cc
+++ b/source/blender/draw/intern/draw_cache_impl_curves.cc
@@ -29,9 +29,11 @@
#include "GPU_material.h"
#include "GPU_texture.h"
+#include "DRW_render.h"
+
#include "draw_cache_impl.h" /* own include */
#include "draw_cache_inline.h"
-#include "draw_hair_private.h" /* own include */
+#include "draw_curves_private.h" /* own include */
using blender::float3;
using blender::IndexRange;
@@ -41,7 +43,7 @@ using blender::Span;
/* Curves GPUBatch Cache */
struct CurvesBatchCache {
- ParticleHairCache hair;
+ CurvesEvalCache curves_cache;
GPUBatch *edit_points;
@@ -70,6 +72,28 @@ static void curves_batch_cache_init(Curves &curves)
cache->is_dirty = false;
}
+static void curves_batch_cache_clear_data(CurvesEvalCache &curves_cache)
+{
+ /* TODO: more granular update tagging. */
+ GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_point_buf);
+ GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_length_buf);
+ DRW_TEXTURE_FREE_SAFE(curves_cache.point_tex);
+ DRW_TEXTURE_FREE_SAFE(curves_cache.length_tex);
+
+ GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_strand_buf);
+ GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_strand_seg_buf);
+ DRW_TEXTURE_FREE_SAFE(curves_cache.strand_tex);
+ DRW_TEXTURE_FREE_SAFE(curves_cache.strand_seg_tex);
+
+ for (int i = 0; i < MAX_HAIR_SUBDIV; i++) {
+ GPU_VERTBUF_DISCARD_SAFE(curves_cache.final[i].proc_buf);
+ DRW_TEXTURE_FREE_SAFE(curves_cache.final[i].proc_tex);
+ for (int j = 0; j < MAX_THICKRES; j++) {
+ GPU_BATCH_DISCARD_SAFE(curves_cache.final[i].proc_hairs[j]);
+ }
+ }
+}
+
static void curves_batch_cache_clear(Curves &curves)
{
CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves.batch_cache);
@@ -77,7 +101,8 @@ static void curves_batch_cache_clear(Curves &curves)
return;
}
- particle_batch_cache_clear_hair(&cache->hair);
+ curves_batch_cache_clear_data(cache->curves_cache);
+
GPU_BATCH_DISCARD_SAFE(cache->edit_points);
}
@@ -116,10 +141,9 @@ void DRW_curves_batch_cache_free(Curves *curves)
MEM_SAFE_FREE(curves->batch_cache);
}
-static void ensure_seg_pt_count(const Curves &curves, ParticleHairCache &curves_cache)
+static void ensure_seg_pt_count(const Curves &curves, CurvesEvalCache &curves_cache)
{
- if ((curves_cache.pos != nullptr && curves_cache.indices != nullptr) ||
- (curves_cache.proc_point_buf != nullptr)) {
+ if (curves_cache.proc_point_buf != nullptr) {
return;
}
@@ -169,7 +193,7 @@ static void curves_batch_cache_fill_segments_proc_pos(const Curves &curves_id,
}
static void curves_batch_cache_ensure_procedural_pos(Curves &curves,
- ParticleHairCache &cache,
+ CurvesEvalCache &cache,
GPUMaterial *gpu_material)
{
if (cache.proc_point_buf == nullptr || DRW_vbo_requested(cache.proc_point_buf)) {
@@ -229,7 +253,7 @@ static void curves_batch_cache_fill_strands_data(const Curves &curves_id,
}
static void curves_batch_cache_ensure_procedural_strand_data(Curves &curves,
- ParticleHairCache &cache)
+ CurvesEvalCache &cache)
{
GPUVertBufRaw data_step, seg_step;
@@ -259,7 +283,7 @@ static void curves_batch_cache_ensure_procedural_strand_data(Curves &curves,
cache.proc_strand_seg_buf);
}
-static void curves_batch_cache_ensure_procedural_final_points(ParticleHairCache &cache, int subdiv)
+static void curves_batch_cache_ensure_procedural_final_points(CurvesEvalCache &cache, int subdiv)
{
/* Same format as point_tex. */
GPUVertFormat format = {0};
@@ -296,7 +320,7 @@ static void curves_batch_cache_fill_segments_indices(const Curves &curves,
}
static void curves_batch_cache_ensure_procedural_indices(Curves &curves,
- ParticleHairCache &cache,
+ CurvesEvalCache &cache,
const int thickness_res,
const int subdiv)
{
@@ -330,7 +354,7 @@ static void curves_batch_cache_ensure_procedural_indices(Curves &curves,
}
bool curves_ensure_procedural_data(Object *object,
- ParticleHairCache **r_hair_cache,
+ CurvesEvalCache **r_hair_cache,
GPUMaterial *gpu_material,
const int subdiv,
const int thickness_res)
@@ -339,30 +363,31 @@ bool curves_ensure_procedural_data(Object *object,
Curves &curves = *static_cast<Curves *>(object->data);
CurvesBatchCache &cache = curves_batch_cache_get(curves);
- *r_hair_cache = &cache.hair;
+ *r_hair_cache = &cache.curves_cache;
const int steps = 3; /* TODO: don't hard-code? */
(*r_hair_cache)->final[subdiv].strands_res = 1 << (steps + subdiv);
/* Refreshed on combing and simulation. */
if ((*r_hair_cache)->proc_point_buf == nullptr) {
- ensure_seg_pt_count(curves, cache.hair);
- curves_batch_cache_ensure_procedural_pos(curves, cache.hair, gpu_material);
+ ensure_seg_pt_count(curves, cache.curves_cache);
+ curves_batch_cache_ensure_procedural_pos(curves, cache.curves_cache, gpu_material);
need_ft_update = true;
}
/* Refreshed if active layer or custom data changes. */
if ((*r_hair_cache)->strand_tex == nullptr) {
- curves_batch_cache_ensure_procedural_strand_data(curves, cache.hair);
+ curves_batch_cache_ensure_procedural_strand_data(curves, cache.curves_cache);
}
/* Refreshed only on subdiv count change. */
if ((*r_hair_cache)->final[subdiv].proc_buf == nullptr) {
- curves_batch_cache_ensure_procedural_final_points(cache.hair, subdiv);
+ curves_batch_cache_ensure_procedural_final_points(cache.curves_cache, subdiv);
need_ft_update = true;
}
if ((*r_hair_cache)->final[subdiv].proc_hairs[thickness_res - 1] == nullptr) {
- curves_batch_cache_ensure_procedural_indices(curves, cache.hair, thickness_res, subdiv);
+ curves_batch_cache_ensure_procedural_indices(
+ curves, cache.curves_cache, thickness_res, subdiv);
}
return need_ft_update;
@@ -385,10 +410,10 @@ void DRW_curves_batch_cache_create_requested(const Object *ob)
CurvesBatchCache &cache = curves_batch_cache_get(*curves);
if (DRW_batch_requested(cache.edit_points, GPU_PRIM_POINTS)) {
- DRW_vbo_request(cache.edit_points, &cache.hair.proc_point_buf);
+ DRW_vbo_request(cache.edit_points, &cache.curves_cache.proc_point_buf);
}
- if (DRW_vbo_requested(cache.hair.proc_point_buf)) {
- curves_batch_cache_ensure_procedural_pos(*curves, cache.hair, nullptr);
+ if (DRW_vbo_requested(cache.curves_cache.proc_point_buf)) {
+ curves_batch_cache_ensure_procedural_pos(*curves, cache.curves_cache, nullptr);
}
}
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index c4fa60ef51d..e4aec17eb69 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -518,15 +518,17 @@ static uint mesh_cd_calc_gpu_layers_vcol_used(const Mesh *me_query,
domain = ATTR_DOMAIN_POINT;
layer_i = CustomData_get_named_layer_index(cd_vdata, CD_PROP_COLOR, name);
- layer_i = layer_i == -1 ? CustomData_get_named_layer_index(cd_vdata, CD_MLOOPCOL, name) :
- layer_i;
+ layer_i = layer_i == -1 ?
+ CustomData_get_named_layer_index(cd_vdata, CD_PROP_BYTE_COLOR, name) :
+ layer_i;
if (layer_i == -1) {
domain = ATTR_DOMAIN_CORNER;
layer_i = layer_i == -1 ? CustomData_get_named_layer_index(cd_ldata, CD_PROP_COLOR, name) :
layer_i;
- layer_i = layer_i == -1 ? CustomData_get_named_layer_index(cd_ldata, CD_MLOOPCOL, name) :
- layer_i;
+ layer_i = layer_i == -1 ?
+ CustomData_get_named_layer_index(cd_ldata, CD_PROP_BYTE_COLOR, name) :
+ layer_i;
}
/* Note: this is not the same as the layer_i below. */
@@ -610,17 +612,17 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
}
if (layer == -1) {
- layer = CustomData_get_named_layer(cd_vdata, CD_MLOOPCOL, name);
+ layer = CustomData_get_named_layer(cd_vdata, CD_PROP_BYTE_COLOR, name);
if (layer != -1) {
- type = CD_MLOOPCOL;
+ type = CD_PROP_BYTE_COLOR;
domain = ATTR_DOMAIN_POINT;
}
}
if (layer == -1) {
- layer = CustomData_get_named_layer(cd_ldata, CD_MLOOPCOL, name);
+ layer = CustomData_get_named_layer(cd_ldata, CD_PROP_BYTE_COLOR, name);
if (layer != -1) {
- type = CD_MLOOPCOL;
+ type = CD_PROP_BYTE_COLOR;
domain = ATTR_DOMAIN_CORNER;
}
}
@@ -700,11 +702,11 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
}
/* Note: attr->type will always be CD_PROP_COLOR even for
- * CD_MLOOPCOL layers, see node_shader_gpu_vertex_color in
+ * CD_PROP_BYTE_COLOR layers, see node_shader_gpu_vertex_color in
* node_shader_vertex_color.cc.
*/
case CD_MCOL:
- case CD_MLOOPCOL:
+ case CD_PROP_BYTE_COLOR:
case CD_PROP_COLOR: {
int vcol_bit = mesh_cd_calc_gpu_layers_vcol_used(&me_query, cd_vdata, cd_ldata, name);
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
index c6b56723818..0f1ab967ca5 100644
--- a/source/blender/draw/intern/draw_cache_impl_particles.c
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -164,7 +164,7 @@ static void particle_batch_cache_clear_point(ParticlePointCache *point_cache)
GPU_VERTBUF_DISCARD_SAFE(point_cache->pos);
}
-void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache)
+static void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache)
{
/* TODO: more granular update tagging. */
GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_point_buf);
@@ -822,10 +822,11 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit
active_uv = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPUV);
render_uv = CustomData_get_render_layer(&psmd->mesh_final->ldata, CD_MLOOPUV);
}
- if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL)) {
- cache->num_col_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPCOL);
- active_col = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL);
- render_col = CustomData_get_render_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL);
+ if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR)) {
+ cache->num_col_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata,
+ CD_PROP_BYTE_COLOR);
+ active_col = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR);
+ render_col = CustomData_get_render_layer(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR);
}
}
@@ -891,7 +892,7 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit
GPU_vertbuf_attr_get_raw_data(cache->proc_col_buf[i], col_id, &col_step[i]);
char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
- const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPCOL, i);
+ const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR, i);
GPU_vertformat_safe_attr_name(name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
int n = 0;
@@ -1162,9 +1163,9 @@ static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit,
num_uv_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPUV);
active_uv = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPUV);
}
- if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL)) {
- num_col_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPCOL);
- active_col = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL);
+ if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR)) {
+ num_col_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR);
+ active_col = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR);
}
}
@@ -1195,7 +1196,8 @@ static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit,
for (int i = 0; i < num_col_layers; i++) {
char uuid[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
- const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPCOL, i);
+ const char *name = CustomData_get_layer_name(
+ &psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR, i);
GPU_vertformat_safe_attr_name(name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
BLI_snprintf(uuid, sizeof(uuid), "c%s", attr_safe_name);
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index d302140d9ac..779ac43178c 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -21,6 +21,8 @@ struct Object;
struct ParticleSystem;
struct RegionView3D;
struct ViewLayer;
+struct Scene;
+struct DRWData;
/* Keep in sync with globalsBlock in shaders */
BLI_STATIC_ASSERT_ALIGN(GlobalsUboStorage, 16)
@@ -54,16 +56,12 @@ struct DRWShadingGroup *DRW_shgroup_hair_create_sub(struct Object *object,
struct DRWShadingGroup *shgrp,
struct GPUMaterial *gpu_material);
-struct DRWShadingGroup *DRW_shgroup_curves_create_sub(struct Object *object,
- struct DRWShadingGroup *shgrp,
- struct GPUMaterial *gpu_material);
/**
* \note Only valid after #DRW_hair_update().
*/
struct GPUVertBuf *DRW_hair_pos_buffer_get(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md);
-struct GPUVertBuf *DRW_curves_pos_buffer_get(struct Object *object);
void DRW_hair_duplimat_get(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md,
@@ -73,6 +71,37 @@ void DRW_hair_init(void);
void DRW_hair_update(void);
void DRW_hair_free(void);
+/* draw_curves.cc */
+
+/**
+ * \note Only valid after #DRW_curves_update().
+ */
+struct GPUVertBuf *DRW_curves_pos_buffer_get(struct Object *object);
+
+struct DRWShadingGroup *DRW_shgroup_curves_create_sub(struct Object *object,
+ struct DRWShadingGroup *shgrp,
+ struct GPUMaterial *gpu_material);
+
+void DRW_curves_init(void);
+void DRW_curves_update(void);
+void DRW_curves_free(void);
+
+/* draw_volume.cc */
+
+/**
+ * Add attributes bindings of volume grids to an existing shading group.
+ * No draw call is added so the caller can decide how to use the data.
+ * \return nullptr if there is something to draw.
+ */
+struct DRWShadingGroup *DRW_shgroup_volume_create_sub(struct Scene *scene,
+ struct Object *ob,
+ struct DRWShadingGroup *shgrp,
+ struct GPUMaterial *gpu_material);
+
+void DRW_volume_init(struct DRWData *drw_data);
+void DRW_volume_ubos_pool_free(void *pool);
+void DRW_volume_free(void);
+
/* draw_fluid.c */
/* Fluid simulation. */
@@ -83,7 +112,9 @@ void DRW_fluid_ensure_flags(struct FluidModifierData *fmd);
void DRW_fluid_ensure_range_field(struct FluidModifierData *fmd);
void DRW_smoke_free(struct FluidModifierData *fmd);
-void DRW_smoke_free_velocity(struct FluidModifierData *fmd);
+
+void DRW_smoke_init(struct DRWData *drw_data);
+void DRW_smoke_exit(struct DRWData *drw_data);
/* draw_common.c */
diff --git a/source/blender/draw/intern/draw_curves.cc b/source/blender/draw/intern/draw_curves.cc
new file mode 100644
index 00000000000..88118361115
--- /dev/null
+++ b/source/blender/draw/intern/draw_curves.cc
@@ -0,0 +1,325 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2017 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup draw
+ *
+ * \brief Contains procedural GPU hair drawing methods.
+ */
+
+#include "BLI_string_utils.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_customdata_types.h"
+
+#include "GPU_batch.h"
+#include "GPU_capabilities.h"
+#include "GPU_compute.h"
+#include "GPU_material.h"
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+#include "GPU_vertex_buffer.h"
+
+#include "DRW_render.h"
+
+#include "draw_hair_private.h"
+#include "draw_shader.h"
+
+#ifndef __APPLE__
+# define USE_TRANSFORM_FEEDBACK
+# define USE_COMPUTE_SHADERS
+#endif
+
+BLI_INLINE eParticleRefineShaderType drw_curves_shader_type_get()
+{
+#ifdef USE_COMPUTE_SHADERS
+ if (GPU_compute_shader_support() && GPU_shader_storage_buffer_objects_support()) {
+ return PART_REFINE_SHADER_COMPUTE;
+ }
+#endif
+#ifdef USE_TRANSFORM_FEEDBACK
+ return PART_REFINE_SHADER_TRANSFORM_FEEDBACK;
+#endif
+ return PART_REFINE_SHADER_TRANSFORM_FEEDBACK_WORKAROUND;
+}
+
+#ifndef USE_TRANSFORM_FEEDBACK
+struct CurvesEvalCall {
+ struct CurvesEvalCall *next;
+ GPUVertBuf *vbo;
+ DRWShadingGroup *shgrp;
+ uint vert_len;
+};
+
+static CurvesEvalCall *g_tf_calls = nullptr;
+static int g_tf_id_offset;
+static int g_tf_target_width;
+static int g_tf_target_height;
+#endif
+
+static GPUVertBuf *g_dummy_vbo = nullptr;
+static GPUTexture *g_dummy_texture = nullptr;
+static DRWPass *g_tf_pass; /* XXX can be a problem with multiple DRWManager in the future */
+
+static GPUShader *curves_eval_shader_get(CurvesEvalShader type)
+{
+ return DRW_shader_curves_refine_get(type, drw_curves_shader_type_get());
+}
+
+void DRW_curves_init(void)
+{
+ /* Initialize legacy hair too, to avoid verbosity in callers. */
+ DRW_hair_init();
+
+#if defined(USE_TRANSFORM_FEEDBACK) || defined(USE_COMPUTE_SHADERS)
+ g_tf_pass = DRW_pass_create("Update Curves Pass", (DRWState)0);
+#else
+ g_tf_pass = DRW_pass_create("Update Curves Pass", DRW_STATE_WRITE_COLOR);
+#endif
+
+ if (g_dummy_vbo == nullptr) {
+ /* initialize vertex format */
+ GPUVertFormat format = {0};
+ uint dummy_id = GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ g_dummy_vbo = GPU_vertbuf_create_with_format(&format);
+
+ const float vert[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ GPU_vertbuf_data_alloc(g_dummy_vbo, 1);
+ GPU_vertbuf_attr_fill(g_dummy_vbo, dummy_id, vert);
+ /* Create vbo immediately to bind to texture buffer. */
+ GPU_vertbuf_use(g_dummy_vbo);
+
+ g_dummy_texture = GPU_texture_create_from_vertbuf("hair_dummy_attr", g_dummy_vbo);
+ }
+}
+
+static void drw_curves_cache_shgrp_attach_resources(DRWShadingGroup *shgrp,
+ CurvesEvalCache *cache,
+ const int subdiv)
+{
+ DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", cache->point_tex);
+ DRW_shgroup_uniform_texture(shgrp, "hairStrandBuffer", cache->strand_tex);
+ DRW_shgroup_uniform_texture(shgrp, "hairStrandSegBuffer", cache->strand_seg_tex);
+ DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &cache->final[subdiv].strands_res, 1);
+}
+
+static void drw_curves_cache_update_compute(CurvesEvalCache *cache, const int subdiv)
+{
+ const int strands_len = cache->strands_len;
+ const int final_points_len = cache->final[subdiv].strands_res * strands_len;
+ if (final_points_len > 0) {
+ GPUShader *shader = curves_eval_shader_get(CURVES_EVAL_CATMULL_ROM);
+ DRWShadingGroup *shgrp = DRW_shgroup_create(shader, g_tf_pass);
+ drw_curves_cache_shgrp_attach_resources(shgrp, cache, subdiv);
+ DRW_shgroup_vertex_buffer(shgrp, "posTime", cache->final[subdiv].proc_buf);
+
+ const int max_strands_per_call = GPU_max_work_group_count(0);
+ int strands_start = 0;
+ while (strands_start < strands_len) {
+ int batch_strands_len = MIN2(strands_len - strands_start, max_strands_per_call);
+ DRWShadingGroup *subgroup = DRW_shgroup_create_sub(shgrp);
+ DRW_shgroup_uniform_int_copy(subgroup, "hairStrandOffset", strands_start);
+ DRW_shgroup_call_compute(subgroup, batch_strands_len, cache->final[subdiv].strands_res, 1);
+ strands_start += batch_strands_len;
+ }
+ }
+}
+
+static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, const int subdiv)
+{
+ const int final_points_len = cache->final[subdiv].strands_res * cache->strands_len;
+ if (final_points_len > 0) {
+ GPUShader *tf_shader = curves_eval_shader_get(CURVES_EVAL_CATMULL_ROM);
+
+#ifdef USE_TRANSFORM_FEEDBACK
+ DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create(
+ tf_shader, g_tf_pass, cache->final[subdiv].proc_buf);
+#else
+ DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass);
+
+ CurvesEvalCall *pr_call = MEM_new<CurvesEvalCall>(__func__);
+ pr_call->next = g_tf_calls;
+ pr_call->vbo = cache->final[subdiv].proc_buf;
+ pr_call->shgrp = tf_shgrp;
+ pr_call->vert_len = final_points_len;
+ g_tf_calls = pr_call;
+ DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1);
+ DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1);
+ DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1);
+#endif
+
+ drw_curves_cache_shgrp_attach_resources(tf_shgrp, cache, subdiv);
+ DRW_shgroup_call_procedural_points(tf_shgrp, nullptr, final_points_len);
+ }
+}
+
+static CurvesEvalCache *drw_curves_cache_get(Object *object,
+ GPUMaterial *gpu_material,
+ int subdiv,
+ int thickness_res)
+{
+ CurvesEvalCache *cache;
+ bool update = curves_ensure_procedural_data(object, &cache, gpu_material, subdiv, thickness_res);
+
+ if (update) {
+ if (drw_curves_shader_type_get() == PART_REFINE_SHADER_COMPUTE) {
+ drw_curves_cache_update_compute(cache, subdiv);
+ }
+ else {
+ drw_curves_cache_update_transform_feedback(cache, subdiv);
+ }
+ }
+ return cache;
+}
+
+GPUVertBuf *DRW_curves_pos_buffer_get(Object *object)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+
+ int subdiv = scene->r.hair_subdiv;
+ int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
+
+ CurvesEvalCache *cache = drw_curves_cache_get(object, nullptr, subdiv, thickness_res);
+
+ return cache->final[subdiv].proc_buf;
+}
+
+DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
+ DRWShadingGroup *shgrp_parent,
+ GPUMaterial *gpu_material)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+
+ int subdiv = scene->r.hair_subdiv;
+ int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
+
+ CurvesEvalCache *curves_cache = drw_curves_cache_get(
+ object, gpu_material, subdiv, thickness_res);
+
+ DRWShadingGroup *shgrp = DRW_shgroup_create_sub(shgrp_parent);
+
+ /* Fix issue with certain driver not drawing anything if there is no texture bound to
+ * "ac", "au", "u" or "c". */
+ DRW_shgroup_uniform_texture(shgrp, "u", g_dummy_texture);
+ DRW_shgroup_uniform_texture(shgrp, "au", g_dummy_texture);
+ DRW_shgroup_uniform_texture(shgrp, "c", g_dummy_texture);
+ DRW_shgroup_uniform_texture(shgrp, "ac", g_dummy_texture);
+
+ /* TODO: Generalize radius implementation for curves data type. */
+ float hair_rad_shape = 1.0f;
+ float hair_rad_root = 0.005f;
+ float hair_rad_tip = 0.0f;
+ bool hair_close_tip = true;
+
+ DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", curves_cache->final[subdiv].proc_tex);
+ if (curves_cache->length_tex) {
+ DRW_shgroup_uniform_texture(shgrp, "hairLen", curves_cache->length_tex);
+ }
+ DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &curves_cache->final[subdiv].strands_res, 1);
+ DRW_shgroup_uniform_int_copy(shgrp, "hairThicknessRes", thickness_res);
+ DRW_shgroup_uniform_float_copy(shgrp, "hairRadShape", hair_rad_shape);
+ DRW_shgroup_uniform_mat4_copy(shgrp, "hairDupliMatrix", object->obmat);
+ DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", hair_rad_root);
+ DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", hair_rad_tip);
+ DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", hair_close_tip);
+ /* TODO(fclem): Until we have a better way to cull the curves and render with orco, bypass
+ * culling test. */
+ GPUBatch *geom = curves_cache->final[subdiv].proc_hairs[thickness_res - 1];
+ DRW_shgroup_call_no_cull(shgrp, geom, object);
+
+ return shgrp;
+}
+
+void DRW_curves_update()
+{
+ /* Update legacy hair too, to avoid verbosity in callers. */
+ DRW_hair_update();
+
+#ifndef USE_TRANSFORM_FEEDBACK
+ /**
+ * Workaround to transform feedback not working on mac.
+ * 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,
+ * 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.
+ */
+
+ if (g_tf_calls == nullptr) {
+ return;
+ }
+
+ /* Search ideal buffer size. */
+ uint max_size = 0;
+ for (CurvesEvalCall *pr_call = g_tf_calls; pr_call; pr_call = pr_call->next) {
+ max_size = max_ii(max_size, pr_call->vert_len);
+ }
+
+ /* Create target Texture / Frame-buffer */
+ /* Don't use max size as it can be really heavy and fail.
+ * Do chunks of maximum 2048 * 2048 hair points. */
+ int width = 2048;
+ int height = min_ii(width, 1 + max_size / width);
+ GPUTexture *tex = DRW_texture_pool_query_2d(
+ width, height, GPU_RGBA32F, (DrawEngineType *)DRW_curves_update);
+ g_tf_target_height = height;
+ g_tf_target_width = width;
+
+ GPUFrameBuffer *fb = nullptr;
+ GPU_framebuffer_ensure_config(&fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(tex),
+ });
+
+ float *data = static_cast<float *>(
+ MEM_mallocN(sizeof(float[4]) * width * height, "tf fallback buffer"));
+
+ GPU_framebuffer_bind(fb);
+ while (g_tf_calls != nullptr) {
+ CurvesEvalCall *pr_call = g_tf_calls;
+ g_tf_calls = g_tf_calls->next;
+
+ g_tf_id_offset = 0;
+ while (pr_call->vert_len > 0) {
+ int max_read_px_len = min_ii(width * height, pr_call->vert_len);
+
+ DRW_draw_pass_subset(g_tf_pass, pr_call->shgrp, pr_call->shgrp);
+ /* Read back result to main memory. */
+ GPU_framebuffer_read_color(fb, 0, 0, width, height, 4, 0, GPU_DATA_FLOAT, data);
+ /* Upload back to VBO. */
+ GPU_vertbuf_use(pr_call->vbo);
+ GPU_vertbuf_update_sub(pr_call->vbo,
+ sizeof(float[4]) * g_tf_id_offset,
+ sizeof(float[4]) * max_read_px_len,
+ data);
+
+ g_tf_id_offset += max_read_px_len;
+ pr_call->vert_len -= max_read_px_len;
+ }
+
+ MEM_freeN(pr_call);
+ }
+
+ MEM_freeN(data);
+ GPU_framebuffer_free(fb);
+#else
+ /* Just render the pass when using compute shaders or transform feedback. */
+ DRW_draw_pass(g_tf_pass);
+ if (drw_curves_shader_type_get() == PART_REFINE_SHADER_COMPUTE) {
+ GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE);
+ }
+#endif
+}
+
+void DRW_curves_free()
+{
+ DRW_hair_free();
+
+ GPU_VERTBUF_DISCARD_SAFE(g_dummy_vbo);
+ DRW_TEXTURE_FREE_SAFE(g_dummy_texture);
+}
diff --git a/source/blender/draw/intern/draw_curves_private.h b/source/blender/draw/intern/draw_curves_private.h
new file mode 100644
index 00000000000..76d5f15319d
--- /dev/null
+++ b/source/blender/draw/intern/draw_curves_private.h
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2017 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup draw
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_THICKRES 2 /* see eHairType */
+#define MAX_HAIR_SUBDIV 4 /* see hair_subdiv rna */
+
+typedef enum CurvesEvalShader {
+ CURVES_EVAL_CATMULL_ROM = 0,
+ CURVES_EVAL_BEZIER = 1,
+} CurvesEvalShader;
+#define CURVES_EVAL_SHADER_NUM 3
+
+struct GPUVertBuf;
+struct GPUIndexBuf;
+struct GPUBatch;
+struct GPUTexture;
+
+typedef struct CurvesEvalFinalCache {
+ /* Output of the subdivision stage: vertex buffer sized to subdiv level. */
+ GPUVertBuf *proc_buf;
+ GPUTexture *proc_tex;
+
+ /* Just contains a huge index buffer used to draw the final curves. */
+ GPUBatch *proc_hairs[MAX_THICKRES];
+
+ /* Points per curve, at least 2. */
+ int strands_res;
+} CurvesEvalFinalCache;
+
+/* Curves procedural display: Evaluation is done on the GPU. */
+typedef struct CurvesEvalCache {
+ /* Input control points */
+ GPUVertBuf *proc_point_buf;
+ GPUTexture *point_tex;
+
+ /** Info of control points strands (segment count and base index) */
+ GPUVertBuf *proc_strand_buf;
+ GPUTexture *strand_tex;
+
+ /* Curve length data. */
+ GPUVertBuf *proc_length_buf;
+ GPUTexture *length_tex;
+
+ GPUVertBuf *proc_strand_seg_buf;
+ GPUTexture *strand_seg_tex;
+
+ CurvesEvalFinalCache final[MAX_HAIR_SUBDIV];
+
+ int strands_len;
+ int elems_len;
+ int point_len;
+} CurvesEvalCache;
+
+/**
+ * Ensure all textures and buffers needed for GPU accelerated drawing.
+ */
+bool curves_ensure_procedural_data(struct Object *object,
+ struct CurvesEvalCache **r_hair_cache,
+ struct GPUMaterial *gpu_material,
+ int subdiv,
+ int thickness_res);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/draw/intern/draw_fluid.c b/source/blender/draw/intern/draw_fluid.c
index 667bd24dddb..d3d4bbf505e 100644
--- a/source/blender/draw/intern/draw_fluid.c
+++ b/source/blender/draw/intern/draw_fluid.c
@@ -9,6 +9,7 @@
#include <string.h>
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -21,6 +22,8 @@
#include "GPU_texture.h"
+#include "draw_manager.h"
+
#include "draw_common.h" /* Own include. */
#ifdef WITH_FLUID
@@ -419,46 +422,6 @@ static bool get_smoke_velocity_field(FluidDomainSettings *fds,
/** \name Public API
* \{ */
-void DRW_smoke_free(FluidModifierData *fmd)
-{
- if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) {
- if (fmd->domain->tex_density) {
- GPU_texture_free(fmd->domain->tex_density);
- fmd->domain->tex_density = NULL;
- }
-
- if (fmd->domain->tex_color) {
- GPU_texture_free(fmd->domain->tex_color);
- fmd->domain->tex_color = NULL;
- }
-
- if (fmd->domain->tex_shadow) {
- GPU_texture_free(fmd->domain->tex_shadow);
- fmd->domain->tex_shadow = NULL;
- }
-
- if (fmd->domain->tex_flame) {
- GPU_texture_free(fmd->domain->tex_flame);
- fmd->domain->tex_flame = NULL;
- }
-
- if (fmd->domain->tex_flame_coba) {
- GPU_texture_free(fmd->domain->tex_flame_coba);
- fmd->domain->tex_flame_coba = NULL;
- }
-
- if (fmd->domain->tex_coba) {
- GPU_texture_free(fmd->domain->tex_coba);
- fmd->domain->tex_coba = NULL;
- }
-
- if (fmd->domain->tex_field) {
- GPU_texture_free(fmd->domain->tex_field);
- fmd->domain->tex_field = NULL;
- }
- }
-}
-
void DRW_smoke_ensure_coba_field(FluidModifierData *fmd)
{
#ifndef WITH_FLUID
@@ -469,6 +432,7 @@ void DRW_smoke_ensure_coba_field(FluidModifierData *fmd)
if (!fds->tex_field) {
fds->tex_field = create_field_texture(fds, false);
+ BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_field));
}
if (!fds->tex_coba && !ELEM(fds->coba_field,
FLUID_DOMAIN_FIELD_PHI,
@@ -478,6 +442,7 @@ void DRW_smoke_ensure_coba_field(FluidModifierData *fmd)
FLUID_DOMAIN_FIELD_FLAGS,
FLUID_DOMAIN_FIELD_PRESSURE)) {
fds->tex_coba = create_transfer_function(TFUNC_COLOR_RAMP, fds->coba);
+ BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_coba));
}
}
#endif
@@ -493,19 +458,24 @@ void DRW_smoke_ensure(FluidModifierData *fmd, int highres)
if (!fds->tex_density) {
fds->tex_density = create_density_texture(fds, highres);
+ BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_density));
}
if (!fds->tex_color) {
fds->tex_color = create_color_texture(fds, highres);
+ BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_color));
}
if (!fds->tex_flame) {
fds->tex_flame = create_flame_texture(fds, highres);
+ BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_flame));
}
if (!fds->tex_flame_coba && fds->tex_flame) {
fds->tex_flame_coba = create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL);
+ BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_flame_coba));
}
if (!fds->tex_shadow) {
fds->tex_shadow = create_volume_texture(
fds->res, GPU_R8, GPU_DATA_FLOAT, manta_smoke_get_shadow(fds->fluid));
+ BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_shadow));
}
}
#endif /* WITH_FLUID */
@@ -536,6 +506,9 @@ void DRW_smoke_ensure_velocity(FluidModifierData *fmd)
"vely", UNPACK3(fds->res), 1, GPU_R16F, GPU_DATA_FLOAT, vel_y);
fds->tex_velocity_z = GPU_texture_create_3d(
"velz", UNPACK3(fds->res), 1, GPU_R16F, GPU_DATA_FLOAT, vel_z);
+ BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_velocity_x));
+ BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_velocity_y));
+ BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_velocity_z));
}
}
#endif /* WITH_FLUID */
@@ -551,6 +524,7 @@ void DRW_fluid_ensure_flags(FluidModifierData *fmd)
if (!fds->tex_flags) {
fds->tex_flags = create_volume_texture(
fds->res, GPU_R8UI, GPU_DATA_INT, manta_smoke_get_flags(fds->fluid));
+ BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_flags));
swizzle_texture_channel_single(fds->tex_flags);
}
@@ -568,42 +542,29 @@ void DRW_fluid_ensure_range_field(FluidModifierData *fmd)
if (!fds->tex_range_field) {
fds->tex_range_field = create_field_texture(fds, true);
+ BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_range_field));
}
}
#endif /* WITH_FLUID */
}
-void DRW_smoke_free_velocity(FluidModifierData *fmd)
+void DRW_smoke_init(DRWData *drw_data)
{
- /* TODO: Unify with the other #GPU_free_smoke. */
-
- if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) {
- if (fmd->domain->tex_velocity_x) {
- GPU_texture_free(fmd->domain->tex_velocity_x);
- }
-
- if (fmd->domain->tex_velocity_y) {
- GPU_texture_free(fmd->domain->tex_velocity_y);
- }
-
- if (fmd->domain->tex_velocity_z) {
- GPU_texture_free(fmd->domain->tex_velocity_z);
- }
-
- if (fmd->domain->tex_flags) {
- GPU_texture_free(fmd->domain->tex_flags);
- }
-
- if (fmd->domain->tex_range_field) {
- GPU_texture_free(fmd->domain->tex_range_field);
- }
+ BLI_listbase_clear(&drw_data->smoke_textures);
+}
- fmd->domain->tex_velocity_x = NULL;
- fmd->domain->tex_velocity_y = NULL;
- fmd->domain->tex_velocity_z = NULL;
- fmd->domain->tex_flags = NULL;
- fmd->domain->tex_range_field = NULL;
+void DRW_smoke_exit(DRWData *drw_data)
+{
+ /* Free Smoke Textures after rendering */
+ /* XXX This is a waste of processing and GPU bandwidth if nothing
+ * is updated. But the problem is since Textures are stored in the
+ * modifier we don't want them to take precious VRAM if the
+ * modifier is not used for display. We should share them for
+ * all viewport in a redraw at least. */
+ LISTBASE_FOREACH (LinkData *, link, &drw_data->smoke_textures) {
+ GPU_TEXTURE_FREE_SAFE(*(GPUTexture **)link->data);
}
+ BLI_freelistN(&drw_data->smoke_textures);
}
/** \} */
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
index aac6f7e58c5..8351452769d 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.c
@@ -179,25 +179,6 @@ static ParticleHairCache *drw_hair_particle_cache_get(Object *object,
return cache;
}
-static ParticleHairCache *drw_curves_cache_get(Object *object,
- GPUMaterial *gpu_material,
- int subdiv,
- int thickness_res)
-{
- ParticleHairCache *cache;
- bool update = curves_ensure_procedural_data(object, &cache, gpu_material, subdiv, thickness_res);
-
- if (update) {
- if (drw_hair_shader_type_get() == PART_REFINE_SHADER_COMPUTE) {
- drw_hair_particle_cache_update_compute(cache, subdiv);
- }
- else {
- drw_hair_particle_cache_update_transform_feedback(cache, subdiv);
- }
- }
- return cache;
-}
-
GPUVertBuf *DRW_hair_pos_buffer_get(Object *object, ParticleSystem *psys, ModifierData *md)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
@@ -212,19 +193,6 @@ GPUVertBuf *DRW_hair_pos_buffer_get(Object *object, ParticleSystem *psys, Modifi
return cache->final[subdiv].proc_buf;
}
-GPUVertBuf *DRW_curves_pos_buffer_get(Object *object)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
-
- int subdiv = scene->r.hair_subdiv;
- int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
-
- ParticleHairCache *cache = drw_curves_cache_get(object, NULL, subdiv, thickness_res);
-
- return cache->final[subdiv].proc_buf;
-}
-
void DRW_hair_duplimat_get(Object *object,
ParticleSystem *UNUSED(psys),
ModifierData *UNUSED(md),
@@ -323,71 +291,6 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object,
return shgrp;
}
-DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
- DRWShadingGroup *shgrp_parent,
- GPUMaterial *gpu_material)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
-
- int subdiv = scene->r.hair_subdiv;
- int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
-
- ParticleHairCache *curves_cache = drw_curves_cache_get(
- object, gpu_material, subdiv, thickness_res);
-
- DRWShadingGroup *shgrp = DRW_shgroup_create_sub(shgrp_parent);
-
- /* TODO: optimize this. Only bind the ones GPUMaterial needs. */
- for (int i = 0; i < curves_cache->num_uv_layers; i++) {
- for (int n = 0; n < MAX_LAYER_NAME_CT && curves_cache->uv_layer_names[i][n][0] != '\0'; n++) {
- DRW_shgroup_uniform_texture(
- shgrp, curves_cache->uv_layer_names[i][n], curves_cache->uv_tex[i]);
- }
- }
- for (int i = 0; i < curves_cache->num_col_layers; i++) {
- for (int n = 0; n < MAX_LAYER_NAME_CT && curves_cache->col_layer_names[i][n][0] != '\0'; n++) {
- DRW_shgroup_uniform_texture(
- shgrp, curves_cache->col_layer_names[i][n], curves_cache->col_tex[i]);
- }
- }
-
- /* Fix issue with certain driver not drawing anything if there is no texture bound to
- * "ac", "au", "u" or "c". */
- if (curves_cache->num_uv_layers == 0) {
- DRW_shgroup_uniform_texture(shgrp, "u", g_dummy_texture);
- DRW_shgroup_uniform_texture(shgrp, "au", g_dummy_texture);
- }
- if (curves_cache->num_col_layers == 0) {
- DRW_shgroup_uniform_texture(shgrp, "c", g_dummy_texture);
- DRW_shgroup_uniform_texture(shgrp, "ac", g_dummy_texture);
- }
-
- /* TODO: Generalize radius implementation for curves data type. */
- float hair_rad_shape = 1.0f;
- float hair_rad_root = 0.005f;
- float hair_rad_tip = 0.0f;
- bool hair_close_tip = true;
-
- DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", curves_cache->final[subdiv].proc_tex);
- if (curves_cache->length_tex) {
- DRW_shgroup_uniform_texture(shgrp, "hairLen", curves_cache->length_tex);
- }
- DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &curves_cache->final[subdiv].strands_res, 1);
- DRW_shgroup_uniform_int_copy(shgrp, "hairThicknessRes", thickness_res);
- DRW_shgroup_uniform_float_copy(shgrp, "hairRadShape", hair_rad_shape);
- DRW_shgroup_uniform_mat4_copy(shgrp, "hairDupliMatrix", object->obmat);
- DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", hair_rad_root);
- DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", hair_rad_tip);
- DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", hair_close_tip);
- /* TODO(fclem): Until we have a better way to cull the curves and render with orco, bypass
- * culling test. */
- GPUBatch *geom = curves_cache->final[subdiv].proc_hairs[thickness_res - 1];
- DRW_shgroup_call_no_cull(shgrp, geom, object);
-
- return shgrp;
-}
-
void DRW_hair_update(void)
{
#ifndef USE_TRANSFORM_FEEDBACK
diff --git a/source/blender/draw/intern/draw_hair_private.h b/source/blender/draw/intern/draw_hair_private.h
index 58e8609106b..5d84c8863f2 100644
--- a/source/blender/draw/intern/draw_hair_private.h
+++ b/source/blender/draw/intern/draw_hair_private.h
@@ -75,8 +75,6 @@ typedef struct ParticleHairCache {
int point_len;
} ParticleHairCache;
-void particle_batch_cache_clear_hair(struct ParticleHairCache *hair_cache);
-
/**
* Ensure all textures and buffers needed for GPU accelerated drawing.
*/
@@ -88,15 +86,6 @@ bool particles_ensure_procedural_data(struct Object *object,
int subdiv,
int thickness_res);
-/**
- * Ensure all textures and buffers needed for GPU accelerated drawing.
- */
-bool curves_ensure_procedural_data(struct Object *object,
- struct ParticleHairCache **r_hair_cache,
- struct GPUMaterial *gpu_material,
- int subdiv,
- int thickness_res);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 88d05fcd928..adf9d4a13df 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -478,6 +478,7 @@ void DRW_viewport_data_free(DRWData *drw_data)
MEM_freeN(drw_data->matrices_ubo);
MEM_freeN(drw_data->obinfos_ubo);
}
+ DRW_volume_ubos_pool_free(drw_data->volume_grids_ubos);
MEM_freeN(drw_data);
}
@@ -1649,7 +1650,9 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
DRW_globals_update();
drw_debug_init();
- DRW_hair_init();
+ DRW_curves_init();
+ DRW_volume_init(DST.vmempool);
+ DRW_smoke_init(DST.vmempool);
/* No frame-buffer allowed before drawing. */
BLI_assert(GPU_framebuffer_active_get() == GPU_framebuffer_back_get());
@@ -1704,7 +1707,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
GPU_framebuffer_bind(DST.default_framebuffer);
GPU_framebuffer_clear_depth_stencil(DST.default_framebuffer, 1.0f, 0xFF);
- DRW_hair_update();
+ DRW_curves_update();
DRW_draw_callbacks_pre_scene();
@@ -1715,6 +1718,8 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
GPU_flush();
}
+ DRW_smoke_exit(DST.vmempool);
+
DRW_stats_reset();
DRW_draw_callbacks_post_scene();
@@ -1999,6 +2004,8 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
GPU_framebuffer_restore();
+ DRW_smoke_exit(DST.vmempool);
+
drw_manager_exit(&DST);
/* Reset state after drawing */
@@ -2015,7 +2022,9 @@ void DRW_render_object_iter(
void (*callback)(void *vedata, Object *ob, RenderEngine *engine, struct Depsgraph *depsgraph))
{
const DRWContextState *draw_ctx = DRW_context_state_get();
- DRW_hair_init();
+ DRW_curves_init();
+ DRW_volume_init(DST.vmempool);
+ DRW_smoke_init(DST.vmempool);
drw_task_graph_init();
const int object_type_exclude_viewport = draw_ctx->v3d ?
@@ -2070,7 +2079,9 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
drw_manager_init(&DST, NULL, NULL);
- DRW_hair_init();
+ DRW_curves_init();
+ DRW_volume_init(DST.vmempool);
+ DRW_smoke_init(DST.vmempool);
ViewportEngineData *data = DRW_view_data_engine_data_get_ensure(DST.view_data_active,
draw_engine_type);
@@ -2079,6 +2090,8 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
callback(data, user_data);
DST.buffer_finish_called = false;
+ DRW_smoke_exit(DST.vmempool);
+
GPU_framebuffer_restore();
/* The use of custom pipeline in other thread using the same
@@ -2095,11 +2108,15 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
void DRW_cache_restart(void)
{
+ DRW_smoke_exit(DST.vmempool);
+
drw_manager_init(&DST, DST.viewport, (int[2]){UNPACK2(DST.size)});
DST.buffer_finish_called = false;
- DRW_hair_init();
+ DRW_curves_init();
+ DRW_volume_init(DST.vmempool);
+ DRW_smoke_init(DST.vmempool);
}
void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph,
@@ -2416,7 +2433,9 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
/* Init engines */
drw_engines_init();
- DRW_hair_init();
+ DRW_curves_init();
+ DRW_volume_init(DST.vmempool);
+ DRW_smoke_init(DST.vmempool);
{
drw_engines_cache_init();
@@ -2493,7 +2512,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
DRW_state_reset();
DRW_draw_callbacks_pre_scene();
- DRW_hair_update();
+ DRW_curves_update();
/* Only 1-2 passes. */
while (true) {
@@ -2511,6 +2530,8 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
}
}
+ DRW_smoke_exit(DST.vmempool);
+
DRW_state_reset();
drw_engines_disable();
@@ -2586,7 +2607,9 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph,
/* Init engines */
drw_engines_init();
- DRW_hair_init();
+ DRW_curves_init();
+ DRW_volume_init(DST.vmempool);
+ DRW_smoke_init(DST.vmempool);
{
drw_engines_cache_init();
@@ -2619,10 +2642,12 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph,
/* Start Drawing */
DRW_state_reset();
- DRW_hair_update();
+ DRW_curves_update();
drw_engines_draw_scene();
+ DRW_smoke_exit(DST.vmempool);
+
DRW_state_reset();
/* TODO: Reading depth for operators should be done here. */
@@ -3008,7 +3033,8 @@ void DRW_engines_free(void)
GPU_FRAMEBUFFER_FREE_SAFE(g_select_buffer.framebuffer_depth_only);
DRW_shaders_free();
- DRW_hair_free();
+ DRW_curves_free();
+ DRW_volume_free();
DRW_shape_cache_free();
DRW_stats_free();
DRW_globals_free();
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 832897b7040..8812f112014 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -527,6 +527,10 @@ typedef struct DRWData {
struct GPUUniformBuf **obinfos_ubo;
struct GHash *obattrs_ubo_pool;
uint ubo_len;
+ /** Per draw-call volume object data. */
+ void *volume_grids_ubos; /* VolumeUniformBufPool */
+ /** List of smoke textures to free after drawing. */
+ ListBase smoke_textures;
/** Texture pool to reuse temp texture across engines. */
/* TODO(@fclem): The pool could be shared even between view-ports. */
struct DRWTexturePool *texture_pool;
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index 39f083aaf96..b5432da0957 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -15,6 +15,7 @@
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
+#include "BKE_volume.h"
#include "DNA_curve_types.h"
#include "DNA_mesh_types.h"
@@ -555,10 +556,19 @@ void DRW_shgroup_vertex_buffer_ref_ex(DRWShadingGroup *shgroup,
static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[4])
{
ID *ob_data = (ob) ? ob->data : NULL;
+ float loc[3], size[3];
float *texcoloc = NULL;
float *texcosize = NULL;
if (ob_data != NULL) {
switch (GS(ob_data->name)) {
+ case ID_VO: {
+ BoundBox *bbox = BKE_volume_boundbox_get(ob);
+ mid_v3_v3v3(loc, bbox->vec[0], bbox->vec[6]);
+ sub_v3_v3v3(size, bbox->vec[0], bbox->vec[6]);
+ texcoloc = loc;
+ texcosize = size;
+ break;
+ }
case ID_ME:
BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, &texcosize);
break;
diff --git a/source/blender/draw/intern/draw_shader.c b/source/blender/draw/intern/draw_shader.c
index 53da300c106..487a09d313d 100644
--- a/source/blender/draw/intern/draw_shader.c
+++ b/source/blender/draw/intern/draw_shader.c
@@ -92,6 +92,30 @@ GPUShader *DRW_shader_hair_refine_get(ParticleRefineShader refinement,
return e_data.hair_refine_sh[refinement];
}
+GPUShader *DRW_shader_curves_refine_get(CurvesEvalShader type, eParticleRefineShaderType sh_type)
+{
+ /* TODO: Implement curves evaluation types (Bezier and Catmull Rom). */
+ if (e_data.hair_refine_sh[type] == NULL) {
+ GPUShader *sh = NULL;
+ switch (sh_type) {
+ case PART_REFINE_SHADER_COMPUTE:
+ sh = hair_refine_shader_compute_create(type);
+ break;
+ case PART_REFINE_SHADER_TRANSFORM_FEEDBACK:
+ sh = hair_refine_shader_transform_feedback_create(type);
+ break;
+ case PART_REFINE_SHADER_TRANSFORM_FEEDBACK_WORKAROUND:
+ sh = hair_refine_shader_transform_feedback_workaround_create(type);
+ break;
+ default:
+ BLI_assert_msg(0, "Incorrect shader type");
+ }
+ e_data.hair_refine_sh[type] = sh;
+ }
+
+ return e_data.hair_refine_sh[type];
+}
+
/** \} */
void DRW_shaders_free(void)
diff --git a/source/blender/draw/intern/draw_shader.h b/source/blender/draw/intern/draw_shader.h
index 65b9cafc1d9..650e78c9362 100644
--- a/source/blender/draw/intern/draw_shader.h
+++ b/source/blender/draw/intern/draw_shader.h
@@ -7,6 +7,7 @@
#pragma once
+#include "draw_curves_private.h"
#include "draw_hair_private.h"
#ifdef __cplusplus
@@ -25,6 +26,10 @@ typedef enum eParticleRefineShaderType {
struct GPUShader *DRW_shader_hair_refine_get(ParticleRefineShader refinement,
eParticleRefineShaderType sh_type);
+
+struct GPUShader *DRW_shader_curves_refine_get(CurvesEvalShader type,
+ eParticleRefineShaderType sh_type);
+
void DRW_shaders_free(void);
#ifdef __cplusplus
diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h
index 58875c0496a..db128fffde7 100644
--- a/source/blender/draw/intern/draw_shader_shared.h
+++ b/source/blender/draw/intern/draw_shader_shared.h
@@ -6,12 +6,16 @@
typedef struct ViewInfos ViewInfos;
typedef struct ObjectMatrices ObjectMatrices;
typedef struct ObjectInfos ObjectInfos;
+typedef struct VolumeInfos VolumeInfos;
#endif
#define DRW_SHADER_SHARED_H
#define DRW_RESOURCE_CHUNK_LEN 512
+/* Define the maximum number of grid we allow in a volume UBO. */
+#define DRW_GRID_PER_VOLUME_MAX 16
+
struct ViewInfos {
/* View matrices */
float4x4 persmat;
@@ -63,6 +67,18 @@ struct ObjectInfos {
};
BLI_STATIC_ASSERT_ALIGN(ViewInfos, 16)
+struct VolumeInfos {
+ /* Object to grid-space. */
+ float4x4 grids_xform[DRW_GRID_PER_VOLUME_MAX];
+ /* NOTE: vec4 for alignment. Only float3 needed. */
+ float4 color_mul;
+ float density_scale;
+ float temperature_mul;
+ float temperature_bias;
+ float _pad;
+};
+BLI_STATIC_ASSERT_ALIGN(VolumeInfos, 16)
+
#define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors)
#define ObjectInfo (drw_infos[resource_id].drw_Infos)
#define ObjectColor (drw_infos[resource_id].drw_ObjectColor)
diff --git a/source/blender/draw/intern/draw_volume.cc b/source/blender/draw/intern/draw_volume.cc
new file mode 100644
index 00000000000..8d9a6f486e2
--- /dev/null
+++ b/source/blender/draw/intern/draw_volume.cc
@@ -0,0 +1,263 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup draw
+ *
+ * \brief Contains Volume object GPU attributes configuration.
+ */
+
+#include "DRW_gpu_wrapper.hh"
+#include "DRW_render.h"
+
+#include "DNA_fluid_types.h"
+#include "DNA_volume_types.h"
+
+#include "BKE_fluid.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_volume.h"
+#include "BKE_volume_render.h"
+
+#include "GPU_material.h"
+
+#include "draw_common.h"
+#include "draw_manager.h"
+
+using namespace blender;
+using namespace blender::draw;
+using VolumeInfosBuf = blender::draw::UniformBuffer<VolumeInfos>;
+
+static struct {
+ GPUTexture *dummy_zero;
+ GPUTexture *dummy_one;
+ float dummy_grid_mat[4][4];
+} g_data = {};
+
+struct VolumeUniformBufPool {
+ Vector<VolumeInfosBuf *> ubos;
+ uint used = 0;
+
+ ~VolumeUniformBufPool()
+ {
+ for (VolumeInfosBuf *ubo : ubos) {
+ delete ubo;
+ }
+ }
+
+ void reset()
+ {
+ used = 0;
+ }
+
+ VolumeInfosBuf *alloc()
+ {
+ if (used >= ubos.size()) {
+ VolumeInfosBuf *buf = new VolumeInfosBuf();
+ ubos.append(buf);
+ return buf;
+ }
+ return ubos[used++];
+ }
+};
+
+void DRW_volume_ubos_pool_free(void *pool)
+{
+ delete reinterpret_cast<VolumeUniformBufPool *>(pool);
+}
+
+static void drw_volume_globals_init()
+{
+ const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ const float one[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ g_data.dummy_zero = GPU_texture_create_3d(
+ "dummy_zero", 1, 1, 1, 1, GPU_RGBA8, GPU_DATA_FLOAT, zero);
+ g_data.dummy_one = GPU_texture_create_3d(
+ "dummy_one", 1, 1, 1, 1, GPU_RGBA8, GPU_DATA_FLOAT, one);
+ GPU_texture_wrap_mode(g_data.dummy_zero, true, true);
+ GPU_texture_wrap_mode(g_data.dummy_one, true, true);
+
+ memset(g_data.dummy_grid_mat, 0, sizeof(g_data.dummy_grid_mat));
+}
+
+void DRW_volume_free(void)
+{
+ GPU_TEXTURE_FREE_SAFE(g_data.dummy_zero);
+ GPU_TEXTURE_FREE_SAFE(g_data.dummy_one);
+}
+
+static GPUTexture *grid_default_texture(eGPUDefaultValue default_value)
+{
+ switch (default_value) {
+ case GPU_DEFAULT_0:
+ return g_data.dummy_zero;
+ case GPU_DEFAULT_1:
+ return g_data.dummy_one;
+ }
+ return g_data.dummy_zero;
+}
+
+void DRW_volume_init(DRWData *drw_data)
+{
+ if (drw_data->volume_grids_ubos == nullptr) {
+ drw_data->volume_grids_ubos = new VolumeUniformBufPool();
+ }
+ VolumeUniformBufPool *pool = (VolumeUniformBufPool *)drw_data->volume_grids_ubos;
+ pool->reset();
+
+ if (g_data.dummy_one == nullptr) {
+ drw_volume_globals_init();
+ }
+}
+
+static DRWShadingGroup *drw_volume_object_grids_init(Object *ob,
+ ListBase *attrs,
+ DRWShadingGroup *grp)
+{
+ VolumeUniformBufPool *pool = (VolumeUniformBufPool *)DST.vmempool->volume_grids_ubos;
+ VolumeInfosBuf &volume_infos = *pool->alloc();
+
+ Volume *volume = (Volume *)ob->data;
+ BKE_volume_load(volume, G.main);
+
+ grp = DRW_shgroup_create_sub(grp);
+
+ volume_infos.density_scale = BKE_volume_density_scale(volume, ob->obmat);
+ volume_infos.color_mul = float4(1.0f);
+ volume_infos.temperature_mul = 1.0f;
+ volume_infos.temperature_bias = 0.0f;
+
+ /* Bind volume grid textures. */
+ int grid_id = 0;
+ LISTBASE_FOREACH (GPUMaterialAttribute *, attr, attrs) {
+ const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, attr->name);
+ const DRWVolumeGrid *drw_grid = (volume_grid) ?
+ DRW_volume_batch_cache_get_grid(volume, volume_grid) :
+ nullptr;
+
+ /* Handle 3 cases here:
+ * - Grid exists and texture was loaded -> use texture.
+ * - Grid exists but has zero size or failed to load -> use zero.
+ * - Grid does not exist -> use default value. */
+ const GPUTexture *grid_tex = (drw_grid) ? drw_grid->texture :
+ (volume_grid) ? g_data.dummy_zero :
+ grid_default_texture(attr->default_value);
+ DRW_shgroup_uniform_texture(grp, attr->input_name, grid_tex);
+
+ copy_m4_m4(volume_infos.grids_xform[grid_id++].ptr(), drw_grid->object_to_texture);
+ }
+
+ volume_infos.push_update();
+
+ DRW_shgroup_uniform_block(grp, "drw_volume", volume_infos);
+
+ return grp;
+}
+
+static DRWShadingGroup *drw_volume_object_mesh_init(Scene *scene,
+ Object *ob,
+ ListBase *attrs,
+ DRWShadingGroup *grp)
+{
+ VolumeUniformBufPool *pool = (VolumeUniformBufPool *)DST.vmempool->volume_grids_ubos;
+ VolumeInfosBuf &volume_infos = *pool->alloc();
+
+ ModifierData *md = nullptr;
+
+ volume_infos.density_scale = 1.0f;
+ volume_infos.color_mul = float4(1.0f);
+ volume_infos.temperature_mul = 1.0f;
+ volume_infos.temperature_bias = 0.0f;
+
+ /* Smoke Simulation */
+ if ((md = BKE_modifiers_findby_type(ob, eModifierType_Fluid)) &&
+ (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) &&
+ ((FluidModifierData *)md)->domain != nullptr) {
+ FluidModifierData *fmd = (FluidModifierData *)md;
+ FluidDomainSettings *fds = fmd->domain;
+
+ /* Don't try to show liquid domains here. */
+ if (!fds->fluid || !(fds->type == FLUID_DOMAIN_TYPE_GAS)) {
+ return nullptr;
+ }
+
+ if (fds->fluid && (fds->type == FLUID_DOMAIN_TYPE_GAS)) {
+ DRW_smoke_ensure(fmd, fds->flags & FLUID_DOMAIN_USE_NOISE);
+ }
+
+ grp = DRW_shgroup_create_sub(grp);
+
+ int grid_id = 0;
+ LISTBASE_FOREACH (GPUMaterialAttribute *, attr, attrs) {
+ if (STREQ(attr->name, "density")) {
+ DRW_shgroup_uniform_texture_ref(
+ grp, attr->input_name, fds->tex_density ? &fds->tex_density : &g_data.dummy_one);
+ }
+ else if (STREQ(attr->name, "color")) {
+ DRW_shgroup_uniform_texture_ref(
+ grp, attr->input_name, fds->tex_color ? &fds->tex_color : &g_data.dummy_one);
+ }
+ else if (STR_ELEM(attr->name, "flame", "temperature")) {
+ DRW_shgroup_uniform_texture_ref(
+ grp, attr->input_name, fds->tex_flame ? &fds->tex_flame : &g_data.dummy_zero);
+ }
+ else {
+ DRW_shgroup_uniform_texture(
+ grp, attr->input_name, grid_default_texture(attr->default_value));
+ }
+ copy_m4_m4(volume_infos.grids_xform[grid_id++].ptr(), g_data.dummy_grid_mat);
+ }
+
+ bool use_constant_color = ((fds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 &&
+ (fds->active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0);
+ if (use_constant_color) {
+ volume_infos.color_mul = float4(UNPACK3(fds->active_color), 1.0f);
+ }
+
+ /* Output is such that 0..1 maps to 0..1000K */
+ volume_infos.temperature_mul = fds->flame_max_temp - fds->flame_ignition;
+ volume_infos.temperature_bias = fds->flame_ignition;
+ }
+ else {
+ grp = DRW_shgroup_create_sub(grp);
+
+ int grid_id = 0;
+ LISTBASE_FOREACH (GPUMaterialAttribute *, attr, attrs) {
+ DRW_shgroup_uniform_texture(
+ grp, attr->input_name, grid_default_texture(attr->default_value));
+ copy_m4_m4(volume_infos.grids_xform[grid_id++].ptr(), g_data.dummy_grid_mat);
+ }
+ }
+
+ volume_infos.push_update();
+
+ DRW_shgroup_uniform_block(grp, "drw_volume", volume_infos);
+
+ return grp;
+}
+
+static DRWShadingGroup *drw_volume_world_grids_init(ListBase *attrs, DRWShadingGroup *grp)
+{
+ /* Bind default volume grid textures. */
+ LISTBASE_FOREACH (GPUMaterialAttribute *, attr, attrs) {
+ DRW_shgroup_uniform_texture(grp, attr->input_name, grid_default_texture(attr->default_value));
+ }
+ return grp;
+}
+
+DRWShadingGroup *DRW_shgroup_volume_create_sub(Scene *scene,
+ Object *ob,
+ DRWShadingGroup *shgrp,
+ GPUMaterial *gpu_material)
+{
+ ListBase attrs = GPU_material_attributes(gpu_material);
+
+ if (ob == nullptr) {
+ return drw_volume_world_grids_init(&attrs, shgrp);
+ }
+ if (ob->type == OB_VOLUME) {
+ return drw_volume_object_grids_init(ob, &attrs, shgrp);
+ }
+ return drw_volume_object_mesh_init(scene, ob, &attrs, shgrp);
+}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
index d52226a4c90..4cb68cad66c 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
@@ -173,7 +173,7 @@ static void extract_vcol_init(const MeshRenderData *mr,
}
BMIter iter;
- const bool is_byte = ref.layer->type == CD_MLOOPCOL;
+ const bool is_byte = ref.layer->type == CD_PROP_BYTE_COLOR;
const bool is_point = ref.domain == ATTR_DOMAIN_POINT;
BMFace *f;
@@ -318,7 +318,7 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
BMIter iter;
BMFace *f;
int cd_ofs = cdata->layers[layer_i].offset;
- const bool is_byte = ref.layer->type == CD_MLOOPCOL;
+ const bool is_byte = ref.layer->type == CD_PROP_BYTE_COLOR;
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
BMLoop *l_iter = f->l_first;
diff --git a/source/blender/draw/intern/shaders/common_attribute_lib.glsl b/source/blender/draw/intern/shaders/common_attribute_lib.glsl
index 99db2929a13..30239a84c0c 100644
--- a/source/blender/draw/intern/shaders/common_attribute_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_attribute_lib.glsl
@@ -19,3 +19,15 @@ vec4 attr_load_vec4(samplerBuffer attr);
vec3 attr_load_vec3(samplerBuffer attr);
vec2 attr_load_vec2(samplerBuffer attr);
float attr_load_float(samplerBuffer attr);
+
+vec3 attr_load_orco(sampler3D orco);
+vec4 attr_load_tangent(sampler3D tangent);
+vec3 attr_load_uv(sampler3D attr);
+vec4 attr_load_color(sampler3D tex);
+vec4 attr_load_vec4(sampler3D tex);
+vec3 attr_load_vec3(sampler3D tex);
+vec2 attr_load_vec2(sampler3D tex);
+float attr_load_float(sampler3D tex);
+
+float attr_load_temperature_post(float attr);
+vec4 attr_load_color_post(vec4 attr);
diff --git a/source/blender/draw/intern/shaders/draw_object_infos_info.hh b/source/blender/draw/intern/shaders/draw_object_infos_info.hh
index 392b016fc3b..c74a043ec97 100644
--- a/source/blender/draw/intern/shaders/draw_object_infos_info.hh
+++ b/source/blender/draw/intern/shaders/draw_object_infos_info.hh
@@ -6,3 +6,7 @@ GPU_SHADER_CREATE_INFO(draw_object_infos)
.typedef_source("draw_shader_shared.h")
.define("OBINFO_LIB")
.uniform_buf(1, "ObjectInfos", "drw_infos[DRW_RESOURCE_CHUNK_LEN]", Frequency::BATCH);
+
+GPU_SHADER_CREATE_INFO(draw_volume_infos)
+ .typedef_source("draw_shader_shared.h")
+ .uniform_buf(2, "VolumeInfos", "drw_volume", Frequency::BATCH);
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 5b742ddf272..14a3b958ea6 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -1126,17 +1126,17 @@ static void get_keyframe_values_create_reports(ReportList *reports,
for (int i = 0; i < count; i++) {
const bool cur_index_evaluated = ELEM(index, i, -1) || force_all;
if (!cur_index_evaluated) {
- /* values[i] was never intended to be remapped. */
+ /* `values[i]` was never intended to be remapped. */
continue;
}
if (BLI_BITMAP_TEST_BOOL(successful_remaps, i)) {
- /* values[i] succesfully remapped. */
+ /* `values[i]` successfully remapped. */
continue;
}
total_failed++;
- /* Report that values[i] were intended to be remapped but failed remapping process. */
+ /* Report that `values[i]` were intended to be remapped but failed remapping process. */
BLI_dynstr_appendf(ds_failed_indices, "%d, ", i);
}
diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc
index 467b8efa622..452f1df86fb 100644
--- a/source/blender/editors/geometry/geometry_attributes.cc
+++ b/source/blender/editors/geometry/geometry_attributes.cc
@@ -241,7 +241,6 @@ enum class ConvertAttributeMode {
Generic,
UVMap,
VertexGroup,
- VertexColor,
};
static bool geometry_attribute_convert_poll(bContext *C)
@@ -288,7 +287,7 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op)
const CustomDataType dst_type = static_cast<CustomDataType>(
RNA_enum_get(op->ptr, "data_type"));
- if (ELEM(dst_type, CD_PROP_STRING, CD_MLOOPCOL)) {
+ if (ELEM(dst_type, CD_PROP_STRING)) {
BKE_report(op->reports, RPT_ERROR, "Cannot convert to the selected type");
return OPERATOR_CANCELLED;
}
@@ -314,20 +313,6 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op)
&mesh->ldata, CD_MLOOPUV, CD_ASSIGN, dst_uvs, mesh->totloop, name.c_str());
break;
}
- case ConvertAttributeMode::VertexColor: {
- MLoopCol *dst_colors = static_cast<MLoopCol *>(
- MEM_calloc_arrayN(mesh->totloop, sizeof(MLoopCol), __func__));
- VArray<ColorGeometry4f> src_varray = mesh_component.attribute_get_for_read<ColorGeometry4f>(
- name, ATTR_DOMAIN_CORNER, ColorGeometry4f{0.0f, 0.0f, 0.0f, 1.0f});
- for (const int i : IndexRange(mesh->totloop)) {
- ColorGeometry4b encoded_color = src_varray[i].encode();
- copy_v4_v4_uchar(&dst_colors[i].r, &encoded_color.r);
- }
- mesh_component.attribute_try_delete(name);
- CustomData_add_layer_named(
- &mesh->ldata, CD_MLOOPCOL, CD_ASSIGN, dst_colors, mesh->totloop, name.c_str());
- break;
- }
case ConvertAttributeMode::VertexGroup: {
Array<float> src_weights(mesh->totvert);
VArray<float> src_varray = mesh_component.attribute_get_for_read<float>(
@@ -385,7 +370,7 @@ void GEOMETRY_OT_color_attribute_add(wmOperatorType *ot)
{0, nullptr, 0, nullptr, nullptr}};
static EnumPropertyItem types[3] = {{CD_PROP_COLOR, "COLOR", 0, "Color", ""},
- {CD_MLOOPCOL, "BYTE_COLOR", 0, "Byte Color", ""},
+ {CD_PROP_BYTE_COLOR, "BYTE_COLOR", 0, "Byte Color", ""},
{0, nullptr, 0, nullptr, nullptr}};
prop = RNA_def_enum(ot->srna,
@@ -415,9 +400,9 @@ static int geometry_color_attribute_set_render_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "name", name);
CustomDataLayer *layer = BKE_id_attribute_find(id, name, CD_PROP_COLOR, ATTR_DOMAIN_POINT);
- layer = !layer ? BKE_id_attribute_find(id, name, CD_MLOOPCOL, ATTR_DOMAIN_POINT) : layer;
+ layer = !layer ? BKE_id_attribute_find(id, name, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_POINT) : layer;
layer = !layer ? BKE_id_attribute_find(id, name, CD_PROP_COLOR, ATTR_DOMAIN_CORNER) : layer;
- layer = !layer ? BKE_id_attribute_find(id, name, CD_MLOOPCOL, ATTR_DOMAIN_CORNER) : layer;
+ layer = !layer ? BKE_id_attribute_find(id, name, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_CORNER) : layer;
if (layer) {
BKE_id_attributes_render_color_set(id, layer);
@@ -550,7 +535,6 @@ void GEOMETRY_OT_attribute_convert(wmOperatorType *ot)
{int(ConvertAttributeMode::Generic), "GENERIC", 0, "Generic", ""},
{int(ConvertAttributeMode::UVMap), "UV_MAP", 0, "UV Map", ""},
{int(ConvertAttributeMode::VertexGroup), "VERTEX_GROUP", 0, "Vertex Group", ""},
- {int(ConvertAttributeMode::VertexColor), "VERTEX_COLOR", 0, "Color Attribute", ""},
{0, nullptr, 0, nullptr, nullptr},
};
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
index e4cb6d149f5..54aa5d16941 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
@@ -99,7 +99,7 @@ static void cage2d_draw_box_corners(const rctf *r,
const float color[3],
const float line_width)
{
- /* Note(Metal): Prefer using 3D coordinates with 3D shader, even if rendering 2D gizmo's. */
+ /* NOTE(Metal): Prefer using 3D coordinates with 3D shader, even if rendering 2D gizmo's. */
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
@@ -442,7 +442,7 @@ static void imm_draw_point_aspect_2d(
uint pos, float x, float y, float rad_x, float rad_y, bool solid)
{
if (solid) {
- /* Note(Metal/AMD): Small Triangle-list primitives more optimal for GPU HW than Trianglestrip.
+ /* NOTE(Metal/AMD): Small Triangle-list primitives more optimal for GPU HW than Triangle-strip.
*/
immBegin(GPU_PRIM_TRIS, 6);
immVertex2f(pos, x - rad_x, y - rad_y);
@@ -455,7 +455,7 @@ static void imm_draw_point_aspect_2d(
immEnd();
}
else {
- /* Note(Metal/AMD): Small Line-list primitives more optimal for GPU HW than Linestrip. */
+ /* NOTE(Metal/AMD): Small Line-list primitives more optimal for GPU HW than Line-strip. */
immBegin(GPU_PRIM_LINES, 8);
immVertex2f(pos, x - rad_x, y - rad_y);
immVertex2f(pos, x - rad_x, y + rad_y);
@@ -479,7 +479,7 @@ static void cage2d_draw_circle_wire(const rctf *r,
const int draw_options,
const float line_width)
{
- /* Note(Metal): Prefer using 3D coordinates with 3D shader input, even if rendering 2D gizmo's.
+ /* NOTE(Metal): Prefer using 3D coordinates with 3D shader input, even if rendering 2D gizmo's.
*/
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
@@ -491,7 +491,7 @@ static void cage2d_draw_circle_wire(const rctf *r,
immUniform2fv("viewportSize", &viewport[2]);
immUniform1f("lineWidth", line_width * U.pixelsize);
- /* Small 'lines' primitives more efficient for hardware processing than linestrip. */
+ /* Small 'lines' primitives more efficient for hardware processing than line-strip. */
immBegin(GPU_PRIM_LINES, 8);
immVertex3f(pos, r->xmin, r->ymin, 0.0f);
immVertex3f(pos, r->xmax, r->ymin, 0.0f);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 93a4a784674..7c7f532f087 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -1313,7 +1313,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
/* Calc geometry data. */
BKE_gpencil_stroke_geometry_update(gpd, gps);
- /* In Multiframe mode, duplicate the stroke in other frames. */
+ /* In multi-frame mode, duplicate the stroke in other frames. */
if (GPENCIL_MULTIEDIT_SESSIONS_ON(p->gpd)) {
const bool tail = (ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK);
BKE_gpencil_stroke_copy_to_keyframes(gpd, gpl, p->gpf, gps, tail);
diff --git a/source/blender/editors/include/ED_space_api.h b/source/blender/editors/include/ED_space_api.h
index fd4a28240fa..c69698f3f73 100644
--- a/source/blender/editors/include/ED_space_api.h
+++ b/source/blender/editors/include/ED_space_api.h
@@ -18,7 +18,7 @@ struct bContext;
void ED_spacetypes_init(void);
void ED_spacemacros_init(void);
-/* the pluginnable API for export to editors */
+/* The plugin-able API for export to editors. */
/* -------------------------------------------------------------------- */
/** \name Calls for registering default spaces
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index a5e2e9353bf..4e6437e043a 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -13,6 +13,7 @@
#include "DNA_brush_types.h"
#include "DNA_cachefile_types.h"
+#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curveprofile_types.h"
#include "DNA_gpencil_modifier_types.h"
@@ -588,6 +589,234 @@ void UI_context_active_but_prop_get_templateID(bContext *C,
}
}
+static void template_id_liboverride_hierarchy_collection_root_find_recursive(
+ Collection *collection,
+ const int parent_level,
+ Collection **r_collection_parent_best,
+ int *r_parent_level_best)
+{
+ if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY_REAL(collection)) {
+ return;
+ }
+ if (ID_IS_OVERRIDABLE_LIBRARY(collection) || ID_IS_OVERRIDE_LIBRARY_REAL(collection)) {
+ if (parent_level > *r_parent_level_best) {
+ *r_parent_level_best = parent_level;
+ *r_collection_parent_best = collection;
+ }
+ }
+ for (CollectionParent *iter = collection->parents.first; iter != NULL; iter = iter->next) {
+ if (iter->collection->id.lib != collection->id.lib && ID_IS_LINKED(iter->collection)) {
+ continue;
+ }
+ template_id_liboverride_hierarchy_collection_root_find_recursive(
+ iter->collection, parent_level + 1, r_collection_parent_best, r_parent_level_best);
+ }
+}
+
+static void template_id_liboverride_hierarchy_collections_tag_recursive(
+ Collection *root_collection, ID *target_id, const bool do_parents)
+{
+ root_collection->id.tag |= LIB_TAG_DOIT;
+
+ /* Tag all local parents of the root collection, so that usages of the root collection and other
+ * linked ones can be replaced by the local overrides in those parents too. */
+ if (do_parents) {
+ for (CollectionParent *iter = root_collection->parents.first; iter != NULL;
+ iter = iter->next) {
+ if (ID_IS_LINKED(iter->collection)) {
+ continue;
+ }
+ iter->collection->id.tag |= LIB_TAG_DOIT;
+ }
+ }
+
+ for (CollectionChild *iter = root_collection->children.first; iter != NULL; iter = iter->next) {
+ if (iter->collection->id.lib != root_collection->id.lib && ID_IS_LINKED(root_collection)) {
+ continue;
+ }
+ if (ID_IS_LINKED(iter->collection) && iter->collection->id.lib != target_id->lib) {
+ continue;
+ }
+ if (GS(target_id->name) == ID_OB &&
+ !BKE_collection_has_object_recursive(iter->collection, (Object *)target_id)) {
+ continue;
+ }
+ if (GS(target_id->name) == ID_GR &&
+ !BKE_collection_has_collection(iter->collection, (Collection *)target_id)) {
+ continue;
+ }
+ template_id_liboverride_hierarchy_collections_tag_recursive(
+ iter->collection, target_id, false);
+ }
+}
+
+static void template_id_liboverride_hierarchy_create(bContext *C,
+ Main *bmain,
+ TemplateID *template_ui,
+ PointerRNA *idptr,
+ const char **r_undo_push_label)
+{
+ ID *id = idptr->data;
+ ID *owner_id = template_ui->ptr.owner_id;
+
+ /* Attempt to perform a hierarchy override, based on contextual data available.
+ * NOTE: do not attempt to perform such hierarchy override at all cost, if there is not enough
+ * context, better to abort than create random overrides all over the place. */
+ if (!ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(id)) {
+ return;
+ }
+
+ Object *object_active = CTX_data_active_object(C);
+ if (object_active == NULL && GS(owner_id->name) == ID_OB) {
+ object_active = (Object *)owner_id;
+ }
+ if (object_active != NULL) {
+ if (ID_IS_LINKED(object_active)) {
+ if (object_active->id.lib != id->lib ||
+ !ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(object_active)) {
+ /* The active object is from a different library than the overridden ID, or otherwise
+ * cannot be used in hierarchy. */
+ object_active = NULL;
+ }
+ }
+ else if (!ID_IS_OVERRIDE_LIBRARY_REAL(object_active)) {
+ /* Fully local object cannot be used in override hierarchy either. */
+ object_active = NULL;
+ }
+ }
+
+ Collection *collection_active = CTX_data_collection(C);
+ if (collection_active == NULL && GS(owner_id->name) == ID_GR) {
+ collection_active = (Collection *)owner_id;
+ }
+ if (collection_active != NULL) {
+ if (ID_IS_LINKED(collection_active)) {
+ if (collection_active->id.lib != id->lib ||
+ !ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(collection_active)) {
+ /* The active collection is from a different library than the overridden ID, or otherwise
+ * cannot be used in hierarchy. */
+ collection_active = NULL;
+ }
+ else {
+ int parent_level_best = -1;
+ Collection *collection_parent_best = NULL;
+ template_id_liboverride_hierarchy_collection_root_find_recursive(
+ collection_active, 0, &collection_parent_best, &parent_level_best);
+ collection_active = collection_parent_best;
+ }
+ }
+ else if (!ID_IS_OVERRIDE_LIBRARY_REAL(collection_active)) {
+ /* Fully local collection cannot be used in override hierarchy either. */
+ collection_active = NULL;
+ }
+ }
+ if (collection_active == NULL && object_active != NULL &&
+ (ID_IS_LINKED(object_active) || ID_IS_OVERRIDE_LIBRARY_REAL(object_active))) {
+ /* If we failed to find a valid 'active' collection so far for our override hierarchy, but do
+ * have a valid 'active' object, try to find a collection from that object. */
+ LISTBASE_FOREACH (Collection *, collection_iter, &bmain->collections) {
+ if (!(ID_IS_LINKED(collection_iter) || ID_IS_OVERRIDE_LIBRARY_REAL(collection_iter))) {
+ continue;
+ }
+ if (!BKE_collection_has_object_recursive(collection_iter, object_active)) {
+ continue;
+ }
+ int parent_level_best = -1;
+ Collection *collection_parent_best = NULL;
+ template_id_liboverride_hierarchy_collection_root_find_recursive(
+ collection_iter, 0, &collection_parent_best, &parent_level_best);
+ collection_active = collection_parent_best;
+ break;
+ }
+ }
+
+ ID *id_override = NULL;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ switch (GS(id->name)) {
+ case ID_GR:
+ if (collection_active != NULL &&
+ BKE_collection_has_collection(collection_active, (Collection *)id)) {
+ template_id_liboverride_hierarchy_collections_tag_recursive(collection_active, id, true);
+ if (object_active != NULL) {
+ object_active->id.tag |= LIB_TAG_DOIT;
+ }
+ BKE_lib_override_library_create(
+ bmain, scene, view_layer, NULL, id, &collection_active->id, NULL, &id_override);
+ }
+ else if (object_active != NULL && !ID_IS_LINKED(object_active) &&
+ &object_active->instance_collection->id == id) {
+ object_active->id.tag |= LIB_TAG_DOIT;
+ BKE_lib_override_library_create(bmain,
+ scene,
+ view_layer,
+ id->lib,
+ id,
+ &object_active->id,
+ &object_active->id,
+ &id_override);
+ }
+ break;
+ case ID_OB:
+ if (collection_active != NULL &&
+ BKE_collection_has_object_recursive(collection_active, (Object *)id)) {
+ template_id_liboverride_hierarchy_collections_tag_recursive(collection_active, id, true);
+ if (object_active != NULL) {
+ object_active->id.tag |= LIB_TAG_DOIT;
+ }
+ BKE_lib_override_library_create(
+ bmain, scene, view_layer, NULL, id, &collection_active->id, NULL, &id_override);
+ }
+ break;
+ case ID_ME:
+ case ID_CU_LEGACY:
+ case ID_MB:
+ case ID_LT:
+ case ID_LA:
+ case ID_CA:
+ case ID_SPK:
+ case ID_AR:
+ case ID_GD:
+ case ID_CV:
+ case ID_PT:
+ case ID_VO:
+ if (object_active != NULL && object_active->data == id) {
+ if (collection_active != NULL &&
+ BKE_collection_has_object_recursive(collection_active, object_active)) {
+ template_id_liboverride_hierarchy_collections_tag_recursive(collection_active, id, true);
+ if (object_active != NULL) {
+ object_active->id.tag |= LIB_TAG_DOIT;
+ }
+ BKE_lib_override_library_create(
+ bmain, scene, view_layer, NULL, id, &collection_active->id, NULL, &id_override);
+ }
+ else {
+ object_active->id.tag |= LIB_TAG_DOIT;
+ BKE_lib_override_library_create(
+ bmain, scene, view_layer, NULL, id, &object_active->id, NULL, &id_override);
+ }
+ }
+ break;
+ case ID_MA:
+ case ID_TE:
+ case ID_IM:
+ break;
+ case ID_WO:
+ break;
+ case ID_PA:
+ break;
+ default:
+ break;
+ }
+ if (id_override != NULL) {
+ id_override->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;
+ *r_undo_push_label = "Make Library Override Hierarchy";
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+ DEG_relations_tag_update(bmain);
+ }
+}
+
static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
{
TemplateID *template_ui = (TemplateID *)arg_litem;
@@ -637,33 +866,8 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
if (id) {
Main *bmain = CTX_data_main(C);
if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
- if (ID_IS_OVERRIDABLE_LIBRARY(id)) {
- /* Only remap that specific ID usage to overriding local data-block. */
- ID *override_id = BKE_lib_override_library_create_from_id(bmain, id, false);
- if (override_id != NULL) {
- BKE_main_id_newptr_and_tag_clear(bmain);
-
- if (GS(override_id->name) == ID_OB) {
- Scene *scene = CTX_data_scene(C);
- if (!BKE_collection_has_object_recursive(scene->master_collection,
- (Object *)override_id)) {
- BKE_collection_object_add_from(
- bmain, scene, (Object *)id, (Object *)override_id);
- }
- }
-
- /* Assign new pointer, takes care of updates/notifiers */
- RNA_id_pointer_create(override_id, &idptr);
- /* Insert into override hierarchy if possible. */
- ID *owner_id = template_ui->ptr.owner_id;
- if (owner_id != NULL && ID_IS_OVERRIDE_LIBRARY_REAL(owner_id)) {
- override_id->override_library->hierarchy_root =
- owner_id->override_library->hierarchy_root;
- owner_id->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_NO_HIERARCHY;
- }
- }
- undo_push_label = "Make Library Override";
- }
+ template_id_liboverride_hierarchy_create(
+ C, bmain, template_ui, &idptr, &undo_push_label);
}
else {
if (BKE_lib_id_make_local(bmain, id, 0)) {
@@ -1006,6 +1210,7 @@ static void template_ID(const bContext *C,
}
if (ID_IS_LINKED(id)) {
+ const bool disabled = !BKE_idtype_idcode_is_localizable(GS(id->name));
if (id->tag & LIB_TAG_INDIRECT) {
but = uiDefIconBut(block,
UI_BTYPE_BUT,
@@ -1020,12 +1225,10 @@ static void template_ID(const bContext *C,
0,
0,
0,
- TIP_("Indirect library data-block, cannot change"));
- UI_but_flag_enable(but, UI_BUT_DISABLED);
+ TIP_("Indirect library data-block, cannot be made local, "
+ "Shift + Click to create a library override hierarchy"));
}
else {
- const bool disabled = (!BKE_idtype_idcode_is_localizable(GS(id->name)) ||
- (idfrom && idfrom->lib));
but = uiDefIconBut(block,
UI_BTYPE_BUT,
0,
@@ -1041,13 +1244,13 @@ static void template_ID(const bContext *C,
0,
TIP_("Direct linked library data-block, click to make local, "
"Shift + Click to create a library override"));
- if (disabled) {
- UI_but_flag_enable(but, UI_BUT_DISABLED);
- }
- else {
- UI_but_funcN_set(
- but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_LOCAL));
- }
+ }
+ if (disabled) {
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
+ }
+ else {
+ UI_but_funcN_set(
+ but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_LOCAL));
}
}
else if (ID_IS_OVERRIDE_LIBRARY(id)) {
diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c
index beed4abd52b..3345d422bd1 100644
--- a/source/blender/editors/io/io_obj.c
+++ b/source/blender/editors/io/io_obj.c
@@ -438,7 +438,7 @@ void WM_OT_obj_import(struct wmOperatorType *ot)
0.0f,
1000.0f,
"Clamp Bounding Box",
- "Resize the objects to keep bounding box under this value. Value 0 diables clamping",
+ "Resize the objects to keep bounding box under this value. Value 0 disables clamping",
0.0f,
1000.0f);
RNA_def_enum(ot->srna,
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index e3c3f1c38a0..0bd054e1b89 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -319,7 +319,7 @@ static int select_exec(bContext *C, wmOperator *op)
ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
- return OPERATOR_FINISHED;
+ return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
}
MaskSplinePointUW *uw;
@@ -361,14 +361,14 @@ static int select_exec(bContext *C, wmOperator *op)
ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
- return OPERATOR_FINISHED;
+ return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
}
if (deselect_all) {
/* For clip editor tracks, leave deselect all to clip editor. */
if (!ED_clip_can_select(C)) {
ED_mask_deselect_all(C);
ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
- return OPERATOR_FINISHED;
+ return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
}
}
@@ -386,7 +386,9 @@ static int select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
RNA_float_set_array(op->ptr, "location", co);
- return select_exec(C, op);
+ const int retval = select_exec(C, op);
+
+ return WM_operator_flag_only_pass_through_on_press(retval, event);
}
void MASK_OT_select(wmOperatorType *ot)
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index d3fc83eedd7..7634ce6af9e 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -230,8 +230,6 @@ static int geometry_extract_apply(bContext *C,
}
}
- BKE_mesh_calc_normals(new_ob->data);
-
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, new_ob);
BKE_mesh_batch_cache_dirty_tag(new_ob->data, BKE_MESH_BATCH_DIRTY_ALL);
DEG_relations_tag_update(bmain);
@@ -551,7 +549,6 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op)
CustomData_free_layers(&new_ob_mesh->vdata, CD_PAINT_MASK, new_ob_mesh->totvert);
BKE_mesh_nomain_to_mesh(new_ob_mesh, new_ob->data, new_ob, &CD_MASK_MESH, true);
- BKE_mesh_calc_normals(new_ob->data);
BKE_mesh_copy_parameters_for_eval(new_ob->data, mesh);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, new_ob);
BKE_mesh_batch_cache_dirty_tag(new_ob->data, BKE_MESH_BATCH_DIRTY_ALL);
@@ -561,7 +558,6 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op)
}
BKE_mesh_nomain_to_mesh(new_mesh, ob->data, ob, &CD_MASK_MESH, true);
- BKE_mesh_calc_normals(ob->data);
if (ob->mode == OB_MODE_SCULPT) {
SculptSession *ss = ob->sculpt;
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 7feb04b3672..c3d5f33705c 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -937,7 +937,7 @@ bool EDBM_uv_check(BMEditMesh *em)
bool EDBM_vert_color_check(BMEditMesh *em)
{
/* some of these checks could be a touch overkill */
- return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_MLOOPCOL);
+ return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_PROP_BYTE_COLOR);
}
/** \} */
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index 6f5c9d410c7..d11f0b490c1 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -109,7 +109,7 @@ static void delete_customdata_layer(Mesh *me, CustomDataLayer *layer)
int layer_index, tot, n;
char htype = BM_FACE;
- if (ELEM(type, CD_MLOOPCOL, CD_MLOOPUV)) {
+ if (ELEM(type, CD_PROP_BYTE_COLOR, CD_MLOOPUV)) {
htype = BM_LOOP;
}
else if (ELEM(type, CD_PROP_COLOR)) {
@@ -379,25 +379,25 @@ int ED_mesh_color_add(
if (me->edit_mesh) {
em = me->edit_mesh;
- layernum = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPCOL);
+ layernum = CustomData_number_of_layers(&em->bm->ldata, CD_PROP_BYTE_COLOR);
if (layernum >= MAX_MCOL) {
BKE_reportf(reports, RPT_WARNING, "Cannot add more than %i vertex color layers", MAX_MCOL);
return -1;
}
- /* CD_MLOOPCOL */
- BM_data_layer_add_named(em->bm, &em->bm->ldata, CD_MLOOPCOL, name);
+ /* CD_PROP_BYTE_COLOR */
+ BM_data_layer_add_named(em->bm, &em->bm->ldata, CD_PROP_BYTE_COLOR, name);
/* copy data from active vertex color layer */
if (layernum && do_init) {
- const int layernum_dst = CustomData_get_active_layer(&em->bm->ldata, CD_MLOOPCOL);
- BM_data_layer_copy(em->bm, &em->bm->ldata, CD_MLOOPCOL, layernum_dst, layernum);
+ const int layernum_dst = CustomData_get_active_layer(&em->bm->ldata, CD_PROP_BYTE_COLOR);
+ BM_data_layer_copy(em->bm, &em->bm->ldata, CD_PROP_BYTE_COLOR, layernum_dst, layernum);
}
if (active_set || layernum == 0) {
- CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPCOL, layernum);
+ CustomData_set_layer_active(&em->bm->ldata, CD_PROP_BYTE_COLOR, layernum);
}
}
else {
- layernum = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
+ layernum = CustomData_number_of_layers(&me->ldata, CD_PROP_BYTE_COLOR);
if (layernum >= MAX_MCOL) {
BKE_reportf(reports, RPT_WARNING, "Cannot add more than %i vertex color layers", MAX_MCOL);
return -1;
@@ -405,14 +405,15 @@ int ED_mesh_color_add(
if (me->mloopcol && do_init) {
CustomData_add_layer_named(
- &me->ldata, CD_MLOOPCOL, CD_DUPLICATE, me->mloopcol, me->totloop, name);
+ &me->ldata, CD_PROP_BYTE_COLOR, CD_DUPLICATE, me->mloopcol, me->totloop, name);
}
else {
- CustomData_add_layer_named(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop, name);
+ CustomData_add_layer_named(
+ &me->ldata, CD_PROP_BYTE_COLOR, CD_DEFAULT, NULL, me->totloop, name);
}
if (active_set || layernum == 0) {
- CustomData_set_layer_active(&me->ldata, CD_MLOOPCOL, layernum);
+ CustomData_set_layer_active(&me->ldata, CD_PROP_BYTE_COLOR, layernum);
}
BKE_mesh_update_customdata_pointers(me, true);
@@ -427,18 +428,20 @@ int ED_mesh_color_add(
bool ED_mesh_color_ensure(struct Mesh *me, const char *name)
{
BLI_assert(me->edit_mesh == NULL);
+ CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
- if (!me->mloopcol && me->totloop) {
- CustomData_add_layer_named(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop, name);
- int layer_i = CustomData_get_layer_index(&me->ldata, CD_MLOOPCOL);
+ if (!layer) {
+ CustomData_add_layer_named(
+ &me->ldata, CD_PROP_BYTE_COLOR, CD_DEFAULT, NULL, me->totloop, name);
+ layer = me->ldata.layers + CustomData_get_layer_index(&me->ldata, CD_PROP_BYTE_COLOR);
- BKE_id_attributes_active_color_set(&me->id, me->ldata.layers + layer_i);
+ BKE_id_attributes_active_color_set(&me->id, layer);
BKE_mesh_update_customdata_pointers(me, true);
}
DEG_id_tag_update(&me->id, 0);
- return (me->mloopcol != NULL);
+ return (layer != NULL);
}
bool ED_mesh_color_remove_index(Mesh *me, const int n)
@@ -447,7 +450,7 @@ bool ED_mesh_color_remove_index(Mesh *me, const int n)
CustomDataLayer *cdl;
int index;
- index = CustomData_get_layer_index_n(ldata, CD_MLOOPCOL, n);
+ index = CustomData_get_layer_index_n(ldata, CD_PROP_BYTE_COLOR, n);
cdl = (index == -1) ? NULL : &ldata->layers[index];
if (!cdl) {
@@ -463,7 +466,7 @@ bool ED_mesh_color_remove_index(Mesh *me, const int n)
bool ED_mesh_color_remove_active(Mesh *me)
{
CustomData *ldata = GET_CD_DATA(me, ldata);
- const int n = CustomData_get_active_layer(ldata, CD_MLOOPCOL);
+ const int n = CustomData_get_active_layer(ldata, CD_PROP_BYTE_COLOR);
if (n != -1) {
return ED_mesh_color_remove_index(me, n);
}
@@ -472,7 +475,7 @@ bool ED_mesh_color_remove_active(Mesh *me)
bool ED_mesh_color_remove_named(Mesh *me, const char *name)
{
CustomData *ldata = GET_CD_DATA(me, ldata);
- const int n = CustomData_get_named_layer(ldata, CD_MLOOPCOL, name);
+ const int n = CustomData_get_named_layer(ldata, CD_PROP_BYTE_COLOR, name);
if (n != -1) {
return ED_mesh_color_remove_index(me, n);
}
@@ -715,7 +718,7 @@ static bool vertex_color_remove_poll(bContext *C)
Object *ob = ED_object_context(C);
Mesh *me = ob->data;
CustomData *ldata = GET_CD_DATA(me, ldata);
- const int active = CustomData_get_active_layer(ldata, CD_MLOOPCOL);
+ const int active = CustomData_get_active_layer(ldata, CD_PROP_BYTE_COLOR);
if (active != -1) {
return true;
}
@@ -1092,7 +1095,8 @@ void ED_mesh_update(Mesh *mesh, bContext *C, bool calc_edges, bool calc_edges_lo
/* Default state is not to have tessface's so make sure this is the case. */
BKE_mesh_tessface_clear(mesh);
- BKE_mesh_calc_normals(mesh);
+ /* Tag lazily calculated data as dirty. */
+ BKE_mesh_normals_tag_dirty(mesh);
DEG_id_tag_update(&mesh->id, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, mesh);
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index d57471b658c..9575fde68f0 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -681,8 +681,8 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
/* tessface data removed above, no need to update */
BKE_mesh_update_customdata_pointers(me, false);
- /* update normals in case objects with non-uniform scale are joined */
- BKE_mesh_calc_normals(me);
+ /* Tag normals dirty because vertex positions could be changed from the original. */
+ BKE_mesh_normals_tag_dirty(me);
/* old material array */
for (a = 1; a <= ob->totcol; a++) {
diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc
index b3c5879b4d0..508d452bfe4 100644
--- a/source/blender/editors/object/object_add.cc
+++ b/source/blender/editors/object/object_add.cc
@@ -1638,7 +1638,7 @@ struct CollectionAddInfo {
ushort local_view_bits;
/* The transform that should be applied to the collection, determined through operator properties
* if set (e.g. to place the collection under the cursor), otherwise through context (e.g. 3D
- * cursor location). */
+ * cursor location). */
float loc[3], rot[3];
};
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index d469efbd0a1..1483c24ac70 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -172,28 +172,35 @@ static bool multiresbake_check(bContext *C, wmOperator *op)
ok = false;
}
else {
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+ iuser.tile = tile->tile_number;
- if (!ibuf) {
- BKE_report(op->reports, RPT_ERROR, "Baking should happen to image with image buffer");
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
- ok = false;
- }
- else {
- if (ibuf->rect == NULL && ibuf->rect_float == NULL) {
- ok = false;
- }
+ if (!ibuf) {
+ BKE_report(
+ op->reports, RPT_ERROR, "Baking should happen to image with image buffer");
- if (ibuf->rect_float && !(ELEM(ibuf->channels, 0, 4))) {
ok = false;
}
-
- if (!ok) {
- BKE_report(op->reports, RPT_ERROR, "Baking to unsupported image type");
+ else {
+ if (ibuf->rect == NULL && ibuf->rect_float == NULL) {
+ ok = false;
+ }
+
+ if (ibuf->rect_float && !(ELEM(ibuf->channels, 0, 4))) {
+ ok = false;
+ }
+
+ if (!ok) {
+ BKE_report(op->reports, RPT_ERROR, "Baking to unsupported image type");
+ }
}
- }
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
}
}
}
@@ -274,21 +281,27 @@ static void clear_single_image(Image *image, ClearFlag flag)
const float disp_solid[4] = {0.5f, 0.5f, 0.5f, 1.0f};
if ((image->id.tag & LIB_TAG_DOIT) == 0) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
+ LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) {
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+ iuser.tile = tile->tile_number;
- if (flag == CLEAR_TANGENT_NORMAL) {
- IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid);
- }
- else if (flag == CLEAR_DISPLACEMENT) {
- IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? disp_alpha : disp_solid);
- }
- else {
- IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid);
- }
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, &iuser, NULL);
- image->id.tag |= LIB_TAG_DOIT;
+ if (flag == CLEAR_TANGENT_NORMAL) {
+ IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid);
+ }
+ else if (flag == CLEAR_DISPLACEMENT) {
+ IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? disp_alpha : disp_solid);
+ }
+ else {
+ IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid);
+ }
+
+ image->id.tag |= LIB_TAG_DOIT;
- BKE_image_release_ibuf(image, ibuf, NULL);
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
}
}
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 3060a1ecf62..a7379d7e492 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -19,6 +19,7 @@
#include "BLI_fileops.h"
#include "BLI_listbase.h"
#include "BLI_path_util.h"
+#include "BLI_string.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -165,6 +166,7 @@ static void bake_update_image(ScrArea *area, Image *image)
}
static bool write_internal_bake_pixels(Image *image,
+ const int image_tile_number,
BakePixel pixel_array[],
float *buffer,
const int width,
@@ -174,7 +176,8 @@ static bool write_internal_bake_pixels(Image *image,
const bool is_clear,
const bool is_noncolor,
Mesh const *mesh_eval,
- char const *uv_layer)
+ char const *uv_layer,
+ const float uv_offset[2])
{
ImBuf *ibuf;
void *lock;
@@ -182,7 +185,10 @@ static bool write_internal_bake_pixels(Image *image,
char *mask_buffer = NULL;
const size_t pixels_num = (size_t)width * (size_t)height;
- ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+ iuser.tile = image_tile_number;
+ ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
if (!ibuf) {
return false;
@@ -270,7 +276,7 @@ static bool write_internal_bake_pixels(Image *image,
/* margins */
if (margin > 0) {
- RE_bake_margin(ibuf, mask_buffer, margin, margin_type, mesh_eval, uv_layer);
+ RE_bake_margin(ibuf, mask_buffer, margin, margin_type, mesh_eval, uv_layer, uv_offset);
}
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
@@ -303,10 +309,8 @@ static void bake_targets_refresh(BakeTargets *targets)
if (ima) {
BKE_image_partial_update_mark_full_update(ima);
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- BKE_image_free_gputextures(ima);
- DEG_id_tag_update(&ima->id, 0);
- }
+ BKE_image_free_gputextures(ima);
+ DEG_id_tag_update(&ima->id, 0);
}
}
}
@@ -321,7 +325,8 @@ static bool write_external_bake_pixels(const char *filepath,
ImageFormatData *im_format,
const bool is_noncolor,
Mesh const *mesh_eval,
- char const *uv_layer)
+ char const *uv_layer,
+ const float uv_offset[2])
{
ImBuf *ibuf = NULL;
bool ok = false;
@@ -378,7 +383,7 @@ static bool write_external_bake_pixels(const char *filepath,
mask_buffer = MEM_callocN(sizeof(char) * pixels_num, "Bake Mask");
RE_bake_mask_fill(pixel_array, pixels_num, mask_buffer);
- RE_bake_margin(ibuf, mask_buffer, margin, margin_type, mesh_eval, uv_layer);
+ RE_bake_margin(ibuf, mask_buffer, margin, margin_type, mesh_eval, uv_layer, uv_offset);
if (mask_buffer) {
MEM_freeN(mask_buffer);
@@ -443,7 +448,7 @@ static bool bake_object_check(ViewLayer *view_layer,
if (target == R_BAKE_TARGET_VERTEX_COLORS) {
MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
const bool mcol_valid = (mcol != NULL);
- MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
+ MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_PROP_BYTE_COLOR);
if (mloopcol == NULL && !mcol_valid) {
BKE_reportf(reports,
RPT_ERROR,
@@ -467,7 +472,6 @@ static bool bake_object_check(ViewLayer *view_layer,
ED_object_get_active_image(ob, mat_nr, &image, NULL, &node, &ntree);
if (image) {
- ImBuf *ibuf;
if (node) {
if (BKE_node_is_connected_to_output(ntree, node)) {
@@ -482,21 +486,27 @@ static bool bake_object_check(ViewLayer *view_layer,
}
}
- void *lock;
- ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
+ LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) {
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+ iuser.tile = tile->tile_number;
- if (ibuf) {
- BKE_image_release_ibuf(image, ibuf, lock);
- }
- else {
- BKE_reportf(reports,
- RPT_ERROR,
- "Uninitialized image \"%s\" from object \"%s\"",
- image->id.name + 2,
- ob->id.name + 2);
+ void *lock;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
+
+ if (ibuf) {
+ BKE_image_release_ibuf(image, ibuf, lock);
+ }
+ else {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Uninitialized image \"%s\" from object \"%s\"",
+ image->id.name + 2,
+ ob->id.name + 2);
- BKE_image_release_ibuf(image, ibuf, lock);
- return false;
+ BKE_image_release_ibuf(image, ibuf, lock);
+ return false;
+ }
}
}
else {
@@ -687,36 +697,35 @@ static bool bake_targets_init_image_textures(const BakeAPIRender *bkr,
}
}
- /* Over-allocate in case there is more materials than images. */
+ /* Allocate material mapping. */
targets->materials_num = materials_num;
- targets->images = MEM_callocN(sizeof(BakeImage) * targets->materials_num, "BakeTargets.images");
- targets->material_to_image = MEM_callocN(sizeof(int) * targets->materials_num,
+ targets->material_to_image = MEM_callocN(sizeof(Image *) * targets->materials_num,
"BakeTargets.material_to_image");
/* Error handling and tag (in case multiple materials share the same image). */
BKE_main_id_tag_idcode(bkr->main, ID_IM, LIB_TAG_DOIT, false);
+ targets->images = NULL;
+
for (int i = 0; i < materials_num; i++) {
Image *image;
ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL);
- /* Some materials have no image, we just ignore those cases. */
- if (image == NULL) {
- targets->material_to_image[i] = -1;
- }
- else if (image->id.tag & LIB_TAG_DOIT) {
- for (int j = 0; j < i; j++) {
- if (targets->images[j].image == image) {
- targets->material_to_image[i] = j;
- break;
- }
+ targets->material_to_image[i] = image;
+
+ /* Some materials have no image, we just ignore those cases.
+ * Also setup each image only once. */
+ if (image && !(image->id.tag & LIB_TAG_DOIT)) {
+ LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) {
+ /* Add bake image. */
+ targets->images = MEM_recallocN(targets->images,
+ sizeof(BakeImage) * (targets->images_num + 1));
+ targets->images[targets->images_num].image = image;
+ targets->images[targets->images_num].tile_number = tile->tile_number;
+ targets->images_num++;
}
- }
- else {
- targets->material_to_image[i] = targets->images_num;
- targets->images[targets->images_num].image = image;
+
image->id.tag |= LIB_TAG_DOIT;
- targets->images_num++;
}
}
@@ -735,13 +744,19 @@ static bool bake_targets_init_internal(const BakeAPIRender *bkr,
/* Saving to image datablocks. */
for (int i = 0; i < targets->images_num; i++) {
BakeImage *bk_image = &targets->images[i];
+
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+ iuser.tile = bk_image->tile_number;
+
void *lock;
- ImBuf *ibuf = BKE_image_acquire_ibuf(bk_image->image, NULL, &lock);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(bk_image->image, &iuser, &lock);
if (ibuf) {
bk_image->width = ibuf->x;
bk_image->height = ibuf->y;
bk_image->offset = targets->pixels_num;
+ BKE_image_get_tile_uv(bk_image->image, bk_image->tile_number, bk_image->uv_offset);
targets->pixels_num += (size_t)ibuf->x * (size_t)ibuf->y;
}
@@ -768,6 +783,7 @@ static bool bake_targets_output_internal(const BakeAPIRender *bkr,
for (int i = 0; i < targets->images_num; i++) {
BakeImage *bk_image = &targets->images[i];
const bool ok = write_internal_bake_pixels(bk_image->image,
+ bk_image->tile_number,
pixel_array + bk_image->offset,
targets->result +
bk_image->offset * targets->channels_num,
@@ -778,7 +794,8 @@ static bool bake_targets_output_internal(const BakeAPIRender *bkr,
bkr->is_clear,
targets->is_noncolor,
mesh_eval,
- bkr->uv_layer);
+ bkr->uv_layer,
+ bk_image->uv_offset);
/* might be read by UI to set active image for display */
bake_update_image(bkr->area, bk_image->image);
@@ -815,7 +832,6 @@ static bool bake_targets_init_external(const BakeAPIRender *bkr,
bk_image->width = bkr->width;
bk_image->height = bkr->height;
bk_image->offset = targets->pixels_num;
- bk_image->image = NULL;
targets->pixels_num += (size_t)bkr->width * (size_t)bkr->height;
@@ -827,7 +843,7 @@ static bool bake_targets_init_external(const BakeAPIRender *bkr,
if (!bkr->is_split_materials) {
/* saving a single image */
for (int i = 0; i < targets->materials_num; i++) {
- targets->material_to_image[i] = 0;
+ targets->material_to_image[i] = targets->images[0].image;
}
}
@@ -865,25 +881,26 @@ static bool bake_targets_output_external(const BakeAPIRender *bkr,
}
if (bkr->is_split_materials) {
- if (bk_image->image) {
- BLI_path_suffix(name, FILE_MAX, bk_image->image->id.name + 2, "_");
+ if (ob_eval->mat[i]) {
+ BLI_path_suffix(name, FILE_MAX, ob_eval->mat[i]->id.name + 2, "_");
+ }
+ else if (mesh_eval->mat[i]) {
+ BLI_path_suffix(name, FILE_MAX, mesh_eval->mat[i]->id.name + 2, "_");
}
else {
- if (ob_eval->mat[i]) {
- BLI_path_suffix(name, FILE_MAX, ob_eval->mat[i]->id.name + 2, "_");
- }
- else if (mesh_eval->mat[i]) {
- BLI_path_suffix(name, FILE_MAX, mesh_eval->mat[i]->id.name + 2, "_");
- }
- else {
- /* if everything else fails, use the material index */
- char tmp[5];
- sprintf(tmp, "%d", i % 1000);
- BLI_path_suffix(name, FILE_MAX, tmp, "_");
- }
+ /* if everything else fails, use the material index */
+ char tmp[5];
+ sprintf(tmp, "%d", i % 1000);
+ BLI_path_suffix(name, FILE_MAX, tmp, "_");
}
}
+ if (bk_image->tile_number) {
+ char tmp[FILE_MAX];
+ SNPRINTF(tmp, "%d", bk_image->tile_number);
+ BLI_path_suffix(name, FILE_MAX, tmp, "_");
+ }
+
/* save it externally */
const bool ok = write_external_bake_pixels(name,
pixel_array + bk_image->offset,
@@ -896,7 +913,8 @@ static bool bake_targets_output_external(const BakeAPIRender *bkr,
&bake->im_format,
targets->is_noncolor,
mesh_eval,
- bkr->uv_layer);
+ bkr->uv_layer,
+ bk_image->uv_offset);
if (!ok) {
BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\"", name);
@@ -927,7 +945,7 @@ static bool bake_targets_init_vertex_colors(BakeTargets *targets, Object *ob, Re
Mesh *me = ob->data;
MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
const bool mcol_valid = (mcol != NULL);
- MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
+ MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_PROP_BYTE_COLOR);
if (mloopcol == NULL && !mcol_valid) {
BKE_report(reports, RPT_ERROR, "No vertex colors layer found to bake to");
return false;
@@ -1081,7 +1099,7 @@ static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob)
Mesh *me = ob->data;
MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
const bool mcol_valid = (mcol != NULL);
- MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
+ MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_PROP_BYTE_COLOR);
const int channels_num = targets->channels_num;
const float *result = targets->result;
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index 23d2327fe72..dfe858e5bd9 100644
--- a/source/blender/editors/object/object_data_transfer.c
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -89,7 +89,7 @@ static void dt_add_vcol_layers(CustomData *cdata,
EnumPropertyItem **r_item,
int *r_totitem)
{
- int types[2] = {CD_PROP_COLOR, CD_MLOOPCOL};
+ int types[2] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR};
for (int i = 0; i < 2; i++) {
CustomDataType type = types[i];
@@ -196,14 +196,14 @@ static const EnumPropertyItem *dt_layers_select_src_itemf(bContext *C,
cddata_masks.vmask |= CD_MASK_PROP_COLOR;
}
if (data_type & (DT_TYPE_MLOOPCOL_VERT)) {
- cddata_masks.vmask |= CD_MASK_MLOOPCOL;
+ cddata_masks.vmask |= CD_MASK_PROP_BYTE_COLOR;
}
if (data_type & (DT_TYPE_MPROPCOL_LOOP)) {
cddata_masks.lmask |= CD_MASK_PROP_COLOR;
}
if (data_type & (DT_TYPE_MLOOPCOL_LOOP)) {
- cddata_masks.lmask |= CD_MASK_MLOOPCOL;
+ cddata_masks.lmask |= CD_MASK_PROP_BYTE_COLOR;
}
Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_src_eval, &cddata_masks);
diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc
index f7543c97903..8b2dbd4a865 100644
--- a/source/blender/editors/object/object_modifier.cc
+++ b/source/blender/editors/object/object_modifier.cc
@@ -855,7 +855,7 @@ bool ED_object_modifier_apply(Main *bmain,
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
ModifierData *md_eval = (ob_eval) ? BKE_modifiers_findby_name(ob_eval, md->name) : md;
- /* allow apply of a not-realtime modifier, by first re-enabling realtime. */
+ /* Allow apply of a non-real-time modifier, by first re-enabling real-time. */
int prev_mode = md_eval->mode;
md_eval->mode |= eModifierMode_Realtime;
diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc
index 966df0668ca..ba2efa6e517 100644
--- a/source/blender/editors/object/object_remesh.cc
+++ b/source/blender/editors/object/object_remesh.cc
@@ -40,6 +40,7 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_shrinkwrap.h"
+#include "BKE_unit.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -282,7 +283,7 @@ static void voxel_size_parallel_lines_draw(uint pos3d,
immEnd();
}
-static void voxel_size_edit_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
+static void voxel_size_edit_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
{
VoxelSizeEditCustomData *cd = static_cast<VoxelSizeEditCustomData *>(arg);
@@ -338,8 +339,15 @@ static void voxel_size_edit_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar),
short fstyle_points = fstyle->points;
char str[VOXEL_SIZE_EDIT_MAX_STR_LEN];
short strdrawlen = 0;
-
- BLI_snprintf(str, VOXEL_SIZE_EDIT_MAX_STR_LEN, "%.4f", cd->voxel_size);
+ Scene *scene = CTX_data_scene(C);
+ UnitSettings *unit = &scene->unit;
+ BKE_unit_value_as_string(str,
+ VOXEL_SIZE_EDIT_MAX_STR_LEN,
+ (double)(cd->voxel_size * unit->scale_length),
+ 4,
+ B_UNIT_LENGTH,
+ unit,
+ true);
strdrawlen = BLI_strlen_utf8(str);
immUnbindProgram();
@@ -885,9 +893,6 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update
BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
if (qj->smooth_normals) {
- if (qj->use_mesh_symmetry) {
- BKE_mesh_calc_normals(static_cast<Mesh *>(ob->data));
- }
BKE_mesh_smooth_flag_set(static_cast<Mesh *>(ob->data), true);
}
diff --git a/source/blender/editors/object/object_transform.cc b/source/blender/editors/object/object_transform.cc
index 976fe683f95..da3df159c33 100644
--- a/source/blender/editors/object/object_transform.cc
+++ b/source/blender/editors/object/object_transform.cc
@@ -884,9 +884,6 @@ static int apply_objects_internal(bContext *C,
/* adjust data */
BKE_mesh_transform(me, mat, true);
-
- /* If normal layers exist, they are now dirty. */
- BKE_mesh_normals_tag_dirty(me);
}
else if (ob->type == OB_ARMATURE) {
bArmature *arm = static_cast<bArmature *>(ob->data);
@@ -1173,6 +1170,12 @@ void OBJECT_OT_transform_apply(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Apply Parent Inverse Operator
+ * \{ */
+
static int object_parent_inverse_apply_exec(bContext *C, wmOperator *UNUSED(op))
{
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
@@ -1194,7 +1197,7 @@ void OBJECT_OT_parent_inverse_apply(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Apply Parent Inverse";
- ot->description = "Apply the object's parent inverse to the its data";
+ ot->description = "Apply the object's parent inverse to its data";
ot->idname = "OBJECT_OT_parent_inverse_apply";
/* api callbacks */
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index abdae5c44f9..08eed52f440 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -48,7 +48,7 @@ set(SRC
paint_ops.c
paint_stroke.c
paint_utils.c
- paint_vertex.c
+ paint_vertex.cc
paint_vertex_color_ops.c
paint_vertex_color_utils.c
paint_vertex_proj.c
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
index 5f262384945..0d399419ad8 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
@@ -96,6 +96,7 @@ struct AddOperationExecutor {
CurvesSculpt *curves_sculpt_ = nullptr;
Brush *brush_ = nullptr;
+ BrushCurvesSculptSettings *brush_settings_ = nullptr;
float brush_radius_re_;
float2 brush_pos_re_;
@@ -162,17 +163,18 @@ struct AddOperationExecutor {
curves_sculpt_ = scene_->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush(&curves_sculpt_->paint);
+ brush_settings_ = brush_->curves_sculpt_settings;
brush_radius_re_ = BKE_brush_size_get(scene_, brush_);
brush_pos_re_ = stroke_extension.mouse_position;
use_front_face_ = brush_->flag & BRUSH_FRONTFACE;
const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
brush_->falloff_shape);
- add_amount_ = std::max(0, brush_->curves_sculpt_settings->add_amount);
- interpolate_length_ = curves_sculpt_->flag & CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH;
- interpolate_shape_ = curves_sculpt_->flag & CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE;
+ add_amount_ = std::max(0, brush_settings_->add_amount);
+ interpolate_length_ = brush_settings_->flag & BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH;
+ interpolate_shape_ = brush_settings_->flag & BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE;
use_interpolation_ = interpolate_length_ || interpolate_shape_;
- new_curve_length_ = curves_sculpt_->curve_length;
+ new_curve_length_ = brush_settings_->curve_length;
tot_old_curves_ = curves_->curves_num();
tot_old_points_ = curves_->points_num();
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
index 6a47f90d4ac..232d632aa3f 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
@@ -136,6 +136,9 @@ struct CombOperationExecutor {
curves_id_ = static_cast<Curves *>(object_->data);
curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
+ if (curves_->curves_num() == 0) {
+ return;
+ }
brush_pos_prev_re_ = self_->brush_pos_last_re_;
brush_pos_re_ = stroke_extension.mouse_position;
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
index 7cc5e524c30..6228a643a76 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
@@ -311,6 +311,9 @@ struct CurvesEffectOperationExecutor {
curves_id_ = static_cast<Curves *>(object_->data);
curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
+ if (curves_->curves_num() == 0) {
+ return;
+ }
CurvesSculpt &curves_sculpt = *scene_->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush(&curves_sculpt.paint);
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
index b367c5bb6ec..6d930d35f04 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
@@ -116,6 +116,9 @@ struct SnakeHookOperatorExecutor {
curves_id_ = static_cast<Curves *>(object_->data);
curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
+ if (curves_->curves_num() == 0) {
+ return;
+ }
brush_pos_prev_re_ = self.last_mouse_position_re_;
brush_pos_re_ = stroke_extension.mouse_position;
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index f784ebe4b4f..187f793eefe 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -133,7 +133,7 @@ void PAINT_OT_weight_gradient(struct wmOperatorType *ot);
void PAINT_OT_vertex_paint_toggle(struct wmOperatorType *ot);
void PAINT_OT_vertex_paint(struct wmOperatorType *ot);
-unsigned int vpaint_get_current_col(struct Scene *scene, struct VPaint *vp, bool secondary);
+unsigned int vpaint_get_current_color(struct Scene *scene, struct VPaint *vp, bool secondary);
/* paint_vertex_color_utils.c */
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 5929aa75b45..3ca686e9351 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -950,7 +950,6 @@ static void sculpt_gesture_trim_normals_update(SculptGestureContext *sgcontext)
{
SculptGestureTrimOperation *trim_operation = (SculptGestureTrimOperation *)sgcontext->operation;
Mesh *trim_mesh = trim_operation->mesh;
- BKE_mesh_calc_normals(trim_mesh);
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(trim_mesh);
BMesh *bm;
@@ -1288,7 +1287,6 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
}),
sculpt_mesh);
BM_mesh_free(bm);
- BKE_mesh_normals_tag_dirty(result);
BKE_mesh_nomain_to_mesh(
result, sgcontext->vc.obact->data, sgcontext->vc.obact, &CD_MASK_MESH, true);
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.cc
index 33b92c22d3f..8b62dd33961 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.cc
@@ -13,11 +13,14 @@
#include "MEM_guardedalloc.h"
#include "BLI_array_utils.h"
+#include "BLI_color.hh"
+#include "BLI_color_mix.hh"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_string.h"
#include "BLI_task.h"
+#include "BLI_task.hh"
#include "DNA_brush_types.h"
#include "DNA_mesh_types.h"
@@ -26,6 +29,7 @@
#include "DNA_scene_types.h"
#include "RNA_access.h"
+#include "RNA_prototypes.h"
#include "BKE_attribute.h"
#include "BKE_brush.h"
@@ -66,14 +70,53 @@
#include "paint_intern.h" /* own include */
#include "sculpt_intern.h"
+using blender::IndexRange;
+using namespace blender;
+using namespace blender::color;
+
/* -------------------------------------------------------------------- */
/** \name Internal Utilities
* \{ */
+static uint color2uint(ColorPaint4b c)
+{
+ return *(reinterpret_cast<uint *>(&c));
+}
+
+static bool isZero(ColorPaint4f c)
+{
+ return c.r == 0.0f && c.g == 0.0f && c.b == 0.0f && c.a == 0.0f;
+}
+
+static bool isZero(ColorPaint4b c)
+{
+ return c.r == 0 && c.g == 0 && c.b == 0 && c.a == 0;
+}
+
+template<typename Color = ColorPaint4f> static ColorPaint4f toFloat(const Color &c)
+{
+ if constexpr (std::is_same_v<Color, ColorPaint4b>) {
+ return c.decode();
+ }
+ else {
+ return c;
+ }
+}
+
+template<typename Color = ColorPaint4f> static Color fromFloat(const ColorPaint4f &c)
+{
+ if constexpr (std::is_same_v<Color, ColorPaint4b>) {
+ return c.encode();
+ }
+ else {
+ return c;
+ }
+}
+
/* Use for 'blur' brush, align with PBVH nodes, created and freed on each update. */
-struct VPaintAverageAccum {
- uint len;
- uint value[3];
+template<typename BlendType> struct VPaintAverageAccum {
+ BlendType len;
+ BlendType value[3];
};
struct WPaintAverageAccum {
@@ -93,7 +136,27 @@ struct NormalAnglePrecalc {
float angle_range;
};
-static void view_angle_limits_init(struct NormalAnglePrecalc *a, float angle, bool do_mask_normal)
+/* Returns number of elements. */
+static int get_vcol_elements(Mesh *me, size_t *r_elem_size)
+{
+ CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
+ AttributeDomain domain = BKE_id_attribute_domain(&me->id, layer);
+
+ if (r_elem_size) {
+ *r_elem_size = layer->type == CD_PROP_COLOR ? sizeof(float) * 4ULL : 4ULL;
+ }
+
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ return me->totvert;
+ case ATTR_DOMAIN_CORNER:
+ return me->totloop;
+ default:
+ return 0;
+ }
+}
+
+static void view_angle_limits_init(NormalAnglePrecalc *a, float angle, bool do_mask_normal)
{
angle = RAD2DEGF(angle);
a->do_mask_normal = do_mask_normal;
@@ -117,7 +180,7 @@ static void view_angle_limits_init(struct NormalAnglePrecalc *a, float angle, bo
a->angle_inner__cos = cosf(a->angle_inner);
}
-static float view_angle_limits_apply_falloff(const struct NormalAnglePrecalc *a,
+static float view_angle_limits_apply_falloff(const NormalAnglePrecalc *a,
float angle_cos,
float *mask_p)
{
@@ -169,10 +232,10 @@ static bool vertex_paint_use_fast_update_check(Object *ob)
{
const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob);
- if (me_eval != NULL) {
+ if (me_eval != nullptr) {
Mesh *me = BKE_mesh_from_object(ob);
if (me && me->mloopcol) {
- return (me->mloopcol == CustomData_get_layer(&me_eval->ldata, CD_MLOOPCOL));
+ return (me->mloopcol == CustomData_get_layer(&me_eval->ldata, CD_PROP_BYTE_COLOR));
}
}
@@ -196,9 +259,8 @@ bool vertex_paint_mode_poll(bContext *C)
}
CustomDataLayer *layer = BKE_id_attributes_active_color_get((ID *)ob->data);
- AttributeDomain domain = BKE_id_attribute_domain((ID *)ob->data, layer);
- return layer && layer->type == CD_MLOOPCOL && domain == ATTR_DOMAIN_CORNER;
+ return layer != nullptr;
}
static bool vertex_paint_poll_ex(bContext *C, bool check_tool)
@@ -239,8 +301,8 @@ static bool weight_paint_poll_ex(bContext *C, bool check_tool)
Object *ob = CTX_data_active_object(C);
ScrArea *area;
- if ((ob != NULL) && (ob->mode & OB_MODE_WEIGHT_PAINT) &&
- (BKE_paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != NULL) &&
+ if ((ob != nullptr) && (ob->mode & OB_MODE_WEIGHT_PAINT) &&
+ (BKE_paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != nullptr) &&
(area = CTX_wm_area(C)) && (area->spacetype == SPACE_VIEW3D)) {
ARegion *region = CTX_wm_region(C);
if (ELEM(region->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_HUD)) {
@@ -262,41 +324,54 @@ bool weight_paint_poll_ignore_tool(bContext *C)
return weight_paint_poll_ex(C, false);
}
-uint vpaint_get_current_col(Scene *scene, VPaint *vp, bool secondary)
+template<typename Color, typename Traits, AttributeDomain domain>
+static Color vpaint_get_current_col(Scene *scene, VPaint *vp, bool secondary)
{
Brush *brush = BKE_paint_brush(&vp->paint);
- uchar col[4];
- rgb_float_to_uchar(col,
- secondary ? BKE_brush_secondary_color_get(scene, brush) :
- BKE_brush_color_get(scene, brush));
- col[3] = 255; /* alpha isn't used, could even be removed to speedup paint a little */
- return *(uint *)col;
+ float color[4];
+ const float *brush_color = secondary ? BKE_brush_secondary_color_get(scene, brush) :
+ BKE_brush_color_get(scene, brush);
+ copy_v3_v3(color, brush_color);
+ color[3] = 1.0f; /* alpha isn't used, could even be removed to speedup paint a little */
+
+ return fromFloat<Color>(ColorPaint4f(color));
+}
+
+uint vpaint_get_current_color(Scene *scene, VPaint *vp, bool secondary)
+{
+ ColorPaint4b col = vpaint_get_current_col<ColorPaint4b, ByteTraits, ATTR_DOMAIN_CORNER>(
+ scene, vp, secondary);
+
+ return color2uint(col);
}
/* wpaint has 'wpaint_blend' */
-static uint vpaint_blend(const VPaint *vp,
- uint color_curr,
- uint color_orig,
- uint color_paint,
- const int alpha_i,
- /* pre scaled from [0-1] --> [0-255] */
- const int brush_alpha_value_i)
+template<typename Color, typename Traits>
+static Color vpaint_blend(const VPaint *vp,
+ Color color_curr,
+ Color color_orig,
+ Color color_paint,
+ const typename Traits::ValueType alpha,
+ const typename Traits::BlendType brush_alpha_value)
{
+ using Value = typename Traits::ValueType;
+
const Brush *brush = vp->paint.brush;
- const IMB_BlendMode blend = brush->blend;
+ const IMB_BlendMode blend = (IMB_BlendMode)brush->blend;
- uint color_blend = ED_vpaint_blend_tool(blend, color_curr, color_paint, alpha_i);
+ Color color_blend = BLI_mix_colors<Color, Traits>(blend, color_curr, color_paint, alpha);
/* If no accumulate, clip color adding with `color_orig` & `color_test`. */
if (!brush_use_accumulate(vp)) {
- uint color_test, a;
- char *cp, *ct, *co;
+ uint a;
+ Color color_test;
+ Value *cp, *ct, *co;
- color_test = ED_vpaint_blend_tool(blend, color_orig, color_paint, brush_alpha_value_i);
+ color_test = BLI_mix_colors<Color, Traits>(blend, color_orig, color_paint, brush_alpha_value);
- cp = (char *)&color_blend;
- ct = (char *)&color_test;
- co = (char *)&color_orig;
+ cp = (Value *)&color_blend;
+ ct = (Value *)&color_test;
+ co = (Value *)&color_orig;
for (a = 0; a < 4; a++) {
if (ct[a] < co[a]) {
@@ -320,36 +395,15 @@ static uint vpaint_blend(const VPaint *vp,
if ((brush->flag & BRUSH_LOCK_ALPHA) &&
!ELEM(blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA)) {
- char *cp, *cc;
- cp = (char *)&color_blend;
- cc = (char *)&color_curr;
+ Value *cp, *cc;
+ cp = (Value *)&color_blend;
+ cc = (Value *)&color_curr;
cp[3] = cc[3];
}
return color_blend;
}
-static void tex_color_alpha(VPaint *vp, const ViewContext *vc, const float co[3], float r_rgba[4])
-{
- const Brush *brush = BKE_paint_brush(&vp->paint);
- BLI_assert(brush->mtex.tex != NULL);
- if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
- BKE_brush_sample_tex_3d(vc->scene, brush, co, r_rgba, 0, NULL);
- }
- else {
- float co_ss[2]; /* screenspace */
- if (ED_view3d_project_float_object(
- vc->region, co, co_ss, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) ==
- V3D_PROJ_RET_OK) {
- const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */
- BKE_brush_sample_tex_3d(vc->scene, brush, co_ss_3d, r_rgba, 0, NULL);
- }
- else {
- zero_v4(r_rgba);
- }
- }
-}
-
/* vpaint has 'vpaint_blend' */
static float wpaint_blend(const VPaint *wp,
float weight,
@@ -359,7 +413,7 @@ static float wpaint_blend(const VPaint *wp,
const short do_flip)
{
const Brush *brush = wp->paint.brush;
- IMB_BlendMode blend = brush->blend;
+ IMB_BlendMode blend = (IMB_BlendMode)brush->blend;
if (do_flip) {
switch (blend) {
@@ -390,6 +444,32 @@ static float wpaint_blend(const VPaint *wp,
return weight;
}
+static void paint_and_tex_color_alpha_intern(VPaint *vp,
+ const ViewContext *vc,
+ const float co[3],
+ float r_rgba[4])
+{
+ const Brush *brush = BKE_paint_brush(&vp->paint);
+ BLI_assert(brush->mtex.tex != nullptr);
+ if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
+ BKE_brush_sample_tex_3d(vc->scene, brush, co, r_rgba, 0, nullptr);
+ }
+ else {
+ float co_ss[2]; /* screenspace */
+ if (ED_view3d_project_float_object(
+ vc->region,
+ co,
+ co_ss,
+ (eV3DProjTest)(V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR)) == V3D_PROJ_RET_OK) {
+ const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */
+ BKE_brush_sample_tex_3d(vc->scene, brush, co_ss_3d, r_rgba, 0, nullptr);
+ }
+ else {
+ zero_v4(r_rgba);
+ }
+ }
+}
+
static float wpaint_clamp_monotonic(float oldval, float curval, float newval)
{
if (newval < oldval) {
@@ -488,7 +568,7 @@ static bool do_weight_paint_normalize_all_locked(MDeformVert *dvert,
uint i, tot = 0;
MDeformWeight *dw;
- if (lock_flags == NULL) {
+ if (lock_flags == nullptr) {
do_weight_paint_normalize_all(dvert, defbase_tot, vgroup_validmap);
return true;
}
@@ -703,7 +783,7 @@ struct WeightPaintGroupData {
* this _could_ be made a part of the operators 'WPaintData' struct, or at
* least a member, but for now keep its own struct, initialized on every
* paint stroke update - campbell */
-typedef struct WeightPaintInfo {
+struct WeightPaintInfo {
int defbase_tot;
@@ -711,7 +791,7 @@ typedef struct WeightPaintInfo {
int defbase_tot_sel;
int defbase_tot_unsel;
- struct WeightPaintGroupData active, mirror;
+ WeightPaintGroupData active, mirror;
/* boolean array for locked bones,
* length of defbase_tot */
@@ -734,7 +814,7 @@ typedef struct WeightPaintInfo {
bool is_normalized;
float brush_alpha_value; /* result of BKE_brush_alpha_get() */
-} WeightPaintInfo;
+};
static void do_weight_paint_vertex_single(
/* vars which remain the same for every vert */
@@ -746,7 +826,7 @@ static void do_weight_paint_vertex_single(
float alpha,
float paintweight)
{
- Mesh *me = ob->data;
+ Mesh *me = (Mesh *)ob->data;
MDeformVert *dv = &me->dvert[index];
bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
@@ -763,7 +843,7 @@ static void do_weight_paint_vertex_single(
/* Check if we should mirror vertex groups (X-axis). */
if (ME_USING_MIRROR_X_VERTEX_GROUPS(me)) {
- index_mirr = mesh_get_x_mirror_vert(ob, NULL, index, topology);
+ index_mirr = mesh_get_x_mirror_vert(ob, nullptr, index, topology);
vgroup_mirr = wpi->mirror.index;
/* another possible error - mirror group _and_ active group are the same (which is fine),
@@ -801,7 +881,7 @@ static void do_weight_paint_vertex_single(
dw = BKE_defvert_ensure_index(dv, wpi->active.index);
}
- if (dw == NULL) {
+ if (dw == nullptr) {
return;
}
@@ -811,9 +891,9 @@ static void do_weight_paint_vertex_single(
if (wp->flag & VP_FLAG_VGROUP_RESTRICT) {
dw_mirr = BKE_defvert_find_index(dv_mirr, vgroup_mirr);
- if (dw_mirr == NULL) {
+ if (dw_mirr == nullptr) {
index_mirr = vgroup_mirr = -1;
- dv_mirr = NULL;
+ dv_mirr = nullptr;
}
}
else {
@@ -834,8 +914,8 @@ static void do_weight_paint_vertex_single(
}
}
else {
- dv_mirr = NULL;
- dw_mirr = NULL;
+ dv_mirr = nullptr;
+ dw_mirr = nullptr;
}
weight_cur = dw->weight;
@@ -959,13 +1039,13 @@ static void do_weight_paint_vertex_multi(
float alpha,
float paintweight)
{
- Mesh *me = ob->data;
+ Mesh *me = (Mesh *)ob->data;
MDeformVert *dv = &me->dvert[index];
bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
/* mirror vars */
int index_mirr = -1;
- MDeformVert *dv_mirr = NULL;
+ MDeformVert *dv_mirr = nullptr;
/* weights */
float curw, curw_real, oldw, neww, change, curw_mirr, change_mirr;
@@ -973,7 +1053,7 @@ static void do_weight_paint_vertex_multi(
/* Check if we should mirror vertex groups (X-axis). */
if (ME_USING_MIRROR_X_VERTEX_GROUPS(me)) {
- index_mirr = mesh_get_x_mirror_vert(ob, NULL, index, topology);
+ index_mirr = mesh_get_x_mirror_vert(ob, nullptr, index, topology);
if (!ELEM(index_mirr, -1, index)) {
dv_mirr = &me->dvert[index_mirr];
@@ -1033,13 +1113,13 @@ static void do_weight_paint_vertex_multi(
/* verify for all groups that 0 < result <= 1 */
multipaint_clamp_change(dv, wpi->defbase_tot, wpi->defbase_sel, &change);
- if (dv_mirr != NULL) {
+ if (dv_mirr != nullptr) {
curw_mirr = BKE_defvert_multipaint_collective_weight(
dv_mirr, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->is_normalized);
if (curw_mirr == 0.0f) {
/* can't mirror into a zero weight vertex */
- dv_mirr = NULL;
+ dv_mirr = nullptr;
}
else {
/* mirror is changed to achieve the same collective weight value */
@@ -1062,7 +1142,7 @@ static void do_weight_paint_vertex_multi(
/* apply validated change to vertex and mirror */
multipaint_apply_change(dv, wpi->defbase_tot, change, wpi->defbase_sel);
- if (dv_mirr != NULL) {
+ if (dv_mirr != nullptr) {
multipaint_apply_change(dv_mirr, wpi->defbase_tot, change_mirr, wpi->defbase_sel);
}
@@ -1071,7 +1151,7 @@ static void do_weight_paint_vertex_multi(
do_weight_paint_normalize_all_locked_try_active(
dv, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->active.lock);
- if (dv_mirr != NULL) {
+ if (dv_mirr != nullptr) {
do_weight_paint_normalize_all_locked_try_active(
dv_mirr, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->active.lock);
}
@@ -1105,21 +1185,46 @@ static void vertex_paint_init_session(Depsgraph *depsgraph,
/* Create persistent sculpt mode data */
BKE_sculpt_toolsettings_data_ensure(scene);
- BLI_assert(ob->sculpt == NULL);
- ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
+ BLI_assert(ob->sculpt == nullptr);
+ ob->sculpt = (SculptSession *)MEM_callocN(sizeof(SculptSession), "sculpt session");
ob->sculpt->mode_type = object_mode;
- BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
}
-static void vertex_paint_init_stroke(Depsgraph *depsgraph, Object *ob)
+static void vertex_paint_init_stroke(Scene *scene, Depsgraph *depsgraph, Object *ob)
{
- BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
+ ToolSettings *ts = scene->toolsettings;
+ SculptSession *ss = ob->sculpt;
+
+ /* Ensure ss->cache is allocated. It will mostly be initialized in
+ * vwpaint_update_cache_invariants and vwpaint_update_cache_variants.
+ */
+ if (!ss->cache) {
+ ss->cache = (StrokeCache *)MEM_callocN(sizeof(StrokeCache), "stroke cache");
+ }
+
+ /* Allocate scratch array for previous colors if needed. */
+ if (!brush_use_accumulate(ts->vpaint)) {
+ if (!ob->sculpt->cache->prev_colors_vpaint) {
+ Mesh *me = BKE_object_get_original_mesh(ob);
+ size_t elem_size;
+ int elem_num;
+
+ elem_num = get_vcol_elements(me, &elem_size);
+
+ ob->sculpt->cache->prev_colors_vpaint = (uint *)MEM_callocN(elem_num * elem_size, __func__);
+ }
+ }
+ else {
+ MEM_SAFE_FREE(ob->sculpt->cache->prev_colors_vpaint);
+ }
}
static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob)
{
/* Create maps */
- struct SculptVertexPaintGeomMap *gmap = NULL;
+ SculptVertexPaintGeomMap *gmap = nullptr;
if (ob->mode == OB_MODE_VERTEX_PAINT) {
gmap = &ob->sculpt->mode.vpaint.gmap;
BLI_assert(ob->sculpt->mode_type == OB_MODE_VERTEX_PAINT);
@@ -1129,18 +1234,18 @@ static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob)
BLI_assert(ob->sculpt->mode_type == OB_MODE_WEIGHT_PAINT);
}
else {
- ob->sculpt->mode_type = 0;
+ ob->sculpt->mode_type = (eObjectMode)0;
BLI_assert(0);
return;
}
- Mesh *me = ob->data;
+ Mesh *me = (Mesh *)ob->data;
- if (gmap->vert_to_loop == NULL) {
- gmap->vert_map_mem = NULL;
- gmap->vert_to_loop = NULL;
- gmap->poly_map_mem = NULL;
- gmap->vert_to_poly = NULL;
+ if (gmap->vert_to_loop == nullptr) {
+ gmap->vert_map_mem = nullptr;
+ gmap->vert_to_loop = nullptr;
+ gmap->poly_map_mem = nullptr;
+ gmap->vert_to_poly = nullptr;
BKE_mesh_vert_loop_map_create(&gmap->vert_to_loop,
&gmap->vert_map_mem,
me->mpoly,
@@ -1158,24 +1263,15 @@ static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob)
}
/* Create average brush arrays */
- if (ob->mode == OB_MODE_VERTEX_PAINT) {
- if (!brush_use_accumulate(ts->vpaint)) {
- if (ob->sculpt->mode.vpaint.previous_color == NULL) {
- ob->sculpt->mode.vpaint.previous_color = MEM_callocN(me->totloop * sizeof(uint), __func__);
- }
- }
- else {
- MEM_SAFE_FREE(ob->sculpt->mode.vpaint.previous_color);
- }
- }
- else if (ob->mode == OB_MODE_WEIGHT_PAINT) {
+ if (ob->mode == OB_MODE_WEIGHT_PAINT) {
if (!brush_use_accumulate(ts->wpaint)) {
- if (ob->sculpt->mode.wpaint.alpha_weight == NULL) {
- ob->sculpt->mode.wpaint.alpha_weight = MEM_callocN(me->totvert * sizeof(float), __func__);
+ if (ob->sculpt->mode.wpaint.alpha_weight == nullptr) {
+ ob->sculpt->mode.wpaint.alpha_weight = (float *)MEM_callocN(me->totvert * sizeof(float),
+ __func__);
}
- if (ob->sculpt->mode.wpaint.dvert_prev == NULL) {
- ob->sculpt->mode.wpaint.dvert_prev = MEM_callocN(me->totvert * sizeof(MDeformVert),
- __func__);
+ if (ob->sculpt->mode.wpaint.dvert_prev == nullptr) {
+ ob->sculpt->mode.wpaint.dvert_prev = (MDeformVert *)MEM_callocN(
+ me->totvert * sizeof(MDeformVert), __func__);
MDeformVert *dv = ob->sculpt->mode.wpaint.dvert_prev;
for (int i = 0; i < me->totvert; i++, dv++) {
/* Use to show this isn't initialized, never apply to the mesh data. */
@@ -1185,10 +1281,10 @@ static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob)
}
else {
MEM_SAFE_FREE(ob->sculpt->mode.wpaint.alpha_weight);
- if (ob->sculpt->mode.wpaint.dvert_prev != NULL) {
+ if (ob->sculpt->mode.wpaint.dvert_prev != nullptr) {
BKE_defvert_array_free_elems(ob->sculpt->mode.wpaint.dvert_prev, me->totvert);
MEM_freeN(ob->sculpt->mode.wpaint.dvert_prev);
- ob->sculpt->mode.wpaint.dvert_prev = NULL;
+ ob->sculpt->mode.wpaint.dvert_prev = nullptr;
}
}
}
@@ -1213,7 +1309,7 @@ static void ed_vwpaintmode_enter_generic(
if (mode_flag == OB_MODE_VERTEX_PAINT) {
const ePaintMode paint_mode = PAINT_MODE_VERTEX;
- ED_mesh_color_ensure(me, NULL);
+ ED_mesh_color_ensure(me, nullptr);
BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->vpaint);
Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
@@ -1240,7 +1336,7 @@ static void ed_vwpaintmode_enter_generic(
if (ob->sculpt) {
if (ob->sculpt->cache) {
SCULPT_cache_free(ob->sculpt->cache);
- ob->sculpt->cache = NULL;
+ ob->sculpt->cache = nullptr;
}
BKE_sculptsession_free(ob);
}
@@ -1255,7 +1351,7 @@ void ED_object_vpaintmode_enter_ex(Main *bmain, Depsgraph *depsgraph, Scene *sce
{
ed_vwpaintmode_enter_generic(bmain, depsgraph, scene, ob, OB_MODE_VERTEX_PAINT);
}
-void ED_object_vpaintmode_enter(struct bContext *C, Depsgraph *depsgraph)
+void ED_object_vpaintmode_enter(bContext *C, Depsgraph *depsgraph)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -1267,7 +1363,7 @@ void ED_object_wpaintmode_enter_ex(Main *bmain, Depsgraph *depsgraph, Scene *sce
{
ed_vwpaintmode_enter_generic(bmain, depsgraph, scene, ob, OB_MODE_WEIGHT_PAINT);
}
-void ED_object_wpaintmode_enter(struct bContext *C, Depsgraph *depsgraph)
+void ED_object_wpaintmode_enter(bContext *C, Depsgraph *depsgraph)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -1309,7 +1405,7 @@ static void ed_vwpaintmode_exit_generic(Object *ob, const eObjectMode mode_flag)
/* If the cache is not released by a cancel or a done, free it now. */
if (ob->sculpt && ob->sculpt->cache) {
SCULPT_cache_free(ob->sculpt->cache);
- ob->sculpt->cache = NULL;
+ ob->sculpt->cache = nullptr;
}
BKE_sculptsession_free(ob);
@@ -1332,7 +1428,7 @@ void ED_object_vpaintmode_exit_ex(Object *ob)
{
ed_vwpaintmode_exit_generic(ob, OB_MODE_VERTEX_PAINT);
}
-void ED_object_vpaintmode_exit(struct bContext *C)
+void ED_object_vpaintmode_exit(bContext *C)
{
Object *ob = CTX_data_active_object(C);
ED_object_vpaintmode_exit_ex(ob);
@@ -1342,7 +1438,7 @@ void ED_object_wpaintmode_exit_ex(Object *ob)
{
ed_vwpaintmode_exit_generic(ob, OB_MODE_WEIGHT_PAINT);
}
-void ED_object_wpaintmode_exit(struct bContext *C)
+void ED_object_wpaintmode_exit(bContext *C)
{
Object *ob = CTX_data_active_object(C);
ED_object_wpaintmode_exit_ex(ob);
@@ -1368,7 +1464,7 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
ToolSettings *ts = scene->toolsettings;
if (!is_mode_set) {
- if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
+ if (!ED_object_mode_compat_set(C, ob, (eObjectMode)mode_flag, op->reports)) {
return OPERATOR_CANCELLED;
}
}
@@ -1409,10 +1505,10 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
static bool paint_mode_toggle_poll_test(bContext *C)
{
Object *ob = CTX_data_active_object(C);
- if (ob == NULL || ob->type != OB_MESH) {
+ if (ob == nullptr || ob->type != OB_MESH) {
return false;
}
- if (!ob->data || ID_IS_LINKED(ob->data) || ID_IS_OVERRIDE_LIBRARY(ob->data)) {
+ if (!ob->data || ID_IS_LINKED(ob->data)) {
return false;
}
return true;
@@ -1442,9 +1538,9 @@ void PAINT_OT_weight_paint_toggle(wmOperatorType *ot)
struct WPaintData {
ViewContext vc;
- struct NormalAnglePrecalc normal_angle_precalc;
+ NormalAnglePrecalc normal_angle_precalc;
- struct WeightPaintGroupData active, mirror;
+ WeightPaintGroupData active, mirror;
/* variables for auto normalize */
const bool *vgroup_validmap; /* stores if vgroups tie to deforming bones or not */
@@ -1507,7 +1603,7 @@ static void vwpaint_update_cache_invariants(
StrokeCache *cache;
Scene *scene = CTX_data_scene(C);
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
- ViewContext *vc = paint_stroke_view_context(op->customdata);
+ ViewContext *vc = paint_stroke_view_context((PaintStroke *)op->customdata);
Object *ob = CTX_data_active_object(C);
float mat[3][3];
float view_dir[3] = {0.0f, 0.0f, 1.0f};
@@ -1515,7 +1611,7 @@ static void vwpaint_update_cache_invariants(
/* VW paint needs to allocate stroke cache before update is called. */
if (!ss->cache) {
- cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
+ cache = (StrokeCache *)MEM_callocN(sizeof(StrokeCache), "stroke cache");
ss->cache = cache;
}
else {
@@ -1551,7 +1647,7 @@ static void vwpaint_update_cache_invariants(
/* Truly temporary data that isn't stored in properties */
cache->vc = vc;
cache->brush = brush;
- cache->first_time = 1;
+ cache->first_time = true;
/* cache projection matrix */
ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, cache->projection_mat);
@@ -1618,12 +1714,12 @@ static void vwpaint_update_cache_variants(bContext *C, VPaint *vp, Object *ob, P
static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
{
Scene *scene = CTX_data_scene(C);
- struct PaintStroke *stroke = op->customdata;
+ PaintStroke *stroke = (PaintStroke *)op->customdata;
ToolSettings *ts = scene->toolsettings;
Object *ob = CTX_data_active_object(C);
Mesh *me = BKE_mesh_from_object(ob);
- struct WPaintData *wpd;
- struct WPaintVGroupIndex vgroup_index;
+ WPaintData *wpd;
+ WPaintVGroupIndex vgroup_index;
int defbase_tot, defbase_tot_sel;
bool *defbase_sel;
SculptSession *ss = ob->sculpt;
@@ -1638,13 +1734,13 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
/* check if we are attempting to paint onto a locked vertex group,
* and other options disallow it from doing anything useful */
bDeformGroup *dg;
- dg = BLI_findlink(&me->vertex_group_names, vgroup_index.active);
+ dg = (bDeformGroup *)BLI_findlink(&me->vertex_group_names, vgroup_index.active);
if (dg->flag & DG_LOCK_WEIGHT) {
BKE_report(op->reports, RPT_WARNING, "Active group is locked, aborting");
return false;
}
if (vgroup_index.mirror != -1) {
- dg = BLI_findlink(&me->vertex_group_names, vgroup_index.mirror);
+ dg = (bDeformGroup *)BLI_findlink(&me->vertex_group_names, vgroup_index.mirror);
if (dg->flag & DG_LOCK_WEIGHT) {
BKE_report(op->reports, RPT_WARNING, "Mirror group is locked, aborting");
return false;
@@ -1667,7 +1763,7 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
for (i = 0; i < defbase_tot; i++) {
if (defbase_sel[i]) {
- dg = BLI_findlink(&me->vertex_group_names, i);
+ dg = (bDeformGroup *)BLI_findlink(&me->vertex_group_names, i);
if (dg->flag & DG_LOCK_WEIGHT) {
BKE_report(op->reports, RPT_WARNING, "Multipaint group is locked, aborting");
MEM_freeN(defbase_sel);
@@ -1679,7 +1775,7 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
/* ALLOCATIONS! no return after this line */
/* make mode data storage */
- wpd = MEM_callocN(sizeof(struct WPaintData), "WPaintData");
+ wpd = (WPaintData *)MEM_callocN(sizeof(WPaintData), "WPaintData");
paint_stroke_set_mode_data(stroke, wpd);
ED_view3d_viewcontext_init(C, &wpd->vc, depsgraph);
view_angle_limits_init(&wpd->normal_angle_precalc,
@@ -1712,10 +1808,10 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
}
if (wpd->do_lock_relative || (ts->auto_normalize && wpd->lock_flags && !wpd->do_multipaint)) {
- bool *unlocked = MEM_dupallocN(wpd->vgroup_validmap);
+ bool *unlocked = (bool *)MEM_dupallocN(wpd->vgroup_validmap);
if (wpd->lock_flags) {
- bool *locked = MEM_mallocN(sizeof(bool) * wpd->defbase_tot, __func__);
+ bool *locked = (bool *)MEM_mallocN(sizeof(bool) * wpd->defbase_tot, __func__);
BKE_object_defgroup_split_locked_validmap(
wpd->defbase_tot, wpd->lock_flags, wpd->vgroup_validmap, locked, unlocked);
wpd->vgroup_locked = locked;
@@ -1726,7 +1822,7 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
if (wpd->do_multipaint && ts->auto_normalize) {
bool *tmpflags;
- tmpflags = MEM_mallocN(sizeof(bool) * defbase_tot, __func__);
+ tmpflags = (bool *)MEM_mallocN(sizeof(bool) * defbase_tot, __func__);
if (wpd->lock_flags) {
BLI_array_binary_or(tmpflags, wpd->defbase_sel, wpd->lock_flags, wpd->defbase_tot);
}
@@ -1738,27 +1834,27 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
else if (ts->auto_normalize) {
bool *tmpflags;
- tmpflags = wpd->lock_flags ? MEM_dupallocN(wpd->lock_flags) :
- MEM_callocN(sizeof(bool) * defbase_tot, __func__);
+ tmpflags = wpd->lock_flags ? (bool *)MEM_dupallocN(wpd->lock_flags) :
+ (bool *)MEM_callocN(sizeof(bool) * defbase_tot, __func__);
tmpflags[wpd->active.index] = true;
wpd->active.lock = tmpflags;
- tmpflags = wpd->lock_flags ? MEM_dupallocN(wpd->lock_flags) :
- MEM_callocN(sizeof(bool) * defbase_tot, __func__);
+ tmpflags = wpd->lock_flags ? (bool *)MEM_dupallocN(wpd->lock_flags) :
+ (bool *)MEM_callocN(sizeof(bool) * defbase_tot, __func__);
tmpflags[(wpd->mirror.index != -1) ? wpd->mirror.index : wpd->active.index] = true;
wpd->mirror.lock = tmpflags;
}
/* If not previously created, create vertex/weight paint mode session data */
- vertex_paint_init_stroke(depsgraph, ob);
+ vertex_paint_init_stroke(scene, depsgraph, ob);
vwpaint_update_cache_invariants(C, vp, ss, op, mouse);
vertex_paint_init_session_data(ts, ob);
if (ELEM(vp->paint.brush->weightpaint_tool, WPAINT_TOOL_SMEAR, WPAINT_TOOL_BLUR)) {
- wpd->precomputed_weight = MEM_mallocN(sizeof(float) * me->totvert, __func__);
+ wpd->precomputed_weight = (float *)MEM_mallocN(sizeof(float) * me->totvert, __func__);
}
- if (ob->sculpt->mode.wpaint.dvert_prev != NULL) {
+ if (ob->sculpt->mode.wpaint.dvert_prev != nullptr) {
MDeformVert *dv = ob->sculpt->mode.wpaint.dvert_prev;
for (int i = 0; i < me->totvert; i++, dv++) {
/* Use to show this isn't initialized, never apply to the mesh data. */
@@ -1807,27 +1903,26 @@ static void do_wpaint_precompute_weight_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict UNUSED(tls))
{
- SculptThreadedTaskData *data = userdata;
+ SculptThreadedTaskData *data = (SculptThreadedTaskData *)userdata;
const MDeformVert *dv = &data->me->dvert[n];
data->wpd->precomputed_weight[n] = wpaint_get_active_weight(dv, data->wpi);
}
static void precompute_weight_values(
- bContext *C, Object *ob, Brush *brush, struct WPaintData *wpd, WeightPaintInfo *wpi, Mesh *me)
+ bContext *C, Object *ob, Brush *brush, WPaintData *wpd, WeightPaintInfo *wpi, Mesh *me)
{
if (wpd->precomputed_weight_ready && !brush_use_accumulate_ex(brush, ob->mode)) {
return;
}
/* threaded loop over vertices */
- SculptThreadedTaskData data = {
- .C = C,
- .ob = ob,
- .wpd = wpd,
- .wpi = wpi,
- .me = me,
- };
+ SculptThreadedTaskData data;
+ data.C = C;
+ data.ob = ob;
+ data.wpd = wpd;
+ data.wpi = wpi;
+ data.me = me;
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
@@ -1840,11 +1935,11 @@ static void do_wpaint_brush_blur_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict UNUSED(tls))
{
- SculptThreadedTaskData *data = userdata;
+ SculptThreadedTaskData *data = (SculptThreadedTaskData *)userdata;
SculptSession *ss = data->ob->sculpt;
const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
const bool has_grids = (pbvh_type == PBVH_GRIDS);
- const struct SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap;
+ const SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap;
const Brush *brush = data->brush;
const StrokeCache *cache = ss->cache;
@@ -1931,11 +2026,11 @@ static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict UNUSED(tls))
{
- SculptThreadedTaskData *data = userdata;
+ SculptThreadedTaskData *data = (SculptThreadedTaskData *)userdata;
SculptSession *ss = data->ob->sculpt;
const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
const bool has_grids = (pbvh_type == PBVH_GRIDS);
- const struct SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap;
+ const SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap;
const Brush *brush = data->brush;
const Scene *scene = CTX_data_scene(data->C);
@@ -2041,7 +2136,7 @@ static void do_wpaint_brush_draw_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict UNUSED(tls))
{
- SculptThreadedTaskData *data = userdata;
+ SculptThreadedTaskData *data = (SculptThreadedTaskData *)userdata;
SculptSession *ss = data->ob->sculpt;
const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
const bool has_grids = (pbvh_type == PBVH_GRIDS);
@@ -2112,7 +2207,7 @@ static void do_wpaint_brush_draw_task_cb_ex(void *__restrict userdata,
static void do_wpaint_brush_calc_average_weight_cb_ex(
void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
{
- SculptThreadedTaskData *data = userdata;
+ SculptThreadedTaskData *data = (SculptThreadedTaskData *)userdata;
SculptSession *ss = data->ob->sculpt;
StrokeCache *cache = ss->cache;
const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
@@ -2122,7 +2217,7 @@ static void do_wpaint_brush_calc_average_weight_cb_ex(
const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
- struct WPaintAverageAccum *accum = (struct WPaintAverageAccum *)data->custom_data + n;
+ WPaintAverageAccum *accum = (WPaintAverageAccum *)data->custom_data + n;
accum->len = 0;
accum->value = 0.0;
@@ -2143,7 +2238,6 @@ static void do_wpaint_brush_calc_average_weight_cb_ex(
BKE_brush_curve_strength(data->brush, sqrtf(test.dist), cache->radius) > 0.0) {
const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
vd.vert_indices[vd.i];
- // const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
const char v_flag = data->me->mvert[v_index].flag;
/* If the vertex is selected. */
@@ -2162,7 +2256,8 @@ static void calculate_average_weight(SculptThreadedTaskData *data,
PBVHNode **UNUSED(nodes),
int totnode)
{
- struct WPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
+ WPaintAverageAccum *accum = (WPaintAverageAccum *)MEM_mallocN(sizeof(*accum) * totnode,
+ __func__);
data->custom_data = accum;
TaskParallelSettings settings;
@@ -2187,7 +2282,7 @@ static void wpaint_paint_leaves(bContext *C,
Object *ob,
Sculpt *sd,
VPaint *vp,
- struct WPaintData *wpd,
+ WPaintData *wpd,
WeightPaintInfo *wpi,
Mesh *me,
PBVHNode **nodes,
@@ -2197,17 +2292,16 @@ static void wpaint_paint_leaves(bContext *C,
const Brush *brush = ob->sculpt->cache->brush;
/* threaded loop over nodes */
- SculptThreadedTaskData data = {
- .C = C,
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .vp = vp,
- .wpd = wpd,
- .wpi = wpi,
- .me = me,
- };
+ SculptThreadedTaskData data = {nullptr};
+ data.C = C;
+ data.sd = sd;
+ data.ob = ob;
+ data.brush = brush;
+ data.nodes = nodes;
+ data.vp = vp;
+ data.wpd = wpd;
+ data.wpi = wpi;
+ data.me = me;
/* Use this so average can modify its weight without touching the brush. */
data.strength = BKE_brush_weight_get(scene, brush);
@@ -2239,16 +2333,16 @@ static PBVHNode **vwpaint_pbvh_gather_generic(
{
SculptSession *ss = ob->sculpt;
const bool use_normal = vwpaint_use_normal(wp);
- PBVHNode **nodes = NULL;
+ PBVHNode **nodes = nullptr;
/* Build a list of all nodes that are potentially within the brush's area of influence */
if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
- SculptSearchSphereData data = {
- .ss = ss,
- .sd = sd,
- .radius_squared = ss->cache->radius_squared,
- .original = true,
- };
+ SculptSearchSphereData data = {nullptr};
+ data.ss = ss;
+ data.sd = sd;
+ data.radius_squared = ss->cache->radius_squared;
+ data.original = true;
+
BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode);
if (use_normal) {
SCULPT_pbvh_calc_area_normal(
@@ -2259,16 +2353,16 @@ static PBVHNode **vwpaint_pbvh_gather_generic(
}
}
else {
- struct DistRayAABB_Precalc dist_ray_to_aabb_precalc;
+ DistRayAABB_Precalc dist_ray_to_aabb_precalc;
dist_squared_ray_to_aabb_v3_precalc(
&dist_ray_to_aabb_precalc, ss->cache->location, ss->cache->view_normal);
- SculptSearchCircleData data = {
- .ss = ss,
- .sd = sd,
- .radius_squared = ss->cache->radius_squared,
- .original = true,
- .dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc,
- };
+ SculptSearchCircleData data = {nullptr};
+ data.ss = ss;
+ data.sd = sd;
+ data.radius_squared = ss->cache->radius_squared;
+ data.original = true;
+ data.dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc;
+
BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_circle_cb, &data, &nodes, r_totnode);
if (use_normal) {
copy_v3_v3(ss->cache->sculpt_normal_symm, ss->cache->view_normal);
@@ -2284,7 +2378,7 @@ static void wpaint_do_paint(bContext *C,
Object *ob,
VPaint *wp,
Sculpt *sd,
- struct WPaintData *wpd,
+ WPaintData *wpd,
WeightPaintInfo *wpi,
Mesh *me,
Brush *brush,
@@ -2311,7 +2405,7 @@ static void wpaint_do_radial_symmetry(bContext *C,
Object *ob,
VPaint *wp,
Sculpt *sd,
- struct WPaintData *wpd,
+ WPaintData *wpd,
WeightPaintInfo *wpi,
Mesh *me,
Brush *brush,
@@ -2327,10 +2421,10 @@ static void wpaint_do_radial_symmetry(bContext *C,
/* near duplicate of: sculpt.c's,
* 'do_symmetrical_brush_actions' and 'vpaint_do_symmetrical_brush_actions'. */
static void wpaint_do_symmetrical_brush_actions(
- bContext *C, Object *ob, VPaint *wp, Sculpt *sd, struct WPaintData *wpd, WeightPaintInfo *wpi)
+ bContext *C, Object *ob, VPaint *wp, Sculpt *sd, WPaintData *wpd, WeightPaintInfo *wpi)
{
Brush *brush = BKE_paint_brush(&wp->paint);
- Mesh *me = ob->data;
+ Mesh *me = (Mesh *)ob->data;
SculptSession *ss = ob->sculpt;
StrokeCache *cache = ss->cache;
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
@@ -2380,14 +2474,14 @@ static void wpaint_do_symmetrical_brush_actions(
static void wpaint_stroke_update_step(bContext *C,
wmOperator *UNUSED(op),
- struct PaintStroke *stroke,
+ PaintStroke *stroke,
PointerRNA *itemptr)
{
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = CTX_data_tool_settings(C);
VPaint *wp = ts->wpaint;
Brush *brush = BKE_paint_brush(&wp->paint);
- struct WPaintData *wpd = paint_stroke_mode_data(stroke);
+ WPaintData *wpd = (WPaintData *)paint_stroke_mode_data(stroke);
ViewContext *vc;
Object *ob = CTX_data_active_object(C);
@@ -2400,11 +2494,11 @@ static void wpaint_stroke_update_step(bContext *C,
const float brush_alpha_value = BKE_brush_alpha_get(scene, brush);
- /* intentionally don't initialize as NULL, make sure we initialize all members below */
+ /* intentionally don't initialize as nullptr, make sure we initialize all members below */
WeightPaintInfo wpi;
/* cannot paint if there is no stroke data */
- if (wpd == NULL) {
+ if (wpd == nullptr) {
/* XXX: force a redraw here, since even though we can't paint,
* at least view won't freeze until stroke ends */
ED_region_tag_redraw(CTX_wm_region(C));
@@ -2434,7 +2528,7 @@ static void wpaint_stroke_update_step(bContext *C,
wpi.vgroup_unlocked = wpd->vgroup_unlocked;
wpi.do_flip = RNA_boolean_get(itemptr, "pen_flip") || ss->cache->invert;
wpi.do_multipaint = wpd->do_multipaint;
- wpi.do_auto_normalize = ((ts->auto_normalize != 0) && (wpi.vgroup_validmap != NULL) &&
+ wpi.do_auto_normalize = ((ts->auto_normalize != 0) && (wpi.vgroup_validmap != nullptr) &&
(wpi.do_multipaint || wpi.vgroup_validmap[wpi.active.index]));
wpi.do_lock_relative = wpd->do_lock_relative;
wpi.is_normalized = wpi.do_auto_normalize || wpi.do_lock_relative;
@@ -2442,7 +2536,7 @@ static void wpaint_stroke_update_step(bContext *C,
/* *** done setting up WeightPaintInfo *** */
if (wpd->precomputed_weight) {
- precompute_weight_values(C, ob, brush, wpd, &wpi, ob->data);
+ precompute_weight_values(C, ob, brush, wpd, &wpi, (Mesh *)ob->data);
}
wpaint_do_symmetrical_brush_actions(C, ob, wp, sd, wpd, &wpi);
@@ -2455,9 +2549,9 @@ static void wpaint_stroke_update_step(bContext *C,
mul_v3_m4v3(loc_world, ob->obmat, ss->cache->true_location);
paint_last_stroke_update(scene, loc_world);
- BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ BKE_mesh_batch_cache_dirty_tag((Mesh *)ob->data, BKE_MESH_BATCH_DIRTY_ALL);
- DEG_id_tag_update(ob->data, 0);
+ DEG_id_tag_update((ID *)ob->data, 0);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
swap_m4m4(wpd->vc.rv3d->persmat, mat);
@@ -2483,10 +2577,10 @@ static void wpaint_stroke_update_step(bContext *C,
ED_region_tag_redraw_partial(vc->region, &r, true);
}
-static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
+static void wpaint_stroke_done(const bContext *C, PaintStroke *stroke)
{
Object *ob = CTX_data_active_object(C);
- struct WPaintData *wpd = paint_stroke_mode_data(stroke);
+ WPaintData *wpd = (WPaintData *)paint_stroke_mode_data(stroke);
if (wpd) {
if (wpd->defbase_sel) {
@@ -2530,7 +2624,7 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
ParticleSystem *psys;
int i;
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
+ for (psys = (ParticleSystem *)ob->particlesystem.first; psys; psys = psys->next) {
for (i = 0; i < PSYS_TOT_VG; i++) {
if (psys->vgroup[i] == BKE_object_defgroup_active_index_get(ob)) {
psys->recalc |= ID_RECALC_PSYS_RESET;
@@ -2540,12 +2634,12 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
}
}
- DEG_id_tag_update(ob->data, 0);
+ DEG_id_tag_update((ID *)ob->data, 0);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
SCULPT_cache_free(ob->sculpt->cache);
- ob->sculpt->cache = NULL;
+ ob->sculpt->cache = nullptr;
}
static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -2557,12 +2651,12 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
SCULPT_stroke_get_location,
wpaint_stroke_test_start,
wpaint_stroke_update_step,
- NULL,
+ nullptr,
wpaint_stroke_done,
event->type);
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_free(C, op, op->customdata);
+ paint_stroke_free(C, op, (PaintStroke *)op->customdata);
return OPERATOR_FINISHED;
}
/* add modal handler */
@@ -2581,12 +2675,12 @@ static int wpaint_exec(bContext *C, wmOperator *op)
SCULPT_stroke_get_location,
wpaint_stroke_test_start,
wpaint_stroke_update_step,
- NULL,
+ nullptr,
wpaint_stroke_done,
0);
/* frees op->customdata */
- paint_stroke_exec(C, op, op->customdata);
+ paint_stroke_exec(C, op, (PaintStroke *)op->customdata);
return OPERATOR_FINISHED;
}
@@ -2596,15 +2690,15 @@ static void wpaint_cancel(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
if (ob->sculpt->cache) {
SCULPT_cache_free(ob->sculpt->cache);
- ob->sculpt->cache = NULL;
+ ob->sculpt->cache = nullptr;
}
- paint_stroke_cancel(C, op, op->customdata);
+ paint_stroke_cancel(C, op, (PaintStroke *)op->customdata);
}
static int wpaint_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- return paint_stroke_modal(C, op, event, (struct PaintStroke **)&op->customdata);
+ return paint_stroke_modal(C, op, event, (PaintStroke **)&op->customdata);
}
void PAINT_OT_weight_paint(wmOperatorType *ot)
@@ -2647,7 +2741,7 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op)
ToolSettings *ts = scene->toolsettings;
if (!is_mode_set) {
- if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
+ if (!ED_object_mode_compat_set(C, ob, (eObjectMode)mode_flag, op->reports)) {
return OPERATOR_CANCELLED;
}
}
@@ -2667,13 +2761,12 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op)
BKE_paint_toolslots_brush_validate(bmain, &ts->vpaint->paint);
}
- BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ BKE_mesh_batch_cache_dirty_tag((Mesh *)ob->data, BKE_MESH_BATCH_DIRTY_ALL);
/* update modifier stack for mapping requirements */
DEG_id_tag_update(&me->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
-
WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
WM_toolsystem_update_from_context_view3d(C);
@@ -2720,14 +2813,20 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
* - revise whether op->customdata should be added in object, in set_vpaint.
*/
-struct VPaintData {
+struct VPaintDataBase {
ViewContext vc;
- struct NormalAnglePrecalc normal_angle_precalc;
+ AttributeDomain domain;
+ CustomDataType type;
+};
+
+template<typename Color, typename Traits, AttributeDomain domain>
+struct VPaintData : public VPaintDataBase {
+ NormalAnglePrecalc normal_angle_precalc;
- uint paintcol;
+ Color paintcol;
struct VertProjHandle *vp_handle;
- struct CoNo *vertexcosnos;
+ CoNo *vertexcosnos;
/**
* Modify #Mesh.mloopcol directly, since the derived mesh is drawing from this
@@ -2743,44 +2842,43 @@ struct VPaintData {
/* Special storage for smear brush, avoid feedback loop - update each step. */
struct {
- uint *color_prev;
- uint *color_curr;
+ void *color_prev;
+ void *color_curr;
} smear;
};
-static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const float mouse[2])
+template<typename Color, typename Traits, AttributeDomain domain>
+static void *vpaint_init_vpaint(bContext *C,
+ wmOperator *op,
+ Scene *scene,
+ Depsgraph *depsgraph,
+ VPaint *vp,
+ Object *ob,
+ Mesh *me,
+ const Brush *brush)
{
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- struct PaintStroke *stroke = op->customdata;
- VPaint *vp = ts->vpaint;
- Brush *brush = BKE_paint_brush(&vp->paint);
- struct VPaintData *vpd;
- Object *ob = CTX_data_active_object(C);
- Mesh *me;
- SculptSession *ss = ob->sculpt;
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ VPaintData<Color, Traits, domain> *vpd;
- /* context checks could be a poll() */
- me = BKE_mesh_from_object(ob);
- if (me == NULL || me->totpoly == 0) {
- return false;
- }
+ size_t elem_size;
+ int elem_num = get_vcol_elements(me, &elem_size);
+ /* make mode data storage */
+ vpd = MEM_new<VPaintData<Color, Traits, domain>>("VPaintData");
- ED_mesh_color_ensure(me, NULL);
- if (me->mloopcol == NULL) {
- return false;
+ if constexpr (std::is_same_v<Color, ColorPaint4f>) {
+ vpd->type = CD_PROP_COLOR;
+ }
+ else {
+ vpd->type = CD_PROP_BYTE_COLOR;
}
- /* make mode data storage */
- vpd = MEM_callocN(sizeof(*vpd), "VPaintData");
- paint_stroke_set_mode_data(stroke, vpd);
+ vpd->domain = domain;
+
ED_view3d_viewcontext_init(C, &vpd->vc, depsgraph);
view_angle_limits_init(&vpd->normal_angle_precalc,
vp->paint.brush->falloff_angle,
(vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
- vpd->paintcol = vpaint_get_current_col(
+ vpd->paintcol = vpaint_get_current_col<Color, Traits, domain>(
scene, vp, (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_INVERT));
vpd->is_texbrush = !(brush->vertexpaint_tool == VPAINT_TOOL_BLUR) && brush->mtex.tex;
@@ -2789,22 +2887,23 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
* if not we can skip face map trickiness */
if (vertex_paint_use_fast_update_check(ob)) {
vpd->use_fast_update = true;
- // printf("Fast update!\n");
}
else {
vpd->use_fast_update = false;
- // printf("No fast update!\n");
}
/* to keep tracked of modified loops for shared vertex color blending */
if (brush->vertexpaint_tool == VPAINT_TOOL_BLUR) {
- vpd->mlooptag = MEM_mallocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
+ vpd->mlooptag = (bool *)MEM_mallocN(sizeof(bool) * elem_num, "VPaintData mlooptag");
}
if (brush->vertexpaint_tool == VPAINT_TOOL_SMEAR) {
- vpd->smear.color_prev = MEM_mallocN(sizeof(uint) * me->totloop, __func__);
- memcpy(vpd->smear.color_prev, me->mloopcol, sizeof(uint) * me->totloop);
- vpd->smear.color_curr = MEM_dupallocN(vpd->smear.color_prev);
+ CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
+
+ vpd->smear.color_prev = MEM_malloc_arrayN(elem_num, elem_size, __func__);
+ memcpy(vpd->smear.color_prev, layer->data, elem_size * elem_num);
+
+ vpd->smear.color_curr = (uint *)MEM_dupallocN(vpd->smear.color_prev);
}
/* Create projection handle */
@@ -2814,516 +2913,845 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
ob->sculpt->building_vp_handle = false;
}
+ return static_cast<void *>(vpd);
+}
+
+static bool vpaint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
+{
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ PaintStroke *stroke = (PaintStroke *)op->customdata;
+ VPaint *vp = ts->vpaint;
+ Brush *brush = BKE_paint_brush(&vp->paint);
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me;
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+
+ /* context checks could be a poll() */
+ me = BKE_mesh_from_object(ob);
+ if (me == nullptr || me->totpoly == 0) {
+ return false;
+ }
+
+ ED_mesh_color_ensure(me, nullptr);
+
+ CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
+ if (!layer) {
+ return false;
+ }
+
+ AttributeDomain domain = BKE_id_attribute_domain(&me->id, layer);
+ void *vpd = nullptr;
+
+ if (domain == ATTR_DOMAIN_POINT) {
+ if (layer->type == CD_PROP_COLOR) {
+ vpd = vpaint_init_vpaint<ColorPaint4f, FloatTraits, ATTR_DOMAIN_POINT>(
+ C, op, scene, depsgraph, vp, ob, me, brush);
+ }
+ else if (layer->type == CD_PROP_BYTE_COLOR) {
+ vpd = vpaint_init_vpaint<ColorPaint4b, ByteTraits, ATTR_DOMAIN_POINT>(
+ C, op, scene, depsgraph, vp, ob, me, brush);
+ }
+ }
+ else if (domain == ATTR_DOMAIN_CORNER) {
+ if (layer->type == CD_PROP_COLOR) {
+ vpd = vpaint_init_vpaint<ColorPaint4f, FloatTraits, ATTR_DOMAIN_CORNER>(
+ C, op, scene, depsgraph, vp, ob, me, brush);
+ }
+ else if (layer->type == CD_PROP_BYTE_COLOR) {
+ vpd = vpaint_init_vpaint<ColorPaint4b, ByteTraits, ATTR_DOMAIN_CORNER>(
+ C, op, scene, depsgraph, vp, ob, me, brush);
+ }
+ }
+
+ BLI_assert(vpd != nullptr);
+
+ paint_stroke_set_mode_data(stroke, vpd);
+
/* If not previously created, create vertex/weight paint mode session data */
- vertex_paint_init_stroke(depsgraph, ob);
+ vertex_paint_init_stroke(scene, depsgraph, ob);
vwpaint_update_cache_invariants(C, vp, ss, op, mouse);
vertex_paint_init_session_data(ts, ob);
- if (ob->sculpt->mode.vpaint.previous_color != NULL) {
- memset(ob->sculpt->mode.vpaint.previous_color, 0, sizeof(uint) * me->totloop);
- }
-
return true;
}
-static void do_vpaint_brush_calc_average_color_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
+template<class Color = ColorPaint4b, typename Traits = ByteTraits>
+static void do_vpaint_brush_blur_loops(bContext *C,
+ Sculpt *UNUSED(sd),
+ VPaint *vp,
+ VPaintData<Color, Traits, ATTR_DOMAIN_CORNER> *vpd,
+ Object *ob,
+ Mesh *me,
+ PBVHNode **nodes,
+ int totnode,
+ Color *lcol)
{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
- const bool has_grids = (pbvh_type == PBVH_GRIDS);
- const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
+ using Blend = typename Traits::BlendType;
- StrokeCache *cache = ss->cache;
- uint *lcol = data->lcol;
- char *col;
- const bool use_vert_sel = (data->me->editflag &
- (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
+ SculptSession *ss = ob->sculpt;
- struct VPaintAverageAccum *accum = (struct VPaintAverageAccum *)data->custom_data + n;
- accum->len = 0;
- memset(accum->value, 0, sizeof(accum->value));
+ const Brush *brush = ob->sculpt->cache->brush;
+ const Scene *scene = CTX_data_scene(C);
+
+ Color *previous_color = static_cast<Color *>(ss->cache->prev_colors_vpaint);
+
+ blender::threading::parallel_for(IndexRange(totnode), 1LL, [&](IndexRange range) {
+ for (int n : range) {
+ const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
+ const bool has_grids = (pbvh_type == PBVH_GRIDS);
+
+ const SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
+ const StrokeCache *cache = ss->cache;
+ float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
+ get_brush_alpha_data(
+ scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
+ const bool use_normal = vwpaint_use_normal(vp);
+ const bool use_vert_sel = (me->editflag &
+ (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, brush->falloff_shape);
+ const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
+ ss, brush->falloff_shape);
+
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ /* For grid based pbvh, take the vert whose loop corresponds to the current grid.
+ * Otherwise, take the current vert. */
+ const int v_index = has_grids ? me->mloop[vd.grid_indices[vd.g]].v :
+ vd.vert_indices[vd.i];
+ const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
+ const MVert *mv = &me->mvert[v_index];
+
+ /* If the vertex is selected for painting. */
+ if (!use_vert_sel || mv->flag & SELECT) {
+ float brush_strength = cache->bstrength;
+ const float angle_cos = (use_normal && vd.no) ?
+ dot_v3v3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
+ if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
+ ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
+ view_angle_limits_apply_falloff(
+ &vpd->normal_angle_precalc, angle_cos, &brush_strength))) {
+ const float brush_fade = BKE_brush_curve_strength(
+ brush, sqrtf(test.dist), cache->radius);
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
+ /* Get the average poly color */
+ Color color_final(0, 0, 0, 0);
- /* For each vertex */
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- /* Test to see if the vertex coordinates are within the spherical brush region. */
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
- vd.vert_indices[vd.i];
- if (BKE_brush_curve_strength(data->brush, 0.0, cache->radius) > 0.0) {
- /* If the vertex is selected for painting. */
- const MVert *mv = &data->me->mvert[v_index];
- if (!use_vert_sel || mv->flag & SELECT) {
- accum->len += gmap->vert_to_loop[v_index].count;
- /* if a vertex is within the brush region, then add its color to the blend. */
- for (int j = 0; j < gmap->vert_to_loop[v_index].count; j++) {
- const int l_index = gmap->vert_to_loop[v_index].indices[j];
- col = (char *)(&lcol[l_index]);
- /* Color is squared to compensate the sqrt color encoding. */
- accum->value[0] += col[0] * col[0];
- accum->value[1] += col[1] * col[1];
- accum->value[2] += col[2] * col[2];
+ int total_hit_loops = 0;
+ Blend blend[4] = {0};
+
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ int p_index = gmap->vert_to_poly[v_index].indices[j];
+ const MPoly *mp = &me->mpoly[p_index];
+ if (!use_face_sel || mp->flag & ME_FACE_SEL) {
+ total_hit_loops += mp->totloop;
+ for (int k = 0; k < mp->totloop; k++) {
+ const uint l_index = mp->loopstart + k;
+ Color *col = lcol + l_index;
+
+ /* Color is squared to compensate the sqrt color encoding. */
+ blend[0] += (Blend)col->r * (Blend)col->r;
+ blend[1] += (Blend)col->g * (Blend)col->g;
+ blend[2] += (Blend)col->b * (Blend)col->b;
+ blend[3] += (Blend)col->a * (Blend)col->a;
+ }
+ }
+ }
+
+ if (total_hit_loops != 0) {
+ /* Use rgb^2 color averaging. */
+ Color *col = &color_final;
+
+ color_final.r = Traits::round(
+ sqrtf(Traits::divide_round(blend[0], total_hit_loops)));
+ color_final.g = Traits::round(
+ sqrtf(Traits::divide_round(blend[1], total_hit_loops)));
+ color_final.b = Traits::round(
+ sqrtf(Traits::divide_round(blend[2], total_hit_loops)));
+ color_final.a = Traits::round(
+ sqrtf(Traits::divide_round(blend[3], total_hit_loops)));
+
+ /* For each poly owning this vert,
+ * paint each loop belonging to this vert. */
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ const int p_index = gmap->vert_to_poly[v_index].indices[j];
+ const int l_index = gmap->vert_to_loop[v_index].indices[j];
+ BLI_assert(me->mloop[l_index].v == v_index);
+ const MPoly *mp = &me->mpoly[p_index];
+ if (!use_face_sel || mp->flag & ME_FACE_SEL) {
+ Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
+
+ if (previous_color != nullptr) {
+ /* Get the previous loop color */
+ if (isZero(previous_color[l_index])) {
+ previous_color[l_index] = lcol[l_index];
+ }
+ color_orig = previous_color[l_index];
+ }
+ const float final_alpha = Traits::range * brush_fade * brush_strength *
+ brush_alpha_pressure * grid_alpha;
+ /* Mix the new color with the original
+ * based on the brush strength and the curve. */
+ lcol[l_index] = vpaint_blend<Color, Traits>(vp,
+ lcol[l_index],
+ color_orig,
+ *col,
+ final_alpha,
+ Traits::range * brush_strength);
+ }
+ }
+ }
+ }
}
}
}
- }
- }
- BKE_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
+ };
+ });
}
-static float tex_color_alpha_ubyte(SculptThreadedTaskData *data,
- const float v_co[3],
- uint *r_color)
+template<class Color = ColorPaint4b, typename Traits = ByteTraits>
+static void do_vpaint_brush_blur_verts(bContext *C,
+ Sculpt *UNUSED(sd),
+ VPaint *vp,
+ VPaintData<Color, Traits, ATTR_DOMAIN_POINT> *vpd,
+ Object *ob,
+ Mesh *me,
+ PBVHNode **nodes,
+ int totnode,
+ Color *lcol)
{
- float rgba[4];
- float rgba_br[3];
- tex_color_alpha(data->vp, &data->vpd->vc, v_co, rgba);
- rgb_uchar_to_float(rgba_br, (const uchar *)&data->vpd->paintcol);
- mul_v3_v3(rgba_br, rgba);
- rgb_float_to_uchar((uchar *)r_color, rgba_br);
- return rgba[3];
-}
+ using Blend = typename Traits::BlendType;
-static void do_vpaint_brush_draw_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
- const bool has_grids = (pbvh_type == PBVH_GRIDS);
- const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
+ SculptSession *ss = ob->sculpt;
- const Brush *brush = data->brush;
- const StrokeCache *cache = ss->cache;
- uint *lcol = data->lcol;
- const Scene *scene = CTX_data_scene(data->C);
- float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
- get_brush_alpha_data(
- scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
- const bool use_normal = vwpaint_use_normal(data->vp);
- const bool use_vert_sel = (data->me->editflag &
- (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
- const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ const Brush *brush = ob->sculpt->cache->brush;
+ const Scene *scene = CTX_data_scene(C);
+
+ Color *previous_color = static_cast<Color *>(ss->cache->prev_colors_vpaint);
+
+ blender::threading::parallel_for(IndexRange(totnode), 1LL, [&](IndexRange range) {
+ for (int n : range) {
+ const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
+ const bool has_grids = (pbvh_type == PBVH_GRIDS);
+
+ const SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
+ const StrokeCache *cache = ss->cache;
+ float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
+ get_brush_alpha_data(
+ scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
+ const bool use_normal = vwpaint_use_normal(vp);
+ const bool use_vert_sel = (me->editflag &
+ (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, brush->falloff_shape);
+ const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
+ ss, brush->falloff_shape);
+
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ /* For grid based pbvh, take the vert whose loop corresponds to the current grid.
+ * Otherwise, take the current vert. */
+ const int v_index = has_grids ? me->mloop[vd.grid_indices[vd.g]].v :
+ vd.vert_indices[vd.i];
+ const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
+ const MVert *mv = &me->mvert[v_index];
+
+ /* If the vertex is selected for painting. */
+ if (!use_vert_sel || mv->flag & SELECT) {
+ float brush_strength = cache->bstrength;
+ const float angle_cos = (use_normal && vd.no) ?
+ dot_v3v3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
+ if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
+ ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
+ view_angle_limits_apply_falloff(
+ &vpd->normal_angle_precalc, angle_cos, &brush_strength))) {
+ const float brush_fade = BKE_brush_curve_strength(
+ brush, sqrtf(test.dist), cache->radius);
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
- ss, data->brush->falloff_shape);
+ /* Get the average poly color */
+ Color color_final(0, 0, 0, 0);
- /* For each vertex */
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- /* Test to see if the vertex coordinates are within the spherical brush region. */
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- /* NOTE: Grids are 1:1 with corners (aka loops).
- * For grid based pbvh, take the vert whose loop corresponds to the current grid.
- * Otherwise, take the current vert. */
- const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
- vd.vert_indices[vd.i];
- const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
- const MVert *mv = &data->me->mvert[v_index];
+ int total_hit_loops = 0;
+ Blend blend[4] = {0};
- /* If the vertex is selected for painting. */
- if (!use_vert_sel || mv->flag & SELECT) {
- /* Calc the dot prod. between ray norm on surf and current vert
- * (ie splash prevention factor), and only paint front facing verts. */
- float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
- 1.0f;
- if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
- ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
- view_angle_limits_apply_falloff(
- &data->vpd->normal_angle_precalc, angle_cos, &brush_strength))) {
- const float brush_fade = BKE_brush_curve_strength(
- brush, sqrtf(test.dist), cache->radius);
- uint color_final = data->vpd->paintcol;
-
- /* If we're painting with a texture, sample the texture color and alpha. */
- float tex_alpha = 1.0;
- if (data->vpd->is_texbrush) {
- /* NOTE: we may want to paint alpha as vertex color alpha. */
- tex_alpha = tex_color_alpha_ubyte(
- data, data->vpd->vertexcosnos[v_index].co, &color_final);
- }
- /* For each poly owning this vert, paint each loop belonging to this vert. */
- for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
- const int p_index = gmap->vert_to_poly[v_index].indices[j];
- const int l_index = gmap->vert_to_loop[v_index].indices[j];
- BLI_assert(data->me->mloop[l_index].v == v_index);
- const MPoly *mp = &data->me->mpoly[p_index];
- if (!use_face_sel || mp->flag & ME_FACE_SEL) {
- uint color_orig = 0; /* unused when array is NULL */
- if (ss->mode.vpaint.previous_color != NULL) {
- /* Get the previous loop color */
- if (ss->mode.vpaint.previous_color[l_index] == 0) {
- ss->mode.vpaint.previous_color[l_index] = lcol[l_index];
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ int p_index = gmap->vert_to_poly[v_index].indices[j];
+ const MPoly *mp = &me->mpoly[p_index];
+ if (!use_face_sel || mp->flag & ME_FACE_SEL) {
+ total_hit_loops += mp->totloop;
+ for (int k = 0; k < mp->totloop; k++) {
+ const uint l_index = mp->loopstart + k;
+ const uint v_index = me->mloop[l_index].v;
+
+ Color *col = lcol + v_index;
+
+ /* Color is squared to compensate the sqrt color encoding. */
+ blend[0] += (Blend)col->r * (Blend)col->r;
+ blend[1] += (Blend)col->g * (Blend)col->g;
+ blend[2] += (Blend)col->b * (Blend)col->b;
+ blend[3] += (Blend)col->a * (Blend)col->a;
+ }
+ }
+ }
+
+ if (total_hit_loops != 0) {
+ /* Use rgb^2 color averaging. */
+ Color *col = &color_final;
+
+ color_final.r = Traits::round(
+ sqrtf(Traits::divide_round(blend[0], total_hit_loops)));
+ color_final.g = Traits::round(
+ sqrtf(Traits::divide_round(blend[1], total_hit_loops)));
+ color_final.b = Traits::round(
+ sqrtf(Traits::divide_round(blend[2], total_hit_loops)));
+ color_final.a = Traits::round(
+ sqrtf(Traits::divide_round(blend[3], total_hit_loops)));
+
+ /* For each poly owning this vert,
+ * paint each loop belonging to this vert. */
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ const int p_index = gmap->vert_to_poly[v_index].indices[j];
+
+ BLI_assert(me->mloop[gmap->vert_to_loop[v_index].indices[j]].v == v_index);
+
+ const MPoly *mp = &me->mpoly[p_index];
+ if (!use_face_sel || mp->flag & ME_FACE_SEL) {
+ Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
+
+ if (previous_color != nullptr) {
+ /* Get the previous loop color */
+ if (isZero(previous_color[v_index])) {
+ previous_color[v_index] = lcol[v_index];
+ }
+ color_orig = previous_color[v_index];
+ }
+ const float final_alpha = Traits::range * brush_fade * brush_strength *
+ brush_alpha_pressure * grid_alpha;
+ /* Mix the new color with the original
+ * based on the brush strength and the curve. */
+ lcol[v_index] = vpaint_blend<Color, Traits>(vp,
+ lcol[v_index],
+ color_orig,
+ *col,
+ final_alpha,
+ Traits::range * brush_strength);
+ }
}
- color_orig = ss->mode.vpaint.previous_color[l_index];
}
- const float final_alpha = 255 * brush_fade * brush_strength * tex_alpha *
- brush_alpha_pressure * grid_alpha;
-
- /* Mix the new color with the original based on final_alpha. */
- lcol[l_index] = vpaint_blend(data->vp,
- lcol[l_index],
- color_orig,
- color_final,
- final_alpha,
- 255 * brush_strength);
}
}
}
}
- }
- }
- BKE_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
+ };
+ });
}
-static void do_vpaint_brush_blur_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
+template<typename Color = ColorPaint4b, typename Traits, AttributeDomain domain>
+static void do_vpaint_brush_smear(bContext *C,
+ Sculpt *UNUSED(sd),
+ VPaint *vp,
+ VPaintData<Color, Traits, domain> *vpd,
+ Object *ob,
+ Mesh *me,
+ PBVHNode **nodes,
+ int totnode,
+ Color *lcol)
{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
+ SculptSession *ss = ob->sculpt;
+
+ const SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
+ const StrokeCache *cache = ss->cache;
const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
const bool has_grids = (pbvh_type == PBVH_GRIDS);
- Scene *scene = CTX_data_scene(data->C);
- const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
- const Brush *brush = data->brush;
- const StrokeCache *cache = ss->cache;
- uint *lcol = data->lcol;
- float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
- get_brush_alpha_data(
- scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
- const bool use_normal = vwpaint_use_normal(data->vp);
- const bool use_vert_sel = (data->me->editflag &
- (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
- const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ const Brush *brush = ob->sculpt->cache->brush;
+ const Scene *scene = CTX_data_scene(C);
+ Color *color_curr = static_cast<Color *>(vpd->smear.color_curr);
+ Color *color_prev_smear = static_cast<Color *>(vpd->smear.color_prev);
+ Color *color_prev = reinterpret_cast<Color *>(ss->cache->prev_colors_vpaint);
+
+ blender::threading::parallel_for(IndexRange(totnode), 1LL, [&](IndexRange range) {
+ for (int n : range) {
+ float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
+
+ get_brush_alpha_data(
+ scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
+ float brush_dir[3];
+ const bool use_normal = vwpaint_use_normal(vp);
+ const bool use_vert_sel = (me->editflag &
+ (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+
+ sub_v3_v3v3(brush_dir, cache->location, cache->last_location);
+ project_plane_v3_v3v3(brush_dir, brush_dir, cache->view_normal);
+
+ if (cache->is_last_valid && (normalize_v3(brush_dir) != 0.0f)) {
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, brush->falloff_shape);
+ const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
+ ss, brush->falloff_shape);
+
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ /* For grid based pbvh, take the vert whose loop corresponds to the current grid.
+ * Otherwise, take the current vert. */
+ const int v_index = has_grids ? me->mloop[vd.grid_indices[vd.g]].v :
+ vd.vert_indices[vd.i];
+ const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
+ const MVert *mv_curr = &me->mvert[v_index];
+
+ /* if the vertex is selected for painting. */
+ if (!use_vert_sel || mv_curr->flag & SELECT) {
+ /* Calc the dot prod. between ray norm on surf and current vert
+ * (ie splash prevention factor), and only paint front facing verts. */
+ float brush_strength = cache->bstrength;
+ const float angle_cos = (use_normal && vd.no) ?
+ dot_v3v3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
+ if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
+ ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
+ view_angle_limits_apply_falloff(
+ &vpd->normal_angle_precalc, angle_cos, &brush_strength))) {
+ const float brush_fade = BKE_brush_curve_strength(
+ brush, sqrtf(test.dist), cache->radius);
+
+ bool do_color = false;
+ /* Minimum dot product between brush direction and current
+ * to neighbor direction is 0.0, meaning orthogonal. */
+ float stroke_dot_max = 0.0f;
+
+ /* Get the color of the loop in the opposite
+ * direction of the brush movement */
+ Color color_final(0, 0, 0, 0);
+
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ const int p_index = gmap->vert_to_poly[v_index].indices[j];
+ const int l_index = gmap->vert_to_loop[v_index].indices[j];
+ BLI_assert(me->mloop[l_index].v == v_index);
+ UNUSED_VARS_NDEBUG(l_index);
+ const MPoly *mp = &me->mpoly[p_index];
+ if (!use_face_sel || mp->flag & ME_FACE_SEL) {
+ const MLoop *ml_other = &me->mloop[mp->loopstart];
+ for (int k = 0; k < mp->totloop; k++, ml_other++) {
+ const uint v_other_index = ml_other->v;
+ if (v_other_index != v_index) {
+ const MVert *mv_other = &me->mvert[v_other_index];
+
+ /* Get the direction from the
+ * selected vert to the neighbor. */
+ float other_dir[3];
+ sub_v3_v3v3(other_dir, mv_curr->co, mv_other->co);
+ project_plane_v3_v3v3(other_dir, other_dir, cache->view_normal);
+
+ normalize_v3(other_dir);
+
+ const float stroke_dot = dot_v3v3(other_dir, brush_dir);
+ int elem_index;
+
+ if constexpr (domain == ATTR_DOMAIN_POINT) {
+ elem_index = ml_other->v;
+ }
+ else {
+ elem_index = mp->loopstart + k;
+ }
+
+ if (stroke_dot > stroke_dot_max) {
+ stroke_dot_max = stroke_dot;
+ color_final = color_prev_smear[elem_index];
+ do_color = true;
+ }
+ }
+ }
+ }
+ }
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
- ss, data->brush->falloff_shape);
+ if (do_color) {
+ const float final_alpha = Traits::range * brush_fade * brush_strength *
+ brush_alpha_pressure * grid_alpha;
- /* For each vertex */
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- /* Test to see if the vertex coordinates are within the spherical brush region. */
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- /* For grid based pbvh, take the vert whose loop corresponds to the current grid.
- * Otherwise, take the current vert. */
- const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
- vd.vert_indices[vd.i];
- const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
- const MVert *mv = &data->me->mvert[v_index];
+ /* For each poly owning this vert,
+ * paint each loop belonging to this vert. */
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ const int p_index = gmap->vert_to_poly[v_index].indices[j];
+ const int l_index = gmap->vert_to_loop[v_index].indices[j];
- /* If the vertex is selected for painting. */
- if (!use_vert_sel || mv->flag & SELECT) {
- float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
- 1.0f;
- if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
- ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
- view_angle_limits_apply_falloff(
- &data->vpd->normal_angle_precalc, angle_cos, &brush_strength))) {
- const float brush_fade = BKE_brush_curve_strength(
- brush, sqrtf(test.dist), cache->radius);
+ int elem_index;
+ if constexpr (domain == ATTR_DOMAIN_POINT) {
+ elem_index = v_index;
+ }
+ else {
+ elem_index = l_index;
+ }
- /* Get the average poly color */
- uint color_final = 0;
- int total_hit_loops = 0;
- uint blend[4] = {0};
- for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
- int p_index = gmap->vert_to_poly[v_index].indices[j];
- const MPoly *mp = &data->me->mpoly[p_index];
- if (!use_face_sel || mp->flag & ME_FACE_SEL) {
- total_hit_loops += mp->totloop;
- for (int k = 0; k < mp->totloop; k++) {
- const uint l_index = mp->loopstart + k;
- const char *col = (const char *)(&lcol[l_index]);
- /* Color is squared to compensate the sqrt color encoding. */
- blend[0] += (uint)col[0] * (uint)col[0];
- blend[1] += (uint)col[1] * (uint)col[1];
- blend[2] += (uint)col[2] * (uint)col[2];
- blend[3] += (uint)col[3] * (uint)col[3];
+ BLI_assert(me->mloop[l_index].v == v_index);
+
+ const MPoly *mp = &me->mpoly[p_index];
+ if (!use_face_sel || mp->flag & ME_FACE_SEL) {
+ /* Get the previous element color */
+ Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
+
+ if (color_prev != nullptr) {
+ /* Get the previous element color */
+ if (isZero(color_prev[elem_index])) {
+ color_prev[elem_index] = lcol[elem_index];
+ }
+ color_orig = color_prev[elem_index];
+ }
+ /* Mix the new color with the original
+ * based on the brush strength and the curve. */
+ lcol[elem_index] = vpaint_blend<Color, Traits>(vp,
+ lcol[elem_index],
+ color_orig,
+ color_final,
+ final_alpha,
+ Traits::range *
+ brush_strength);
+
+ color_curr[elem_index] = lcol[elem_index];
+ }
+ }
+ }
}
}
}
- if (total_hit_loops != 0) {
- /* Use rgb^2 color averaging. */
- char *col = (char *)(&color_final);
- col[0] = round_fl_to_uchar(sqrtf(divide_round_i(blend[0], total_hit_loops)));
- col[1] = round_fl_to_uchar(sqrtf(divide_round_i(blend[1], total_hit_loops)));
- col[2] = round_fl_to_uchar(sqrtf(divide_round_i(blend[2], total_hit_loops)));
- col[3] = round_fl_to_uchar(sqrtf(divide_round_i(blend[3], total_hit_loops)));
-
- /* For each poly owning this vert,
- * paint each loop belonging to this vert. */
- for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
- const int p_index = gmap->vert_to_poly[v_index].indices[j];
- const int l_index = gmap->vert_to_loop[v_index].indices[j];
- BLI_assert(data->me->mloop[l_index].v == v_index);
- const MPoly *mp = &data->me->mpoly[p_index];
- if (!use_face_sel || mp->flag & ME_FACE_SEL) {
- uint color_orig = 0; /* unused when array is NULL */
- if (ss->mode.vpaint.previous_color != NULL) {
- /* Get the previous loop color */
- if (ss->mode.vpaint.previous_color[l_index] == 0) {
- ss->mode.vpaint.previous_color[l_index] = lcol[l_index];
- }
- color_orig = ss->mode.vpaint.previous_color[l_index];
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+ }
+ });
+}
+
+template<typename Color, typename Traits, AttributeDomain domain>
+static void calculate_average_color(VPaintData<Color, Traits, domain> *vpd,
+ Object *ob,
+ Mesh *me,
+ const Brush *brush,
+ Color *lcol,
+ PBVHNode **nodes,
+ int totnode)
+{
+ using Blend = typename Traits::BlendType;
+
+ VPaintAverageAccum<Blend> *accum = (VPaintAverageAccum<Blend> *)MEM_mallocN(
+ sizeof(*accum) * totnode, __func__);
+ blender::threading::parallel_for(IndexRange(totnode), 1LL, [&](IndexRange range) {
+ for (int n : range) {
+ SculptSession *ss = ob->sculpt;
+ const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
+ const bool has_grids = (pbvh_type == PBVH_GRIDS);
+ const SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
+
+ StrokeCache *cache = ss->cache;
+ const bool use_vert_sel = (me->editflag &
+ (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
+
+ VPaintAverageAccum<Blend> *accum2 = accum + n;
+ accum2->len = 0;
+ memset(accum2->value, 0, sizeof(accum2->value));
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, brush->falloff_shape);
+
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const int v_index = has_grids ? me->mloop[vd.grid_indices[vd.g]].v :
+ vd.vert_indices[vd.i];
+ if (BKE_brush_curve_strength(brush, 0.0, cache->radius) > 0.0) {
+ /* If the vertex is selected for painting. */
+ const MVert *mv = &me->mvert[v_index];
+ if (!use_vert_sel || mv->flag & SELECT) {
+ accum2->len += gmap->vert_to_loop[v_index].count;
+ /* if a vertex is within the brush region, then add its color to the blend. */
+ for (int j = 0; j < gmap->vert_to_loop[v_index].count; j++) {
+ int elem_index;
+
+ if constexpr (domain == ATTR_DOMAIN_CORNER) {
+ elem_index = gmap->vert_to_loop[v_index].indices[j];
+ }
+ else {
+ elem_index = v_index;
}
- const float final_alpha = 255 * brush_fade * brush_strength *
- brush_alpha_pressure * grid_alpha;
- /* Mix the new color with the original
- * based on the brush strength and the curve. */
- lcol[l_index] = vpaint_blend(data->vp,
- lcol[l_index],
- color_orig,
- *((uint *)col),
- final_alpha,
- 255 * brush_strength);
+
+ Color *col = lcol + elem_index;
+
+ /* Color is squared to compensate the sqrt color encoding. */
+ accum2->value[0] += col->r * col->r;
+ accum2->value[1] += col->g * col->g;
+ accum2->value[2] += col->b * col->b;
}
}
}
}
}
+ BKE_pbvh_vertex_iter_end;
}
+ });
+
+ Blend accum_len = 0;
+ Blend accum_value[3] = {0};
+ Color blend(0, 0, 0, 0);
+
+ for (int i = 0; i < totnode; i++) {
+ accum_len += accum[i].len;
+ accum_value[0] += accum[i].value[0];
+ accum_value[1] += accum[i].value[1];
+ accum_value[2] += accum[i].value[2];
+ }
+ if (accum_len != 0) {
+ blend.r = Traits::round(sqrtf(Traits::divide_round(accum_value[0], accum_len)));
+ blend.g = Traits::round(sqrtf(Traits::divide_round(accum_value[1], accum_len)));
+ blend.b = Traits::round(sqrtf(Traits::divide_round(accum_value[2], accum_len)));
+ blend.a = Traits::range;
+
+ vpd->paintcol = blend;
}
- BKE_pbvh_vertex_iter_end;
}
-static void do_vpaint_brush_smear_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
+template<typename Color, typename Traits, AttributeDomain domain>
+static float paint_and_tex_color_alpha(VPaint *vp,
+ VPaintData<Color, Traits, domain> *vpd,
+ const float v_co[3],
+ Color *r_color)
{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
- const bool has_grids = (pbvh_type == PBVH_GRIDS);
-
- Scene *scene = CTX_data_scene(data->C);
- const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
- const Brush *brush = data->brush;
- const StrokeCache *cache = ss->cache;
- uint *lcol = data->lcol;
- float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
- get_brush_alpha_data(
- scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
- float brush_dir[3];
- const bool use_normal = vwpaint_use_normal(data->vp);
- const bool use_vert_sel = (data->me->editflag &
- (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
- const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ ColorPaint4f rgba;
+ ColorPaint4f rgba_br = toFloat(*r_color);
- sub_v3_v3v3(brush_dir, cache->location, cache->last_location);
- project_plane_v3_v3v3(brush_dir, brush_dir, cache->view_normal);
+ paint_and_tex_color_alpha_intern(vp, &vpd->vc, v_co, &rgba.r);
- if (cache->is_last_valid && (normalize_v3(brush_dir) != 0.0f)) {
+ rgb_uchar_to_float(&rgba_br.r, (const uchar *)&vpd->paintcol);
+ mul_v3_v3(rgba_br, rgba);
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
- ss, data->brush->falloff_shape);
+ *r_color = fromFloat<Color>(rgba_br);
+ return rgba[3];
+}
- /* For each vertex */
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- /* Test to see if the vertex coordinates are within the spherical brush region. */
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- /* For grid based pbvh, take the vert whose loop corresponds to the current grid.
- * Otherwise, take the current vert. */
- const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v :
- vd.vert_indices[vd.i];
- const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
- const MVert *mv_curr = &data->me->mvert[v_index];
+template<typename Color, typename Traits, AttributeDomain domain>
+static void vpaint_do_draw(bContext *C,
+ Sculpt *UNUSED(sd),
+ VPaint *vp,
+ VPaintData<Color, Traits, domain> *vpd,
+ Object *ob,
+ Mesh *me,
+ PBVHNode **nodes,
+ int totnode,
+ Color *lcol)
+{
+ SculptSession *ss = ob->sculpt;
+ const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
- /* if the vertex is selected for painting. */
- if (!use_vert_sel || mv_curr->flag & SELECT) {
- /* Calc the dot prod. between ray norm on surf and current vert
- * (ie splash prevention factor), and only paint front facing verts. */
- float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ?
- dot_v3v3(sculpt_normal_frontface, vd.no) :
- 1.0f;
- if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
- ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
- view_angle_limits_apply_falloff(
- &data->vpd->normal_angle_precalc, angle_cos, &brush_strength))) {
- const float brush_fade = BKE_brush_curve_strength(
- brush, sqrtf(test.dist), cache->radius);
+ const Brush *brush = ob->sculpt->cache->brush;
+ const Scene *scene = CTX_data_scene(C);
+
+ Color *previous_color = static_cast<Color *>(ss->cache->prev_colors_vpaint);
+
+ blender::threading::parallel_for(IndexRange(totnode), 1LL, [&](IndexRange range) {
+ for (int n : range) {
+ const bool has_grids = (pbvh_type == PBVH_GRIDS);
+ const SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
+
+ const StrokeCache *cache = ss->cache;
+ float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
+ get_brush_alpha_data(
+ scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
+ const bool use_normal = vwpaint_use_normal(vp);
+ const bool use_vert_sel = (me->editflag &
+ (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, brush->falloff_shape);
+ const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
+ ss, brush->falloff_shape);
+
+ Color paintcol = vpd->paintcol;
+
+ /* For each vertex */
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ /* Test to see if the vertex coordinates are within the spherical brush region. */
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ /* NOTE: Grids are 1:1 with corners (aka loops).
+ * For grid based pbvh, take the vert whose loop corresponds to the current grid.
+ * Otherwise, take the current vert. */
+ const int v_index = has_grids ? me->mloop[vd.grid_indices[vd.g]].v :
+ vd.vert_indices[vd.i];
+ const float grid_alpha = has_grids ? 1.0f / vd.gridsize : 1.0f;
+ const MVert *mv = &me->mvert[v_index];
+
+ /* If the vertex is selected for painting. */
+ if (!use_vert_sel || mv->flag & SELECT) {
+ /* Calc the dot prod. between ray norm on surf and current vert
+ * (ie splash prevention factor), and only paint front facing verts. */
+ float brush_strength = cache->bstrength;
+ const float angle_cos = (use_normal && vd.no) ?
+ dot_v3v3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
+ if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
+ ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
+ view_angle_limits_apply_falloff(
+ &vpd->normal_angle_precalc, angle_cos, &brush_strength))) {
+ const float brush_fade = BKE_brush_curve_strength(
+ brush, sqrtf(test.dist), cache->radius);
- bool do_color = false;
- /* Minimum dot product between brush direction and current
- * to neighbor direction is 0.0, meaning orthogonal. */
- float stroke_dot_max = 0.0f;
+ Color color_final = paintcol;
- /* Get the color of the loop in the opposite
- * direction of the brush movement */
- uint color_final = 0;
- for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
- const int p_index = gmap->vert_to_poly[v_index].indices[j];
- const int l_index = gmap->vert_to_loop[v_index].indices[j];
- BLI_assert(data->me->mloop[l_index].v == v_index);
- UNUSED_VARS_NDEBUG(l_index);
- const MPoly *mp = &data->me->mpoly[p_index];
- if (!use_face_sel || mp->flag & ME_FACE_SEL) {
- const MLoop *ml_other = &data->me->mloop[mp->loopstart];
- for (int k = 0; k < mp->totloop; k++, ml_other++) {
- const uint v_other_index = ml_other->v;
- if (v_other_index != v_index) {
- const MVert *mv_other = &data->me->mvert[v_other_index];
-
- /* Get the direction from the
- * selected vert to the neighbor. */
- float other_dir[3];
- sub_v3_v3v3(other_dir, mv_curr->co, mv_other->co);
- project_plane_v3_v3v3(other_dir, other_dir, cache->view_normal);
-
- normalize_v3(other_dir);
-
- const float stroke_dot = dot_v3v3(other_dir, brush_dir);
-
- if (stroke_dot > stroke_dot_max) {
- stroke_dot_max = stroke_dot;
- color_final = data->vpd->smear.color_prev[mp->loopstart + k];
- do_color = true;
- }
- }
- }
+ /* If we're painting with a texture, sample the texture color and alpha. */
+ float tex_alpha = 1.0;
+ if (vpd->is_texbrush) {
+ /* NOTE: we may want to paint alpha as vertex color alpha. */
+ tex_alpha = paint_and_tex_color_alpha<Color, Traits, domain>(
+ vp, vpd, vpd->vertexcosnos[v_index].co, &color_final);
}
- }
- if (do_color) {
- const float final_alpha = 255 * brush_fade * brush_strength * brush_alpha_pressure *
- grid_alpha;
+ Color color_orig(0, 0, 0, 0);
- /* For each poly owning this vert,
- * paint each loop belonging to this vert. */
- for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
- const int p_index = gmap->vert_to_poly[v_index].indices[j];
- const int l_index = gmap->vert_to_loop[v_index].indices[j];
- BLI_assert(data->me->mloop[l_index].v == v_index);
- const MPoly *mp = &data->me->mpoly[p_index];
- if (!use_face_sel || mp->flag & ME_FACE_SEL) {
+ if constexpr (domain == ATTR_DOMAIN_POINT) {
+ int v_index = vd.index;
+
+ if (previous_color != nullptr) {
/* Get the previous loop color */
- uint color_orig = 0; /* unused when array is NULL */
- if (ss->mode.vpaint.previous_color != NULL) {
- /* Get the previous loop color */
- if (ss->mode.vpaint.previous_color[l_index] == 0) {
- ss->mode.vpaint.previous_color[l_index] = lcol[l_index];
+ if (isZero(previous_color[v_index])) {
+ previous_color[v_index] = lcol[v_index];
+ }
+ color_orig = previous_color[v_index];
+ }
+ const float final_alpha = Traits::frange * brush_fade * brush_strength *
+ tex_alpha * brush_alpha_pressure * grid_alpha;
+
+ lcol[v_index] = vpaint_blend<Color, Traits>(vp,
+ lcol[v_index],
+ color_orig,
+ color_final,
+ final_alpha,
+ Traits::range * brush_strength);
+ }
+ else {
+ /* For each poly owning this vert, paint each loop belonging to this vert. */
+ for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
+ const int p_index = gmap->vert_to_poly[v_index].indices[j];
+ const int l_index = gmap->vert_to_loop[v_index].indices[j];
+ BLI_assert(me->mloop[l_index].v == v_index);
+ const MPoly *mp = &me->mpoly[p_index];
+ if (!use_face_sel || mp->flag & ME_FACE_SEL) {
+ Color color_orig = Color(0, 0, 0, 0); /* unused when array is nullptr */
+
+ if (previous_color != nullptr) {
+ /* Get the previous loop color */
+ if (isZero(previous_color[l_index])) {
+ previous_color[l_index] = lcol[l_index];
+ }
+ color_orig = previous_color[l_index];
}
- color_orig = ss->mode.vpaint.previous_color[l_index];
+ const float final_alpha = Traits::frange * brush_fade * brush_strength *
+ tex_alpha * brush_alpha_pressure * grid_alpha;
+
+ /* Mix the new color with the original based on final_alpha. */
+ lcol[l_index] = vpaint_blend<Color, Traits>(vp,
+ lcol[l_index],
+ color_orig,
+ color_final,
+ final_alpha,
+ Traits::range * brush_strength);
}
- /* Mix the new color with the original
- * based on the brush strength and the curve. */
- lcol[l_index] = vpaint_blend(data->vp,
- lcol[l_index],
- color_orig,
- color_final,
- final_alpha,
- 255 * brush_strength);
-
- data->vpd->smear.color_curr[l_index] = lcol[l_index];
}
}
}
}
}
}
+ BKE_pbvh_vertex_iter_end;
}
- BKE_pbvh_vertex_iter_end;
- }
+ });
}
-static void calculate_average_color(SculptThreadedTaskData *data,
- PBVHNode **UNUSED(nodes),
- int totnode)
+template<typename Color, typename Traits, AttributeDomain domain>
+static void vpaint_do_blur(bContext *C,
+ Sculpt *sd,
+ VPaint *vp,
+ VPaintData<Color, Traits, domain> *vpd,
+ Object *ob,
+ Mesh *me,
+ PBVHNode **nodes,
+ int totnode,
+ Color *lcol)
{
- struct VPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
- data->custom_data = accum;
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings);
-
- uint accum_len = 0;
- uint accum_value[3] = {0};
- uchar blend[4] = {0};
- for (int i = 0; i < totnode; i++) {
- accum_len += accum[i].len;
- accum_value[0] += accum[i].value[0];
- accum_value[1] += accum[i].value[1];
- accum_value[2] += accum[i].value[2];
+ if constexpr (domain == ATTR_DOMAIN_POINT) {
+ do_vpaint_brush_blur_verts<Color, Traits>(C, sd, vp, vpd, ob, me, nodes, totnode, lcol);
}
- if (accum_len != 0) {
- blend[0] = round_fl_to_uchar(sqrtf(divide_round_i(accum_value[0], accum_len)));
- blend[1] = round_fl_to_uchar(sqrtf(divide_round_i(accum_value[1], accum_len)));
- blend[2] = round_fl_to_uchar(sqrtf(divide_round_i(accum_value[2], accum_len)));
- blend[3] = 255;
- data->vpd->paintcol = *((uint *)blend);
+ else {
+ do_vpaint_brush_blur_loops<Color, Traits>(C, sd, vp, vpd, ob, me, nodes, totnode, lcol);
}
-
- MEM_SAFE_FREE(data->custom_data); /* 'accum' */
}
+template<typename Color, typename Traits, AttributeDomain domain>
static void vpaint_paint_leaves(bContext *C,
Sculpt *sd,
VPaint *vp,
- struct VPaintData *vpd,
+ VPaintData<Color, Traits, domain> *vpd,
Object *ob,
Mesh *me,
+ Color *lcol,
PBVHNode **nodes,
int totnode)
{
+
+ for (int i : IndexRange(totnode)) {
+ SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_COLOR);
+ }
+
const Brush *brush = ob->sculpt->cache->brush;
- SculptThreadedTaskData data = {
- .C = C,
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .vp = vp,
- .vpd = vpd,
- .lcol = (uint *)me->mloopcol,
- .me = me,
- };
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
switch ((eBrushVertexPaintTool)brush->vertexpaint_tool) {
case VPAINT_TOOL_AVERAGE:
- calculate_average_color(&data, nodes, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
+ calculate_average_color<Color, Traits, domain>(vpd, ob, me, brush, lcol, nodes, totnode);
+ break;
+ case VPAINT_TOOL_DRAW:
+ vpaint_do_draw<Color, Traits, domain>(C, sd, vp, vpd, ob, me, nodes, totnode, lcol);
break;
case VPAINT_TOOL_BLUR:
- BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_blur_task_cb_ex, &settings);
+ vpaint_do_blur<Color, Traits, domain>(C, sd, vp, vpd, ob, me, nodes, totnode, lcol);
break;
case VPAINT_TOOL_SMEAR:
- BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_smear_task_cb_ex, &settings);
+ do_vpaint_brush_smear<Color, Traits, domain>(C, sd, vp, vpd, ob, me, nodes, totnode, lcol);
break;
- case VPAINT_TOOL_DRAW:
- BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
+ default:
break;
}
}
+template<typename Color, typename Traits, AttributeDomain domain>
static void vpaint_do_paint(bContext *C,
Sculpt *sd,
VPaint *vp,
- struct VPaintData *vpd,
+ VPaintData<Color, Traits, domain> *vpd,
Object *ob,
Mesh *me,
Brush *brush,
@@ -3339,18 +3767,22 @@ static void vpaint_do_paint(bContext *C,
int totnode;
PBVHNode **nodes = vwpaint_pbvh_gather_generic(ob, vp, sd, brush, &totnode);
+ CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
+ Color *color_data = static_cast<Color *>(layer->data);
+
/* Paint those leaves. */
- vpaint_paint_leaves(C, sd, vp, vpd, ob, me, nodes, totnode);
+ vpaint_paint_leaves<Color, Traits, domain>(C, sd, vp, vpd, ob, me, color_data, nodes, totnode);
if (nodes) {
MEM_freeN(nodes);
}
}
+template<typename Color, typename Traits, AttributeDomain domain>
static void vpaint_do_radial_symmetry(bContext *C,
Sculpt *sd,
VPaint *vp,
- struct VPaintData *vpd,
+ VPaintData<Color, Traits, domain> *vpd,
Object *ob,
Mesh *me,
Brush *brush,
@@ -3359,17 +3791,18 @@ static void vpaint_do_radial_symmetry(bContext *C,
{
for (int i = 1; i < vp->radial_symm[axis - 'X']; i++) {
const float angle = (2.0 * M_PI) * i / vp->radial_symm[axis - 'X'];
- vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, symm, axis, i, angle);
+ vpaint_do_paint<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, symm, axis, i, angle);
}
}
/* near duplicate of: sculpt.c's,
* 'do_symmetrical_brush_actions' and 'wpaint_do_symmetrical_brush_actions'. */
+template<typename Color, typename Traits, AttributeDomain domain>
static void vpaint_do_symmetrical_brush_actions(
- bContext *C, Sculpt *sd, VPaint *vp, struct VPaintData *vpd, Object *ob)
+ bContext *C, Sculpt *sd, VPaint *vp, VPaintData<Color, Traits, domain> *vpd, Object *ob)
{
Brush *brush = BKE_paint_brush(&vp->paint);
- Mesh *me = ob->data;
+ Mesh *me = (Mesh *)ob->data;
SculptSession *ss = ob->sculpt;
StrokeCache *cache = ss->cache;
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
@@ -3377,10 +3810,10 @@ static void vpaint_do_symmetrical_brush_actions(
/* initial stroke */
cache->mirror_symmetry_pass = 0;
- vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, i, 'X', 0, 0);
- vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'X');
- vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'Y');
- vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'Z');
+ vpaint_do_paint<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'X', 0, 0);
+ vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'X');
+ vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Y');
+ vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Z');
cache->symmetry = symm;
@@ -3393,16 +3826,16 @@ static void vpaint_do_symmetrical_brush_actions(
SCULPT_cache_calc_brushdata_symm(cache, i, 0, 0);
if (i & (1 << 0)) {
- vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, i, 'X', 0, 0);
- vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'X');
+ vpaint_do_paint<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'X', 0, 0);
+ vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'X');
}
if (i & (1 << 1)) {
- vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, i, 'Y', 0, 0);
- vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'Y');
+ vpaint_do_paint<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Y', 0, 0);
+ vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Y');
}
if (i & (1 << 2)) {
- vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, i, 'Z', 0, 0);
- vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, i, 'Z');
+ vpaint_do_paint<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Z', 0, 0);
+ vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Z');
}
}
}
@@ -3411,14 +3844,13 @@ static void vpaint_do_symmetrical_brush_actions(
cache->is_last_valid = true;
}
-static void vpaint_stroke_update_step(bContext *C,
- wmOperator *UNUSED(op),
- struct PaintStroke *stroke,
- PointerRNA *itemptr)
+template<typename Color, typename Traits, AttributeDomain domain>
+static void vpaint_stroke_update_step_intern(bContext *C, PaintStroke *stroke, PointerRNA *itemptr)
{
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = CTX_data_tool_settings(C);
- struct VPaintData *vpd = paint_stroke_mode_data(stroke);
+ VPaintData<Color, Traits, domain> *vpd = static_cast<VPaintData<Color, Traits, domain> *>(
+ paint_stroke_mode_data(stroke));
VPaint *vp = ts->vpaint;
ViewContext *vc = &vpd->vc;
Object *ob = vc->obact;
@@ -3436,15 +3868,20 @@ static void vpaint_stroke_update_step(bContext *C,
swap_m4m4(vc->rv3d->persmat, mat);
- vpaint_do_symmetrical_brush_actions(C, sd, vp, vpd, ob);
+ vpaint_do_symmetrical_brush_actions<Color, Traits, domain>(C, sd, vp, vpd, ob);
swap_m4m4(vc->rv3d->persmat, mat);
- BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ BKE_mesh_batch_cache_dirty_tag((Mesh *)ob->data, BKE_MESH_BATCH_DIRTY_ALL);
if (vp->paint.brush->vertexpaint_tool == VPAINT_TOOL_SMEAR) {
- memcpy(
- vpd->smear.color_prev, vpd->smear.color_curr, sizeof(uint) * ((Mesh *)ob->data)->totloop);
+ Mesh *me = BKE_object_get_original_mesh(ob);
+
+ size_t elem_size;
+ int elem_num;
+
+ elem_num = get_vcol_elements(me, &elem_size);
+ memcpy(vpd->smear.color_prev, vpd->smear.color_curr, elem_size * elem_num);
}
/* Calculate pivot for rotation around selection if needed.
@@ -3458,19 +3895,47 @@ static void vpaint_stroke_update_step(bContext *C,
if (vpd->use_fast_update == false) {
/* recalculate modifier stack to get new colors, slow,
* avoid this if we can! */
- DEG_id_tag_update(ob->data, 0);
+ DEG_id_tag_update((ID *)ob->data, 0);
}
else {
/* Flush changes through DEG. */
- DEG_id_tag_update(ob->data, ID_RECALC_COPY_ON_WRITE);
+ DEG_id_tag_update((ID *)ob->data, ID_RECALC_COPY_ON_WRITE);
}
}
-static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
+static void vpaint_stroke_update_step(bContext *C,
+ wmOperator *UNUSED(op),
+ PaintStroke *stroke,
+ PointerRNA *itemptr)
{
- struct VPaintData *vpd = paint_stroke_mode_data(stroke);
- ViewContext *vc = &vpd->vc;
- Object *ob = vc->obact;
+ VPaintDataBase *vpd = static_cast<VPaintDataBase *>(paint_stroke_mode_data(stroke));
+
+ if (vpd->domain == ATTR_DOMAIN_POINT) {
+ if (vpd->type == CD_PROP_COLOR) {
+ vpaint_stroke_update_step_intern<ColorPaint4f, FloatTraits, ATTR_DOMAIN_POINT>(
+ C, stroke, itemptr);
+ }
+ else if (vpd->type == CD_PROP_BYTE_COLOR) {
+ vpaint_stroke_update_step_intern<ColorPaint4b, ByteTraits, ATTR_DOMAIN_POINT>(
+ C, stroke, itemptr);
+ }
+ }
+ else if (vpd->domain == ATTR_DOMAIN_CORNER) {
+ if (vpd->type == CD_PROP_COLOR) {
+ vpaint_stroke_update_step_intern<ColorPaint4f, FloatTraits, ATTR_DOMAIN_CORNER>(
+ C, stroke, itemptr);
+ }
+ else if (vpd->type == CD_PROP_BYTE_COLOR) {
+ vpaint_stroke_update_step_intern<ColorPaint4b, ByteTraits, ATTR_DOMAIN_CORNER>(
+ C, stroke, itemptr);
+ }
+ }
+}
+
+template<typename Color, typename Traits, AttributeDomain domain>
+static void vpaint_free_vpaintdata(Object *UNUSED(ob), void *_vpd)
+{
+ VPaintData<Color, Traits, domain> *vpd = static_cast<VPaintData<Color, Traits, domain> *>(_vpd);
if (vpd->is_texbrush) {
ED_vpaint_proj_handle_free(vpd->vp_handle);
@@ -3486,6 +3951,34 @@ static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
MEM_freeN(vpd->smear.color_curr);
}
+ MEM_delete<VPaintData<Color, Traits, domain>>(vpd);
+}
+
+static void vpaint_stroke_done(const bContext *C, PaintStroke *stroke)
+{
+ void *vpd_ptr = paint_stroke_mode_data(stroke);
+ VPaintDataBase *vpd = static_cast<VPaintDataBase *>(vpd_ptr);
+
+ ViewContext *vc = &vpd->vc;
+ Object *ob = vc->obact;
+
+ if (vpd->domain == ATTR_DOMAIN_POINT) {
+ if (vpd->type == CD_PROP_COLOR) {
+ vpaint_free_vpaintdata<ColorPaint4f, FloatTraits, ATTR_DOMAIN_POINT>(ob, vpd);
+ }
+ else if (vpd->type == CD_PROP_BYTE_COLOR) {
+ vpaint_free_vpaintdata<ColorPaint4b, ByteTraits, ATTR_DOMAIN_POINT>(ob, vpd);
+ }
+ }
+ else if (vpd->domain == ATTR_DOMAIN_CORNER) {
+ if (vpd->type == CD_PROP_COLOR) {
+ vpaint_free_vpaintdata<ColorPaint4f, FloatTraits, ATTR_DOMAIN_CORNER>(ob, vpd);
+ }
+ else if (vpd->type == CD_PROP_BYTE_COLOR) {
+ vpaint_free_vpaintdata<ColorPaint4b, ByteTraits, ATTR_DOMAIN_CORNER>(ob, vpd);
+ }
+ }
+
SculptSession *ss = ob->sculpt;
if (ss->cache->alt_smooth) {
@@ -3496,10 +3989,10 @@ static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
- MEM_freeN(vpd);
+ SCULPT_undo_push_end(ob);
SCULPT_cache_free(ob->sculpt->cache);
- ob->sculpt->cache = NULL;
+ ob->sculpt->cache = nullptr;
}
static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -3511,12 +4004,20 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
SCULPT_stroke_get_location,
vpaint_stroke_test_start,
vpaint_stroke_update_step,
- NULL,
+ nullptr,
vpaint_stroke_done,
event->type);
+ Object *ob = CTX_data_active_object(C);
+
+ if (SCULPT_has_loop_colors(ob) && ob->sculpt->pbvh) {
+ BKE_pbvh_ensure_node_loops(ob->sculpt->pbvh);
+ }
+
+ SCULPT_undo_push_begin(ob, "Vertex Paint");
+
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_free(C, op, op->customdata);
+ paint_stroke_free(C, op, (PaintStroke *)op->customdata);
return OPERATOR_FINISHED;
}
@@ -3536,12 +4037,12 @@ static int vpaint_exec(bContext *C, wmOperator *op)
SCULPT_stroke_get_location,
vpaint_stroke_test_start,
vpaint_stroke_update_step,
- NULL,
+ nullptr,
vpaint_stroke_done,
0);
/* frees op->customdata */
- paint_stroke_exec(C, op, op->customdata);
+ paint_stroke_exec(C, op, (PaintStroke *)op->customdata);
return OPERATOR_FINISHED;
}
@@ -3551,15 +4052,15 @@ static void vpaint_cancel(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
if (ob->sculpt->cache) {
SCULPT_cache_free(ob->sculpt->cache);
- ob->sculpt->cache = NULL;
+ ob->sculpt->cache = nullptr;
}
- paint_stroke_cancel(C, op, op->customdata);
+ paint_stroke_cancel(C, op, (PaintStroke *)op->customdata);
}
static int vpaint_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- return paint_stroke_modal(C, op, event, (struct PaintStroke **)&op->customdata);
+ return paint_stroke_modal(C, op, event, (PaintStroke **)&op->customdata);
}
void PAINT_OT_vertex_paint(wmOperatorType *ot)
@@ -3582,4 +4083,113 @@ void PAINT_OT_vertex_paint(wmOperatorType *ot)
paint_stroke_operator_properties(ot);
}
+/* -------------------------------------------------------------------- */
+/** \name Set Vertex Colors Operator
+ * \{ */
+
+template<typename Color, typename Traits, AttributeDomain domain>
+static bool vertex_color_set(Object *ob, ColorPaint4f paintcol_in, Color *color_layer)
+{
+ Mesh *me;
+ if (((me = BKE_mesh_from_object(ob)) == nullptr) ||
+ (ED_mesh_color_ensure(me, nullptr) == false)) {
+ return false;
+ }
+
+ Color paintcol = fromFloat<Color>(paintcol_in);
+
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+
+ const MPoly *mp = me->mpoly;
+ for (int i = 0; i < me->totpoly; i++, mp++) {
+ if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
+ continue;
+ }
+
+ int j = 0;
+ do {
+ uint vidx = me->mloop[mp->loopstart + j].v;
+
+ if (!(use_vert_sel && !(me->mvert[vidx].flag & SELECT))) {
+ if constexpr (domain == ATTR_DOMAIN_CORNER) {
+ color_layer[mp->loopstart + j] = paintcol;
+ }
+ else {
+ color_layer[vidx] = paintcol;
+ }
+ }
+ j++;
+ } while (j < mp->totloop);
+ }
+
+ /* remove stale me->mcol, will be added later */
+ BKE_mesh_tessface_clear(me);
+
+ DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE);
+
+ /* NOTE: Original mesh is used for display, so tag it directly here. */
+ BKE_mesh_batch_cache_dirty_tag(me, BKE_MESH_BATCH_DIRTY_ALL);
+
+ return true;
+}
+
+static int vertex_color_set_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *obact = CTX_data_active_object(C);
+ Mesh *me = BKE_object_get_original_mesh(obact);
+
+ // uint paintcol = vpaint_get_current_color(scene, scene->toolsettings->vpaint, false);
+ ColorPaint4f paintcol = vpaint_get_current_col<ColorPaint4f, FloatTraits, ATTR_DOMAIN_POINT>(
+ scene, scene->toolsettings->vpaint, false);
+
+ bool ok = false;
+
+ CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
+ AttributeDomain domain = BKE_id_attribute_domain(&me->id, layer);
+
+ if (domain == ATTR_DOMAIN_POINT) {
+ if (layer->type == CD_PROP_COLOR) {
+ ok = vertex_color_set<ColorPaint4f, FloatTraits, ATTR_DOMAIN_POINT>(
+ obact, paintcol, static_cast<ColorPaint4f *>(layer->data));
+ }
+ else if (layer->type == CD_PROP_BYTE_COLOR) {
+ ok = vertex_color_set<ColorPaint4b, ByteTraits, ATTR_DOMAIN_POINT>(
+ obact, paintcol, static_cast<ColorPaint4b *>(layer->data));
+ }
+ }
+ else {
+ if (layer->type == CD_PROP_COLOR) {
+ ok = vertex_color_set<ColorPaint4f, FloatTraits, ATTR_DOMAIN_CORNER>(
+ obact, paintcol, static_cast<ColorPaint4f *>(layer->data));
+ }
+ else if (layer->type == CD_PROP_BYTE_COLOR) {
+ ok = vertex_color_set<ColorPaint4b, ByteTraits, ATTR_DOMAIN_CORNER>(
+ obact, paintcol, static_cast<ColorPaint4b *>(layer->data));
+ }
+ }
+
+ if (ok) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+ return OPERATOR_FINISHED;
+ }
+ return OPERATOR_CANCELLED;
+}
+
+void PAINT_OT_vertex_color_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Vertex Colors";
+ ot->idname = "PAINT_OT_vertex_color_set";
+ ot->description = "Fill the active vertex color layer with the current paint color";
+
+ /* api callbacks */
+ ot->exec = vertex_color_set_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
index 619607408e5..9f337d8d789 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
@@ -47,75 +47,6 @@ static void tag_object_after_update(Object *object)
BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL);
}
-/* -------------------------------------------------------------------- */
-/** \name Set Vertex Colors Operator
- * \{ */
-
-static bool vertex_color_set(Object *ob, uint paintcol)
-{
- Mesh *me;
- if (((me = BKE_mesh_from_object(ob)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) {
- return false;
- }
-
- const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
-
- const MPoly *mp = me->mpoly;
- for (int i = 0; i < me->totpoly; i++, mp++) {
- MLoopCol *lcol = me->mloopcol + mp->loopstart;
-
- if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
- continue;
- }
-
- int j = 0;
- do {
- uint vidx = me->mloop[mp->loopstart + j].v;
- if (!(use_vert_sel && !(me->mvert[vidx].flag & SELECT))) {
- *(int *)lcol = paintcol;
- }
- lcol++;
- j++;
- } while (j < mp->totloop);
- }
-
- /* remove stale me->mcol, will be added later */
- BKE_mesh_tessface_clear(me);
-
- tag_object_after_update(ob);
-
- return true;
-}
-
-static int vertex_color_set_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Scene *scene = CTX_data_scene(C);
- Object *obact = CTX_data_active_object(C);
- uint paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint, false);
-
- if (vertex_color_set(obact, paintcol)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
-}
-
-void PAINT_OT_vertex_color_set(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Set Vertex Colors";
- ot->idname = "PAINT_OT_vertex_color_set";
- ot->description = "Fill the active vertex color layer with the current paint color";
-
- /* api callbacks */
- ot->exec = vertex_color_set_exec;
- ot->poll = vertex_paint_mode_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
index 8d5f39fd56e..cd099f71ccd 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
@@ -73,570 +73,3 @@ bool ED_vpaint_color_transform(struct Object *ob,
return true;
}
-
-/* -------------------------------------------------------------------- */
-/** \name Color Blending Modes
- * \{ */
-
-BLI_INLINE uint mcol_blend(uint col_src, uint col_dst, int fac)
-{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- if (fac >= 255) {
- return col_dst;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- /* Updated to use the rgb squared color model which blends nicer. */
- int r1 = cp_src[0] * cp_src[0];
- int g1 = cp_src[1] * cp_src[1];
- int b1 = cp_src[2] * cp_src[2];
- int a1 = cp_src[3] * cp_src[3];
-
- int r2 = cp_dst[0] * cp_dst[0];
- int g2 = cp_dst[1] * cp_dst[1];
- int b2 = cp_dst[2] * cp_dst[2];
- int a2 = cp_dst[3] * cp_dst[3];
-
- cp_mix[0] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * r1 + fac * r2), 255)));
- cp_mix[1] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * g1 + fac * g2), 255)));
- cp_mix[2] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * b1 + fac * b2), 255)));
- cp_mix[3] = round_fl_to_uchar(sqrtf(divide_round_i((mfac * a1 + fac * a2), 255)));
-
- return col_mix;
-}
-
-BLI_INLINE uint mcol_add(uint col_src, uint col_dst, int fac)
-{
- uchar *cp_src, *cp_dst, *cp_mix;
- int temp;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- temp = cp_src[0] + divide_round_i((fac * cp_dst[0]), 255);
- cp_mix[0] = (temp > 254) ? 255 : temp;
- temp = cp_src[1] + divide_round_i((fac * cp_dst[1]), 255);
- cp_mix[1] = (temp > 254) ? 255 : temp;
- temp = cp_src[2] + divide_round_i((fac * cp_dst[2]), 255);
- cp_mix[2] = (temp > 254) ? 255 : temp;
- temp = cp_src[3] + divide_round_i((fac * cp_dst[3]), 255);
- cp_mix[3] = (temp > 254) ? 255 : temp;
-
- return col_mix;
-}
-
-BLI_INLINE uint mcol_sub(uint col_src, uint col_dst, int fac)
-{
- uchar *cp_src, *cp_dst, *cp_mix;
- int temp;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- temp = cp_src[0] - divide_round_i((fac * cp_dst[0]), 255);
- cp_mix[0] = (temp < 0) ? 0 : temp;
- temp = cp_src[1] - divide_round_i((fac * cp_dst[1]), 255);
- cp_mix[1] = (temp < 0) ? 0 : temp;
- temp = cp_src[2] - divide_round_i((fac * cp_dst[2]), 255);
- cp_mix[2] = (temp < 0) ? 0 : temp;
- temp = cp_src[3] - divide_round_i((fac * cp_dst[3]), 255);
- cp_mix[3] = (temp < 0) ? 0 : temp;
-
- return col_mix;
-}
-
-BLI_INLINE uint mcol_mul(uint col_src, uint col_dst, int fac)
-{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- /* first mul, then blend the fac */
- cp_mix[0] = divide_round_i(mfac * cp_src[0] * 255 + fac * cp_dst[0] * cp_src[0], 255 * 255);
- cp_mix[1] = divide_round_i(mfac * cp_src[1] * 255 + fac * cp_dst[1] * cp_src[1], 255 * 255);
- cp_mix[2] = divide_round_i(mfac * cp_src[2] * 255 + fac * cp_dst[2] * cp_src[2], 255 * 255);
- cp_mix[3] = divide_round_i(mfac * cp_src[3] * 255 + fac * cp_dst[3] * cp_src[3], 255 * 255);
-
- return col_mix;
-}
-
-BLI_INLINE uint mcol_lighten(uint col_src, uint col_dst, int fac)
-{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
- if (fac >= 255) {
- return col_dst;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- /* See if we're lighter, if so mix, else don't do anything.
- * if the paint color is darker then the original, then ignore */
- if (IMB_colormanagement_get_luminance_byte(cp_src) >
- IMB_colormanagement_get_luminance_byte(cp_dst)) {
- return col_src;
- }
-
- cp_mix[0] = divide_round_i(mfac * cp_src[0] + fac * cp_dst[0], 255);
- cp_mix[1] = divide_round_i(mfac * cp_src[1] + fac * cp_dst[1], 255);
- cp_mix[2] = divide_round_i(mfac * cp_src[2] + fac * cp_dst[2], 255);
- cp_mix[3] = divide_round_i(mfac * cp_src[3] + fac * cp_dst[3], 255);
-
- return col_mix;
-}
-
-BLI_INLINE uint mcol_darken(uint col_src, uint col_dst, int fac)
-{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
- if (fac >= 255) {
- return col_dst;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- /* See if we're darker, if so mix, else don't do anything.
- * if the paint color is brighter then the original, then ignore */
- if (IMB_colormanagement_get_luminance_byte(cp_src) <
- IMB_colormanagement_get_luminance_byte(cp_dst)) {
- return col_src;
- }
-
- cp_mix[0] = divide_round_i((mfac * cp_src[0] + fac * cp_dst[0]), 255);
- cp_mix[1] = divide_round_i((mfac * cp_src[1] + fac * cp_dst[1]), 255);
- cp_mix[2] = divide_round_i((mfac * cp_src[2] + fac * cp_dst[2]), 255);
- cp_mix[3] = divide_round_i((mfac * cp_src[3] + fac * cp_dst[3]), 255);
- return col_mix;
-}
-
-BLI_INLINE uint mcol_colordodge(uint col_src, uint col_dst, int fac)
-{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac, temp;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- temp = (cp_dst[0] == 255) ? 255 : min_ii((cp_src[0] * 225) / (255 - cp_dst[0]), 255);
- cp_mix[0] = (mfac * cp_src[0] + temp * fac) / 255;
- temp = (cp_dst[1] == 255) ? 255 : min_ii((cp_src[1] * 225) / (255 - cp_dst[1]), 255);
- cp_mix[1] = (mfac * cp_src[1] + temp * fac) / 255;
- temp = (cp_dst[2] == 255) ? 255 : min_ii((cp_src[2] * 225) / (255 - cp_dst[2]), 255);
- cp_mix[2] = (mfac * cp_src[2] + temp * fac) / 255;
- temp = (cp_dst[3] == 255) ? 255 : min_ii((cp_src[3] * 225) / (255 - cp_dst[3]), 255);
- cp_mix[3] = (mfac * cp_src[3] + temp * fac) / 255;
- return col_mix;
-}
-
-BLI_INLINE uint mcol_difference(uint col_src, uint col_dst, int fac)
-{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac, temp;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- temp = abs(cp_src[0] - cp_dst[0]);
- cp_mix[0] = (mfac * cp_src[0] + temp * fac) / 255;
- temp = abs(cp_src[1] - cp_dst[1]);
- cp_mix[1] = (mfac * cp_src[1] + temp * fac) / 255;
- temp = abs(cp_src[2] - cp_dst[2]);
- cp_mix[2] = (mfac * cp_src[2] + temp * fac) / 255;
- temp = abs(cp_src[3] - cp_dst[3]);
- cp_mix[3] = (mfac * cp_src[3] + temp * fac) / 255;
- return col_mix;
-}
-
-BLI_INLINE uint mcol_screen(uint col_src, uint col_dst, int fac)
-{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac, temp;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- temp = max_ii(255 - (((255 - cp_src[0]) * (255 - cp_dst[0])) / 255), 0);
- cp_mix[0] = (mfac * cp_src[0] + temp * fac) / 255;
- temp = max_ii(255 - (((255 - cp_src[1]) * (255 - cp_dst[1])) / 255), 0);
- cp_mix[1] = (mfac * cp_src[1] + temp * fac) / 255;
- temp = max_ii(255 - (((255 - cp_src[2]) * (255 - cp_dst[2])) / 255), 0);
- cp_mix[2] = (mfac * cp_src[2] + temp * fac) / 255;
- temp = max_ii(255 - (((255 - cp_src[3]) * (255 - cp_dst[3])) / 255), 0);
- cp_mix[3] = (mfac * cp_src[3] + temp * fac) / 255;
- return col_mix;
-}
-
-BLI_INLINE uint mcol_hardlight(uint col_src, uint col_dst, int fac)
-{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac, temp;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- int i = 0;
-
- for (i = 0; i < 4; i++) {
- if (cp_dst[i] > 127) {
- temp = 255 - ((255 - 2 * (cp_dst[i] - 127)) * (255 - cp_src[i]) / 255);
- }
- else {
- temp = (2 * cp_dst[i] * cp_src[i]) >> 8;
- }
- cp_mix[i] = min_ii((mfac * cp_src[i] + temp * fac) / 255, 255);
- }
- return col_mix;
-}
-
-BLI_INLINE uint mcol_overlay(uint col_src, uint col_dst, int fac)
-{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac, temp;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- int i = 0;
-
- for (i = 0; i < 4; i++) {
- if (cp_src[i] > 127) {
- temp = 255 - ((255 - 2 * (cp_src[i] - 127)) * (255 - cp_dst[i]) / 255);
- }
- else {
- temp = (2 * cp_dst[i] * cp_src[i]) >> 8;
- }
- cp_mix[i] = min_ii((mfac * cp_src[i] + temp * fac) / 255, 255);
- }
- return col_mix;
-}
-
-BLI_INLINE uint mcol_softlight(uint col_src, uint col_dst, int fac)
-{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac, temp;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- for (int i = 0; i < 4; i++) {
- if (cp_src[i] < 127) {
- temp = ((2 * ((cp_dst[i] / 2) + 64)) * cp_src[i]) / 255;
- }
- else {
- temp = 255 - (2 * (255 - ((cp_dst[i] / 2) + 64)) * (255 - cp_src[i]) / 255);
- }
- cp_mix[i] = (temp * fac + cp_src[i] * mfac) / 255;
- }
- return col_mix;
-}
-
-BLI_INLINE uint mcol_exclusion(uint col_src, uint col_dst, int fac)
-{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac, temp;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- int i = 0;
-
- for (i = 0; i < 4; i++) {
- temp = 127 - ((2 * (cp_src[i] - 127) * (cp_dst[i] - 127)) / 255);
- cp_mix[i] = (temp * fac + cp_src[i] * mfac) / 255;
- }
- return col_mix;
-}
-
-BLI_INLINE uint mcol_luminosity(uint col_src, uint col_dst, int fac)
-{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- float h1, s1, v1;
- float h2, s2, v2;
- float r, g, b;
- rgb_to_hsv(cp_src[0] / 255.0f, cp_src[1] / 255.0f, cp_src[2] / 255.0f, &h1, &s1, &v1);
- rgb_to_hsv(cp_dst[0] / 255.0f, cp_dst[1] / 255.0f, cp_dst[2] / 255.0f, &h2, &s2, &v2);
-
- v1 = v2;
-
- hsv_to_rgb(h1, s1, v1, &r, &g, &b);
-
- cp_mix[0] = ((int)(r * 255.0f) * fac + mfac * cp_src[0]) / 255;
- cp_mix[1] = ((int)(g * 255.0f) * fac + mfac * cp_src[1]) / 255;
- cp_mix[2] = ((int)(b * 255.0f) * fac + mfac * cp_src[2]) / 255;
- cp_mix[3] = ((int)(cp_dst[3]) * fac + mfac * cp_src[3]) / 255;
- return col_mix;
-}
-
-BLI_INLINE uint mcol_saturation(uint col_src, uint col_dst, int fac)
-{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- float h1, s1, v1;
- float h2, s2, v2;
- float r, g, b;
- rgb_to_hsv(cp_src[0] / 255.0f, cp_src[1] / 255.0f, cp_src[2] / 255.0f, &h1, &s1, &v1);
- rgb_to_hsv(cp_dst[0] / 255.0f, cp_dst[1] / 255.0f, cp_dst[2] / 255.0f, &h2, &s2, &v2);
-
- if (s1 > EPS_SATURATION) {
- s1 = s2;
- }
-
- hsv_to_rgb(h1, s1, v1, &r, &g, &b);
-
- cp_mix[0] = ((int)(r * 255.0f) * fac + mfac * cp_src[0]) / 255;
- cp_mix[1] = ((int)(g * 255.0f) * fac + mfac * cp_src[1]) / 255;
- cp_mix[2] = ((int)(b * 255.0f) * fac + mfac * cp_src[2]) / 255;
- return col_mix;
-}
-
-BLI_INLINE uint mcol_hue(uint col_src, uint col_dst, int fac)
-{
- uchar *cp_src, *cp_dst, *cp_mix;
- int mfac;
- uint col_mix = 0;
-
- if (fac == 0) {
- return col_src;
- }
-
- mfac = 255 - fac;
-
- cp_src = (uchar *)&col_src;
- cp_dst = (uchar *)&col_dst;
- cp_mix = (uchar *)&col_mix;
-
- float h1, s1, v1;
- float h2, s2, v2;
- float r, g, b;
- rgb_to_hsv(cp_src[0] / 255.0f, cp_src[1] / 255.0f, cp_src[2] / 255.0f, &h1, &s1, &v1);
- rgb_to_hsv(cp_dst[0] / 255.0f, cp_dst[1] / 255.0f, cp_dst[2] / 255.0f, &h2, &s2, &v2);
-
- h1 = h2;
-
- hsv_to_rgb(h1, s1, v1, &r, &g, &b);
-
- cp_mix[0] = ((int)(r * 255.0f) * fac + mfac * cp_src[0]) / 255;
- cp_mix[1] = ((int)(g * 255.0f) * fac + mfac * cp_src[1]) / 255;
- cp_mix[2] = ((int)(b * 255.0f) * fac + mfac * cp_src[2]) / 255;
- cp_mix[3] = ((int)(cp_dst[3]) * fac + mfac * cp_src[3]) / 255;
- return col_mix;
-}
-
-BLI_INLINE uint mcol_alpha_add(uint col_src, int fac)
-{
- uchar *cp_src, *cp_mix;
- int temp;
- uint col_mix = col_src;
-
- if (fac == 0) {
- return col_src;
- }
-
- cp_src = (uchar *)&col_src;
- cp_mix = (uchar *)&col_mix;
-
- temp = cp_src[3] + fac;
- cp_mix[3] = (temp > 254) ? 255 : temp;
-
- return col_mix;
-}
-
-BLI_INLINE uint mcol_alpha_sub(uint col_src, int fac)
-{
- uchar *cp_src, *cp_mix;
- int temp;
- uint col_mix = col_src;
-
- if (fac == 0) {
- return col_src;
- }
-
- cp_src = (uchar *)&col_src;
- cp_mix = (uchar *)&col_mix;
-
- temp = cp_src[3] - fac;
- cp_mix[3] = temp < 0 ? 0 : temp;
-
- return col_mix;
-}
-
-uint ED_vpaint_blend_tool(const int tool, const uint col, const uint paintcol, const int alpha_i)
-{
- switch ((IMB_BlendMode)tool) {
- case IMB_BLEND_MIX:
- return mcol_blend(col, paintcol, alpha_i);
- case IMB_BLEND_ADD:
- return mcol_add(col, paintcol, alpha_i);
- case IMB_BLEND_SUB:
- return mcol_sub(col, paintcol, alpha_i);
- case IMB_BLEND_MUL:
- return mcol_mul(col, paintcol, alpha_i);
- case IMB_BLEND_LIGHTEN:
- return mcol_lighten(col, paintcol, alpha_i);
- case IMB_BLEND_DARKEN:
- return mcol_darken(col, paintcol, alpha_i);
- case IMB_BLEND_COLORDODGE:
- return mcol_colordodge(col, paintcol, alpha_i);
- case IMB_BLEND_DIFFERENCE:
- return mcol_difference(col, paintcol, alpha_i);
- case IMB_BLEND_SCREEN:
- return mcol_screen(col, paintcol, alpha_i);
- case IMB_BLEND_HARDLIGHT:
- return mcol_hardlight(col, paintcol, alpha_i);
- case IMB_BLEND_OVERLAY:
- return mcol_overlay(col, paintcol, alpha_i);
- case IMB_BLEND_SOFTLIGHT:
- return mcol_softlight(col, paintcol, alpha_i);
- case IMB_BLEND_EXCLUSION:
- return mcol_exclusion(col, paintcol, alpha_i);
- case IMB_BLEND_LUMINOSITY:
- return mcol_luminosity(col, paintcol, alpha_i);
- case IMB_BLEND_SATURATION:
- return mcol_saturation(col, paintcol, alpha_i);
- case IMB_BLEND_HUE:
- return mcol_hue(col, paintcol, alpha_i);
- /* non-color */
- case IMB_BLEND_ERASE_ALPHA:
- return mcol_alpha_sub(col, alpha_i);
- case IMB_BLEND_ADD_ALPHA:
- return mcol_alpha_add(col, alpha_i);
- default:
- BLI_assert(0);
- return 0;
- }
-}
-
-/** \} */
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index bbbed32e316..93a60b9908e 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -2780,7 +2780,7 @@ static void sculpt_pbvh_update_pixels(PaintModeSettings *paint_mode_settings,
return;
}
- BKE_pbvh_build_pixels(ss->pbvh, mesh->mloop, &mesh->ldata, image, image_user);
+ BKE_pbvh_build_pixels(ss->pbvh, mesh, image, image_user);
}
/** \} */
@@ -3097,8 +3097,7 @@ void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
for (a = 0; a < me->totvert; a++, mvert++) {
copy_v3_v3(mvert->co, vertCos[a]);
}
-
- BKE_mesh_calc_normals(me);
+ BKE_mesh_normals_tag_dirty(me);
}
/* Apply new coords on active key block, no need to re-allocate kb->data here! */
@@ -3915,16 +3914,6 @@ bool SCULPT_mode_poll(bContext *C)
return ob && ob->mode & OB_MODE_SCULPT;
}
-bool SCULPT_vertex_colors_poll(bContext *C)
-{
- if (!SCULPT_mode_poll(C)) {
- return false;
- }
-
- Object *ob = CTX_data_active_object(C);
- return ob->sculpt && SCULPT_has_colors(ob->sculpt);
-}
-
bool SCULPT_mode_poll_view3d(bContext *C)
{
return (SCULPT_mode_poll(C) && CTX_wm_region_view3d(C));
@@ -4026,6 +4015,7 @@ void SCULPT_cache_free(StrokeCache *cache)
MEM_SAFE_FREE(cache->detail_directions);
MEM_SAFE_FREE(cache->prev_displacement);
MEM_SAFE_FREE(cache->limit_surface_co);
+ MEM_SAFE_FREE(cache->prev_colors_vpaint);
if (cache->pose_ik_chain) {
SCULPT_pose_ik_chain_free(cache->pose_ik_chain);
@@ -5256,6 +5246,24 @@ static bool over_mesh(bContext *C, struct wmOperator *UNUSED(op), float x, float
return SCULPT_stroke_get_location(C, co, mouse);
}
+bool SCULPT_handles_colors_report(SculptSession *ss, ReportList *reports)
+{
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES:
+ return true;
+ case PBVH_BMESH:
+ BKE_report(reports, RPT_ERROR, "Not supported in dynamic topology mode");
+ return false;
+ case PBVH_GRIDS:
+ BKE_report(reports, RPT_ERROR, "Not supported in multiresolution mode");
+ return false;
+ }
+
+ BLI_assert_msg(0, "PBVH corruption, type was invalid.");
+
+ return false;
+}
+
static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const float mouse[2])
{
/* Don't start the stroke until mouse goes over the mesh.
@@ -5438,6 +5446,12 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent
sculpt_brush_stroke_init(C, op);
+ Object *ob = CTX_data_active_object(C);
+
+ if (!SCULPT_handles_colors_report(ob->sculpt, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+
stroke = paint_stroke_new(C,
op,
SCULPT_stroke_get_location,
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
index 5d4a2c54832..a705f6aa8a8 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
@@ -24,6 +24,7 @@
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
+#include "BKE_report.h"
#include "BKE_scene.h"
#include "IMB_colormanagement.h"
@@ -342,10 +343,7 @@ static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent
}
/* Disable for multires and dyntopo for now */
- if (!ss->pbvh) {
- return OPERATOR_CANCELLED;
- }
- if (BKE_pbvh_type(pbvh) != PBVH_FACES) {
+ if (!ss->pbvh || !SCULPT_handles_colors_report(ss, op->reports)) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 3839c0e71e4..f13f1c79a7a 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -219,7 +219,6 @@ typedef struct SculptThreadedTaskData {
int totnode;
struct VPaint *vp;
- struct VPaintData *vpd;
struct WPaintData *wpd;
struct WeightPaintInfo *wpi;
unsigned int *lcol;
@@ -493,6 +492,7 @@ typedef struct StrokeCache {
float mouse_event[2];
float (*prev_colors)[4];
+ void *prev_colors_vpaint;
/* Multires Displacement Smear. */
float (*prev_displacement)[3];
@@ -782,7 +782,17 @@ bool SCULPT_mode_poll_view3d(struct bContext *C);
bool SCULPT_poll(struct bContext *C);
bool SCULPT_poll_view3d(struct bContext *C);
-bool SCULPT_vertex_colors_poll(struct bContext *C);
+/**
+ * Returns true if sculpt session can handle color attributes
+ * (BKE_pbvh_type(ss->pbvh) == PBVH_FACES). If false an error
+ * message will be shown to the user. Operators should return
+ * OPERATOR_CANCELLED in this case.
+ *
+ * NOTE: Does not check if a color attribute actually exists.
+ * Calling code must handle this itself; in most cases a call to
+ * BKE_sculpt_color_layer_create_if_needed() is sufficient.
+ */
+bool SCULPT_handles_colors_report(struct SculptSession *ss, struct ReportList *reports);
/** \} */
diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c
index 9581bf2071c..e02c1b1aac3 100644
--- a/source/blender/editors/sculpt_paint/sculpt_ops.c
+++ b/source/blender/editors/sculpt_paint/sculpt_ops.c
@@ -245,7 +245,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
BKE_mesh_mirror_apply_mirror_on_axis(bmain, mesh, sd->symmetrize_direction, dist);
ED_sculpt_undo_geometry_end(ob);
- BKE_mesh_calc_normals(ob->data);
+ BKE_mesh_normals_tag_dirty(mesh);
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
break;
@@ -627,11 +627,11 @@ static int vertex_to_loop_colors_exec(bContext *C, wmOperator *UNUSED(op))
Mesh *mesh = ob->data;
- const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL);
+ const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_PROP_BYTE_COLOR);
if (mloopcol_layer_n == -1) {
return OPERATOR_CANCELLED;
}
- MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n);
+ MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_PROP_BYTE_COLOR, mloopcol_layer_n);
const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
if (MPropCol_layer_n == -1) {
@@ -662,6 +662,21 @@ static int vertex_to_loop_colors_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
+static bool sculpt_colors_poll(bContext *C)
+{
+ if (!SCULPT_mode_poll(C)) {
+ return false;
+ }
+
+ Object *ob = CTX_data_active_object(C);
+
+ if (!ob->sculpt || !ob->sculpt->pbvh || BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_FACES) {
+ return false;
+ }
+
+ return SCULPT_has_colors(ob->sculpt);
+}
+
static void SCULPT_OT_vertex_to_loop_colors(wmOperatorType *ot)
{
/* identifiers */
@@ -670,7 +685,7 @@ static void SCULPT_OT_vertex_to_loop_colors(wmOperatorType *ot)
ot->idname = "SCULPT_OT_vertex_to_loop_colors";
/* api callbacks */
- ot->poll = SCULPT_vertex_colors_poll;
+ ot->poll = sculpt_colors_poll;
ot->exec = vertex_to_loop_colors_exec;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -692,11 +707,11 @@ static int loop_to_vertex_colors_exec(bContext *C, wmOperator *UNUSED(op))
Mesh *mesh = ob->data;
- const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL);
+ const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_PROP_BYTE_COLOR);
if (mloopcol_layer_n == -1) {
return OPERATOR_CANCELLED;
}
- MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n);
+ MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_PROP_BYTE_COLOR, mloopcol_layer_n);
const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
if (MPropCol_layer_n == -1) {
@@ -734,15 +749,13 @@ static void SCULPT_OT_loop_to_vertex_colors(wmOperatorType *ot)
ot->idname = "SCULPT_OT_loop_to_vertex_colors";
/* api callbacks */
- ot->poll = SCULPT_vertex_colors_poll;
+ ot->poll = sculpt_colors_poll;
ot->exec = loop_to_vertex_colors_exec;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static int sculpt_sample_color_invoke(bContext *C,
- wmOperator *UNUSED(op),
- const wmEvent *UNUSED(e))
+static int sculpt_sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e))
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Scene *scene = CTX_data_scene(C);
@@ -752,11 +765,17 @@ static int sculpt_sample_color_invoke(bContext *C,
int active_vertex = SCULPT_active_vertex_get(ss);
float active_vertex_color[4];
- if (!SCULPT_has_colors(ss)) {
+ if (!SCULPT_handles_colors_report(ss, op->reports)) {
return OPERATOR_CANCELLED;
}
- SCULPT_vertex_color_get(ss, active_vertex, active_vertex_color);
+ /* No color attribute? Set color to white. */
+ if (!SCULPT_has_colors(ss)) {
+ copy_v4_fl(active_vertex_color, 1.0f);
+ }
+ else {
+ SCULPT_vertex_color_get(ss, active_vertex, active_vertex_color);
+ }
float color_srgb[3];
copy_v3_v3(color_srgb, active_vertex_color);
@@ -777,7 +796,7 @@ static void SCULPT_OT_sample_color(wmOperatorType *ot)
/* api callbacks */
ot->invoke = sculpt_sample_color_invoke;
- ot->poll = SCULPT_vertex_colors_poll;
+ ot->poll = SCULPT_mode_poll;
ot->flag = OPTYPE_REGISTER;
}
@@ -1025,8 +1044,8 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
- /* Color data is not available in Multires. */
- if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
+ /* Color data is not available in multi-resolution or dynamic topology. */
+ if (!SCULPT_handles_colors_report(ss, op->reports)) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
index 1fc7551f545..df1ccc0fbe9 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
@@ -330,7 +330,7 @@ static void do_paint_pixels(void *__restrict userdata,
kernel_float4.init_brush_color(image_buffer);
}
else {
- kernel_float4.init_brush_color(image_buffer);
+ kernel_byte4.init_brush_color(image_buffer);
}
for (const PackedPixelRow &pixel_row : tile_data.pixel_rows) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index eae90359dfd..5867dc558de 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -854,7 +854,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
if (tag_update) {
Mesh *mesh = ob->data;
- BKE_mesh_calc_normals(mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
BKE_sculptsession_free_deformMats(ss);
}
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index eda9f89b51c..80efaf4ed9f 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -744,7 +744,7 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
for (strip = nlt->strips.first, index = 1; strip; strip = strip->next, index++) {
if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) {
const float xminc = strip->start + text_margin_x;
- const float xmaxc = strip->end + text_margin_x;
+ const float xmaxc = strip->end - text_margin_x;
/* draw the visualization of the strip */
nla_draw_strip(snla, adt, nlt, strip, v2d, ymin, ymax);
diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc
index 2536496b50d..fee64da0459 100644
--- a/source/blender/editors/space_node/node_geometry_attribute_search.cc
+++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc
@@ -135,7 +135,7 @@ static CustomDataType data_type_in_attribute_input_node(const CustomDataType typ
case CD_PROP_COLOR:
case CD_PROP_BOOL:
return type;
- case CD_MLOOPCOL:
+ case CD_PROP_BYTE_COLOR:
return CD_PROP_COLOR;
case CD_PROP_STRING:
/* Unsupported currently. */
diff --git a/source/blender/editors/space_node/node_view.cc b/source/blender/editors/space_node/node_view.cc
index f5f5a9e6f67..91a21527ac9 100644
--- a/source/blender/editors/space_node/node_view.cc
+++ b/source/blender/editors/space_node/node_view.cc
@@ -179,6 +179,8 @@ void NODE_OT_view_selected(wmOperatorType *ot)
struct NodeViewMove {
int mvalo[2];
int xmin, ymin, xmax, ymax;
+ /** Original Offset for cancel. */
+ float xof_orig, yof_orig;
};
static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event)
@@ -207,13 +209,24 @@ static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, const wmEvent *e
case LEFTMOUSE:
case MIDDLEMOUSE:
- case RIGHTMOUSE:
if (event->val == KM_RELEASE) {
MEM_freeN(nvm);
op->customdata = nullptr;
return OPERATOR_FINISHED;
}
break;
+ case EVT_ESCKEY:
+ case RIGHTMOUSE:
+ snode->xof = nvm->xof_orig;
+ snode->yof = nvm->yof_orig;
+ ED_region_tag_redraw(region);
+ WM_main_add_notifier(NC_NODE | ND_DISPLAY, nullptr);
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_NODE_VIEW, nullptr);
+
+ MEM_freeN(nvm);
+ op->customdata = nullptr;
+
+ return OPERATOR_CANCELLED;
}
return OPERATOR_RUNNING_MODAL;
@@ -249,6 +262,9 @@ static int snode_bg_viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *
nvm->ymin = -(region->winy / 2) - (ibuf->y * (0.5f * snode->zoom)) + pad;
nvm->ymax = (region->winy / 2) + (ibuf->y * (0.5f * snode->zoom)) - pad;
+ nvm->xof_orig = snode->xof;
+ nvm->yof_orig = snode->yof;
+
BKE_image_release_ibuf(ima, ibuf, lock);
/* add modal handler */
diff --git a/source/blender/editors/space_sequencer/sequencer_channels_draw.c b/source/blender/editors/space_sequencer/sequencer_channels_draw.c
index b4bb4e950f0..a777132e9fc 100644
--- a/source/blender/editors/space_sequencer/sequencer_channels_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_channels_draw.c
@@ -347,6 +347,8 @@ void channel_draw_context_init(const bContext *C,
void draw_channels(const bContext *C, ARegion *region)
{
+ draw_background();
+
Editing *ed = SEQ_editing_get(CTX_data_scene(C));
if (ed == NULL) {
return;
@@ -357,7 +359,6 @@ void draw_channels(const bContext *C, ARegion *region)
UI_view2d_view_ortho(context.v2d);
- draw_background();
draw_channel_headers(&context);
UI_view2d_view_restore(C);
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 8e5931b127a..95707f83d85 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -27,6 +27,7 @@
#include "SEQ_channels.h"
#include "SEQ_iterator.h"
+#include "SEQ_relations.h"
#include "SEQ_select.h"
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
@@ -1920,7 +1921,7 @@ static bool select_grouped_effect(SeqCollection *strips,
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && (seq->type & SEQ_TYPE_EFFECT) &&
- ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) {
+ SEQ_relation_is_effect_of_strip(seq, actseq)) {
effects[seq->type] = true;
}
}
diff --git a/source/blender/editors/space_sequencer/sequencer_thumbnails.c b/source/blender/editors/space_sequencer/sequencer_thumbnails.c
index f5c5c7af4b6..43c5e004040 100644
--- a/source/blender/editors/space_sequencer/sequencer_thumbnails.c
+++ b/source/blender/editors/space_sequencer/sequencer_thumbnails.c
@@ -86,6 +86,11 @@ static bool check_seq_need_thumbnails(Sequence *seq, rctf *view_area)
return false;
}
+ /* Handle is moved, but not for this strip. */
+ if ((G.moving & G_TRANSFORM_SEQ) != 0 && (seq->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) == 0) {
+ return false;
+ }
+
return true;
}
@@ -123,26 +128,13 @@ static void seq_get_thumb_image_dimensions(Sequence *seq,
}
}
-static float seq_thumbnail_get_start_frame(Sequence *seq, float frame_step, rctf *view_area)
-{
- if (seq->start > view_area->xmin && seq->start < view_area->xmax) {
- return seq->start;
- }
-
- /* Drawing and caching both check to see if strip is in view area or not before calling this
- * function so assuming strip/part of strip in view. */
-
- int no_invisible_thumbs = (view_area->xmin - seq->start) / frame_step;
- return ((no_invisible_thumbs - 1) * frame_step) + seq->start;
-}
-
static void thumbnail_start_job(void *data,
short *stop,
short *UNUSED(do_update),
float *UNUSED(progress))
{
ThumbnailDrawJob *tj = data;
- float start_frame, frame_step;
+ float frame_step;
GHashIterator gh_iter;
@@ -155,9 +147,8 @@ static void thumbnail_start_job(void *data,
if (check_seq_need_thumbnails(seq_orig, tj->view_area)) {
seq_get_thumb_image_dimensions(
val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, tj->thumb_height, NULL, NULL);
- start_frame = seq_thumbnail_get_start_frame(seq_orig, frame_step, tj->view_area);
SEQ_render_thumbnails(
- &tj->context, val->seq_dupli, seq_orig, start_frame, frame_step, tj->view_area, stop);
+ &tj->context, val->seq_dupli, seq_orig, frame_step, tj->view_area, stop);
SEQ_relations_sequence_free_anim(val->seq_dupli);
}
BLI_ghashIterator_step(&gh_iter);
@@ -172,7 +163,6 @@ static void thumbnail_start_job(void *data,
if (check_seq_need_thumbnails(seq_orig, tj->view_area)) {
seq_get_thumb_image_dimensions(
val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, tj->thumb_height, NULL, NULL);
- start_frame = seq_thumbnail_get_start_frame(seq_orig, frame_step, tj->view_area);
SEQ_render_thumbnails_base_set(&tj->context, val->seq_dupli, seq_orig, tj->view_area, stop);
SEQ_relations_sequence_free_anim(val->seq_dupli);
}
@@ -458,40 +448,31 @@ void draw_seq_strip_thumbnail(View2D *v2d,
upper_thumb_bound = seq->enddisp;
}
- float thumb_x_start = seq_thumbnail_get_start_frame(seq, thumb_width, &v2d->cur);
+ float timeline_frame = SEQ_render_thumbnail_first_frame_get(seq, thumb_width, &v2d->cur);
float thumb_x_end;
- while (thumb_x_start + thumb_width < v2d->cur.xmin) {
- thumb_x_start += thumb_width;
- }
-
- /* Ignore thumbs to the left of strip. */
- while (thumb_x_start + thumb_width < seq->startdisp) {
- thumb_x_start += thumb_width;
- }
-
GSet *last_displayed_thumbnails = last_displayed_thumbnails_list_ensure(C, seq);
/* Cleanup thumbnail list outside of rendered range, which is cleaned up one by one to prevent
* flickering after zooming. */
if (!sequencer_thumbnail_v2d_is_navigating(C)) {
- last_displayed_thumbnails_list_cleanup(last_displayed_thumbnails, -FLT_MAX, thumb_x_start);
+ last_displayed_thumbnails_list_cleanup(last_displayed_thumbnails, -FLT_MAX, timeline_frame);
}
/* Start drawing. */
- while (thumb_x_start < upper_thumb_bound) {
- thumb_x_end = thumb_x_start + thumb_width;
+ while (timeline_frame < upper_thumb_bound) {
+ thumb_x_end = timeline_frame + thumb_width;
clipped = false;
/* Checks to make sure that thumbs are loaded only when in view and within the confines of the
* strip. Some may not be required but better to have conditions for safety as x1 here is
* point to start caching from and not drawing. */
- if (thumb_x_start > v2d->cur.xmax) {
+ if (timeline_frame > v2d->cur.xmax) {
break;
}
/* Set the clipping bound to show the left handle moving over thumbs and not shift thumbs. */
- if (IN_RANGE_INCL(seq->startdisp, thumb_x_start, thumb_x_end)) {
- cut_off = seq->startdisp - thumb_x_start;
+ if (IN_RANGE_INCL(seq->startdisp, timeline_frame, thumb_x_end)) {
+ cut_off = seq->startdisp - timeline_frame;
clipped = true;
}
@@ -499,7 +480,7 @@ void draw_seq_strip_thumbnail(View2D *v2d,
if (thumb_x_end > (upper_thumb_bound)) {
thumb_x_end = upper_thumb_bound;
clipped = true;
- if (thumb_x_end - thumb_x_start < 1) {
+ if (thumb_x_end - timeline_frame < 1) {
break;
}
}
@@ -508,14 +489,12 @@ void draw_seq_strip_thumbnail(View2D *v2d,
float zoom_y = thumb_height / image_height;
float cropx_min = (cut_off / pixelx) / (zoom_y / pixely);
- float cropx_max = ((thumb_x_end - thumb_x_start) / pixelx) / (zoom_y / pixely);
- if (cropx_max == (thumb_x_end - thumb_x_start)) {
+ float cropx_max = ((thumb_x_end - timeline_frame) / pixelx) / (zoom_y / pixely);
+ if (cropx_max == (thumb_x_end - timeline_frame)) {
cropx_max = cropx_max + 1;
}
BLI_rcti_init(&crop, (int)(cropx_min), (int)cropx_max, 0, (int)(image_height)-1);
- int timeline_frame = round_fl_to_int(thumb_x_start);
-
/* Get the image. */
ImBuf *ibuf = SEQ_get_thumbnail(&context, seq, timeline_frame, &crop, clipped);
@@ -529,7 +508,7 @@ void draw_seq_strip_thumbnail(View2D *v2d,
else if (!sequencer_thumbnail_v2d_is_navigating(C)) {
/* Clear images in frame range occupied by new thumbnail. */
last_displayed_thumbnails_list_cleanup(
- last_displayed_thumbnails, thumb_x_start, thumb_x_end);
+ last_displayed_thumbnails, timeline_frame, thumb_x_end);
/* Insert new thumbnail frame to list. */
BLI_gset_add(last_displayed_thumbnails, POINTER_FROM_INT(timeline_frame));
}
@@ -558,10 +537,10 @@ void draw_seq_strip_thumbnail(View2D *v2d,
ED_draw_imbuf_ctx_clipping(C,
ibuf,
- thumb_x_start + cut_off,
+ timeline_frame + cut_off,
y1,
true,
- thumb_x_start + cut_off,
+ timeline_frame + cut_off,
y1,
thumb_x_end,
thumb_y_end,
@@ -570,7 +549,7 @@ void draw_seq_strip_thumbnail(View2D *v2d,
IMB_freeImBuf(ibuf);
GPU_blend(GPU_BLEND_NONE);
cut_off = 0;
- thumb_x_start += thumb_width;
+ timeline_frame = SEQ_render_thumbnail_next_frame_get(seq, timeline_frame, thumb_width);
}
- last_displayed_thumbnails_list_cleanup(last_displayed_thumbnails, thumb_x_start, FLT_MAX);
+ last_displayed_thumbnails_list_cleanup(last_displayed_thumbnails, timeline_frame, FLT_MAX);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c
index 4d245b9ddaa..c407dad623d 100644
--- a/source/blender/editors/space_sequencer/sequencer_view.c
+++ b/source/blender/editors/space_sequencer/sequencer_view.c
@@ -22,9 +22,11 @@
#include "RNA_define.h"
+#include "SEQ_iterator.h"
#include "SEQ_select.h"
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
+#include "SEQ_transform.h"
/* For menu, popup, icons, etc. */
#include "ED_anim_api.h"
@@ -260,14 +262,30 @@ void SEQUENCER_OT_view_zoom_ratio(wmOperatorType *ot)
/** \name Frame Selected Operator
* \{ */
-static int sequencer_view_selected_exec(bContext *C, wmOperator *op)
+static void seq_view_collection_rect_preview(Scene *scene, SeqCollection *strips, rctf *rect)
+{
+ float min[2], max[2];
+ SEQ_image_transform_bounding_box_from_collection(scene, strips, true, min, max);
+
+ rect->xmin = min[0];
+ rect->xmax = max[0];
+ rect->ymin = min[1];
+ rect->ymax = max[1];
+
+ float minsize = min_ff(BLI_rctf_size_x(rect), BLI_rctf_size_y(rect));
+
+ /* If the size of the strip is smaller than a pixel, add padding to prevent division by zero. */
+ if (minsize < 1.0f) {
+ BLI_rctf_pad(rect, 20.0f, 20.0f);
+ }
+
+ /* Add padding. */
+ BLI_rctf_scale(rect, 1.1f);
+}
+
+static void seq_view_collection_rect_timeline(Scene *scene, SeqCollection *strips, rctf *rect)
{
- Scene *scene = CTX_data_scene(C);
- View2D *v2d = UI_view2d_fromcontext(C);
- ARegion *region = CTX_wm_region(C);
- Editing *ed = SEQ_editing_get(scene);
Sequence *seq;
- rctf cur_new = v2d->cur;
int xmin = MAXFRAME * 2;
int xmax = -MAXFRAME * 2;
@@ -278,49 +296,63 @@ static int sequencer_view_selected_exec(bContext *C, wmOperator *op)
int ymargin = 1;
int xmargin = FPS;
- if (ed == NULL) {
- return OPERATOR_CANCELLED;
- }
-
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if (seq->flag & SELECT) {
- xmin = min_ii(xmin, seq->startdisp);
- xmax = max_ii(xmax, seq->enddisp);
+ SEQ_ITERATOR_FOREACH (seq, strips) {
+ xmin = min_ii(xmin, seq->startdisp);
+ xmax = max_ii(xmax, seq->enddisp);
- ymin = min_ii(ymin, seq->machine);
- ymax = max_ii(ymax, seq->machine);
- }
+ ymin = min_ii(ymin, seq->machine);
+ ymax = max_ii(ymax, seq->machine);
}
- if (ymax != 0) {
- const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ xmax += xmargin;
+ xmin -= xmargin;
+ ymax += ymargin;
+ ymin -= ymargin;
- xmax += xmargin;
- xmin -= xmargin;
- ymax += ymargin;
- ymin -= ymargin;
+ orig_height = BLI_rctf_size_y(rect);
- orig_height = BLI_rctf_size_y(&cur_new);
+ rect->xmin = xmin;
+ rect->xmax = xmax;
- cur_new.xmin = xmin;
- cur_new.xmax = xmax;
+ rect->ymin = ymin;
+ rect->ymax = ymax;
- cur_new.ymin = ymin;
- cur_new.ymax = ymax;
+ /* Only zoom out vertically. */
+ if (orig_height > BLI_rctf_size_y(rect)) {
+ ymid = BLI_rctf_cent_y(rect);
- /* Only zoom out vertically. */
- if (orig_height > BLI_rctf_size_y(&cur_new)) {
- ymid = BLI_rctf_cent_y(&cur_new);
+ rect->ymin = ymid - (orig_height / 2);
+ rect->ymax = ymid + (orig_height / 2);
+ }
+}
- cur_new.ymin = ymid - (orig_height / 2);
- cur_new.ymax = ymid + (orig_height / 2);
- }
+static int sequencer_view_selected_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ARegion *region = CTX_wm_region(C);
+ SeqCollection *strips = selected_strips_from_context(C);
+ View2D *v2d = UI_view2d_fromcontext(C);
+ rctf cur_new = v2d->cur;
- UI_view2d_smooth_view(C, region, &cur_new, smooth_viewtx);
+ if (SEQ_collection_len(strips) == 0) {
+ return OPERATOR_CANCELLED;
+ }
- return OPERATOR_FINISHED;
+ if (sequencer_view_has_preview_poll(C) && !sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
}
- return OPERATOR_CANCELLED;
+
+ if (region && region->regiontype == RGN_TYPE_PREVIEW) {
+ seq_view_collection_rect_preview(scene, strips, &cur_new);
+ }
+ else {
+ seq_view_collection_rect_timeline(scene, strips, &cur_new);
+ }
+
+ const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ UI_view2d_smooth_view(C, region, &cur_new, smooth_viewtx);
+
+ return OPERATOR_FINISHED;
}
void SEQUENCER_OT_view_selected(wmOperatorType *ot)
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index 0a0669e02e4..89bff839481 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -331,6 +331,31 @@ static void sequencer_refresh(const bContext *C, ScrArea *area)
break;
}
+ ARegion *region_channels = sequencer_find_region(area, RGN_TYPE_CHANNELS);
+ if (sseq->view == SEQ_VIEW_SEQUENCE) {
+ if (region_channels && (region_channels->flag & RGN_FLAG_HIDDEN)) {
+ region_channels->flag &= ~RGN_FLAG_HIDDEN;
+ region_channels->v2d.flag &= ~V2D_IS_INIT;
+ view_changed = true;
+ }
+ if (region_channels && region_channels->alignment != RGN_ALIGN_LEFT) {
+ region_channels->alignment = RGN_ALIGN_LEFT;
+ view_changed = true;
+ }
+ }
+ else {
+ if (region_channels && !(region_channels->flag & RGN_FLAG_HIDDEN)) {
+ region_channels->flag |= RGN_FLAG_HIDDEN;
+ region_channels->v2d.flag &= ~V2D_IS_INIT;
+ WM_event_remove_handlers((bContext *)C, &region_channels->handlers);
+ view_changed = true;
+ }
+ if (region_channels && region_channels->alignment != RGN_ALIGN_NONE) {
+ region_channels->alignment = RGN_ALIGN_NONE;
+ view_changed = true;
+ }
+ }
+
if (view_changed) {
ED_area_init(wm, window, area);
ED_area_tag_redraw(area);
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index 14b9dbe4b44..b3d6c395e89 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -300,6 +300,7 @@ static float get_default_column_width(const ColumnValues &values)
return values.default_width;
}
static const float float_width = 3;
+ static const float int_width = 2;
switch (values.type()) {
case SPREADSHEET_VALUE_TYPE_BOOL:
return 2.0f;
@@ -317,6 +318,8 @@ static float get_default_column_width(const ColumnValues &values)
return 8.0f;
case SPREADSHEET_VALUE_TYPE_STRING:
return 5.0f;
+ case SPREADSHEET_VALUE_TYPE_BYTE_COLOR:
+ return 4.0f * int_width;
case SPREADSHEET_VALUE_TYPE_UNKNOWN:
return 2.0f;
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
index 19fe61f0ed3..a29aa1fd026 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
@@ -44,6 +44,9 @@ eSpreadsheetColumnValueType cpp_type_to_column_type(const CPPType &type)
if (type.is<InstanceReference>()) {
return SPREADSHEET_VALUE_TYPE_INSTANCES;
}
+ if (type.is<ColorGeometry4b>()) {
+ return SPREADSHEET_VALUE_TYPE_BYTE_COLOR;
+ }
return SPREADSHEET_VALUE_TYPE_UNKNOWN;
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
index db466f8ccf3..e19a343335a 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
@@ -191,6 +191,10 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
const ColorGeometry4f value = data.get<ColorGeometry4f>(real_index);
this->draw_float_vector(params, Span(&value.r, 4));
}
+ else if (data.type().is<ColorGeometry4b>()) {
+ const ColorGeometry4b value = data.get<ColorGeometry4b>(real_index);
+ this->draw_int_vector(params, {value.r, value.g, value.b, value.a});
+ }
else if (data.type().is<InstanceReference>()) {
const InstanceReference value = data.get<InstanceReference>(real_index);
switch (value.type()) {
@@ -304,6 +308,34 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
}
}
+ void draw_int_vector(const CellDrawParams &params, const Span<int> values) const
+ {
+ BLI_assert(!values.is_empty());
+ const float segment_width = (float)params.width / values.size();
+ for (const int i : values.index_range()) {
+ const int value = values[i];
+ const std::string value_str = std::to_string(value);
+ uiBut *but = uiDefIconTextBut(params.block,
+ UI_BTYPE_LABEL,
+ 0,
+ ICON_NONE,
+ value_str.c_str(),
+ params.xmin + i * segment_width,
+ params.ymin,
+ segment_width,
+ params.height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ /* Right-align Ints. */
+ UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
+ UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT);
+ }
+ }
+
int column_width(int column_index) const final
{
return spreadsheet_layout_.columns[column_index].width;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
index e45317c2a5c..eb8f111baa0 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
@@ -106,10 +106,10 @@ static void apply_row_filter(const SpreadsheetRowFilter &row_filter,
const float2 value = row_filter.value_float2;
switch (row_filter.operation) {
case SPREADSHEET_ROW_FILTER_EQUAL: {
- const float threshold_sq = row_filter.threshold;
+ const float threshold_sq = pow2f(row_filter.threshold);
apply_filter_operation(
column_data.typed<float2>(),
- [&](const float2 cell) { return math::distance_squared(cell, value) > threshold_sq; },
+ [&](const float2 cell) { return math::distance_squared(cell, value) <= threshold_sq; },
prev_mask,
new_indices);
break;
@@ -136,10 +136,10 @@ static void apply_row_filter(const SpreadsheetRowFilter &row_filter,
const float3 value = row_filter.value_float3;
switch (row_filter.operation) {
case SPREADSHEET_ROW_FILTER_EQUAL: {
- const float threshold_sq = row_filter.threshold;
+ const float threshold_sq = pow2f(row_filter.threshold);
apply_filter_operation(
column_data.typed<float3>(),
- [&](const float3 cell) { return math::distance_squared(cell, value) > threshold_sq; },
+ [&](const float3 cell) { return math::distance_squared(cell, value) <= threshold_sq; },
prev_mask,
new_indices);
break;
@@ -168,19 +168,25 @@ static void apply_row_filter(const SpreadsheetRowFilter &row_filter,
}
else if (column_data.type().is<ColorGeometry4f>()) {
const ColorGeometry4f value = row_filter.value_color;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- const float threshold_sq = row_filter.threshold;
- apply_filter_operation(
- column_data.typed<ColorGeometry4f>(),
- [&](const ColorGeometry4f cell) {
- return len_squared_v4v4(cell, value) > threshold_sq;
- },
- prev_mask,
- new_indices);
- break;
- }
- }
+ const float threshold_sq = pow2f(row_filter.threshold);
+ apply_filter_operation(
+ column_data.typed<ColorGeometry4f>(),
+ [&](const ColorGeometry4f cell) { return len_squared_v4v4(cell, value) <= threshold_sq; },
+ prev_mask,
+ new_indices);
+ }
+ else if (column_data.type().is<ColorGeometry4b>()) {
+ const ColorGeometry4b value = row_filter.value_byte_color;
+ const float4 value_floats = {(float)value.r, (float)value.g, (float)value.b, (float)value.a};
+ const float threshold_sq = pow2f(row_filter.threshold);
+ apply_filter_operation(
+ column_data.typed<ColorGeometry4b>(),
+ [&](const ColorGeometry4b cell) {
+ const float4 cell_floats = {(float)cell.r, (float)cell.g, (float)cell.b, (float)cell.a};
+ return len_squared_v4v4(value_floats, cell_floats) <= threshold_sq;
+ },
+ prev_mask,
+ new_indices);
}
else if (column_data.type().is<InstanceReference>()) {
const StringRef value = row_filter.value_string;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
index 6206b2d0c03..7c1ac024c12 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
@@ -42,7 +42,8 @@ static std::string operation_string(const eSpreadsheetColumnValueType data_type,
if (ELEM(data_type,
SPREADSHEET_VALUE_TYPE_BOOL,
SPREADSHEET_VALUE_TYPE_INSTANCES,
- SPREADSHEET_VALUE_TYPE_COLOR)) {
+ SPREADSHEET_VALUE_TYPE_COLOR,
+ SPREADSHEET_VALUE_TYPE_BYTE_COLOR)) {
return "=";
}
@@ -101,6 +102,14 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter,
}
case SPREADSHEET_VALUE_TYPE_STRING:
return row_filter.value_string;
+ case SPREADSHEET_VALUE_TYPE_BYTE_COLOR: {
+ std::ostringstream result;
+ result.precision(3);
+ result << std::fixed << "(" << (int)row_filter.value_byte_color[0] << ", "
+ << (int)row_filter.value_byte_color[1] << ", " << (int)row_filter.value_byte_color[2]
+ << ", " << (int)row_filter.value_byte_color[3] << ")";
+ return result.str();
+ }
case SPREADSHEET_VALUE_TYPE_UNKNOWN:
return "";
}
@@ -229,6 +238,10 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel)
case SPREADSHEET_VALUE_TYPE_STRING:
uiItemR(layout, filter_ptr, "value_string", 0, IFACE_("Value"), ICON_NONE);
break;
+ case SPREADSHEET_VALUE_TYPE_BYTE_COLOR:
+ uiItemR(layout, filter_ptr, "value_byte_color", 0, IFACE_("Value"), ICON_NONE);
+ uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
+ break;
case SPREADSHEET_VALUE_TYPE_UNKNOWN:
uiItemL(layout, IFACE_("Unknown column type"), ICON_ERROR);
break;
diff --git a/source/blender/editors/space_text/text_format_py.c b/source/blender/editors/space_text/text_format_py.c
index 4048e181fde..47d0168195b 100644
--- a/source/blender/editors/space_text/text_format_py.c
+++ b/source/blender/editors/space_text/text_format_py.c
@@ -31,26 +31,40 @@
static int txtfmt_py_find_builtinfunc(const char *string)
{
int i, len;
- /* list is from...
+ /**
+ * The following items are derived from this list:
+ * \code{.py}
* ", ".join(['"%s"' % kw
- * for kw in __import__("keyword").kwlist
- * if kw not in {"False", "None", "True", "def", "class"}])
+ * for kw in sorted(__import__("keyword").kwlist + __import__("keyword").softkwlist)
+ * if kw not in {"False", "None", "True", "def", "class", "_"}])
+ * \endcode
*
- * ... and for this code:
- * print("\n".join(['else if (STR_LITERAL_STARTSWITH(string, "%s", len)) i = len;' % kw
- * for kw in __import__("keyword").kwlist
- * if kw not in {"False", "None", "True", "def", "class"}]))
+ * The code below can be re-generated using:
+ * \code{.py}
+ * import keyword
+ * ignore = {"False", "None", "True", "def", "class", "_"}
+ * keywords = sorted(set(keyword.kwlist + keyword.softkwlist) - ignore)
+ * longest = max(len(kw) for kw in keywords)
+ * first = 'if (STR_LITERAL_STARTSWITH(string, "%s",%s len)) { i = len;'
+ * middle = '} else if (STR_LITERAL_STARTSWITH(string, "%s",%s len)) { i = len;'
+ * last = '} else %s { i = 0;'
+ * print("\n".join([(first if i==0 else middle) % (kw, ' '*(longest - len(kw)))
+ * for (i, kw) in enumerate(keywords)]) + "\n" +
+ * last % (' '*(longest-2)) + "\n" +
+ * "}")
+ * \endcode
*/
/* Keep aligned args for readability. */
/* clang-format off */
- if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len;
+ } else if (STR_LITERAL_STARTSWITH(string, "as", len)) { i = len;
+ } else if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "async", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "await", len)) { i = len;
- } else if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len;
- } else if (STR_LITERAL_STARTSWITH(string, "as", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len;
+ } else if (STR_LITERAL_STARTSWITH(string, "case", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "continue", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "del", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "elif", len)) { i = len;
@@ -65,6 +79,7 @@ static int txtfmt_py_find_builtinfunc(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "in", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "is", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "lambda", len)) { i = len;
+ } else if (STR_LITERAL_STARTSWITH(string, "match", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "nonlocal", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "not", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "or", len)) { i = len;
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index 3f1483bbd03..753f82e483e 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -3459,12 +3459,6 @@ static int text_insert_exec(bContext *C, wmOperator *op)
while (str[i]) {
code = BLI_str_utf8_as_unicode_step(str, str_len, &i);
done |= txt_add_char(text, code);
- if (U.text_flag & USER_TEXT_EDIT_AUTO_CLOSE) {
- if (text_closing_character_pair_get(code)) {
- done |= txt_add_char(text, text_closing_character_pair_get(code));
- txt_move_left(text, false);
- }
- }
}
}
@@ -3484,6 +3478,7 @@ static int text_insert_exec(bContext *C, wmOperator *op)
static int text_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ uint auto_close_char = 0;
int ret;
/* NOTE: the "text" property is always set from key-map,
@@ -3510,10 +3505,23 @@ static int text_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
str[len] = '\0';
RNA_string_set(op->ptr, "text", str);
+
+ if (U.text_flag & USER_TEXT_EDIT_AUTO_CLOSE) {
+ auto_close_char = BLI_str_utf8_as_unicode(str);
+ }
}
ret = text_insert_exec(C, op);
+ if ((ret == OPERATOR_FINISHED) && (auto_close_char != 0)) {
+ const uint auto_close_match = text_closing_character_pair_get(auto_close_char);
+ if (auto_close_match != 0) {
+ Text *text = CTX_data_edit_text(C);
+ txt_add_char(text, auto_close_match);
+ txt_move_left(text, false);
+ }
+ }
+
/* run the script while editing, evil but useful */
if (ret == OPERATOR_FINISHED && CTX_wm_space_text(C)->live_edit) {
text_run_script(C, NULL);
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 6cb3d629e55..1d22c2f237b 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -1628,7 +1628,7 @@ void ED_view3d_buttons_region_layout_ex(const bContext *C,
ARRAY_SET_ITEMS(contexts, ".greasepencil_vertex");
break;
case CTX_MODE_SCULPT_CURVES:
- ARRAY_SET_ITEMS(contexts, ".curves_sculpt");
+ ARRAY_SET_ITEMS(contexts, ".paint_common", ".curves_sculpt");
break;
default:
break;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 593c4f6e755..5a27349dc7f 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -2371,7 +2371,7 @@ void ED_view3d_datamask(const bContext *C,
CustomData_MeshMasks *r_cddata_masks)
{
if (ELEM(v3d->shading.type, OB_TEXTURE, OB_MATERIAL, OB_RENDER)) {
- r_cddata_masks->lmask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
+ r_cddata_masks->lmask |= CD_MASK_MLOOPUV | CD_MASK_PROP_BYTE_COLOR;
r_cddata_masks->vmask |= CD_MASK_ORCO | CD_MASK_PROP_COLOR;
}
else if (v3d->shading.type == OB_SOLID) {
@@ -2379,7 +2379,7 @@ void ED_view3d_datamask(const bContext *C,
r_cddata_masks->lmask |= CD_MASK_MLOOPUV;
}
if (v3d->shading.color_type == V3D_SHADING_VERTEX_COLOR) {
- r_cddata_masks->lmask |= CD_MASK_MLOOPCOL;
+ r_cddata_masks->lmask |= CD_MASK_PROP_BYTE_COLOR;
r_cddata_masks->vmask |= CD_MASK_ORCO | CD_MASK_PROP_COLOR;
}
}
diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c
index 05d4372723b..298de9b8730 100644
--- a/source/blender/editors/space_view3d/view3d_placement.c
+++ b/source/blender/editors/space_view3d/view3d_placement.c
@@ -737,6 +737,10 @@ static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEv
WM_event_drag_start_mval(event, ipd->region, mval);
int flag_orig = snap_state_new->flag;
snap_state_new->flag |= V3D_SNAPCURSOR_TOGGLE_ALWAYS_TRUE;
+
+ /* Be sure to also compute the #V3DSnapCursorData.plane_omat. */
+ snap_state->draw_plane = true;
+
ED_view3d_cursor_snap_data_get(snap_state_new, C, mval[0], mval[1]);
snap_state_new->flag = flag_orig;
}
diff --git a/source/blender/editors/transform/transform_gizmo_2d.c b/source/blender/editors/transform/transform_gizmo_2d.c
index f2fb5b26305..838b40c2040 100644
--- a/source/blender/editors/transform/transform_gizmo_2d.c
+++ b/source/blender/editors/transform/transform_gizmo_2d.c
@@ -251,17 +251,9 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min
SEQ_filter_selected_strips(strips);
int selected_strips = SEQ_collection_len(strips);
if (selected_strips > 0) {
- INIT_MINMAX2(r_min, r_max);
has_select = true;
-
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, strips) {
- float quad[4][2];
- SEQ_image_transform_quad_get(scene, seq, selected_strips != 1, quad);
- for (int i = 0; i < 4; i++) {
- minmax_v2v2_v2(r_min, r_max, quad[i]);
- }
- }
+ SEQ_image_transform_bounding_box_from_collection(
+ scene, strips, selected_strips != 1, r_min, r_max);
}
SEQ_collection_free(strips);
if (selected_strips > 1) {
diff --git a/source/blender/editors/transform/transform_mode_bend.c b/source/blender/editors/transform/transform_mode_bend.c
index 348f012e300..acc6b20810f 100644
--- a/source/blender/editors/transform/transform_mode_bend.c
+++ b/source/blender/editors/transform/transform_mode_bend.c
@@ -106,7 +106,7 @@ static void transdata_elem_bend(const TransInfo *t,
}
if (t->options & CTX_GPENCIL_STROKES) {
- /* grease pencil multiframe falloff */
+ /* Grease pencil multi-frame falloff. */
bGPDstroke *gps = (bGPDstroke *)td->extra;
if (gps != NULL) {
fac_scaled = fac * td->factor * gps->runtime.multi_frame_falloff;
diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc
index ab78ef6a5aa..abeb376a9a6 100644
--- a/source/blender/editors/transform/transform_snap_object.cc
+++ b/source/blender/editors/transform/transform_snap_object.cc
@@ -242,7 +242,7 @@ static SnapObjectData *snap_object_data_lookup(SnapObjectContext *sctx, Object *
if (sod == nullptr) {
if (sctx->cache.data_to_object_map != nullptr) {
ob_eval = static_cast<Object *>(
- BLI_ghash_lookup(sctx->cache.data_to_object_map, ob_eval->data));
+ BLI_ghash_lookup(sctx->cache.data_to_object_map, ob_eval->runtime.data_orig));
/* Could be NULl when mixing edit-mode and non edit-mode objects. */
if (ob_eval != nullptr) {
sod = static_cast<SnapObjectData *>(BLI_ghash_lookup(sctx->cache.object_map, ob_eval));
@@ -369,7 +369,7 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
sctx->cache.data_to_object_map = BLI_ghash_ptr_new(__func__);
}
void **ob_p;
- if (BLI_ghash_ensure_p(sctx->cache.data_to_object_map, ob_eval->data, &ob_p)) {
+ if (BLI_ghash_ensure_p(sctx->cache.data_to_object_map, ob_eval->runtime.data_orig, &ob_p)) {
ob_eval = static_cast<Object *>(*ob_p);
}
else {
diff --git a/source/blender/editors/transform/transform_snap_sequencer.c b/source/blender/editors/transform/transform_snap_sequencer.c
index cf229c9e9ec..7715388bf52 100644
--- a/source/blender/editors/transform/transform_snap_sequencer.c
+++ b/source/blender/editors/transform/transform_snap_sequencer.c
@@ -21,6 +21,7 @@
#include "SEQ_channels.h"
#include "SEQ_effects.h"
#include "SEQ_iterator.h"
+#include "SEQ_relations.h"
#include "SEQ_render.h"
#include "SEQ_sequencer.h"
@@ -102,8 +103,7 @@ static void query_strip_effects_fn(Sequence *seq_reference,
/* Find all strips connected to `seq_reference`. */
LISTBASE_FOREACH (Sequence *, seq_test, seqbase) {
- if (seq_test->seq1 == seq_reference || seq_test->seq2 == seq_reference ||
- seq_test->seq3 == seq_reference) {
+ if (SEQ_relation_is_effect_of_strip(seq_test, seq_reference)) {
query_strip_effects_fn(seq_test, seqbase, collection);
}
}
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 54a6bb44bad..03e9134c6c2 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -608,9 +608,9 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
// colors and transparency (the latter represented by grayscale colors)
MLoopCol *colors = (MLoopCol *)CustomData_add_layer_named(
- &mesh->ldata, CD_MLOOPCOL, CD_CALLOC, nullptr, mesh->totloop, "Color");
+ &mesh->ldata, CD_PROP_BYTE_COLOR, CD_CALLOC, nullptr, mesh->totloop, "Color");
MLoopCol *transp = (MLoopCol *)CustomData_add_layer_named(
- &mesh->ldata, CD_MLOOPCOL, CD_CALLOC, nullptr, mesh->totloop, "Alpha");
+ &mesh->ldata, CD_PROP_BYTE_COLOR, CD_CALLOC, nullptr, mesh->totloop, "Alpha");
mesh->mloopcol = colors;
mesh->mat = (Material **)MEM_mallocN(sizeof(Material *) * mesh->totcol, "MaterialList");
diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index 5a27cda0787..0005d788a3b 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -38,7 +38,7 @@
#include "BLI_vector.hh"
#include "BLI_vector_set.hh"
-#include "FN_multi_function_builder.hh"
+#include "FN_multi_function.hh"
namespace blender::fn {
diff --git a/source/blender/functions/intern/cpp_types.cc b/source/blender/functions/intern/cpp_types.cc
index a2adc2ea8b6..5c43fffdd61 100644
--- a/source/blender/functions/intern/cpp_types.cc
+++ b/source/blender/functions/intern/cpp_types.cc
@@ -11,6 +11,7 @@ MAKE_FIELD_CPP_TYPE(FloatField, float);
MAKE_FIELD_CPP_TYPE(Float2Field, blender::float2);
MAKE_FIELD_CPP_TYPE(Float3Field, blender::float3);
MAKE_FIELD_CPP_TYPE(ColorGeometry4fField, blender::ColorGeometry4f);
+MAKE_FIELD_CPP_TYPE(ColorGeometry4bField, blender::ColorGeometry4b);
MAKE_FIELD_CPP_TYPE(BoolField, bool);
MAKE_FIELD_CPP_TYPE(Int8Field, int8_t);
MAKE_FIELD_CPP_TYPE(Int32Field, int32_t);
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
index 944674c23a9..a53da717606 100644
--- a/source/blender/functions/intern/field.cc
+++ b/source/blender/functions/intern/field.cc
@@ -8,6 +8,7 @@
#include "BLI_vector_set.hh"
#include "FN_field.hh"
+#include "FN_multi_function_builder.hh"
#include "FN_multi_function_procedure.hh"
#include "FN_multi_function_procedure_builder.hh"
#include "FN_multi_function_procedure_executor.hh"
diff --git a/source/blender/functions/intern/multi_function_procedure_executor.cc b/source/blender/functions/intern/multi_function_procedure_executor.cc
index 7a0b74d8039..c58ca0bb8fd 100644
--- a/source/blender/functions/intern/multi_function_procedure_executor.cc
+++ b/source/blender/functions/intern/multi_function_procedure_executor.cc
@@ -681,14 +681,9 @@ class VariableState : NonCopyable, NonMovable {
/* Sanity check to make sure that enough indices can be destructed. */
BLI_assert(new_tot_initialized >= 0);
- bool do_destruct_self = false;
-
switch (value_->type) {
case ValueType::GVArray: {
- if (mask.size() == full_mask.size()) {
- do_destruct_self = true;
- }
- else {
+ if (mask.size() < full_mask.size()) {
/* Not all elements are destructed. Since we can't work on the original array, we have to
* create a copy first. */
this->ensure_is_mutable(full_mask, data_type, value_allocator);
@@ -701,16 +696,10 @@ class VariableState : NonCopyable, NonMovable {
case ValueType::Span: {
const CPPType &type = data_type.single_type();
type.destruct_indices(this->value_as<VariableValue_Span>()->data, mask);
- if (new_tot_initialized == 0) {
- do_destruct_self = true;
- }
break;
}
case ValueType::GVVectorArray: {
- if (mask.size() == full_mask.size()) {
- do_destruct_self = true;
- }
- else {
+ if (mask.size() < full_mask.size()) {
/* Not all elements are cleared. Since we can't work on the original vector array, we
* have to create a copy first. A possible future optimization is to create the partial
* copy directly. */
@@ -729,22 +718,26 @@ class VariableState : NonCopyable, NonMovable {
BLI_assert(value_typed->is_initialized);
UNUSED_VARS_NDEBUG(value_typed);
if (mask.size() == tot_initialized_) {
- do_destruct_self = true;
+ const CPPType &type = data_type.single_type();
+ type.destruct(value_typed->data);
+ value_typed->is_initialized = false;
}
break;
}
case ValueType::OneVector: {
auto *value_typed = this->value_as<VariableValue_OneVector>();
- UNUSED_VARS(value_typed);
if (mask.size() == tot_initialized_) {
- do_destruct_self = true;
+ value_typed->data.clear(IndexRange(1));
}
break;
}
}
tot_initialized_ = new_tot_initialized;
- return do_destruct_self;
+
+ const bool should_self_destruct = new_tot_initialized == 0 &&
+ caller_provided_storage_ == nullptr;
+ return should_self_destruct;
}
void indices_split(IndexMask mask, IndicesSplitVectors &r_indices)
diff --git a/source/blender/functions/tests/FN_multi_function_procedure_test.cc b/source/blender/functions/tests/FN_multi_function_procedure_test.cc
index a196d0396ec..e7cedb40f83 100644
--- a/source/blender/functions/tests/FN_multi_function_procedure_test.cc
+++ b/source/blender/functions/tests/FN_multi_function_procedure_test.cc
@@ -378,4 +378,34 @@ TEST(multi_function_procedure, BufferReuse)
EXPECT_EQ(results[4], 53);
}
+TEST(multi_function_procedure, OutputBufferReplaced)
+{
+ MFProcedure procedure;
+ MFProcedureBuilder builder{procedure};
+
+ const int output_value = 42;
+ CustomMF_GenericConstant constant_fn(CPPType::get<int>(), &output_value, false);
+ MFVariable &var_o = procedure.new_variable(MFDataType::ForSingle<int>());
+ builder.add_output_parameter(var_o);
+ builder.add_call_with_all_variables(constant_fn, {&var_o});
+ builder.add_destruct(var_o);
+ builder.add_call_with_all_variables(constant_fn, {&var_o});
+ builder.add_return();
+
+ EXPECT_TRUE(procedure.validate());
+
+ MFProcedureExecutor procedure_fn{procedure};
+
+ Array<int> output(3, 0);
+ fn::MFParamsBuilder params(procedure_fn, output.size());
+ params.add_uninitialized_single_output(output.as_mutable_span());
+
+ fn::MFContextBuilder context;
+ procedure_fn.call(IndexMask(output.size()), params, context);
+
+ EXPECT_EQ(output[0], output_value);
+ EXPECT_EQ(output[1], output_value);
+ EXPECT_EQ(output[2], output_value);
+}
+
} // namespace blender::fn::tests
diff --git a/source/blender/geometry/intern/mesh_merge_by_distance.cc b/source/blender/geometry/intern/mesh_merge_by_distance.cc
index 9bb1cbb324e..e45b84632ab 100644
--- a/source/blender/geometry/intern/mesh_merge_by_distance.cc
+++ b/source/blender/geometry/intern/mesh_merge_by_distance.cc
@@ -1580,10 +1580,6 @@ static Mesh *create_merged_mesh(const Mesh &mesh,
BLI_assert((int)r_i == result_npolys);
BLI_assert(loop_cur == result_nloops);
- /* We could only update the normals of the elements in context, but the next modifier can make it
- * dirty anyway which would make the work useless. */
- BKE_mesh_normals_tag_dirty(result);
-
return result;
}
diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc
index 0a0f01c1ff2..f3f0e5b1fce 100644
--- a/source/blender/geometry/intern/realize_instances.cc
+++ b/source/blender/geometry/intern/realize_instances.cc
@@ -1015,8 +1015,6 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
if (vertex_ids) {
vertex_ids.save();
}
-
- BKE_mesh_normals_tag_dirty(dst_mesh);
}
/** \} */
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
index e2cd1741e16..b666eb677eb 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
@@ -984,7 +984,7 @@ void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance)
/* No need to care for different line types/occlusion and so on, because at this stage they
* are all the same within a chain. */
- /* If p3 is within the p1-p2 segment of a width of "tolerance" */
+ /* If p3 is within the p1-p2 segment of a width of "tolerance". */
if (dist_to_line_segment_v2(eci3->pos, eci->pos, eci2->pos) < tolerance) {
/* And if p4 is on the extension of p1-p2 , we remove p3. */
if ((eci4 = eci3->next) && (dist_to_line_v2(eci4->pos, eci->pos, eci2->pos) < tolerance)) {
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 4969d84fb54..57952887d89 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -370,7 +370,6 @@ set(GLSL_SRC
shaders/material/gpu_shader_material_velvet.glsl
shaders/material/gpu_shader_material_vertex_color.glsl
shaders/material/gpu_shader_material_volume_absorption.glsl
- shaders/material/gpu_shader_material_volume_info.glsl
shaders/material/gpu_shader_material_volume_principled.glsl
shaders/material/gpu_shader_material_volume_scatter.glsl
shaders/material/gpu_shader_material_wireframe.glsl
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index f38b9681ad7..58bbe11b4d6 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -109,14 +109,14 @@ typedef enum eGPUMaterialStatus {
GPU_MAT_SUCCESS,
} eGPUMaterialStatus;
-typedef enum eGPUVolumeDefaultValue {
- GPU_VOLUME_DEFAULT_0,
- GPU_VOLUME_DEFAULT_1,
-} eGPUVolumeDefaultValue;
+typedef enum eGPUDefaultValue {
+ GPU_DEFAULT_0 = 0,
+ GPU_DEFAULT_1,
+} eGPUDefaultValue;
typedef struct GPUCodegenOutput {
char *attr_load;
- /* Nodetree functions calls. */
+ /* Node-tree functions calls. */
char *displacement;
char *surface;
char *volume;
@@ -131,6 +131,10 @@ typedef void (*GPUCodegenCallbackFn)(void *thunk, GPUMaterial *mat, GPUCodegenOu
GPUNodeLink *GPU_constant(const float *num);
GPUNodeLink *GPU_uniform(const float *num);
GPUNodeLink *GPU_attribute(GPUMaterial *mat, CustomDataType type, const char *name);
+GPUNodeLink *GPU_attribute_with_default(GPUMaterial *mat,
+ CustomDataType type,
+ const char *name,
+ eGPUDefaultValue default_value);
GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat, const char *name, bool use_dupli);
GPUNodeLink *GPU_image(GPUMaterial *mat,
struct Image *ima,
@@ -142,9 +146,7 @@ GPUNodeLink *GPU_image_tiled(GPUMaterial *mat,
eGPUSamplerState sampler_state);
GPUNodeLink *GPU_image_tiled_mapping(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser);
GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *row);
-GPUNodeLink *GPU_volume_grid(GPUMaterial *mat,
- const char *name,
- eGPUVolumeDefaultValue default_value);
+
/**
* Create an implementation defined differential calculation of a float function.
* The given function should return a float.
@@ -237,7 +239,6 @@ struct GPUUniformBuf *GPU_material_uniform_buffer_get(GPUMaterial *material);
void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs);
struct GPUUniformBuf *GPU_material_create_sss_profile_ubo(void);
-bool GPU_material_is_volume_shader(GPUMaterial *mat);
bool GPU_material_has_surface_output(GPUMaterial *mat);
bool GPU_material_has_volume_output(GPUMaterial *mat);
@@ -255,9 +256,11 @@ void GPU_pass_cache_free(void);
typedef struct GPUMaterialAttribute {
struct GPUMaterialAttribute *next, *prev;
- int type; /* CustomDataType */
- char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */
+ int type; /* CustomDataType */
+ char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */
+ char input_name[12 + 1]; /* GPU_MAX_SAFE_ATTR_NAME + 1 */
eGPUType gputype;
+ eGPUDefaultValue default_value; /* Only for volumes attributes. */
int id;
int users;
} GPUMaterialAttribute;
@@ -274,18 +277,8 @@ typedef struct GPUMaterialTexture {
int sampler_state; /* eGPUSamplerState */
} GPUMaterialTexture;
-typedef struct GPUMaterialVolumeGrid {
- struct GPUMaterialVolumeGrid *next, *prev;
- char *name;
- eGPUVolumeDefaultValue default_value;
- char sampler_name[32]; /* Name of sampler in GLSL. */
- char transform_name[32]; /* Name of 4x4 matrix in GLSL. */
- int users;
-} GPUMaterialVolumeGrid;
-
ListBase GPU_material_attributes(GPUMaterial *material);
ListBase GPU_material_textures(GPUMaterial *material);
-ListBase GPU_material_volume_grids(GPUMaterial *material);
typedef struct GPUUniformAttr {
struct GPUUniformAttr *next, *prev;
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index eed7685bf01..0e7ce0889c2 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -371,12 +371,6 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader,
eGPUShaderConfig sh_cfg);
GPUShader *GPU_shader_get_builtin_shader(eGPUBuiltinShader shader);
-void GPU_shader_get_builtin_shader_code(eGPUBuiltinShader shader,
- const char **r_vert,
- const char **r_frag,
- const char **r_geom,
- const char **r_defines);
-
void GPU_shader_free_builtin_shaders(void);
/* Vertex attributes for shaders */
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 110fdfbd2d9..fed998bb33e 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -207,7 +207,7 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
int update_flags)
{
const MPropCol *vtcol = vcol_type == CD_PROP_COLOR ? vcol_data : NULL;
- const MLoopCol *vcol = vcol_type == CD_MLOOPCOL ? vcol_data : NULL;
+ const MLoopCol *vcol = vcol_type == CD_PROP_BYTE_COLOR ? vcol_data : NULL;
const float(*f3col)[3] = vcol_type == CD_PROP_FLOAT3 ? vcol_data : NULL;
const bool color_loops = vcol_domain == ATTR_DOMAIN_CORNER;
diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc
index 8963fa45c96..048928b2312 100644
--- a/source/blender/gpu/intern/gpu_codegen.cc
+++ b/source/blender/gpu/intern/gpu_codegen.cc
@@ -49,7 +49,6 @@ using namespace blender::gpu::shader;
struct GPUCodegenCreateInfo : ShaderCreateInfo {
struct NameBuffer {
- char attr_names[16][GPU_MAX_SAFE_ATTR_NAME + 1];
char var_names[16][8];
};
@@ -171,10 +170,6 @@ static std::ostream &operator<<(std::ostream &stream, const GPUInput *input)
return stream << input->texture->sampler_name;
case GPU_SOURCE_TEX_TILED_MAPPING:
return stream << input->texture->tiled_mapping_name;
- case GPU_SOURCE_VOLUME_GRID:
- return stream << input->volume_grid->sampler_name;
- case GPU_SOURCE_VOLUME_GRID_TRANSFORM:
- return stream << input->volume_grid->transform_name;
default:
BLI_assert(0);
return stream;
@@ -276,28 +271,6 @@ class GPUCodegen {
}
};
-static char attr_prefix_get(CustomDataType type)
-{
- switch (type) {
- case CD_MTFACE:
- return 'u';
- case CD_TANGENT:
- return 't';
- case CD_MCOL:
- case CD_MLOOPCOL:
- return 'c';
- case CD_PROP_COLOR:
- return 'c';
- case CD_AUTO_FROM_NAME:
- return 'a';
- case CD_HAIRLENGTH:
- return 'l';
- default:
- BLI_assert_msg(0, "GPUVertAttr Prefix type not found : This should not happen!");
- return '\0';
- }
-}
-
void GPUCodegen::generate_attribs()
{
if (BLI_listbase_is_empty(&graph.attributes)) {
@@ -317,24 +290,9 @@ void GPUCodegen::generate_attribs()
int slot = 15;
LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph.attributes) {
-
- /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */
- if (attr->type == CD_ORCO) {
- /* OPTI: orco is computed from local positions, but only if no modifier is present. */
- STRNCPY(info.name_buffer->attr_names[slot], "orco");
- }
- else {
- char *name = info.name_buffer->attr_names[slot];
- name[0] = attr_prefix_get(static_cast<CustomDataType>(attr->type));
- name[1] = '\0';
- if (attr->name[0] != '\0') {
- /* XXX FIXME: see notes in mesh_render_data_create() */
- GPU_vertformat_safe_attr_name(attr->name, &name[1], GPU_MAX_SAFE_ATTR_NAME);
- }
- }
SNPRINTF(info.name_buffer->var_names[slot], "v%d", attr->id);
- blender::StringRefNull attr_name = info.name_buffer->attr_names[slot];
+ blender::StringRefNull attr_name = attr->input_name;
blender::StringRefNull var_name = info.name_buffer->var_names[slot];
eGPUType input_type, iface_type;
@@ -395,12 +353,6 @@ void GPUCodegen::generate_resources()
info.sampler(0, ImageType::FLOAT_2D, tex->sampler_name, Frequency::BATCH);
}
}
- /* Volume Grids. */
- LISTBASE_FOREACH (GPUMaterialVolumeGrid *, grid, &graph.volume_grids) {
- info.sampler(0, ImageType::FLOAT_3D, grid->sampler_name, Frequency::BATCH);
- /* TODO(@fclem): Global uniform. To put in an UBO. */
- info.push_constant(Type::MAT4, grid->transform_name);
- }
if (!BLI_listbase_is_empty(&ubo_inputs_)) {
/* NOTE: generate_uniform_buffer() should have sorted the inputs before this. */
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 711a3943a25..3d5e9723103 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -219,11 +219,6 @@ ListBase GPU_material_textures(GPUMaterial *material)
return material->graph.textures;
}
-ListBase GPU_material_volume_grids(GPUMaterial *material)
-{
- return material->graph.volume_grids;
-}
-
GPUUniformAttrList *GPU_material_uniform_attributes(GPUMaterial *material)
{
GPUUniformAttrList *attrs = &material->graph.uniform_attrs;
@@ -599,11 +594,6 @@ void GPU_material_status_set(GPUMaterial *mat, eGPUMaterialStatus status)
/* Code generation */
-bool GPU_material_is_volume_shader(GPUMaterial *mat)
-{
- return mat->is_volume_shader;
-}
-
bool GPU_material_has_surface_output(GPUMaterial *mat)
{
return mat->has_surface_output;
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
index d9143a12d5b..7f96a3b01c4 100644
--- a/source/blender/gpu/intern/gpu_node_graph.c
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -20,6 +20,7 @@
#include "BLI_utildefines.h"
#include "GPU_texture.h"
+#include "GPU_vertex_format.h"
#include "gpu_material_library.h"
#include "gpu_node_graph.h"
@@ -102,14 +103,6 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType
input->source = GPU_SOURCE_TEX_TILED_MAPPING;
input->texture = link->texture;
break;
- case GPU_NODE_LINK_VOLUME_GRID:
- input->source = GPU_SOURCE_VOLUME_GRID;
- input->volume_grid = link->volume_grid;
- break;
- case GPU_NODE_LINK_VOLUME_GRID_TRANSFORM:
- input->source = GPU_SOURCE_VOLUME_GRID_TRANSFORM;
- input->volume_grid = link->volume_grid;
- break;
case GPU_NODE_LINK_ATTR:
input->source = GPU_SOURCE_ATTR;
input->attr = link->attr;
@@ -335,6 +328,45 @@ void gpu_node_graph_finalize_uniform_attrs(GPUNodeGraph *graph)
/* Attributes and Textures */
+static char attr_prefix_get(CustomDataType type)
+{
+ switch (type) {
+ case CD_MTFACE:
+ return 'u';
+ case CD_TANGENT:
+ return 't';
+ case CD_MCOL:
+ case CD_PROP_BYTE_COLOR:
+ return 'c';
+ case CD_PROP_COLOR:
+ return 'c';
+ case CD_AUTO_FROM_NAME:
+ return 'a';
+ case CD_HAIRLENGTH:
+ return 'l';
+ default:
+ BLI_assert_msg(0, "GPUVertAttr Prefix type not found : This should not happen!");
+ return '\0';
+ }
+}
+
+static void attr_input_name(GPUMaterialAttribute *attr)
+{
+ /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */
+ if (attr->type == CD_ORCO) {
+ /* OPTI: orco is computed from local positions, but only if no modifier is present. */
+ STRNCPY(attr->input_name, "orco");
+ }
+ else {
+ attr->input_name[0] = attr_prefix_get(attr->type);
+ attr->input_name[1] = '\0';
+ if (attr->name[0] != '\0') {
+ /* XXX FIXME: see notes in mesh_render_data_create() */
+ GPU_vertformat_safe_attr_name(attr->name, &attr->input_name[1], GPU_MAX_SAFE_ATTR_NAME);
+ }
+ }
+}
+
/** Add a new varying attribute of given type and name. Returns NULL if out of slots. */
static GPUMaterialAttribute *gpu_node_graph_add_attribute(GPUNodeGraph *graph,
CustomDataType type,
@@ -360,6 +392,7 @@ static GPUMaterialAttribute *gpu_node_graph_add_attribute(GPUNodeGraph *graph,
attr = MEM_callocN(sizeof(*attr), __func__);
attr->type = type;
STRNCPY(attr->name, name);
+ attr_input_name(attr);
attr->id = num_attributes;
BLI_addtail(&graph->attributes, attr);
}
@@ -443,35 +476,6 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph,
return tex;
}
-static GPUMaterialVolumeGrid *gpu_node_graph_add_volume_grid(GPUNodeGraph *graph,
- const char *name,
- eGPUVolumeDefaultValue default_value)
-{
- /* Find existing volume grid. */
- int num_grids = 0;
- GPUMaterialVolumeGrid *grid = graph->volume_grids.first;
- for (; grid; grid = grid->next) {
- if (STREQ(grid->name, name) && grid->default_value == default_value) {
- break;
- }
- num_grids++;
- }
-
- /* Add new requested volume grid. */
- if (grid == NULL) {
- grid = MEM_callocN(sizeof(*grid), __func__);
- grid->name = BLI_strdup(name);
- grid->default_value = default_value;
- BLI_snprintf(grid->sampler_name, sizeof(grid->sampler_name), "vsamp%d", num_grids);
- BLI_snprintf(grid->transform_name, sizeof(grid->transform_name), "vtfm%d", num_grids);
- BLI_addtail(&graph->volume_grids, grid);
- }
-
- grid->users++;
-
- return grid;
-}
-
/* Creating Inputs */
GPUNodeLink *GPU_attribute(GPUMaterial *mat, const CustomDataType type, const char *name)
@@ -496,6 +500,18 @@ GPUNodeLink *GPU_attribute(GPUMaterial *mat, const CustomDataType type, const ch
return link;
}
+GPUNodeLink *GPU_attribute_with_default(GPUMaterial *mat,
+ const CustomDataType type,
+ const char *name,
+ eGPUDefaultValue default_value)
+{
+ GPUNodeLink *link = GPU_attribute(mat, type, name);
+ if (link->link_type == GPU_NODE_LINK_ATTR) {
+ link->attr->default_value = default_value;
+ }
+ return link;
+}
+
GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat, const char *name, bool use_dupli)
{
GPUNodeGraph *graph = gpu_material_node_graph(mat);
@@ -586,39 +602,6 @@ GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *ro
return link;
}
-GPUNodeLink *GPU_volume_grid(GPUMaterial *mat,
- const char *name,
- eGPUVolumeDefaultValue default_value)
-{
- /* NOTE: this could be optimized by automatically merging duplicate
- * lookups of the same attribute. */
- GPUNodeGraph *graph = gpu_material_node_graph(mat);
- GPUNodeLink *link = gpu_node_link_create();
- link->link_type = GPU_NODE_LINK_VOLUME_GRID;
- link->volume_grid = gpu_node_graph_add_volume_grid(graph, name, default_value);
-
- GPUNodeLink *transform_link = gpu_node_link_create();
- transform_link->link_type = GPU_NODE_LINK_VOLUME_GRID_TRANSFORM;
- transform_link->volume_grid = link->volume_grid;
- transform_link->volume_grid->users++;
-
- GPUNodeLink *cos_link = GPU_attribute(mat, CD_ORCO, "");
-
- /* Two special cases, where we adjust the output values of smoke grids to
- * bring the into standard range without having to modify the grid values. */
- if (STREQ(name, "color")) {
- GPU_link(mat, "node_attribute_volume_color", link, transform_link, cos_link, &link);
- }
- else if (STREQ(name, "temperature")) {
- GPU_link(mat, "node_attribute_volume_temperature", link, transform_link, cos_link, &link);
- }
- else {
- GPU_link(mat, "node_attribute_volume", link, transform_link, cos_link, &link);
- }
-
- return link;
-}
-
/* Creating Nodes */
bool GPU_link(GPUMaterial *mat, const char *name, ...)
@@ -767,9 +750,6 @@ static void gpu_inputs_free(ListBase *inputs)
else if (ELEM(input->source, GPU_SOURCE_TEX, GPU_SOURCE_TEX_TILED_MAPPING)) {
input->texture->users--;
}
- else if (ELEM(input->source, GPU_SOURCE_VOLUME_GRID, GPU_SOURCE_VOLUME_GRID_TRANSFORM)) {
- input->volume_grid->users--;
- }
if (input->link) {
gpu_node_link_free(input->link);
@@ -816,10 +796,6 @@ void gpu_node_graph_free(GPUNodeGraph *graph)
BLI_freelistN(&graph->material_functions);
gpu_node_graph_free_nodes(graph);
- LISTBASE_FOREACH (GPUMaterialVolumeGrid *, grid, &graph->volume_grids) {
- MEM_SAFE_FREE(grid->name);
- }
- BLI_freelistN(&graph->volume_grids);
BLI_freelistN(&graph->textures);
BLI_freelistN(&graph->attributes);
GPU_uniform_attr_list_free(&graph->uniform_attrs);
@@ -894,14 +870,6 @@ void gpu_node_graph_prune_unused(GPUNodeGraph *graph)
}
}
- for (GPUMaterialVolumeGrid *grid = graph->volume_grids.first, *next = NULL; grid; grid = next) {
- next = grid->next;
- if (grid->users == 0) {
- MEM_SAFE_FREE(grid->name);
- BLI_freelinkN(&graph->volume_grids, grid);
- }
- }
-
GPUUniformAttrList *uattrs = &graph->uniform_attrs;
LISTBASE_FOREACH_MUTABLE (GPUUniformAttr *, attr, &uattrs->list) {
diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h
index 024119e1c24..ae472d5b7aa 100644
--- a/source/blender/gpu/intern/gpu_node_graph.h
+++ b/source/blender/gpu/intern/gpu_node_graph.h
@@ -34,8 +34,6 @@ typedef enum eGPUDataSource {
GPU_SOURCE_STRUCT,
GPU_SOURCE_TEX,
GPU_SOURCE_TEX_TILED_MAPPING,
- GPU_SOURCE_VOLUME_GRID,
- GPU_SOURCE_VOLUME_GRID_TRANSFORM,
GPU_SOURCE_FUNCTION_CALL,
} eGPUDataSource;
@@ -48,8 +46,6 @@ typedef enum {
GPU_NODE_LINK_IMAGE,
GPU_NODE_LINK_IMAGE_TILED,
GPU_NODE_LINK_IMAGE_TILED_MAPPING,
- GPU_NODE_LINK_VOLUME_GRID,
- GPU_NODE_LINK_VOLUME_GRID_TRANSFORM,
GPU_NODE_LINK_OUTPUT,
GPU_NODE_LINK_UNIFORM,
GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN,
@@ -90,8 +86,6 @@ struct GPUNodeLink {
const float *data;
/* GPU_NODE_LINK_COLORBAND */
struct GPUTexture **colorband;
- /* GPU_NODE_LINK_VOLUME_GRID */
- struct GPUMaterialVolumeGrid *volume_grid;
/* GPU_NODE_LINK_OUTPUT */
struct GPUOutput *output;
/* GPU_NODE_LINK_ATTR */
@@ -134,8 +128,6 @@ typedef struct GPUInput {
struct GPUMaterialAttribute *attr;
/* GPU_SOURCE_UNIFORM_ATTR */
struct GPUUniformAttr *uniform_attr;
- /* GPU_SOURCE_VOLUME_GRID | GPU_SOURCE_VOLUME_GRID_TRANSFORM */
- struct GPUMaterialVolumeGrid *volume_grid;
/* GPU_SOURCE_FUNCTION_CALL */
char function_call[64];
};
@@ -170,7 +162,6 @@ typedef struct GPUNodeGraph {
/* Requested attributes and textures. */
ListBase attributes;
ListBase textures;
- ListBase volume_grids;
/* The list of uniform attributes. */
GPUUniformAttrList uniform_attrs;
diff --git a/source/blender/gpu/intern/gpu_shader_builtin.c b/source/blender/gpu/intern/gpu_shader_builtin.c
index dfedb64ce61..1958ecedb28 100644
--- a/source/blender/gpu/intern/gpu_shader_builtin.c
+++ b/source/blender/gpu/intern/gpu_shader_builtin.c
@@ -402,19 +402,6 @@ GPUShader *GPU_shader_get_builtin_shader(eGPUBuiltinShader shader)
return GPU_shader_get_builtin_shader_with_config(shader, GPU_SHADER_CFG_DEFAULT);
}
-void GPU_shader_get_builtin_shader_code(eGPUBuiltinShader shader,
- const char **r_vert,
- const char **r_frag,
- const char **r_geom,
- const char **r_defines)
-{
- const GPUShaderStages *stages = &builtin_shader_stages[shader];
- *r_vert = stages->vert;
- *r_frag = stages->frag;
- *r_geom = stages->geom;
- *r_defines = stages->defs;
-}
-
void GPU_shader_free_builtin_shaders(void)
{
for (int i = 0; i < GPU_SHADER_CFG_LEN; i++) {
diff --git a/source/blender/gpu/intern/gpu_shader_create_info.hh b/source/blender/gpu/intern/gpu_shader_create_info.hh
index 3ab96d0d84a..7c827e237eb 100644
--- a/source/blender/gpu/intern/gpu_shader_create_info.hh
+++ b/source/blender/gpu/intern/gpu_shader_create_info.hh
@@ -627,7 +627,9 @@ struct ShaderCreateInfo {
Resource res(Resource::BindType::SAMPLER, slot);
res.sampler.type = type;
res.sampler.name = name;
- res.sampler.sampler = sampler;
+ /* Produces ASAN errors for the moment. */
+ // res.sampler.sampler = sampler;
+ UNUSED_VARS(sampler);
((freq == Frequency::PASS) ? pass_resources_ : batch_resources_).append(res);
interface_names_size_ += name.size() + 1;
return *(Self *)this;
diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc
index 9768318f3b6..51d470ef0c1 100644
--- a/source/blender/gpu/opengl/gl_shader.cc
+++ b/source/blender/gpu/opengl/gl_shader.cc
@@ -855,7 +855,7 @@ static char *glsl_patch_default_get()
STR_CONCAT(patch, slen, "#define gpu_InstanceIndex (gl_InstanceID + gpu_BaseInstance)\n");
/* Array compat. */
- STR_CONCAT(patch, slen, "#define array(_type) _type[]\n");
+ STR_CONCAT(patch, slen, "#define gpu_Array(_type) _type[]\n");
/* Derivative sign can change depending on implementation. */
STR_CONCATF(patch, slen, "#define DFDX_SIGN %1.1f\n", GLContext::derivative_signs[0]);
@@ -882,7 +882,7 @@ static char *glsl_patch_compute_get()
STR_CONCAT(patch, slen, "#extension GL_ARB_compute_shader :enable\n");
/* Array compat. */
- STR_CONCAT(patch, slen, "#define array(_type) _type[]\n");
+ STR_CONCAT(patch, slen, "#define gpu_Array(_type) _type[]\n");
BLI_assert(slen < sizeof(patch));
return patch;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl
index faf37db3ea6..2ae53b35b3f 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl
@@ -1,3 +1,17 @@
+
+void node_attribute_color(vec4 attr, out vec4 out_attr)
+{
+ out_attr = attr_load_color_post(attr);
+}
+
+void node_attribute_temperature(vec4 attr, out vec4 out_attr)
+{
+ out_attr.x = attr_load_temperature_post(attr.x);
+ out_attr.y = 0.0;
+ out_attr.z = 0.0;
+ out_attr.w = 1.0;
+}
+
void node_attribute(
vec4 attr, out vec4 outcol, out vec3 outvec, out float outf, out float outalpha)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
index 2885bf4e082..a8b4b039370 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
@@ -1,6 +1,5 @@
#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
-
void node_hair_info(float hair_length,
out float is_strand,
out float intercept,
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl
index 1b1fed9502e..ad3d4737193 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl
@@ -1,6 +1,5 @@
#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
-
void node_point_info(out vec3 position, out float radius, out float random)
{
#ifdef POINTCLOUD_SHADER
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl
index 89091316823..da131978f72 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl
@@ -1,6 +1,5 @@
#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
-
void node_tex_environment_equirectangular(vec3 co, out vec3 uv)
{
vec3 nco = normalize(co);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl
deleted file mode 100644
index 464cf5227b4..00000000000
--- a/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl
+++ /dev/null
@@ -1,51 +0,0 @@
-
-/* Uniforms to convert smoke grid values into standard range. */
-uniform vec3 volumeColor = vec3(1.0);
-uniform vec2 volumeTemperature = vec2(0.0);
-
-/* Generic volume attribute. */
-void node_attribute_volume(sampler3D tex, mat4 transform, vec3 cos, out vec3 outvec)
-{
- /* Optional per-grid transform. */
- if (transform[3][3] != 0.0) {
- cos = (transform * vec4(cos, 1.0)).xyz;
- }
-
- outvec = texture(tex, cos).rgb;
-}
-
-/* Special color attribute for smoke. */
-void node_attribute_volume_color(sampler3D tex, mat4 transform, vec3 cos, out vec3 outvec)
-{
- /* Optional per-grid transform. */
- if (transform[3][3] != 0.0) {
- cos = (transform * vec4(cos, 1.0)).xyz;
- }
-
- /* Density is premultiplied for interpolation, divide it out here. */
- vec4 value = texture(tex, cos).rgba;
- if (value.a > 1e-8) {
- value.rgb /= value.a;
- }
-
- outvec = value.rgb * volumeColor;
-}
-
-/* Special temperature attribute for smoke. */
-void node_attribute_volume_temperature(sampler3D tex, mat4 transform, vec3 cos, out float outf)
-{
- /* Optional per-grid transform. */
- if (transform[3][3] != 0.0) {
- cos = (transform * vec4(cos, 1.0)).xyz;
- }
-
- float value = texture(tex, cos).r;
- if (volumeTemperature.x < volumeTemperature.y) {
- outf = (value > 0.01) ?
- volumeTemperature.x + value * (volumeTemperature.y - volumeTemperature.x) :
- 0.0;
- }
- else {
- outf = value;
- }
-}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl
index 1127c34b3ac..21c4aba0ffe 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl
@@ -10,9 +10,9 @@ void node_volume_principled(vec4 color,
vec4 blackbody_tint,
float temperature,
float weight,
- float density_attribute,
+ vec4 density_attribute,
vec4 color_attribute,
- float temperature_attribute,
+ vec4 temperature_attribute,
sampler1DArray spectrummap,
float layer,
out Closure result)
@@ -25,7 +25,7 @@ void node_volume_principled(vec4 color,
density = max(density, 0.0);
if (density > 1e-5) {
- density = max(density * density_attribute, 0.0);
+ density = max(density * density_attribute.x, 0.0);
}
if (density > 1e-5) {
@@ -47,7 +47,7 @@ void node_volume_principled(vec4 color,
if (blackbody_intensity > 1e-3) {
/* Add temperature from attribute. */
- float T = max(temperature * max(temperature_attribute, 0.0), 0.0);
+ float T = max(temperature * max(temperature_attribute.x, 0.0), 0.0);
/* Stefan-Boltzman law. */
float T2 = T * T;
diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc
index bbb196dc383..07b185ffd64 100644
--- a/source/blender/io/alembic/exporter/abc_writer_mesh.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc
@@ -359,7 +359,7 @@ void ABCGenericMeshWriter::write_arb_geo_params(struct Mesh *me)
else {
arb_geom_params = abc_poly_mesh_.getSchema().getArbGeomParams();
}
- write_custom_data(arb_geom_params, m_custom_data_config, &me->ldata, CD_MLOOPCOL);
+ write_custom_data(arb_geom_params, m_custom_data_config, &me->ldata, CD_PROP_BYTE_COLOR);
}
bool ABCGenericMeshWriter::get_velocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels)
diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc
index c413fbf0ff9..45bf898f3f5 100644
--- a/source/blender/io/alembic/intern/abc_customdata.cc
+++ b/source/blender/io/alembic/intern/abc_customdata.cc
@@ -294,7 +294,7 @@ void write_custom_data(const OCompoundProperty &prop,
write_uv(prop, config, cd_data, name);
}
- else if (cd_data_type == CD_MLOOPCOL) {
+ else if (cd_data_type == CD_PROP_BYTE_COLOR) {
write_mcol(prop, config, cd_data, name);
}
}
@@ -412,7 +412,7 @@ static void read_custom_data_mcols(const std::string &iobject_full_name,
/* Read the vertex colors */
void *cd_data = config.add_customdata_cb(
- config.mesh, prop_header.getName().c_str(), CD_MLOOPCOL);
+ config.mesh, prop_header.getName().c_str(), CD_PROP_BYTE_COLOR);
MCol *cfaces = static_cast<MCol *>(cd_data);
MPoly *mpolys = config.mpoly;
MLoop *mloops = config.mloop;
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc
index fe2b0470432..2d2dcfb1f42 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc
@@ -245,7 +245,7 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
static void process_no_normals(CDStreamConfig &config)
{
/* Absence of normals in the Alembic mesh is interpreted as 'smooth'. */
- BKE_mesh_calc_normals(config.mesh);
+ BKE_mesh_normals_tag_dirty(config.mesh);
}
static void process_loop_normals(CDStreamConfig &config, const N3fArraySamplePtr loop_normals_ptr)
@@ -382,7 +382,7 @@ static void *add_customdata_cb(Mesh *mesh, const char *name, int data_type)
int numloops;
/* unsupported custom data type -- don't do anything. */
- if (!ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) {
+ if (!ELEM(cd_data_type, CD_MLOOPUV, CD_PROP_BYTE_COLOR)) {
return nullptr;
}
diff --git a/source/blender/io/collada/GeometryExporter.cpp b/source/blender/io/collada/GeometryExporter.cpp
index 3b21d423df5..3952a4ae334 100644
--- a/source/blender/io/collada/GeometryExporter.cpp
+++ b/source/blender/io/collada/GeometryExporter.cpp
@@ -378,12 +378,12 @@ void GeometryExporter::create_mesh_primitive_list(short material_index,
}
}
- int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
+ int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_PROP_BYTE_COLOR);
if (totlayer_mcol > 0) {
int map_index = 0;
for (int a = 0; a < totlayer_mcol; a++) {
- char *layer_name = bc_CustomData_get_layer_name(&me->ldata, CD_MLOOPCOL, a);
+ char *layer_name = bc_CustomData_get_layer_name(&me->ldata, CD_PROP_BYTE_COLOR, a);
COLLADASW::Input input4(COLLADASW::InputSemantic::COLOR,
makeUrl(makeVertexColorSourceId(geom_id, layer_name)),
(has_uvs) ? 3 : 2, /* all color layers have same index order */
@@ -468,7 +468,7 @@ void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me)
void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me)
{
/* Find number of vertex color layers */
- int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
+ int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_PROP_BYTE_COLOR);
if (totlayer_mcol == 0) {
return;
}
@@ -477,11 +477,11 @@ void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me)
for (int a = 0; a < totlayer_mcol; a++) {
map_index++;
- MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(&me->ldata, CD_MLOOPCOL, a);
+ MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(&me->ldata, CD_PROP_BYTE_COLOR, a);
COLLADASW::FloatSourceF source(mSW);
- char *layer_name = bc_CustomData_get_layer_name(&me->ldata, CD_MLOOPCOL, a);
+ char *layer_name = bc_CustomData_get_layer_name(&me->ldata, CD_PROP_BYTE_COLOR, a);
std::string layer_id = makeVertexColorSourceId(geom_id, layer_name);
source.setId(layer_id);
diff --git a/source/blender/io/collada/MeshImporter.cpp b/source/blender/io/collada/MeshImporter.cpp
index fc94e912417..6e109353be8 100644
--- a/source/blender/io/collada/MeshImporter.cpp
+++ b/source/blender/io/collada/MeshImporter.cpp
@@ -471,9 +471,9 @@ void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me)
collada_mesh->getColors().getInputInfosArray()[i];
COLLADAFW::String colname = extract_vcolname(info->mName);
CustomData_add_layer_named(
- &me->ldata, CD_MLOOPCOL, CD_DEFAULT, nullptr, me->totloop, colname.c_str());
+ &me->ldata, CD_PROP_BYTE_COLOR, CD_DEFAULT, nullptr, me->totloop, colname.c_str());
}
- me->mloopcol = (MLoopCol *)CustomData_get_layer_n(&me->ldata, CD_MLOOPCOL, 0);
+ me->mloopcol = (MLoopCol *)CustomData_get_layer_n(&me->ldata, CD_PROP_BYTE_COLOR, 0);
}
}
}
@@ -724,7 +724,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
COLLADAFW::IndexList &color_index_list = *mp->getColorIndices(vcolor_index);
COLLADAFW::String colname = extract_vcolname(color_index_list.getName());
MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_named(
- &me->ldata, CD_MLOOPCOL, colname.c_str());
+ &me->ldata, CD_PROP_BYTE_COLOR, colname.c_str());
if (mloopcol == nullptr) {
fprintf(stderr,
"Collada import: Mesh [%s] : Unknown reference to VCOLOR [#%s].\n",
@@ -1057,7 +1057,6 @@ Object *MeshImporter::create_mesh_object(
Mesh *new_mesh = uid_mesh_map[*geom_uid];
BKE_mesh_assign_object(m_bmain, ob, new_mesh);
- BKE_mesh_calc_normals(new_mesh);
/* Because BKE_mesh_assign_object would have already decreased it... */
id_us_plus(&old_mesh->id);
diff --git a/source/blender/io/common/intern/string_utils.cc b/source/blender/io/common/intern/string_utils.cc
index 01107b0866e..3a12250e14b 100644
--- a/source/blender/io/common/intern/string_utils.cc
+++ b/source/blender/io/common/intern/string_utils.cc
@@ -7,7 +7,7 @@
* their standard libraries are not quite there yet.
* LLVM/libc++ only has a float parser since LLVM 14,
* and gcc/libstdc++ since 11.1. So until at least these are
- * the mininum spec, use an external library. */
+ * the minimum spec, use an external library. */
#include "fast_float.h"
#include <charconv>
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 646d1ba1fde..328b4109616 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -149,7 +149,7 @@ static void *add_customdata_cb(Mesh *mesh, const char *name, const int data_type
int numloops;
/* unsupported custom data type -- don't do anything. */
- if (!ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) {
+ if (!ELEM(cd_data_type, CD_MLOOPUV, CD_PROP_BYTE_COLOR)) {
return nullptr;
}
@@ -457,7 +457,7 @@ void USDMeshReader::read_colors(Mesh *mesh, const double motionSampleTime)
return;
}
- void *cd_ptr = add_customdata_cb(mesh, "displayColors", CD_MLOOPCOL);
+ void *cd_ptr = add_customdata_cb(mesh, "displayColors", CD_PROP_BYTE_COLOR);
if (!cd_ptr) {
std::cerr << "WARNING: Couldn't add displayColors custom data.\n";
diff --git a/source/blender/io/usd/tests/usd_tests_common.h b/source/blender/io/usd/tests/usd_tests_common.h
index b298a253ddc..7f6ae558354 100644
--- a/source/blender/io/usd/tests/usd_tests_common.h
+++ b/source/blender/io/usd/tests/usd_tests_common.h
@@ -8,7 +8,7 @@ namespace blender::io::usd {
/* Calls the function to load the USD plugins from the
* USD data directory under the Blender bin directory
- * that was supplied as the --test-release-dir flag to ctest.
+ * that was supplied as the --test-release-dir flag to `ctest`.
* Thus function must be called before instantiating a USD
* stage to avoid errors. The returned string is the path to
* the USD data files directory from which the plugins were
diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h
index ee78b610276..3e7a4431bf5 100644
--- a/source/blender/makesdna/DNA_brush_enums.h
+++ b/source/blender/makesdna/DNA_brush_enums.h
@@ -610,6 +610,8 @@ typedef enum eBrushFalloffShape {
typedef enum eBrushCurvesSculptFlag {
BRUSH_CURVES_SCULPT_FLAG_SCALE_UNIFORM = (1 << 0),
BRUSH_CURVES_SCULPT_FLAG_GROW_SHRINK_INVERT = (1 << 1),
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH = (1 << 2),
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE = (1 << 3),
} eBrushCurvesSculptFlag;
#define MAX_BRUSH_PIXEL_RADIUS 500
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 2d879f5afa0..7d230b7d7a3 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -144,6 +144,8 @@ typedef struct BrushCurvesSculptSettings {
uint32_t flag;
/** When shrinking curves, they shouldn't become shorter than this length. */
float minimum_length;
+ /** Length of newly added curves when it is not interpolated from other curves. */
+ float curve_length;
} BrushCurvesSculptSettings;
typedef struct Brush {
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index 305b913b19e..6e18d442ee2 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -298,6 +298,13 @@ typedef struct Curve {
* original object data.
*/
const struct Curves *curve_eval;
+ /**
+ * If non-zero, the #editfont and #editnurb pointers are not owned by this #Curve. That means
+ * this curve is a container for the result of object geometry evaluation. This only works
+ * because evaluated object data never outlives original data.
+ */
+ char edit_data_from_original;
+ char _pad3[7];
void *batch_cache;
} Curve;
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index 858de733558..ef937fb139b 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -113,7 +113,7 @@ typedef enum CustomDataType {
CD_MTEXPOLY = 15, /* deprecated */
#endif
CD_MLOOPUV = 16,
- CD_MLOOPCOL = 17,
+ CD_PROP_BYTE_COLOR = 17,
CD_TANGENT = 18,
CD_MDISPS = 19,
CD_PREVIEW_MCOL = 20, /* for displaying weightpaint colors */
@@ -181,7 +181,7 @@ typedef enum CustomDataType {
#define CD_MASK_ORCO (1 << CD_ORCO)
// #define CD_MASK_MTEXPOLY (1 << CD_MTEXPOLY) /* DEPRECATED */
#define CD_MASK_MLOOPUV (1 << CD_MLOOPUV)
-#define CD_MASK_MLOOPCOL (1 << CD_MLOOPCOL)
+#define CD_MASK_PROP_BYTE_COLOR (1 << CD_PROP_BYTE_COLOR)
#define CD_MASK_TANGENT (1 << CD_TANGENT)
#define CD_MASK_MDISPS (1 << CD_MDISPS)
#define CD_MASK_PREVIEW_MCOL (1 << CD_PREVIEW_MCOL)
@@ -224,11 +224,11 @@ typedef enum CustomDataType {
/* All generic attributes. */
#define CD_MASK_PROP_ALL \
(CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 | CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 | \
- CD_MASK_PROP_COLOR | CD_MASK_PROP_STRING | CD_MASK_MLOOPCOL | CD_MASK_PROP_BOOL | \
+ CD_MASK_PROP_COLOR | CD_MASK_PROP_STRING | CD_MASK_PROP_BYTE_COLOR | CD_MASK_PROP_BOOL | \
CD_MASK_PROP_INT8)
/* All color attributes */
-#define CD_MASK_COLOR_ALL (CD_MASK_PROP_COLOR | CD_MASK_MLOOPCOL)
+#define CD_MASK_COLOR_ALL (CD_MASK_PROP_COLOR | CD_MASK_PROP_BYTE_COLOR)
typedef struct CustomData_MeshMasks {
uint64_t vmask;
diff --git a/source/blender/makesdna/DNA_fluid_defaults.h b/source/blender/makesdna/DNA_fluid_defaults.h
index fd48585792f..90a91c6c995 100644
--- a/source/blender/makesdna/DNA_fluid_defaults.h
+++ b/source/blender/makesdna/DNA_fluid_defaults.h
@@ -187,6 +187,7 @@
.cache_comp = SM_CACHE_LIGHT, \
.cache_high_comp = SM_CACHE_LIGHT, \
.cache_file_format = 0, \
+ .velocity_scale = 1.0f, \
}
/** \} */
diff --git a/source/blender/makesdna/DNA_fluid_types.h b/source/blender/makesdna/DNA_fluid_types.h
index 11780d99af8..5a1636879bb 100644
--- a/source/blender/makesdna/DNA_fluid_types.h
+++ b/source/blender/makesdna/DNA_fluid_types.h
@@ -670,7 +670,10 @@ typedef struct FluidDomainSettings {
char interp_method;
char gridlines_color_field; /* Simulation field used to color map onto gridlines. */
char gridlines_cell_filter;
- char _pad10[7]; /* Unused. */
+ char _pad10[3]; /* Unused. */
+
+ /* Velocity factor for motion blur rendering. */
+ float velocity_scale;
/* OpenVDB cache options. */
int openvdb_compression;
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 2b4858d4106..cd4676ee08e 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -221,7 +221,7 @@ typedef struct Mesh {
/**
* The active vertex corner color layer, if it exists. Also called "Vertex Color" in Blender's
* UI, even though it is stored per face corner.
- * \note This pointer is for convenient access to the #CD_MLOOPCOL layer in #ldata.
+ * \note This pointer is for convenient access to the #CD_PROP_BYTE_COLOR layer in #ldata.
*/
struct MLoopCol *mloopcol;
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index d6c1040110f..bfe967fcde5 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1014,23 +1014,8 @@ typedef struct Sculpt {
struct Object *gravity_object;
} Sculpt;
-typedef enum CurvesSculptFlag {
- CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH = (1 << 0),
- CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE = (1 << 1),
-} CurvesSculptFlag;
-
typedef struct CurvesSculpt {
Paint paint;
- /** Minimum distance between newly added curves on a surface. */
- float distance;
-
- /** CurvesSculptFlag. */
- uint32_t flag;
-
- /** Length of newly added curves when it is not interpolated from other curves. */
- float curve_length;
-
- char _pad[4];
} CurvesSculpt;
typedef struct UvSculpt {
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 8d527caa361..bce124a26cf 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -1968,8 +1968,7 @@ typedef struct SpreadsheetRowFilter {
float value_float2[2];
float value_float3[3];
float value_color[4];
-
- char _pad1[4];
+ uint8_t value_byte_color[4];
} SpreadsheetRowFilter;
typedef enum eSpaceSpreadsheet_RowFilterFlag {
@@ -2006,6 +2005,7 @@ typedef enum eSpreadsheetColumnValueType {
SPREADSHEET_VALUE_TYPE_COLOR = 5,
SPREADSHEET_VALUE_TYPE_INSTANCES = 6,
SPREADSHEET_VALUE_TYPE_STRING = 7,
+ SPREADSHEET_VALUE_TYPE_BYTE_COLOR = 8,
} eSpreadsheetColumnValueType;
/**
diff --git a/source/blender/makesdna/DNA_volume_defaults.h b/source/blender/makesdna/DNA_volume_defaults.h
index 2025d664d40..ee98f0ea4fd 100644
--- a/source/blender/makesdna/DNA_volume_defaults.h
+++ b/source/blender/makesdna/DNA_volume_defaults.h
@@ -36,7 +36,8 @@
.frame_duration = 0, \
.display = _DNA_DEFAULT_VolumeDisplay, \
.render = _DNA_DEFAULT_VolumeRender, \
- }
+ .velocity_scale = 1.0f, \
+}
/** \} */
diff --git a/source/blender/makesdna/DNA_volume_types.h b/source/blender/makesdna/DNA_volume_types.h
index f2f53bc910f..a2e558aa790 100644
--- a/source/blender/makesdna/DNA_volume_types.h
+++ b/source/blender/makesdna/DNA_volume_types.h
@@ -24,6 +24,11 @@ typedef struct Volume_Runtime {
/** Default simplify level for volume grids loaded from files. */
int default_simplify_level;
+
+ /* Names for scalar grids which would need to be merged to recompose the velocity grid. */
+ char velocity_x_grid[64];
+ char velocity_y_grid[64];
+ char velocity_z_grid[64];
} Volume_Runtime;
typedef struct VolumeDisplay {
@@ -75,6 +80,18 @@ typedef struct Volume {
VolumeRender render;
VolumeDisplay display;
+ /* Velocity field name. */
+ char velocity_grid[64];
+
+ char _pad3[3];
+
+ /* Unit of time the velocity vectors are expressed in.
+ * This uses the same enumeration values as #CacheFile.velocity_unit. */
+ char velocity_unit;
+
+ /* Factor for velocity vector for artistic control. */
+ float velocity_scale;
+
/* Draw Cache */
void *batch_cache;
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index ade0fcdb13f..cfd0c986df9 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -364,7 +364,7 @@ typedef struct wmKeyMapItem {
short type;
/** KM_ANY, KM_PRESS, KM_NOTHING etc. */
int8_t val;
- /** Use when `val == KM_CLICK_DRAG`, */
+ /** Use when `val == KM_CLICK_DRAG`. */
int8_t direction;
/** `oskey` also known as apple, windows-key or super. */
short shift, ctrl, alt, oskey;
diff --git a/source/blender/makesrna/RNA_enum_items.h b/source/blender/makesrna/RNA_enum_items.h
index 6e2c898d691..6539d636697 100644
--- a/source/blender/makesrna/RNA_enum_items.h
+++ b/source/blender/makesrna/RNA_enum_items.h
@@ -212,6 +212,8 @@ DEF_ENUM(rna_enum_subdivision_boundary_smooth_items)
DEF_ENUM(rna_enum_transform_orientation_items)
+DEF_ENUM(rna_enum_velocity_unit_items)
+
/* Not available to RNA pre-processing (`makesrna`).
* Defined in editors for example. */
#ifndef RNA_MAKESRNA
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 8d022338d7a..df92601dd0c 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -1047,6 +1047,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
RNA_def_property_update(prop, 0, "rna_Bone_bbone_handle_update");
}
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_PTR_NO_OWNERSHIP);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
RNA_def_property_ui_text(
prop, "B-Bone Start Handle", "Bone that serves as the start handle for the B-Bone curve");
@@ -1091,6 +1092,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
RNA_def_property_update(prop, 0, "rna_Bone_bbone_handle_update");
}
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_PTR_NO_OWNERSHIP);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
RNA_def_property_ui_text(
prop, "B-Bone End Handle", "Bone that serves as the end handle for the B-Bone curve");
diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c
index b11250cf891..5efbebc9b97 100644
--- a/source/blender/makesrna/intern/rna_attribute.c
+++ b/source/blender/makesrna/intern/rna_attribute.c
@@ -28,7 +28,7 @@ const EnumPropertyItem rna_enum_attribute_type_items[] = {
{CD_PROP_INT32, "INT", 0, "Integer", "32-bit integer"},
{CD_PROP_FLOAT3, "FLOAT_VECTOR", 0, "Vector", "3D vector with floating-point values"},
{CD_PROP_COLOR, "FLOAT_COLOR", 0, "Color", "RGBA color with floating-point values"},
- {CD_MLOOPCOL, "BYTE_COLOR", 0, "Byte Color", "RGBA color with 8-bit values"},
+ {CD_PROP_BYTE_COLOR, "BYTE_COLOR", 0, "Byte Color", "RGBA color with 8-bit values"},
{CD_PROP_STRING, "STRING", 0, "String", "Text string"},
{CD_PROP_BOOL, "BOOLEAN", 0, "Boolean", "True or false"},
{CD_PROP_FLOAT2, "FLOAT2", 0, "2D Vector", "2D vector with floating-point values"},
@@ -42,7 +42,7 @@ const EnumPropertyItem rna_enum_attribute_type_with_auto_items[] = {
{CD_PROP_INT32, "INT", 0, "Integer", "32-bit integer"},
{CD_PROP_FLOAT3, "FLOAT_VECTOR", 0, "Vector", "3D vector with floating-point values"},
{CD_PROP_COLOR, "FLOAT_COLOR", 0, "Color", "RGBA color with floating-point values"},
- {CD_MLOOPCOL, "BYTE_COLOR", 0, "Byte Color", "RGBA color with 8-bit values"},
+ {CD_PROP_BYTE_COLOR, "BYTE_COLOR", 0, "Byte Color", "RGBA color with 8-bit values"},
{CD_PROP_STRING, "STRING", 0, "String", "Text string"},
{CD_PROP_BOOL, "BOOLEAN", 0, "Boolean", "True or false"},
{CD_PROP_FLOAT2, "FLOAT2", 0, "2D Vector", "2D vector with floating-point values"},
@@ -113,7 +113,7 @@ static StructRNA *srna_by_custom_data_layer_type(const CustomDataType type)
return &RNA_FloatVectorAttribute;
case CD_PROP_COLOR:
return &RNA_FloatColorAttribute;
- case CD_MLOOPCOL:
+ case CD_PROP_BYTE_COLOR:
return &RNA_ByteColorAttribute;
case CD_PROP_STRING:
return &RNA_StringAttribute;
@@ -231,7 +231,7 @@ static void rna_Attribute_data_begin(CollectionPropertyIterator *iter, PointerRN
case CD_PROP_COLOR:
struct_size = sizeof(MPropCol);
break;
- case CD_MLOOPCOL:
+ case CD_PROP_BYTE_COLOR:
struct_size = sizeof(MLoopCol);
break;
case CD_PROP_STRING:
@@ -339,9 +339,17 @@ static int rna_Attributes_layer_skip(CollectionPropertyIterator *UNUSED(iter), v
return !(CD_TYPE_AS_MASK(layer->type) & CD_MASK_PROP_ALL);
}
-static int rna_Attributes_noncolor_layer_skip(CollectionPropertyIterator *UNUSED(iter), void *data)
+static int rna_Attributes_noncolor_layer_skip(CollectionPropertyIterator *iter, void *data)
{
CustomDataLayer *layer = (CustomDataLayer *)data;
+
+ /* Check valid domain here, too, keep in line with rna_AttributeGroup_color_length(). */
+ ID *id = iter->parent.owner_id;
+ AttributeDomain domain = BKE_id_attribute_domain(id, layer);
+ if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) {
+ return 1;
+ }
+
return !(CD_TYPE_AS_MASK(layer->type) & CD_MASK_COLOR_ALL) || (layer->flag & CD_FLAG_TEMPORARY);
}
@@ -423,7 +431,7 @@ int rna_AttributeGroup_color_length(PointerRNA *ptr)
{
return BKE_id_attributes_length(ptr->owner_id,
ATTR_DOMAIN_MASK_POINT | ATTR_DOMAIN_MASK_CORNER,
- CD_MASK_PROP_COLOR | CD_MASK_MLOOPCOL);
+ CD_MASK_PROP_COLOR | CD_MASK_PROP_BYTE_COLOR);
}
int rna_AttributeGroup_length(PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 25dd87b1e74..cc5141bde03 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -119,11 +119,11 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
{SCULPT_TOOL_CLOTH, "CLOTH", ICON_BRUSH_SCULPT_DRAW, "Cloth", ""},
{SCULPT_TOOL_SIMPLIFY, "SIMPLIFY", ICON_BRUSH_DATA, "Simplify", ""},
{SCULPT_TOOL_MASK, "MASK", ICON_BRUSH_MASK, "Mask", ""},
+ {SCULPT_TOOL_DRAW_FACE_SETS, "DRAW_FACE_SETS", ICON_BRUSH_MASK, "Draw Face Sets", ""},
{SCULPT_TOOL_DISPLACEMENT_ERASER, "DISPLACEMENT_ERASER", ICON_BRUSH_SCULPT_DRAW, "Multires Displacement Eraser", ""},
{SCULPT_TOOL_DISPLACEMENT_SMEAR, "DISPLACEMENT_SMEAR", ICON_BRUSH_SCULPT_DRAW, "Multires Displacement Smear", ""},
{SCULPT_TOOL_PAINT, "PAINT", ICON_BRUSH_SCULPT_DRAW, "Paint", ""},
{SCULPT_TOOL_SMEAR, "SMEAR", ICON_BRUSH_SCULPT_DRAW, "Smear", ""},
- {SCULPT_TOOL_DRAW_FACE_SETS, "DRAW_FACE_SETS", ICON_BRUSH_MASK, "Draw Face Sets", ""},
{0, NULL, 0, NULL, NULL},
};
/* clang-format on */
@@ -1944,6 +1944,23 @@ static void rna_def_curves_sculpt_options(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_text(
prop, "Minimum Length", "Avoid shrinking curves shorter than this length");
+
+ prop = RNA_def_property(srna, "interpolate_length", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH);
+ RNA_def_property_ui_text(
+ prop, "Interpolate Length", "Use length of the curves in close proximity");
+
+ prop = RNA_def_property(srna, "interpolate_shape", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE);
+ RNA_def_property_ui_text(
+ prop, "Interpolate Shape", "Use shape of the curves in close proximity");
+
+ prop = RNA_def_property(srna, "curve_length", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
+ RNA_def_property_ui_text(
+ prop,
+ "Curve Length",
+ "Length of newly added curves when it is not interpolated from other curves");
}
static void rna_def_brush(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_cachefile.c b/source/blender/makesrna/intern/rna_cachefile.c
index 62b08ebb281..c8b154b9b04 100644
--- a/source/blender/makesrna/intern/rna_cachefile.c
+++ b/source/blender/makesrna/intern/rna_cachefile.c
@@ -14,6 +14,12 @@
#include "rna_internal.h"
+const EnumPropertyItem rna_enum_velocity_unit_items[] = {
+ {CACHEFILE_VELOCITY_UNIT_SECOND, "SECOND", 0, "Second", ""},
+ {CACHEFILE_VELOCITY_UNIT_FRAME, "FRAME", 0, "Frame", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifdef RNA_RUNTIME
# include "BLI_math.h"
@@ -350,15 +356,9 @@ static void rna_def_cachefile(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_CacheFile_update");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- static const EnumPropertyItem velocity_unit_items[] = {
- {CACHEFILE_VELOCITY_UNIT_SECOND, "SECOND", 0, "Second", ""},
- {CACHEFILE_VELOCITY_UNIT_FRAME, "FRAME", 0, "Frame", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
prop = RNA_def_property(srna, "velocity_unit", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "velocity_unit");
- RNA_def_property_enum_items(prop, velocity_unit_items);
+ RNA_def_property_enum_items(prop, rna_enum_velocity_unit_items);
RNA_def_property_ui_text(
prop,
"Velocity Unit",
diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c
index dab3cd68d4c..e0ec146a248 100644
--- a/source/blender/makesrna/intern/rna_fluid.c
+++ b/source/blender/makesrna/intern/rna_fluid.c
@@ -2644,6 +2644,12 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_enum_items(prop, gridlines_cell_filter_items);
RNA_def_property_ui_text(prop, "Cell Type", "Cell type to be highlighted");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "velocity_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "velocity_scale");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Velocity Scale", "Factor to control the amount of motion blur");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_update");
}
static void rna_def_fluid_flow_settings(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 52af96e355d..0e7c332f6a4 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -753,9 +753,9 @@ static void rna_MeshUVLoopLayer_clone_set(PointerRNA *ptr, bool value)
/* vertex_color_layers */
-DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_color, ldata, CD_MLOOPCOL)
+DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_color, ldata, CD_PROP_BYTE_COLOR)
DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(
- vertex_color, ldata, CD_MLOOPCOL, active, MeshLoopColorLayer)
+ vertex_color, ldata, CD_PROP_BYTE_COLOR, active, MeshLoopColorLayer)
static void rna_MeshLoopColorLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
@@ -773,22 +773,22 @@ static int rna_MeshLoopColorLayer_data_length(PointerRNA *ptr)
static bool rna_MeshLoopColorLayer_active_render_get(PointerRNA *ptr)
{
- return rna_CustomDataLayer_active_get(ptr, rna_mesh_ldata(ptr), CD_MLOOPCOL, 1);
+ return rna_CustomDataLayer_active_get(ptr, rna_mesh_ldata(ptr), CD_PROP_BYTE_COLOR, 1);
}
static bool rna_MeshLoopColorLayer_active_get(PointerRNA *ptr)
{
- return rna_CustomDataLayer_active_get(ptr, rna_mesh_ldata(ptr), CD_MLOOPCOL, 0);
+ return rna_CustomDataLayer_active_get(ptr, rna_mesh_ldata(ptr), CD_PROP_BYTE_COLOR, 0);
}
static void rna_MeshLoopColorLayer_active_render_set(PointerRNA *ptr, bool value)
{
- rna_CustomDataLayer_active_set(ptr, rna_mesh_ldata(ptr), value, CD_MLOOPCOL, 1);
+ rna_CustomDataLayer_active_set(ptr, rna_mesh_ldata(ptr), value, CD_PROP_BYTE_COLOR, 1);
}
static void rna_MeshLoopColorLayer_active_set(PointerRNA *ptr, bool value)
{
- rna_CustomDataLayer_active_set(ptr, rna_mesh_ldata(ptr), value, CD_MLOOPCOL, 0);
+ rna_CustomDataLayer_active_set(ptr, rna_mesh_ldata(ptr), value, CD_PROP_BYTE_COLOR, 0);
}
/* sculpt_vertex_color_layers */
@@ -1340,7 +1340,7 @@ static char *rna_MeshLoopColorLayer_path(PointerRNA *ptr)
static char *rna_MeshColor_path(PointerRNA *ptr)
{
- return rna_LoopCustomData_data_path(ptr, "vertex_colors", CD_MLOOPCOL);
+ return rna_LoopCustomData_data_path(ptr, "vertex_colors", CD_PROP_BYTE_COLOR);
}
static char *rna_MeshVertColorLayer_path(PointerRNA *ptr)
@@ -1564,7 +1564,7 @@ static PointerRNA rna_Mesh_vertex_color_new(struct Mesh *me,
if (index != -1) {
ldata = rna_mesh_ldata_helper(me);
- cdl = &ldata->layers[CustomData_get_layer_index_n(ldata, CD_MLOOPCOL, index)];
+ cdl = &ldata->layers[CustomData_get_layer_index_n(ldata, CD_PROP_BYTE_COLOR, index)];
}
RNA_pointer_create(&me->id, &RNA_MeshLoopColorLayer, cdl, &ptr);
@@ -3182,6 +3182,7 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_pointer_funcs(
prop, "rna_Mesh_uv_layer_clone_get", "rna_Mesh_uv_layer_clone_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_ui_text(
prop, "Clone UV Loop Layer", "UV loop layer to be used as cloning source");
@@ -3197,6 +3198,7 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_pointer_funcs(
prop, "rna_Mesh_uv_layer_stencil_get", "rna_Mesh_uv_layer_stencil_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_ui_text(prop, "Mask UV Loop Layer", "UV loop layer to mask the painted area");
prop = RNA_def_property(srna, "uv_layer_stencil_index", PROP_INT, PROP_UNSIGNED);
diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c
index b1ebe583afc..8447074a3ef 100644
--- a/source/blender/makesrna/intern/rna_mesh_api.c
+++ b/source/blender/makesrna/intern/rna_mesh_api.c
@@ -159,7 +159,6 @@ static void rna_Mesh_normals_split_custom_set_from_vertices(Mesh *mesh,
static void rna_Mesh_transform(Mesh *mesh, float mat[16], bool shape_keys)
{
BKE_mesh_transform(mesh, (float(*)[4])mat, shape_keys);
- BKE_mesh_normals_tag_dirty(mesh);
DEG_id_tag_update(&mesh->id, 0);
}
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 16045e6cddf..456f774648a 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -1361,13 +1361,13 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf(
}
}
}
- else if (STREQ(RNA_property_identifier(prop), "layers_vcol_select_vert_src") ||
- STREQ(RNA_property_identifier(prop), "layers_vcol_select_loop_src")) {
+ else if (STREQ(RNA_property_identifier(prop), "layers_vcol_vert_select_src") ||
+ STREQ(RNA_property_identifier(prop), "layers_vcol_loop_select_src")) {
Object *ob_src = dtmd->ob_source;
if (ob_src) {
AttributeDomain domain = STREQ(RNA_property_identifier(prop),
- "layers_vcol_select_vert_src") ?
+ "layers_vcol_vert_select_src") ?
ATTR_DOMAIN_POINT :
ATTR_DOMAIN_CORNER;
@@ -1389,7 +1389,7 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf(
cdata = &me_eval->ldata;
}
- CustomDataType types[2] = {CD_PROP_COLOR, CD_MLOOPCOL};
+ CustomDataType types[2] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR};
int idx = 0;
for (int i = 0; i < 2; i++) {
@@ -1480,12 +1480,16 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_dst_itemf(
}
else if (STREQ(RNA_property_identifier(prop), "layers_vcol_vert_select_dst") ||
STREQ(RNA_property_identifier(prop), "layers_vcol_loop_select_dst")) {
+ int multilayer_index = STREQ(RNA_property_identifier(prop), "layers_vcol_vert_select_dst") ?
+ DT_MULTILAYER_INDEX_VCOL_VERT :
+ DT_MULTILAYER_INDEX_VCOL_LOOP;
+
/* Only list destination layers if we have a single source! */
- if (dtmd->layers_select_src[DT_MULTILAYER_INDEX_VCOL_LOOP] >= 0) {
+ if (dtmd->layers_select_src[multilayer_index] >= 0) {
Object *ob_dst = CTX_data_active_object(C); /* XXX Is this OK? */
if (ob_dst && ob_dst->data) {
- CustomDataType types[2] = {CD_PROP_COLOR, CD_MLOOPCOL};
+ CustomDataType types[2] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR};
Mesh *me_dst = ob_dst->data;
CustomData *cdata = STREQ(RNA_property_identifier(prop), "layers_vcol_vert_select_dst") ?
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 31b2d36dcfd..4195782db08 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -1420,8 +1420,13 @@ static bNodeSocket *rna_NodeTree_inputs_new(
bNodeSocket *sock = ntreeAddSocketInterface(ntree, SOCK_IN, type, name);
- ED_node_tree_propagate_change(NULL, bmain, ntree);
- WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
+ if (sock == NULL) {
+ BKE_report(reports, RPT_ERROR, "Unable to create socket");
+ }
+ else {
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
+ WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
+ }
return sock;
}
@@ -1435,8 +1440,13 @@ static bNodeSocket *rna_NodeTree_outputs_new(
bNodeSocket *sock = ntreeAddSocketInterface(ntree, SOCK_OUT, type, name);
- ED_node_tree_propagate_change(NULL, bmain, ntree);
- WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
+ if (sock == NULL) {
+ BKE_report(reports, RPT_ERROR, "Unable to create socket");
+ }
+ else {
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
+ WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
+ }
return sock;
}
@@ -2134,8 +2144,13 @@ static void rna_GeometryNodeCompare_data_type_update(Main *bmain, Scene *scene,
static bool generic_attribute_type_supported(const EnumPropertyItem *item)
{
- return ELEM(
- item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_COLOR, CD_PROP_BOOL, CD_PROP_INT32);
+ return ELEM(item->value,
+ CD_PROP_FLOAT,
+ CD_PROP_FLOAT3,
+ CD_PROP_COLOR,
+ CD_PROP_BOOL,
+ CD_PROP_INT32,
+ CD_PROP_BYTE_COLOR);
}
static const EnumPropertyItem *rna_GeometryNodeAttributeType_type_itemf(bContext *UNUSED(C),
PointerRNA *UNUSED(ptr),
@@ -2146,6 +2161,18 @@ static const EnumPropertyItem *rna_GeometryNodeAttributeType_type_itemf(bContext
return itemf_function_check(rna_enum_attribute_type_items, generic_attribute_type_supported);
}
+static bool generic_attribute_type_supported_with_socket(const EnumPropertyItem *item)
+{
+ return generic_attribute_type_supported(item) && !ELEM(item->value, CD_PROP_BYTE_COLOR);
+}
+static const EnumPropertyItem *rna_GeometryNodeAttributeType_type_with_socket_itemf(
+ bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ *r_free = true;
+ return itemf_function_check(rna_enum_attribute_type_items,
+ generic_attribute_type_supported_with_socket);
+}
+
static bool transfer_attribute_type_supported(const EnumPropertyItem *item)
{
return ELEM(
@@ -10209,7 +10236,8 @@ static void def_geo_raycast(StructRNA *srna)
prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_itemf");
+ RNA_def_property_enum_funcs(
+ prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_with_socket_itemf");
RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
RNA_def_property_ui_text(prop, "Data Type", "Type of data stored in attribute");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
@@ -10261,7 +10289,8 @@ static void def_geo_input_named_attribute(StructRNA *srna)
prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_itemf");
+ RNA_def_property_enum_funcs(
+ prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_with_socket_itemf");
RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
RNA_def_property_ui_text(prop, "Data Type", "The data type used to read the attribute values");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
@@ -10275,7 +10304,8 @@ static void def_geo_attribute_capture(StructRNA *srna)
prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_itemf");
+ RNA_def_property_enum_funcs(
+ prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_with_socket_itemf");
RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
RNA_def_property_ui_text(prop, "Data Type", "Type of data stored in attribute");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
@@ -10502,7 +10532,8 @@ static void def_geo_viewer(StructRNA *srna)
prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_itemf");
+ RNA_def_property_enum_funcs(
+ prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_with_socket_itemf");
RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
RNA_def_property_ui_text(prop, "Data Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
@@ -10532,7 +10563,8 @@ static void def_geo_field_at_index(StructRNA *srna)
prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom2");
RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_itemf");
+ RNA_def_property_enum_funcs(
+ prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_with_socket_itemf");
RNA_def_property_ui_text(prop, "Data Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
}
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 03f800d14d1..6f2264680c8 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -676,7 +676,7 @@ static void rna_ParticleSystem_mcol_on_emitter(ParticleSystem *particlesystem,
int vcol_no,
float r_mcol[3])
{
- if (!CustomData_has_layer(&modifier->mesh_final->ldata, CD_MLOOPCOL)) {
+ if (!CustomData_has_layer(&modifier->mesh_final->ldata, CD_PROP_BYTE_COLOR)) {
BKE_report(reports, RPT_ERROR, "Mesh has no VCol data");
zero_v3(r_mcol);
return;
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index 2390fdd72f0..a80e9573657 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -1360,7 +1360,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "custom_tx");
RNA_def_property_struct_type(prop, "PoseBone");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_PTR_NO_OWNERSHIP);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
RNA_def_property_ui_text(prop,
"Custom Shape Transform",
"Bone that defines the display transform of this custom shape");
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 373df6b7444..a7d673d3fe1 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -1474,6 +1474,11 @@ static int rna_property_override_diff_propptr(Main *bmain,
(is_array ? RNA_property_##_typename##_set_index((_ptr), (_prop), (_index), (_value)) : \
RNA_property_##_typename##_set((_ptr), (_prop), (_value)))
+/**
+ * /return `0` is matching, `-1` if `prop_a < prop_b`, `1` if `prop_a > prop_b`. Note that for
+ * unquantifiable properties (e.g. pointers or collections), return value should be interpreted as
+ * a boolean (false == matching, true == not matching).
+ */
int rna_property_override_diff_default(Main *bmain,
PropertyRNAOrID *prop_a,
PropertyRNAOrID *prop_b,
@@ -1932,25 +1937,25 @@ int rna_property_override_diff_default(Main *bmain,
}
else if (is_id || is_valid_for_diffing) {
if (equals || do_create) {
- const int eq = rna_property_override_diff_propptr(bmain,
- ptr_a->owner_id,
- ptr_b->owner_id,
- &iter_a.ptr,
- &iter_b.ptr,
- mode,
- no_ownership,
- no_prop_name,
- override,
- rna_path,
- rna_path_len,
- PROP_COLLECTION,
- propname_a,
- propname_b,
- idx_a,
- idx_b,
- flags,
- r_override_changed);
- equals = equals && eq;
+ const int comp = rna_property_override_diff_propptr(bmain,
+ ptr_a->owner_id,
+ ptr_b->owner_id,
+ &iter_a.ptr,
+ &iter_b.ptr,
+ mode,
+ no_ownership,
+ no_prop_name,
+ override,
+ rna_path,
+ rna_path_len,
+ PROP_COLLECTION,
+ propname_a,
+ propname_b,
+ idx_a,
+ idx_b,
+ flags,
+ r_override_changed);
+ equals = equals && (comp == 0);
}
}
@@ -2596,10 +2601,11 @@ bool rna_property_override_apply_default(Main *bmain,
int item_index_src, item_index_ref;
if (RNA_property_collection_lookup_string_index(
ptr_src, prop_src, opop->subitem_local_name, &item_ptr_src, &item_index_src) &&
- RNA_property_collection_lookup_int(
- ptr_src, prop_src, item_index_src + 1, &item_ptr_src) &&
- RNA_property_collection_lookup_string_index(
- ptr_dst, prop_dst, opop->subitem_local_name, &item_ptr_ref, &item_index_ref)) {
+ RNA_property_collection_lookup_string_index(ptr_dst,
+ prop_dst,
+ opop->subitem_reference_name,
+ &item_ptr_ref,
+ &item_index_ref)) {
is_valid = true;
item_index_dst = item_index_ref + 1;
}
@@ -2607,10 +2613,10 @@ bool rna_property_override_apply_default(Main *bmain,
if (!is_valid && opop->subitem_local_index >= 0) {
/* Find from index. */
if (RNA_property_collection_lookup_int(
- ptr_src, prop_src, opop->subitem_local_index + 1, &item_ptr_src) &&
+ ptr_src, prop_src, opop->subitem_local_index, &item_ptr_src) &&
RNA_property_collection_lookup_int(
- ptr_dst, prop_dst, opop->subitem_local_index, &item_ptr_ref)) {
- item_index_dst = opop->subitem_local_index + 1;
+ ptr_dst, prop_dst, opop->subitem_reference_index, &item_ptr_ref)) {
+ item_index_dst = opop->subitem_reference_index + 1;
is_valid = true;
}
}
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 7f0a9627a17..b647a823929 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -2630,7 +2630,7 @@ static const EnumPropertyItem *rna_UnitSettings_itemf_wrapper(const int system,
EnumPropertyItem adaptive = {0};
adaptive.identifier = "ADAPTIVE";
- adaptive.name = "Adaptive";
+ adaptive.name = N_("Adaptive");
adaptive.value = USER_UNIT_ADAPTIVE;
RNA_enum_item_add(&items, &totitem, &adaptive);
@@ -3092,7 +3092,10 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "lock_object_mode", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "object_flag", SCE_OBJECT_MODE_LOCK);
- RNA_def_property_ui_text(prop, "Lock Object Modes", "Restrict select to the current mode");
+ RNA_def_property_ui_text(prop,
+ "Lock Object Modes",
+ "Restrict selection to objects using the same mode as the active "
+ "object, to prevent accidental mode switch when selecting");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
static const EnumPropertyItem workspace_tool_items[] = {
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 37c687ddb2b..017e8bde7a1 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -562,8 +562,8 @@ static void rna_PaintModeSettings_canvas_source_update(bContext *C, PointerRNA *
{
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- /* When canvas source changes the pbvh would require updates when switching between color
- * attributes. */
+ /* When canvas source changes the PBVH would require updates when switching between color
+ * attributes. */
if (ob && ob->type == OB_MESH) {
BKE_texpaint_slots_refresh_object(scene, ob);
DEG_id_tag_update(&ob->id, 0);
@@ -1565,35 +1565,10 @@ static void rna_def_gpencil_sculpt(BlenderRNA *brna)
static void rna_def_curves_sculpt(BlenderRNA *brna)
{
StructRNA *srna;
- PropertyRNA *prop;
srna = RNA_def_struct(brna, "CurvesSculpt", "Paint");
RNA_def_struct_path_func(srna, "rna_CurvesSculpt_path");
RNA_def_struct_ui_text(srna, "Curves Sculpt Paint", "");
-
- prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_range(prop, 0.0f, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, 6);
- RNA_def_property_ui_text(
- prop, "Distance", "Radius around curves roots in which no new curves can be added");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-
- prop = RNA_def_property(srna, "interpolate_length", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH);
- RNA_def_property_ui_text(
- prop, "Interpolate Length", "Use length of the curves in close proximity");
-
- prop = RNA_def_property(srna, "interpolate_shape", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE);
- RNA_def_property_ui_text(
- prop, "Interpolate Shape", "Use shape of the curves in close proximity");
-
- prop = RNA_def_property(srna, "curve_length", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_range(prop, 0.0, FLT_MAX);
- RNA_def_property_ui_text(
- prop,
- "Curve Length",
- "Length of newly added curves when it is not interpolated from other curves");
}
void RNA_def_sculpt_paint(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index a27e699ef3d..3fd87a16d28 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -2169,11 +2169,12 @@ static void rna_def_channel(BlenderRNA *brna)
prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_CHANNEL_LOCK);
RNA_def_property_ui_text(prop, "Lock channel", "");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_CHANNEL_MUTE);
RNA_def_property_ui_text(prop, "Mute channel", "");
- RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_sound_update");
}
static void rna_def_editor(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index c40a2ed9260..1f68855622f 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -424,7 +424,7 @@ static const EnumPropertyItem rna_enum_shading_color_type_items[] = {
{V3D_SHADING_SINGLE_COLOR, "SINGLE", 0, "Single", "Show scene in a single color"},
{V3D_SHADING_OBJECT_COLOR, "OBJECT", 0, "Object", "Show object color"},
{V3D_SHADING_RANDOM_COLOR, "RANDOM", 0, "Random", "Show random object color"},
- {V3D_SHADING_VERTEX_COLOR, "VERTEX", 0, "Color", "Show active color attribute"},
+ {V3D_SHADING_VERTEX_COLOR, "VERTEX", 0, "Attribute", "Show active color attribute"},
{V3D_SHADING_TEXTURE_COLOR, "TEXTURE", 0, "Texture", "Show texture"},
{0, NULL, 0, NULL, NULL},
};
@@ -7752,6 +7752,12 @@ static void rna_def_spreadsheet_row_filter(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Color Value", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+ prop = RNA_def_property(srna, "value_byte_color", PROP_INT, PROP_NONE);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_range(prop, 0, 255);
+ RNA_def_property_ui_text(prop, "Byte Color Value", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
prop = RNA_def_property(srna, "value_string", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Text Value", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
diff --git a/source/blender/makesrna/intern/rna_volume.c b/source/blender/makesrna/intern/rna_volume.c
index 5b323629a80..12cb35b239d 100644
--- a/source/blender/makesrna/intern/rna_volume.c
+++ b/source/blender/makesrna/intern/rna_volume.c
@@ -78,6 +78,15 @@ static void rna_Volume_update_is_sequence(Main *bmain, Scene *scene, PointerRNA
DEG_relations_tag_update(bmain);
}
+static void rna_Volume_velocity_grid_set(PointerRNA *ptr, const char *value)
+{
+ Volume *volume = (Volume *)ptr->data;
+ if (!BKE_volume_set_velocity_grid_by_name(volume, value)) {
+ WM_reportf(RPT_ERROR, "Could not find grid with name %s", value);
+ }
+ WM_main_add_notifier(NC_GEOM | ND_DATA, volume);
+}
+
/* Grid */
static void rna_VolumeGrid_name_get(PointerRNA *ptr, char *value)
@@ -248,6 +257,7 @@ static void rna_def_volume_grid(BlenderRNA *brna)
RNA_def_property_string_funcs(
prop, "rna_VolumeGrid_name_get", "rna_VolumeGrid_name_length", NULL);
RNA_def_property_ui_text(prop, "Name", "Volume grid name");
+ RNA_def_struct_name_property(srna, prop);
prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -619,6 +629,55 @@ static void rna_def_volume(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "VolumeRender");
RNA_def_property_ui_text(prop, "Render", "Volume render settings for 3D viewport");
+ /* Velocity. */
+ prop = RNA_def_property(srna, "velocity_grid", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "velocity_grid");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Volume_velocity_grid_set");
+ RNA_def_property_ui_text(
+ prop,
+ "Velocity Grid",
+ "Name of the velocity field, or the base name if the velocity is split into multiple grids");
+
+ prop = RNA_def_property(srna, "velocity_unit", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "velocity_unit");
+ RNA_def_property_enum_items(prop, rna_enum_velocity_unit_items);
+ RNA_def_property_ui_text(
+ prop,
+ "Velocity Unit",
+ "Define how the velocity vectors are interpreted with regard to time, 'frame' means "
+ "the delta time is 1 frame, 'second' means the delta time is 1 / FPS");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+
+ prop = RNA_def_property(srna, "velocity_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "velocity_scale");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Velocity Scale", "Factor to control the amount of motion blur");
+
+ /* Scalar grids for velocity. */
+ prop = RNA_def_property(srna, "velocity_x_grid", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "runtime.velocity_x_grid");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop,
+ "Velocity X Grid",
+ "Name of the grid for the X axis component of the velocity field if it "
+ "was split into multiple grids");
+
+ prop = RNA_def_property(srna, "velocity_y_grid", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "runtime.velocity_y_grid");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop,
+ "Velocity Y Grid",
+ "Name of the grid for the Y axis component of the velocity field if it "
+ "was split into multiple grids");
+
+ prop = RNA_def_property(srna, "velocity_z_grid", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "runtime.velocity_z_grid");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop,
+ "Velocity Z Grid",
+ "Name of the grid for the Z axis component of the velocity field if it "
+ "was split into multiple grids");
+
/* Common */
rna_def_animdata_common(srna);
}
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 758858c8b1d..c44a4e0b438 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -789,13 +789,6 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
MEM_freeN(full_doubles_map);
}
- /* In case org dm has dirty normals, or we made some merging, mark normals as dirty in new mesh!
- * TODO: we may need to set other dirty flags as well?
- */
- if (use_recalc_normals) {
- BKE_mesh_normals_tag_dirty(result);
- }
-
if (vgroup_start_cap_remap) {
MEM_freeN(vgroup_start_cap_remap);
}
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index b6cceade4e2..a7364af10a3 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -229,8 +229,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
BM_mesh_free(bm);
- BKE_mesh_normals_tag_dirty(result);
-
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc
index 915428f99da..d47f2a130e3 100644
--- a/source/blender/modifiers/intern/MOD_boolean.cc
+++ b/source/blender/modifiers/intern/MOD_boolean.cc
@@ -501,7 +501,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh);
BM_mesh_free(bm);
- BKE_mesh_normals_tag_dirty(result);
}
if (result == nullptr) {
@@ -536,7 +535,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh);
BM_mesh_free(bm);
- BKE_mesh_normals_tag_dirty(result);
}
}
}
diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c
index 61959d242d8..687ff04cedf 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -263,8 +263,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, struct
MEM_freeN(edgeMap);
MEM_freeN(faceMap);
- BKE_mesh_normals_tag_dirty(result);
-
/* TODO(sybren): also copy flags & tags? */
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c
index 1cb308bb2a0..593610f5bad 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -120,7 +120,7 @@ static void deformVerts(ModifierData *md,
uint mvert_num = 0;
BKE_mesh_vert_coords_apply(mesh_src, vertexCos);
- BKE_mesh_calc_normals(mesh_src);
+ BKE_mesh_normals_tag_dirty(mesh_src);
current_time = DEG_get_ctime(ctx->depsgraph);
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index 67515478be5..70f028d6907 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -212,8 +212,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
TIMEIT_END(decim);
#endif
- BKE_mesh_normals_tag_dirty(result);
-
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c
index f8cf80b673c..1891ac5df7c 100644
--- a/source/blender/modifiers/intern/MOD_dynamicpaint.c
+++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c
@@ -91,7 +91,7 @@ static void requiredDataMask(Object *UNUSED(ob),
/* mcol */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT ||
surface->init_color_type == MOD_DPAINT_INITIAL_VERTEXCOLOR) {
- r_cddata_masks->lmask |= CD_MASK_MLOOPCOL;
+ r_cddata_masks->lmask |= CD_MASK_PROP_BYTE_COLOR;
}
/* CD_MDEFORMVERT */
if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index 14431e5ff2e..49ddcb9a61d 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -102,7 +102,6 @@ Mesh *doEdgeSplit(const Mesh *mesh, EdgeSplitModifierData *emd)
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
- BKE_mesh_normals_tag_dirty(result);
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index 87ff648f13d..9e2bb79138e 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -1102,7 +1102,6 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
/* finalization */
BKE_mesh_calc_edges_tessface(explode);
BKE_mesh_convert_mfaces_to_mpolys(explode);
- BKE_mesh_normals_tag_dirty(explode);
if (psmd->psys->lattice_deform_data) {
BKE_lattice_deform_data_destroy(psmd->psys->lattice_deform_data);
diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc
index cb26bd1b26b..900dee98268 100644
--- a/source/blender/modifiers/intern/MOD_mask.cc
+++ b/source/blender/modifiers/intern/MOD_mask.cc
@@ -748,7 +748,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx)
}
BKE_mesh_calc_edges_loose(result);
- BKE_mesh_normals_tag_dirty(result);
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index 7545bae43b3..85b6cf6a2cd 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -119,6 +119,7 @@ using blender::threading::EnumerableThreadSpecific;
using namespace blender::fn::multi_function_types;
using namespace blender::nodes::derived_node_tree_types;
using geo_log::GeometryAttributeInfo;
+using geo_log::NamedAttributeUsage;
static void initData(ModifierData *md)
{
@@ -997,30 +998,34 @@ static void store_computed_output_attributes(
const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(store.data.type());
const std::optional<AttributeMetaData> meta_data = component.attribute_get_meta_data(
store.name);
- if (meta_data.has_value() && meta_data->domain == store.domain &&
- meta_data->data_type == data_type) {
- /* Copy the data into an existing attribute. */
- blender::bke::WriteAttributeLookup write_attribute = component.attribute_try_get_for_write(
- store.name);
- if (write_attribute) {
- write_attribute.varray.set_all(store.data.data());
- if (write_attribute.tag_modified_fn) {
- write_attribute.tag_modified_fn();
- }
- }
- store.data.type().destruct_n(store.data.data(), store.data.size());
- MEM_freeN(store.data.data());
+
+ /* Attempt to remove the attribute if it already exists but the domain and type don't match.
+ * Removing the attribute won't succeed if it is built in and non-removable. */
+ if (meta_data.has_value() &&
+ (meta_data->domain != store.domain || meta_data->data_type != data_type)) {
+ component.attribute_try_delete(store.name);
}
- else {
- /* Replace the existing attribute with the new data. */
- if (meta_data.has_value()) {
- component.attribute_try_delete(store.name);
- }
- component.attribute_try_create(store.name,
- store.domain,
- blender::bke::cpp_type_to_custom_data_type(store.data.type()),
- AttributeInitMove(store.data.data()));
+
+ /* Try to create the attribute reusing the stored buffer. This will only succeed if the
+ * attribute didn't exist before, or if it existed but was removed above. */
+ if (component.attribute_try_create(
+ store.name,
+ store.domain,
+ blender::bke::cpp_type_to_custom_data_type(store.data.type()),
+ AttributeInitMove(store.data.data()))) {
+ continue;
+ }
+
+ OutputAttribute attribute = component.attribute_try_get_for_output_only(
+ store.name, store.domain, data_type);
+ if (attribute) {
+ attribute.varray().set_all(store.data.data());
+ attribute.save();
}
+
+ /* We were unable to reuse the data, so it must be destructed and freed. */
+ store.data.type().destruct_n(store.data.data(), store.data.size());
+ MEM_freeN(store.data.data());
}
}
@@ -1619,6 +1624,71 @@ static void output_attribute_panel_draw(const bContext *C, Panel *panel)
}
}
+static void used_attributes_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr);
+ NodesModifierData *nmd = static_cast<NodesModifierData *>(ptr->data);
+
+ if (nmd->runtime_eval_log == nullptr) {
+ return;
+ }
+ const geo_log::ModifierLog &log = *static_cast<geo_log::ModifierLog *>(nmd->runtime_eval_log);
+ Map<std::string, NamedAttributeUsage> usage_by_attribute;
+ log.foreach_node_log([&](const geo_log::NodeLog &node_log) {
+ for (const geo_log::UsedNamedAttribute &used_attribute : node_log.used_named_attributes()) {
+ usage_by_attribute.lookup_or_add_as(used_attribute.name,
+ used_attribute.usage) |= used_attribute.usage;
+ }
+ });
+
+ if (usage_by_attribute.is_empty()) {
+ uiItemL(layout, IFACE_("No named attributes used"), ICON_INFO);
+ return;
+ }
+
+ Vector<std::pair<StringRefNull, NamedAttributeUsage>> sorted_used_attribute;
+ for (auto &&item : usage_by_attribute.items()) {
+ sorted_used_attribute.append({item.key, item.value});
+ }
+ std::sort(sorted_used_attribute.begin(), sorted_used_attribute.end());
+
+ for (const auto &pair : sorted_used_attribute) {
+ const StringRefNull attribute_name = pair.first;
+ const NamedAttributeUsage usage = pair.second;
+
+ /* #uiLayoutRowWithHeading doesn't seem to work in this case. */
+ uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
+
+ std::stringstream ss;
+ Vector<std::string> usages;
+ if ((usage & NamedAttributeUsage::Read) != NamedAttributeUsage::None) {
+ usages.append(TIP_("Read"));
+ }
+ if ((usage & NamedAttributeUsage::Write) != NamedAttributeUsage::None) {
+ usages.append(TIP_("Write"));
+ }
+ if ((usage & NamedAttributeUsage::Remove) != NamedAttributeUsage::None) {
+ usages.append(TIP_("Remove"));
+ }
+ for (const int i : usages.index_range()) {
+ ss << usages[i];
+ if (i < usages.size() - 1) {
+ ss << ", ";
+ }
+ }
+
+ uiLayout *row = uiLayoutRow(split, false);
+ uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
+ uiLayoutSetActive(row, false);
+ uiItemL(row, ss.str().c_str(), ICON_NONE);
+
+ row = uiLayoutRow(split, false);
+ uiItemL(row, attribute_name.c_str(), ICON_NONE);
+ }
+}
+
static void panelRegister(ARegionType *region_type)
{
PanelType *panel_type = modifier_panel_register(region_type, eModifierType_Nodes, panel_draw);
@@ -1628,6 +1698,12 @@ static void panelRegister(ARegionType *region_type)
nullptr,
output_attribute_panel_draw,
panel_type);
+ modifier_subpanel_register(region_type,
+ "used_attributes",
+ N_("Used Attributes"),
+ nullptr,
+ used_attributes_panel_draw,
+ panel_type);
}
static void blendWrite(BlendWriter *writer, const ModifierData *md)
diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
index 68207d84015..e43d2b4ad85 100644
--- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
+++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
@@ -1635,10 +1635,8 @@ class GeometryNodesEvaluator {
if (conversions_.is_convertible(from_base_type, to_base_type)) {
if (from_field_type->is_field(from_value)) {
const GField &from_field = *from_field_type->get_field_ptr(from_value);
- const MultiFunction &fn = *conversions_.get_conversion_multi_function(
- MFDataType::ForSingle(from_base_type), MFDataType::ForSingle(to_base_type));
- auto operation = std::make_shared<fn::FieldOperation>(fn, Vector<GField>{from_field});
- to_field_type->construct_from_field(to_value, GField(std::move(operation), 0));
+ to_field_type->construct_from_field(to_value,
+ conversions_.try_convert(from_field, to_base_type));
}
else {
to_field_type->default_construct(to_value);
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index 6ded702ceda..b5411eee883 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -302,8 +302,6 @@ static Mesh *generate_ocean_geometry(OceanModifierData *omd, Mesh *mesh_orig, co
}
}
- BKE_mesh_normals_tag_dirty(result);
-
return result;
}
@@ -361,7 +359,6 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes
if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) {
result = generate_ocean_geometry(omd, mesh, resolution);
- BKE_mesh_normals_tag_dirty(result);
}
else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) {
result = (Mesh *)BKE_id_copy_ex(NULL, &mesh->id, NULL, LIB_ID_COPY_LOCALIZE);
@@ -376,17 +373,17 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes
/* add vcols before displacement - allows lookup based on position */
if (omd->flag & MOD_OCEAN_GENERATE_FOAM) {
- if (CustomData_number_of_layers(&result->ldata, CD_MLOOPCOL) < MAX_MCOL) {
+ if (CustomData_number_of_layers(&result->ldata, CD_PROP_BYTE_COLOR) < MAX_MCOL) {
const int polys_num = result->totpoly;
const int loops_num = result->totloop;
MLoop *mloops = result->mloop;
MLoopCol *mloopcols = CustomData_add_layer_named(
- &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, loops_num, omd->foamlayername);
+ &result->ldata, CD_PROP_BYTE_COLOR, CD_CALLOC, NULL, loops_num, omd->foamlayername);
MLoopCol *mloopcols_spray = NULL;
if (omd->flag & MOD_OCEAN_GENERATE_SPRAY) {
mloopcols_spray = CustomData_add_layer_named(
- &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, loops_num, omd->spraylayername);
+ &result->ldata, CD_PROP_BYTE_COLOR, CD_CALLOC, NULL, loops_num, omd->spraylayername);
}
if (mloopcols) { /* unlikely to fail */
@@ -472,6 +469,8 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes
}
}
+ BKE_mesh_normals_tag_dirty(mesh);
+
if (allocated_ocean) {
BKE_ocean_free(omd->ocean);
omd->ocean = NULL;
@@ -490,15 +489,7 @@ static Mesh *doOcean(ModifierData *UNUSED(md), const ModifierEvalContext *UNUSED
static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
- Mesh *result;
-
- result = doOcean(md, ctx, mesh);
-
- if (result != mesh) {
- BKE_mesh_normals_tag_dirty(result);
- }
-
- return result;
+ return doOcean(md, ctx, mesh);
}
// #define WITH_OCEANSIM
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index 205a1986552..2a8d2454670 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -59,7 +59,7 @@ static void requiredDataMask(Object *UNUSED(ob),
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md;
if (pimd->index_layer_name[0] != '\0' || pimd->value_layer_name[0] != '\0') {
- r_cddata_masks->lmask |= CD_MASK_MLOOPCOL;
+ r_cddata_masks->lmask |= CD_MASK_PROP_BYTE_COLOR;
}
}
@@ -328,9 +328,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
orig_mloop = mesh->mloop;
MLoopCol *mloopcols_index = CustomData_get_layer_named(
- &result->ldata, CD_MLOOPCOL, pimd->index_layer_name);
+ &result->ldata, CD_PROP_BYTE_COLOR, pimd->index_layer_name);
MLoopCol *mloopcols_value = CustomData_get_layer_named(
- &result->ldata, CD_MLOOPCOL, pimd->value_layer_name);
+ &result->ldata, CD_PROP_BYTE_COLOR, pimd->value_layer_name);
int *vert_part_index = NULL;
float *vert_part_value = NULL;
if (mloopcols_index != NULL) {
@@ -530,8 +530,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
MEM_SAFE_FREE(vert_part_index);
MEM_SAFE_FREE(vert_part_value);
- BKE_mesh_normals_tag_dirty(result);
-
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index 7df7ba7c1db..032227307e7 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -158,7 +158,6 @@ static void deformVerts(ModifierData *md,
/* make new mesh */
psmd->mesh_final = BKE_mesh_copy_for_eval(mesh_src, false);
BKE_mesh_vert_coords_apply(psmd->mesh_final, vertexCos);
- BKE_mesh_calc_normals(psmd->mesh_final);
BKE_mesh_tessface_ensure(psmd->mesh_final);
diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c
index f6f4746f44f..288faee247f 100644
--- a/source/blender/modifiers/intern/MOD_remesh.c
+++ b/source/blender/modifiers/intern/MOD_remesh.c
@@ -206,7 +206,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx)
BKE_mesh_copy_parameters_for_eval(result, mesh);
BKE_mesh_calc_edges(result, true, false);
- BKE_mesh_normals_tag_dirty(result);
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index 4ace6404388..05072cf340c 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -384,7 +384,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
mvert_new = result->mvert;
float(*vert_normals_new)[3] = BKE_mesh_vertex_normals_for_write(result);
- BKE_mesh_vertex_normals_clear_dirty(result);
mpoly_new = result->mpoly;
mloop_new = result->mloop;
medge_new = result->medge;
@@ -1120,7 +1119,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
}
if ((ltmd->flag & MOD_SCREW_MERGE) && (screw_ofs == 0.0f)) {
- Mesh *result_prev = result;
result = mesh_remove_doubles_on_axis(result,
mvert_new,
totvert,
@@ -1128,13 +1126,10 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
axis_vec,
ob_axis != NULL ? mtx_tx[3] : NULL,
ltmd->merge_dist);
- if (result != result_prev) {
- BKE_mesh_normals_tag_dirty(result);
- }
}
- if ((ltmd->flag & MOD_SCREW_NORMAL_CALC) == 0) {
- BKE_mesh_normals_tag_dirty(result);
+ if ((ltmd->flag & MOD_SCREW_NORMAL_CALC)) {
+ BKE_mesh_vertex_normals_clear_dirty(result);
}
return result;
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index b950578ff1b..7f96dcb82fb 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -1950,8 +1950,6 @@ static Mesh *base_skin(Mesh *origmesh, SkinModifierData *smd, eSkinErrorFlag *r_
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, origmesh);
BM_mesh_free(bm);
- BKE_mesh_normals_tag_dirty(result);
-
skin_set_orig_indices(result);
return result;
diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
index 8a84cd0a3bf..8a5b600974c 100644
--- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
+++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
@@ -2016,8 +2016,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
}
}
- BKE_mesh_normals_tag_dirty(result);
-
/* Make edges. */
{
uint i = 0;
diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c
index 3e75e325e44..c2869e590bd 100644
--- a/source/blender/modifiers/intern/MOD_surface.c
+++ b/source/blender/modifiers/intern/MOD_surface.c
@@ -129,7 +129,7 @@ static void deformVerts(ModifierData *md,
MVert *x, *v;
BKE_mesh_vert_coords_apply(surmd->mesh, vertexCos);
- BKE_mesh_calc_normals(surmd->mesh);
+ BKE_mesh_normals_tag_dirty(surmd->mesh);
mesh_verts_num = surmd->mesh->totvert;
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index d7e57c1f6e5..f1e8ef5bf38 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -89,8 +89,6 @@ static Mesh *triangulate_mesh(Mesh *mesh,
me->flag |= ME_EDGEDRAW | ME_EDGERENDER;
}
- BKE_mesh_normals_tag_dirty(result);
-
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index dae7d19844e..b657ea87244 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -97,8 +97,6 @@ static Mesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, Mesh *
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
- BKE_mesh_normals_tag_dirty(result);
-
return result;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
index 87f000897ed..877dc05211d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
@@ -131,8 +131,6 @@ static Mesh *hull_from_bullet(const Mesh *mesh, Span<float3> coords)
}
plConvexHullDelete(hull);
-
- BKE_mesh_normals_tag_dirty(result);
return result;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
index c3b1a141f4a..8a0c900fbde 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -1225,8 +1225,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
}
BKE_mesh_calc_edges_loose(mesh_out);
- /* Tag to recalculate normals later. */
- BKE_mesh_normals_tag_dirty(mesh_out);
geometry_set.replace_mesh(mesh_out);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
index 2894e608819..dcd9bcfb034 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
@@ -897,7 +897,6 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
copy_v3_v3(mesh_out->mvert[i].co, vertex_positions[i]);
}
memcpy(mesh_out->medge, new_edges.data(), sizeof(MEdge) * new_edges.size());
- BKE_mesh_normals_tag_dirty(mesh_out);
geometry_set.replace_mesh(mesh_out);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
index c03a340a0c8..84acab47661 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
@@ -41,8 +41,6 @@ static Mesh *mesh_edge_split(const Mesh &mesh, const IndexMask selection)
Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, &mesh);
BM_mesh_free(bm);
- BKE_mesh_normals_tag_dirty(result);
-
return result;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
index e53be5213f6..636ecb8ab41 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
@@ -407,7 +407,6 @@ Mesh *create_cuboid_mesh(const float3 size,
calculate_polys(config, {mesh->mpoly, mesh->totpoly}, {mesh->mloop, mesh->totloop});
BKE_mesh_calc_edges(mesh, false, false);
- BKE_mesh_normals_tag_dirty(mesh);
calculate_uvs(config, mesh);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
index e1f85be0f80..3c0ccb01673 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
@@ -50,7 +50,6 @@ static void geometry_set_mesh_subdivide(GeometrySet &geometry_set, const int lev
}
Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh_in);
- BKE_mesh_normals_tag_dirty(mesh_out);
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
mesh_component.replace(mesh_out);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
index 296b40c6c49..507c6e81b1f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
@@ -18,8 +18,10 @@ namespace blender::nodes::node_geo_set_material_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"))
- .supported_type(
- {GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_VOLUME, GEO_COMPONENT_TYPE_POINT_CLOUD});
+ .supported_type({GEO_COMPONENT_TYPE_MESH,
+ GEO_COMPONENT_TYPE_VOLUME,
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ GEO_COMPONENT_TYPE_CURVE});
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
b.add_input<decl::Material>(N_("Material")).hide_label();
b.add_output<decl::Geometry>(N_("Geometry"));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc
index 92614d1a31d..b51fc063ab8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc
@@ -5,6 +5,8 @@
#include "NOD_socket_search_link.hh"
+#include "BKE_type_conversions.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_store_named_attribute_cc {
@@ -55,7 +57,8 @@ static void node_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, socket_vector, data_type == CD_PROP_FLOAT3);
nodeSetSocketAvailability(ntree, socket_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(ntree, socket_color4f, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(
+ ntree, socket_color4f, ELEM(data_type, CD_PROP_COLOR, CD_PROP_BYTE_COLOR));
nodeSetSocketAvailability(ntree, socket_boolean, data_type == CD_PROP_BOOL);
nodeSetSocketAvailability(ntree, socket_int32, data_type == CD_PROP_INT32);
}
@@ -149,6 +152,12 @@ static void node_geo_exec(GeoNodeExecParams params)
case CD_PROP_COLOR:
field = params.get_input<Field<ColorGeometry4f>>("Value_Color");
break;
+ case CD_PROP_BYTE_COLOR: {
+ field = params.get_input<Field<ColorGeometry4f>>("Value_Color");
+ field = bke::get_implicit_type_conversions().try_convert(field,
+ CPPType::get<ColorGeometry4b>());
+ break;
+ }
case CD_PROP_BOOL:
field = params.get_input<Field<bool>>("Value_Bool");
break;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
index a5fe491e12b..4832feac5bd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
@@ -119,7 +119,6 @@ static void node_geo_exec(GeoNodeExecParams params)
}
Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh_in);
- BKE_mesh_normals_tag_dirty(mesh_out);
mesh_component.replace(mesh_out);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
index cc115ee3b3f..e95db205920 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
@@ -43,7 +43,6 @@ static void translate_mesh(Mesh &mesh, const float3 translation)
static void transform_mesh(Mesh &mesh, const float4x4 &transform)
{
BKE_mesh_transform(&mesh, transform.values, false);
- BKE_mesh_normals_tag_dirty(&mesh);
}
static void translate_pointcloud(PointCloud &pointcloud, const float3 translation)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
index 76cdbfb140f..992470e8279 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
@@ -62,7 +62,6 @@ static Mesh *triangulate_mesh_selection(const Mesh &mesh,
BM_mesh_triangulate(bm, quad_method, ngon_method, min_vertices, true, nullptr, nullptr, nullptr);
Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cd_mask_extra, &mesh);
BM_mesh_free(bm);
- BKE_mesh_normals_tag_dirty(result);
return result;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
index c30c05bdd0d..e5827c24320 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
@@ -139,7 +139,6 @@ static Mesh *create_mesh_from_volume_grids(Span<openvdb::GridBase::ConstPtr> gri
}
BKE_mesh_calc_edges(mesh, false, false);
- BKE_mesh_normals_tag_dirty(mesh);
return mesh;
}
diff --git a/source/blender/nodes/shader/node_shader_tree.cc b/source/blender/nodes/shader/node_shader_tree.cc
index d917106807c..c5f40a46ca3 100644
--- a/source/blender/nodes/shader/node_shader_tree.cc
+++ b/source/blender/nodes/shader/node_shader_tree.cc
@@ -722,7 +722,7 @@ static void ntree_shader_weight_tree_invert(bNodeTree *ntree, bNode *output_node
}
case SH_NODE_ADD_SHADER: {
/* Simple passthrough node. Each original inputs will get the same weight. */
- /* TODO(fclem) Better use some kind of reroute node? */
+ /* TODO(fclem): Better use some kind of reroute node? */
nodes_copy[id] = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH);
nodes_copy[id]->custom1 = NODE_MATH_ADD;
nodes_copy[id]->tmp_flag = -2; /* Copy */
@@ -761,14 +761,14 @@ static void ntree_shader_weight_tree_invert(bNodeTree *ntree, bNode *output_node
}
id++;
/* Reroute the weight input to the 3 processing nodes. Simplify linking later-on. */
- /* TODO(fclem) Better use some kind of reroute node? */
+ /* TODO(fclem): Better use some kind of reroute node? */
nodes_copy[id] = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH);
nodes_copy[id]->custom1 = NODE_MATH_ADD;
nodes_copy[id]->tmp_flag = -2; /* Copy */
((bNodeSocketValueFloat *)ntree_shader_node_input_get(nodes_copy[id], 0)->default_value)
->value = 0.0f;
id++;
- /* Link between nodes for the substraction. */
+ /* Link between nodes for the subtraction. */
fromnode = nodes_copy[id_start];
tonode = nodes_copy[id_start + 1];
fromsock = ntree_shader_node_output_get(fromnode, 0);
@@ -890,8 +890,8 @@ static void ntree_shader_weight_tree_invert(bNodeTree *ntree, bNode *output_node
break;
}
- /* Manually add the link to the socket to avoid calling
- * BKE_ntree_update_main_tree(G.main, oop, nullptr. */
+ /* Manually add the link to the socket to avoid calling:
+ * `BKE_ntree_update_main_tree(G.main, oop, nullptr)`. */
fromsock->link = nodeAddLink(ntree, fromnode, fromsock, tonode, tosock);
BLI_assert(fromsock->link);
}
@@ -957,8 +957,8 @@ static void ntree_shader_shader_to_rgba_branch(bNodeTree *ntree, bNode *output_n
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
node->tmp_flag = -1;
}
- /* First gather the shader_to_rgba nodes linked to the ouput. This is separate to avoid
- * conflicting usage of the node->tmp_flag. */
+ /* First gather the shader_to_rgba nodes linked to the output. This is separate to avoid
+ * conflicting usage of the `node->tmp_flag`. */
Vector<bNode *> shader_to_rgba_nodes;
nodeChainIterBackwards(ntree, output_node, shader_to_rgba_node_gather, &shader_to_rgba_nodes, 0);
@@ -971,7 +971,7 @@ static void ntree_shader_shader_to_rgba_branch(bNodeTree *ntree, bNode *output_n
bNode *start_node_copy = ntree_shader_copy_branch(
ntree, start_node, closure_node_filter, nullptr, 0);
/* Replace node copy link. This assumes that every node possibly connected to the closure input
- * has only one ouput. */
+ * has only one output. */
bNodeSocket *closure_output = ntree_shader_node_output_get(start_node_copy, 0);
nodeRemLink(ntree, closure_input->link);
nodeAddLink(ntree, start_node_copy, closure_output, shader_to_rgba, closure_input);
diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.cc b/source/blender/nodes/shader/nodes/node_shader_attribute.cc
index bb01818e734..d01271c15d3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_attribute.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_attribute.cc
@@ -37,24 +37,6 @@ static int node_shader_gpu_attribute(GPUMaterial *mat,
NodeShaderAttribute *attr = static_cast<NodeShaderAttribute *>(node->storage);
bool is_varying = attr->type == SHD_ATTRIBUTE_GEOMETRY;
- if (GPU_material_is_volume_shader(mat) && is_varying) {
- if (out[0].hasoutput) {
- out[0].link = GPU_volume_grid(mat, attr->name, GPU_VOLUME_DEFAULT_0);
- }
- if (out[1].hasoutput) {
- out[1].link = GPU_volume_grid(mat, attr->name, GPU_VOLUME_DEFAULT_0);
- }
- if (out[2].hasoutput) {
- out[2].link = GPU_volume_grid(mat, attr->name, GPU_VOLUME_DEFAULT_0);
- }
- if (out[3].hasoutput) {
- static const float default_alpha = 1.0f;
- out[3].link = GPU_constant(&default_alpha);
- }
-
- return 1;
- }
-
GPUNodeLink *cd_attr;
if (is_varying) {
@@ -64,6 +46,13 @@ static int node_shader_gpu_attribute(GPUMaterial *mat,
cd_attr = GPU_uniform_attribute(mat, attr->name, attr->type == SHD_ATTRIBUTE_INSTANCER);
}
+ if (STREQ(attr->name, "color")) {
+ GPU_link(mat, "node_attribute_color", cd_attr, &cd_attr);
+ }
+ else if (STREQ(attr->name, "temperature")) {
+ GPU_link(mat, "node_attribute_temperature", cd_attr, &cd_attr);
+ }
+
GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr);
int i;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc
index dbff092234b..df5fbac3ab5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc
@@ -37,15 +37,15 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
NodeTexImage *tex_original = (NodeTexImage *)node_original->storage;
ImageUser *iuser = &tex_original->iuser;
eGPUSamplerState sampler = GPU_SAMPLER_REPEAT | GPU_SAMPLER_ANISO | GPU_SAMPLER_FILTER;
- /* TODO(fclem): For now assume mipmap is always enabled. */
+ /* TODO(@fclem): For now assume mipmap is always enabled. */
if (true) {
sampler |= GPU_SAMPLER_MIPMAP;
}
GPUNodeLink *outalpha;
- /* HACK(fclem): For lookdev mode: do not compile an empty environment and just create an empty
- * texture entry point. We manually bind to it after DRW_shgroup_add_material_resources(). */
+ /* HACK(@fclem): For lookdev mode: do not compile an empty environment and just create an empty
+ * texture entry point. We manually bind to it after #DRW_shgroup_add_material_resources(). */
if (!ima && !GPU_material_flag_get(mat, GPU_MATFLAG_LOOKDEV_HACK)) {
return GPU_stack_link(mat, node, "node_tex_environment_empty", in, out);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_info.cc b/source/blender/nodes/shader/nodes/node_shader_volume_info.cc
index 6676a7653fe..a202312f8d8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_info.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_info.cc
@@ -20,16 +20,18 @@ static int node_shader_gpu_volume_info(GPUMaterial *mat,
GPUNodeStack *out)
{
if (out[0].hasoutput) {
- out[0].link = GPU_volume_grid(mat, "color", GPU_VOLUME_DEFAULT_0);
+ out[0].link = GPU_attribute(mat, CD_AUTO_FROM_NAME, "color");
+ GPU_link(mat, "node_attribute_color", out[0].link, &out[0].link);
}
if (out[1].hasoutput) {
- out[1].link = GPU_volume_grid(mat, "density", GPU_VOLUME_DEFAULT_0);
+ out[1].link = GPU_attribute(mat, CD_AUTO_FROM_NAME, "density");
}
if (out[2].hasoutput) {
- out[2].link = GPU_volume_grid(mat, "flame", GPU_VOLUME_DEFAULT_0);
+ out[2].link = GPU_attribute(mat, CD_AUTO_FROM_NAME, "flame");
}
if (out[3].hasoutput) {
- out[3].link = GPU_volume_grid(mat, "temperature", GPU_VOLUME_DEFAULT_0);
+ out[3].link = GPU_attribute(mat, CD_AUTO_FROM_NAME, "temperature");
+ GPU_link(mat, "node_attribute_temperature", out[3].link, &out[3].link);
}
return true;
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc b/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc
index d414b4b2ef7..07e700e550a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc
@@ -43,6 +43,18 @@ static void node_shader_init_volume_principled(bNodeTree *UNUSED(ntree), bNode *
}
}
+static void attribute_post_process(GPUMaterial *mat,
+ const char *attribute_name,
+ GPUNodeLink **attribute_link)
+{
+ if (STREQ(attribute_name, "color")) {
+ GPU_link(mat, "node_attribute_color", *attribute_link, attribute_link);
+ }
+ else if (STREQ(attribute_name, "temperature")) {
+ GPU_link(mat, "node_attribute_temperature", *attribute_link, attribute_link);
+ }
+}
+
static int node_shader_gpu_volume_principled(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
@@ -67,28 +79,29 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat,
}
if (STREQ(sock->name, "Density Attribute")) {
- density = GPU_volume_grid(mat, attribute_name, GPU_VOLUME_DEFAULT_1);
+ density = GPU_attribute_with_default(mat, CD_AUTO_FROM_NAME, attribute_name, GPU_DEFAULT_1);
+ attribute_post_process(mat, attribute_name, &density);
}
else if (STREQ(sock->name, "Color Attribute")) {
- color = GPU_volume_grid(mat, attribute_name, GPU_VOLUME_DEFAULT_1);
+ color = GPU_attribute_with_default(mat, CD_AUTO_FROM_NAME, attribute_name, GPU_DEFAULT_1);
+ attribute_post_process(mat, attribute_name, &color);
}
else if (use_blackbody && STREQ(sock->name, "Temperature Attribute")) {
- temperature = GPU_volume_grid(mat, attribute_name, GPU_VOLUME_DEFAULT_0);
+ temperature = GPU_attribute(mat, CD_AUTO_FROM_NAME, attribute_name);
+ attribute_post_process(mat, attribute_name, &temperature);
}
}
/* Default values if attributes not found. */
+ static float white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
if (!density) {
- static float one = 1.0f;
- density = GPU_constant(&one);
+ density = GPU_constant(white);
}
if (!color) {
- static float white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
color = GPU_constant(white);
}
if (!temperature) {
- static float one = 1.0f;
- temperature = GPU_constant(&one);
+ temperature = GPU_constant(white);
}
/* Create blackbody spectrum. */
diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c
index e591dfa2929..58bfb922327 100644
--- a/source/blender/python/bmesh/bmesh_py_types_customdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c
@@ -193,7 +193,7 @@ static PyGetSetDef bpy_bmlayeraccess_vert_getseters[] = {
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
bpy_bmlayeraccess_collection__color_doc,
- (void *)CD_MLOOPCOL},
+ (void *)CD_PROP_BYTE_COLOR},
{"string",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
@@ -254,7 +254,7 @@ static PyGetSetDef bpy_bmlayeraccess_edge_getseters[] = {
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
bpy_bmlayeraccess_collection__color_doc,
- (void *)CD_MLOOPCOL},
+ (void *)CD_PROP_BYTE_COLOR},
{"string",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
@@ -307,7 +307,7 @@ static PyGetSetDef bpy_bmlayeraccess_face_getseters[] = {
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
bpy_bmlayeraccess_collection__color_doc,
- (void *)CD_MLOOPCOL},
+ (void *)CD_PROP_BYTE_COLOR},
{"string",
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
@@ -365,7 +365,7 @@ static PyGetSetDef bpy_bmlayeraccess_loop_getseters[] = {
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
bpy_bmlayeraccess_collection__color_doc,
- (void *)CD_MLOOPCOL},
+ (void *)CD_PROP_BYTE_COLOR},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
@@ -1134,7 +1134,7 @@ PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer)
ret = BPy_BMLoopUV_CreatePyObject(value);
break;
}
- case CD_MLOOPCOL: {
+ case CD_PROP_BYTE_COLOR: {
ret = BPy_BMLoopColor_CreatePyObject(value);
break;
}
@@ -1236,7 +1236,7 @@ int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObj
ret = BPy_BMLoopUV_AssignPyObject(value, py_value);
break;
}
- case CD_MLOOPCOL: {
+ case CD_PROP_BYTE_COLOR: {
ret = BPy_BMLoopColor_AssignPyObject(value, py_value);
break;
}
diff --git a/source/blender/python/gpu/gpu_py_batch.c b/source/blender/python/gpu/gpu_py_batch.c
index 232d4775746..02bcf80aa5d 100644
--- a/source/blender/python/gpu/gpu_py_batch.c
+++ b/source/blender/python/gpu/gpu_py_batch.c
@@ -82,6 +82,18 @@ static PyObject *pygpu_batch__tp_new(PyTypeObject *UNUSED(type), PyObject *args,
}
BLI_assert(prim_type.value_found != GPU_PRIM_NONE);
+ if (prim_type.value_found == GPU_PRIM_LINE_LOOP) {
+ PyErr_WarnEx(PyExc_DeprecationWarning,
+ "'LINE_LOOP' is deprecated. Please use 'LINE_STRIP' and close the segment.",
+ 1);
+ }
+ else if (prim_type.value_found == GPU_PRIM_TRI_FAN) {
+ PyErr_WarnEx(
+ PyExc_DeprecationWarning,
+ "'TRI_FAN' is deprecated. Please use 'TRI_STRIP' or 'TRIS' and try modifying your "
+ "vertices or indices to match the topology.",
+ 1);
+ }
if (py_vertbuf == NULL) {
PyErr_Format(PyExc_TypeError, exc_str_missing_arg, _keywords[1], 2);
diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c
index 9fe4bdcbaa0..77333c6dfea 100644
--- a/source/blender/python/gpu/gpu_py_shader.c
+++ b/source/blender/python/gpu/gpu_py_shader.c
@@ -30,17 +30,37 @@
/** \name Enum Conversion.
* \{ */
-#define PYDOC_BUILTIN_SHADER_LIST \
- " - ``2D_FLAT_COLOR``\n" \
- " - ``2D_IMAGE``\n" \
- " - ``2D_SMOOTH_COLOR``\n" \
- " - ``2D_UNIFORM_COLOR``\n" \
- " - ``3D_FLAT_COLOR``\n" \
- " - ``3D_SMOOTH_COLOR``\n" \
- " - ``3D_UNIFORM_COLOR``\n" \
- " - ``3D_POLYLINE_FLAT_COLOR``\n" \
- " - ``3D_POLYLINE_SMOOTH_COLOR``\n" \
- " - ``3D_POLYLINE_UNIFORM_COLOR``\n"
+#define PYDOC_BUILTIN_SHADER_DESCRIPTION \
+ "``2D_FLAT_COLOR``\n" \
+ " :Attributes: vec3 pos, vec4 color\n" \
+ " :Uniforms: none\n" \
+ "``2D_IMAGE``\n" \
+ " :Attributes: vec3 pos, vec2 texCoord\n" \
+ " :Uniforms: sampler2D image\n" \
+ "``2D_SMOOTH_COLOR``\n" \
+ " :Attributes: vec3 pos, vec4 color\n" \
+ " :Uniforms: none\n" \
+ "``2D_UNIFORM_COLOR``\n" \
+ " :Attributes: vec3 pos\n" \
+ " :Uniforms: vec4 color\n" \
+ "``3D_FLAT_COLOR``\n" \
+ " :Attributes: vec3 pos, vec4 color\n" \
+ " :Uniforms: none\n" \
+ "``3D_SMOOTH_COLOR``\n" \
+ " :Attributes: vec3 pos, vec4 color\n" \
+ " :Uniforms: none\n" \
+ "``3D_UNIFORM_COLOR``\n" \
+ " :Attributes: vec3 pos\n" \
+ " :Uniforms: vec4 color\n" \
+ "``3D_POLYLINE_FLAT_COLOR``\n" \
+ " :Attributes: vec3 pos, vec4 color\n" \
+ " :Uniforms: vec2 viewportSize, float lineWidth\n" \
+ "``3D_POLYLINE_SMOOTH_COLOR``\n" \
+ " :Attributes: vec3 pos, vec4 color\n" \
+ " :Uniforms: vec2 viewportSize, float lineWidth\n" \
+ "``3D_POLYLINE_UNIFORM_COLOR``\n" \
+ " :Attributes: vec3 pos\n" \
+ " :Uniforms: vec2 viewportSize, float lineWidth\n"
static const struct PyC_StringEnumItems pygpu_shader_builtin_items[] = {
{GPU_SHADER_2D_FLAT_COLOR, "2D_FLAT_COLOR"},
@@ -731,7 +751,9 @@ static PyObject *pygpu_shader_unbind(BPyGPUShader *UNUSED(self))
PyDoc_STRVAR(pygpu_shader_from_builtin_doc,
".. function:: from_builtin(shader_name, config='DEFAULT')\n"
"\n"
- " Shaders that are embedded in the blender internal code.\n"
+ " Shaders that are embedded in the blender internal code:\n"
+ "" PYDOC_BUILTIN_SHADER_DESCRIPTION
+ "\n"
" They all read the uniform ``mat4 ModelViewProjectionMatrix``,\n"
" which can be edited by the :mod:`gpu.matrix` module.\n"
"\n"
@@ -739,11 +761,7 @@ PyDoc_STRVAR(pygpu_shader_from_builtin_doc,
"``CLIPPED`` value to the config parameter. Note that in this case you also need to "
"manually set the value of ``mat4 ModelMatrix``.\n"
"\n"
- " For more details, you can check the shader code with the\n"
- " :func:`gpu.shader.code_from_builtin` function.\n"
- "\n"
- " :param shader_name: One of these builtin shader names:\n"
- "\n" PYDOC_BUILTIN_SHADER_LIST
+ " :param shader_name: One of the builtin shader names.\n"
" :type shader_name: str\n"
" :param config: One of these types of shader configuration:\n"
"\n"
@@ -784,52 +802,6 @@ static PyObject *pygpu_shader_from_builtin(PyObject *UNUSED(self), PyObject *arg
return BPyGPUShader_CreatePyObject(shader, true);
}
-PyDoc_STRVAR(pygpu_shader_code_from_builtin_doc,
- ".. function:: code_from_builtin(pygpu_shader_name)\n"
- "\n"
- " Exposes the internal shader code for consultation.\n"
- "\n"
- " :param pygpu_shader_name: One of these builtin shader names:\n"
- "\n" PYDOC_BUILTIN_SHADER_LIST
- " :type pygpu_shader_name: str\n"
- " :return: Vertex, fragment and geometry shader codes.\n"
- " :rtype: dict\n");
-static PyObject *pygpu_shader_code_from_builtin(BPyGPUShader *UNUSED(self), PyObject *arg)
-{
- const char *vert;
- const char *frag;
- const char *geom;
- const char *defines;
-
- PyObject *item, *r_dict;
-
- struct PyC_StringEnum pygpu_bultinshader = {pygpu_shader_builtin_items};
- if (!PyC_ParseStringEnum(arg, &pygpu_bultinshader)) {
- return NULL;
- }
-
- GPU_shader_get_builtin_shader_code(
- pygpu_bultinshader.value_found, &vert, &frag, &geom, &defines);
-
- r_dict = PyDict_New();
-
- PyDict_SetItemString(r_dict, "vertex_shader", item = PyUnicode_FromString(vert));
- Py_DECREF(item);
-
- PyDict_SetItemString(r_dict, "fragment_shader", item = PyUnicode_FromString(frag));
- Py_DECREF(item);
-
- if (geom) {
- PyDict_SetItemString(r_dict, "geometry_shader", item = PyUnicode_FromString(geom));
- Py_DECREF(item);
- }
- if (defines) {
- PyDict_SetItemString(r_dict, "defines", item = PyUnicode_FromString(defines));
- Py_DECREF(item);
- }
- return r_dict;
-}
-
PyDoc_STRVAR(pygpu_shader_create_from_info_doc,
".. function:: create_from_info(shader_info)\n"
"\n"
@@ -868,10 +840,6 @@ static struct PyMethodDef pygpu_shader_module__tp_methods[] = {
(PyCFunction)pygpu_shader_from_builtin,
METH_VARARGS | METH_KEYWORDS,
pygpu_shader_from_builtin_doc},
- {"code_from_builtin",
- (PyCFunction)pygpu_shader_code_from_builtin,
- METH_O,
- pygpu_shader_code_from_builtin_doc},
{"create_from_info",
(PyCFunction)pygpu_shader_create_from_info,
METH_O,
@@ -887,28 +855,7 @@ PyDoc_STRVAR(pygpu_shader_module__tp_doc,
"All built-in shaders have the ``mat4 ModelViewProjectionMatrix`` uniform.\n"
"\n"
"Its value must be modified using the :class:`gpu.matrix` module.\n"
- "\n"
- "``2D_UNIFORM_COLOR``\n"
- " :Attributes: vec3 pos\n"
- " :Uniforms: vec4 color\n"
- "``2D_FLAT_COLOR``\n"
- " :Attributes: vec3 pos, vec4 color\n"
- " :Uniforms: none\n"
- "``2D_SMOOTH_COLOR``\n"
- " :Attributes: vec3 pos, vec4 color\n"
- " :Uniforms: none\n"
- "``2D_IMAGE``\n"
- " :Attributes: vec3 pos, vec2 texCoord\n"
- " :Uniforms: sampler2D image\n"
- "``3D_UNIFORM_COLOR``\n"
- " :Attributes: vec3 pos\n"
- " :Uniforms: vec4 color\n"
- "``3D_FLAT_COLOR``\n"
- " :Attributes: vec3 pos, vec4 color\n"
- " :Uniforms: none\n"
- "``3D_SMOOTH_COLOR``\n"
- " :Attributes: vec3 pos, vec4 color\n"
- " :Uniforms: none\n");
+ "\n" PYDOC_BUILTIN_SHADER_DESCRIPTION);
static PyModuleDef pygpu_shader_module_def = {
PyModuleDef_HEAD_INIT,
.m_name = "gpu.shader",
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 86dc5800b67..e4e198ab812 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -60,6 +60,7 @@ set(SRC
bpy_rna_anim.c
bpy_rna_array.c
bpy_rna_callback.c
+ bpy_rna_context.c
bpy_rna_data.c
bpy_rna_driver.c
bpy_rna_gizmo.c
@@ -101,6 +102,7 @@ set(SRC
bpy_rna.h
bpy_rna_anim.h
bpy_rna_callback.h
+ bpy_rna_context.h
bpy_rna_data.h
bpy_rna_driver.h
bpy_rna_gizmo.h
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index db0067fc18e..95879b02295 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -60,6 +60,23 @@ static wmOperatorType *ot_lookup_from_py_string(PyObject *value, const char *py_
return ot;
}
+static void op_context_override_deprecated_warning(const char *action, const char *opname)
+{
+ if (PyErr_WarnFormat(
+ PyExc_DeprecationWarning,
+ /* Use stack level 2 as this call is wrapped by `release/scripts/modules/bpy/ops.py`,
+ * An extra stack level is needed to show the warning in the authors script. */
+ 2,
+ "Passing in context overrides is deprecated in favor of "
+ "Context.temp_override(..), %s \"%s\"",
+ action,
+ opname) < 0) {
+ /* The function has no return value, the exception cannot
+ * be reported to the caller, so just log it. */
+ PyErr_WriteUnraisable(NULL);
+ }
+}
+
static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args)
{
wmOperatorType *ot;
@@ -113,7 +130,10 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args)
if (ELEM(context_dict, NULL, Py_None)) {
context_dict = NULL;
}
- else if (!PyDict_Check(context_dict)) {
+ else if (PyDict_Check(context_dict)) {
+ op_context_override_deprecated_warning("polling", opname);
+ }
+ else {
PyErr_Format(PyExc_TypeError,
"Calling operator \"bpy.ops.%s.poll\" error, "
"custom context expected a dict or None, got a %.200s",
@@ -218,7 +238,10 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
if (ELEM(context_dict, NULL, Py_None)) {
context_dict = NULL;
}
- else if (!PyDict_Check(context_dict)) {
+ else if (PyDict_Check(context_dict)) {
+ op_context_override_deprecated_warning("calling", opname);
+ }
+ else {
PyErr_Format(PyExc_TypeError,
"Calling operator \"bpy.ops.%s\" error, "
"custom context expected a dict or None, got a %.200s",
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 5db66405403..c67f0c028cf 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -4398,7 +4398,7 @@ static int pyrna_struct_meta_idprop_setattro(PyObject *cls, PyObject *attr, PyOb
}
}
- /* Fallback to standard py, delattr/setattr. */
+ /* Fallback to standard Python's `delattr/setattr`. */
return PyType_Type.tp_setattro(cls, attr, value);
}
@@ -7872,6 +7872,50 @@ StructRNA *pyrna_struct_as_srna(PyObject *self, const bool parent, const char *e
return srna;
}
+const PointerRNA *pyrna_struct_as_ptr(PyObject *py_obj, const StructRNA *srna)
+{
+ BPy_StructRNA *bpy_srna = (BPy_StructRNA *)py_obj;
+ if (!BPy_StructRNA_Check(py_obj) || !RNA_struct_is_a(bpy_srna->ptr.type, srna)) {
+ PyErr_Format(PyExc_TypeError,
+ "Expected a \"bpy.types.%.200s\" not a \"%.200s\"",
+ RNA_struct_identifier(srna),
+ Py_TYPE(py_obj)->tp_name);
+ return NULL;
+ }
+ PYRNA_STRUCT_CHECK_OBJ(bpy_srna);
+ return &bpy_srna->ptr;
+}
+
+const PointerRNA *pyrna_struct_as_ptr_or_null(PyObject *py_obj, const StructRNA *srna)
+{
+ if (py_obj == Py_None) {
+ return &PointerRNA_NULL;
+ }
+ return pyrna_struct_as_ptr(py_obj, srna);
+}
+
+int pyrna_struct_as_ptr_parse(PyObject *o, void *p)
+{
+ struct BPy_StructRNA_Parse *srna_parse = p;
+ BLI_assert(srna_parse->type != NULL);
+ srna_parse->ptr = pyrna_struct_as_ptr(o, srna_parse->type);
+ if (srna_parse->ptr == NULL) {
+ return 0;
+ }
+ return 1;
+}
+
+int pyrna_struct_as_ptr_or_null_parse(PyObject *o, void *p)
+{
+ struct BPy_StructRNA_Parse *srna_parse = p;
+ BLI_assert(srna_parse->type != NULL);
+ srna_parse->ptr = pyrna_struct_as_ptr_or_null(o, srna_parse->type);
+ if (srna_parse->ptr == NULL) {
+ return 0;
+ }
+ return 1;
+}
+
/* Orphan functions, not sure where they should go. */
StructRNA *srna_from_self(PyObject *self, const char *error_prefix)
{
diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h
index 573daac6e95..91fa0ea2c8d 100644
--- a/source/blender/python/intern/bpy_rna.h
+++ b/source/blender/python/intern/bpy_rna.h
@@ -187,6 +187,33 @@ PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop);
int pyrna_deferred_register_class(struct StructRNA *srna, PyTypeObject *py_class);
+const PointerRNA *pyrna_struct_as_ptr(PyObject *py_obj, const StructRNA *srna);
+const PointerRNA *pyrna_struct_as_ptr_or_null(PyObject *py_obj, const StructRNA *srna);
+
+/**
+ * Struct used for RNA argument parsing functions:
+ * - #pyrna_struct_as_ptr_parse
+ * - #pyrna_struct_as_ptr_or_null_parse
+ */
+struct BPy_StructRNA_Parse {
+ /** The struct RNA must match this type. */
+ StructRNA *type;
+ /** Result, may be `PointerRNA_NULL` if #pyrna_struct_as_ptr_or_null_parse is used. */
+ const PointerRNA *ptr;
+};
+
+/**
+ * Sets #BPy_StructRNA_Parse.ptr to the value in the #BPy_StructRNA.ptr (from `o`)
+ * or raise an error if the type isn't a #BPy_StructRNA.
+ *
+ * Use with #PyArg_ParseTuple's `O&` formatting.
+ */
+int pyrna_struct_as_ptr_parse(PyObject *o, void *p);
+/**
+ * A version of #pyrna_struct_as_ptr_parse that maps Python's `None` to #PointerRNA_NULL.
+ */
+int pyrna_struct_as_ptr_or_null_parse(PyObject *o, void *p);
+
void pyrna_struct_type_extend_capi(struct StructRNA *srna,
struct PyMethodDef *py_method,
struct PyGetSetDef *py_getset);
diff --git a/source/blender/python/intern/bpy_rna_context.c b/source/blender/python/intern/bpy_rna_context.c
new file mode 100644
index 00000000000..811552ce938
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_context.c
@@ -0,0 +1,306 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup pythonintern
+ *
+ * This file adds some helper methods to the context, that cannot fit well in RNA itself.
+ */
+
+#include <Python.h>
+
+#include "BLI_listbase.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "bpy_rna_context.h"
+
+#include "RNA_access.h"
+#include "RNA_prototypes.h"
+
+#include "bpy_rna.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Temporary Context Override (Python Context Manager)
+ * \{ */
+
+typedef struct ContextStore {
+ wmWindow *win;
+ bool win_is_set;
+ ScrArea *area;
+ bool area_is_set;
+ ARegion *region;
+ bool region_is_set;
+} ContextStore;
+
+typedef struct BPyContextTempOverride {
+ PyObject_HEAD /* Required Python macro. */
+ bContext *context;
+
+ ContextStore ctx_init;
+ ContextStore ctx_temp;
+ /** Bypass Python overrides set when calling an operator from Python. */
+ struct bContext_PyState py_state;
+ /**
+ * This dictionary is used to store members that don't have special handling,
+ * see: #bpy_context_temp_override_extract_known_args,
+ * these will then be accessed via #BPY_context_member_get.
+ *
+ * This also supports nested *stacking*, so a nested temp-context-overrides
+ * will overlay the new members on the old members (instead of ignoring them).
+ */
+ PyObject *py_state_context_dict;
+} BPyContextTempOverride;
+
+static void bpy_rna_context_temp_override__tp_dealloc(BPyContextTempOverride *self)
+{
+ PyObject_DEL(self);
+}
+
+static PyObject *bpy_rna_context_temp_override_enter(BPyContextTempOverride *self)
+{
+ bContext *C = self->context;
+
+ CTX_py_state_push(C, &self->py_state, self->py_state_context_dict);
+
+ self->ctx_init.win = CTX_wm_window(C);
+ self->ctx_init.win_is_set = (self->ctx_init.win != self->ctx_temp.win);
+ self->ctx_init.area = CTX_wm_area(C);
+ self->ctx_init.area_is_set = (self->ctx_init.area != self->ctx_temp.area);
+ self->ctx_init.region = CTX_wm_region(C);
+ self->ctx_init.region_is_set = (self->ctx_init.region != self->ctx_temp.region);
+
+ wmWindow *win = self->ctx_temp.win_is_set ? self->ctx_temp.win : self->ctx_init.win;
+ bScreen *screen = win ? WM_window_get_active_screen(win) : NULL;
+ ScrArea *area = self->ctx_temp.area_is_set ? self->ctx_temp.area : self->ctx_init.area;
+ ARegion *region = self->ctx_temp.region_is_set ? self->ctx_temp.region : self->ctx_init.region;
+
+ /* Sanity check, the region is in the screen/area. */
+ if (self->ctx_temp.region_is_set && (region != NULL)) {
+ if (area == NULL) {
+ PyErr_SetString(PyExc_TypeError, "Region set with NULL area");
+ return NULL;
+ }
+ if ((screen && BLI_findindex(&screen->regionbase, region) == -1) &&
+ (BLI_findindex(&area->regionbase, region) == -1)) {
+ PyErr_SetString(PyExc_TypeError, "Region not found in area");
+ return NULL;
+ }
+ }
+
+ if (self->ctx_temp.area_is_set && (area != NULL)) {
+ if (screen == NULL) {
+ PyErr_SetString(PyExc_TypeError, "Area set with NULL screen");
+ return NULL;
+ }
+ if (BLI_findindex(&screen->areabase, area) == -1) {
+ PyErr_SetString(PyExc_TypeError, "Area not found in screen");
+ return NULL;
+ }
+ }
+
+ if (self->ctx_temp.win_is_set) {
+ CTX_wm_window_set(C, self->ctx_temp.win);
+ }
+ if (self->ctx_temp.area_is_set) {
+ CTX_wm_area_set(C, self->ctx_temp.area);
+ }
+ if (self->ctx_temp.region_is_set) {
+ CTX_wm_region_set(C, self->ctx_temp.region);
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *bpy_rna_context_temp_override_exit(BPyContextTempOverride *self,
+ PyObject *UNUSED(args))
+{
+ bContext *C = self->context;
+
+ /* Special case where the window is expected to be freed on file-read,
+ * in this case the window should not be restored, see: T92818. */
+ bool do_restore = true;
+ if (self->ctx_init.win) {
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (BLI_findindex(&wm->windows, self->ctx_init.win) == -1) {
+ CTX_wm_window_set(C, NULL);
+ do_restore = false;
+ }
+ }
+
+ if (do_restore) {
+ if (self->ctx_init.win_is_set) {
+ CTX_wm_window_set(C, self->ctx_init.win);
+ }
+ if (self->ctx_init.area_is_set) {
+ CTX_wm_area_set(C, self->ctx_init.area);
+ }
+ if (self->ctx_init.region_is_set) {
+ CTX_wm_region_set(C, self->ctx_init.region);
+ }
+ }
+
+ CTX_py_state_pop(C, &self->py_state);
+ Py_CLEAR(self->py_state_context_dict);
+
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef bpy_rna_context_temp_override__tp_methods[] = {
+ {"__enter__", (PyCFunction)bpy_rna_context_temp_override_enter, METH_NOARGS},
+ {"__exit__", (PyCFunction)bpy_rna_context_temp_override_exit, METH_VARARGS},
+ {NULL},
+};
+
+static PyTypeObject BPyContextTempOverride_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0).tp_name = "ContextTempOverride",
+ .tp_basicsize = sizeof(BPyContextTempOverride),
+ .tp_dealloc = (destructor)bpy_rna_context_temp_override__tp_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_methods = bpy_rna_context_temp_override__tp_methods,
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Context Temporary Override Method
+ * \{ */
+
+static PyObject *bpy_context_temp_override_extract_known_args(const char *const *kwds_static,
+ PyObject *kwds)
+{
+ PyObject *sentinel = Py_Ellipsis;
+ PyObject *kwds_parse = PyDict_New();
+ for (int i = 0; kwds_static[i]; i++) {
+ PyObject *key = PyUnicode_FromString(kwds_static[i]);
+ PyObject *val = _PyDict_Pop(kwds, key, sentinel);
+ if (val != sentinel) {
+ if (PyDict_SetItem(kwds_parse, key, val) == -1) {
+ BLI_assert_unreachable();
+ }
+ }
+ Py_DECREF(key);
+ Py_DECREF(val);
+ }
+ return kwds_parse;
+}
+
+PyDoc_STRVAR(bpy_context_temp_override_doc,
+ ".. method:: temp_override(window, area, region, **keywords)\n"
+ "\n"
+ " Context manager to temporarily override members in the context.\n"
+ "\n"
+ " :arg window: Window override or None.\n"
+ " :type window: :class:`bpy.types.Window`\n"
+ " :arg area: Area override or None.\n"
+ " :type area: :class:`bpy.types.Area`\n"
+ " :arg region: Region override or None.\n"
+ " :type region: :class:`bpy.types.Region`\n"
+ " :arg keywords: Additional keywords override context members.\n"
+ " :return: The context manager .\n"
+ " :rtype: context manager\n");
+static PyObject *bpy_context_temp_override(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ const PointerRNA *context_ptr = pyrna_struct_as_ptr(self, &RNA_Context);
+ if (context_ptr == NULL) {
+ return NULL;
+ }
+
+ if (kwds == NULL) {
+ /* While this is effectively NOP, support having no keywords as it's more involved
+ * to return an alternative (dummy) context manager. */
+ }
+ else {
+ /* Needed because the keywords copied into `kwds_parse` could contain anything.
+ * As the types of keys aren't checked. */
+ if (!PyArg_ValidateKeywordArguments(kwds)) {
+ return NULL;
+ }
+ }
+
+ struct {
+ struct BPy_StructRNA_Parse window;
+ struct BPy_StructRNA_Parse area;
+ struct BPy_StructRNA_Parse region;
+ } params = {
+ .window = {.type = &RNA_Window},
+ .area = {.type = &RNA_Area},
+ .region = {.type = &RNA_Region},
+ };
+
+ static const char *const _keywords[] = {"window", "area", "region", NULL};
+ static _PyArg_Parser _parser = {
+ "|$" /* Optional, keyword only arguments. */
+ "O&" /* `window` */
+ "O&" /* `area` */
+ "O&" /* `region` */
+ ":temp_override",
+ _keywords,
+ 0,
+ };
+ /* Parse known keywords, the remaining keywords are set using #CTX_py_state_push. */
+ kwds = kwds ? PyDict_Copy(kwds) : PyDict_New();
+ {
+ PyObject *kwds_parse = bpy_context_temp_override_extract_known_args(_keywords, kwds);
+ const int parse_result = _PyArg_ParseTupleAndKeywordsFast(args,
+ kwds_parse,
+ &_parser,
+ pyrna_struct_as_ptr_or_null_parse,
+ &params.window,
+ pyrna_struct_as_ptr_or_null_parse,
+ &params.area,
+ pyrna_struct_as_ptr_or_null_parse,
+ &params.region);
+ Py_DECREF(kwds_parse);
+ if (parse_result == -1) {
+ Py_DECREF(kwds);
+ return NULL;
+ }
+ }
+
+ bContext *C = context_ptr->data;
+ {
+ /* Merge existing keys that don't exist in the keywords passed in.
+ * This makes it possible to nest context overrides. */
+ PyObject *context_dict_current = CTX_py_dict_get(C);
+ if (context_dict_current != NULL) {
+ PyDict_Merge(kwds, context_dict_current, 0);
+ }
+ }
+
+ ContextStore ctx_temp = {NULL};
+ if (params.window.ptr != NULL) {
+ ctx_temp.win = params.window.ptr->data;
+ ctx_temp.win_is_set = true;
+ }
+ if (params.area.ptr != NULL) {
+ ctx_temp.area = params.area.ptr->data;
+ ctx_temp.area_is_set = true;
+ }
+
+ if (params.region.ptr != NULL) {
+ ctx_temp.region = params.region.ptr->data;
+ ctx_temp.region_is_set = true;
+ }
+
+ BPyContextTempOverride *ret = PyObject_New(BPyContextTempOverride, &BPyContextTempOverride_Type);
+ ret->context = C;
+ ret->ctx_temp = ctx_temp;
+ memset(&ret->ctx_init, 0, sizeof(ret->ctx_init));
+
+ ret->py_state_context_dict = kwds;
+
+ return (PyObject *)ret;
+}
+
+/** \} */
+
+PyMethodDef BPY_rna_context_temp_override_method_def = {
+ "temp_override",
+ (PyCFunction)bpy_context_temp_override,
+ METH_VARARGS | METH_KEYWORDS,
+ bpy_context_temp_override_doc,
+};
diff --git a/source/blender/python/intern/bpy_rna_context.h b/source/blender/python/intern/bpy_rna_context.h
new file mode 100644
index 00000000000..ddd328131e6
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_context.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup pythonintern
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern PyMethodDef BPY_rna_context_temp_override_method_def;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/python/intern/bpy_rna_types_capi.c b/source/blender/python/intern/bpy_rna_types_capi.c
index a5299bc1616..376195ab845 100644
--- a/source/blender/python/intern/bpy_rna_types_capi.c
+++ b/source/blender/python/intern/bpy_rna_types_capi.c
@@ -22,6 +22,7 @@
#include "bpy_library.h"
#include "bpy_rna.h"
#include "bpy_rna_callback.h"
+#include "bpy_rna_context.h"
#include "bpy_rna_data.h"
#include "bpy_rna_id_collection.h"
#include "bpy_rna_text.h"
@@ -159,6 +160,17 @@ static struct PyGetSetDef pyrna_windowmanager_getset[] = {
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Context Type
+ * \{ */
+
+static struct PyMethodDef pyrna_context_methods[] = {
+ {NULL, NULL, 0, NULL}, /* #BPY_rna_context_temp_override_method_def */
+ {NULL, NULL, 0, NULL},
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Space Type
* \{ */
@@ -254,6 +266,10 @@ void BPY_rna_types_extend_capi(void)
/* WindowManager */
pyrna_struct_type_extend_capi(
&RNA_WindowManager, pyrna_windowmanager_methods, pyrna_windowmanager_getset);
+
+ /* Context */
+ ARRAY_SET_ITEMS(pyrna_context_methods, BPY_rna_context_temp_override_method_def);
+ pyrna_struct_type_extend_capi(&RNA_Context, pyrna_context_methods, NULL);
}
/** \} */
diff --git a/source/blender/render/RE_bake.h b/source/blender/render/RE_bake.h
index da48599fdf9..56c66df5925 100644
--- a/source/blender/render/RE_bake.h
+++ b/source/blender/render/RE_bake.h
@@ -19,6 +19,8 @@ extern "C" {
typedef struct BakeImage {
struct Image *image;
+ int tile_number;
+ float uv_offset[2];
int width;
int height;
size_t offset;
@@ -30,7 +32,7 @@ typedef struct BakeTargets {
int images_num;
/* Lookup table from Material number to BakeImage. */
- int *material_to_image;
+ struct Image **material_to_image;
int materials_num;
/* Pixel buffer to bake to. */
@@ -104,7 +106,8 @@ void RE_bake_margin(struct ImBuf *ibuf,
int margin,
char margin_type,
struct Mesh const *me,
- char const *uv_layer);
+ char const *uv_layer,
+ const float uv_offset[2]);
void RE_bake_normal_world_to_object(const BakePixel pixel_array[],
size_t pixels_num,
diff --git a/source/blender/render/RE_texture_margin.h b/source/blender/render/RE_texture_margin.h
index 85bd06b9940..0c91abeaddd 100644
--- a/source/blender/render/RE_texture_margin.h
+++ b/source/blender/render/RE_texture_margin.h
@@ -25,13 +25,18 @@ struct Mesh;
* \param me: the mesh to use the polygons of.
* \param uv_layer: The UV layer to use.
*/
-void RE_generate_texturemargin_adjacentfaces(
- struct ImBuf *ibuf, char *mask, const int margin, struct Mesh const *me, char const *uv_layer);
+void RE_generate_texturemargin_adjacentfaces(struct ImBuf *ibuf,
+ char *mask,
+ const int margin,
+ struct Mesh const *me,
+ char const *uv_layer,
+ const float uv_offset[2]);
void RE_generate_texturemargin_adjacentfaces_dm(struct ImBuf *ibuf,
char *mask,
const int margin,
- struct DerivedMesh *dm);
+ struct DerivedMesh *dm,
+ const float uv_offset[2]);
#ifdef __cplusplus
}
diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c
index 69235fb6cb1..5953c0f0f8f 100644
--- a/source/blender/render/intern/bake.c
+++ b/source/blender/render/intern/bake.c
@@ -146,12 +146,13 @@ void RE_bake_margin(ImBuf *ibuf,
const int margin,
const char margin_type,
Mesh const *me,
- char const *uv_layer)
+ char const *uv_layer,
+ const float uv_offset[2])
{
/* margin */
switch (margin_type) {
case R_BAKE_ADJACENT_FACES:
- RE_generate_texturemargin_adjacentfaces(ibuf, mask, margin, me, uv_layer);
+ RE_generate_texturemargin_adjacentfaces(ibuf, mask, margin, me, uv_layer, uv_offset);
break;
default:
/* fall through */
@@ -746,30 +747,36 @@ void RE_bake_pixels_populate(Mesh *me,
for (int i = 0; i < tottri; i++) {
const MLoopTri *lt = &looptri[i];
const MPoly *mp = &me->mpoly[lt->poly];
- float vec[3][2];
- int mat_nr = mp->mat_nr;
- int image_id = targets->material_to_image[mat_nr];
- if (image_id < 0) {
- continue;
- }
-
- bd.bk_image = &targets->images[image_id];
bd.primitive_id = i;
- for (int a = 0; a < 3; a++) {
- const float *uv = mloopuv[lt->tri[a]].uv;
+ /* Find images matching this material. */
+ Image *image = targets->material_to_image[mp->mat_nr];
+ for (int image_id = 0; image_id < targets->images_num; image_id++) {
+ BakeImage *bk_image = &targets->images[image_id];
+ if (bk_image->image != image) {
+ continue;
+ }
- /* NOTE(campbell): workaround for pixel aligned UVs which are common and can screw up our
- * intersection tests where a pixel gets in between 2 faces or the middle of a quad,
- * camera aligned quads also have this problem but they are less common.
- * Add a small offset to the UVs, fixes bug T18685. */
- vec[a][0] = uv[0] * (float)bd.bk_image->width - (0.5f + 0.001f);
- vec[a][1] = uv[1] * (float)bd.bk_image->height - (0.5f + 0.002f);
- }
+ /* Compute triangle vertex UV coordinates. */
+ float vec[3][2];
+ for (int a = 0; a < 3; a++) {
+ const float *uv = mloopuv[lt->tri[a]].uv;
+
+ /* NOTE(campbell): workaround for pixel aligned UVs which are common and can screw up our
+ * intersection tests where a pixel gets in between 2 faces or the middle of a quad,
+ * camera aligned quads also have this problem but they are less common.
+ * Add a small offset to the UVs, fixes bug T18685. */
+ vec[a][0] = (uv[0] - bk_image->uv_offset[0]) * (float)bk_image->width - (0.5f + 0.001f);
+ vec[a][1] = (uv[1] - bk_image->uv_offset[1]) * (float)bk_image->height - (0.5f + 0.002f);
+ }
- bake_differentials(&bd, vec[0], vec[1], vec[2]);
- zspan_scanconvert(&bd.zspan[image_id], (void *)&bd, vec[0], vec[1], vec[2], store_bake_pixel);
+ /* Rasterize triangle. */
+ bd.bk_image = bk_image;
+ bake_differentials(&bd, vec[0], vec[1], vec[2]);
+ zspan_scanconvert(
+ &bd.zspan[image_id], (void *)&bd, vec[0], vec[1], vec[2], store_bake_pixel);
+ }
}
for (int i = 0; i < targets->images_num; i++) {
diff --git a/source/blender/render/intern/multires_bake.c b/source/blender/render/intern/multires_bake.c
index 33d961c027d..f93397eedab 100644
--- a/source/blender/render/intern/multires_bake.c
+++ b/source/blender/render/intern/multires_bake.c
@@ -51,7 +51,7 @@ typedef void (*MPassKnownData)(DerivedMesh *lores_dm,
const int x,
const int y);
-typedef void *(*MInitBakeData)(MultiresBakeRender *bkr, Image *ima);
+typedef void *(*MInitBakeData)(MultiresBakeRender *bkr, ImBuf *ibuf);
typedef void (*MFreeBakeData)(void *bake_data);
typedef struct MultiresBakeResult {
@@ -64,6 +64,7 @@ typedef struct {
MPoly *mpoly;
MLoop *mloop;
MLoopUV *mloopuv;
+ float uv_offset[2];
const MLoopTri *mlooptri;
float *pvtangent;
const float (*precomputed_normals)[3];
@@ -91,7 +92,6 @@ typedef struct {
typedef struct {
float *heights;
- Image *ima;
DerivedMesh *ssdm;
const int *orig_index_mp_to_orig;
} MHeightBakeData;
@@ -148,7 +148,8 @@ static void init_bake_rast(MBakeRast *bake_rast,
static void flush_pixel(const MResolvePixelData *data, const int x, const int y)
{
- const float st[2] = {(x + 0.5f) / data->w, (y + 0.5f) / data->h};
+ const float st[2] = {(x + 0.5f) / data->w + data->uv_offset[0],
+ (y + 0.5f) / data->h + data->uv_offset[1]};
const float *st0, *st1, *st2;
const float *tang0, *tang1, *tang2;
float no0[3], no1[3], no2[3];
@@ -395,8 +396,12 @@ static void *do_multires_bake_thread(void *data_v)
data->tri_index = tri_index;
- bake_rasterize(
- bake_rast, mloopuv[lt->tri[0]].uv, mloopuv[lt->tri[1]].uv, mloopuv[lt->tri[2]].uv);
+ float uv[3][2];
+ sub_v2_v2v2(uv[0], mloopuv[lt->tri[0]].uv, data->uv_offset);
+ sub_v2_v2v2(uv[1], mloopuv[lt->tri[1]].uv, data->uv_offset);
+ sub_v2_v2v2(uv[2], mloopuv[lt->tri[2]].uv, data->uv_offset);
+
+ bake_rasterize(bake_rast, uv[0], uv[1], uv[2]);
/* tag image buffer for refresh */
if (data->ibuf->rect_float) {
@@ -447,6 +452,8 @@ static void init_ccgdm_arrays(DerivedMesh *dm)
static void do_multires_bake(MultiresBakeRender *bkr,
Image *ima,
+ ImageTile *tile,
+ ImBuf *ibuf,
bool require_tangent,
MPassKnownData passKnownData,
MInitBakeData initBakeData,
@@ -462,7 +469,6 @@ static void do_multires_bake(MultiresBakeRender *bkr,
MultiresBakeThread *handles;
MultiresBakeQueue queue;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
MVert *mvert = dm->getVertArray(dm);
MPoly *mpoly = dm->getPolyArray(dm);
MLoop *mloop = dm->getLoopArray(dm);
@@ -511,7 +517,7 @@ static void do_multires_bake(MultiresBakeRender *bkr,
/* all threads shares the same custom bake data */
if (initBakeData) {
- bake_data = initBakeData(bkr, ima);
+ bake_data = initBakeData(bkr, ibuf);
}
if (tot_thread > 1) {
@@ -539,6 +545,7 @@ static void do_multires_bake(MultiresBakeRender *bkr,
handle->data.mvert = mvert;
handle->data.vert_normals = vert_normals;
handle->data.mloopuv = mloopuv;
+ BKE_image_get_tile_uv(ima, tile->tile_number, handle->data.uv_offset);
handle->data.mlooptri = mlooptri;
handle->data.mloop = mloop;
handle->data.pvtangent = pvtangent;
@@ -590,8 +597,6 @@ static void do_multires_bake(MultiresBakeRender *bkr,
MEM_freeN(handles);
BKE_id_free(NULL, temp_mesh);
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
}
}
@@ -758,10 +763,9 @@ static void interp_barycentric_mlooptri(DerivedMesh *dm,
/* **************** Displacement Baker **************** */
-static void *init_heights_data(MultiresBakeRender *bkr, Image *ima)
+static void *init_heights_data(MultiresBakeRender *bkr, ImBuf *ibuf)
{
MHeightBakeData *height_data;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
DerivedMesh *lodm = bkr->lores_dm;
BakeImBufuserData *userdata = ibuf->userdata;
@@ -772,7 +776,6 @@ static void *init_heights_data(MultiresBakeRender *bkr, Image *ima)
height_data = MEM_callocN(sizeof(MHeightBakeData), "MultiresBake heightData");
- height_data->ima = ima;
height_data->heights = userdata->displacement_buffer;
if (!bkr->use_lores_mesh) {
@@ -794,8 +797,6 @@ static void *init_heights_data(MultiresBakeRender *bkr, Image *ima)
height_data->orig_index_mp_to_orig = lodm->getPolyDataArray(lodm, CD_ORIGINDEX);
- BKE_image_release_ibuf(ima, ibuf, NULL);
-
return (void *)height_data;
}
@@ -903,7 +904,7 @@ static void apply_heights_callback(DerivedMesh *lores_dm,
/* **************** Normal Maps Baker **************** */
-static void *init_normal_data(MultiresBakeRender *bkr, Image *UNUSED(ima))
+static void *init_normal_data(MultiresBakeRender *bkr, ImBuf *UNUSED(ibuf))
{
MNormalBakeData *normal_data;
DerivedMesh *lodm = bkr->lores_dm;
@@ -1099,7 +1100,7 @@ static void create_ao_raytree(MultiresBakeRender *bkr, MAOBakeData *ao_data)
RE_rayobject_done(raytree);
}
-static void *init_ao_data(MultiresBakeRender *bkr, Image *UNUSED(ima))
+static void *init_ao_data(MultiresBakeRender *bkr, ImBuf *UNUSED(ibuf))
{
MAOBakeData *ao_data;
DerivedMesh *lodm = bkr->lores_dm;
@@ -1313,8 +1314,12 @@ static void apply_ao_callback(DerivedMesh *lores_dm,
/* ******$***************** Post processing ************************* */
-static void bake_ibuf_filter(
- ImBuf *ibuf, char *mask, const int margin, const char margin_type, DerivedMesh *dm)
+static void bake_ibuf_filter(ImBuf *ibuf,
+ char *mask,
+ const int margin,
+ const char margin_type,
+ DerivedMesh *dm,
+ const float uv_offset[2])
{
/* must check before filtering */
const bool is_new_alpha = (ibuf->planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(ibuf);
@@ -1322,7 +1327,7 @@ static void bake_ibuf_filter(
if (margin) {
switch (margin_type) {
case R_BAKE_ADJACENT_FACES:
- RE_generate_texturemargin_adjacentfaces_dm(ibuf, mask, margin, dm);
+ RE_generate_texturemargin_adjacentfaces_dm(ibuf, mask, margin, dm, uv_offset);
break;
default:
/* fall through */
@@ -1427,38 +1432,54 @@ static void bake_images(MultiresBakeRender *bkr, MultiresBakeResult *result)
for (link = bkr->image.first; link; link = link->next) {
Image *ima = (Image *)link->data;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
-
- if (ibuf->x > 0 && ibuf->y > 0) {
- BakeImBufuserData *userdata = MEM_callocN(sizeof(BakeImBufuserData),
- "MultiresBake userdata");
- userdata->mask_buffer = MEM_callocN(ibuf->y * ibuf->x, "MultiresBake imbuf mask");
- ibuf->userdata = userdata;
-
- switch (bkr->mode) {
- case RE_BAKE_NORMALS:
- do_multires_bake(
- bkr, ima, true, apply_tangmat_callback, init_normal_data, free_normal_data, result);
- break;
- case RE_BAKE_DISPLACEMENT:
- do_multires_bake(bkr,
- ima,
- false,
- apply_heights_callback,
- init_heights_data,
- free_heights_data,
- result);
- break;
-/* TODO: restore ambient occlusion baking support. */
+
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+ iuser.tile = tile->tile_number;
+
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+
+ if (ibuf->x > 0 && ibuf->y > 0) {
+ BakeImBufuserData *userdata = MEM_callocN(sizeof(BakeImBufuserData),
+ "MultiresBake userdata");
+ userdata->mask_buffer = MEM_callocN(ibuf->y * ibuf->x, "MultiresBake imbuf mask");
+ ibuf->userdata = userdata;
+
+ switch (bkr->mode) {
+ case RE_BAKE_NORMALS:
+ do_multires_bake(bkr,
+ ima,
+ tile,
+ ibuf,
+ true,
+ apply_tangmat_callback,
+ init_normal_data,
+ free_normal_data,
+ result);
+ break;
+ case RE_BAKE_DISPLACEMENT:
+ do_multires_bake(bkr,
+ ima,
+ tile,
+ ibuf,
+ false,
+ apply_heights_callback,
+ init_heights_data,
+ free_heights_data,
+ result);
+ break;
+ /* TODO: restore ambient occlusion baking support. */
#if 0
- case RE_BAKE_AO:
- do_multires_bake(bkr, ima, false, apply_ao_callback, init_ao_data, free_ao_data, result);
- break;
+ case RE_BAKE_AO:
+ do_multires_bake(bkr, ima, tile, ibuf, false, apply_ao_callback, init_ao_data, free_ao_data, result);
+ break;
#endif
+ }
}
- }
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
ima->id.tag |= LIB_TAG_DOIT;
}
@@ -1471,48 +1492,62 @@ static void finish_images(MultiresBakeRender *bkr, MultiresBakeResult *result)
for (link = bkr->image.first; link; link = link->next) {
Image *ima = (Image *)link->data;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
- BakeImBufuserData *userdata = (BakeImBufuserData *)ibuf->userdata;
- if (ibuf->x <= 0 || ibuf->y <= 0) {
- continue;
- }
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+ iuser.tile = tile->tile_number;
- if (use_displacement_buffer) {
- bake_ibuf_normalize_displacement(ibuf,
- userdata->displacement_buffer,
- userdata->mask_buffer,
- result->height_min,
- result->height_max);
- }
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+ BakeImBufuserData *userdata = (BakeImBufuserData *)ibuf->userdata;
- bake_ibuf_filter(
- ibuf, userdata->mask_buffer, bkr->bake_margin, bkr->bake_margin_type, bkr->lores_dm);
+ if (ibuf->x <= 0 || ibuf->y <= 0) {
+ continue;
+ }
- ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
- BKE_image_mark_dirty(ima, ibuf);
+ if (use_displacement_buffer) {
+ bake_ibuf_normalize_displacement(ibuf,
+ userdata->displacement_buffer,
+ userdata->mask_buffer,
+ result->height_min,
+ result->height_max);
+ }
- if (ibuf->rect_float) {
- ibuf->userflags |= IB_RECT_INVALID;
- }
+ float uv_offset[2];
+ BKE_image_get_tile_uv(ima, tile->tile_number, uv_offset);
- if (ibuf->mipmap[0]) {
- ibuf->userflags |= IB_MIPMAP_INVALID;
- imb_freemipmapImBuf(ibuf);
- }
+ bake_ibuf_filter(ibuf,
+ userdata->mask_buffer,
+ bkr->bake_margin,
+ bkr->bake_margin_type,
+ bkr->lores_dm,
+ uv_offset);
+
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+ BKE_image_mark_dirty(ima, ibuf);
- if (ibuf->userdata) {
- if (userdata->displacement_buffer) {
- MEM_freeN(userdata->displacement_buffer);
+ if (ibuf->rect_float) {
+ ibuf->userflags |= IB_RECT_INVALID;
}
- MEM_freeN(userdata->mask_buffer);
- MEM_freeN(userdata);
- ibuf->userdata = NULL;
- }
+ if (ibuf->mipmap[0]) {
+ ibuf->userflags |= IB_MIPMAP_INVALID;
+ imb_freemipmapImBuf(ibuf);
+ }
+
+ if (ibuf->userdata) {
+ if (userdata->displacement_buffer) {
+ MEM_freeN(userdata->displacement_buffer);
+ }
- BKE_image_release_ibuf(ima, ibuf, NULL);
- DEG_id_tag_update(&ima->id, 0);
+ MEM_freeN(userdata->mask_buffer);
+ MEM_freeN(userdata);
+ ibuf->userdata = NULL;
+ }
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ DEG_id_tag_update(&ima->id, 0);
+ }
}
}
diff --git a/source/blender/render/intern/texture_margin.cc b/source/blender/render/intern/texture_margin.cc
index d01c0dbea71..2d68148a86a 100644
--- a/source/blender/render/intern/texture_margin.cc
+++ b/source/blender/render/intern/texture_margin.cc
@@ -46,6 +46,7 @@ class TextureMarginMap {
Vector<int> loop_to_poly_map_;
int w_, h_;
+ float uv_offset_[2];
Vector<uint32_t> pixel_data_;
ZSpan zspan_;
uint32_t value_to_store_;
@@ -61,6 +62,7 @@ class TextureMarginMap {
public:
TextureMarginMap(size_t w,
size_t h,
+ const float uv_offset[2],
MPoly const *mpoly,
MLoop const *mloop,
MLoopUV const *mloopuv,
@@ -76,6 +78,8 @@ class TextureMarginMap {
totloop_(totloop),
totedge_(totedge)
{
+ copy_v2_v2(uv_offset_, uv_offset);
+
pixel_data_.resize(w_ * h_, 0xFFFFFFFF);
zbuf_alloc_span(&zspan_, w_, h_);
@@ -277,8 +281,8 @@ class TextureMarginMap {
float2 uv_to_xy(MLoopUV const &mloopuv) const
{
float2 ret;
- ret.x = ((mloopuv.uv[0] * w_) - (0.5f + 0.001f));
- ret.y = ((mloopuv.uv[1] * h_) - (0.5f + 0.001f));
+ ret.x = (((mloopuv.uv[0] - uv_offset_[0]) * w_) - (0.5f + 0.001f));
+ ret.y = (((mloopuv.uv[1] - uv_offset_[1]) * h_) - (0.5f + 0.001f));
return ret;
}
@@ -482,7 +486,8 @@ static void generate_margin(ImBuf *ibuf,
const int margin,
const Mesh *me,
DerivedMesh *dm,
- char const *uv_layer)
+ char const *uv_layer,
+ const float uv_offset[2])
{
MPoly *mpoly;
@@ -531,7 +536,8 @@ static void generate_margin(ImBuf *ibuf,
tottri = dm->getNumLoopTri(dm);
}
- TextureMarginMap map(ibuf->x, ibuf->y, mpoly, mloop, mloopuv, totpoly, totloop, totedge);
+ TextureMarginMap map(
+ ibuf->x, ibuf->y, uv_offset, mpoly, mloop, mloopuv, totpoly, totloop, totedge);
bool draw_new_mask = false;
/* Now the map contains 3 sorts of values: 0xFFFFFFFF for empty pixels, `0x80000000 + polyindex`
@@ -555,8 +561,8 @@ static void generate_margin(ImBuf *ibuf,
* intersection tests where a pixel gets in between 2 faces or the middle of a quad,
* camera aligned quads also have this problem but they are less common.
* Add a small offset to the UVs, fixes bug T18685. */
- vec[a][0] = uv[0] * (float)ibuf->x - (0.5f + 0.001f);
- vec[a][1] = uv[1] * (float)ibuf->y - (0.5f + 0.002f);
+ vec[a][0] = (uv[0] - uv_offset[0]) * (float)ibuf->x - (0.5f + 0.001f);
+ vec[a][1] = (uv[1] - uv_offset[1]) * (float)ibuf->y - (0.5f + 0.002f);
}
/* NOTE: we need the top bit for the dijkstra distance map. */
@@ -592,16 +598,20 @@ static void generate_margin(ImBuf *ibuf,
} // namespace blender::render::texturemargin
-void RE_generate_texturemargin_adjacentfaces(
- ImBuf *ibuf, char *mask, const int margin, const Mesh *me, char const *uv_layer)
+void RE_generate_texturemargin_adjacentfaces(ImBuf *ibuf,
+ char *mask,
+ const int margin,
+ const Mesh *me,
+ char const *uv_layer,
+ const float uv_offset[2])
{
- blender::render::texturemargin::generate_margin(ibuf, mask, margin, me, nullptr, uv_layer);
+ blender::render::texturemargin::generate_margin(
+ ibuf, mask, margin, me, nullptr, uv_layer, uv_offset);
}
-void RE_generate_texturemargin_adjacentfaces_dm(ImBuf *ibuf,
- char *mask,
- const int margin,
- DerivedMesh *dm)
+void RE_generate_texturemargin_adjacentfaces_dm(
+ ImBuf *ibuf, char *mask, const int margin, DerivedMesh *dm, const float uv_offset[2])
{
- blender::render::texturemargin::generate_margin(ibuf, mask, margin, nullptr, dm, nullptr);
+ blender::render::texturemargin::generate_margin(
+ ibuf, mask, margin, nullptr, dm, nullptr, uv_offset);
}
diff --git a/source/blender/render/intern/texture_pointdensity.c b/source/blender/render/intern/texture_pointdensity.c
index bb313d4962c..8ba3bac7cad 100644
--- a/source/blender/render/intern/texture_pointdensity.c
+++ b/source/blender/render/intern/texture_pointdensity.c
@@ -277,11 +277,12 @@ static void pointdensity_cache_vertex_color(PointDensity *pd,
BLI_assert(data_color);
- if (!CustomData_has_layer(&mesh->ldata, CD_MLOOPCOL)) {
+ if (!CustomData_has_layer(&mesh->ldata, CD_PROP_BYTE_COLOR)) {
return;
}
- CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPCOL, pd->vertex_attribute_name, layername);
- mcol = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPCOL, layername);
+ CustomData_validate_layer_name(
+ &mesh->ldata, CD_PROP_BYTE_COLOR, pd->vertex_attribute_name, layername);
+ mcol = CustomData_get_layer_named(&mesh->ldata, CD_PROP_BYTE_COLOR, layername);
if (!mcol) {
return;
}
@@ -372,7 +373,7 @@ static void pointdensity_cache_object(PointDensity *pd, Object *ob)
mask.fmask |= CD_MASK_MTFACE | CD_MASK_MCOL;
switch (pd->ob_color_source) {
case TEX_PD_COLOR_VERTCOL:
- mask.lmask |= CD_MASK_MLOOPCOL;
+ mask.lmask |= CD_MASK_PROP_BYTE_COLOR;
break;
case TEX_PD_COLOR_VERTWEIGHT:
mask.vmask |= CD_MASK_MDEFORMVERT;
diff --git a/source/blender/sequencer/SEQ_channels.h b/source/blender/sequencer/SEQ_channels.h
index 1d87875fb26..9436d5dfa32 100644
--- a/source/blender/sequencer/SEQ_channels.h
+++ b/source/blender/sequencer/SEQ_channels.h
@@ -15,6 +15,7 @@ struct Editing;
struct ListBase;
struct Scene;
struct SeqTimelineChannel;
+struct Sequence;
struct ListBase *SEQ_channels_displayed_get(struct Editing *ed);
void SEQ_channels_displayed_set(struct Editing *ed, struct ListBase *channels);
@@ -28,6 +29,7 @@ char *SEQ_channel_name_get(struct ListBase *channels, const int channel_index);
bool SEQ_channel_is_locked(const struct SeqTimelineChannel *channel);
bool SEQ_channel_is_muted(const struct SeqTimelineChannel *channel);
int SEQ_channel_index_get(const struct SeqTimelineChannel *channel);
+ListBase *SEQ_get_channels_by_seq(struct ListBase *seqbase, const struct Sequence *seq);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/SEQ_relations.h b/source/blender/sequencer/SEQ_relations.h
index 735b5659ca9..917f549f16d 100644
--- a/source/blender/sequencer/SEQ_relations.h
+++ b/source/blender/sequencer/SEQ_relations.h
@@ -19,6 +19,10 @@ struct Scene;
struct Sequence;
/**
+ * Check if one sequence is input to the other.
+ */
+bool SEQ_relation_is_effect_of_strip(const struct Sequence *effect, const struct Sequence *input);
+/**
* Function to free imbuf and anim data on changes.
*/
void SEQ_relations_sequence_free_anim(struct Sequence *seq);
@@ -64,6 +68,7 @@ void SEQ_cache_iterate(
struct Sequence *SEQ_find_metastrip_by_sequence(ListBase *seqbase /* = ed->seqbase */,
struct Sequence *meta /* = NULL */,
struct Sequence *seq);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/sequencer/SEQ_render.h b/source/blender/sequencer/SEQ_render.h
index bfe10d3eae9..a74eba5fc6f 100644
--- a/source/blender/sequencer/SEQ_render.h
+++ b/source/blender/sequencer/SEQ_render.h
@@ -17,6 +17,7 @@ struct ListBase;
struct Main;
struct Scene;
struct Sequence;
+struct rctf;
typedef enum eSeqTaskId {
SEQ_TASK_MAIN_RENDER,
@@ -64,7 +65,6 @@ struct ImBuf *SEQ_render_give_ibuf_direct(const SeqRenderData *context,
void SEQ_render_thumbnails(const struct SeqRenderData *context,
struct Sequence *seq,
struct Sequence *seq_orig,
- float start_frame,
float frame_step,
rctf *view_area,
const short *stop);
@@ -77,6 +77,18 @@ struct ImBuf *SEQ_get_thumbnail(const struct SeqRenderData *context,
rcti *crop,
bool clipped);
/**
+ * Get frame for first thumbnail.
+ */
+float SEQ_render_thumbnail_first_frame_get(struct Sequence *seq,
+ float frame_step,
+ struct rctf *view_area);
+/**
+ * Get frame for first thumbnail.
+ */
+float SEQ_render_thumbnail_next_frame_get(struct Sequence *seq,
+ float last_frame,
+ float frame_step);
+/**
* Get frame step for equally spaced thumbnails. These thumbnails should always be present in
* memory, so they can be used when zooming.
*/
diff --git a/source/blender/sequencer/SEQ_transform.h b/source/blender/sequencer/SEQ_transform.h
index eb910a5a5d1..a342dfe10a2 100644
--- a/source/blender/sequencer/SEQ_transform.h
+++ b/source/blender/sequencer/SEQ_transform.h
@@ -119,6 +119,22 @@ void SEQ_image_preview_unit_from_px(const struct Scene *scene,
const float co_src[2],
float co_dst[2]);
+/**
+ * Get viewport axis aligned bounding box from a collection of sequences.
+ * The collection must have one or more strips
+ *
+ * \param scene: Scene in which strips are located
+ * \param strips: Collection of strips to get the bounding box from
+ * \param apply_rotation: Include sequence rotation transform in the bounding box calculation
+ * \param r_min: Minimum x and y values
+ * \param r_max: Maximum x and y values
+ */
+void SEQ_image_transform_bounding_box_from_collection(struct Scene *scene,
+ struct SeqCollection *strips,
+ bool apply_rotation,
+ float r_min[2],
+ float r_max[2]);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/sequencer/intern/channels.c b/source/blender/sequencer/intern/channels.c
index e8e82af03f5..21e3461c7d0 100644
--- a/source/blender/sequencer/intern/channels.c
+++ b/source/blender/sequencer/intern/channels.c
@@ -81,3 +81,19 @@ bool SEQ_channel_is_muted(const SeqTimelineChannel *channel)
{
return (channel->flag & SEQ_CHANNEL_MUTE) != 0;
}
+
+ListBase *SEQ_get_channels_by_seq(ListBase *seqbase, const Sequence *seq)
+{
+ ListBase *lb = NULL;
+
+ LISTBASE_FOREACH (Sequence *, iseq, seqbase) {
+ if (seq == iseq) {
+ return seqbase;
+ }
+ if ((lb = SEQ_get_channels_by_seq(&iseq->seqbase, seq))) {
+ return lb;
+ }
+ }
+
+ return NULL;
+}
diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c
index 0192f4f625c..f4fc79a6572 100644
--- a/source/blender/sequencer/intern/effects.c
+++ b/source/blender/sequencer/intern/effects.c
@@ -44,6 +44,7 @@
#include "RE_pipeline.h"
+#include "SEQ_channels.h"
#include "SEQ_effects.h"
#include "SEQ_proxy.h"
#include "SEQ_relations.h"
@@ -2421,8 +2422,6 @@ static ImBuf *do_multicam(const SeqRenderData *context,
{
ImBuf *out;
Editing *ed;
- ListBase *seqbasep;
- ListBase *channels = &seq->channels;
if (seq->multicam_source == 0 || seq->multicam_source >= seq->machine) {
return NULL;
@@ -2432,7 +2431,8 @@ static ImBuf *do_multicam(const SeqRenderData *context,
if (!ed) {
return NULL;
}
- seqbasep = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
+ ListBase *seqbasep = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
+ ListBase *channels = SEQ_get_channels_by_seq(&ed->seqbase, seq);
if (!seqbasep) {
return NULL;
}
@@ -2463,13 +2463,12 @@ static int early_out_adjustment(Sequence *UNUSED(seq), float UNUSED(fac))
static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, float timeline_frame)
{
Editing *ed;
- ListBase *seqbasep;
- ListBase *channels = &seq->channels;
ImBuf *i = NULL;
ed = context->scene->ed;
- seqbasep = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
+ ListBase *seqbasep = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
+ ListBase *channels = SEQ_get_channels_by_seq(&ed->seqbase, seq);
/* Clamp timeline_frame to strip range so it behaves as if it had "still frame" offset (last
* frame is static after end of strip). This is how most strips behave. This way transition
diff --git a/source/blender/sequencer/intern/iterator.c b/source/blender/sequencer/intern/iterator.c
index a4d8cf79d1f..2710edd6e80 100644
--- a/source/blender/sequencer/intern/iterator.c
+++ b/source/blender/sequencer/intern/iterator.c
@@ -20,6 +20,7 @@
#include "BKE_scene.h"
#include "SEQ_iterator.h"
+#include "SEQ_relations.h"
#include "SEQ_render.h"
#include "SEQ_time.h"
#include "render.h"
@@ -241,15 +242,6 @@ static void collection_filter_channel_up_to_incl(SeqCollection *collection, cons
}
}
-static bool seq_is_effect_of(const Sequence *seq_effect, const Sequence *possibly_input)
-{
- if (seq_effect->seq1 == possibly_input || seq_effect->seq2 == possibly_input ||
- seq_effect->seq3 == possibly_input) {
- return true;
- }
- return false;
-}
-
/* Check if seq must be rendered. This depends on whole stack in some cases, not only seq itself.
* Order of applying these conditions is important. */
static bool must_render_strip(const Sequence *seq, SeqCollection *strips_at_timeline_frame)
@@ -262,7 +254,8 @@ static bool must_render_strip(const Sequence *seq, SeqCollection *strips_at_time
return false;
}
- if ((seq_iter->type & SEQ_TYPE_EFFECT) != 0 && seq_is_effect_of(seq_iter, seq)) {
+ if ((seq_iter->type & SEQ_TYPE_EFFECT) != 0 &&
+ SEQ_relation_is_effect_of_strip(seq_iter, seq)) {
/* Strips in same channel or higher than its effect are rendered. */
if (seq->machine >= seq_iter->machine) {
return true;
diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c
index 18b0794dc72..8d8a13be09e 100644
--- a/source/blender/sequencer/intern/render.c
+++ b/source/blender/sequencer/intern/render.c
@@ -1992,6 +1992,32 @@ ImBuf *SEQ_render_give_ibuf_direct(const SeqRenderData *context,
return ibuf;
}
+float SEQ_render_thumbnail_first_frame_get(Sequence *seq, float frame_step, rctf *view_area)
+{
+ int first_drawable_frame = max_iii(seq->startdisp, seq->start, view_area->xmin);
+
+ /* First frame should correspond to handle position. */
+ if (first_drawable_frame == seq->startdisp) {
+ return seq->startdisp;
+ }
+
+ float aligned_frame_offset = (int)((first_drawable_frame - seq->start) / frame_step) *
+ frame_step;
+ return seq->start + aligned_frame_offset;
+}
+
+float SEQ_render_thumbnail_next_frame_get(Sequence *seq, float last_frame, float frame_step)
+{
+ float next_frame = last_frame + frame_step;
+
+ /* If handle position was displayed, align next frame with `seq->start`. */
+ if (last_frame == seq->startdisp) {
+ next_frame = seq->start + ((int)((last_frame - seq->start) / frame_step) + 1) * frame_step;
+ }
+
+ return next_frame;
+}
+
/* Gets the direct image from source and scales to thumbnail size. */
static ImBuf *seq_get_uncached_thumbnail(const SeqRenderData *context,
SeqRenderState *state,
@@ -2053,7 +2079,6 @@ ImBuf *SEQ_get_thumbnail(
void SEQ_render_thumbnails(const SeqRenderData *context,
Sequence *seq,
Sequence *seq_orig,
- float start_frame,
float frame_step,
rctf *view_area,
const short *stop)
@@ -2063,24 +2088,24 @@ void SEQ_render_thumbnails(const SeqRenderData *context,
/* Adding the hold offset value (seq->anim_startofs) to the start frame. Position of image not
* affected, but frame loaded affected. */
- start_frame = start_frame - frame_step;
float upper_thumb_bound = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp;
upper_thumb_bound = (upper_thumb_bound > view_area->xmax) ? view_area->xmax + frame_step :
upper_thumb_bound;
- while ((start_frame < upper_thumb_bound) & !*stop) {
+ float timeline_frame = SEQ_render_thumbnail_first_frame_get(seq, frame_step, view_area);
+ while ((timeline_frame < upper_thumb_bound) & !*stop) {
ImBuf *ibuf = seq_cache_get(
- context, seq_orig, round_fl_to_int(start_frame), SEQ_CACHE_STORE_THUMBNAIL);
+ context, seq_orig, round_fl_to_int(timeline_frame), SEQ_CACHE_STORE_THUMBNAIL);
if (ibuf) {
IMB_freeImBuf(ibuf);
- start_frame += frame_step;
+ timeline_frame = SEQ_render_thumbnail_next_frame_get(seq, timeline_frame, frame_step);
continue;
}
- ibuf = seq_get_uncached_thumbnail(context, &state, seq, round_fl_to_int(start_frame));
+ ibuf = seq_get_uncached_thumbnail(context, &state, seq, round_fl_to_int(timeline_frame));
if (ibuf) {
- seq_cache_thumbnail_put(context, seq_orig, round_fl_to_int(start_frame), ibuf, view_area);
+ seq_cache_thumbnail_put(context, seq_orig, round_fl_to_int(timeline_frame), ibuf, view_area);
IMB_freeImBuf(ibuf);
seq_orig->flag &= ~SEQ_FLAG_SKIP_THUMBNAILS;
}
@@ -2090,7 +2115,7 @@ void SEQ_render_thumbnails(const SeqRenderData *context,
return;
}
- start_frame += frame_step;
+ timeline_frame = SEQ_render_thumbnail_next_frame_get(seq, timeline_frame, frame_step);
}
}
diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c
index 7aa81f5ae8a..6c7bb71cb75 100644
--- a/source/blender/sequencer/intern/strip_edit.c
+++ b/source/blender/sequencer/intern/strip_edit.c
@@ -154,8 +154,7 @@ static void sequencer_flag_users_for_removal(Scene *scene, ListBase *seqbase, Se
}
/* Remove effects, that use seq. */
- if ((user_seq->seq1 && user_seq->seq1 == seq) || (user_seq->seq2 && user_seq->seq2 == seq) ||
- (user_seq->seq3 && user_seq->seq3 == seq)) {
+ if (SEQ_relation_is_effect_of_strip(user_seq, seq)) {
user_seq->flag |= SEQ_FLAG_DELETE;
/* Strips can be used as mask even if not in same seqbase. */
sequencer_flag_users_for_removal(scene, &scene->ed->seqbase, user_seq);
diff --git a/source/blender/sequencer/intern/strip_relations.c b/source/blender/sequencer/intern/strip_relations.c
index a65a331c650..1899cc99263 100644
--- a/source/blender/sequencer/intern/strip_relations.c
+++ b/source/blender/sequencer/intern/strip_relations.c
@@ -34,10 +34,15 @@
#include "image_cache.h"
#include "utils.h"
+bool SEQ_relation_is_effect_of_strip(const Sequence *effect, const Sequence *input)
+{
+ return ELEM(input, effect->seq1, effect->seq2);
+}
+
/* check whether sequence cur depends on seq */
static bool seq_relations_check_depend(Sequence *seq, Sequence *cur)
{
- if (cur->seq1 == seq || cur->seq2 == seq || cur->seq3 == seq) {
+ if (SEQ_relation_is_effect_of_strip(cur, seq)) {
return true;
}
diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c
index 087e2610bd6..2c9ab0a3335 100644
--- a/source/blender/sequencer/intern/strip_transform.c
+++ b/source/blender/sequencer/intern/strip_transform.c
@@ -297,6 +297,9 @@ static int shuffle_seq_time_offset_test(SeqCollection *strips_to_shuffle,
if (!SEQ_transform_test_overlap_seq_seq(seq, seq_other)) {
continue;
}
+ if (SEQ_relation_is_effect_of_strip(seq_other, seq)) {
+ continue;
+ }
if (UNLIKELY(SEQ_collection_has_strip(seq_other, strips_to_shuffle))) {
CLOG_WARN(&LOG,
"Strip overlaps with itself or another strip, that is to be shuffled. "
@@ -517,3 +520,18 @@ void SEQ_image_preview_unit_from_px(const Scene *scene, const float co_src[2], f
co_dst[0] = co_src[0] / scene->r.xsch;
co_dst[1] = co_src[1] / scene->r.ysch;
}
+
+void SEQ_image_transform_bounding_box_from_collection(
+ Scene *scene, SeqCollection *strips, bool apply_rotation, float r_min[2], float r_max[2])
+{
+ Sequence *seq;
+
+ INIT_MINMAX2(r_min, r_max);
+ SEQ_ITERATOR_FOREACH (seq, strips) {
+ float quad[4][2];
+ SEQ_image_transform_quad_get(scene, seq, apply_rotation, quad);
+ for (int i = 0; i < 4; i++) {
+ minmax_v2v2_v2(r_min, r_max, quad[i]);
+ }
+ }
+}
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h b/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
index ef6bee0c1fe..992c7a9b2ec 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
@@ -124,7 +124,7 @@ struct wmGizmoMap {
/**
* This is a container for all gizmo types that can be instantiated in a region.
- * (similar to dropboxes).
+ * (similar to drop-boxes).
*
* \note There is only ever one of these for every (area, region) combination.
*/
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index d17afad0918..7457358698d 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -896,16 +896,32 @@ elseif(WIN32)
endif()
if(WITH_CODEC_FFMPEG)
- install(
- FILES
- ${LIBDIR}/ffmpeg/lib/avcodec-58.dll
- ${LIBDIR}/ffmpeg/lib/avformat-58.dll
- ${LIBDIR}/ffmpeg/lib/avdevice-58.dll
- ${LIBDIR}/ffmpeg/lib/avutil-56.dll
- ${LIBDIR}/ffmpeg/lib/swscale-5.dll
- ${LIBDIR}/ffmpeg/lib/swresample-3.dll
- DESTINATION "."
- )
+ # Filenames change slightly between ffmpeg versions
+ # check both 5.0 and fallback to 4.4 to ease the transition
+ # between versions.
+ if(EXISTS "${LIBDIR}/ffmpeg/lib/avcodec-59.dll")
+ install(
+ FILES
+ ${LIBDIR}/ffmpeg/lib/avcodec-59.dll
+ ${LIBDIR}/ffmpeg/lib/avformat-59.dll
+ ${LIBDIR}/ffmpeg/lib/avdevice-59.dll
+ ${LIBDIR}/ffmpeg/lib/avutil-57.dll
+ ${LIBDIR}/ffmpeg/lib/swscale-6.dll
+ ${LIBDIR}/ffmpeg/lib/swresample-4.dll
+ DESTINATION "."
+ )
+ else()
+ install(
+ FILES
+ ${LIBDIR}/ffmpeg/lib/avcodec-58.dll
+ ${LIBDIR}/ffmpeg/lib/avformat-58.dll
+ ${LIBDIR}/ffmpeg/lib/avdevice-58.dll
+ ${LIBDIR}/ffmpeg/lib/avutil-56.dll
+ ${LIBDIR}/ffmpeg/lib/swscale-5.dll
+ ${LIBDIR}/ffmpeg/lib/swresample-3.dll
+ DESTINATION "."
+ )
+ endif()
endif()
if(WITH_TBB)
install(
diff --git a/source/tools b/source/tools
-Subproject 4c1e01e3e309282beb1af3b1eddb2c7f9a666b5
+Subproject 1e658ca996f11e5ff3398d89bd81f5b719304a5