From ccbde00a835a6cd88d8409608339a87e62d5bb46 Mon Sep 17 00:00:00 2001 From: Joseph Eagar Date: Sun, 23 Jan 2022 12:27:34 -0800 Subject: [PATCH] Merge sculpt-dev -> master --- build_files/build_environment/CMakeLists.txt | 1 + .../build_environment/cmake/download.cmake | 1 + .../build_environment/cmake/freetype.cmake | 10 +- .../build_environment/cmake/harvest.cmake | 2 + .../build_environment/cmake/versions.cmake | 11 +- build_files/build_environment/install_deps.sh | 2 +- .../cmake/platform/platform_apple.cmake | 4 + .../cmake/platform/platform_unix.cmake | 8 +- .../cmake/platform/platform_win32.cmake | 6 +- .../bpy.types.Bone.convert_local_to_pose.py | 51 +- doc/python_api/sphinx_doc_gen.py | 1 + intern/cycles/blender/addon/ui.py | 42 +- intern/cycles/blender/mesh.cpp | 10 +- intern/cycles/blender/object.cpp | 11 + intern/cycles/blender/output_driver.cpp | 4 +- intern/cycles/device/metal/bvh.h | 5 + intern/cycles/device/metal/bvh.mm | 217 +++ intern/cycles/device/metal/device_impl.h | 2 + intern/cycles/device/metal/device_impl.mm | 33 +- intern/cycles/device/metal/kernel.h | 2 + intern/cycles/device/metal/kernel.mm | 36 +- intern/cycles/integrator/pass_accessor.cpp | 7 +- intern/cycles/kernel/bvh/local.h | 26 +- intern/cycles/kernel/bvh/shadow_all.h | 53 +- intern/cycles/kernel/bvh/traversal.h | 48 +- intern/cycles/kernel/bvh/volume.h | 34 +- intern/cycles/kernel/bvh/volume_all.h | 32 +- intern/cycles/kernel/closure/volume.h | 12 +- .../cycles/kernel/device/metal/kernel.metal | 146 +- intern/cycles/kernel/film/read.h | 15 + .../kernel/geom/motion_triangle_intersect.h | 25 +- .../cycles/kernel/geom/triangle_intersect.h | 18 +- .../cycles/kernel/integrator/shade_surface.h | 2 +- .../cycles/kernel/integrator/shade_volume.h | 2 +- intern/cycles/kernel/svm/attribute.h | 12 +- intern/cycles/scene/alembic.cpp | 23 +- intern/cycles/scene/alembic.h | 6 + intern/cycles/scene/alembic_read.cpp | 38 +- intern/cycles/scene/alembic_read.h | 3 +- intern/cycles/scene/colorspace.cpp | 89 +- intern/cycles/scene/colorspace.h | 6 +- intern/cycles/scene/constant_fold.cpp | 10 +- intern/cycles/scene/image.cpp | 12 +- intern/cycles/scene/mesh.cpp | 16 +- intern/cycles/scene/mesh.h | 6 +- intern/cycles/scene/mesh_subdivision.cpp | 36 +- intern/cycles/util/array.h | 18 +- intern/cycles/util/math_int4.h | 5 +- intern/ghost/intern/GHOST_WindowX11.cpp | 2 +- intern/ghost/intern/GHOST_Wintab.cpp | 6 +- intern/ghost/intern/GHOST_Wintab.h | 3 +- intern/ghost/test/CMakeLists.txt | 2 +- release/datafiles/locale | 2 +- release/scripts/addons | 2 +- release/scripts/addons_contrib | 2 +- release/scripts/modules/keyingsets_utils.py | 2 +- release/scripts/startup/bl_operators/wm.py | 127 +- .../startup/bl_ui/properties_constraint.py | 23 + .../startup/bl_ui/properties_data_mesh.py | 18 +- .../startup/bl_ui/properties_object.py | 24 +- .../startup/bl_ui/properties_paint_common.py | 9 +- .../scripts/startup/bl_ui/space_userpref.py | 1 + release/scripts/startup/bl_ui/space_view3d.py | 4 + release/scripts/startup/nodeitems_builtins.py | 4 + source/blender/blenfont/CMakeLists.txt | 2 +- .../blenkernel/BKE_blendfile_link_append.h | 2 +- source/blender/blenkernel/BKE_brush_engine.h | 4 +- source/blender/blenkernel/BKE_brush_engine.hh | 429 ++++- source/blender/blenkernel/BKE_cachefile.h | 10 + source/blender/blenkernel/BKE_customdata.h | 8 + source/blender/blenkernel/BKE_main.h | 7 + source/blender/blenkernel/BKE_mesh.h | 8 + source/blender/blenkernel/BKE_mesh_runtime.h | 4 - source/blender/blenkernel/BKE_node.h | 4 + source/blender/blenkernel/BKE_subdiv.h | 4 +- .../blender/blenkernel/BKE_subdiv_modifier.h | 16 +- source/blender/blenkernel/BKE_volume.h | 5 + .../blender/blenkernel/BKE_volume_to_mesh.hh | 9 + source/blender/blenkernel/CMakeLists.txt | 11 +- source/blender/blenkernel/intern/armature.c | 9 +- .../blender/blenkernel/intern/bassrelief.cc | 4 +- .../blenkernel/intern/blendfile_link_append.c | 20 +- source/blender/blenkernel/intern/bpath.c | 2 +- .../blenkernel/intern/brush_channel_define.h | 107 +- .../intern/brush_channel_define_header.h | 163 ++ .../blenkernel/intern/brush_channel_names.hh | 6 +- .../blender/blenkernel/intern/brush_engine.c | 6 +- .../blender/blenkernel/intern/brush_engine.cc | 35 + source/blender/blenkernel/intern/cachefile.c | 47 +- source/blender/blenkernel/intern/curve.cc | 112 +- .../blender/blenkernel/intern/customdata.cc | 63 +- .../intern/geometry_component_mesh.cc | 337 ++-- source/blender/blenkernel/intern/mesh.cc | 2 + source/blender/blenkernel/intern/mesh_merge.c | 16 +- .../blender/blenkernel/intern/mesh_runtime.c | 121 +- .../blenkernel/intern/multires_reshape.h | 3 + .../intern/multires_reshape_smooth.c | 84 +- .../blenkernel/intern/multires_reshape_util.c | 2 + source/blender/blenkernel/intern/node.cc | 4 + source/blender/blenkernel/intern/paint.c | 1 + source/blender/blenkernel/intern/pbvh.c | 1 - source/blender/blenkernel/intern/pointcache.c | 30 +- .../blender/blenkernel/intern/spline_nurbs.cc | 72 +- .../blenkernel/intern/subdiv_converter_mesh.c | 15 +- .../blender/blenkernel/intern/subdiv_inline.h | 6 +- .../blenkernel/intern/subdiv_modifier.c | 2 - source/blender/blenkernel/intern/volume.cc | 45 +- .../blenkernel/intern/volume_to_mesh.cc | 9 - source/blender/blenlib/BLI_math_vector.hh | 5 + source/blender/blenlib/BLI_vector_set.hh | 8 + .../blender/blenlib/intern/math_base_inline.c | 16 +- source/blender/blenlib/intern/math_geom.c | 2 +- source/blender/blenlib/intern/timecode.c | 2 +- source/blender/blenlib/tests/BLI_any_test.cc | 2 +- source/blender/blenloader/intern/readfile.c | 1 - .../blenloader/intern/versioning_250.c | 7 +- .../blenloader/intern/versioning_300.c | 6 +- .../blenloader/intern/versioning_legacy.c | 3 +- .../blenloader/intern/versioning_userdef.c | 4 +- source/blender/bmesh/CMakeLists.txt | 4 +- source/blender/bmesh/bmesh.h | 1 + source/blender/bmesh/intern/bmesh_construct.c | 42 +- source/blender/bmesh/intern/bmesh_construct.h | 13 + source/blender/bmesh/intern/bmesh_mesh.c | 2 +- .../blender/bmesh/intern/bmesh_mesh_convert.c | 1671 ----------------- source/blender/bmesh/intern/bmesh_private.h | 8 + source/blender/bmesh/operators/bmo_create.c | 2 +- source/blender/bmesh/operators/bmo_hull.c | 2 +- .../intern/builder/deg_builder_relations.cc | 15 +- source/blender/draw/CMakeLists.txt | 544 +++--- .../draw/engines/overlay/overlay_armature.c | 2 +- .../draw/engines/overlay/overlay_shader.c | 4 +- .../overlay/shaders/edit_mesh_common_lib.glsl | 6 +- .../overlay/shaders/edit_mesh_vert.glsl | 12 +- .../shaders/workbench_common_lib.glsl | 13 +- .../workbench/shaders/workbench_data_lib.glsl | 5 +- .../shaders/workbench_effect_cavity_frag.glsl | 4 + .../shaders/workbench_image_lib.glsl | 2 + .../shaders/workbench_prepass_frag.glsl | 4 +- .../shaders/workbench_prepass_hair_vert.glsl | 6 +- .../workbench_prepass_pointcloud_vert.glsl | 4 +- .../shaders/workbench_prepass_vert.glsl | 6 +- .../workbench_shader_interface_lib.glsl | 8 +- .../workbench_transparent_accum_frag.glsl | 2 + .../draw_cache_extract_mesh_render_data.c | 3 +- .../intern/draw_cache_impl_subdivision.cc | 3 +- source/blender/draw/intern/draw_manager.c | 24 +- .../intern/mesh_extractors/extract_mesh.h | 5 +- .../extract_mesh_vbo_edit_data.cc | 15 +- .../shaders/common_fullscreen_vert.glsl | 2 + .../intern/shaders/common_pointcloud_lib.glsl | 4 + .../draw/intern/shaders/common_view_lib.glsl | 18 +- .../editors/asset/intern/asset_indexer.cc | 36 +- .../editors/asset/intern/asset_list.cc | 6 - source/blender/editors/curve/editcurve.c | 11 +- source/blender/editors/curve/editcurve_add.c | 6 +- .../blender/editors/geometry/CMakeLists.txt | 2 + .../editors/geometry/geometry_attributes.cc | 213 ++- .../editors/geometry/geometry_intern.hh | 4 + .../blender/editors/geometry/geometry_ops.cc | 3 + source/blender/editors/gpencil/drawgpencil.c | 29 +- .../editors/gpencil/editaction_gpencil.c | 5 +- source/blender/editors/include/BIF_glutil.h | 146 +- source/blender/editors/include/ED_node.h | 7 - source/blender/editors/include/ED_transform.h | 3 +- source/blender/editors/include/UI_interface.h | 7 + source/blender/editors/interface/interface.c | 45 +- .../editors/interface/interface_draw.c | 55 +- .../editors/interface/interface_handlers.c | 2 +- .../editors/interface/interface_icons.c | 117 +- .../editors/interface/interface_intern.h | 3 + .../interface/interface_template_list.cc | 1 + .../interface_template_search_menu.cc | 3 + .../editors/interface/interface_templates.c | 61 + source/blender/editors/io/io_cache.c | 168 +- source/blender/editors/io/io_cache.h | 4 + source/blender/editors/io/io_ops.c | 5 + source/blender/editors/mask/mask_draw.c | 3 +- source/blender/editors/mesh/editmesh_undo.c | 12 +- source/blender/editors/object/object_bake.c | 15 +- .../blender/editors/object/object_bake_api.c | 38 +- .../blender/editors/object/object_transform.c | 4 +- .../blender/editors/render/render_preview.cc | 22 +- source/blender/editors/screen/glutil.c | 375 ++-- .../editors/sculpt_paint/sculpt_intern.h | 8 +- source/blender/editors/space_file/file_draw.c | 29 +- source/blender/editors/space_file/filelist.c | 15 +- .../blender/editors/space_file/space_file.c | 11 +- .../blender/editors/space_node/CMakeLists.txt | 1 - source/blender/editors/space_node/drawnode.cc | 97 +- source/blender/editors/space_node/node_add.cc | 4 + .../blender/editors/space_node/node_draw.cc | 51 +- .../blender/editors/space_node/node_edit.cc | 43 +- .../node_geometry_attribute_search.cc | 8 +- .../blender/editors/space_node/node_gizmo.cc | 4 + .../blender/editors/space_node/node_group.cc | 6 +- .../blender/editors/space_node/node_intern.hh | 43 +- source/blender/editors/space_node/node_ops.cc | 22 +- .../editors/space_node/node_relationships.cc | 86 +- .../blender/editors/space_node/node_select.cc | 121 +- .../editors/space_node/node_templates.cc | 13 +- .../editors/space_node/node_toolbar.cc | 39 - .../blender/editors/space_node/node_view.cc | 8 +- .../blender/editors/space_node/space_node.cc | 34 +- .../editors/space_sequencer/sequencer_edit.c | 146 +- .../space_sequencer/sequencer_thumbnails.c | 2 +- .../editors/space_topbar/space_topbar.c | 11 +- .../editors/space_view3d/view3d_buttons.c | 66 +- .../transform/transform_convert_curve.c | 35 +- .../transform/transform_convert_mesh.c | 9 +- .../transform/transform_convert_mesh_edge.c | 4 +- .../transform/transform_convert_sequencer.c | 1 + .../editors/transform/transform_generics.c | 2 +- .../transform/transform_gizmo_extrude_3d.c | 5 +- .../editors/transform/transform_mode.c | 7 +- .../editors/transform/transform_mode.h | 3 +- .../transform/transform_mode_edge_crease.c | 13 +- .../blender/editors/transform/transform_ops.c | 31 +- source/blender/freestyle/CMakeLists.txt | 2 +- .../intern/MOD_gpencillineart.c | 7 +- .../intern/lineart/MOD_lineart.h | 4 + .../intern/lineart/lineart_chain.c | 58 + .../intern/lineart/lineart_cpu.c | 96 +- source/blender/gpu/CMakeLists.txt | 435 +++-- source/blender/gpu/GPU_immediate.h | 1 + source/blender/gpu/GPU_shader.h | 3 + .../gpu/intern/gpu_capabilities_private.hh | 4 +- source/blender/gpu/intern/gpu_immediate.cc | 6 + source/blender/gpu/intern/gpu_init_exit.c | 8 + source/blender/gpu/intern/gpu_shader.cc | 192 ++ .../blender/gpu/intern/gpu_shader_builtin.c | 249 +-- .../gpu/intern/gpu_shader_interface.hh | 26 +- .../blender/gpu/intern/gpu_shader_private.hh | 12 +- source/blender/gpu/opengl/gl_backend.cc | 5 + source/blender/gpu/opengl/gl_context.hh | 2 + source/blender/gpu/opengl/gl_shader.cc | 459 ++++- source/blender/gpu/opengl/gl_shader.hh | 12 +- .../blender/gpu/opengl/gl_shader_interface.cc | 133 ++ .../blender/gpu/opengl/gl_shader_interface.hh | 2 + .../gpu_shader_2D_area_borders_frag.glsl | 3 +- .../gpu_shader_2D_area_borders_vert.glsl | 3 +- .../gpu_shader_2D_flat_color_vert.glsl | 3 +- .../gpu_shader_2D_image_multi_rect_vert.glsl | 10 +- .../gpu_shader_2D_image_rect_vert.glsl | 2 + .../gpu/shaders/gpu_shader_2D_image_vert.glsl | 3 +- .../gpu_shader_2D_line_dashed_frag.glsl | 3 + ...der_2D_line_dashed_uniform_color_vert.glsl | 3 +- .../shaders/gpu_shader_2D_nodelink_frag.glsl | 3 +- .../shaders/gpu_shader_2D_nodelink_vert.glsl | 54 +- ..._shader_2D_point_uniform_size_aa_vert.glsl | 2 + ...2D_point_uniform_size_outline_aa_vert.glsl | 3 +- ...point_varying_size_varying_color_vert.glsl | 3 +- .../gpu_shader_2D_smooth_color_frag.glsl | 3 +- .../gpu_shader_2D_smooth_color_vert.glsl | 3 +- .../gpu/shaders/gpu_shader_2D_vert.glsl | 8 +- .../gpu_shader_2D_widget_base_frag.glsl | 2 + .../gpu_shader_2D_widget_base_vert.glsl | 15 +- .../gpu_shader_2D_widget_shadow_frag.glsl | 2 + .../gpu_shader_2D_widget_shadow_vert.glsl | 5 + ..._shader_3D_clipped_uniform_color_vert.glsl | 3 +- .../gpu_shader_3D_flat_color_vert.glsl | 9 +- .../gpu/shaders/gpu_shader_3D_image_vert.glsl | 2 + ...der_3D_line_dashed_uniform_color_vert.glsl | 7 +- .../shaders/gpu_shader_3D_normal_vert.glsl | 3 +- .../gpu_shader_3D_passthrough_vert.glsl | 6 +- ...D_point_fixed_size_varying_color_vert.glsl | 3 +- ..._shader_3D_point_uniform_size_aa_vert.glsl | 9 +- ...point_varying_size_varying_color_vert.glsl | 3 +- .../shaders/gpu_shader_3D_polyline_frag.glsl | 7 +- .../shaders/gpu_shader_3D_polyline_geom.glsl | 11 +- .../shaders/gpu_shader_3D_polyline_vert.glsl | 9 +- .../gpu_shader_3D_smooth_color_frag.glsl | 3 +- .../gpu_shader_3D_smooth_color_vert.glsl | 9 +- .../gpu/shaders/gpu_shader_3D_vert.glsl | 9 +- .../gpu_shader_cfg_world_clip_lib.glsl | 6 + .../gpu/shaders/gpu_shader_checker_frag.glsl | 3 +- .../shaders/gpu_shader_colorspace_lib.glsl | 2 + .../gpu_shader_common_obinfos_lib.glsl | 3 + .../shaders/gpu_shader_diag_stripes_frag.glsl | 3 +- ...u_shader_flat_color_alpha_test_0_frag.glsl | 3 +- .../shaders/gpu_shader_flat_color_frag.glsl | 3 +- .../gpu/shaders/gpu_shader_flat_id_frag.glsl | 3 +- .../gpu/shaders/gpu_shader_geometry.glsl | 5 +- .../gpu_shader_gpencil_stroke_frag.glsl | 8 +- .../gpu_shader_gpencil_stroke_geom.glsl | 138 +- .../gpu_shader_gpencil_stroke_vert.glsl | 14 +- .../shaders/gpu_shader_image_color_frag.glsl | 3 +- .../gpu_shader_image_desaturate_frag.glsl | 3 +- .../gpu/shaders/gpu_shader_image_frag.glsl | 3 +- .../gpu_shader_image_modulate_alpha_frag.glsl | 2 + .../gpu_shader_image_overlays_merge_frag.glsl | 2 + ...ader_image_overlays_stereo_merge_frag.glsl | 8 +- .../gpu_shader_image_shuffle_color_frag.glsl | 9 +- .../gpu_shader_image_varying_color_frag.glsl | 3 +- ...nce_variying_size_variying_color_vert.glsl | 9 +- .../gpu_shader_keyframe_shape_frag.glsl | 2 + .../gpu_shader_keyframe_shape_vert.glsl | 10 +- ...pu_shader_point_uniform_color_aa_frag.glsl | 3 +- ...r_point_uniform_color_outline_aa_frag.glsl | 3 +- .../gpu_shader_point_varying_color_frag.glsl | 16 +- ...varying_color_varying_outline_aa_frag.glsl | 3 +- .../gpu_shader_simple_lighting_frag.glsl | 17 +- .../gpu/shaders/gpu_shader_text_frag.glsl | 3 +- .../gpu/shaders/gpu_shader_text_vert.glsl | 3 +- .../gpu_shader_uniform_color_frag.glsl | 3 +- .../gpu_shader_material_tex_voronoi.glsl | 8 +- source/blender/io/alembic/ABC_alembic.h | 2 + .../io/alembic/exporter/abc_writer_mesh.cc | 62 +- .../io/alembic/intern/abc_reader_archive.cc | 49 + .../io/alembic/intern/abc_reader_archive.h | 10 +- .../io/alembic/intern/abc_reader_mesh.cc | 30 + .../blender/io/alembic/intern/alembic_capi.cc | 22 +- .../blender/io/usd/intern/usd_reader_mesh.cc | 34 + .../blender/io/usd/intern/usd_reader_mesh.h | 1 + .../blender/io/usd/intern/usd_writer_mesh.cc | 46 +- .../exporter/obj_export_file_writer.cc | 37 +- .../exporter/obj_export_file_writer.hh | 11 +- .../wavefront_obj/exporter/obj_export_io.hh | 87 +- .../wavefront_obj/exporter/obj_export_mesh.cc | 140 +- .../wavefront_obj/exporter/obj_export_mesh.hh | 33 +- .../io/wavefront_obj/exporter/obj_exporter.cc | 26 +- .../wavefront_obj/tests/obj_exporter_tests.cc | 38 +- source/blender/makesdna/DNA_ID.h | 7 +- source/blender/makesdna/DNA_cachefile_types.h | 19 +- .../blender/makesdna/DNA_customdata_types.h | 4 + .../makesdna/DNA_gpencil_modifier_defaults.h | 3 +- .../makesdna/DNA_gpencil_modifier_types.h | 1 + source/blender/makesdna/DNA_lineart_types.h | 3 + source/blender/makesdna/DNA_mesh_types.h | 1 + source/blender/makesdna/DNA_node_types.h | 15 + source/blender/makesdna/DNA_scene_defaults.h | 4 +- source/blender/makesdna/DNA_scene_types.h | 13 +- .../blender/makesdna/DNA_sculpt_brush_types.h | 4 +- source/blender/makesdna/DNA_space_types.h | 7 + source/blender/makesdna/DNA_userdef_types.h | 4 +- .../blender/makesdna/intern/dna_rename_defs.h | 1 + source/blender/makesrna/RNA_access.h | 1 + source/blender/makesrna/RNA_enum_items.h | 1 + source/blender/makesrna/RNA_enum_types.h | 4 +- source/blender/makesrna/intern/rna_action.c | 4 +- source/blender/makesrna/intern/rna_animviz.c | 6 + .../blender/makesrna/intern/rna_attribute.c | 9 +- .../blender/makesrna/intern/rna_cachefile.c | 167 ++ source/blender/makesrna/intern/rna_fcurve.c | 2 +- .../makesrna/intern/rna_gpencil_modifier.c | 27 + source/blender/makesrna/intern/rna_mesh.c | 155 ++ source/blender/makesrna/intern/rna_modifier.c | 4 +- source/blender/makesrna/intern/rna_nodetree.c | 92 + .../blender/makesrna/intern/rna_object_api.c | 2 +- source/blender/makesrna/intern/rna_rna.c | 6 +- source/blender/makesrna/intern/rna_scene.c | 39 +- .../makesrna/intern/rna_sculpt_paint.c | 2 +- source/blender/makesrna/intern/rna_ui_api.c | 18 + source/blender/makesrna/intern/rna_userdef.c | 8 + source/blender/makesrna/intern/rna_wm.c | 2 +- .../blender/modifiers/intern/MOD_boolean.cc | 11 +- .../modifiers/intern/MOD_meshsequencecache.c | 22 + source/blender/modifiers/intern/MOD_subsurf.c | 3 + source/blender/modifiers/intern/MOD_weld.cc | 131 +- source/blender/nodes/NOD_geometry.h | 4 + source/blender/nodes/NOD_static_types.h | 4 + .../nodes/node_composite_scene_time.cc | 2 +- source/blender/nodes/geometry/CMakeLists.txt | 4 + .../nodes/node_geo_attribute_capture.cc | 2 +- .../nodes/node_geo_curve_set_handles.cc | 2 +- .../node_geo_distribute_points_on_faces.cc | 2 +- .../nodes/node_geo_input_mesh_edge_angle.cc | 154 +- .../nodes/node_geo_input_mesh_island.cc | 62 +- .../nodes/intern/node_socket_declarations.cc | 3 +- .../blender/nodes/shader/node_shader_tree.cc | 17 + .../blender/python/gpu/gpu_py_framebuffer.c | 2 + source/blender/python/intern/bpy_props.c | 4 +- source/blender/render/CMakeLists.txt | 2 + source/blender/render/RE_bake.h | 8 +- source/blender/render/RE_multires_bake.h | 3 +- source/blender/render/intern/bake.c | 19 +- source/blender/render/intern/multires_bake.c | 23 +- source/blender/sequencer/CMakeLists.txt | 2 + source/blender/sequencer/SEQ_clipboard.h | 1 + source/blender/sequencer/SEQ_sequencer.h | 4 +- source/blender/sequencer/intern/clipboard.c | 15 +- source/blender/sequencer/intern/proxy.c | 2 +- source/blender/sequencer/intern/sequencer.c | 142 +- source/blender/sequencer/intern/sequencer.h | 5 +- source/blender/sequencer/intern/strip_edit.c | 4 +- .../sequencer/intern/strip_transform.c | 1 + source/blender/sequencer/intern/utils.c | 5 +- .../windowmanager/intern/wm_dragdrop.c | 26 +- .../blender/windowmanager/intern/wm_files.c | 43 +- .../blender/windowmanager/intern/wm_gesture.c | 2 +- source/blender/windowmanager/wm_event_types.h | 169 +- source/creator/CMakeLists.txt | 4 +- tests/python/bl_alembic_io_test.py | 52 + 393 files changed, 7658 insertions(+), 4950 deletions(-) create mode 100644 source/blender/blenkernel/intern/brush_channel_define_header.h delete mode 100644 source/blender/bmesh/intern/bmesh_mesh_convert.c delete mode 100644 source/blender/editors/space_node/node_toolbar.cc diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt index af1653de59a..0d305e0dd1f 100644 --- a/build_files/build_environment/CMakeLists.txt +++ b/build_files/build_environment/CMakeLists.txt @@ -63,6 +63,7 @@ include(cmake/jpeg.cmake) include(cmake/blosc.cmake) include(cmake/pthreads.cmake) include(cmake/openexr.cmake) +include(cmake/brotli.cmake) include(cmake/freetype.cmake) include(cmake/freeglut.cmake) include(cmake/glew.cmake) diff --git a/build_files/build_environment/cmake/download.cmake b/build_files/build_environment/cmake/download.cmake index 2a84202ea02..d3a4d767c08 100644 --- a/build_files/build_environment/cmake/download.cmake +++ b/build_files/build_environment/cmake/download.cmake @@ -94,3 +94,4 @@ download_source(POTRACE) download_source(HARU) download_source(ZSTD) download_source(FLEX) +download_source(BROTLI) diff --git a/build_files/build_environment/cmake/freetype.cmake b/build_files/build_environment/cmake/freetype.cmake index 49a83cb3377..52261b47618 100644 --- a/build_files/build_environment/cmake/freetype.cmake +++ b/build_files/build_environment/cmake/freetype.cmake @@ -23,9 +23,12 @@ set(FREETYPE_EXTRA_ARGS -DWITH_HarfBuzz=OFF -DFT_WITH_HARFBUZZ=OFF -DFT_WITH_BZIP2=OFF + -DFT_WITH_BROTLI=ON -DCMAKE_DISABLE_FIND_PACKAGE_HarfBuzz=TRUE -DCMAKE_DISABLE_FIND_PACKAGE_BZip2=TRUE - -DCMAKE_DISABLE_FIND_PACKAGE_BrotliDec=TRUE) + -DPC_BROTLIDEC_INCLUDEDIR=${LIBDIR}/brotli/include + -DPC_BROTLIDEC_LIBDIR=${LIBDIR}/brotli/lib + ) ExternalProject_Add(external_freetype URL file://${PACKAGE_DIR}/${FREETYPE_FILE} @@ -36,6 +39,11 @@ ExternalProject_Add(external_freetype INSTALL_DIR ${LIBDIR}/freetype ) +add_dependencies( + external_freetype + external_brotli +) + if(BUILD_MODE STREQUAL Release AND WIN32) ExternalProject_Add_Step(external_freetype after_install COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/freetype ${HARVEST_TARGET}/freetype diff --git a/build_files/build_environment/cmake/harvest.cmake b/build_files/build_environment/cmake/harvest.cmake index 4d06430ea49..0e68e720b44 100644 --- a/build_files/build_environment/cmake/harvest.cmake +++ b/build_files/build_environment/cmake/harvest.cmake @@ -79,6 +79,8 @@ endfunction() harvest(alembic/include alembic/include "*.h") harvest(alembic/lib/libAlembic.a alembic/lib/libAlembic.a) harvest(alembic/bin alembic/bin "*") +harvest(brotli/include brotli/include "*.h") +harvest(brotli/lib brotli/lib "*.a") harvest(boost/include boost/include "*") harvest(boost/lib boost/lib "*.a") harvest(ffmpeg/include ffmpeg/include "*.h") diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake index c758dbd265e..cc811cef06f 100644 --- a/build_files/build_environment/cmake/versions.cmake +++ b/build_files/build_environment/cmake/versions.cmake @@ -83,9 +83,9 @@ else() set(OPENEXR_VERSION_POSTFIX) endif() -set(FREETYPE_VERSION 2.10.2) +set(FREETYPE_VERSION 2.11.0) set(FREETYPE_URI http://prdownloads.sourceforge.net/freetype/freetype-${FREETYPE_VERSION}.tar.gz) -set(FREETYPE_HASH b1cb620e4c875cd4d1bfa04945400945) +set(FREETYPE_HASH cf09172322f6b50cf8f568bf8fe14bde) set(FREETYPE_HASH_TYPE MD5) set(FREETYPE_FILE freetype-${FREETYPE_VERSION}.tar.gz) @@ -500,3 +500,10 @@ set(ZSTD_FILE zstd-${ZSTD_VERSION}.tar.gz) set(SSE2NEON_GIT https://github.com/DLTcollab/sse2neon.git) set(SSE2NEON_GIT_HASH fe5ff00bb8d19b327714a3c290f3e2ce81ba3525) + +set(BROTLI_VERSION v1.0.9) +set(BROTLI_URI https://github.com/google/brotli/archive/refs/tags/${BROTLI_VERSION}.tar.gz) +set(BROTLI_HASH f9e8d81d0405ba66d181529af42a3354f838c939095ff99930da6aa9cdf6fe46) +set(BROTLI_HASH_TYPE SHA256) +set(BROTLI_FILE brotli-${BROTLI_VERSION}.tar.gz) + diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index bf24c3ef285..ce7a251bfba 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -492,7 +492,7 @@ OIIO_SKIP=false LLVM_VERSION="12.0.0" LLVM_VERSION_SHORT="12.0" LLVM_VERSION_MIN="11.0" -LLVM_VERSION_MEX="13.0" +LLVM_VERSION_MEX="14.0" LLVM_VERSION_FOUND="" LLVM_FORCE_BUILD=false LLVM_FORCE_REBUILD=false diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake index 447645b6806..8acea1be841 100644 --- a/build_files/cmake/platform/platform_apple.cmake +++ b/build_files/cmake/platform/platform_apple.cmake @@ -166,7 +166,11 @@ if(WITH_FFTW3) find_package(Fftw3) endif() +# FreeType compiled with Brotli compression for woff2. find_package(Freetype REQUIRED) +list(APPEND FREETYPE_LIBRARIES + ${LIBDIR}/brotli/lib/libbrotlicommon-static.a + ${LIBDIR}/brotli/lib/libbrotlidec-static.a) if(WITH_IMAGE_OPENEXR) find_package(OpenEXR) diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index 43dbc7c9c98..b6da737af71 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -700,14 +700,18 @@ if(CMAKE_COMPILER_IS_GNUCC) find_path( MOLD_BIN_DIR "ld" HINTS "${MOLD_PREFIX}" - PATH_SUFFIXES "lib/mold" "lib64/mold" + # The default path is `libexec`, Arch Linux for e.g. + # replaces this with `lib` so check both. + PATH_SUFFIXES "libexec/mold" "lib/mold" "lib64/mold" NO_DEFAULT_PATH NO_CACHE ) if(NOT MOLD_BIN_DIR) message(STATUS "The mold linker could not find the directory containing the linker command " - "(typically \"${MOLD_PREFIX}/lib/mold\"), using system linker.") + "(typically " + "\"${MOLD_PREFIX}/libexec/mold/ld\") or " + "\"${MOLD_PREFIX}/lib/mold/ld\") using system linker.") set(WITH_LINKER_MOLD OFF) endif() unset(MOLD_PREFIX) diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake index 851dafc34fb..0439e2fa5c2 100644 --- a/build_files/cmake/platform/platform_win32.cmake +++ b/build_files/cmake/platform/platform_win32.cmake @@ -347,7 +347,11 @@ set(FREETYPE_INCLUDE_DIRS ${LIBDIR}/freetype/include ${LIBDIR}/freetype/include/freetype2 ) -set(FREETYPE_LIBRARY ${LIBDIR}/freetype/lib/freetype2ST.lib) +set(FREETYPE_LIBRARIES + ${LIBDIR}/freetype/lib/freetype2ST.lib + ${LIBDIR}/brotli/lib/brotlidec-static.lib + ${LIBDIR}/brotli/lib/brotlicommon-static.lib +) windows_find_package(freetype REQUIRED) if(WITH_FFTW3) diff --git a/doc/python_api/examples/bpy.types.Bone.convert_local_to_pose.py b/doc/python_api/examples/bpy.types.Bone.convert_local_to_pose.py index f3cc95dec61..4a88096cf6f 100644 --- a/doc/python_api/examples/bpy.types.Bone.convert_local_to_pose.py +++ b/doc/python_api/examples/bpy.types.Bone.convert_local_to_pose.py @@ -8,27 +8,42 @@ def set_pose_matrices(obj, matrix_map): "Assign pose space matrices of all bones at once, ignoring constraints." def rec(pbone, parent_matrix): - matrix = matrix_map[pbone.name] + if pbone.name in matrix_map: + matrix = matrix_map[pbone.name] - ## Instead of: - # pbone.matrix = matrix - # bpy.context.view_layer.update() + ## Instead of: + # pbone.matrix = matrix + # bpy.context.view_layer.update() - # Compute and assign local matrix, using the new parent matrix - if pbone.parent: - pbone.matrix_basis = pbone.bone.convert_local_to_pose( - matrix, - pbone.bone.matrix_local, - parent_matrix=parent_matrix, - parent_matrix_local=pbone.parent.bone.matrix_local, - invert=True - ) + # Compute and assign local matrix, using the new parent matrix + if pbone.parent: + pbone.matrix_basis = pbone.bone.convert_local_to_pose( + matrix, + pbone.bone.matrix_local, + parent_matrix=parent_matrix, + parent_matrix_local=pbone.parent.bone.matrix_local, + invert=True + ) + else: + pbone.matrix_basis = pbone.bone.convert_local_to_pose( + matrix, + pbone.bone.matrix_local, + invert=True + ) else: - pbone.matrix_basis = pbone.bone.convert_local_to_pose( - matrix, - pbone.bone.matrix_local, - invert=True - ) + # Compute the updated pose matrix from local and new parent matrix + if pbone.parent: + matrix = pbone.bone.convert_local_to_pose( + pbone.matrix_basis, + pbone.bone.matrix_local, + parent_matrix=parent_matrix, + parent_matrix_local=pbone.parent.bone.matrix_local, + ) + else: + matrix = pbone.bone.convert_local_to_pose( + pbone.matrix_basis, + pbone.bone.matrix_local, + ) # Recursively process children, passing the new matrix through for child in pbone.children: diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index fda47194be0..0ae3b24578b 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -1762,6 +1762,7 @@ except ModuleNotFoundError: fw("html_show_sphinx = False\n") fw("html_baseurl = 'https://docs.blender.org/api/current/'\n") fw("html_use_opensearch = 'https://docs.blender.org/api/current'\n") + fw("html_show_search_summary = True\n") fw("html_split_index = True\n") fw("html_static_path = ['static']\n") fw("html_extra_path = ['static/favicon.ico', 'static/blender_logo.svg']\n") diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index e4fbc898070..5b600692152 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -119,12 +119,6 @@ def use_optix(context): return (get_device_type(context) == 'OPTIX' and cscene.device == 'GPU') -def use_sample_all_lights(context): - cscene = context.scene.cycles - - return cscene.sample_all_lights_direct or cscene.sample_all_lights_indirect - - def show_device_active(context): cscene = context.scene.cycles if cscene.device != 'GPU': @@ -1803,18 +1797,45 @@ class CYCLES_RENDER_PT_bake_output(CyclesButtonsPanel, Panel): rd = scene.render if rd.use_bake_multires: - layout.prop(rd, "bake_margin") layout.prop(rd, "use_bake_clear", text="Clear Image") - if rd.bake_type == 'DISPLACEMENT': layout.prop(rd, "use_bake_lores_mesh") else: layout.prop(cbk, "target") - if cbk.target == 'IMAGE_TEXTURES': - layout.prop(cbk, "margin") layout.prop(cbk, "use_clear", text="Clear Image") +class CYCLES_RENDER_PT_bake_output_margin(CyclesButtonsPanel, Panel): + bl_label = "Margin" + bl_context = "render" + bl_parent_id = "CYCLES_RENDER_PT_bake_output" + COMPAT_ENGINES = {'CYCLES'} + + @classmethod + def poll(cls, context): + scene = context.scene + cbk = scene.render.bake + return cbk.target == 'IMAGE_TEXTURES' + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + scene = context.scene + cscene = scene.cycles + cbk = scene.render.bake + rd = scene.render + + if rd.use_bake_multires: + layout.prop(rd, "bake_margin_type", text="Type") + layout.prop(rd, "bake_margin", text="Size") + else: + if cbk.target == 'IMAGE_TEXTURES': + layout.prop(cbk, "margin_type", text="Type") + layout.prop(cbk, "margin", text="Size") + + class CYCLES_RENDER_PT_debug(CyclesDebugButtonsPanel, Panel): bl_label = "Debug" @@ -2183,6 +2204,7 @@ classes = ( CYCLES_RENDER_PT_bake_influence, CYCLES_RENDER_PT_bake_selected_to_active, CYCLES_RENDER_PT_bake_output, + CYCLES_RENDER_PT_bake_output_margin, CYCLES_RENDER_PT_debug, node_panel(CYCLES_MATERIAL_PT_settings), node_panel(CYCLES_MATERIAL_PT_settings_surface), diff --git a/intern/cycles/blender/mesh.cpp b/intern/cycles/blender/mesh.cpp index 5e2b700427a..4ec25a868ae 100644 --- a/intern/cycles/blender/mesh.cpp +++ b/intern/cycles/blender/mesh.cpp @@ -1071,7 +1071,15 @@ static void create_subd_mesh(Scene *scene, for (BL::MeshEdge &e : b_mesh.edges) { if (e.crease() != 0.0f) { - mesh->add_crease(e.vertices()[0], e.vertices()[1], e.crease()); + mesh->add_edge_crease(e.vertices()[0], e.vertices()[1], e.crease()); + } + } + + for (BL::MeshVertexCreaseLayer &c : b_mesh.vertex_creases) { + for (int i = 0; i < c.data.length(); ++i) { + if (c.data[i].value() != 0.0f) { + mesh->add_vertex_crease(i, c.data[i].value()); + } } } diff --git a/intern/cycles/blender/object.cpp b/intern/cycles/blender/object.cpp index 86314d3b196..65a04a39660 100644 --- a/intern/cycles/blender/object.cpp +++ b/intern/cycles/blender/object.cpp @@ -529,6 +529,17 @@ void BlenderSync::sync_procedural(BL::Object &b_ob, string absolute_path = blender_absolute_path(b_data, b_ob, b_mesh_cache.cache_file().filepath()); procedural->set_filepath(ustring(absolute_path)); + array layers; + for (BL::CacheFileLayer &layer : cache_file.layers) { + if (layer.hide_layer()) { + continue; + } + + absolute_path = blender_absolute_path(b_data, b_ob, layer.filepath()); + layers.push_back_slow(ustring(absolute_path)); + } + procedural->set_layers(layers); + procedural->set_scale(cache_file.scale()); procedural->set_use_prefetch(cache_file.use_prefetch()); diff --git a/intern/cycles/blender/output_driver.cpp b/intern/cycles/blender/output_driver.cpp index 7b253e4cd3e..d5cc0c60bae 100644 --- a/intern/cycles/blender/output_driver.cpp +++ b/intern/cycles/blender/output_driver.cpp @@ -51,7 +51,7 @@ bool BlenderOutputDriver::read_render_tile(const Tile &tile) BL::RenderLayer b_rlay = *b_single_rlay; - vector pixels(tile.size.x * tile.size.y * 4); + vector pixels(static_cast(tile.size.x) * tile.size.y * 4); /* Copy each pass. * TODO:copy only the required ones for better performance? */ @@ -109,7 +109,7 @@ void BlenderOutputDriver::write_render_tile(const Tile &tile) BL::RenderLayer b_rlay = *b_single_rlay; - vector pixels(tile.size.x * tile.size.y * 4); + vector pixels(static_cast(tile.size.x) * tile.size.y * 4); /* Copy each pass. */ for (BL::RenderPass &b_pass : b_rlay.passes) { diff --git a/intern/cycles/device/metal/bvh.h b/intern/cycles/device/metal/bvh.h index cbc5ca7d2c3..58d71e3928f 100644 --- a/intern/cycles/device/metal/bvh.h +++ b/intern/cycles/device/metal/bvh.h @@ -58,6 +58,11 @@ class BVHMetal : public BVH { id queue, Geometry *const geom, bool refit); + bool build_BLAS_pointcloud(Progress &progress, + id device, + id queue, + Geometry *const geom, + bool refit); bool build_TLAS(Progress &progress, id device, id queue, bool refit); }; diff --git a/intern/cycles/device/metal/bvh.mm b/intern/cycles/device/metal/bvh.mm index 1953102cb41..8b252f1a5ec 100644 --- a/intern/cycles/device/metal/bvh.mm +++ b/intern/cycles/device/metal/bvh.mm @@ -19,6 +19,7 @@ # include "scene/hair.h" # include "scene/mesh.h" # include "scene/object.h" +# include "scene/pointcloud.h" # include "util/progress.h" @@ -475,6 +476,220 @@ bool BVHMetal::build_BLAS_hair(Progress &progress, return false; } +bool BVHMetal::build_BLAS_pointcloud(Progress &progress, + id device, + id queue, + Geometry *const geom, + bool refit) +{ + if (@available(macos 12.0, *)) { + /* Build BLAS for point cloud */ + PointCloud *pointcloud = static_cast(geom); + if (pointcloud->num_points() == 0) { + return false; + } + + /*------------------------------------------------*/ + BVH_status("Building pointcloud BLAS | %7d points | %s", + (int)pointcloud->num_points(), + geom->name.c_str()); + /*------------------------------------------------*/ + + const size_t num_points = pointcloud->get_points().size(); + const float3 *points = pointcloud->get_points().data(); + const float *radius = pointcloud->get_radius().data(); + + const bool use_fast_trace_bvh = (params.bvh_type == BVH_TYPE_STATIC); + + size_t num_motion_steps = 1; + Attribute *motion_keys = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if (motion_blur && pointcloud->get_use_motion_blur() && motion_keys) { + num_motion_steps = pointcloud->get_motion_steps(); + } + + const size_t num_aabbs = num_motion_steps; + + MTLResourceOptions storage_mode; + if (device.hasUnifiedMemory) { + storage_mode = MTLResourceStorageModeShared; + } + else { + storage_mode = MTLResourceStorageModeManaged; + } + + /* Allocate a GPU buffer for the AABB data and populate it */ + id aabbBuf = [device + newBufferWithLength:num_aabbs * sizeof(MTLAxisAlignedBoundingBox) + options:storage_mode]; + MTLAxisAlignedBoundingBox *aabb_data = (MTLAxisAlignedBoundingBox *)[aabbBuf contents]; + + /* Get AABBs for each motion step */ + size_t center_step = (num_motion_steps - 1) / 2; + for (size_t step = 0; step < num_motion_steps; ++step) { + /* The center step for motion vertices is not stored in the attribute */ + if (step != center_step) { + size_t attr_offset = (step > center_step) ? step - 1 : step; + points = motion_keys->data_float3() + attr_offset * num_points; + } + + for (size_t j = 0; j < num_points; ++j) { + const PointCloud::Point point = pointcloud->get_point(j); + BoundBox bounds = BoundBox::empty; + point.bounds_grow(points, radius, bounds); + + const size_t index = step * num_points + j; + aabb_data[index].min = (MTLPackedFloat3 &)bounds.min; + aabb_data[index].max = (MTLPackedFloat3 &)bounds.max; + } + } + + if (storage_mode == MTLResourceStorageModeManaged) { + [aabbBuf didModifyRange:NSMakeRange(0, aabbBuf.length)]; + } + +# if 0 + for (size_t i=0; i aabb_ptrs; + aabb_ptrs.reserve(num_motion_steps); + for (size_t step = 0; step < num_motion_steps; ++step) { + MTLMotionKeyframeData *k = [MTLMotionKeyframeData data]; + k.buffer = aabbBuf; + k.offset = step * num_points * sizeof(MTLAxisAlignedBoundingBox); + aabb_ptrs.push_back(k); + } + + MTLAccelerationStructureMotionBoundingBoxGeometryDescriptor *geomDescMotion = + [MTLAccelerationStructureMotionBoundingBoxGeometryDescriptor descriptor]; + geomDescMotion.boundingBoxBuffers = [NSArray arrayWithObjects:aabb_ptrs.data() + count:aabb_ptrs.size()]; + geomDescMotion.boundingBoxCount = num_points; + geomDescMotion.boundingBoxStride = sizeof(aabb_data[0]); + geomDescMotion.intersectionFunctionTableOffset = 2; + + /* Force a single any-hit call, so shadow record-all behavior works correctly */ + /* (Match optix behavior: unsigned int build_flags = + * OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL;) */ + geomDescMotion.allowDuplicateIntersectionFunctionInvocation = false; + geomDescMotion.opaque = true; + geomDesc = geomDescMotion; + } + else { + MTLAccelerationStructureBoundingBoxGeometryDescriptor *geomDescNoMotion = + [MTLAccelerationStructureBoundingBoxGeometryDescriptor descriptor]; + geomDescNoMotion.boundingBoxBuffer = aabbBuf; + geomDescNoMotion.boundingBoxBufferOffset = 0; + geomDescNoMotion.boundingBoxCount = int(num_aabbs); + geomDescNoMotion.boundingBoxStride = sizeof(aabb_data[0]); + geomDescNoMotion.intersectionFunctionTableOffset = 2; + + /* Force a single any-hit call, so shadow record-all behavior works correctly */ + /* (Match optix behavior: unsigned int build_flags = + * OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL;) */ + geomDescNoMotion.allowDuplicateIntersectionFunctionInvocation = false; + geomDescNoMotion.opaque = true; + geomDesc = geomDescNoMotion; + } + + MTLPrimitiveAccelerationStructureDescriptor *accelDesc = + [MTLPrimitiveAccelerationStructureDescriptor descriptor]; + accelDesc.geometryDescriptors = @[ geomDesc ]; + + if (motion_blur) { + accelDesc.motionStartTime = 0.0f; + accelDesc.motionEndTime = 1.0f; + accelDesc.motionStartBorderMode = MTLMotionBorderModeVanish; + accelDesc.motionEndBorderMode = MTLMotionBorderModeVanish; + accelDesc.motionKeyframeCount = num_motion_steps; + } + + if (!use_fast_trace_bvh) { + accelDesc.usage |= (MTLAccelerationStructureUsageRefit | + MTLAccelerationStructureUsagePreferFastBuild); + } + + MTLAccelerationStructureSizes accelSizes = [device + accelerationStructureSizesWithDescriptor:accelDesc]; + id accel_uncompressed = [device + newAccelerationStructureWithSize:accelSizes.accelerationStructureSize]; + id scratchBuf = [device newBufferWithLength:accelSizes.buildScratchBufferSize + options:MTLResourceStorageModePrivate]; + id sizeBuf = [device newBufferWithLength:8 options:MTLResourceStorageModeShared]; + id accelCommands = [queue commandBuffer]; + id accelEnc = + [accelCommands accelerationStructureCommandEncoder]; + if (refit) { + [accelEnc refitAccelerationStructure:accel_struct + descriptor:accelDesc + destination:accel_uncompressed + scratchBuffer:scratchBuf + scratchBufferOffset:0]; + } + else { + [accelEnc buildAccelerationStructure:accel_uncompressed + descriptor:accelDesc + scratchBuffer:scratchBuf + scratchBufferOffset:0]; + } + if (use_fast_trace_bvh) { + [accelEnc writeCompactedAccelerationStructureSize:accel_uncompressed + toBuffer:sizeBuf + offset:0 + sizeDataType:MTLDataTypeULong]; + } + [accelEnc endEncoding]; + [accelCommands addCompletedHandler:^(id command_buffer) { + /* free temp resources */ + [scratchBuf release]; + [aabbBuf release]; + + if (use_fast_trace_bvh) { + /* Compact the accel structure */ + uint64_t compressed_size = *(uint64_t *)sizeBuf.contents; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + id accelCommands = [queue commandBuffer]; + id accelEnc = + [accelCommands accelerationStructureCommandEncoder]; + id accel = [device + newAccelerationStructureWithSize:compressed_size]; + [accelEnc copyAndCompactAccelerationStructure:accel_uncompressed + toAccelerationStructure:accel]; + [accelEnc endEncoding]; + [accelCommands addCompletedHandler:^(id command_buffer) { + uint64_t allocated_size = [accel allocatedSize]; + stats.mem_alloc(allocated_size); + accel_struct = accel; + [accel_uncompressed release]; + accel_struct_building = false; + }]; + [accelCommands commit]; + }); + } + else { + /* set our acceleration structure to the uncompressed structure */ + accel_struct = accel_uncompressed; + + uint64_t allocated_size = [accel_struct allocatedSize]; + stats.mem_alloc(allocated_size); + accel_struct_building = false; + } + [sizeBuf release]; + }]; + + accel_struct_building = true; + [accelCommands commit]; + return true; + } + return false; +} + bool BVHMetal::build_BLAS(Progress &progress, id device, id queue, @@ -491,6 +706,8 @@ bool BVHMetal::build_BLAS(Progress &progress, return build_BLAS_mesh(progress, device, queue, geom, refit); case Geometry::HAIR: return build_BLAS_hair(progress, device, queue, geom, refit); + case Geometry::POINTCLOUD: + return build_BLAS_pointcloud(progress, device, queue, geom, refit); default: return false; } diff --git a/intern/cycles/device/metal/device_impl.h b/intern/cycles/device/metal/device_impl.h index a420a3ba704..8d289beda13 100644 --- a/intern/cycles/device/metal/device_impl.h +++ b/intern/cycles/device/metal/device_impl.h @@ -115,6 +115,8 @@ class MetalDevice : public Device { void load_texture_info(); + void erase_allocation(device_memory &mem); + virtual bool should_use_graphics_interop() override; virtual unique_ptr gpu_queue_create() override; diff --git a/intern/cycles/device/metal/device_impl.mm b/intern/cycles/device/metal/device_impl.mm index 4ad5a3caebc..17acb2c94e4 100644 --- a/intern/cycles/device/metal/device_impl.mm +++ b/intern/cycles/device/metal/device_impl.mm @@ -87,17 +87,14 @@ MetalDevice::MetalDevice(const DeviceInfo &info, Stats &stats, Profiler &profile default: break; case METAL_GPU_INTEL: { - use_metalrt = false; max_threads_per_threadgroup = 64; break; } case METAL_GPU_AMD: { - use_metalrt = false; max_threads_per_threadgroup = 128; break; } case METAL_GPU_APPLE: { - use_metalrt = true; max_threads_per_threadgroup = 512; break; } @@ -432,6 +429,25 @@ void MetalDevice::load_texture_info() } } +void MetalDevice::erase_allocation(device_memory &mem) +{ + stats.mem_free(mem.device_size); + mem.device_pointer = 0; + mem.device_size = 0; + + auto it = metal_mem_map.find(&mem); + if (it != metal_mem_map.end()) { + MetalMem *mmem = it->second.get(); + + /* blank out reference to MetalMem* in the launch params (fixes crash T94736) */ + if (mmem->pointer_index >= 0) { + device_ptr *pointers = (device_ptr *)&launch_params; + pointers[mmem->pointer_index] = 0; + } + metal_mem_map.erase(it); + } +} + MetalDevice::MetalMem *MetalDevice::generic_alloc(device_memory &mem) { size_t size = mem.memory_size(); @@ -561,11 +577,7 @@ void MetalDevice::generic_free(device_memory &mem) mmem.mtlBuffer = nil; } - stats.mem_free(mem.device_size); - mem.device_pointer = 0; - mem.device_size = 0; - - metal_mem_map.erase(&mem); + erase_allocation(mem); } } @@ -954,10 +966,7 @@ void MetalDevice::tex_free(device_texture &mem) delayed_free_list.push_back(mmem.mtlTexture); mmem.mtlTexture = nil; } - stats.mem_free(mem.device_size); - mem.device_pointer = 0; - mem.device_size = 0; - metal_mem_map.erase(&mem); + erase_allocation(mem); } } diff --git a/intern/cycles/device/metal/kernel.h b/intern/cycles/device/metal/kernel.h index 4874af1bfa6..a4bfb30436d 100644 --- a/intern/cycles/device/metal/kernel.h +++ b/intern/cycles/device/metal/kernel.h @@ -36,6 +36,8 @@ enum { METALRT_FUNC_CURVE_RIBBON_SHADOW, METALRT_FUNC_CURVE_ALL, METALRT_FUNC_CURVE_ALL_SHADOW, + METALRT_FUNC_POINT, + METALRT_FUNC_POINT_SHADOW, METALRT_FUNC_NUM }; diff --git a/intern/cycles/device/metal/kernel.mm b/intern/cycles/device/metal/kernel.mm index f948a8a0a0f..e9bd1cea5df 100644 --- a/intern/cycles/device/metal/kernel.mm +++ b/intern/cycles/device/metal/kernel.mm @@ -358,6 +358,8 @@ bool MetalDeviceKernels::load(MetalDevice *device, int kernel_type) "__intersection__curve_ribbon_shadow", "__intersection__curve_all", "__intersection__curve_all_shadow", + "__intersection__point", + "__intersection__point_shadow", }; assert(sizeof(function_names) / sizeof(function_names[0]) == METALRT_FUNC_NUM); @@ -400,36 +402,50 @@ bool MetalDeviceKernels::load(MetalDevice *device, int kernel_type) NSArray *function_list = nil; if (device->use_metalrt) { - id box_intersect_default = nil; - id box_intersect_shadow = nil; + id curve_intersect_default = nil; + id curve_intersect_shadow = nil; + id point_intersect_default = nil; + id point_intersect_shadow = nil; if (device->kernel_features & KERNEL_FEATURE_HAIR) { /* Add curve intersection programs. */ if (device->kernel_features & KERNEL_FEATURE_HAIR_THICK) { /* Slower programs for thick hair since that also slows down ribbons. * Ideally this should not be needed. */ - box_intersect_default = rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_ALL]; - box_intersect_shadow = rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_ALL_SHADOW]; + curve_intersect_default = rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_ALL]; + curve_intersect_shadow = + rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_ALL_SHADOW]; } else { - box_intersect_default = rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_RIBBON]; - box_intersect_shadow = + curve_intersect_default = rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_RIBBON]; + curve_intersect_shadow = rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_RIBBON_SHADOW]; } } + if (device->kernel_features & KERNEL_FEATURE_POINTCLOUD) { + point_intersect_default = rt_intersection_funcs[kernel_type][METALRT_FUNC_POINT]; + point_intersect_shadow = rt_intersection_funcs[kernel_type][METALRT_FUNC_POINT_SHADOW]; + } table_functions[METALRT_TABLE_DEFAULT] = [NSArray arrayWithObjects:rt_intersection_funcs[kernel_type][METALRT_FUNC_DEFAULT_TRI], - box_intersect_default ? - box_intersect_default : + curve_intersect_default ? + curve_intersect_default : + rt_intersection_funcs[kernel_type][METALRT_FUNC_DEFAULT_BOX], + point_intersect_default ? + point_intersect_default : rt_intersection_funcs[kernel_type][METALRT_FUNC_DEFAULT_BOX], nil]; table_functions[METALRT_TABLE_SHADOW] = [NSArray arrayWithObjects:rt_intersection_funcs[kernel_type][METALRT_FUNC_SHADOW_TRI], - box_intersect_shadow ? - box_intersect_shadow : + curve_intersect_shadow ? + curve_intersect_shadow : + rt_intersection_funcs[kernel_type][METALRT_FUNC_SHADOW_BOX], + point_intersect_shadow ? + point_intersect_shadow : rt_intersection_funcs[kernel_type][METALRT_FUNC_SHADOW_BOX], nil]; table_functions[METALRT_TABLE_LOCAL] = [NSArray arrayWithObjects:rt_intersection_funcs[kernel_type][METALRT_FUNC_LOCAL_TRI], + rt_intersection_funcs[kernel_type][METALRT_FUNC_LOCAL_BOX], rt_intersection_funcs[kernel_type][METALRT_FUNC_LOCAL_BOX], nil]; diff --git a/intern/cycles/integrator/pass_accessor.cpp b/intern/cycles/integrator/pass_accessor.cpp index 4479442df56..9fa5aab9ea9 100644 --- a/intern/cycles/integrator/pass_accessor.cpp +++ b/intern/cycles/integrator/pass_accessor.cpp @@ -141,6 +141,7 @@ bool PassAccessor::get_render_tile_pixels(const RenderBuffers *render_buffers, const PassType type = pass_access_info_.type; const PassMode mode = pass_access_info_.mode; const PassInfo pass_info = Pass::get_info(type, pass_access_info_.include_albedo); + int num_written_components = pass_info.num_components; if (pass_info.num_components == 1) { /* Single channel passes. */ @@ -188,8 +189,10 @@ bool PassAccessor::get_render_tile_pixels(const RenderBuffers *render_buffers, else if ((pass_info.divide_type != PASS_NONE || pass_info.direct_type != PASS_NONE || pass_info.indirect_type != PASS_NONE) && mode != PassMode::DENOISED) { - /* RGB lighting passes that need to divide out color and/or sum direct and indirect. */ + /* RGB lighting passes that need to divide out color and/or sum direct and indirect. + * These can also optionally write alpha like the combined pass. */ get_pass_light_path(render_buffers, buffer_params, destination); + num_written_components = 4; } else { /* Passes that need no special computation, or denoised passes that already @@ -215,7 +218,7 @@ bool PassAccessor::get_render_tile_pixels(const RenderBuffers *render_buffers, } } - pad_pixels(buffer_params, destination, pass_info.num_components); + pad_pixels(buffer_params, destination, num_written_components); return true; } diff --git a/intern/cycles/kernel/bvh/local.h b/intern/cycles/kernel/bvh/local.h index 79cde69699e..4d0e6aac901 100644 --- a/intern/cycles/kernel/bvh/local.h +++ b/intern/cycles/kernel/bvh/local.h @@ -148,12 +148,23 @@ ccl_device_inline /* intersect ray against primitive */ for (; prim_addr < prim_addr2; prim_addr++) { kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); + + /* Only intersect with matching object, for instanced objects we + * already know we are only intersecting the right object. */ + if (object == OBJECT_NONE) { + if (kernel_tex_fetch(__prim_object, prim_addr) != local_object) { + continue; + } + } + + const int prim = kernel_tex_fetch(__prim_index, prim_addr); + if (triangle_intersect_local(kg, local_isect, P, dir, - object, local_object, + prim, prim_addr, isect_t, lcg_state, @@ -168,13 +179,24 @@ ccl_device_inline /* intersect ray against primitive */ for (; prim_addr < prim_addr2; prim_addr++) { kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); + + /* Only intersect with matching object, for instanced objects we + * already know we are only intersecting the right object. */ + if (object == OBJECT_NONE) { + if (kernel_tex_fetch(__prim_object, prim_addr) != local_object) { + continue; + } + } + + const int prim = kernel_tex_fetch(__prim_index, prim_addr); + if (motion_triangle_intersect_local(kg, local_isect, P, dir, ray->time, - object, local_object, + prim, prim_addr, isect_t, lcg_state, diff --git a/intern/cycles/kernel/bvh/shadow_all.h b/intern/cycles/kernel/bvh/shadow_all.h index b0e799675e0..0fb86bfda77 100644 --- a/intern/cycles/kernel/bvh/shadow_all.h +++ b/intern/cycles/kernel/bvh/shadow_all.h @@ -146,7 +146,7 @@ ccl_device_inline --stack_ptr; /* primitive intersection */ - while (prim_addr < prim_addr2) { + for (; prim_addr < prim_addr2; prim_addr++) { kernel_assert((kernel_tex_fetch(__prim_type, prim_addr) & PRIMITIVE_ALL) == (type & PRIMITIVE_ALL)); bool hit; @@ -156,16 +156,29 @@ ccl_device_inline * might give a few % performance improvement */ Intersection isect ccl_optional_struct_init; + const int prim_object = (object == OBJECT_NONE) ? + kernel_tex_fetch(__prim_object, prim_addr) : + object; + const int prim = kernel_tex_fetch(__prim_index, prim_addr); + switch (type & PRIMITIVE_ALL) { case PRIMITIVE_TRIANGLE: { hit = triangle_intersect( - kg, &isect, P, dir, t_max_current, visibility, object, prim_addr); + kg, &isect, P, dir, t_max_current, visibility, prim_object, prim, prim_addr); break; } #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { - hit = motion_triangle_intersect( - kg, &isect, P, dir, t_max_current, ray->time, visibility, object, prim_addr); + hit = motion_triangle_intersect(kg, + &isect, + P, + dir, + t_max_current, + ray->time, + visibility, + prim_object, + prim, + prim_addr); break; } #endif @@ -182,20 +195,9 @@ ccl_device_inline } } - const int curve_object = (object == OBJECT_NONE) ? - kernel_tex_fetch(__prim_object, prim_addr) : - object; const int curve_type = kernel_tex_fetch(__prim_type, prim_addr); - const int curve_prim = kernel_tex_fetch(__prim_index, prim_addr); - hit = curve_intersect(kg, - &isect, - P, - dir, - t_max_current, - curve_object, - curve_prim, - ray->time, - curve_type); + hit = curve_intersect( + kg, &isect, P, dir, t_max_current, prim_object, prim, ray->time, curve_type); break; } @@ -211,20 +213,9 @@ ccl_device_inline } } - const int point_object = (object == OBJECT_NONE) ? - kernel_tex_fetch(__prim_object, prim_addr) : - object; - const int point_prim = kernel_tex_fetch(__prim_index, prim_addr); const int point_type = kernel_tex_fetch(__prim_type, prim_addr); - hit = point_intersect(kg, - &isect, - P, - dir, - t_max_current, - point_object, - point_prim, - ray->time, - point_type); + hit = point_intersect( + kg, &isect, P, dir, t_max_current, prim_object, prim, ray->time, point_type); break; } #endif /* BVH_FEATURE(BVH_POINTCLOUD) */ @@ -301,8 +292,6 @@ ccl_device_inline integrator_state_write_shadow_isect(state, &isect, record_index); } } - - prim_addr++; } } else { diff --git a/intern/cycles/kernel/bvh/traversal.h b/intern/cycles/kernel/bvh/traversal.h index e4bff1a8a80..dc2d1422df6 100644 --- a/intern/cycles/kernel/bvh/traversal.h +++ b/intern/cycles/kernel/bvh/traversal.h @@ -137,8 +137,14 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg, case PRIMITIVE_TRIANGLE: { for (; prim_addr < prim_addr2; prim_addr++) { kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); + + const int prim_object = (object == OBJECT_NONE) ? + kernel_tex_fetch(__prim_object, prim_addr) : + object; + const int prim = kernel_tex_fetch(__prim_index, prim_addr); + if (triangle_intersect( - kg, isect, P, dir, isect->t, visibility, object, prim_addr)) { + kg, isect, P, dir, isect->t, visibility, prim_object, prim, prim_addr)) { /* shadow ray early termination */ if (visibility & PATH_RAY_SHADOW_OPAQUE) return true; @@ -150,8 +156,22 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg, case PRIMITIVE_MOTION_TRIANGLE: { for (; prim_addr < prim_addr2; prim_addr++) { kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); - if (motion_triangle_intersect( - kg, isect, P, dir, isect->t, ray->time, visibility, object, prim_addr)) { + + const int prim_object = (object == OBJECT_NONE) ? + kernel_tex_fetch(__prim_object, prim_addr) : + object; + const int prim = kernel_tex_fetch(__prim_index, prim_addr); + + if (motion_triangle_intersect(kg, + isect, + P, + dir, + isect->t, + ray->time, + visibility, + prim_object, + prim, + prim_addr)) { /* shadow ray early termination */ if (visibility & PATH_RAY_SHADOW_OPAQUE) return true; @@ -173,13 +193,14 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg, } } - const int curve_object = (object == OBJECT_NONE) ? - kernel_tex_fetch(__prim_object, prim_addr) : - object; - const int curve_prim = kernel_tex_fetch(__prim_index, prim_addr); + const int prim_object = (object == OBJECT_NONE) ? + kernel_tex_fetch(__prim_object, prim_addr) : + object; + const int prim = kernel_tex_fetch(__prim_index, prim_addr); + const int curve_type = kernel_tex_fetch(__prim_type, prim_addr); const bool hit = curve_intersect( - kg, isect, P, dir, isect->t, curve_object, curve_prim, ray->time, curve_type); + kg, isect, P, dir, isect->t, prim_object, prim, ray->time, curve_type); if (hit) { /* shadow ray early termination */ if (visibility & PATH_RAY_SHADOW_OPAQUE) @@ -200,13 +221,14 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg, } } - const int point_object = (object == OBJECT_NONE) ? - kernel_tex_fetch(__prim_object, prim_addr) : - object; - const int point_prim = kernel_tex_fetch(__prim_index, prim_addr); + const int prim_object = (object == OBJECT_NONE) ? + kernel_tex_fetch(__prim_object, prim_addr) : + object; + const int prim = kernel_tex_fetch(__prim_index, prim_addr); + const int point_type = kernel_tex_fetch(__prim_type, prim_addr); const bool hit = point_intersect( - kg, isect, P, dir, isect->t, point_object, point_prim, ray->time, point_type); + kg, isect, P, dir, isect->t, prim_object, prim, ray->time, point_type); if (hit) { /* shadow ray early termination */ if (visibility & PATH_RAY_SHADOW_OPAQUE) diff --git a/intern/cycles/kernel/bvh/volume.h b/intern/cycles/kernel/bvh/volume.h index fa56bd02bef..c0746c8efc3 100644 --- a/intern/cycles/kernel/bvh/volume.h +++ b/intern/cycles/kernel/bvh/volume.h @@ -140,14 +140,17 @@ ccl_device_inline for (; prim_addr < prim_addr2; prim_addr++) { kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); /* only primitives from volume object */ - uint tri_object = (object == OBJECT_NONE) ? - kernel_tex_fetch(__prim_object, prim_addr) : - object; - int object_flag = kernel_tex_fetch(__object_flag, tri_object); + const int prim_object = (object == OBJECT_NONE) ? + kernel_tex_fetch(__prim_object, prim_addr) : + object; + const int prim = kernel_tex_fetch(__prim_index, prim_addr); + + int object_flag = kernel_tex_fetch(__object_flag, prim_object); if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; } - triangle_intersect(kg, isect, P, dir, isect->t, visibility, object, prim_addr); + triangle_intersect( + kg, isect, P, dir, isect->t, visibility, prim_object, prim, prim_addr); } break; } @@ -157,15 +160,24 @@ ccl_device_inline for (; prim_addr < prim_addr2; prim_addr++) { kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); /* only primitives from volume object */ - uint tri_object = (object == OBJECT_NONE) ? - kernel_tex_fetch(__prim_object, prim_addr) : - object; - int object_flag = kernel_tex_fetch(__object_flag, tri_object); + const int prim_object = (object == OBJECT_NONE) ? + kernel_tex_fetch(__prim_object, prim_addr) : + object; + const int prim = kernel_tex_fetch(__prim_index, prim_addr); + int object_flag = kernel_tex_fetch(__object_flag, prim_object); if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; } - motion_triangle_intersect( - kg, isect, P, dir, isect->t, ray->time, visibility, object, prim_addr); + motion_triangle_intersect(kg, + isect, + P, + dir, + isect->t, + ray->time, + visibility, + prim_object, + prim, + prim_addr); } break; } diff --git a/intern/cycles/kernel/bvh/volume_all.h b/intern/cycles/kernel/bvh/volume_all.h index 1d7d942e736..a88c9d95d46 100644 --- a/intern/cycles/kernel/bvh/volume_all.h +++ b/intern/cycles/kernel/bvh/volume_all.h @@ -143,15 +143,16 @@ ccl_device_inline for (; prim_addr < prim_addr2; prim_addr++) { kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); /* only primitives from volume object */ - uint tri_object = (object == OBJECT_NONE) ? - kernel_tex_fetch(__prim_object, prim_addr) : - object; - int object_flag = kernel_tex_fetch(__object_flag, tri_object); + const int prim_object = (object == OBJECT_NONE) ? + kernel_tex_fetch(__prim_object, prim_addr) : + object; + const int prim = kernel_tex_fetch(__prim_index, prim_addr); + int object_flag = kernel_tex_fetch(__object_flag, prim_object); if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; } hit = triangle_intersect( - kg, isect_array, P, dir, isect_t, visibility, object, prim_addr); + kg, isect_array, P, dir, isect_t, visibility, prim_object, prim, prim_addr); if (hit) { /* Move on to next entry in intersections array. */ isect_array++; @@ -183,15 +184,24 @@ ccl_device_inline for (; prim_addr < prim_addr2; prim_addr++) { kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); /* only primitives from volume object */ - uint tri_object = (object == OBJECT_NONE) ? - kernel_tex_fetch(__prim_object, prim_addr) : - object; - int object_flag = kernel_tex_fetch(__object_flag, tri_object); + const int prim_object = (object == OBJECT_NONE) ? + kernel_tex_fetch(__prim_object, prim_addr) : + object; + const int prim = kernel_tex_fetch(__prim_index, prim_addr); + int object_flag = kernel_tex_fetch(__object_flag, prim_object); if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; } - hit = motion_triangle_intersect( - kg, isect_array, P, dir, isect_t, ray->time, visibility, object, prim_addr); + hit = motion_triangle_intersect(kg, + isect_array, + P, + dir, + isect_t, + ray->time, + visibility, + prim_object, + prim, + prim_addr); if (hit) { /* Move on to next entry in intersections array. */ isect_array++; diff --git a/intern/cycles/kernel/closure/volume.h b/intern/cycles/kernel/closure/volume.h index 023fb3ac4ea..4a7a63819ab 100644 --- a/intern/cycles/kernel/closure/volume.h +++ b/intern/cycles/kernel/closure/volume.h @@ -199,22 +199,18 @@ ccl_device int volume_sample_channel(float3 albedo, * Tracing". Matt Jen-Yuan Chiang, Peter Kutz, Brent Burley. SIGGRAPH 2016. */ float3 weights = fabs(throughput * albedo); float sum_weights = weights.x + weights.y + weights.z; - float3 weights_pdf; if (sum_weights > 0.0f) { - weights_pdf = weights / sum_weights; + *pdf = weights / sum_weights; } else { - weights_pdf = make_float3(1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 3.0f); + *pdf = make_float3(1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 3.0f); } - *pdf = weights_pdf; - - /* OpenCL does not support -> on float3, so don't use pdf->x. */ - if (rand < weights_pdf.x) { + if (rand < pdf->x) { return 0; } - else if (rand < weights_pdf.x + weights_pdf.y) { + else if (rand < pdf->x + pdf->y) { return 1; } else { diff --git a/intern/cycles/kernel/device/metal/kernel.metal b/intern/cycles/kernel/device/metal/kernel.metal index deb7dafe55e..3303b541487 100644 --- a/intern/cycles/kernel/device/metal/kernel.metal +++ b/intern/cycles/kernel/device/metal/kernel.metal @@ -576,6 +576,150 @@ __intersection__curve_all_shadow(constant KernelParamsMetal &launch_params_metal return result; } - #endif /* __HAIR__ */ + +#ifdef __POINTCLOUD__ +ccl_device_inline +void metalrt_intersection_point(constant KernelParamsMetal &launch_params_metal, + ray_data MetalKernelContext::MetalRTIntersectionPayload &payload, + const uint object, + const uint prim, + const uint type, + const float3 ray_origin, + const float3 ray_direction, + float time, + const float ray_tmax, + thread BoundingBoxIntersectionResult &result) +{ +# ifdef __VISIBILITY_FLAG__ + const uint visibility = payload.visibility; + if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) { + return; + } +# endif + + float3 P = ray_origin; + float3 dir = ray_direction; + + /* The direction is not normalized by default, but the point intersection routine expects that */ + float len; + dir = normalize_len(dir, &len); + + Intersection isect; + isect.t = ray_tmax; + /* Transform maximum distance into object space. */ + if (isect.t != FLT_MAX) + isect.t *= len; + + MetalKernelContext context(launch_params_metal); + if (context.point_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) { + result = metalrt_visibility_test( + launch_params_metal, payload, object, prim, isect.u); + if (result.accept) { + result.distance = isect.t / len; + payload.u = isect.u; + payload.v = isect.v; + payload.prim = prim; + payload.type = type; + } + } +} + +ccl_device_inline +void metalrt_intersection_point_shadow(constant KernelParamsMetal &launch_params_metal, + ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload, + const uint object, + const uint prim, + const uint type, + const float3 ray_origin, + const float3 ray_direction, + float time, + const float ray_tmax, + thread BoundingBoxIntersectionResult &result) +{ + const uint visibility = payload.visibility; + + float3 P = ray_origin; + float3 dir = ray_direction; + + /* The direction is not normalized by default, but the point intersection routine expects that */ + float len; + dir = normalize_len(dir, &len); + + Intersection isect; + isect.t = ray_tmax; + /* Transform maximum distance into object space */ + if (isect.t != FLT_MAX) + isect.t *= len; + + MetalKernelContext context(launch_params_metal); + if (context.point_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) { + result.continue_search = metalrt_shadow_all_hit( + launch_params_metal, payload, object, prim, float2(isect.u, isect.v), ray_tmax); + result.accept = !result.continue_search; + + if (result.accept) { + result.distance = isect.t / len; + } + } +} + +[[intersection(bounding_box, triangle_data, METALRT_TAGS)]] +BoundingBoxIntersectionResult +__intersection__point(constant KernelParamsMetal &launch_params_metal [[buffer(1)]], + ray_data MetalKernelContext::MetalRTIntersectionPayload &payload [[payload]], + const uint object [[user_instance_id]], + const uint primitive_id [[primitive_id]], + const float3 ray_origin [[origin]], + const float3 ray_direction [[direction]], + const float ray_tmax [[max_distance]]) +{ + const uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object); + const int type = kernel_tex_fetch(__objects, object).primitive_type; + + BoundingBoxIntersectionResult result; + result.accept = false; + result.continue_search = true; + result.distance = ray_tmax; + + metalrt_intersection_point(launch_params_metal, payload, object, prim, type, ray_origin, ray_direction, +# if defined(__METALRT_MOTION__) + payload.time, +# else + 0.0f, +# endif + ray_tmax, result); + + return result; +} + +[[intersection(bounding_box, triangle_data, METALRT_TAGS)]] +BoundingBoxIntersectionResult +__intersection__point_shadow(constant KernelParamsMetal &launch_params_metal [[buffer(1)]], + ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload [[payload]], + const uint object [[user_instance_id]], + const uint primitive_id [[primitive_id]], + const float3 ray_origin [[origin]], + const float3 ray_direction [[direction]], + const float ray_tmax [[max_distance]]) +{ + const uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object); + const int type = kernel_tex_fetch(__objects, object).primitive_type; + + BoundingBoxIntersectionResult result; + result.accept = false; + result.continue_search = true; + result.distance = ray_tmax; + + metalrt_intersection_point_shadow(launch_params_metal, payload, object, prim, type, ray_origin, ray_direction, +# if defined(__METALRT_MOTION__) + payload.time, +# else + 0.0f, +# endif + ray_tmax, result); + + return result; +} +#endif /* __POINTCLOUD__ */ #endif /* __METALRT__ */ diff --git a/intern/cycles/kernel/film/read.h b/intern/cycles/kernel/film/read.h index 18a593a75b1..ba895fd8909 100644 --- a/intern/cycles/kernel/film/read.h +++ b/intern/cycles/kernel/film/read.h @@ -214,6 +214,21 @@ ccl_device_inline void film_get_pass_pixel_light_path( pixel[0] = f.x; pixel[1] = f.y; pixel[2] = f.z; + + /* Optional alpha channel. */ + if (kfilm_convert->num_components >= 4) { + if (kfilm_convert->pass_combined != PASS_UNUSED) { + float scale, scale_exposure; + film_get_scale_and_scale_exposure(kfilm_convert, buffer, &scale, &scale_exposure); + + ccl_global const float *in_combined = buffer + kfilm_convert->pass_combined; + const float alpha = in_combined[3] * scale; + pixel[3] = film_transparency_to_alpha(alpha); + } + else { + pixel[3] = 1.0f; + } + } } ccl_device_inline void film_get_pass_pixel_float3(ccl_global const KernelFilmConvert *ccl_restrict diff --git a/intern/cycles/kernel/geom/motion_triangle_intersect.h b/intern/cycles/kernel/geom/motion_triangle_intersect.h index 3bbb7be685d..cb6d210d90f 100644 --- a/intern/cycles/kernel/geom/motion_triangle_intersect.h +++ b/intern/cycles/kernel/geom/motion_triangle_intersect.h @@ -153,14 +153,12 @@ ccl_device_inline bool motion_triangle_intersect(KernelGlobals kg, float time, uint visibility, int object, + int prim, int prim_addr) { - /* Primitive index for vertex location lookup. */ - int prim = kernel_tex_fetch(__prim_index, prim_addr); - int fobject = (object == OBJECT_NONE) ? kernel_tex_fetch(__prim_object, prim_addr) : object; /* Get vertex locations for intersection. */ float3 verts[3]; - motion_triangle_vertices(kg, fobject, prim, time, verts); + motion_triangle_vertices(kg, object, prim, time, verts); /* Ray-triangle intersection, unoptimized. */ float t, u, v; if (ray_triangle_intersect(P, dir, tmax, verts[0], verts[1], verts[2], &u, &v, &t)) { @@ -175,8 +173,7 @@ ccl_device_inline bool motion_triangle_intersect(KernelGlobals kg, isect->u = u; isect->v = v; isect->prim = prim; - isect->object = (object == OBJECT_NONE) ? kernel_tex_fetch(__prim_object, prim_addr) : - object; + isect->object = object; isect->type = PRIMITIVE_MOTION_TRIANGLE; return true; } @@ -196,25 +193,15 @@ ccl_device_inline bool motion_triangle_intersect_local(KernelGlobals kg, float3 dir, float time, int object, - int local_object, + int prim, int prim_addr, float tmax, ccl_private uint *lcg_state, int max_hits) { - /* Only intersect with matching object, for instanced objects we - * already know we are only intersecting the right object. */ - if (object == OBJECT_NONE) { - if (kernel_tex_fetch(__prim_object, prim_addr) != local_object) { - return false; - } - } - - /* Primitive index for vertex location lookup. */ - int prim = kernel_tex_fetch(__prim_index, prim_addr); /* Get vertex locations for intersection. */ float3 verts[3]; - motion_triangle_vertices(kg, local_object, prim, time, verts); + motion_triangle_vertices(kg, object, prim, time, verts); /* Ray-triangle intersection, unoptimized. */ float t, u, v; if (!ray_triangle_intersect(P, dir, tmax, verts[0], verts[1], verts[2], &u, &v, &t)) { @@ -266,7 +253,7 @@ ccl_device_inline bool motion_triangle_intersect_local(KernelGlobals kg, isect->u = u; isect->v = v; isect->prim = prim; - isect->object = local_object; + isect->object = object; isect->type = PRIMITIVE_MOTION_TRIANGLE; /* Record geometric normal. */ diff --git a/intern/cycles/kernel/geom/triangle_intersect.h b/intern/cycles/kernel/geom/triangle_intersect.h index 4a7f38131da..0169b40bc34 100644 --- a/intern/cycles/kernel/geom/triangle_intersect.h +++ b/intern/cycles/kernel/geom/triangle_intersect.h @@ -33,9 +33,9 @@ ccl_device_inline bool triangle_intersect(KernelGlobals kg, float tmax, uint visibility, int object, + int prim, int prim_addr) { - const int prim = kernel_tex_fetch(__prim_index, prim_addr); const uint tri_vindex = kernel_tex_fetch(__tri_vindex, prim).w; const float3 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0), tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1), @@ -49,8 +49,7 @@ ccl_device_inline bool triangle_intersect(KernelGlobals kg, if (kernel_tex_fetch(__prim_visibility, prim_addr) & visibility) #endif { - isect->object = (object == OBJECT_NONE) ? kernel_tex_fetch(__prim_object, prim_addr) : - object; + isect->object = object; isect->prim = prim; isect->type = PRIMITIVE_TRIANGLE; isect->u = u; @@ -74,21 +73,12 @@ ccl_device_inline bool triangle_intersect_local(KernelGlobals kg, float3 P, float3 dir, int object, - int local_object, + int prim, int prim_addr, float tmax, ccl_private uint *lcg_state, int max_hits) { - /* Only intersect with matching object, for instanced objects we - * already know we are only intersecting the right object. */ - if (object == OBJECT_NONE) { - if (kernel_tex_fetch(__prim_object, prim_addr) != local_object) { - return false; - } - } - - const int prim = kernel_tex_fetch(__prim_index, prim_addr); const uint tri_vindex = kernel_tex_fetch(__tri_vindex, prim).w; const float3 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0), tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1), @@ -139,7 +129,7 @@ ccl_device_inline bool triangle_intersect_local(KernelGlobals kg, /* Record intersection. */ ccl_private Intersection *isect = &local_isect->hits[hit]; isect->prim = prim; - isect->object = local_object; + isect->object = object; isect->type = PRIMITIVE_TRIANGLE; isect->u = u; isect->v = v; diff --git a/intern/cycles/kernel/integrator/shade_surface.h b/intern/cycles/kernel/integrator/shade_surface.h index 3d5b65458c7..9f6077e5d66 100644 --- a/intern/cycles/kernel/integrator/shade_surface.h +++ b/intern/cycles/kernel/integrator/shade_surface.h @@ -188,7 +188,7 @@ ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg, const uint16_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce); uint32_t shadow_flag = INTEGRATOR_STATE(state, path, flag); shadow_flag |= (is_light) ? PATH_RAY_SHADOW_FOR_LIGHT : 0; - shadow_flag |= PATH_RAY_SURFACE_PASS; + shadow_flag |= (shadow_flag & PATH_RAY_ANY_PASS) ? 0 : PATH_RAY_SURFACE_PASS; const float3 throughput = INTEGRATOR_STATE(state, path, throughput) * bsdf_eval_sum(&bsdf_eval); if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) { diff --git a/intern/cycles/kernel/integrator/shade_volume.h b/intern/cycles/kernel/integrator/shade_volume.h index 712c22357b8..00fa256d894 100644 --- a/intern/cycles/kernel/integrator/shade_volume.h +++ b/intern/cycles/kernel/integrator/shade_volume.h @@ -797,7 +797,7 @@ ccl_device_forceinline void integrate_volume_direct_light( const uint16_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce); uint32_t shadow_flag = INTEGRATOR_STATE(state, path, flag); shadow_flag |= (is_light) ? PATH_RAY_SHADOW_FOR_LIGHT : 0; - shadow_flag |= PATH_RAY_VOLUME_PASS; + shadow_flag |= (shadow_flag & PATH_RAY_ANY_PASS) ? 0 : PATH_RAY_VOLUME_PASS; const float3 throughput_phase = throughput * bsdf_eval_sum(&phase_eval); if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) { diff --git a/intern/cycles/kernel/svm/attribute.h b/intern/cycles/kernel/svm/attribute.h index e9de0164c7a..17301028528 100644 --- a/intern/cycles/kernel/svm/attribute.h +++ b/intern/cycles/kernel/svm/attribute.h @@ -87,7 +87,9 @@ ccl_device_noinline void svm_node_attr(KernelGlobals kg, if (node.y == ATTR_STD_GENERATED && desc.element == ATTR_ELEMENT_NONE) { /* No generated attribute, fall back to object coordinates. */ float3 f = sd->P; - object_inverse_position_transform(kg, sd, &f); + if (sd->object != OBJECT_NONE) { + object_inverse_position_transform(kg, sd, &f); + } if (type == NODE_ATTR_OUTPUT_FLOAT) { stack_store_float(stack, out_offset, average(f)); } @@ -179,7 +181,9 @@ ccl_device_noinline void svm_node_attr_bump_dx(KernelGlobals kg, if (node.y == ATTR_STD_GENERATED && desc.element == ATTR_ELEMENT_NONE) { /* No generated attribute, fall back to object coordinates. */ float3 f = sd->P + sd->dP.dx; - object_inverse_position_transform(kg, sd, &f); + if (sd->object != OBJECT_NONE) { + object_inverse_position_transform(kg, sd, &f); + } if (type == NODE_ATTR_OUTPUT_FLOAT) { stack_store_float(stack, out_offset, average(f)); } @@ -275,7 +279,9 @@ ccl_device_noinline void svm_node_attr_bump_dy(KernelGlobals kg, if (node.y == ATTR_STD_GENERATED && desc.element == ATTR_ELEMENT_NONE) { /* No generated attribute, fall back to object coordinates. */ float3 f = sd->P + sd->dP.dy; - object_inverse_position_transform(kg, sd, &f); + if (sd->object != OBJECT_NONE) { + object_inverse_position_transform(kg, sd, &f); + } if (type == NODE_ATTR_OUTPUT_FLOAT) { stack_store_float(stack, out_offset, average(f)); } diff --git a/intern/cycles/scene/alembic.cpp b/intern/cycles/scene/alembic.cpp index 71fa1863b8b..a8aec133fb6 100644 --- a/intern/cycles/scene/alembic.cpp +++ b/intern/cycles/scene/alembic.cpp @@ -742,6 +742,7 @@ NODE_DEFINE(AlembicProcedural) NodeType *type = NodeType::add("alembic", create); SOCKET_STRING(filepath, "Filename", ustring()); + SOCKET_STRING_ARRAY(layers, "Layers", array()); SOCKET_FLOAT(frame, "Frame", 1.0f); SOCKET_FLOAT(start_frame, "Start Frame", 1.0f); SOCKET_FLOAT(end_frame, "End Frame", 1.0f); @@ -839,14 +840,26 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress) return; } - if (!archive.valid()) { + if (!archive.valid() || filepath_is_modified() || layers_is_modified()) { Alembic::AbcCoreFactory::IFactory factory; factory.setPolicy(Alembic::Abc::ErrorHandler::kQuietNoopPolicy); - archive = factory.getArchive(filepath.c_str()); + + std::vector filenames; + filenames.push_back(filepath.c_str()); + + for (const ustring &layer : layers) { + filenames.push_back(layer.c_str()); + } + + /* We need to reverse the order as overriding archives should come first. */ + std::reverse(filenames.begin(), filenames.end()); + + archive = factory.getArchive(filenames); if (!archive.valid()) { /* avoid potential infinite update loops in viewport synchronization */ filepath.clear(); + layers.clear(); clear_modified(); return; } @@ -1165,6 +1178,12 @@ void AlembicProcedural::read_subd(AlembicObject *abc_object, Abc::chrono_t frame cached_data.subd_creases_weight.copy_to_socket( frame_time, mesh, mesh->get_subd_creases_weight_socket()); + cached_data.subd_vertex_crease_indices.copy_to_socket( + frame_time, mesh, mesh->get_subd_vert_creases_socket()); + + cached_data.subd_vertex_crease_weights.copy_to_socket( + frame_time, mesh, mesh->get_subd_vert_creases_weight_socket()); + mesh->set_num_subd_faces(mesh->get_subd_shader().size()); /* Update attributes. */ diff --git a/intern/cycles/scene/alembic.h b/intern/cycles/scene/alembic.h index 3a4d37da3ff..9ea4737bea1 100644 --- a/intern/cycles/scene/alembic.h +++ b/intern/cycles/scene/alembic.h @@ -320,6 +320,8 @@ struct CachedData { DataStore num_ngons; DataStore> subd_creases_edge; DataStore> subd_creases_weight; + DataStore> subd_vertex_crease_indices; + DataStore> subd_vertex_crease_weights; /* hair data */ DataStore> curve_keys; @@ -479,6 +481,10 @@ class AlembicProcedural : public Procedural { /* The file path to the Alembic archive */ NODE_SOCKET_API(ustring, filepath) + /* Layers for the Alembic archive. Layers are in the order in which they override data, with the + * latter elements overriding the former ones. */ + NODE_SOCKET_API_ARRAY(array, layers) + /* The current frame to render. */ NODE_SOCKET_API(float, frame) diff --git a/intern/cycles/scene/alembic_read.cpp b/intern/cycles/scene/alembic_read.cpp index 07874b7528e..33908dff6e5 100644 --- a/intern/cycles/scene/alembic_read.cpp +++ b/intern/cycles/scene/alembic_read.cpp @@ -478,7 +478,9 @@ static void add_subd_polygons(CachedData &cached_data, const SubDSchemaData &dat cached_data.uv_loops.add_data(uv_loops, time); } -static void add_subd_creases(CachedData &cached_data, const SubDSchemaData &data, chrono_t time) +static void add_subd_edge_creases(CachedData &cached_data, + const SubDSchemaData &data, + chrono_t time) { if (!(data.crease_indices.valid() && data.crease_indices.valid() && data.crease_sharpnesses.valid())) { @@ -517,6 +519,37 @@ static void add_subd_creases(CachedData &cached_data, const SubDSchemaData &data } } +static void add_subd_vertex_creases(CachedData &cached_data, + const SubDSchemaData &data, + chrono_t time) +{ + if (!(data.corner_indices.valid() && data.crease_sharpnesses.valid())) { + return; + } + + const ISampleSelector iss = ISampleSelector(time); + const Int32ArraySamplePtr creases_indices = data.crease_indices.getValue(iss); + const FloatArraySamplePtr creases_sharpnesses = data.crease_sharpnesses.getValue(iss); + + if (!(creases_indices && creases_sharpnesses) || + creases_indices->size() != creases_sharpnesses->size()) { + return; + } + + array sharpnesses; + sharpnesses.reserve(creases_indices->size()); + array indices; + indices.reserve(creases_indices->size()); + + for (size_t i = 0; i < creases_indices->size(); i++) { + indices.push_back_reserved((*creases_indices)[i]); + sharpnesses.push_back_reserved((*creases_sharpnesses)[i]); + } + + cached_data.subd_vertex_crease_indices.add_data(indices, time); + cached_data.subd_vertex_crease_weights.add_data(sharpnesses, time); +} + static void read_subd_geometry(CachedData &cached_data, const SubDSchemaData &data, chrono_t time) { const ISampleSelector iss = ISampleSelector(time); @@ -525,7 +558,8 @@ static void read_subd_geometry(CachedData &cached_data, const SubDSchemaData &da if (data.topology_variance != kHomogenousTopology || cached_data.shader.size() == 0) { add_subd_polygons(cached_data, data, time); - add_subd_creases(cached_data, data, time); + add_subd_edge_creases(cached_data, data, time); + add_subd_vertex_creases(cached_data, data, time); } } diff --git a/intern/cycles/scene/alembic_read.h b/intern/cycles/scene/alembic_read.h index e95750ce691..94018b82747 100644 --- a/intern/cycles/scene/alembic_read.h +++ b/intern/cycles/scene/alembic_read.h @@ -76,9 +76,10 @@ struct SubDSchemaData { vector shader_face_sets; - // Those are unsupported for now. Alembic::AbcGeom::IInt32ArrayProperty corner_indices; Alembic::AbcGeom::IFloatArrayProperty corner_sharpnesses; + + // Those are unsupported for now. Alembic::AbcGeom::IInt32Property face_varying_interpolate_boundary; Alembic::AbcGeom::IInt32Property face_varying_propagate_corners; Alembic::AbcGeom::IInt32Property interpolate_boundary; diff --git a/intern/cycles/scene/colorspace.cpp b/intern/cycles/scene/colorspace.cpp index c1a308fcbaa..f0b7eb724de 100644 --- a/intern/cycles/scene/colorspace.cpp +++ b/intern/cycles/scene/colorspace.cpp @@ -263,7 +263,9 @@ template inline void cast_from_float4(T *data, float4 value) /* Slower versions for other all data types, which needs to convert to float and back. */ template -inline void processor_apply_pixels(const OCIO::Processor *processor, T *pixels, size_t num_pixels) +inline void processor_apply_pixels_rgba(const OCIO::Processor *processor, + T *pixels, + size_t num_pixels) { /* TODO: implement faster version for when we know the conversion * is a simple matrix transform between linear spaces. In that case @@ -310,25 +312,79 @@ inline void processor_apply_pixels(const OCIO::Processor *processor, T *pixels, } } } + +template +inline void processor_apply_pixels_grayscale(const OCIO::Processor *processor, + T *pixels, + size_t num_pixels) +{ + OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor(); + + /* Process large images in chunks to keep temporary memory requirement down. */ + const size_t chunk_size = std::min((size_t)(16 * 1024 * 1024), num_pixels); + vector float_pixels(chunk_size * 3); + + for (size_t j = 0; j < num_pixels; j += chunk_size) { + size_t width = std::min(chunk_size, num_pixels - j); + + /* Convert to 3 channels, since that's the minimum required by OpenColorIO. */ + { + const T *pixel = pixels + j; + float *fpixel = float_pixels.data(); + for (size_t i = 0; i < width; i++, pixel++, fpixel += 3) { + const float f = util_image_cast_to_float(*pixel); + fpixel[0] = f; + fpixel[1] = f; + fpixel[2] = f; + } + } + + OCIO::PackedImageDesc desc((float *)float_pixels.data(), width, 1, 3); + device_processor->apply(desc); + + { + T *pixel = pixels + j; + const float *fpixel = float_pixels.data(); + for (size_t i = 0; i < width; i++, pixel++, fpixel += 3) { + float f = average(make_float3(fpixel[0], fpixel[1], fpixel[2])); + if (compress_as_srgb) { + f = color_linear_to_srgb(f); + } + *pixel = util_image_cast_from_float(f); + } + } + } +} + #endif template -void ColorSpaceManager::to_scene_linear(ustring colorspace, - T *pixels, - size_t num_pixels, - bool compress_as_srgb) +void ColorSpaceManager::to_scene_linear( + ustring colorspace, T *pixels, size_t num_pixels, bool is_rgba, bool compress_as_srgb) { #ifdef WITH_OCIO const OCIO::Processor *processor = (const OCIO::Processor *)get_processor(colorspace); if (processor) { - if (compress_as_srgb) { - /* Compress output as sRGB. */ - processor_apply_pixels(processor, pixels, num_pixels); + if (is_rgba) { + if (compress_as_srgb) { + /* Compress output as sRGB. */ + processor_apply_pixels_rgba(processor, pixels, num_pixels); + } + else { + /* Write output as scene linear directly. */ + processor_apply_pixels_rgba(processor, pixels, num_pixels); + } } else { - /* Write output as scene linear directly. */ - processor_apply_pixels(processor, pixels, num_pixels); + if (compress_as_srgb) { + /* Compress output as sRGB. */ + processor_apply_pixels_grayscale(processor, pixels, num_pixels); + } + else { + /* Write output as scene linear directly. */ + processor_apply_pixels_grayscale(processor, pixels, num_pixels); + } } } #else @@ -348,6 +404,11 @@ void ColorSpaceManager::to_scene_linear(ColorSpaceProcessor *processor_, if (processor) { OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor(); + if (channels == 1) { + float3 rgb = make_float3(pixel[0], pixel[0], pixel[0]); + device_processor->applyRGB(&rgb.x); + pixel[0] = average(rgb); + } if (channels == 3) { device_processor->applyRGB(pixel); } @@ -390,9 +451,9 @@ void ColorSpaceManager::free_memory() } /* Template instantiations so we don't have to inline functions. */ -template void ColorSpaceManager::to_scene_linear(ustring, uchar *, size_t, bool); -template void ColorSpaceManager::to_scene_linear(ustring, ushort *, size_t, bool); -template void ColorSpaceManager::to_scene_linear(ustring, half *, size_t, bool); -template void ColorSpaceManager::to_scene_linear(ustring, float *, size_t, bool); +template void ColorSpaceManager::to_scene_linear(ustring, uchar *, size_t, bool, bool); +template void ColorSpaceManager::to_scene_linear(ustring, ushort *, size_t, bool, bool); +template void ColorSpaceManager::to_scene_linear(ustring, half *, size_t, bool, bool); +template void ColorSpaceManager::to_scene_linear(ustring, float *, size_t, bool, bool); CCL_NAMESPACE_END diff --git a/intern/cycles/scene/colorspace.h b/intern/cycles/scene/colorspace.h index 7f7bc604f07..f02c1231a44 100644 --- a/intern/cycles/scene/colorspace.h +++ b/intern/cycles/scene/colorspace.h @@ -43,10 +43,8 @@ class ColorSpaceManager { /* Convert pixels in the specified colorspace to scene linear color for * rendering. Must be a colorspace returned from detect_known_colorspace. */ template - static void to_scene_linear(ustring colorspace, - T *pixels, - size_t num_pixels, - bool compress_as_srgb); + static void to_scene_linear( + ustring colorspace, T *pixels, size_t num_pixels, bool is_rgba, bool compress_as_srgb); /* Efficiently convert pixels to scene linear colorspace at render time, * for OSL where the image texture cache contains original pixels. The diff --git a/intern/cycles/scene/constant_fold.cpp b/intern/cycles/scene/constant_fold.cpp index a5fb68bf229..e9fb3426b70 100644 --- a/intern/cycles/scene/constant_fold.cpp +++ b/intern/cycles/scene/constant_fold.cpp @@ -441,9 +441,13 @@ void ConstantFolder::fold_mapping(NodeMappingType type) const if (is_zero(scale_in)) { make_zero(); } - else if ((is_zero(location_in) || type == NODE_MAPPING_TYPE_VECTOR || - type == NODE_MAPPING_TYPE_NORMAL) && - is_zero(rotation_in) && is_one(scale_in)) { + else if ( + /* Can't constant fold since we always need to normalize the output. */ + (type != NODE_MAPPING_TYPE_NORMAL) && + /* Check all use values are zero, note location is not used by vector and normal types. */ + (is_zero(location_in) || type == NODE_MAPPING_TYPE_VECTOR || + type == NODE_MAPPING_TYPE_NORMAL) && + is_zero(rotation_in) && is_one(scale_in)) { try_bypass_or_make_constant(vector_in); } } diff --git a/intern/cycles/scene/image.cpp b/intern/cycles/scene/image.cpp index 3595ca55a46..dbc8bf213af 100644 --- a/intern/cycles/scene/image.cpp +++ b/intern/cycles/scene/image.cpp @@ -576,13 +576,13 @@ bool ImageManager::file_load_image(Image *img, int texture_limit) pixels[i * 4 + 3] = one; } } + } - if (img->metadata.colorspace != u_colorspace_raw && - img->metadata.colorspace != u_colorspace_srgb) { - /* Convert to scene linear. */ - ColorSpaceManager::to_scene_linear( - img->metadata.colorspace, pixels, num_pixels, img->metadata.compress_as_srgb); - } + if (img->metadata.colorspace != u_colorspace_raw && + img->metadata.colorspace != u_colorspace_srgb) { + /* Convert to scene linear. */ + ColorSpaceManager::to_scene_linear( + img->metadata.colorspace, pixels, num_pixels, is_rgba, img->metadata.compress_as_srgb); } /* Make sure we don't have buggy values. */ diff --git a/intern/cycles/scene/mesh.cpp b/intern/cycles/scene/mesh.cpp index e65b8462e34..c381d7a54ff 100644 --- a/intern/cycles/scene/mesh.cpp +++ b/intern/cycles/scene/mesh.cpp @@ -141,6 +141,9 @@ NODE_DEFINE(Mesh) subdivision_type_enum.insert("catmull_clark", SUBDIVISION_CATMULL_CLARK); SOCKET_ENUM(subdivision_type, "Subdivision Type", subdivision_type_enum, SUBDIVISION_NONE); + SOCKET_INT_ARRAY(subd_vert_creases, "Subdivision Vertex Crease", array()); + SOCKET_FLOAT_ARRAY( + subd_vert_creases_weight, "Subdivision Vertex Crease Weights", array()); SOCKET_INT_ARRAY(subd_creases_edge, "Subdivision Crease Edges", array()); SOCKET_FLOAT_ARRAY(subd_creases_weight, "Subdivision Crease Weights", array()); SOCKET_INT_ARRAY(subd_face_corners, "Subdivision Face Corners", array()); @@ -408,7 +411,7 @@ Mesh::SubdFace Mesh::get_subd_face(size_t index) const return s; } -void Mesh::add_crease(int v0, int v1, float weight) +void Mesh::add_edge_crease(int v0, int v1, float weight) { subd_creases_edge.push_back_slow(v0); subd_creases_edge.push_back_slow(v1); @@ -419,6 +422,17 @@ void Mesh::add_crease(int v0, int v1, float weight) tag_subd_creases_weight_modified(); } +void Mesh::add_vertex_crease(int v, float weight) +{ + assert(v < verts.size()); + + subd_vert_creases.push_back_slow(v); + subd_vert_creases_weight.push_back_slow(weight); + + tag_subd_vert_creases_modified(); + tag_subd_vert_creases_weight_modified(); +} + void Mesh::copy_center_to_motion_step(const int motion_step) { Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); diff --git a/intern/cycles/scene/mesh.h b/intern/cycles/scene/mesh.h index 254672d0620..07acd5328d2 100644 --- a/intern/cycles/scene/mesh.h +++ b/intern/cycles/scene/mesh.h @@ -160,6 +160,9 @@ class Mesh : public Geometry { NODE_SOCKET_API_ARRAY(array, subd_creases_edge) NODE_SOCKET_API_ARRAY(array, subd_creases_weight) + NODE_SOCKET_API_ARRAY(array, subd_vert_creases) + NODE_SOCKET_API_ARRAY(array, subd_vert_creases_weight) + /* Subdivisions parameters */ NODE_SOCKET_API(float, subd_dicing_rate) NODE_SOCKET_API(int, subd_max_level) @@ -210,7 +213,8 @@ class Mesh : public Geometry { void add_vertex_slow(float3 P); void add_triangle(int v0, int v1, int v2, int shader, bool smooth); void add_subd_face(int *corners, int num_corners, int shader_, bool smooth_); - void add_crease(int v0, int v1, float weight); + void add_edge_crease(int v0, int v1, float weight); + void add_vertex_crease(int v, float weight); void copy_center_to_motion_step(const int motion_step); diff --git a/intern/cycles/scene/mesh_subdivision.cpp b/intern/cycles/scene/mesh_subdivision.cpp index 35f15cfafbc..7c88e310527 100644 --- a/intern/cycles/scene/mesh_subdivision.cpp +++ b/intern/cycles/scene/mesh_subdivision.cpp @@ -82,24 +82,54 @@ template<> bool TopologyRefinerFactory::assignComponentTags(TopologyRefiner &refiner, ccl::Mesh const &mesh) { + /* Historical maximum crease weight used at Pixar, influencing the maximum in OpenSubDiv. */ + static constexpr float CREASE_SCALE = 10.0f; + size_t num_creases = mesh.get_subd_creases_weight().size(); + size_t num_vertex_creases = mesh.get_subd_vert_creases().size(); + + /* The last loop is over the vertices, so early exit to avoid iterating them needlessly. */ + if (num_creases == 0 && num_vertex_creases == 0) { + return true; + } for (int i = 0; i < num_creases; i++) { ccl::Mesh::SubdEdgeCrease crease = mesh.get_subd_crease(i); Index edge = findBaseEdge(refiner, crease.v[0], crease.v[1]); if (edge != INDEX_INVALID) { - setBaseEdgeSharpness(refiner, edge, crease.crease * 10.0f); + setBaseEdgeSharpness(refiner, edge, crease.crease * CREASE_SCALE); } } + std::map vertex_creases; + + for (size_t i = 0; i < num_vertex_creases; ++i) { + const int vertex_idx = mesh.get_subd_vert_creases()[i]; + const float weight = mesh.get_subd_vert_creases_weight()[i]; + + vertex_creases[vertex_idx] = weight * CREASE_SCALE; + } + for (int i = 0; i < mesh.get_verts().size(); i++) { + float sharpness = 0.0f; + std::map::const_iterator iter = vertex_creases.find(i); + + if (iter != vertex_creases.end()) { + sharpness = iter->second; + } + ConstIndexArray vert_edges = getBaseVertexEdges(refiner, i); if (vert_edges.size() == 2) { - float sharpness = refiner.getLevel(0).getEdgeSharpness(vert_edges[0]); - sharpness = ccl::min(sharpness, refiner.getLevel(0).getEdgeSharpness(vert_edges[1])); + const float sharpness0 = refiner.getLevel(0).getEdgeSharpness(vert_edges[0]); + const float sharpness1 = refiner.getLevel(0).getEdgeSharpness(vert_edges[1]); + sharpness += ccl::min(sharpness0, sharpness1); + sharpness = ccl::min(sharpness, CREASE_SCALE); + } + + if (sharpness != 0.0f) { setBaseVertexSharpness(refiner, i, sharpness); } } diff --git a/intern/cycles/util/array.h b/intern/cycles/util/array.h index 4c905b09138..1c5e3e8d4ec 100644 --- a/intern/cycles/util/array.h +++ b/intern/cycles/util/array.h @@ -64,7 +64,7 @@ template class arra else { data_ = mem_allocate(from.datasize_); if (from.datasize_ > 0) { - memcpy(data_, from.data_, from.datasize_ * sizeof(T)); + mem_copy(data_, from.data_, from.datasize_); } datasize_ = from.datasize_; capacity_ = datasize_; @@ -76,7 +76,7 @@ template class arra if (this != &from) { resize(from.size()); if (datasize_ > 0) { - memcpy((void *)data_, from.data_, datasize_ * sizeof(T)); + mem_copy(data_, from.data_, datasize_); } } @@ -88,7 +88,7 @@ template class arra resize(from.size()); if (from.size() > 0 && datasize_ > 0) { - memcpy(data_, &from[0], datasize_ * sizeof(T)); + mem_copy(data_, from.data(), datasize_); } return *this; @@ -161,8 +161,7 @@ template class arra return NULL; } else if (data_ != NULL) { - memcpy( - (void *)newdata, data_, ((datasize_ < newsize) ? datasize_ : newsize) * sizeof(T)); + mem_copy(newdata, data_, ((datasize_ < newsize) ? datasize_ : newsize)); mem_free(data_, capacity_); } data_ = newdata; @@ -246,7 +245,7 @@ template class arra if (newcapacity > capacity_) { T *newdata = mem_allocate(newcapacity); if (data_ != NULL) { - memcpy(newdata, data_, ((datasize_ < newcapacity) ? datasize_ : newcapacity) * sizeof(T)); + mem_copy(newdata, data_, ((datasize_ < newcapacity) ? datasize_ : newcapacity)); mem_free(data_, capacity_); } data_ = newdata; @@ -280,7 +279,7 @@ template class arra if (from.size()) { size_t old_size = size(); resize(old_size + from.size()); - memcpy(data_ + old_size, from.data(), sizeof(T) * from.size()); + mem_copy(data_ + old_size, from.data(), from.size()); } } @@ -308,6 +307,11 @@ template class arra } } + inline void mem_copy(T *mem_to, const T *mem_from, const size_t N) + { + memcpy((void *)mem_to, mem_from, sizeof(T) * N); + } + T *data_; size_t datasize_; size_t capacity_; diff --git a/intern/cycles/util/math_int4.h b/intern/cycles/util/math_int4.h index 9e3f001efc2..eaa9be73b63 100644 --- a/intern/cycles/util/math_int4.h +++ b/intern/cycles/util/math_int4.h @@ -131,10 +131,7 @@ ccl_device_inline int4 clamp(const int4 &a, const int4 &mn, const int4 &mx) ccl_device_inline int4 select(const int4 &mask, const int4 &a, const int4 &b) { # ifdef __KERNEL_SSE__ - const __m128 m = _mm_cvtepi32_ps(mask); - /* TODO(sergey): avoid cvt. */ - return int4(_mm_castps_si128( - _mm_or_ps(_mm_and_ps(m, _mm_castsi128_ps(a)), _mm_andnot_ps(m, _mm_castsi128_ps(b))))); + return int4(_mm_or_si128(_mm_and_si128(mask, a), _mm_andnot_si128(mask, b))); # else return make_int4( (mask.x) ? a.x : b.x, (mask.y) ? a.y : b.y, (mask.z) ? a.z : b.z, (mask.w) ? a.w : b.w); diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 8b44403c598..c77ef162d9a 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -544,7 +544,7 @@ void GHOST_WindowX11::refreshXInputDevices() std::vector xevents; for (GHOST_SystemX11::GHOST_TabletX11 &xtablet : m_system->GetXTablets()) { - /* With modern XInput (xlib 1.6.2 at least and/or evdev 2.9.0) and some 'no-name' tablets + /* With modern XInput (XLIB 1.6.2 at least and/or EVDEV 2.9.0) and some 'no-name' tablets * like 'UC-LOGIC Tablet WP5540U', we also need to 'select' ButtonPress for motion event, * otherwise we do not get any tablet motion event once pen is pressed... See T43367. */ diff --git a/intern/ghost/intern/GHOST_Wintab.cpp b/intern/ghost/intern/GHOST_Wintab.cpp index d13d1a560b7..953fcb171e5 100644 --- a/intern/ghost/intern/GHOST_Wintab.cpp +++ b/intern/ghost/intern/GHOST_Wintab.cpp @@ -130,8 +130,7 @@ GHOST_Wintab *GHOST_Wintab::loadWintab(HWND hwnd) } } - return new GHOST_Wintab(hwnd, - std::move(handle), + return new GHOST_Wintab(std::move(handle), info, get, set, @@ -174,8 +173,7 @@ void GHOST_Wintab::extractCoordinates(LOGCONTEXT &lc, Coord &tablet, Coord &syst system.y.ext = -lc.lcSysExtY; } -GHOST_Wintab::GHOST_Wintab(HWND hwnd, - unique_hmodule handle, +GHOST_Wintab::GHOST_Wintab(unique_hmodule handle, GHOST_WIN32_WTInfo info, GHOST_WIN32_WTGet get, GHOST_WIN32_WTSet set, diff --git a/intern/ghost/intern/GHOST_Wintab.h b/intern/ghost/intern/GHOST_Wintab.h index c61b1c8ccda..1994f057db9 100644 --- a/intern/ghost/intern/GHOST_Wintab.h +++ b/intern/ghost/intern/GHOST_Wintab.h @@ -214,8 +214,7 @@ class GHOST_Wintab { /** Most recently received tablet data, or none if pen is not in range. */ GHOST_TabletData m_lastTabletData = GHOST_TABLET_DATA_NONE; - GHOST_Wintab(HWND hwnd, - unique_hmodule handle, + GHOST_Wintab(unique_hmodule handle, GHOST_WIN32_WTInfo info, GHOST_WIN32_WTGet get, GHOST_WIN32_WTSet set, diff --git a/intern/ghost/test/CMakeLists.txt b/intern/ghost/test/CMakeLists.txt index 37bb00332dd..acd0da8785e 100644 --- a/intern/ghost/test/CMakeLists.txt +++ b/intern/ghost/test/CMakeLists.txt @@ -292,7 +292,7 @@ target_link_libraries(multitest_c guardedalloc_lib wcwidth_lib ${OPENGL_gl_LIBRARY} - ${FREETYPE_LIBRARY} + ${FREETYPE_LIBRARIES} ${ZLIB_LIBRARIES} ${CMAKE_DL_LIBS} ${PLATFORM_LINKLIBS} diff --git a/release/datafiles/locale b/release/datafiles/locale index d46eacffd92..68f8874599d 160000 --- a/release/datafiles/locale +++ b/release/datafiles/locale @@ -1 +1 @@ -Subproject commit d46eacffd92496ae9702a71dfc4da235eaf7731b +Subproject commit 68f8874599d7fbac10fa332535450d8a78fafda2 diff --git a/release/scripts/addons b/release/scripts/addons index d4fcda5935c..b825c2d31ad 160000 --- a/release/scripts/addons +++ b/release/scripts/addons @@ -1 +1 @@ -Subproject commit d4fcda5935c5c561e77aadd32a32500cf280dcaa +Subproject commit b825c2d31ad39218fe39c99037d31bc2479211bd diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib index 7936dde9ece..61e45814503 160000 --- a/release/scripts/addons_contrib +++ b/release/scripts/addons_contrib @@ -1 +1 @@ -Subproject commit 7936dde9ece881d531b1a2ee6c45ddb56d30038c +Subproject commit 61e45814503f51963c91c51aaf764612e7c5dc72 diff --git a/release/scripts/modules/keyingsets_utils.py b/release/scripts/modules/keyingsets_utils.py index 84a01ef3666..0dd06995ed3 100644 --- a/release/scripts/modules/keyingsets_utils.py +++ b/release/scripts/modules/keyingsets_utils.py @@ -245,7 +245,7 @@ def RKS_GEN_custom_props(_ksi, _context, ks, data): # Can technically happen, but there is no known case. continue if rna_property is None: - # In this case the property cannot be converted to an + # In this case the property cannot be converted to an # FCurve-compatible value, so we can't keyframe it anyways. continue if rna_property.rna_type not in prop_type_compat: diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 7b45df26677..e51618a3c55 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -2467,18 +2467,22 @@ class WM_OT_batch_rename(Operator): name="Type", items=( ('OBJECT', "Objects", ""), + ('COLLECTION', "Collections", ""), ('MATERIAL', "Materials", ""), None, # Enum identifiers are compared with 'object.type'. + # Follow order in "Add" menu. ('MESH', "Meshes", ""), ('CURVE', "Curves", ""), ('META', "Metaballs", ""), + ('VOLUME', "Volumes", ""), + ('GPENCIL', "Grease Pencils", ""), ('ARMATURE', "Armatures", ""), ('LATTICE', "Lattices", ""), - ('GPENCIL', "Grease Pencils", ""), + ('LIGHT', "Light", ""), + ('LIGHT_PROBE', "Light Probes", ""), ('CAMERA', "Cameras", ""), ('SPEAKER', "Speakers", ""), - ('LIGHT_PROBE', "Light Probes", ""), None, ('BONE', "Bones", ""), ('NODE', "Nodes", ""), @@ -2498,7 +2502,26 @@ class WM_OT_batch_rename(Operator): actions: CollectionProperty(type=BatchRenameAction) @staticmethod - def _data_from_context(context, data_type, only_selected, *, check_context=False): + def _selected_ids_from_outliner_by_type(context, ty): + return [ + id for id in context.selected_ids + if isinstance(id, ty) + if id.library is None + ] + + @staticmethod + def _selected_ids_from_outliner_by_type_for_object_data(context, ty): + # Include selected object-data as well as the selected ID's. + from bpy.types import Object + # De-duplicate the result as object-data may cause duplicates. + return tuple(set([ + id for id_base in context.selected_ids + if isinstance(id := id_base.data if isinstance(id_base, Object) else id_base, ty) + if id.library is None + ])) + + @classmethod + def _data_from_context(cls, context, data_type, only_selected, *, check_context=False): mode = context.mode scene = context.scene @@ -2512,10 +2535,9 @@ class WM_OT_batch_rename(Operator): return data_type_test if data_type == data_type_test: data = ( - # TODO, we don't have access to seqbasep, this won't work when inside metas. - [seq for seq in context.scene.sequence_editor.sequences_all if seq.select] + context.selected_sequences if only_selected else - context.scene.sequence_editor.sequences_all, + scene.sequence_editor.sequences_all, "name", "Strip(s)", ) @@ -2531,6 +2553,18 @@ class WM_OT_batch_rename(Operator): "name", "Node(s)", ) + elif space_type == 'OUTLINER': + data_type_test = 'COLLECTION' + if check_context: + return data_type_test + if data_type == data_type_test: + data = ( + cls._selected_ids_from_outliner_by_type(context, bpy.types.Collection) + if only_selected else + scene.collection.children_recursive, + "name", + "Collection(s)", + ) else: if mode == 'POSE' or (mode == 'WEIGHT_PAINT' and context.pose_object): data_type_test = 'BONE' @@ -2561,15 +2595,17 @@ class WM_OT_batch_rename(Operator): return 'OBJECT' object_data_type_attrs_map = { - 'MESH': ("meshes", "Mesh(es)"), - 'CURVE': ("curves", "Curve(s)"), - 'META': ("metaballs", "Metaball(s)"), - 'ARMATURE': ("armatures", "Armature(s)"), - 'LATTICE': ("lattices", "Lattice(s)"), - 'GPENCIL': ("grease_pencils", "Grease Pencil(s)"), - 'CAMERA': ("cameras", "Camera(s)"), - 'SPEAKER': ("speakers", "Speaker(s)"), - 'LIGHT_PROBE': ("light_probes", "Light Probe(s)"), + 'MESH': ("meshes", "Mesh(es)", bpy.types.Mesh), + 'CURVE': ("curves", "Curve(s)", bpy.types.Curve), + 'META': ("metaballs", "Metaball(s)", bpy.types.MetaBall), + 'VOLUME': ("volumes", "Volume(s)", bpy.types.Volume), + 'GPENCIL': ("grease_pencils", "Grease Pencil(s)", bpy.types.GreasePencil), + 'ARMATURE': ("armatures", "Armature(s)", bpy.types.Armature), + 'LATTICE': ("lattices", "Lattice(s)", bpy.types.Lattice), + 'LIGHT': ("lights", "Light(s)", bpy.types.Light), + 'LIGHT_PROBE': ("light_probes", "Light Probe(s)", bpy.types.LightProbe), + 'CAMERA': ("cameras", "Camera(s)", bpy.types.Camera), + 'SPEAKER': ("speakers", "Speaker(s)", bpy.types.Speaker), } # Finish with space types. @@ -2577,34 +2613,67 @@ class WM_OT_batch_rename(Operator): if data_type == 'OBJECT': data = ( - context.selected_editable_objects + ( + # Outliner. + cls._selected_ids_from_outliner_by_type(context, bpy.types.Object) + if space_type == 'OUTLINER' else + # 3D View (default). + context.selected_editable_objects + ) if only_selected else [id for id in bpy.data.objects if id.library is None], "name", "Object(s)", ) + elif data_type == 'COLLECTION': + data = ( + # Outliner case is handled already. + tuple(set( + ob.instance_collection + for ob in context.selected_objects + if ((ob.instance_type == 'COLLECTION') and + (collection := ob.instance_collection) is not None and + (collection.library is None)) + )) + if only_selected else + [id for id in bpy.data.collections if id.library is None], + "name", + "Collection(s)", + ) elif data_type == 'MATERIAL': data = ( - tuple(set( - slot.material - for ob in context.selected_objects - for slot in ob.material_slots - if slot.material is not None - )) + ( + # Outliner. + cls._selected_ids_from_outliner_by_type(context, bpy.types.Material) + if space_type == 'OUTLINER' else + # 3D View (default). + tuple(set( + id + for ob in context.selected_objects + for slot in ob.material_slots + if (id := slot.material) is not None and id.library is None + )) + ) if only_selected else [id for id in bpy.data.materials if id.library is None], "name", "Material(s)", ) elif data_type in object_data_type_attrs_map.keys(): - attr, descr = object_data_type_attrs_map[data_type] + attr, descr, ty = object_data_type_attrs_map[data_type] data = ( - tuple(set( - id - for ob in context.selected_objects - if ob.type == data_type - if (id := ob.data) is not None and id.library is None - )) + ( + # Outliner. + cls._selected_ids_from_outliner_by_type_for_object_data(context, ty) + if space_type == 'OUTLINER' else + # 3D View (default). + tuple(set( + id + for ob in context.selected_objects + if ob.type == data_type + if (id := ob.data) is not None and id.library is None + )) + ) if only_selected else [id for id in getattr(bpy.data, attr) if id.library is None], "name", diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py index 570a437c213..fcac0af7e86 100644 --- a/release/scripts/startup/bl_ui/properties_constraint.py +++ b/release/scripts/startup/bl_ui/properties_constraint.py @@ -1161,6 +1161,11 @@ class ConstraintButtonsSubPanel: context, self.layout.template_cache_file_time_settings ) + def draw_transform_cache_layers(self, context): + self.draw_transform_cache_subpanel( + context, self.layout.template_cache_file_layers + ) + def draw_transform_cache_subpanel(self, context, template_func): con = self.get_constraint(context) if con.cache_file is None: @@ -1574,6 +1579,22 @@ class BONE_PT_bTransformCacheConstraint_velocity(BoneConstraintPanel, Constraint self.draw_transform_cache_velocity(context) +class OBJECT_PT_bTransformCacheConstraint_layers(ObjectConstraintPanel, ConstraintButtonsSubPanel, Panel): + bl_parent_id = "OBJECT_PT_bTransformCacheConstraint" + bl_label = "Override Layers" + + def draw(self, context): + self.draw_transform_cache_layers(context) + + +class BONE_PT_bTransformCacheConstraint_layers(BoneConstraintPanel, ConstraintButtonsSubPanel, Panel): + bl_parent_id = "BONE_PT_bTransformCacheConstraint" + bl_label = "Override Layers" + + def draw(self, context): + self.draw_transform_cache_layers(context) + + class OBJECT_PT_bTransformCacheConstraint_procedural(ObjectConstraintPanel, ConstraintButtonsSubPanel, Panel): bl_parent_id = "OBJECT_PT_bTransformCacheConstraint" bl_label = "Render Procedural" @@ -1695,6 +1716,7 @@ classes = ( OBJECT_PT_bTransformCacheConstraint_time, OBJECT_PT_bTransformCacheConstraint_procedural, OBJECT_PT_bTransformCacheConstraint_velocity, + OBJECT_PT_bTransformCacheConstraint_layers, OBJECT_PT_bPythonConstraint, OBJECT_PT_bArmatureConstraint, OBJECT_PT_bArmatureConstraint_bones, @@ -1735,6 +1757,7 @@ classes = ( BONE_PT_bTransformCacheConstraint_time, BONE_PT_bTransformCacheConstraint_procedural, BONE_PT_bTransformCacheConstraint_velocity, + BONE_PT_bTransformCacheConstraint_layers, BONE_PT_bPythonConstraint, BONE_PT_bArmatureConstraint, BONE_PT_bArmatureConstraint_bones, diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py index 4c9d254dd81..b19bd65e977 100644 --- a/release/scripts/startup/bl_ui/properties_data_mesh.py +++ b/release/scripts/startup/bl_ui/properties_data_mesh.py @@ -76,6 +76,14 @@ class MESH_MT_shape_key_context_menu(Menu): layout.operator("object.shape_key_move", icon='TRIA_UP_BAR', text="Move to Top").type = 'TOP' layout.operator("object.shape_key_move", icon='TRIA_DOWN_BAR', text="Move to Bottom").type = 'BOTTOM' +class MESH_MT_attribute_context_menu(Menu): + bl_label = "Attribute Specials" + + def draw(self, context): + layout = self.layout + + layout.operator("geometry.attribute_convert") + class MESH_UL_vgroups(UIList): def draw_item(self, _context, layout, _data, item, icon, _active_data_, _active_propname, _index): @@ -601,6 +609,7 @@ class DATA_PT_customdata(MeshButtonsPanel, Panel): col.enabled = obj is not None and obj.mode != 'EDIT' col.prop(me, "use_customdata_vertex_bevel", text="Vertex Bevel Weight") col.prop(me, "use_customdata_edge_bevel", text="Edge Bevel Weight") + col.prop(me, "use_customdata_vertex_crease", text="Vertex Crease") col.prop(me, "use_customdata_edge_crease", text="Edge Crease") @@ -670,11 +679,9 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel): col.operator("geometry.attribute_add", icon='ADD', text="") col.operator("geometry.attribute_remove", icon='REMOVE', text="") - active = mesh.attributes.active - - if active and (active.domain == "POINT" and active.data_type == "FLOAT_COLOR"): - layout.operator("sculpt.vertex_to_loop_colors", text="Save To Corners") - layout.operator("sculpt.loop_to_vertex_colors", text="Load From Corners") + col.separator() + + col.menu("MESH_MT_attribute_context_menu", icon='DOWNARROW_HLT', text="") self.draw_attribute_warnings(context, layout) @@ -712,6 +719,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel): classes = (MESH_MT_vertex_group_context_menu, MESH_MT_shape_key_context_menu, + MESH_MT_attribute_context_menu, MESH_UL_vgroups, MESH_UL_fmaps, MESH_UL_shape_keys, diff --git a/release/scripts/startup/bl_ui/properties_object.py b/release/scripts/startup/bl_ui/properties_object.py index 81a641a20cf..fbd4ed3225a 100644 --- a/release/scripts/startup/bl_ui/properties_object.py +++ b/release/scripts/startup/bl_ui/properties_object.py @@ -184,24 +184,18 @@ class OBJECT_PT_collections(ObjectButtonsPanel, Panel): row.operator("object.collection_add", text="Add to Collection") row.operator("object.collection_add", text="", icon='ADD') - obj_name = obj.name - for collection in bpy.data.collections: - # XXX this is slow and stupid!, we need 2 checks, one that's fast - # and another that we can be sure its not a name collision - # from linked library data - collection_objects = collection.objects - if obj_name in collection.objects and obj in collection_objects[:]: - col = layout.column(align=True) + for collection in obj.users_collection: + col = layout.column(align=True) - col.context_pointer_set("collection", collection) + col.context_pointer_set("collection", collection) - row = col.box().row() - row.prop(collection, "name", text="") - row.operator("object.collection_remove", text="", icon='X', emboss=False) - row.menu("COLLECTION_MT_context_menu", icon='DOWNARROW_HLT', text="") + row = col.box().row() + row.prop(collection, "name", text="") + row.operator("object.collection_remove", text="", icon='X', emboss=False) + row.menu("COLLECTION_MT_context_menu", icon='DOWNARROW_HLT', text="") - row = col.box().row() - row.prop(collection, "instance_offset", text="") + row = col.box().row() + row.prop(collection, "instance_offset", text="") class OBJECT_PT_display(ObjectButtonsPanel, Panel): diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index 5a611985a4d..b6e8778371c 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -2374,8 +2374,13 @@ def brush_basic_texpaint_settings(layout, context, brush, *, compact=False): capabilities = brush.image_paint_capabilities if capabilities.has_color: - UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text="") - if context.mode != "SCULT": + row = layout.row(align=True) + row.ui_units_x = 4 + UnifiedPaintPanel.prop_unified_color(row, context, brush, "color", text="") + UnifiedPaintPanel.prop_unified_color(row, context, brush, "secondary_color", text="") + row.separator() + + if context.mode != "SCULPT": layout.prop(brush, "blend", text="" if compact else "Blend") else: UnifiedPaintPanel.channel_unified(layout, diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 7eaebbcfc8c..80be31fd282 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -2249,6 +2249,7 @@ class USERPREF_PT_experimental_debugging(ExperimentalPanel, Panel): ({"property": "use_cycles_debug"}, None), ({"property": "use_geometry_nodes_legacy"}, "T91274"), ({"property": "show_asset_debug_info"}, None), + ({"property": "use_asset_indexing"}, None), ), ) diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 8ea90179a93..7228a40f9d7 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -4079,6 +4079,10 @@ class VIEW3D_MT_edit_mesh_vertices(Menu): layout.separator() + layout.operator("transform.vert_crease") + + layout.separator() + layout.operator("mesh.blend_from_shape") layout.operator("mesh.shape_propagate_to_all", text="Propagate to Shapes") diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index f6ca200f570..b8099127a55 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -142,6 +142,7 @@ def mesh_node_items(context): yield NodeItemCustom(draw=lambda self, layout, context: layout.separator()) yield NodeItem("GeometryNodeDualMesh") + yield NodeItem("GeometryNodeFlipFaces") yield NodeItem("GeometryNodeMeshBoolean") yield NodeItem("GeometryNodeMeshToCurve") yield NodeItem("GeometryNodeMeshToPoints") @@ -149,6 +150,7 @@ def mesh_node_items(context): yield NodeItem("GeometryNodeSubdivideMesh") yield NodeItem("GeometryNodeSubdivisionSurface") yield NodeItem("GeometryNodeTriangulate") + yield NodeItem("GeometryNodeScaleElements") yield NodeItemCustom(draw=lambda self, layout, context: layout.separator()) yield NodeItem("GeometryNodeInputMeshEdgeAngle") yield NodeItem("GeometryNodeInputMeshEdgeNeighbors") @@ -704,6 +706,7 @@ geometry_node_categories = [ NodeItem("GeometryNodeCurvePrimitiveCircle"), NodeItem("GeometryNodeCurveStar"), NodeItem("GeometryNodeCurveSpiral"), + NodeItem("GeometryNodeCurveArc"), NodeItem("GeometryNodeCurveQuadraticBezier"), NodeItem("GeometryNodeCurvePrimitiveQuadrilateral"), NodeItem("GeometryNodeCurvePrimitiveBezierSegment"), @@ -757,6 +760,7 @@ geometry_node_categories = [ ]), GeometryNodeCategory("GEO_UTILITIES", "Utilities", items=[ NodeItem("GeometryNodeAccumulateField"), + NodeItem("GeometryNodeFieldAtIndex"), NodeItem("ShaderNodeMapRange"), NodeItem("ShaderNodeFloatCurve"), NodeItem("ShaderNodeClamp"), diff --git a/source/blender/blenfont/CMakeLists.txt b/source/blender/blenfont/CMakeLists.txt index cc6e298b322..b1453b243c0 100644 --- a/source/blender/blenfont/CMakeLists.txt +++ b/source/blender/blenfont/CMakeLists.txt @@ -54,7 +54,7 @@ set(LIB bf_gpu bf_intern_guardedalloc - ${FREETYPE_LIBRARY} + ${FREETYPE_LIBRARIES} ) if(WIN32) diff --git a/source/blender/blenkernel/BKE_blendfile_link_append.h b/source/blender/blenkernel/BKE_blendfile_link_append.h index 04521cc8939..e55a2d15dcc 100644 --- a/source/blender/blenkernel/BKE_blendfile_link_append.h +++ b/source/blender/blenkernel/BKE_blendfile_link_append.h @@ -150,7 +150,7 @@ typedef enum eBlendfileLinkAppendForeachItemFlag { * * IMPORTANT: Those 'indirect' items currently may not cover **all** indirectly linked data. * See comments in #foreach_libblock_link_append_callback. */ - BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_INDIRECT = 1 << 0, + BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_INDIRECT = 1 << 1, } eBlendfileLinkAppendForeachItemFlag; /** * Callback called by #BKE_blendfile_link_append_context_item_foreach over each (or a subset of diff --git a/source/blender/blenkernel/BKE_brush_engine.h b/source/blender/blenkernel/BKE_brush_engine.h index 81ef138300d..6e92dad1274 100644 --- a/source/blender/blenkernel/BKE_brush_engine.h +++ b/source/blender/blenkernel/BKE_brush_engine.h @@ -316,8 +316,8 @@ void BKE_brush_channelset_merge(BrushChannelSet *dst, BrushChannelSet *parent); void BKE_brush_channel_apply_mapping_flags(BrushChannel *dst, - BrushChannel *child, - BrushChannel *parent); + const BrushChannel *child, + const BrushChannel *parent); bool BKE_brush_mapping_is_enabled(BrushChannel *child, BrushChannel *parent, int mapping); diff --git a/source/blender/blenkernel/BKE_brush_engine.hh b/source/blender/blenkernel/BKE_brush_engine.hh index 1d816960673..3e9dc9de1b0 100644 --- a/source/blender/blenkernel/BKE_brush_engine.hh +++ b/source/blender/blenkernel/BKE_brush_engine.hh @@ -1,129 +1,252 @@ -#include "DNA_brush_enums.h" -#include "DNA_brush_types.h" -#include "DNA_color_types.h" -#include "DNA_curveprofile_types.h" -#include "DNA_material_types.h" -#include "DNA_node_types.h" -#include "DNA_sculpt_brush_types.h" +#if 1 -#include "BLI_compiler_attrs.h" -#include "BLI_compiler_compat.h" -#include "BLI_ghash.h" -#include "BLI_listbase.h" -#include "BLI_math.h" -#include "BLI_rand.h" -#include "BLI_rect.h" -#include "BLI_smallhash.h" -#include "BLI_utildefines.h" +# include "DNA_brush_enums.h" +# include "DNA_brush_types.h" +# include "DNA_color_types.h" +# include "DNA_curveprofile_types.h" +# include "DNA_material_types.h" +# include "DNA_node_types.h" +# include "DNA_sculpt_brush_types.h" -#include "BKE_brush_engine.h" +# include "BLI_compiler_attrs.h" +# include "BLI_compiler_compat.h" +# include "BLI_ghash.h" +# include "BLI_listbase.h" +# include "BLI_math.h" +# include "BLI_rand.h" +# include "BLI_rect.h" +# include "BLI_smallhash.h" +# include "BLI_utildefines.h" -#include "BKE_brush.h" -#include "BKE_brush_engine.h" -#include "BKE_colorband.h" -#include "BKE_colortools.h" -#include "BKE_context.h" -#include "BKE_curvemapping_cache.h" -#include "BKE_curveprofile.h" -#include "BKE_lib_override.h" -#include "BKE_lib_query.h" -#include "BKE_main.h" -#include "BKE_node.h" -#include "BKE_paint.h" +# include "BKE_brush_engine.h" -#include -#include -#include +# include "BKE_brush.h" +# include "BKE_brush_engine.h" +# include "BKE_colorband.h" +# include "BKE_colortools.h" +# include "BKE_context.h" +# include "BKE_curvemapping_cache.h" +# include "BKE_curveprofile.h" +# include "BKE_lib_override.h" +# include "BKE_lib_query.h" +# include "BKE_main.h" +# include "BKE_node.h" +# include "BKE_paint.h" + +# include +# include +# include +# include +# include + +# include "intern/brush_channel_names.hh" + +# define IS_CACHE_CURVE(curve) BKE_curvemapping_in_cache(curve) +// frees curve if it wasn't cached, returns cache curved +# define GET_CACHE_CURVE(curve) BKE_curvemapping_cache_get(brush_curve_cache, curve, true) +# define RELEASE_CACHE_CURVE(curve) BKE_curvemapping_cache_release(brush_curve_cache, curve) +# define RELEASE_OR_FREE_CURVE(curve) \ + curve ? (BKE_curvemapping_cache_release_or_free(brush_curve_cache, curve), nullptr) : nullptr +# define CURVE_ADDREF(curve) BKE_curvemapping_cache_aquire(brush_curve_cache, curve) + +struct CurveMappingCache *brush_curve_cache = NULL; +extern BrushChannelType brush_builtin_channels[]; +extern int brush_builtin_channel_len; /* build compile time list of channel idnames */ +/** return eithers a reference to a brush channel type, + or if T is BrushCurve the (non-reference) BrushCurveIF wrapper type*/ +# define BRUSH_VALUE_REF(T) typename std::conditional, BrushCurveIF, T &>::type + +template struct extract_float_array { + using type = typename std::conditional, float, T>::type; +}; + namespace blender { namespace brush { +class BrushCurveIF { + public: + BrushCurveIF(BrushCurve *curve) : _curve(curve) + { + } + BrushCurveIF(const BrushCurveIF &b) + { + _curve = b._curve; + } + + float evaluate(float f, float maxval = 1.0f) + { + /* ensure that curve is in valid state */ + initCurve(false); + + return BKE_brush_curve_strength_ex(_curve->preset, _curve->curve, f, maxval); + } + + void initCurve(bool forceCreate = false) + { + if ((forceCreate || _curve->preset == BRUSH_CURVE_CUSTOM) && !_curve->curve) { + CurveMapping *cumap = _curve->curve = static_cast( + MEM_callocN(sizeof(CurveMapping), "channel CurveMapping")); + + int preset = CURVE_PRESET_LINE; + + /* brush and curvemapping presets aren't perfectly compatible, + try to convert in reasonable manner*/ + switch (_curve->preset) { + case BRUSH_CURVE_SMOOTH: + case BRUSH_CURVE_SMOOTHER: + preset = CURVE_PRESET_SMOOTH; + break; + + case BRUSH_CURVE_SHARP: + preset = CURVE_PRESET_SHARP; + break; + case BRUSH_CURVE_POW4: + preset = CURVE_PRESET_POW3; + break; + } + + struct rctf rect; + rect.xmin = rect.ymin = 0.0f; + rect.xmax = rect.ymax = 1.0f; + + BKE_curvemapping_set_defaults(cumap, 1, 0.0f, 0.0f, 1.0f, 1.0f); + BKE_curvemap_reset(cumap->cm, &rect, preset, _curve->preset_slope_negative ? 0 : 1); + + BKE_curvemapping_init(cumap); + } + } + + void ensureWrite() + { + initCurve(true); + + if (IS_CACHE_CURVE(_curve->curve)) { + _curve->curve = BKE_curvemapping_copy(_curve->curve); + } + } + + CurveMapping *curve() + { + initCurve(false); + return _curve->curve; + } + + eBrushCurvePreset &preset() + { + eBrushCurvePreset *p = reinterpret_cast(&_curve->preset); + return *p; + } + + private: + BrushCurve *_curve; +}; + template class BrushChannelIF { public: + BrushChannelIF() + { + _channel = nullptr; + } + BrushChannelIF(BrushChannel *source) : _channel(source) { } - /* evaluation functions */ - - /** int evaluator */ - std::enable_if_t::value> evaluate(BrushMappingData *mapdata = nullptr) + eBrushChannelFlag &flag() { - double val = static_cast(_channel->ivalue); + eBrushChannelFlag *f = reinterpret_cast(&_channel->flag); - val = _evaluate(val, t, 0UL, mapdata); - return static_cast(val); + return *f; } - /** float evaluator */ - std::enable_if_t::value> evaluate(BrushMappingData *mapdata = nullptr) + BrushChannelIF(const BrushChannelIF &b) { - double val = static_cast(_channel->fvalue); - - val = _evaluate(val, t, 0UL, mapdata); - return static_cast(val); + _channel = b._channel; } - /** bool evaluator */ - std::enable_if_t::value> evaluate(BrushMappingData *mapdata = nullptr) - { - double val = static_cast(_channel->fvalue); + BrushChannelIF &operator=(const BrushChannelIF &a) = default; - val = _evaluate(val, t, 0UL, mapdata); - return std::floor(val) != 0; + const BrushChannel &channel() + { + return *_channel; } - /** Curve evaluator. Unlike other channel types, this takes a float - argument, runs it through the brush curve and returns the result as - a float. - - \param t value to evaluate with brush curve - */ - std::enable_if_t< - std::conditional::value, float, std::false_type>::value> - evaluate(float t, BrushMappingData *mapdata = nullptr) + const char *idname() { - t = BKE_brush_curve_strength_ex(_channel->curve.preset, _channel->curve.curve, 1.0f - t, 1.0f); - double val = static_cast(t); - - return static_cast(_evaluate(val, t, 0UL, mapdata)); + return _channel->idname; } - /** value getter for int channels */ - std::add_lvalue_reference_t::value>> value() + const bool isValid() const { - return _channel->ivalue; + return _channel != nullptr; } - /** value getter for float channels */ - std::add_lvalue_reference_t::value>> value() + /** + Returns a reference to value of a brush channel. + + Note that if T is BrushCurve then a BrushCurveIF + wrapper will be returned instead. + + */ + BRUSH_VALUE_REF(T) value() { - return _channel->fvalue; + if constexpr (std::is_same_v) { + return _channel->fvalue; + } + else if constexpr (std::is_same_v) { + return _channel->ivalue; + } + else if constexpr (std::is_same_v) { + bool *boolval = reinterpret_cast(&_channel->ivalue); + return *boolval; + } + else if constexpr (std::is_same_v) { + return BrushCurveIF(&_channel->curve); + } + else if constexpr (std::is_same_v) { + float(*vec3)[3] = reinterpret_cast(_channel->vector); + + return vec3[0]; + } + else if constexpr (std::is_same_v) { + return _channel->vector; + } + + T ret; + return ret; } - /** value getter for bool channels */ - std::add_lvalue_reference_t::value>> value() + /* vectorIndex is only used for float[3] and float[4] specializations*/ + typename extract_float_array::type evaluate(BrushMappingData *mapping = nullptr, int vectorIndex = 0) { - return *(reinterpret_cast(&_channel->ivalue)); - } + if constexpr (std::is_same_v) { + return (float)_evaluate((double)_channel->fvalue, 0, mapping); + } + else if constexpr (std::is_same_v) { + return (int)_evaluate((double)_channel->ivalue, 0, mapping); + } + else if constexpr (std::is_same_v) { + return fabs(_evaluate((double)(_channel->ivalue & 1), 0, mapping)) > FLT_EPSILON; + } + else if constexpr (std::is_same_v || std::is_same_v) { + return (float)_evaluate((double)_channel->vector, vectorIndex, mapping); + } - /** value getter for BrushCurve channels */ - std::add_lvalue_reference_t::value>> value() - { - return _channel->curve; + static_assert(!std::is_same_v, "cannot use evaluate with brush curves"); } private: - double _evaluate(double val, float t, unsigned int idx, BrushMappingData *mapdata = nullptr) + double _evaluate(double val, unsigned int idx, BrushMappingData *mapping = nullptr) { - if (idx == 3 && !(ch->flag & BRUSH_CHANNEL_APPLY_MAPPING_TO_ALPHA)) { - return f; + if (idx == 3 && !(_channel->flag & BRUSH_CHANNEL_APPLY_MAPPING_TO_ALPHA)) { + return val; } - if (mapdata) { - double factor = f; // 1.0f; + if (mapping) { + double factor = val; for (int i = 0; i < BRUSH_MAPPING_MAX; i++) { BrushMapping *mp = _channel->mappings + i; @@ -132,7 +255,7 @@ template class BrushChannelIF { continue; } - float inputf = ((float *)mapdata)[i] * mp->premultiply; + float inputf = (reinterpret_cast(mapping))[i] * mp->premultiply; switch ((BrushMappingFunc)mp->mapfunc) { case BRUSH_MAPFUNC_NONE: @@ -191,34 +314,157 @@ template class BrushChannelIF { f2 = factor - f2; break; case MA_RAMP_DIFF: - f2 = fabsf(factor - f2); + f2 = std::abs(factor - f2); break; default: printf("Unsupported brush mapping blend mode for %s (%s); will mix instead\n", - ch->name, - ch->idname); + _channel->name, + _channel->idname); break; } factor += (f2 - factor) * mp->factor; } - f = factor; - CLAMP(f, _channel->def->min, _channel->def->max); + val = factor; + CLAMP(val, (double)_channel->def->min, (double)_channel->def->max); } - return f; + return val; } BrushChannel *_channel; }; -template class BrushChannelSetIF { +class BrushChannelSetIF { public: BrushChannelSetIF(BrushChannelSet *chset) : _chset(chset) { } + BrushChannelSetIF(const BrushChannelSetIF &b) + { + _chset = b._chset; + } + + bool isValid() + { + return _chset != nullptr; + } + + void destroy() + { + if (_chset) { + if (_chset->namemap) { + BLI_ghash_free(_chset->namemap, nullptr, nullptr); + } + + LISTBASE_FOREACH (BrushChannel *, ch, &_chset->channels) { + if (ch->curve.curve) { + RELEASE_OR_FREE_CURVE(ch->curve.curve); + } + } + + BLI_freelistN(&_chset->channels); + + MEM_SAFE_FREE(_chset); + } + _chset = nullptr; + } + + void ensureChannel(const char *idname) + { + } + + template BrushChannelIF lookup(const char *idname) + { + BrushChannel *ch = static_cast( + BLI_ghash_lookup(_chset->namemap, static_cast(idname))); + BrushChannelIF chif(ch); + + return chif; + } + + template + BRUSH_VALUE_REF(T) + getFinalValue(BrushChannelSet *parentset, + BrushChannelIF ch, + BrushMappingData *mapping = nullptr, + int vectorIndex = 0) + { + return getFinalValue(BrushChannelSetIF(parentset), ch, mapping, vectorIndex); + } + + /** + Looks up channel with same idname as ch in parentset. + If it exists, returns the evaluated value of that channel + taking all inheritance flags and input mappings into + account. + + if it doesn't exist then the value of ch with + input mappings evaluated will be returned. + + Note that if T is BrushCurve then we simply return + a BrushCurveIF wrapper of either ch or the + one in parentset, depending on inheritance flags. + */ + template + typename extract_float_array::type + getFinalValue(BrushChannelSetIF &parentSet, + BrushChannelIF ch, + BrushMappingData *mapping = nullptr, + int vectorIndex = 0) + { + BrushChannelIF ch2; + + if (parentSet.isValid()) { + ch2 = parentSet.lookup(ch.idname()); + } + + if (!parentSet.isValid() || !ch2.isValid()) { + if constexpr (std::is_same_v) { // curve? + return ch.value(); + } + else if constexpr (std::is_array_v) { + return ch.evaluate(mapping, vectorIndex); + } + } + + if constexpr (std::is_same_v) { + return (int)ch.flag() & (int)BRUSH_CHANNEL_INHERIT ? ch2.value() : ch.value(); + } + + BrushChannel _cpy = (int)ch.flag() & (int)BRUSH_CHANNEL_INHERIT ? ch2.channel() : ch.channel(); + BrushChannelIF cpy(&_cpy); + + BKE_brush_channel_apply_mapping_flags(&_cpy, &ch.channel(), &ch2.channel()); + + return cpy.evaluate(mapping, vectorIndex); + } + + /* +We want to validate channel names at compile time, +but we can't do compile-time validation of string literals +without c++20. Instead we use macros to make +lots of accessor methods. + +examples: + + BrushChannelIF strength(); + BrushChannelIF radius(); + BrushChannelIF dyntopo_disabled(); + + auto ch = chset->strength(); + BrushChanneIF ch = chset->strength(); + + if (ch->isValid()) { + float val = ch->value(); + ch->value() = val * val; + } +*/ + +# define BRUSH_CHANNEL_MAKE_CPP_LOOKUPS +# include "intern/brush_channel_define.h" private: BrushChannelSet *_chset; @@ -226,3 +472,4 @@ template class BrushChannelSetIF { } // namespace brush } // namespace blender +#endif diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h index 0ab814c2d94..c6821d88d2a 100644 --- a/source/blender/blenkernel/BKE_cachefile.h +++ b/source/blender/blenkernel/BKE_cachefile.h @@ -28,6 +28,7 @@ extern "C" { #endif struct CacheFile; +struct CacheFileLayer; struct CacheReader; struct Depsgraph; struct Main; @@ -69,6 +70,15 @@ bool BKE_cache_file_uses_render_procedural(const struct CacheFile *cache_file, struct Scene *scene, int dag_eval_mode); +/* Add a layer to the cache_file. Return NULL if the filename is already that of an existing layer + * or if the number of layers exceeds the maximum allowed layer count. */ +struct CacheFileLayer *BKE_cachefile_add_layer(struct CacheFile *cache_file, + const char filename[1024]); + +struct CacheFileLayer *BKE_cachefile_get_active_layer(struct CacheFile *cache_file); + +void BKE_cachefile_remove_layer(struct CacheFile *cache_file, struct CacheFileLayer *layer); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 5c0b6c79164..a9169777986 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -787,6 +787,14 @@ void CustomData_bmesh_asan_poison(const CustomData *data, void *block); void CustomData_bmesh_asan_unpoison(const CustomData *data, void *block); int CustomData_get_named_offset(const CustomData *data, int type, const char *name); +#ifndef NDEBUG +struct DynStr; +/** Use to inspect mesh data when debugging. */ +void CustomData_debug_info_from_layers(const struct CustomData *data, + const char *indent, + struct DynStr *dynstr); +#endif /* NDEBUG */ + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index b7f675e4e97..4c6eb31db4b 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -406,6 +406,13 @@ int set_listbasepointers(struct Main *main, struct ListBase *lb[]); ((main)->versionfile < (ver) || \ ((main)->versionfile == (ver) && (main)->subversionfile < (subver))) +/** + * The size of thumbnails (optionally) stored in the `.blend` files header. + * + * NOTE(@campbellbarton): This is kept small as it's stored uncompressed in the `.blend` file, + * where a larger size would increase the size of every `.blend` file unreasonably. + * If we wanted to increase the size, we'd want to use compression (JPEG or similar). + */ #define BLEN_THUMB_SIZE 128 #define BLEN_THUMB_MEMSIZE(_x, _y) \ diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 2c9615e8242..15ebe724c52 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -25,6 +25,7 @@ #include "BKE_attribute.h" #include "BKE_customdata.h" #include "BKE_mesh_types.h" +#include "BLI_compiler_attrs.h" #include "BLI_utildefines.h" struct BLI_Stack; @@ -1041,6 +1042,13 @@ void BKE_mesh_batch_cache_free(struct Mesh *me); extern void (*BKE_mesh_batch_cache_dirty_tag_cb)(struct Mesh *me, eMeshBatchDirtyMode mode); extern void (*BKE_mesh_batch_cache_free_cb)(struct Mesh *me); +/* mesh_debug.c */ +#ifndef NDEBUG +char *BKE_mesh_debug_info(const struct Mesh *me) + ATTR_NONNULL(1) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +void BKE_mesh_debug_print(const struct Mesh *me) ATTR_NONNULL(1); +#endif + /* Inlines */ /* NOTE(@sybren): Instead of -1 that function uses ORIGINDEX_NONE as defined in BKE_customdata.h, diff --git a/source/blender/blenkernel/BKE_mesh_runtime.h b/source/blender/blenkernel/BKE_mesh_runtime.h index 5069fad6bb7..ad86f6d8f25 100644 --- a/source/blender/blenkernel/BKE_mesh_runtime.h +++ b/source/blender/blenkernel/BKE_mesh_runtime.h @@ -116,10 +116,6 @@ void BKE_mesh_runtime_eval_to_meshkey(struct Mesh *me_deformed, struct KeyBlock *kb); #ifndef NDEBUG -char *BKE_mesh_runtime_debug_info(struct Mesh *me_eval); -void BKE_mesh_runtime_debug_print(struct Mesh *me_eval); -/* XXX Should go in customdata file? */ -void BKE_mesh_runtime_debug_print_cdlayers(struct CustomData *data); bool BKE_mesh_runtime_is_valid(struct Mesh *me_eval); #endif /* NDEBUG */ diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index a76fe2f83e0..3b952204755 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1628,6 +1628,10 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_INPUT_SCENE_TIME 1145 #define GEO_NODE_ACCUMULATE_FIELD 1146 #define GEO_NODE_INPUT_MESH_EDGE_ANGLE 1147 +#define GEO_NODE_FIELD_AT_INDEX 1148 +#define GEO_NODE_CURVE_PRIMITIVE_ARC 1149 +#define GEO_NODE_FLIP_FACES 1150 +#define GEO_NODE_SCALE_ELEMENTS 1151 /** \} */ diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h index 0237661cd16..697b3e9ace7 100644 --- a/source/blender/blenkernel/BKE_subdiv.h +++ b/source/blender/blenkernel/BKE_subdiv.h @@ -306,8 +306,8 @@ BLI_INLINE void BKE_subdiv_rotate_grid_to_quad( int corner, float grid_u, float grid_v, float *r_quad_u, float *r_quad_v); /* Convert Blender edge crease value to OpenSubdiv sharpness. */ -BLI_INLINE float BKE_subdiv_edge_crease_to_sharpness_f(float edge_crease); -BLI_INLINE float BKE_subdiv_edge_crease_to_sharpness_char(char edge_crease); +BLI_INLINE float BKE_subdiv_crease_to_sharpness_f(float edge_crease); +BLI_INLINE float BKE_subdiv_crease_to_sharpness_char(char edge_crease); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_subdiv_modifier.h b/source/blender/blenkernel/BKE_subdiv_modifier.h index e8672b6baa8..8a179206dd7 100644 --- a/source/blender/blenkernel/BKE_subdiv_modifier.h +++ b/source/blender/blenkernel/BKE_subdiv_modifier.h @@ -40,8 +40,10 @@ void BKE_subsurf_modifier_subdiv_settings_init(struct SubdivSettings *settings, const struct SubsurfModifierData *smd, bool use_render_params); -/* If skip_check_is_last is true, we assume that the modifier passed is the last enabled modifier - * in the stack. */ +/** + * \param skip_check_is_last: When true, we assume that the modifier passed is the last enabled + * modifier in the stack. + */ bool BKE_subsurf_modifier_can_do_gpu_subdiv_ex(const struct Scene *scene, const struct Object *ob, const struct SubsurfModifierData *smd, @@ -54,6 +56,10 @@ bool BKE_subsurf_modifier_can_do_gpu_subdiv(const struct Scene *scene, extern void (*BKE_subsurf_modifier_free_gpu_cache_cb)(struct Subdiv *subdiv); +/** + * Main goal of this function is to give usable subdivision surface descriptor + * which matches settings and topology. + */ struct Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure( const struct SubsurfModifierData *smd, const struct SubdivSettings *subdiv_settings, @@ -62,8 +68,10 @@ struct Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure( struct SubsurfRuntimeData *BKE_subsurf_modifier_ensure_runtime(struct SubsurfModifierData *smd); -/* Return the #ModifierMode required for the evaluation of the subsurf modifier, which should be - * used to check if the modifier is enabled. */ +/** + * Return the #ModifierMode required for the evaluation of the subsurf modifier, + * which should be used to check if the modifier is enabled. + */ int BKE_subsurf_modifier_eval_required_mode(bool is_final_render, bool is_edit_mode); #ifdef __cplusplus diff --git a/source/blender/blenkernel/BKE_volume.h b/source/blender/blenkernel/BKE_volume.h index b40facc3572..8b42de7303d 100644 --- a/source/blender/blenkernel/BKE_volume.h +++ b/source/blender/blenkernel/BKE_volume.h @@ -181,6 +181,11 @@ bool BKE_volume_grid_bounds(openvdb::GridBase::ConstPtr grid, blender::float3 &r_min, blender::float3 &r_max); +/** + * Return a new grid pointer with only the metadata and transform changed. + * This is useful for instances, where there is a separate transform on top of the original + * grid transform that must be applied for some operations that only take a grid argument. + */ openvdb::GridBase::ConstPtr BKE_volume_grid_shallow_transform(openvdb::GridBase::ConstPtr grid, const blender::float4x4 &transform); diff --git a/source/blender/blenkernel/BKE_volume_to_mesh.hh b/source/blender/blenkernel/BKE_volume_to_mesh.hh index b99ae625042..123cb33f24f 100644 --- a/source/blender/blenkernel/BKE_volume_to_mesh.hh +++ b/source/blender/blenkernel/BKE_volume_to_mesh.hh @@ -56,11 +56,20 @@ struct Mesh *volume_to_mesh(const openvdb::GridBase &grid, float threshold, float adaptivity); +/** + * Convert an OpenVDB volume grid to corresponding mesh data: vertex positions and quad and + * triangle indices. + */ struct OpenVDBMeshData volume_to_mesh_data(const openvdb::GridBase &grid, const VolumeToMeshResolution &resolution, float threshold, float adaptivity); +/** + * Convert mesh data from the format provided by OpenVDB into Blender's #Mesh data structure. + * This can be used to add mesh data from a grid into an existing mesh rather than merging multiple + * meshes later on. + */ void fill_mesh_from_openvdb_data(const Span vdb_verts, const Span vdb_tris, const Span vdb_quads, diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 0762c88084e..a675e5d4d53 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -108,6 +108,7 @@ set(SRC intern/bpath.c intern/brush.c intern/brush_channel_define.h + intern/brush_channel_define_header.h intern/brush_engine.c intern/brush_engine.cc intern/brush_engine_presets.c @@ -169,6 +170,8 @@ set(SRC intern/icons.cc intern/icons_rasterize.c intern/idprop.c + intern/idprop_create.cc + intern/idprop_serialize.cc intern/idprop_utils.c intern/idtype.c intern/image.c @@ -204,6 +207,7 @@ set(SRC intern/mesh.cc intern/mesh_boolean_convert.cc intern/mesh_convert.cc + intern/mesh_debug.cc intern/mesh_evaluate.cc intern/mesh_fair.cc intern/mesh_iterators.c @@ -393,6 +397,7 @@ set(SRC BKE_hair.h BKE_icons.h BKE_idprop.h + BKE_idprop.hh BKE_idtype.h BKE_image.h BKE_image_save.h @@ -484,7 +489,7 @@ set(SRC BKE_workspace.h BKE_world.h BKE_writeavi.h - intern/brush_channel_names.h + intern/brush_channel_names.hh BKE_brush_engine.h BKE_brush_engine.hh @@ -533,7 +538,7 @@ set(LIB bf_simulation # For `vfontdata_freetype.c`. - ${FREETYPE_LIBRARY} + ${FREETYPE_LIBRARIES} ) if(WITH_BINRELOC) @@ -841,9 +846,11 @@ if(WITH_GTESTS) intern/bpath_test.cc intern/cryptomatte_test.cc intern/fcurve_test.cc + intern/idprop_serialize_test.cc intern/lattice_deform_test.cc intern/layer_test.cc intern/lib_id_test.cc + intern/lib_remap_test.cc intern/tracking_test.cc ) set(TEST_INC diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index ff8c05110b8..5704ef6e42f 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1356,9 +1356,12 @@ static void ease_handle_axis(const float deriv1[3], const float deriv2[3], float copy_v3_v3(r_axis, deriv1); - float len1 = len_squared_v3(deriv1), len2 = len_squared_v3(deriv2); - float ratio = len1 / len2; - + const float len2 = len_squared_v3(deriv2); + if (UNLIKELY(len2 == 0.0f)) { + return; + } + const float len1 = len_squared_v3(deriv1); + const float ratio = len1 / len2; if (ratio < gap * gap) { madd_v3_v3fl(r_axis, deriv2, gap - sqrtf(ratio)); } diff --git a/source/blender/blenkernel/intern/bassrelief.cc b/source/blender/blenkernel/intern/bassrelief.cc index cad07f65254..377f8c6e6b0 100644 --- a/source/blender/blenkernel/intern/bassrelief.cc +++ b/source/blender/blenkernel/intern/bassrelief.cc @@ -174,7 +174,7 @@ struct ReliefOptimizer { /* copy mlooptri in case it's later freed */ - mlooptri = new MLoopTri[totlooptri]; + mlooptri = new MLoopTri[(uint)totlooptri]; for (int i = 0; i < totlooptri; i++) { mlooptri[i] = _mlooptri[i]; } @@ -184,7 +184,7 @@ struct ReliefOptimizer { } arena = BLI_memarena_new(1024 * 32, "relief optimizer arena"); - verts = new ReliefVertex[totvert]; + verts = new ReliefVertex[(uint)totvert]; compress_ratio = 0.5f; const MVert *mv = mvert_; diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c index 169a410bccc..9b3f4c2fae8 100644 --- a/source/blender/blenkernel/intern/blendfile_link_append.c +++ b/source/blender/blenkernel/intern/blendfile_link_append.c @@ -681,21 +681,25 @@ static void loose_data_instantiate_collection_process( Collection *collection = (Collection *)id; bool do_add_collection = (id->tag & LIB_TAG_DOIT) != 0; + if (!do_add_collection) { + continue; + } /* When instantiated into view-layer, do not add collections if one of their parents is also - * instantiated. In case of empty-instantiation though, instantiation of all user-selected - * collections is the desired behavior. */ - if (!do_add_collection || - (!do_instantiate_as_empty && - loose_data_instantiate_collection_parents_check_recursive(collection))) { + * instantiated. */ + if (!do_instantiate_as_empty && + loose_data_instantiate_collection_parents_check_recursive(collection)) { + continue; + } + /* When instantiated as empty, do not add indirectly linked (i.e. non-user-selected) + * collections. */ + if (do_instantiate_as_empty && (item->tag & LINK_APPEND_TAG_INDIRECT) != 0) { continue; } loose_data_instantiate_ensure_active_collection(instantiate_context); Collection *active_collection = instantiate_context->active_collection; - /* In case user requested instantiation of collections as empties, do so for the one they - * explicitly selected (originally directly linked IDs) only. */ - if (do_instantiate_as_empty && (item->tag & LINK_APPEND_TAG_INDIRECT) == 0) { + if (do_instantiate_as_empty) { /* BKE_object_add(...) messes with the selection. */ Object *ob = BKE_object_add_only_object(bmain, OB_EMPTY, collection->id.name + 2); ob->type = OB_EMPTY; diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index 44ef3ec96ff..a1570b4e031 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -237,7 +237,7 @@ void BKE_bpath_missing_files_check(Main *bmain, ReportList *reports) .bmain = bmain, .callback_function = check_missing_files_foreach_path_cb, .flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_SKIP_PACKED | - BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN, + BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN | BKE_BPATH_TRAVERSE_SKIP_WEAK_REFERENCES, .user_data = reports}); } diff --git a/source/blender/blenkernel/intern/brush_channel_define.h b/source/blender/blenkernel/intern/brush_channel_define.h index ed6aa2a8b6a..ef6009a954e 100644 --- a/source/blender/blenkernel/intern/brush_channel_define.h +++ b/source/blender/blenkernel/intern/brush_channel_define.h @@ -13,112 +13,7 @@ places in rna_engine_codebase are relevent: */ -/* static name checking stuff */ -#if defined(BRUSH_CHANNEL_DEFINE_TYPES) || defined(BRUSH_CHANNEL_DEFINE_EXTERNAL) || \ - defined(BRUSH_CHANNEL_MAKE_NAMES) -# ifdef MAKE_FLOAT -# undef MAKE_FLOAT -# endif -# ifdef MAKE_FLOAT_EX -# undef MAKE_FLOAT_EX -# endif -# ifdef MAKE_FLOAT_EX_EX -# undef MAKE_FLOAT_EX_EX -# endif -# ifdef MAKE_FLOAT_EX_INV -# undef MAKE_FLOAT_EX_INV -# endif -# ifdef MAKE_FLOAT3 -# undef MAKE_FLOAT3 -# endif -# ifdef MAKE_FLOAT3_EX -# undef MAKE_FLOAT3_EX -# endif -# ifdef MAKE_INT -# undef MAKE_INT -# endif -# ifdef MAKE_INT_EX -# undef MAKE_INT_EX -# endif -# ifdef MAKE_COLOR3 -# undef MAKE_COLOR3 -# endif -# ifdef MAKE_COLOR4 -# undef MAKE_COLOR4 -# endif -# ifdef MAKE_BOOL -# undef MAKE_BOOL -# endif -# ifdef MAKE_BOOL_EX -# undef MAKE_BOOL_EX -# endif -# ifdef MAKE_ENUM -# undef MAKE_ENUM -# endif -# ifdef MAKE_FLAGS -# undef MAKE_FLAGS -# endif -# ifdef MAKE_ENUM_EX -# undef MAKE_ENUM_EX -# endif -# ifdef MAKE_FLAGS_EX -# undef MAKE_FLAGS_EX -# endif -# ifdef MAKE_CURVE -# undef MAKE_CURVE -# endif -# ifdef MAKE_CURVE_EX -# undef MAKE_CURVE_EX -# endif - -# ifdef MAKE_BUILTIN_CH_DEF -# undef MAKE_BUILTIN_CH_DEF -# endif -# ifdef MAKE_FLOAT_EX_FLAG -# undef MAKE_FLOAT_EX_FLAG -# endif - -# ifdef BRUSH_CHANNEL_DEFINE_TYPES -# define MAKE_BUILTIN_CH_DEF(idname) const char *BRUSH_BUILTIN_##idname = # idname; -# elif BRUSH_CHANNEL_MAKE_NAMES -# define MAKE_BUILTIN_CH_DEF(idname) #idname, -# else -# define MAKE_BUILTIN_CH_DEF(idname) extern const char *BRUSH_BUILTIN_##idname; -# endif - -# define MAKE_FLOAT_EX(idname, name, tooltip, val, min, max, smin, smax, pressure_enabled) \ - MAKE_BUILTIN_CH_DEF(idname) -# define MAKE_FLOAT_EX_FLAG( \ - idname, name, tooltip, val, min, max, smin, smax, pressure_enabled, flag) \ - MAKE_BUILTIN_CH_DEF(idname) - -# define MAKE_FLOAT_EX_INV(idname, name, tooltip, val, min, max, smin, smax, pressure_enabled) \ - MAKE_BUILTIN_CH_DEF(idname) -# define MAKE_FLOAT_EX_EX( \ - idname, name, tooltip, val, min, max, smin, smax, pressure_enabled, inv, flag) \ - MAKE_BUILTIN_CH_DEF(idname) -# define MAKE_FLOAT(idname, name, tooltip, val, min, max) MAKE_BUILTIN_CH_DEF(idname); -# define MAKE_INT_EX(idname, name, tooltip, val, min, max, smin, smax) \ - MAKE_BUILTIN_CH_DEF(idname); -# define MAKE_INT(idname, name, tooltip, val, min, max) MAKE_BUILTIN_CH_DEF(idname); -# define MAKE_BOOL(idname, name, tooltip, val) MAKE_BUILTIN_CH_DEF(idname); -# define MAKE_BOOL_EX(idname, name, tooltip, val, flag) MAKE_BUILTIN_CH_DEF(idname); -# define MAKE_COLOR3(idname, name, tooltip, r, g, b) MAKE_BUILTIN_CH_DEF(idname); -# define MAKE_COLOR4(idname, name, tooltip, r, g, b, a) MAKE_BUILTIN_CH_DEF(idname); -# define MAKE_FLOAT3(idname, name, tooltip, x, y, z, min, max) MAKE_BUILTIN_CH_DEF(idname); -# define MAKE_FLOAT3_EX(idname, name, tooltip, x, y, z, min, max, smin, smax, flag) \ - MAKE_BUILTIN_CH_DEF(idname); -# define MAKE_ENUM(idname1, name1, tooltip1, value1, enumdef1, ...) MAKE_BUILTIN_CH_DEF(idname1); -# define MAKE_ENUM_EX(idname1, name1, tooltip1, value1, flag1, enumdef1, ...) \ - MAKE_BUILTIN_CH_DEF(idname1); -# define MAKE_FLAGS(idname1, name1, tooltip1, value1, enumdef1, ...) MAKE_BUILTIN_CH_DEF(idname1); -# define MAKE_FLAGS_EX(idname1, name1, tooltip1, value1, flag1, enumdef1, ...) \ - MAKE_BUILTIN_CH_DEF(idname1); -# define MAKE_CURVE(idname1, name1, tooltip1, preset1) MAKE_BUILTIN_CH_DEF(idname1); -# define MAKE_CURVE_EX(idname1, name1, tooltip1, preset1, flag, preset_slope_neg) \ - MAKE_BUILTIN_CH_DEF(idname1); -#else -#endif +#include "brush_channel_define_header.h" /* clang-format off */ MAKE_FLOAT_EX(radius,"Radius","Radius of the brush in pixels",50.0f,0.5f,MAX_BRUSH_PIXEL_RADIUS * 10,0.5,MAX_BRUSH_PIXEL_RADIUS,false) diff --git a/source/blender/blenkernel/intern/brush_channel_define_header.h b/source/blender/blenkernel/intern/brush_channel_define_header.h new file mode 100644 index 00000000000..ac839e693c8 --- /dev/null +++ b/source/blender/blenkernel/intern/brush_channel_define_header.h @@ -0,0 +1,163 @@ +/* check if we need to undef various macros */ + +#if defined(BRUSH_CHANNEL_MAKE_CPP_LOOKUPS) || defined(BRUSH_CHANNEL_DEFINE_TYPES) || \ + defined(BRUSH_CHANNEL_DEFINE_EXTERNAL) || defined(BRUSH_CHANNEL_MAKE_NAMES) +# ifdef MAKE_FLOAT +# undef MAKE_FLOAT +# endif +# ifdef MAKE_FLOAT_EX +# undef MAKE_FLOAT_EX +# endif +# ifdef MAKE_FLOAT_EX_EX +# undef MAKE_FLOAT_EX_EX +# endif +# ifdef MAKE_FLOAT_EX_INV +# undef MAKE_FLOAT_EX_INV +# endif +# ifdef MAKE_FLOAT3 +# undef MAKE_FLOAT3 +# endif +# ifdef MAKE_FLOAT3_EX +# undef MAKE_FLOAT3_EX +# endif +# ifdef MAKE_INT +# undef MAKE_INT +# endif +# ifdef MAKE_INT_EX +# undef MAKE_INT_EX +# endif +# ifdef MAKE_COLOR3 +# undef MAKE_COLOR3 +# endif +# ifdef MAKE_COLOR4 +# undef MAKE_COLOR4 +# endif +# ifdef MAKE_BOOL +# undef MAKE_BOOL +# endif +# ifdef MAKE_BOOL_EX +# undef MAKE_BOOL_EX +# endif +# ifdef MAKE_ENUM +# undef MAKE_ENUM +# endif +# ifdef MAKE_FLAGS +# undef MAKE_FLAGS +# endif +# ifdef MAKE_ENUM_EX +# undef MAKE_ENUM_EX +# endif +# ifdef MAKE_FLAGS_EX +# undef MAKE_FLAGS_EX +# endif +# ifdef MAKE_CURVE +# undef MAKE_CURVE +# endif +# ifdef MAKE_CURVE_EX +# undef MAKE_CURVE_EX +# endif + +# ifdef MAKE_BUILTIN_CH_DEF +# undef MAKE_BUILTIN_CH_DEF +# endif +# ifdef MAKE_FLOAT_EX_FLAG +# undef MAKE_FLOAT_EX_FLAG +# endif + +# ifdef MAKE_BUILTIN_CH_DEF +# undef MAKE_BUILTIN_CH_DEF +# endif +#endif + +#ifdef BRUSH_CHANNEL_MAKE_CPP_LOOKUPS + +# define MAKE_BUILTIN_CH_DEF(idname, type) \ + BrushChannelIF idname() \ + { \ + return lookup(#idname); \ + } + +// BrushChannel *ch = lookup(#idname); \ +// return BrushChannelIF(ch); \ +// } + +# define MAKE_FLOAT_EX(idname, name, tooltip, val, min, max, smin, smax, pressure_enabled) \ + MAKE_BUILTIN_CH_DEF(idname, float) +# define MAKE_FLOAT_EX_FLAG( \ + idname, name, tooltip, val, min, max, smin, smax, pressure_enabled, flag) \ + MAKE_BUILTIN_CH_DEF(idname, float) + +# define MAKE_FLOAT_EX_INV(idname, name, tooltip, val, min, max, smin, smax, pressure_enabled) \ + MAKE_BUILTIN_CH_DEF(idname, float) +# define MAKE_FLOAT_EX_EX( \ + idname, name, tooltip, val, min, max, smin, smax, pressure_enabled, inv, flag) \ + MAKE_BUILTIN_CH_DEF(idname, float) +# define MAKE_FLOAT(idname, name, tooltip, val, min, max) MAKE_BUILTIN_CH_DEF(idname, float); + +# define MAKE_INT_EX(idname, name, tooltip, val, min, max, smin, smax) \ + MAKE_BUILTIN_CH_DEF(idname, int); +# define MAKE_INT(idname, name, tooltip, val, min, max) MAKE_BUILTIN_CH_DEF(idname, int); +# define MAKE_BOOL(idname, name, tooltip, val) MAKE_BUILTIN_CH_DEF(idname, bool); +# define MAKE_BOOL_EX(idname, name, tooltip, val, flag) MAKE_BUILTIN_CH_DEF(idname, bool); +# define MAKE_COLOR3(idname, name, tooltip, r, g, b) MAKE_BUILTIN_CH_DEF(idname, float[3]); +# define MAKE_COLOR4(idname, name, tooltip, r, g, b, a) MAKE_BUILTIN_CH_DEF(idname, float[4]); +# define MAKE_FLOAT3(idname, name, tooltip, x, y, z, min, max) \ + MAKE_BUILTIN_CH_DEF(idname, float[3]); +# define MAKE_FLOAT3_EX(idname, name, tooltip, x, y, z, min, max, smin, smax, flag) \ + MAKE_BUILTIN_CH_DEF(idname, float[3]); +# define MAKE_ENUM(idname1, name1, tooltip1, value1, enumdef1, ...) \ + MAKE_BUILTIN_CH_DEF(idname1, int); +# define MAKE_ENUM_EX(idname1, name1, tooltip1, value1, flag1, enumdef1, ...) \ + MAKE_BUILTIN_CH_DEF(idname1, int); +# define MAKE_FLAGS(idname1, name1, tooltip1, value1, enumdef1, ...) \ + MAKE_BUILTIN_CH_DEF(idname1, int); +# define MAKE_FLAGS_EX(idname1, name1, tooltip1, value1, flag1, enumdef1, ...) \ + MAKE_BUILTIN_CH_DEF(idname1, int); +# define MAKE_CURVE(idname1, name1, tooltip1, preset1) MAKE_BUILTIN_CH_DEF(idname1, BrushCurve); +# define MAKE_CURVE_EX(idname1, name1, tooltip1, preset1, flag, preset_slope_neg) \ + MAKE_BUILTIN_CH_DEF(idname1, BrushCurve); + +/* static name checking stuff */ +#elif defined(BRUSH_CHANNEL_DEFINE_TYPES) || defined(BRUSH_CHANNEL_DEFINE_EXTERNAL) || \ + defined(BRUSH_CHANNEL_MAKE_NAMES) + +# ifdef BRUSH_CHANNEL_DEFINE_TYPES +# define MAKE_BUILTIN_CH_DEF(idname) const char *BRUSH_BUILTIN_##idname = # idname; +# elif defined(BRUSH_CHANNEL_MAKE_NAMES) +# define MAKE_BUILTIN_CH_DEF(idname) # idname, +# else +# define MAKE_BUILTIN_CH_DEF(idname) extern const char *BRUSH_BUILTIN_##idname; +# endif + +# define MAKE_FLOAT_EX(idname, name, tooltip, val, min, max, smin, smax, pressure_enabled) \ + MAKE_BUILTIN_CH_DEF(idname) +# define MAKE_FLOAT_EX_FLAG( \ + idname, name, tooltip, val, min, max, smin, smax, pressure_enabled, flag) \ + MAKE_BUILTIN_CH_DEF(idname) + +# define MAKE_FLOAT_EX_INV(idname, name, tooltip, val, min, max, smin, smax, pressure_enabled) \ + MAKE_BUILTIN_CH_DEF(idname) +# define MAKE_FLOAT_EX_EX( \ + idname, name, tooltip, val, min, max, smin, smax, pressure_enabled, inv, flag) \ + MAKE_BUILTIN_CH_DEF(idname) +# define MAKE_FLOAT(idname, name, tooltip, val, min, max) MAKE_BUILTIN_CH_DEF(idname) +# define MAKE_INT_EX(idname, name, tooltip, val, min, max, smin, smax) MAKE_BUILTIN_CH_DEF(idname) +# define MAKE_INT(idname, name, tooltip, val, min, max) MAKE_BUILTIN_CH_DEF(idname) +# define MAKE_BOOL(idname, name, tooltip, val) MAKE_BUILTIN_CH_DEF(idname) +# define MAKE_BOOL_EX(idname, name, tooltip, val, flag) MAKE_BUILTIN_CH_DEF(idname) +# define MAKE_COLOR3(idname, name, tooltip, r, g, b) MAKE_BUILTIN_CH_DEF(idname) +# define MAKE_COLOR4(idname, name, tooltip, r, g, b, a) MAKE_BUILTIN_CH_DEF(idname) +# define MAKE_FLOAT3(idname, name, tooltip, x, y, z, min, max) MAKE_BUILTIN_CH_DEF(idname) +# define MAKE_FLOAT3_EX(idname, name, tooltip, x, y, z, min, max, smin, smax, flag) \ + MAKE_BUILTIN_CH_DEF(idname) +# define MAKE_ENUM(idname1, name1, tooltip1, value1, enumdef1, ...) MAKE_BUILTIN_CH_DEF(idname1) +# define MAKE_ENUM_EX(idname1, name1, tooltip1, value1, flag1, enumdef1, ...) \ + MAKE_BUILTIN_CH_DEF(idname1) +# define MAKE_FLAGS(idname1, name1, tooltip1, value1, enumdef1, ...) MAKE_BUILTIN_CH_DEF(idname1) +# define MAKE_FLAGS_EX(idname1, name1, tooltip1, value1, flag1, enumdef1, ...) \ + MAKE_BUILTIN_CH_DEF(idname1) +# define MAKE_CURVE(idname1, name1, tooltip1, preset1) MAKE_BUILTIN_CH_DEF(idname1) +# define MAKE_CURVE_EX(idname1, name1, tooltip1, preset1, flag, preset_slope_neg) \ + MAKE_BUILTIN_CH_DEF(idname1) +#else +#endif diff --git a/source/blender/blenkernel/intern/brush_channel_names.hh b/source/blender/blenkernel/intern/brush_channel_names.hh index 1b47e092346..b292c7b40c5 100644 --- a/source/blender/blenkernel/intern/brush_channel_names.hh +++ b/source/blender/blenkernel/intern/brush_channel_names.hh @@ -2,7 +2,11 @@ #define BRUSH_CHANNEL_MAKE_NAMES -static std::basic_string brush_channel_idnames[] = { +#ifdef BRUSH_CHANNEL_DEFINE_TYPES +# undef BRUSH_CHANNEL_DEFINE_TYPES +#endif + +static std::basic_string brush_channel_idnames[] = { #include "intern/brush_channel_define.h" }; diff --git a/source/blender/blenkernel/intern/brush_engine.c b/source/blender/blenkernel/intern/brush_engine.c index 0db8869632f..f8089957673 100644 --- a/source/blender/blenkernel/intern/brush_engine.c +++ b/source/blender/blenkernel/intern/brush_engine.c @@ -1191,8 +1191,8 @@ bool BKE_brush_mapping_is_enabled(BrushChannel *child, BrushChannel *parent, int } void BKE_brush_channel_apply_mapping_flags(BrushChannel *dst, - BrushChannel *child, - BrushChannel *parent) + const BrushChannel *child, + const BrushChannel *parent) { for (int i = 0; i < BRUSH_MAPPING_MAX; i++) { BrushMapping *mp = dst->mappings + i; @@ -1289,7 +1289,7 @@ void BKE_brush_channelset_set_final_int(BrushChannelSet *child, BKE_brush_channel_set_int(ch, value); } -float BKE_brush_channelset_get_final_float(BrushChannelSet *child, +float old_BKE_brush_channelset_get_final_float(BrushChannelSet *child, BrushChannelSet *parent, const char *idname, BrushMappingData *mapdata) diff --git a/source/blender/blenkernel/intern/brush_engine.cc b/source/blender/blenkernel/intern/brush_engine.cc index 7d22d1fe8f9..5ef16ac16cc 100644 --- a/source/blender/blenkernel/intern/brush_engine.cc +++ b/source/blender/blenkernel/intern/brush_engine.cc @@ -1,2 +1,37 @@ +#if 1 +#include "BKE_brush_engine.h" #include "BKE_brush_engine.hh" +#include "DNA_sculpt_brush_types.h" + +using BrushChannelSetIF = blender::brush::BrushChannelSetIF; +using BrushChannelFloat = blender::brush::BrushChannelIF; + +float BKE_brush_channelset_get_final_float(BrushChannelSet *child, + BrushChannelSet *parent, + const char *idname, + BrushMappingData *mapdata) +{ + BrushChannelSetIF chset_child(child); + BrushChannelSetIF chset_parent(parent); + + if (!child && parent) { + BrushChannelFloat ch = chset_parent.lookup(idname); + return ch.isValid() ? ch.evaluate(mapdata) : 0.0f; + } + else if (!parent) { + BrushChannelFloat ch = chset_child.lookup(idname); + return ch.isValid() ? ch.evaluate(mapdata) : 0.0f; + } + + BrushChannelFloat ch = chset_child.lookup(idname); + + return chset_child.getFinalValue(chset_parent, ch, mapdata); +} + +namespace blender { +namespace brush { + +} // namespace brush +} // namespace blender +#endif diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 8833f3eabe9..75df2e98fcd 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -54,6 +54,8 @@ #include "BLO_read_write.h" +#include "MEM_guardedalloc.h" + #ifdef WITH_ALEMBIC # include "ABC_alembic.h" #endif @@ -86,6 +88,7 @@ static void cache_file_copy_data(Main *UNUSED(bmain), cache_file_dst->handle = NULL; cache_file_dst->handle_readers = NULL; BLI_duplicatelist(&cache_file_dst->object_paths, &cache_file_src->object_paths); + BLI_duplicatelist(&cache_file_dst->layers, &cache_file_src->layers); } static void cache_file_free_data(ID *id) @@ -93,6 +96,7 @@ static void cache_file_free_data(ID *id) CacheFile *cache_file = (CacheFile *)id; cachefile_handle_free(cache_file); BLI_freelistN(&cache_file->object_paths); + BLI_freelistN(&cache_file->layers); } static void cache_file_foreach_path(ID *id, BPathForeachPathData *bpath_data) @@ -117,6 +121,11 @@ static void cache_file_blend_write(BlendWriter *writer, ID *id, const void *id_a if (cache_file->adt) { BKE_animdata_blend_write(writer, cache_file->adt); } + + /* write layers */ + LISTBASE_FOREACH (CacheFileLayer *, layer, &cache_file->layers) { + BLO_write_struct(writer, CacheFileLayer, layer); + } } static void cache_file_blend_read_data(BlendDataReader *reader, ID *id) @@ -130,6 +139,9 @@ static void cache_file_blend_read_data(BlendDataReader *reader, ID *id) /* relink animdata */ BLO_read_data_address(reader, &cache_file->adt); BKE_animdata_blend_read_data(reader, cache_file->adt); + + /* relink layers */ + BLO_read_list(reader, &cache_file->layers); } IDTypeInfo IDType_ID_CF = { @@ -364,7 +376,8 @@ void BKE_cachefile_eval(Main *bmain, Depsgraph *depsgraph, CacheFile *cache_file #ifdef WITH_ALEMBIC if (BLI_path_extension_check_glob(filepath, "*abc")) { cache_file->type = CACHEFILE_TYPE_ALEMBIC; - cache_file->handle = ABC_create_handle(bmain, filepath, &cache_file->object_paths); + cache_file->handle = ABC_create_handle( + bmain, filepath, cache_file->layers.first, &cache_file->object_paths); BLI_strncpy(cache_file->handle_filepath, filepath, FILE_MAX); } #endif @@ -435,3 +448,35 @@ bool BKE_cache_file_uses_render_procedural(const CacheFile *cache_file, const bool is_final_render = (eEvaluationMode)dag_eval_mode == DAG_EVAL_RENDER; return cache_file->use_render_procedural && !is_final_render; } + +CacheFileLayer *BKE_cachefile_add_layer(CacheFile *cache_file, const char filename[1024]) +{ + for (CacheFileLayer *layer = cache_file->layers.first; layer; layer = layer->next) { + if (STREQ(layer->filepath, filename)) { + return NULL; + } + } + + const int num_layers = BLI_listbase_count(&cache_file->layers); + + CacheFileLayer *layer = MEM_callocN(sizeof(CacheFileLayer), "CacheFileLayer"); + BLI_strncpy(layer->filepath, filename, sizeof(layer->filepath)); + + BLI_addtail(&cache_file->layers, layer); + + cache_file->active_layer = (char)(num_layers + 1); + + return layer; +} + +CacheFileLayer *BKE_cachefile_get_active_layer(CacheFile *cache_file) +{ + return BLI_findlink(&cache_file->layers, cache_file->active_layer - 1); +} + +void BKE_cachefile_remove_layer(CacheFile *cache_file, CacheFileLayer *layer) +{ + cache_file->active_layer = 0; + BLI_remlink(&cache_file->layers, layer); + MEM_freeN(layer); +} diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc index 755b05e2697..70edaccb244 100644 --- a/source/blender/blenkernel/intern/curve.cc +++ b/source/blender/blenkernel/intern/curve.cc @@ -30,6 +30,7 @@ #include "BLI_blenlib.h" #include "BLI_endian_switch.h" #include "BLI_ghash.h" +#include "BLI_index_range.hh" #include "BLI_math.h" #include "BLI_utildefines.h" @@ -67,10 +68,12 @@ #include "BLO_read_write.h" +using blender::IndexRange; + /* globals */ /* local */ -static CLG_LogRef LOG = {"bke.curve"}; +// static CLG_LogRef LOG = {"bke.curve"}; static void curve_init_data(ID *id) { @@ -1160,81 +1163,34 @@ void BKE_nurb_bpoint_calc_plane(struct Nurb *nu, BPoint *bp, float r_plane[3]) static void calcknots(float *knots, const int pnts, const short order, const short flag) { - /* knots: number of pnts NOT corrected for cyclic */ - const int pnts_order = pnts + order; - float k; - int a; + const bool is_cyclic = flag & CU_NURB_CYCLIC; + const bool is_bezier = flag & CU_NURB_BEZIER && !(flag & CU_NURB_ENDPOINT); + const bool is_end_point = flag & CU_NURB_ENDPOINT && !(flag & CU_NURB_BEZIER); + /* Inner knots are always repeated once except on Bezier case. */ + const int repeat_inner = is_bezier ? order - 1 : 1; + /* How many times to repeat 0.0 at the beginning of knot. */ + const int head = is_end_point && !is_cyclic ? order : (is_bezier ? order / 2 : 1); + /* Number of knots replicating widths of the starting knots. + * Covers both Cyclic and EndPoint cases. */ + const int tail = is_cyclic ? 2 * order - 1 : (is_end_point ? order : 0); - switch (flag & (CU_NURB_ENDPOINT | CU_NURB_BEZIER)) { - case CU_NURB_ENDPOINT: - k = 0.0; - for (a = 1; a <= pnts_order; a++) { - knots[a - 1] = k; - if (a >= order && a <= pnts) { - k += 1.0f; - } - } - break; - case CU_NURB_BEZIER: - /* Warning, the order MUST be 2 or 4, - * if this is not enforced, the displist will be corrupt */ - if (order == 4) { - k = 0.34; - for (a = 0; a < pnts_order; a++) { - knots[a] = floorf(k); - k += (1.0f / 3.0f); - } - } - else if (order == 3) { - k = 0.6f; - for (a = 0; a < pnts_order; a++) { - if (a >= order && a <= pnts) { - k += 0.5f; - } - knots[a] = floorf(k); - } - } - else { - CLOG_ERROR(&LOG, "bez nurb curve order is not 3 or 4, should never happen"); - } - break; - default: - for (a = 0; a < pnts_order; a++) { - knots[a] = (float)a; - } - break; - } -} + const int knot_count = pnts + order + (is_cyclic ? order - 1 : 0); -static void makecyclicknots(float *knots, int pnts, short order) -/* pnts, order: number of pnts NOT corrected for cyclic */ -{ - int a, b, order2, c; + int r = head; + float current = 0.0f; - if (knots == nullptr) { - return; - } - - order2 = order - 1; - - /* do first long rows (order -1), remove identical knots at endpoints */ - if (order > 2) { - b = pnts + order2; - for (a = 1; a < order2; a++) { - if (knots[b] != knots[b - a]) { - break; - } - } - if (a == order2) { - knots[pnts + order - 2] += 1.0f; + for (const int i : IndexRange(knot_count - tail)) { + knots[i] = current; + r--; + if (r == 0) { + current += 1.0; + r = repeat_inner; } } - b = order; - c = pnts + order + order2; - for (a = pnts + order2; a < c; a++) { - knots[a] = knots[a - 1] + (knots[b] - knots[b - 1]); - b--; + const int tail_index = knot_count - tail; + for (const int i : IndexRange(tail)) { + knots[tail_index + i] = current + (knots[i] - knots[0]); } } @@ -1247,13 +1203,7 @@ static void makeknots(Nurb *nu, short uv) } if (BKE_nurb_check_valid_u(nu)) { nu->knotsu = (float *)MEM_calloc_arrayN(KNOTSU(nu) + 1, sizeof(float), "makeknots"); - if (nu->flagu & CU_NURB_CYCLIC) { - calcknots(nu->knotsu, nu->pntsu, nu->orderu, 0); /* cyclic should be uniform */ - makecyclicknots(nu->knotsu, nu->pntsu, nu->orderu); - } - else { - calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu); - } + calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu); } else { nu->knotsu = nullptr; @@ -1265,13 +1215,7 @@ static void makeknots(Nurb *nu, short uv) } if (BKE_nurb_check_valid_v(nu)) { nu->knotsv = (float *)MEM_calloc_arrayN(KNOTSV(nu) + 1, sizeof(float), "makeknots"); - if (nu->flagv & CU_NURB_CYCLIC) { - calcknots(nu->knotsv, nu->pntsv, nu->orderv, 0); /* cyclic should be uniform */ - makecyclicknots(nu->knotsv, nu->pntsv, nu->orderv); - } - else { - calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv); - } + calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv); } else { nu->knotsv = nullptr; diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index ea781722885..420e9171812 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -46,6 +46,10 @@ #include "BLI_string_utils.h" #include "BLI_utildefines.h" +#ifndef NDEBUG +# include "BLI_dynstr.h" +#endif + #include "BLT_translation.h" #include "BKE_anonymous_attribute.h" @@ -1804,7 +1808,9 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { /* 29: CD_BWEIGHT */ {sizeof(float), "", 0, N_("BevelWeight"), nullptr, nullptr, layerInterp_bweight}, /* 30: CD_CREASE */ - {sizeof(float), "", 0, N_("SubSurfCrease"), nullptr, nullptr, layerInterp_bweight}, + /* NOTE: we do not interpolate crease data as it should be either inherited for subdivided + * edges, or for vertex creases, only present on the original vertex. */ + {sizeof(float), "", 0, N_("SubSurfCrease"), nullptr, nullptr, nullptr}, /* 31: CD_ORIGSPACE_MLOOP */ {sizeof(OrigSpaceLoop), "OrigSpaceLoop", @@ -2088,7 +2094,7 @@ 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_MESH_ID), + CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_CREASE | CD_MASK_MESH_ID), /* emask */ (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL | CD_MASK_MESH_ID), /* fmask */ 0, /* pmask */ @@ -2100,7 +2106,8 @@ const CustomData_MeshMasks CD_MASK_MESH = { }; const CustomData_MeshMasks CD_MASK_EDITMESH = { /* vmask */ (CD_MASK_MDEFORMVERT | CD_MASK_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY | - CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_MESH_ID), + CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_CREASE | + CD_MASK_MESH_ID), /* emask */ (CD_MASK_PROP_ALL | CD_MASK_MESH_ID), /* fmask */ 0, /* pmask */ (CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS | CD_MASK_MESH_ID), @@ -2111,7 +2118,7 @@ const CustomData_MeshMasks CD_MASK_EDITMESH = { 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_MESH_ID), + CD_MASK_PROP_COLOR | CD_MASK_CREASE | CD_MASK_MESH_ID), /* emask */ (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL | CD_MASK_MESH_ID), /* fmask */ (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT), /* pmask */ @@ -2125,7 +2132,7 @@ const CustomData_MeshMasks CD_MASK_DERIVEDMESH = { 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_MESH_ID | CD_MASK_DYNTOPO_VERT), + CD_MASK_PROP_COLOR | CD_MASK_CREASE | CD_MASK_MESH_ID | CD_MASK_DYNTOPO_VERT), /* emask */ (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL | CD_MASK_MESH_ID), @@ -2155,7 +2162,7 @@ const CustomData_MeshMasks CD_MASK_EVERYTHING = { /* vmask */ (CD_MASK_MVERT | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | 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_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | 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), @@ -2371,7 +2378,8 @@ void CustomData_copy_all_layout(const struct CustomData *source, struct CustomDa } if (source->layers) { - dest->layers = static_cast(MEM_mallocN(sizeof(*dest->layers) * source->totlayer, __func__)); + dest->layers = static_cast( + MEM_mallocN(sizeof(*dest->layers) * source->totlayer, __func__)); for (int i = 0; i < source->totlayer; i++) { dest->layers[i] = source->layers[i]; @@ -5046,7 +5054,12 @@ bool CustomData_verify_versions(struct CustomData *data, int index) /* 0 structnum is used in writing code to tag layer types that should not be written. */ else if (typeInfo->structnum == 0 && /* XXX Not sure why those three are exception, maybe that should be fixed? */ - !ELEM(layer->type, CD_PAINT_MASK, CD_FACEMAP, CD_MTEXPOLY, CD_SCULPT_FACE_SETS)) { + !ELEM(layer->type, + CD_PAINT_MASK, + CD_FACEMAP, + CD_MTEXPOLY, + CD_SCULPT_FACE_SETS, + CD_CREASE)) { keeplayer = false; CLOG_WARN(&LOG, ".blend file read: removing a data layer that should not have been written"); } @@ -5717,6 +5730,10 @@ void CustomData_blend_write(BlendWriter *writer, const bool *layer_data = static_cast(layer->data); BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data); } + else if (layer->type == CD_CREASE) { + const float *layer_data = static_cast(layer->data); + BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data); + } else { const char *structname; int structnum; @@ -5830,3 +5847,33 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count) CustomData_update_typemap(data); CustomData_regen_active_refs(data); // check for corrupted active layer refs } + +#ifndef NDEBUG + +void CustomData_debug_info_from_layers(const CustomData *data, const char *indent, DynStr *dynstr) +{ + for (int type = 0; type < CD_NUMTYPES; type++) { + if (CustomData_has_layer(data, type)) { + /* NOTE: doesn't account for multiple layers. */ + const char *name = CustomData_layertype_name(type); + const int size = CustomData_sizeof(type); + const void *pt = CustomData_get_layer(data, type); + const int pt_size = pt ? (int)(MEM_allocN_len(pt) / size) : 0; + const char *structname; + int structnum; + CustomData_file_write_info(type, &structname, &structnum); + BLI_dynstr_appendf( + dynstr, + "%sdict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n", + indent, + name, + structname, + type, + (const void *)pt, + size, + pt_size); + } + } +} + +#endif /* NDEBUG */ diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 11b350ef2be..2509448d8aa 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -15,6 +15,7 @@ */ #include "BLI_listbase.h" +#include "BLI_task.hh" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -266,89 +267,54 @@ static GVArray adapt_mesh_domain_corner_to_point(const Mesh &mesh, const GVArray /** * Each corner's value is simply a copy of the value at its vertex. - * - * \note Theoretically this interpolation does not need to compute all values at once. - * However, doing that makes the implementation simpler, and this can be optimized in the future if - * only some values are required. */ -template -static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh, - const VArray &old_values, - MutableSpan r_values) -{ - BLI_assert(r_values.size() == mesh.totloop); - - for (const int loop_index : IndexRange(mesh.totloop)) { - const int vertex_index = mesh.mloop[loop_index].v; - r_values[loop_index] = old_values[vertex_index]; - } -} - static GVArray adapt_mesh_domain_point_to_corner(const Mesh &mesh, const GVArray &varray) { GVArray new_varray; attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); - Array values(mesh.totloop); - adapt_mesh_domain_point_to_corner_impl(mesh, varray.typed(), values); - new_varray = VArray::ForContainer(std::move(values)); + new_varray = VArray::ForFunc(mesh.totloop, + [mesh, varray = varray.typed()](const int64_t loop_index) { + const int vertex_index = mesh.mloop[loop_index].v; + return varray[vertex_index]; + }); }); return new_varray; } -/** - * \note Theoretically this interpolation does not need to compute all values at once. - * However, doing that makes the implementation simpler, and this can be optimized in the future if - * only some values are required. - */ -template -static void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh, - const VArray &old_values, - MutableSpan r_values) -{ - BLI_assert(r_values.size() == mesh.totpoly); - attribute_math::DefaultMixer mixer(r_values); - - for (const int poly_index : IndexRange(mesh.totpoly)) { - const MPoly &poly = mesh.mpoly[poly_index]; - for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - const T value = old_values[loop_index]; - mixer.mix_in(poly_index, value); - } - } - - mixer.finalize(); -} - -/* A face is selected if all of its corners were selected. */ -template<> -void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh, - const VArray &old_values, - MutableSpan r_values) -{ - BLI_assert(r_values.size() == mesh.totpoly); - - r_values.fill(true); - for (const int poly_index : IndexRange(mesh.totpoly)) { - const MPoly &poly = mesh.mpoly[poly_index]; - for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - if (!old_values[loop_index]) { - r_values[poly_index] = false; - break; - } - } - } -} - static GVArray adapt_mesh_domain_corner_to_face(const Mesh &mesh, const GVArray &varray) { GVArray new_varray; attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v>) { - Array values(mesh.totpoly); - adapt_mesh_domain_corner_to_face_impl(mesh, varray.typed(), values); - new_varray = VArray::ForContainer(std::move(values)); + if constexpr (std::is_same_v) { + new_varray = VArray::ForFunc( + mesh.totpoly, [mesh, varray = varray.typed()](const int face_index) { + /* A face is selected if all of its corners were selected. */ + const MPoly &poly = mesh.mpoly[face_index]; + for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { + if (!varray[loop_index]) { + return false; + } + } + return true; + }); + } + else { + new_varray = VArray::ForFunc( + mesh.totpoly, [mesh, varray = varray.typed()](const int face_index) { + T return_value; + attribute_math::DefaultMixer mixer({&return_value, 1}); + const MPoly &poly = mesh.mpoly[face_index]; + for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { + const T value = varray[loop_index]; + mixer.mix_in(0, value); + } + mixer.finalize(); + return return_value; + }); + } } }); return new_varray; @@ -406,11 +372,13 @@ void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh, } /* Deselect loose edges without corners that are still selected from the 'true' default. */ - for (const int edge_index : IndexRange(mesh.totedge)) { - if (loose_edges[edge_index]) { - r_values[edge_index] = false; + threading::parallel_for(IndexRange(mesh.totedge), 2048, [&](const IndexRange range) { + for (const int edge_index : range) { + if (loose_edges[edge_index]) { + r_values[edge_index] = false; + } } - } + }); } static GVArray adapt_mesh_domain_corner_to_edge(const Mesh &mesh, const GVArray &varray) @@ -491,11 +459,13 @@ void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh, { BLI_assert(r_values.size() == mesh.totloop); - for (const int poly_index : IndexRange(mesh.totpoly)) { - const MPoly &poly = mesh.mpoly[poly_index]; - MutableSpan poly_corner_values = r_values.slice(poly.loopstart, poly.totloop); - poly_corner_values.fill(old_values[poly_index]); - } + threading::parallel_for(IndexRange(mesh.totpoly), 1024, [&](const IndexRange range) { + for (const int poly_index : range) { + const MPoly &poly = mesh.mpoly[poly_index]; + MutableSpan poly_corner_values = r_values.slice(poly.loopstart, poly.totloop); + poly_corner_values.fill(old_values[poly_index]); + } + }); } static GVArray adapt_mesh_domain_face_to_corner(const Mesh &mesh, const GVArray &varray) @@ -566,111 +536,72 @@ static GVArray adapt_mesh_domain_face_to_edge(const Mesh &mesh, const GVArray &v return new_varray; } -/** - * \note Theoretically this interpolation does not need to compute all values at once. - * However, doing that makes the implementation simpler, and this can be optimized in the future if - * only some values are required. - */ -template -static void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh, - const VArray &old_values, - MutableSpan r_values) -{ - BLI_assert(r_values.size() == mesh.totpoly); - attribute_math::DefaultMixer mixer(r_values); - - for (const int poly_index : IndexRange(mesh.totpoly)) { - const MPoly &poly = mesh.mpoly[poly_index]; - for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - MLoop &loop = mesh.mloop[loop_index]; - const int point_index = loop.v; - mixer.mix_in(poly_index, old_values[point_index]); - } - } - mixer.finalize(); -} - -/* A face is selected if all of its vertices were selected too. */ -template<> -void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh, - const VArray &old_values, - MutableSpan r_values) -{ - BLI_assert(r_values.size() == mesh.totpoly); - - r_values.fill(true); - for (const int poly_index : IndexRange(mesh.totpoly)) { - const MPoly &poly = mesh.mpoly[poly_index]; - for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - MLoop &loop = mesh.mloop[loop_index]; - const int vert_index = loop.v; - if (!old_values[vert_index]) { - r_values[poly_index] = false; - break; - } - } - } -} - static GVArray adapt_mesh_domain_point_to_face(const Mesh &mesh, const GVArray &varray) { GVArray new_varray; attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v>) { - Array values(mesh.totpoly); - adapt_mesh_domain_point_to_face_impl(mesh, varray.typed(), values); - new_varray = VArray::ForContainer(std::move(values)); + if constexpr (std::is_same_v) { + new_varray = VArray::ForFunc( + mesh.totpoly, [mesh, varray = varray.typed()](const int face_index) { + /* A face is selected if all of its vertices were selected. */ + const MPoly &poly = mesh.mpoly[face_index]; + for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { + const MLoop &loop = mesh.mloop[loop_index]; + if (!varray[loop.v]) { + return false; + } + } + return true; + }); + } + else { + new_varray = VArray::ForFunc( + mesh.totpoly, [mesh, varray = varray.typed()](const int face_index) { + T return_value; + attribute_math::DefaultMixer mixer({&return_value, 1}); + const MPoly &poly = mesh.mpoly[face_index]; + for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { + const MLoop &loop = mesh.mloop[loop_index]; + const T value = varray[loop.v]; + mixer.mix_in(0, value); + } + mixer.finalize(); + return return_value; + }); + } } }); return new_varray; } -/** - * \note Theoretically this interpolation does not need to compute all values at once. - * However, doing that makes the implementation simpler, and this can be optimized in the future if - * only some values are required. - */ -template -static void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh, - const VArray &old_values, - MutableSpan r_values) -{ - BLI_assert(r_values.size() == mesh.totedge); - attribute_math::DefaultMixer mixer(r_values); - - for (const int edge_index : IndexRange(mesh.totedge)) { - const MEdge &edge = mesh.medge[edge_index]; - mixer.mix_in(edge_index, old_values[edge.v1]); - mixer.mix_in(edge_index, old_values[edge.v2]); - } - - mixer.finalize(); -} - -/* An edge is selected if both of its vertices were selected. */ -template<> -void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh, - const VArray &old_values, - MutableSpan r_values) -{ - BLI_assert(r_values.size() == mesh.totedge); - - for (const int edge_index : IndexRange(mesh.totedge)) { - const MEdge &edge = mesh.medge[edge_index]; - r_values[edge_index] = old_values[edge.v1] && old_values[edge.v2]; - } -} - static GVArray adapt_mesh_domain_point_to_edge(const Mesh &mesh, const GVArray &varray) { GVArray new_varray; attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v>) { - Array values(mesh.totedge); - adapt_mesh_domain_point_to_edge_impl(mesh, varray.typed(), values); - new_varray = VArray::ForContainer(std::move(values)); + if constexpr (std::is_same_v) { + /* An edge is selected if both of its vertices were selected. */ + new_varray = VArray::ForFunc( + mesh.totedge, [mesh, varray = varray.typed()](const int edge_index) { + const MEdge &edge = mesh.medge[edge_index]; + return varray[edge.v1] && varray[edge.v2]; + }); + } + else { + new_varray = VArray::ForFunc( + mesh.totedge, [mesh, varray = varray.typed()](const int edge_index) { + T return_value; + attribute_math::DefaultMixer mixer({&return_value, 1}); + const MEdge &edge = mesh.medge[edge_index]; + mixer.mix_in(0, varray[edge.v1]); + mixer.mix_in(0, varray[edge.v2]); + mixer.finalize(); + return return_value; + }); + } } }); return new_varray; @@ -787,61 +718,41 @@ static GVArray adapt_mesh_domain_edge_to_point(const Mesh &mesh, const GVArray & return new_varray; } -/** - * \note Theoretically this interpolation does not need to compute all values at once. - * However, doing that makes the implementation simpler, and this can be optimized in the future if - * only some values are required. - */ -template -static void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh, - const VArray &old_values, - MutableSpan r_values) -{ - BLI_assert(r_values.size() == mesh.totpoly); - attribute_math::DefaultMixer mixer(r_values); - - for (const int poly_index : IndexRange(mesh.totpoly)) { - const MPoly &poly = mesh.mpoly[poly_index]; - for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - const MLoop &loop = mesh.mloop[loop_index]; - mixer.mix_in(poly_index, old_values[loop.e]); - } - } - - mixer.finalize(); -} - -/* A face is selected if all of its edges are selected. */ -template<> -void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh, - const VArray &old_values, - MutableSpan r_values) -{ - BLI_assert(r_values.size() == mesh.totpoly); - - r_values.fill(true); - for (const int poly_index : IndexRange(mesh.totpoly)) { - const MPoly &poly = mesh.mpoly[poly_index]; - for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - const MLoop &loop = mesh.mloop[loop_index]; - const int edge_index = loop.e; - if (!old_values[edge_index]) { - r_values[poly_index] = false; - break; - } - } - } -} - static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &varray) { GVArray new_varray; attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v>) { - Array values(mesh.totpoly); - adapt_mesh_domain_edge_to_face_impl(mesh, varray.typed(), values); - new_varray = VArray::ForContainer(std::move(values)); + if constexpr (std::is_same_v) { + /* A face is selected if all of its edges are selected. */ + new_varray = VArray::ForFunc( + mesh.totpoly, [mesh, varray = varray.typed()](const int face_index) { + const MPoly &poly = mesh.mpoly[face_index]; + for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { + const MLoop &loop = mesh.mloop[loop_index]; + if (!varray[loop.e]) { + return false; + } + } + return true; + }); + } + else { + new_varray = VArray::ForFunc( + mesh.totpoly, [mesh, varray = varray.typed()](const int face_index) { + T return_value; + attribute_math::DefaultMixer mixer({&return_value, 1}); + const MPoly &poly = mesh.mpoly[face_index]; + for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { + const MLoop &loop = mesh.mloop[loop_index]; + const T value = varray[loop.e]; + mixer.mix_in(0, value); + } + mixer.finalize(); + return return_value; + }); + } } }); return new_varray; diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 68fc6469d47..29ddfce67c8 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -151,6 +151,8 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int BKE_mesh_update_customdata_pointers(mesh_dst, do_tessface); + mesh_dst->cd_flag = mesh_src->cd_flag; + mesh_dst->edit_mesh = nullptr; mesh_dst->mselect = (MSelect *)MEM_dupallocN(mesh_dst->mselect); diff --git a/source/blender/blenkernel/intern/mesh_merge.c b/source/blender/blenkernel/intern/mesh_merge.c index e6bcd726e03..fb27ca96380 100644 --- a/source/blender/blenkernel/intern/mesh_merge.c +++ b/source/blender/blenkernel/intern/mesh_merge.c @@ -623,10 +623,18 @@ Mesh *BKE_mesh_merge_verts(Mesh *mesh, } /* Copy over data. #CustomData_add_layer can do this, need to look it up. */ - memcpy(result->mvert, mvert, sizeof(MVert) * STACK_SIZE(mvert)); - memcpy(result->medge, medge, sizeof(MEdge) * STACK_SIZE(medge)); - memcpy(result->mloop, mloop, sizeof(MLoop) * STACK_SIZE(mloop)); - memcpy(result->mpoly, mpoly, sizeof(MPoly) * STACK_SIZE(mpoly)); + if (STACK_SIZE(mvert)) { + memcpy(result->mvert, mvert, sizeof(MVert) * STACK_SIZE(mvert)); + } + if (STACK_SIZE(medge)) { + memcpy(result->medge, medge, sizeof(MEdge) * STACK_SIZE(medge)); + } + if (STACK_SIZE(mloop)) { + memcpy(result->mloop, mloop, sizeof(MLoop) * STACK_SIZE(mloop)); + } + if (STACK_SIZE(mpoly)) { + memcpy(result->mpoly, mpoly, sizeof(MPoly) * STACK_SIZE(mpoly)); + } MEM_freeN(mvert); MEM_freeN(medge); diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c index 39dbd7d66a4..e7e5064df7c 100644 --- a/source/blender/blenkernel/intern/mesh_runtime.c +++ b/source/blender/blenkernel/intern/mesh_runtime.c @@ -298,129 +298,10 @@ void BKE_mesh_batch_cache_free(Mesh *me) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Mesh Runtime Debug Helpers +/** \name Mesh Runtime Validation * \{ */ -/* Evaluated mesh info printing function, to help track down differences output. */ - #ifndef NDEBUG -# include "BLI_dynstr.h" - -static void mesh_runtime_debug_info_layers(DynStr *dynstr, CustomData *cd) -{ - int type; - - for (type = 0; type < CD_NUMTYPES; type++) { - if (CustomData_has_layer(cd, type)) { - /* NOTE: doesn't account for multiple layers. */ - const char *name = CustomData_layertype_name(type); - const int size = CustomData_sizeof(type); - const void *pt = CustomData_get_layer(cd, type); - const int pt_size = pt ? (int)(MEM_allocN_len(pt) / size) : 0; - const char *structname; - int structnum; - CustomData_file_write_info(type, &structname, &structnum); - BLI_dynstr_appendf( - dynstr, - " dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n", - name, - structname, - type, - (const void *)pt, - size, - pt_size); - } - } -} - -char *BKE_mesh_runtime_debug_info(Mesh *me_eval) -{ - DynStr *dynstr = BLI_dynstr_new(); - char *ret; - - BLI_dynstr_append(dynstr, "{\n"); - BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)me_eval); -# if 0 - const char *tstr; - switch (me_eval->type) { - case DM_TYPE_CDDM: - tstr = "DM_TYPE_CDDM"; - break; - case DM_TYPE_CCGDM: - tstr = "DM_TYPE_CCGDM"; - break; - default: - tstr = "UNKNOWN"; - break; - } - BLI_dynstr_appendf(dynstr, " 'type': '%s',\n", tstr); -# endif - BLI_dynstr_appendf(dynstr, " 'totvert': %d,\n", me_eval->totvert); - BLI_dynstr_appendf(dynstr, " 'totedge': %d,\n", me_eval->totedge); - BLI_dynstr_appendf(dynstr, " 'totface': %d,\n", me_eval->totface); - BLI_dynstr_appendf(dynstr, " 'totpoly': %d,\n", me_eval->totpoly); - BLI_dynstr_appendf(dynstr, " 'deformed_only': %d,\n", me_eval->runtime.deformed_only); - - BLI_dynstr_append(dynstr, " 'vertexLayers': (\n"); - mesh_runtime_debug_info_layers(dynstr, &me_eval->vdata); - BLI_dynstr_append(dynstr, " ),\n"); - - BLI_dynstr_append(dynstr, " 'edgeLayers': (\n"); - mesh_runtime_debug_info_layers(dynstr, &me_eval->edata); - BLI_dynstr_append(dynstr, " ),\n"); - - BLI_dynstr_append(dynstr, " 'loopLayers': (\n"); - mesh_runtime_debug_info_layers(dynstr, &me_eval->ldata); - BLI_dynstr_append(dynstr, " ),\n"); - - BLI_dynstr_append(dynstr, " 'polyLayers': (\n"); - mesh_runtime_debug_info_layers(dynstr, &me_eval->pdata); - BLI_dynstr_append(dynstr, " ),\n"); - - BLI_dynstr_append(dynstr, " 'tessFaceLayers': (\n"); - mesh_runtime_debug_info_layers(dynstr, &me_eval->fdata); - BLI_dynstr_append(dynstr, " ),\n"); - - BLI_dynstr_append(dynstr, "}\n"); - - ret = BLI_dynstr_get_cstring(dynstr); - BLI_dynstr_free(dynstr); - return ret; -} - -void BKE_mesh_runtime_debug_print(Mesh *me_eval) -{ - char *str = BKE_mesh_runtime_debug_info(me_eval); - puts(str); - fflush(stdout); - MEM_freeN(str); -} - -void BKE_mesh_runtime_debug_print_cdlayers(CustomData *data) -{ - int i; - const CustomDataLayer *layer; - - printf("{\n"); - - for (i = 0, layer = data->layers; i < data->totlayer; i++, layer++) { - - const char *name = CustomData_layertype_name(layer->type); - const int size = CustomData_sizeof(layer->type); - const char *structname; - int structnum; - CustomData_file_write_info(layer->type, &structname, &structnum); - printf(" dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n", - name, - structname, - layer->type, - (const void *)layer->data, - size, - (int)(MEM_allocN_len(layer->data) / size)); - } - - printf("}\n"); -} bool BKE_mesh_runtime_is_valid(Mesh *me_eval) { diff --git a/source/blender/blenkernel/intern/multires_reshape.h b/source/blender/blenkernel/intern/multires_reshape.h index 8a37d0ea785..a038ce5f108 100644 --- a/source/blender/blenkernel/intern/multires_reshape.h +++ b/source/blender/blenkernel/intern/multires_reshape.h @@ -106,6 +106,9 @@ typedef struct MultiresReshapeContext { /* Indexed by base face index, returns first ptex face index corresponding * to that base face. */ int *face_ptex_offset; + + /* Vertex crease custom data layer, null if none is present. */ + const float *cd_vertex_crease; } MultiresReshapeContext; /** diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c index af8391e2193..32c5acbd9f4 100644 --- a/source/blender/blenkernel/intern/multires_reshape_smooth.c +++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c @@ -108,6 +108,7 @@ typedef struct Vertex { int num_grid_coords; GridCoord *grid_coords; + float sharpness; bool is_infinite_sharp; } Vertex; @@ -522,19 +523,33 @@ static int get_reshape_level_resolution(const MultiresReshapeContext *reshape_co return (1 << reshape_context->reshape.level) + 1; } +static bool is_crease_supported(const MultiresReshapeSmoothContext *reshape_smooth_context) +{ + return !ELEM(reshape_smooth_context->smoothing_type, + MULTIRES_SUBDIVIDE_LINEAR, + MULTIRES_SUBDIVIDE_SIMPLE); +} + /* Get crease which will be used for communication to OpenSubdiv topology. * Note that simple subdivision treats all base edges as infinitely sharp. */ -static char get_effective_edge_crease_char( - const MultiresReshapeSmoothContext *reshape_smooth_context, const MEdge *base_edge) +static char get_effective_crease_char(const MultiresReshapeSmoothContext *reshape_smooth_context, + const MEdge *base_edge) { - if (ELEM(reshape_smooth_context->smoothing_type, - MULTIRES_SUBDIVIDE_LINEAR, - MULTIRES_SUBDIVIDE_SIMPLE)) { + if (!is_crease_supported(reshape_smooth_context)) { return 255; } return base_edge->crease; } +static float get_effective_crease_float(const MultiresReshapeSmoothContext *reshape_smooth_context, + const float crease) +{ + if (!is_crease_supported(reshape_smooth_context)) { + return 1.0f; + } + return crease; +} + static void context_init(MultiresReshapeSmoothContext *reshape_smooth_context, const MultiresReshapeContext *reshape_context, const eMultiresSubdivideModeType mode) @@ -629,6 +644,7 @@ static bool foreach_topology_info(const SubdivForeachContext *foreach_context, static void foreach_single_vertex(const SubdivForeachContext *foreach_context, const GridCoord *grid_coord, + const int coarse_vertex_index, const int subdiv_vertex_index) { const MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data; @@ -641,11 +657,32 @@ static void foreach_single_vertex(const SubdivForeachContext *foreach_context, sizeof(Vertex) * (vertex->num_grid_coords + 1)); vertex->grid_coords[vertex->num_grid_coords] = *grid_coord; ++vertex->num_grid_coords; + + if (coarse_vertex_index == -1) { + return; + } + + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + const float *cd_vertex_crease = reshape_context->cd_vertex_crease; + + if (cd_vertex_crease == NULL) { + return; + } + + float crease = cd_vertex_crease[coarse_vertex_index]; + + if (crease == 0.0f) { + return; + } + + crease = get_effective_crease_float(reshape_smooth_context, crease); + vertex->sharpness = BKE_subdiv_crease_to_sharpness_f(crease); } /* TODO(sergey): De-duplicate with similar function in multires_reshape_vertcos.c */ static void foreach_vertex(const SubdivForeachContext *foreach_context, const PTexCoord *ptex_coord, + const int coarse_vertex_index, const int subdiv_vertex_index) { const MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data; @@ -665,12 +702,13 @@ static void foreach_vertex(const SubdivForeachContext *foreach_context, for (int current_corner = 0; current_corner < num_corners; ++current_corner) { GridCoord corner_grid_coord = grid_coord; corner_grid_coord.grid_index = start_grid_index + current_corner; - foreach_single_vertex(foreach_context, &corner_grid_coord, subdiv_vertex_index); + foreach_single_vertex( + foreach_context, &corner_grid_coord, coarse_vertex_index, subdiv_vertex_index); } return; } - foreach_single_vertex(foreach_context, &grid_coord, subdiv_vertex_index); + foreach_single_vertex(foreach_context, &grid_coord, coarse_vertex_index, subdiv_vertex_index); if (grid_coord.u == 0.0f) { GridCoord prev_grid_coord; @@ -678,7 +716,8 @@ static void foreach_vertex(const SubdivForeachContext *foreach_context, prev_grid_coord.u = grid_coord.v; prev_grid_coord.v = 0.0f; - foreach_single_vertex(foreach_context, &prev_grid_coord, subdiv_vertex_index); + foreach_single_vertex( + foreach_context, &prev_grid_coord, coarse_vertex_index, subdiv_vertex_index); } if (grid_coord.v == 0.0f) { @@ -687,7 +726,8 @@ static void foreach_vertex(const SubdivForeachContext *foreach_context, next_grid_coord.u = 0.0f; next_grid_coord.v = grid_coord.u; - foreach_single_vertex(foreach_context, &next_grid_coord, subdiv_vertex_index); + foreach_single_vertex( + foreach_context, &next_grid_coord, coarse_vertex_index, subdiv_vertex_index); } } @@ -705,7 +745,7 @@ static void foreach_vertex_inner(const struct SubdivForeachContext *foreach_cont .u = ptex_face_u, .v = ptex_face_v, }; - foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index); + foreach_vertex(foreach_context, &ptex_coord, -1, subdiv_vertex_index); } static void foreach_vertex_every_corner(const struct SubdivForeachContext *foreach_context, @@ -713,7 +753,7 @@ static void foreach_vertex_every_corner(const struct SubdivForeachContext *forea const int ptex_face_index, const float ptex_face_u, const float ptex_face_v, - const int UNUSED(coarse_vertex_index), + const int coarse_vertex_index, const int UNUSED(coarse_face_index), const int UNUSED(coarse_face_corner), const int subdiv_vertex_index) @@ -723,7 +763,7 @@ static void foreach_vertex_every_corner(const struct SubdivForeachContext *forea .u = ptex_face_u, .v = ptex_face_v, }; - foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index); + foreach_vertex(foreach_context, &ptex_coord, coarse_vertex_index, subdiv_vertex_index); } static void foreach_vertex_every_edge(const struct SubdivForeachContext *foreach_context, @@ -741,7 +781,7 @@ static void foreach_vertex_every_edge(const struct SubdivForeachContext *foreach .u = ptex_face_u, .v = ptex_face_v, }; - foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index); + foreach_vertex(foreach_context, &ptex_coord, -1, subdiv_vertex_index); } static void foreach_loop(const struct SubdivForeachContext *foreach_context, @@ -811,7 +851,7 @@ static void store_edge(MultiresReshapeSmoothContext *reshape_smooth_context, Edge *edge = &reshape_smooth_context->geometry.edges[edge_index]; edge->v1 = subdiv_v1; edge->v2 = subdiv_v2; - edge->sharpness = BKE_subdiv_edge_crease_to_sharpness_char(crease); + edge->sharpness = BKE_subdiv_crease_to_sharpness_char(crease); } static void foreach_edge(const struct SubdivForeachContext *foreach_context, @@ -842,7 +882,7 @@ static void foreach_edge(const struct SubdivForeachContext *foreach_context, /* Edges without crease are to be ignored as well. */ const Mesh *base_mesh = reshape_context->base_mesh; const MEdge *base_edge = &base_mesh->medge[coarse_edge_index]; - const char crease = get_effective_edge_crease_char(reshape_smooth_context, base_edge); + const char crease = get_effective_crease_char(reshape_smooth_context, base_edge); if (crease == 0) { return; } @@ -868,8 +908,7 @@ static void geometry_init_loose_information(MultiresReshapeSmoothContext *reshap if (!BLI_BITMAP_TEST_BOOL(reshape_smooth_context->non_loose_base_edge_map, loop->e)) { BLI_BITMAP_ENABLE(reshape_smooth_context->non_loose_base_edge_map, loop->e); - const char crease = get_effective_edge_crease_char(reshape_smooth_context, - &base_edge[loop->e]); + const char crease = get_effective_crease_char(reshape_smooth_context, &base_edge[loop->e]); if (crease != 0) { ++num_used_edges; } @@ -1012,6 +1051,15 @@ static float get_edge_sharpness(const OpenSubdiv_Converter *converter, const int return edge->sharpness; } +static float get_vertex_sharpness(const OpenSubdiv_Converter *converter, const int vertex_index) +{ + const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data; + BLI_assert(vertex_index < reshape_smooth_context->geometry.num_vertices); + + const Vertex *vertex = &reshape_smooth_context->geometry.vertices[vertex_index]; + return vertex->sharpness; +} + static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter, int vertex_index) { const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data; @@ -1048,7 +1096,7 @@ static void converter_init(const MultiresReshapeSmoothContext *reshape_smooth_co converter->getNumVertexFaces = NULL; converter->getVertexFaces = NULL; converter->isInfiniteSharpVertex = is_infinite_sharp_vertex; - converter->getVertexSharpness = NULL; + converter->getVertexSharpness = get_vertex_sharpness; converter->getNumUVLayers = NULL; converter->precalcUVLayer = NULL; diff --git a/source/blender/blenkernel/intern/multires_reshape_util.c b/source/blender/blenkernel/intern/multires_reshape_util.c index dfd8fc7e2ed..4f69b1014a0 100644 --- a/source/blender/blenkernel/intern/multires_reshape_util.c +++ b/source/blender/blenkernel/intern/multires_reshape_util.c @@ -211,6 +211,8 @@ bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape reshape_context->top.level = mmd->totlvl; reshape_context->top.grid_size = BKE_subdiv_grid_size_from_level(reshape_context->top.level); + reshape_context->cd_vertex_crease = CustomData_get_layer(&base_mesh->vdata, CD_CREASE); + context_init_commoon(reshape_context); return context_verify_or_free(reshape_context); diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 8c6bdb13708..1acd4248639 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -4746,6 +4746,7 @@ static void registerGeometryNodes() register_node_type_geo_curve_fillet(); register_node_type_geo_curve_handle_type_selection(); register_node_type_geo_curve_length(); + register_node_type_geo_curve_primitive_arc(); register_node_type_geo_curve_primitive_bezier_segment(); register_node_type_geo_curve_primitive_circle(); register_node_type_geo_curve_primitive_line(); @@ -4767,6 +4768,8 @@ static void registerGeometryNodes() register_node_type_geo_distribute_points_on_faces(); register_node_type_geo_dual_mesh(); register_node_type_geo_edge_split(); + register_node_type_geo_field_at_index(); + register_node_type_geo_flip_faces(); register_node_type_geo_geometry_to_instance(); register_node_type_geo_image_texture(); register_node_type_geo_input_curve_handles(); @@ -4822,6 +4825,7 @@ static void registerGeometryNodes() register_node_type_geo_realize_instances(); register_node_type_geo_rotate_instances(); register_node_type_geo_sample_texture(); + register_node_type_geo_scale_elements(); register_node_type_geo_scale_instances(); register_node_type_geo_separate_components(); register_node_type_geo_separate_geometry(); diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index de222892fb8..2576b0fd6dc 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -1742,6 +1742,7 @@ static void sculpt_update_object(Depsgraph *depsgraph, ss->totvert = me->totvert; ss->totpoly = me->totpoly; ss->totfaces = me->totpoly; + ss->vert_normals = BKE_mesh_vertex_normals_ensure(me); ss->mvert = me->mvert; ss->medge = me->medge; ss->mpoly = me->mpoly; diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 208ceeacb44..d8dc5fe0a50 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -3607,7 +3607,6 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m vi->mask = NULL; if (pbvh->type == PBVH_FACES) { - /* Cast away const because sculpt/paint code can adjust normals when restoring mesh data. */ vi->vert_normals = pbvh->vert_normals; vi->vmask = CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK); diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 38575f3048f..602546db8df 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -831,31 +831,23 @@ static void ptcache_rigidbody_interpolate(int index, RigidBodyOb *rbo = ob->rigidbody_object; if (rbo->type == RBO_TYPE_ACTIVE) { - ParticleKey keys[4]; - ParticleKey result; - float dfra; - - memset(keys, 0, sizeof(keys)); - - copy_v3_v3(keys[1].co, rbo->pos); - copy_qt_qt(keys[1].rot, rbo->orn); + /* It may be possible to improve results by taking into account velocity + * for interpolation using psys_interpolate_particle, however this is + * not currently cached. */ + float pos[3], orn[4]; if (old_data) { - memcpy(keys[2].co, data, sizeof(float[3])); - memcpy(keys[2].rot, data + 3, sizeof(float[4])); + memcpy(pos, data, sizeof(float[3])); + memcpy(orn, data + 3, sizeof(float[4])); } else { - BKE_ptcache_make_particle_key(&keys[2], 0, data, cfra2); + PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, index, pos); + PTCACHE_DATA_TO(data, BPHYS_DATA_ROTATION, index, orn); } - dfra = cfra2 - cfra1; - - /* NOTE: keys[0] and keys[3] unused for type < 1 (crappy). */ - psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, &result, true); - interp_qt_qtqt(result.rot, keys[1].rot, keys[2].rot, (cfra - cfra1) / dfra); - - copy_v3_v3(rbo->pos, result.co); - copy_qt_qt(rbo->orn, result.rot); + const float t = (cfra - cfra1) / (cfra2 - cfra1); + interp_v3_v3v3(rbo->pos, rbo->pos, pos, t); + interp_qt_qtqt(rbo->orn, rbo->orn, orn, t); } } } diff --git a/source/blender/blenkernel/intern/spline_nurbs.cc b/source/blender/blenkernel/intern/spline_nurbs.cc index 719ba4b7ecd..5993b9a9a27 100644 --- a/source/blender/blenkernel/intern/spline_nurbs.cc +++ b/source/blender/blenkernel/intern/spline_nurbs.cc @@ -179,65 +179,35 @@ int NURBSpline::knots_size() const void NURBSpline::calculate_knots() const { const KnotsMode mode = this->knots_mode; - const int length = this->size(); const int order = order_; + const bool is_bezier = mode == NURBSpline::KnotsMode::Bezier; + const bool is_end_point = mode == NURBSpline::KnotsMode::EndPoint; + /* Inner knots are always repeated once except on Bezier case. */ + const int repeat_inner = is_bezier ? order - 1 : 1; + /* How many times to repeat 0.0 at the beginning of knot. */ + const int head = is_end_point && !is_cyclic_ ? order : (is_bezier ? order / 2 : 1); + /* Number of knots replicating widths of the starting knots. + * Covers both Cyclic and EndPoint cases. */ + const int tail = is_cyclic_ ? 2 * order - 1 : (is_end_point ? order : 0); knots_.resize(this->knots_size()); - MutableSpan knots = knots_; - if (mode == NURBSpline::KnotsMode::Normal || is_cyclic_) { - for (const int i : knots.index_range()) { - knots[i] = static_cast(i); - } - } - else if (mode == NURBSpline::KnotsMode::EndPoint) { - float k = 0.0f; - for (const int i : IndexRange(1, knots.size())) { - knots[i - 1] = k; - if (i >= order && i <= length) { - k += 1.0f; - } - } - } - else if (mode == NURBSpline::KnotsMode::Bezier) { - BLI_assert(ELEM(order, 3, 4)); - if (order == 3) { - float k = 0.6f; - for (const int i : knots.index_range()) { - if (i >= order && i <= length) { - k += 0.5f; - } - knots[i] = std::floor(k); - } - } - else { - float k = 0.34f; - for (const int i : knots.index_range()) { - knots[i] = std::floor(k); - k += 1.0f / 3.0f; - } + int r = head; + float current = 0.0f; + + for (const int i : IndexRange(knots.size() - tail)) { + knots[i] = current; + r--; + if (r == 0) { + current += 1.0; + r = repeat_inner; } } - if (is_cyclic_) { - const int b = length + order - 1; - if (order > 2) { - for (const int i : IndexRange(1, order - 2)) { - if (knots[b] != knots[b - i]) { - if (i == order - 1) { - knots[length + order - 2] += 1.0f; - break; - } - } - } - } - - int c = order; - for (int i = b; i < this->knots_size(); i++) { - knots[i] = knots[i - 1] + (knots[c] - knots[c - 1]); - c--; - } + const int tail_index = knots.size() - tail; + for (const int i : IndexRange(tail)) { + knots[tail_index + i] = current + (knots[i] - knots[0]); } } diff --git a/source/blender/blenkernel/intern/subdiv_converter_mesh.c b/source/blender/blenkernel/intern/subdiv_converter_mesh.c index 41fc28c5d52..fc7ef887879 100644 --- a/source/blender/blenkernel/intern/subdiv_converter_mesh.c +++ b/source/blender/blenkernel/intern/subdiv_converter_mesh.c @@ -40,6 +40,8 @@ #include "opensubdiv_capi.h" #include "opensubdiv_converter_capi.h" +#include "bmesh_class.h" + /* Enable work-around for non-working CPU evaluator when using bilinear scheme. * This forces Catmark scheme with all edges marked as infinitely sharp. */ #define BUGGY_SIMPLE_SCHEME_WORKAROUND 1 @@ -47,6 +49,8 @@ typedef struct ConverterStorage { SubdivSettings settings; const Mesh *mesh; + /* CustomData layer for vertex sharpnesses. */ + const float *cd_vertex_crease; /* Indexed by loop index, value denotes index of face-varying vertex * which corresponds to the UV coordinate. */ @@ -168,7 +172,7 @@ static float get_edge_sharpness(const OpenSubdiv_Converter *converter, int manif } const int edge_index = storage->manifold_edge_index_reverse[manifold_edge_index]; const MEdge *medge = storage->mesh->medge; - return BKE_subdiv_edge_crease_to_sharpness_char(medge[edge_index].crease); + return BKE_subdiv_crease_to_sharpness_char(medge[edge_index].crease); } static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter, @@ -184,14 +188,14 @@ static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter, return BLI_BITMAP_TEST_BOOL(storage->infinite_sharp_vertices_map, vertex_index); } -static float get_vertex_sharpness(const OpenSubdiv_Converter *converter, - int UNUSED(manifold_vertex_index)) +static float get_vertex_sharpness(const OpenSubdiv_Converter *converter, int manifold_vertex_index) { ConverterStorage *storage = converter->user_data; - if (!storage->settings.use_creases) { + if (!storage->settings.use_creases || storage->cd_vertex_crease == NULL) { return 0.0f; } - return 0.0f; + const int vertex_index = storage->manifold_vertex_index_reverse[manifold_vertex_index]; + return BKE_subdiv_crease_to_sharpness_f(storage->cd_vertex_crease[vertex_index]); } static int get_num_uv_layers(const OpenSubdiv_Converter *converter) @@ -393,6 +397,7 @@ static void init_user_data(OpenSubdiv_Converter *converter, ConverterStorage *user_data = MEM_mallocN(sizeof(ConverterStorage), __func__); user_data->settings = *settings; user_data->mesh = mesh; + user_data->cd_vertex_crease = CustomData_get_layer(&mesh->vdata, CD_CREASE); user_data->loop_uv_indices = NULL; initialize_manifold_indices(user_data); converter->user_data = user_data; diff --git a/source/blender/blenkernel/intern/subdiv_inline.h b/source/blender/blenkernel/intern/subdiv_inline.h index ba45d0a4997..d52adff1e61 100644 --- a/source/blender/blenkernel/intern/subdiv_inline.h +++ b/source/blender/blenkernel/intern/subdiv_inline.h @@ -103,13 +103,13 @@ BLI_INLINE void BKE_subdiv_rotate_grid_to_quad( } } -BLI_INLINE float BKE_subdiv_edge_crease_to_sharpness_f(float edge_crease) +BLI_INLINE float BKE_subdiv_crease_to_sharpness_f(float edge_crease) { return edge_crease * edge_crease * 10.0f; } -BLI_INLINE float BKE_subdiv_edge_crease_to_sharpness_char(char edge_crease) +BLI_INLINE float BKE_subdiv_crease_to_sharpness_char(char edge_crease) { const float edge_crease_f = edge_crease / 255.0f; - return BKE_subdiv_edge_crease_to_sharpness_f(edge_crease_f); + return BKE_subdiv_crease_to_sharpness_f(edge_crease_f); } diff --git a/source/blender/blenkernel/intern/subdiv_modifier.c b/source/blender/blenkernel/intern/subdiv_modifier.c index bafcb631f59..65809782f8f 100644 --- a/source/blender/blenkernel/intern/subdiv_modifier.c +++ b/source/blender/blenkernel/intern/subdiv_modifier.c @@ -124,8 +124,6 @@ bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene, void (*BKE_subsurf_modifier_free_gpu_cache_cb)(Subdiv *subdiv) = NULL; -/* Main goal of this function is to give usable subdivision surface descriptor - * which matches settings and topology. */ Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(const SubsurfModifierData *smd, const SubdivSettings *subdiv_settings, const Mesh *mesh, diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc index c17706dc216..39a7725bfa3 100644 --- a/source/blender/blenkernel/intern/volume.cc +++ b/source/blender/blenkernel/intern/volume.cc @@ -138,11 +138,19 @@ static struct VolumeFileCache { } std::lock_guard lock(mutex); - return simplified_grids.lookup_or_add_cb(simplify_level, [&]() { - const float resolution_factor = 1.0f / (1 << simplify_level); - const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(*grid); - return BKE_volume_grid_create_with_changed_resolution(grid_type, *grid, resolution_factor); + openvdb::GridBase::Ptr simple_grid; + + /* Isolate creating grid since that's multithreaded and we are + * holding a mutex lock. */ + blender::threading::isolate_task([&] { + simple_grid = simplified_grids.lookup_or_add_cb(simplify_level, [&]() { + const float resolution_factor = 1.0f / (1 << simplify_level); + const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(*grid); + return BKE_volume_grid_create_with_changed_resolution( + grid_type, *grid, resolution_factor); + }); }); + return simple_grid; } /* Unique key: filename + grid name. */ @@ -247,16 +255,20 @@ static struct VolumeFileCache { protected: void update_for_remove_user(Entry &entry) { - if (entry.num_metadata_users + entry.num_tree_users == 0) { - cache.erase(entry); - } - else if (entry.num_tree_users == 0) { - /* Note we replace the grid rather than clearing, so that if there is - * any other shared pointer to the grid it will keep the tree. */ - entry.grid = entry.grid->copyGridWithNewTree(); - entry.simplified_grids.clear(); - entry.is_loaded = false; - } + /* Isolate file unloading since that's multithreaded and we are + * holding a mutex lock. */ + blender::threading::isolate_task([&] { + if (entry.num_metadata_users + entry.num_tree_users == 0) { + cache.erase(entry); + } + else if (entry.num_tree_users == 0) { + /* Note we replace the grid rather than clearing, so that if there is + * any other shared pointer to the grid it will keep the tree. */ + entry.grid = entry.grid->copyGridWithNewTree(); + entry.simplified_grids.clear(); + entry.is_loaded = false; + } + }); } /* Cache contents */ @@ -1544,11 +1556,6 @@ bool BKE_volume_grid_bounds(openvdb::GridBase::ConstPtr grid, float3 &r_min, flo return true; } -/** - * Return a new grid pointer with only the metadata and transform changed. - * This is useful for instances, where there is a separate transform on top of the original - * grid transform that must be applied for some operations that only take a grid argument. - */ openvdb::GridBase::ConstPtr BKE_volume_grid_shallow_transform(openvdb::GridBase::ConstPtr grid, const blender::float4x4 &transform) { diff --git a/source/blender/blenkernel/intern/volume_to_mesh.cc b/source/blender/blenkernel/intern/volume_to_mesh.cc index 733549c0022..336ce724e35 100644 --- a/source/blender/blenkernel/intern/volume_to_mesh.cc +++ b/source/blender/blenkernel/intern/volume_to_mesh.cc @@ -121,11 +121,6 @@ struct VolumeToMeshOp { } }; -/** - * Convert mesh data from the format provided by OpenVDB into Blender's #Mesh data structure. - * This can be used to add mesh data from a grid into an existing mesh rather than merging multiple - * meshes later on. - */ void fill_mesh_from_openvdb_data(const Span vdb_verts, const Span vdb_tris, const Span vdb_quads, @@ -165,10 +160,6 @@ void fill_mesh_from_openvdb_data(const Span vdb_verts, } } -/** - * Convert an OpenVDB volume grid to corresponding mesh data: vertex positions and quad and - * triangle indices. - */ bke::OpenVDBMeshData volume_to_mesh_data(const openvdb::GridBase &grid, const VolumeToMeshResolution &resolution, const float threshold, diff --git a/source/blender/blenlib/BLI_math_vector.hh b/source/blender/blenlib/BLI_math_vector.hh index e7d765df842..1d60447445e 100644 --- a/source/blender/blenlib/BLI_math_vector.hh +++ b/source/blender/blenlib/BLI_math_vector.hh @@ -365,6 +365,11 @@ template inline T interpolate(const T &a, return a * (1 - t) + b * t; } +template inline T midpoint(const T &a, const T &b) +{ + return (a + b) * 0.5; +} + template inline T faceforward(const T &vector, const T &incident, const T &reference) { diff --git a/source/blender/blenlib/BLI_vector_set.hh b/source/blender/blenlib/BLI_vector_set.hh index cc9cb585a1c..0aac96f93bc 100644 --- a/source/blender/blenlib/BLI_vector_set.hh +++ b/source/blender/blenlib/BLI_vector_set.hh @@ -464,6 +464,14 @@ class VectorSet { return keys_ + this->size(); } + /** + * Get an index range containing all valid indices for this array. + */ + IndexRange index_range() const + { + return IndexRange(this->size()); + } + /** * Print common statistics like size and collision count. This is useful for debugging purposes. */ diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c index 53cf2d61963..cfcc54b1136 100644 --- a/source/blender/blenlib/intern/math_base_inline.c +++ b/source/blender/blenlib/intern/math_base_inline.c @@ -398,7 +398,7 @@ MINLINE float fractf(float a) return a - floorf(a); } -/* Adapted from godot-engine math_funcs.h. */ +/* Adapted from `godot-engine` math_funcs.h. */ MINLINE float wrapf(float value, float max, float min) { float range = max - min; @@ -722,15 +722,15 @@ MINLINE int integer_digits_i(const int i) #ifdef BLI_HAVE_SSE2 -/* Calculate initial guess for arg^exp based on float representation +/** + * Calculate initial guess for `arg^exp` based on float representation * This method gives a constant bias, which can be easily compensated by * multiplying with bias_coeff. - * Gives better results for exponents near 1 (e. g. 4/5). + * Gives better results for exponents near 1 (e.g. `4/5`). * exp = exponent, encoded as uint32_t - * e2coeff = 2^(127/exponent - 127) * bias_coeff^(1/exponent), encoded as - * uint32_t + * `e2coeff = 2^(127/exponent - 127) * bias_coeff^(1/exponent)`, encoded as `uint32_t`. * - * We hope that exp and e2coeff gets properly inlined + * We hope that exp and e2coeff gets properly inlined. */ MALWAYS_INLINE __m128 _bli_math_fastpow(const int exp, const int e2coeff, const __m128 arg) { @@ -742,7 +742,7 @@ MALWAYS_INLINE __m128 _bli_math_fastpow(const int exp, const int e2coeff, const return ret; } -/* Improve x ^ 1.0f/5.0f solution with Newton-Raphson method */ +/** Improve `x ^ 1.0f/5.0f` solution with Newton-Raphson method */ MALWAYS_INLINE __m128 _bli_math_improve_5throot_solution(const __m128 old_result, const __m128 x) { __m128 approx2 = _mm_mul_ps(old_result, old_result); @@ -752,7 +752,7 @@ MALWAYS_INLINE __m128 _bli_math_improve_5throot_solution(const __m128 old_result return _mm_mul_ps(summ, _mm_set1_ps(1.0f / 5.0f)); } -/* Calculate powf(x, 2.4). Working domain: 1e-10 < x < 1e+10 */ +/** Calculate `powf(x, 2.4)`. Working domain: `1e-10 < x < 1e+10`. */ MALWAYS_INLINE __m128 _bli_math_fastpow24(const __m128 arg) { /* max, avg and |avg| errors were calculated in gcc without FMA instructions diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index a155877513a..3800fc58a5b 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -3720,7 +3720,7 @@ void barycentric_weights_v2_quad(const float v1[2], /* NOTE(campbell): fabsf() here is not needed for convex quads * (and not used in #interp_weights_poly_v2). * But in the case of concave/bow-tie quads for the mask rasterizer it - * gives unreliable results without adding absf(). If this becomes an issue for more general + * gives unreliable results without adding `absf()`. If this becomes an issue for more general * usage we could have this optional or use a different function. */ #define MEAN_VALUE_HALF_TAN_V2(_area, i1, i2) \ ((_area = cross_v2v2(dirs[i1], dirs[i2])) != 0.0f ? \ diff --git a/source/blender/blenlib/intern/timecode.c b/source/blender/blenlib/intern/timecode.c index 55131fa639d..14adab8648b 100644 --- a/source/blender/blenlib/intern/timecode.c +++ b/source/blender/blenlib/intern/timecode.c @@ -49,7 +49,7 @@ size_t BLI_timecode_string_from_time(char *str, /* get cframes */ if (time < 0) { - /* correction for negative cfraues */ + /* Correction for negative cframes. */ neg[0] = '-'; time = -time; } diff --git a/source/blender/blenlib/tests/BLI_any_test.cc b/source/blender/blenlib/tests/BLI_any_test.cc index 3a5cbee6d72..dc72affd610 100644 --- a/source/blender/blenlib/tests/BLI_any_test.cc +++ b/source/blender/blenlib/tests/BLI_any_test.cc @@ -54,7 +54,7 @@ TEST(any, AssignMap) Any<> c = std::move(a); /* Test valid state after self assignment. Clang emits `-Wself-assign-overloaded` with `c=c;`. - * And pragma suppression creates warnings on other compilers. */ + * And `pragma` suppression creates warnings on other compilers. */ c = static_cast(c); EXPECT_TRUE(c); EXPECT_EQ((c.get>().lookup(4)), 2); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index f325cec31fd..38f2d8bb22c 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2544,7 +2544,6 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map, else if (sl->spacetype == SPACE_FILE) { SpaceFile *sfile = (SpaceFile *)sl; sfile->op = NULL; - sfile->previews_timer = NULL; sfile->tags = FILE_TAG_REBUILD_MAIN_FILES; } else if (sl->spacetype == SPACE_ACTION) { diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index bee8bb757e4..52737950ea3 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -856,10 +856,9 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) if (!ts->uv_selectmode || ts->vgroup_weight == 0.0f) { ts->selectmode = SCE_SELECT_VERTEX; - /* autokeying - setting should be taken from the user-prefs - * but the userprefs version may not have correct flags set - * (i.e. will result in blank box when enabled) - */ + /* The auto-keying setting should be taken from the user-preferences + * but the user-preferences version may not have correct flags set + * (i.e. will result in blank box when enabled). */ ts->autokey_mode = U.autokey_mode; if (ts->autokey_mode == 0) { ts->autokey_mode = 2; /* 'add/replace' but not on */ diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index 6ccf78cfbf3..56d2de0419a 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -2612,11 +2612,15 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } - /* Rename geometry socket on "String to Curves" node and "Transfer Attribute" node. */ + /* Rename sockets on multiple nodes */ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { if (ntree->type == NTREE_GEOMETRY) { version_node_output_socket_name( ntree, GEO_NODE_STRING_TO_CURVES, "Curves", "Curve Instances"); + version_node_output_socket_name( + ntree, GEO_NODE_INPUT_MESH_EDGE_ANGLE, "Angle", "Unsigned Angle"); + version_node_output_socket_name( + ntree, GEO_NODE_INPUT_MESH_ISLAND, "Index", "Island Index"); version_node_input_socket_name(ntree, GEO_NODE_TRANSFER_ATTRIBUTE, "Target", "Source"); } } diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index 2fceb42262e..94720ad0b0a 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -1859,7 +1859,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain) if (bmain->subversionfile < 4) { for (sce = bmain->scenes.first; sce; sce = sce->id.next) { sce->r.bake_mode = 1; /* prevent to include render stuff here */ - sce->r.bake_filter = 16; + sce->r.bake_margin = 16; + sce->r.bake_margin_type = R_BAKE_ADJACENT_FACES; sce->r.bake_flag = R_BAKE_CLEAR; } } diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index feb1bcd8e00..0739e2ac766 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -606,8 +606,8 @@ void blo_do_versions_userdef(UserDef *userdef) } if (!USER_VERSION_ATLEAST(257, 0)) { - /* clear "AUTOKEY_FLAG_ONLYKEYINGSET" flag from userprefs, - * so that it doesn't linger around from old configs like a ghost */ + /* Clear #AUTOKEY_FLAG_ONLYKEYINGSET flag from user-preferences, + * so that it doesn't linger around from old configurations like a ghost. */ userdef->autokey_flag &= ~AUTOKEY_FLAG_ONLYKEYINGSET; } diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt index 7d00553c911..e738e9f43e0 100644 --- a/source/blender/bmesh/CMakeLists.txt +++ b/source/blender/bmesh/CMakeLists.txt @@ -98,9 +98,11 @@ set(SRC intern/bmesh_marking.h intern/bmesh_mesh.c intern/bmesh_mesh.h - intern/bmesh_mesh_convert.c intern/bmesh_mesh_convert_threaded.c + intern/bmesh_mesh_convert.cc intern/bmesh_mesh_convert.h + intern/bmesh_mesh_debug.c + intern/bmesh_mesh_debug.h intern/bmesh_mesh_duplicate.c intern/bmesh_mesh_duplicate.h intern/bmesh_mesh_normals.c diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h index 40db423ba2f..fc97c55091a 100644 --- a/source/blender/bmesh/bmesh.h +++ b/source/blender/bmesh/bmesh.h @@ -214,6 +214,7 @@ extern "C" { #include "intern/bmesh_marking.h" #include "intern/bmesh_mesh.h" #include "intern/bmesh_mesh_convert.h" +#include "intern/bmesh_mesh_debug.h" #include "intern/bmesh_mesh_duplicate.h" #include "intern/bmesh_mesh_normals.h" #include "intern/bmesh_mesh_partial_update.h" diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index c7853071b0b..2ad78067331 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -883,23 +883,51 @@ static BMFace *bm_mesh_copy_new_face( return f_new; } -void BM_mesh_copy_init_customdata_from_mesh(BMesh *bm_dst, - const Mesh *me_src, - const BMAllocTemplate *allocsize) +void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst, + const Mesh *me_src_array[], + const int me_src_array_len, + const BMAllocTemplate *allocsize) + { if (allocsize == NULL) { allocsize = &bm_mesh_allocsize_default; } - CustomData_copy(&me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0); - CustomData_copy(&me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0); - CustomData_copy(&me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0); - CustomData_copy(&me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0); + char cd_flag = 0; + + for (int i = 0; i < me_src_array_len; i++) { + const Mesh *me_src = me_src_array[i]; + if (i == 0) { + CustomData_copy(&me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0); + CustomData_copy(&me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0); + CustomData_copy(&me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0); + CustomData_copy(&me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0); + } + else { + CustomData_merge(&me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0); + CustomData_merge(&me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0); + CustomData_merge(&me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0); + CustomData_merge(&me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0); + } + + cd_flag |= me_src->cd_flag; + } + + cd_flag |= BM_mesh_cd_flag_from_bmesh(bm_dst); CustomData_bmesh_init_pool(&bm_dst->vdata, allocsize->totvert, BM_VERT); CustomData_bmesh_init_pool(&bm_dst->edata, allocsize->totedge, BM_EDGE); CustomData_bmesh_init_pool(&bm_dst->ldata, allocsize->totloop, BM_LOOP); CustomData_bmesh_init_pool(&bm_dst->pdata, allocsize->totface, BM_FACE); + + BM_mesh_cd_flag_apply(bm_dst, cd_flag); +} + +void BM_mesh_copy_init_customdata_from_mesh(BMesh *bm_dst, + const Mesh *me_src, + const BMAllocTemplate *allocsize) +{ + BM_mesh_copy_init_customdata_from_mesh_array(bm_dst, &me_src, 1, allocsize); } void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTemplate *allocsize) diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h index 7e4d0f8b643..3d5d7202459 100644 --- a/source/blender/bmesh/intern/bmesh_construct.h +++ b/source/blender/bmesh/intern/bmesh_construct.h @@ -146,6 +146,19 @@ void BM_elem_attrs_copy_ex(BMesh *bm_src, void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v); void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v); +/** + * Initialize the `bm_dst` layers in preparation for populating it's contents with multiple meshes. + * Typically done using multiple calls to #BM_mesh_bm_from_me with the same `bm` argument). + * + * \note While the custom-data layers of all meshes are created, the active layers are set + * by the first instance mesh containing that layer type. + * This means the first mesh should always be the main mesh (from the user perspective), + * as this is the mesh they have control over (active UV layer for rendering for example). + */ +void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst, + const struct Mesh *me_src_array[], + int me_src_array_len, + const struct BMAllocTemplate *allocsize); void BM_mesh_copy_init_customdata_from_mesh(BMesh *bm_dst, const struct Mesh *me_src, const struct BMAllocTemplate *allocsize); diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c index a195ab834fb..6175aa85c14 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.c +++ b/source/blender/bmesh/intern/bmesh_mesh.c @@ -1191,7 +1191,7 @@ void BM_mesh_remap(BMesh *bm, /* Edges' pointers, only vert pointers (as we don't mess with loops!), * and - ack! - edge pointers, - * as we have to handle disklinks... */ + * as we have to handle disk-links. */ if (vptr_map || eptr_map) { BM_ITER_MESH (ed, &iter, bm, BM_EDGES_OF_MESH) { if (vptr_map) { diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.c b/source/blender/bmesh/intern/bmesh_mesh_convert.c deleted file mode 100644 index 8b8938ed261..00000000000 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.c +++ /dev/null @@ -1,1671 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup bmesh - * - * BM mesh conversion functions. - * - * \section bm_mesh_conv_shapekey Converting Shape Keys - * - * When converting to/from a Mesh/BMesh you can optionally pass a shape key to edit. - * This has the effect of editing the shape key-block rather than the original mesh vertex coords - * (although additional geometry is still allowed and uses fallback locations on converting). - * - * While this works for any mesh/bmesh this is made use of by entering and exiting edit-mode. - * - * There are comments in code but this should help explain the general - * intention as to how this works converting from/to bmesh. - * \subsection user_pov User Perspective - * - * - Editmode operations when a shape key-block is active edits only that key-block. - * - The first Basis key-block always matches the Mesh verts. - * - Changing vertex locations of _any_ Basis - * will apply offsets to those shape keys using this as their Basis. - * - * \subsection enter_editmode Entering EditMode - #BM_mesh_bm_from_me - * - * - The active key-block is used for BMesh vertex locations on entering edit-mode. - * So obviously the meshes vertex locations remain unchanged and the shape key - * its self is not being edited directly. - * Simply the #BMVert.co is a initialized from active shape key (when its set). - * - All key-blocks are added as CustomData layers (read code for details). - * - * \subsection exit_editmode Exiting EditMode - #BM_mesh_bm_to_me - * - * This is where the most confusing code is! Won't attempt to document the details here, - * for that read the code. - * But basics are as follows. - * - * - Vertex locations (possibly modified from initial active key-block) - * are copied directly into #MVert.co - * (special confusing note that these may be restored later, when editing the 'Basis', read on). - * - if the 'Key' is relative, and the active key-block is the basis for ANY other key-blocks - - * get an array of offsets between the new vertex locations and the original shape key - * (before entering edit-mode), these offsets get applied later on to inactive key-blocks - * using the active one (which we are editing) as their Basis. - * - * Copying the locations back to the shape keys is quite confusing... - * One main area of confusion is that when editing a 'Basis' key-block 'me->key->refkey' - * The coords are written into the mesh, from the users perspective the Basis coords are written - * into the mesh when exiting edit-mode. - * - * When _not_ editing the 'Basis', the original vertex locations - * (stored in the mesh and unchanged during edit-mode), are copied back into the mesh. - * - * This has the effect from the users POV of leaving the mesh un-touched, - * and only editing the active shape key-block. - */ - -#include "DNA_key_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_modifier_types.h" -#include "DNA_object_types.h" - -#include "MEM_guardedalloc.h" - -#include "BLI_alloca.h" -#include "BLI_array.h" -#include "BLI_listbase.h" -#include "BLI_math_vector.h" - -#include "BKE_customdata.h" -#include "BKE_mesh.h" -#include "BKE_mesh_runtime.h" -#include "BKE_multires.h" - -#include "BKE_key.h" -#include "BKE_main.h" - -#include "DEG_depsgraph_query.h" - -#include "bmesh.h" -#include "intern/bmesh_private.h" /* For element checking. */ -#include "range_tree.h" - -static void bm_free_cd_pools(BMesh *bm) -{ - if (bm->vdata.pool) { - BLI_mempool_destroy(bm->vdata.pool); - } - if (bm->edata.pool) { - BLI_mempool_destroy(bm->edata.pool); - } - if (bm->ldata.pool) { - BLI_mempool_destroy(bm->ldata.pool); - } - if (bm->pdata.pool) { - BLI_mempool_destroy(bm->pdata.pool); - } -} - -//#define bm_assign_id(a, b, c, d) -//#define bm_alloc_id(a, b) - -static void bm_unmark_temp_cdlayers(BMesh *bm) -{ - CustomData_unmark_temporary_nocopy(&bm->vdata); - CustomData_unmark_temporary_nocopy(&bm->edata); - CustomData_unmark_temporary_nocopy(&bm->ldata); - CustomData_unmark_temporary_nocopy(&bm->pdata); -} - -static void bm_mark_temp_cdlayers(BMesh *bm) -{ - CustomData_mark_temporary_nocopy(&bm->vdata); - CustomData_mark_temporary_nocopy(&bm->edata); - CustomData_mark_temporary_nocopy(&bm->ldata); - CustomData_mark_temporary_nocopy(&bm->pdata); -} - -#if 0 -# define CustomData_to_bmesh_block(srcdata, destdata, i, block, set_default) \ - { \ - CustomDataLayer *cl = (srcdata)->layers, *cl2 = (destdata)->layers; \ - int size = 0; \ - if (!*block) { \ - *block = BLI_mempool_alloc((destdata)->pool); \ - } \ - for (int j = 0; j < (srcdata)->totlayer; j++, cl++) { \ - if ((destdata)->typemap[cl->type] < 0) { \ - continue; \ - } \ - while (cl2->type != cl->type) { \ - cl2++; \ - } \ - char *ptr = (char *)cl->data; \ - size = cl2 != (destdata)->layers ? cl2->offset - (cl2 - 1)->offset : cl2->offset; \ - ptr += size * i; \ - char *ptr2 = (char *)*block; \ - ptr2 += cl2->offset; \ - memcpy(ptr2, ptr, size); \ - cl2++; \ - } \ - } -#endif - -void BM_mesh_cd_flag_ensure(BMesh *bm, Mesh *mesh, const char cd_flag) -{ - const char cd_flag_all = BM_mesh_cd_flag_from_bmesh(bm) | cd_flag; - BM_mesh_cd_flag_apply(bm, cd_flag_all); - if (mesh) { - mesh->cd_flag = cd_flag_all; - } -} - -void BM_mesh_cd_flag_apply(BMesh *bm, const char cd_flag) -{ - /* CustomData_bmesh_init_pool() must run first */ - BLI_assert(bm->vdata.totlayer == 0 || bm->vdata.pool != NULL); - BLI_assert(bm->edata.totlayer == 0 || bm->edata.pool != NULL); - BLI_assert(bm->pdata.totlayer == 0 || bm->pdata.pool != NULL); - - if (cd_flag & ME_CDFLAG_VERT_BWEIGHT) { - if (!CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) { - BM_data_layer_add(bm, &bm->vdata, CD_BWEIGHT); - } - } - else { - if (CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) { - BM_data_layer_free(bm, &bm->vdata, CD_BWEIGHT); - } - } - - if (cd_flag & ME_CDFLAG_EDGE_BWEIGHT) { - if (!CustomData_has_layer(&bm->edata, CD_BWEIGHT)) { - BM_data_layer_add(bm, &bm->edata, CD_BWEIGHT); - } - } - else { - if (CustomData_has_layer(&bm->edata, CD_BWEIGHT)) { - BM_data_layer_free(bm, &bm->edata, CD_BWEIGHT); - } - } - - if (cd_flag & ME_CDFLAG_EDGE_CREASE) { - if (!CustomData_has_layer(&bm->edata, CD_CREASE)) { - BM_data_layer_add(bm, &bm->edata, CD_CREASE); - } - } - else { - if (CustomData_has_layer(&bm->edata, CD_CREASE)) { - BM_data_layer_free(bm, &bm->edata, CD_CREASE); - } - } -} - -char BM_mesh_cd_flag_from_bmesh(BMesh *bm) -{ - char cd_flag = 0; - if (CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) { - cd_flag |= ME_CDFLAG_VERT_BWEIGHT; - } - if (CustomData_has_layer(&bm->edata, CD_BWEIGHT)) { - cd_flag |= ME_CDFLAG_EDGE_BWEIGHT; - } - if (CustomData_has_layer(&bm->edata, CD_CREASE)) { - cd_flag |= ME_CDFLAG_EDGE_CREASE; - } - - return cd_flag; -} - -/* Static function for alloc (duplicate in modifiers_bmesh.c) */ -static BMFace *bm_face_create_from_mpoly( - MPoly *mp, MLoop *ml, BMesh *bm, BMVert **vtable, BMEdge **etable) -{ - BMVert **verts = BLI_array_alloca(verts, mp->totloop); - BMEdge **edges = BLI_array_alloca(edges, mp->totloop); - int j; - - for (j = 0; j < mp->totloop; j++, ml++) { - verts[j] = vtable[ml->v]; - edges[j] = etable[ml->e]; - } - - return BM_face_create( - bm, verts, edges, mp->totloop, NULL, BM_CREATE_SKIP_CD | BM_CREATE_SKIP_ID); -} - -void BM_enter_multires_space(Object *ob, BMesh *bm, int space) -{ - if (!bm->haveMultiResSettings && ob) { - MultiresModifierData *mmd = get_multires_modifier(NULL, ob, true); - if (mmd) { - bm->multires = *mmd; - bm->haveMultiResSettings = true; - bm->multiresSpace = MULTIRES_SPACE_TANGENT; - } - } - - if (!bm->haveMultiResSettings || !CustomData_has_layer(&bm->ldata, CD_MDISPS) || - space == bm->multiresSpace) { - return; - } - - BKE_multires_bmesh_space_set(ob, bm, space); - bm->multiresSpace = space; -} - -#include "BLI_compiler_attrs.h" - -/** - * \brief Mesh -> BMesh - * \param ob: object that owns bm, may be NULL (which will disable multires space change) - * \param bm: The mesh to write into, while this is typically a newly created BMesh, - * merging into existing data is supported. - * Note the custom-data layout isn't used. - * If more comprehensive merging is needed we should move this into a separate function - * since this should be kept fast for edit-mode switching and storing undo steps. - * - * \warning This function doesn't calculate face normals. - * - * Mesh IDs will be imported unless requested. If the bmesh was created - * with id map enabled then IDs will be checked for uniqueness, otherwise - * they are imported as is. - */ - -void BM_mesh_bm_from_me(Object *ob, - BMesh *bm, - const Mesh *me, - const struct BMeshFromMeshParams *params) -{ - const bool is_new = !(bm->totvert || (bm->vdata.totlayer || bm->edata.totlayer || - bm->pdata.totlayer || bm->ldata.totlayer)); - MVert *mvert; - MEdge *medge; - MLoop *mloop; - MPoly *mp; - KeyBlock *actkey, *block; - BMVert *v, **vtable = NULL; - BMEdge *e, **etable = NULL; - BMFace *f, **ftable = NULL; - float(*keyco)[3] = NULL; - int totloops, i; - CustomData_MeshMasks mask = CD_MASK_BMESH; - CustomData_MeshMasks_update(&mask, ¶ms->cd_mask_extra); - - MultiresModifierData *mmd = ob ? get_multires_modifier(NULL, ob, true) : NULL; - const CustomData *cdatas[] = {&me->vdata, &me->edata, &me->ldata, &me->pdata}; - // const CustomData *bmdatas[] = {&bm->vdata, &bm->edata, &bm->ldata, &bm->pdata}; - - bool check_id_unqiue = false; - - if (!params->ignore_id_layers) { - for (int i = 0; i < 4; i++) { - int type = 1 << i; - - if (CustomData_has_layer(cdatas[i], CD_MESH_ID)) { - bm->idmap.flag |= type | BM_HAS_IDS; - } - } - - bm_init_idmap_cdlayers(bm); - } - - // check_id_unqiue - if ((bm->idmap.flag & BM_HAS_IDS)) { -#ifndef WITH_BM_ID_FREELIST - if (!bm->idmap.idtree) { - bm->idmap.idtree = range_tree_uint_alloc(0, (uint)-1); - } -#endif - - if (bm->idmap.flag & BM_HAS_ID_MAP) { - check_id_unqiue = true; - } - } - - if (params->copy_temp_cdlayers) { - bm_unmark_temp_cdlayers(bm); - } - - if (params->copy_temp_cdlayers) { - mask.vmask |= CD_MASK_MESH_ID; - mask.emask |= CD_MASK_MESH_ID; - mask.lmask |= CD_MASK_MESH_ID; - mask.pmask |= CD_MASK_MESH_ID; - } - - if (mmd) { - bm->multires = *mmd; - bm->haveMultiResSettings = true; - bm->multiresSpace = MULTIRES_SPACE_TANGENT; - } - else { - bm->haveMultiResSettings = false; - } - - if (!me || !me->totvert) { - if (me && is_new) { /* No verts? still copy custom-data layout. */ - bm_free_cd_pools(bm); - - CustomData_copy(&me->vdata, &bm->vdata, mask.vmask, CD_ASSIGN, 0); - CustomData_copy(&me->edata, &bm->edata, mask.emask, CD_ASSIGN, 0); - CustomData_copy(&me->ldata, &bm->ldata, mask.lmask, CD_ASSIGN, 0); - CustomData_copy(&me->pdata, &bm->pdata, mask.pmask, CD_ASSIGN, 0); - - CustomData_bmesh_init_pool_ex(&bm->vdata, me->totvert, BM_VERT, __func__); - CustomData_bmesh_init_pool_ex(&bm->edata, me->totedge, BM_EDGE, __func__); - CustomData_bmesh_init_pool_ex(&bm->ldata, me->totloop, BM_LOOP, __func__); - CustomData_bmesh_init_pool_ex(&bm->pdata, me->totpoly, BM_FACE, __func__); - } - - if (params->copy_temp_cdlayers) { - bm_mark_temp_cdlayers(bm); - } - - if (bm->idmap.flag & BM_HAS_IDS) { - bm_init_idmap_cdlayers(bm); - } - - return; /* Sanity check. */ - } - - /* Only copy normals to the new BMesh if they are not already dirty. This avoids unnecessary - * work, but also accessing normals on an incomplete mesh, for example when restoring undo steps - * in edit mode. */ - const float(*vert_normals)[3] = NULL; - if (!BKE_mesh_vertex_normals_are_dirty(me)) { - vert_normals = BKE_mesh_vertex_normals_ensure(me); - } - - if (is_new) { - bm_free_cd_pools(bm); - - CustomData_copy(&me->vdata, &bm->vdata, mask.vmask, CD_CALLOC, 0); - CustomData_copy(&me->edata, &bm->edata, mask.emask, CD_CALLOC, 0); - CustomData_copy(&me->ldata, &bm->ldata, mask.lmask, CD_CALLOC, 0); - CustomData_copy(&me->pdata, &bm->pdata, mask.pmask, CD_CALLOC, 0); - } - else { - CustomData_bmesh_merge(&me->vdata, &bm->vdata, mask.vmask, CD_CALLOC, bm, BM_VERT); - CustomData_bmesh_merge(&me->edata, &bm->edata, mask.emask, CD_CALLOC, bm, BM_EDGE); - CustomData_bmesh_merge(&me->ldata, &bm->ldata, mask.lmask, CD_CALLOC, bm, BM_LOOP); - CustomData_bmesh_merge(&me->pdata, &bm->pdata, mask.pmask, CD_CALLOC, bm, BM_FACE); - } - - /* -------------------------------------------------------------------- */ - /* Shape Key */ - int tot_shape_keys = 0; - if (me->key != NULL && DEG_is_original_id(&me->id)) { - /* Evaluated meshes can be topologically inconsistent with their shape keys. - * Shape keys are also already integrated into the state of the evaluated - * mesh, so considering them here would kind of apply them twice. */ - tot_shape_keys = BLI_listbase_count(&me->key->block); - - /* Original meshes must never contain a shape-key custom-data layers. - * - * This may happen if and object's mesh data is accidentally - * set to the output from the modifier stack, causing it to be an "original" ID, - * even though the data isn't fully compatible (hence this assert). - * - * This results in: - * - The newly created #BMesh having twice the number of custom-data layers. - * - When converting the #BMesh back to a regular mesh, - * At least one of the extra shape-key blocks will be created in #Mesh.key - * depending on the value of #CustomDataLayer.uid. - * - * We could support mixing both kinds of data if there is a compelling use-case for it. - * At the moment it's simplest to assume all original meshes use the key-block and meshes - * that are evaluated (through the modifier stack for example) use custom-data layers. - */ - BLI_assert(!CustomData_has_layer(&me->vdata, CD_SHAPEKEY)); - } - if (is_new == false && CustomData_has_layer(&me->vdata, CD_SHAPEKEY)) { - tot_shape_keys = min_ii(tot_shape_keys, CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY)); - } - const float(**shape_key_table)[3] = tot_shape_keys ? - BLI_array_alloca(shape_key_table, tot_shape_keys) : - NULL; - - if ((params->active_shapekey != 0) && tot_shape_keys > 0) { - actkey = BLI_findlink(&me->key->block, params->active_shapekey - 1); - } - else { - actkey = NULL; - } - - if (is_new) { - if (tot_shape_keys || params->add_key_index) { - CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0); - } - } - - if (tot_shape_keys) { - if (is_new || params->create_shapekey_layers) { - /* Check if we need to generate unique ids for the shape-keys. - * This also exists in the file reading code, but is here for a sanity check. */ - if (!me->key->uidgen) { - fprintf(stderr, - "%s had to generate shape key uid's in a situation we shouldn't need to! " - "(bmesh internal error)\n", - __func__); - - me->key->uidgen = 1; - for (block = me->key->block.first; block; block = block->next) { - block->uid = me->key->uidgen++; - } - } - } - - if (actkey && actkey->totelem == me->totvert) { - keyco = params->use_shapekey ? actkey->data : NULL; - if (is_new || params->create_shapekey_layers) { - bm->shapenr = params->active_shapekey; - } - } - - for (i = 0, block = me->key->block.first; i < tot_shape_keys; block = block->next, i++) { - if (is_new) { - CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY, CD_ASSIGN, NULL, 0, block->name); - } - else { - BM_data_layer_add_named(bm, &bm->vdata, CD_SHAPEKEY, block->name); - } - - int j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i); - bm->vdata.layers[j].uid = block->uid; - shape_key_table[i] = (const float(*)[3])block->data; - } - } - - if (bm->use_toolflags) { - bm_alloc_toolflags_cdlayers(bm, !is_new); - - if (!bm->vtoolflagpool) { - bm->vtoolflagpool = BLI_mempool_create( - sizeof(BMFlagLayer), bm->totvert, 512, BLI_MEMPOOL_NOP); - bm->etoolflagpool = BLI_mempool_create( - sizeof(BMFlagLayer), bm->totedge, 512, BLI_MEMPOOL_NOP); - bm->ftoolflagpool = BLI_mempool_create( - sizeof(BMFlagLayer), bm->totface, 512, BLI_MEMPOOL_NOP); - - bm->totflags = 1; - } - } - - if (is_new) { - CustomData_bmesh_init_pool_ex(&bm->vdata, me->totvert, BM_VERT, __func__); - CustomData_bmesh_init_pool_ex(&bm->edata, me->totedge, BM_EDGE, __func__); - CustomData_bmesh_init_pool_ex(&bm->ldata, me->totloop, BM_LOOP, __func__); - CustomData_bmesh_init_pool_ex(&bm->pdata, me->totpoly, BM_FACE, __func__); - - BM_mesh_cd_flag_apply(bm, me->cd_flag); - } - else { - BM_mesh_cd_flag_ensure(bm, NULL, me->cd_flag); - } - -#define IS_GARBAGE_ID(id) ((id) < 0 || (id) > id_garbage_threshold) - - int *existing_id_layers[4] = {NULL, NULL, NULL, NULL}; - - /* threshold to detect garbage IDs, number of elements with ids multiplied by 5 */ - int id_garbage_threshold = 0; - - int use_exist_ids = 0; - int has_ids = bm->idmap.flag & BM_HAS_IDS ? - (bm->idmap.flag & (BM_VERT | BM_EDGE | BM_LOOP | BM_FACE)) : - 0; - if (bm->idmap.flag & BM_HAS_IDS) { - int tots[4] = {me->totvert + bm->totvert, - me->totedge + bm->totedge, - me->totloop + bm->totloop, - me->totpoly + bm->totface}; - - if (!params->ignore_id_layers) { - for (int i = 0; i < 4; i++) { - existing_id_layers[i] = (int *)CustomData_get_layer(cdatas[i], CD_MESH_ID); - - if (existing_id_layers[i]) { - id_garbage_threshold += tots[i]; - - use_exist_ids |= 1 << i; - } - } - } - - use_exist_ids &= bm->idmap.flag; - - bm_init_idmap_cdlayers(bm); - } - - id_garbage_threshold *= 5; - - const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); - const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT); - const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE); - int *cd_shape_key_offset = tot_shape_keys ? - MEM_mallocN(sizeof(int) * tot_shape_keys, "cd_shape_key_offset") : - NULL; - const int cd_shape_keyindex_offset = is_new && (tot_shape_keys || params->add_key_index) ? - CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX) : - -1; - - for (int i = 0; i < tot_shape_keys; i++) { - int idx = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i); - cd_shape_key_offset[i] = bm->vdata.layers[idx].offset; - } - - vtable = MEM_mallocN(sizeof(BMVert **) * me->totvert, __func__); - - for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) { - v = vtable[i] = BM_vert_create( - bm, keyco ? keyco[i] : mvert->co, NULL, BM_CREATE_SKIP_CD | BM_CREATE_SKIP_ID); - BM_elem_index_set(v, i); /* set_ok */ - - /* Transfer flag. */ - v->head.hflag = BM_vert_flag_from_mflag(mvert->flag & ~SELECT); - - /* This is necessary for selection counts to work properly. */ - if (mvert->flag & SELECT) { - BM_vert_select_set(bm, v, true); - } - - if (vert_normals) { - copy_v3_v3(v->no, vert_normals[i]); - } - - /* Copy Custom Data */ - CustomData_to_bmesh_block(&me->vdata, &bm->vdata, i, &v->head.data, true); - - bm_elem_check_toolflags(bm, (BMElem *)v); - - if (has_ids & BM_VERT) { - if ((use_exist_ids & BM_VERT) && !IS_GARBAGE_ID(existing_id_layers[0][i])) { - bm_assign_id(bm, (BMElem *)v, existing_id_layers[0][i], false); - } - else { - bm_alloc_id(bm, (BMElem *)v); - } - } - - if (cd_vert_bweight_offset != -1) { - BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mvert->bweight / 255.0f); - } - - /* Set shape key original index. */ - if (cd_shape_keyindex_offset != -1) { - BM_ELEM_CD_SET_INT(v, cd_shape_keyindex_offset, i); - } - - /* Set shape-key data. */ - if (tot_shape_keys) { - for (int j = 0; j < tot_shape_keys; j++) { - float *co_dst = BM_ELEM_CD_GET_VOID_P(v, cd_shape_key_offset[j]); - copy_v3_v3(co_dst, shape_key_table[j][i]); - } - } - } - if (is_new) { - bm->elem_index_dirty &= ~BM_VERT; /* Added in order, clear dirty flag. */ - } - - etable = MEM_mallocN(sizeof(BMEdge **) * me->totedge, __func__); - - medge = me->medge; - for (i = 0; i < me->totedge; i++, medge++) { - e = etable[i] = BM_edge_create( - bm, vtable[medge->v1], vtable[medge->v2], NULL, BM_CREATE_SKIP_CD); - BM_elem_index_set(e, i); /* set_ok */ - - /* Transfer flags. */ - e->head.hflag = BM_edge_flag_from_mflag(medge->flag & ~SELECT); - - /* This is necessary for selection counts to work properly. */ - if (medge->flag & SELECT) { - BM_edge_select_set(bm, e, true); - } - - /* Copy Custom Data */ - CustomData_to_bmesh_block(&me->edata, &bm->edata, i, &e->head.data, true); - - bm_elem_check_toolflags(bm, (BMElem *)e); - - if (has_ids & BM_EDGE) { - if ((use_exist_ids & BM_EDGE) && !IS_GARBAGE_ID(existing_id_layers[1][i])) { - bm_assign_id(bm, (BMElem *)e, existing_id_layers[1][i], false); - } - else { - bm_alloc_id(bm, (BMElem *)e); - } - } - - if (cd_edge_bweight_offset != -1) { - BM_ELEM_CD_SET_FLOAT(e, cd_edge_bweight_offset, (float)medge->bweight / 255.0f); - } - if (cd_edge_crease_offset != -1) { - BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset, (float)medge->crease / 255.0f); - } - } - if (is_new) { - bm->elem_index_dirty &= ~BM_EDGE; /* Added in order, clear dirty flag. */ - } - - /* Only needed for selection. */ - if (me->mselect && me->totselect != 0) { - ftable = MEM_mallocN(sizeof(BMFace **) * me->totpoly, __func__); - } - - mloop = me->mloop; - mp = me->mpoly; - for (i = 0, totloops = 0; i < me->totpoly; i++, mp++) { - BMLoop *l_iter; - BMLoop *l_first; - - f = bm_face_create_from_mpoly(mp, mloop + mp->loopstart, bm, vtable, etable); - if (ftable != NULL) { - ftable[i] = f; - } - - if (UNLIKELY(f == NULL)) { - printf( - "%s: Warning! Bad face in mesh" - " \"%s\" at index %d!, skipping\n", - __func__, - me->id.name + 2, - i); - continue; - } - - /* Don't use 'i' since we may have skipped the face. */ - BM_elem_index_set(f, bm->totface - 1); /* set_ok */ - - /* Transfer flag. */ - f->head.hflag = BM_face_flag_from_mflag(mp->flag & ~ME_FACE_SEL); - - /* This is necessary for selection counts to work properly. */ - if (mp->flag & ME_FACE_SEL) { - BM_face_select_set(bm, f, true); - } - - f->mat_nr = mp->mat_nr; - if (i == me->act_face) { - bm->act_face = f; - } - - int j = mp->loopstart; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - /* Don't use 'j' since we may have skipped some faces, hence some loops. */ - BM_elem_index_set(l_iter, totloops++); /* set_ok */ - - /* Save index of corresponding #MLoop. */ - CustomData_to_bmesh_block(&me->ldata, &bm->ldata, j++, &l_iter->head.data, true); - - if (has_ids & BM_LOOP) { - if ((use_exist_ids & BM_LOOP) && !IS_GARBAGE_ID(existing_id_layers[2][j - 1])) { - bm_assign_id(bm, (BMElem *)l_iter, existing_id_layers[2][j - 1], false); - } - else { - bm_alloc_id(bm, (BMElem *)l_iter); - } - } - } while ((l_iter = l_iter->next) != l_first); - - /* Copy Custom Data */ - CustomData_to_bmesh_block(&me->pdata, &bm->pdata, i, &f->head.data, true); - - bm_elem_check_toolflags(bm, (BMElem *)f); - - if (has_ids & BM_FACE) { - if ((use_exist_ids & BM_FACE) && !IS_GARBAGE_ID(existing_id_layers[3][i])) { - bm_assign_id(bm, (BMElem *)f, existing_id_layers[3][i], false); - } - else { - bm_alloc_id(bm, (BMElem *)f); - } - } - - if (params->calc_face_normal) { - BM_face_normal_update(f); - } - } - if (is_new) { - bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); /* Added in order, clear dirty flag. */ - } - - if (check_id_unqiue) { - bm_update_idmap_cdlayers(bm); - - // validate IDs - - // first clear idmap, we want it to have the first elements - // in each id run, not the last - if (bm->idmap.map) { - memset(bm->idmap.map, 0, sizeof(void *) * bm->idmap.map_size); - } - else if (bm->idmap.ghash) { - BLI_ghash_free(bm->idmap.ghash, NULL, NULL); - bm->idmap.ghash = BLI_ghash_ptr_new("bm->idmap.ghash"); - } - - int iters[] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, -1, BM_FACES_OF_MESH}; - -#ifdef WITH_BM_ID_FREELIST - uint max_id = 0; -#endif - - // find first element in each id run and assign to map - for (int i = 0; i < 4; i++) { - int type = 1 << i; - int iter = iters[i]; - - if (!(bm->idmap.flag & type)) { - continue; - } - - if (iter == -1) { - iter = BM_FACES_OF_MESH; - } - - BMElem *elem; - BMIter iterstate; - BM_ITER_MESH (elem, &iterstate, bm, iter) { - if (i == 2) { // loops - BMFace *f = (BMFace *)elem; - BMLoop *l = f->l_first; - - do { - uint id = (uint)BM_ELEM_GET_ID(bm, (BMElem *)l); -#ifdef WITH_BM_ID_FREELIST - max_id = MAX2(max_id, i); -#endif - if (!BM_ELEM_FROM_ID(bm, id)) { - bm_assign_id_intern(bm, (BMElem *)l, id); - } - } while ((l = l->next) != f->l_first); - } - else { - uint id = (uint)BM_ELEM_GET_ID(bm, elem); -#ifdef WITH_BM_ID_FREELIST - max_id = MAX2(max_id, i); -#endif - - if (!BM_ELEM_FROM_ID(bm, id)) { - bm_assign_id_intern(bm, elem, id); - } - } - } - } - - // now assign new IDs where necessary - - for (int i = 0; i < 4; i++) { - int type = 1 << i; - int iter = iters[i]; - - if (!(bm->idmap.flag & type)) { - continue; - } - - if (iter == -1) { - iter = BM_FACES_OF_MESH; - } - - BMElem *elem; - BMIter iterstate; - - BM_ITER_MESH (elem, &iterstate, bm, iter) { - if (i == 2) { // loops - BMFace *f = (BMFace *)elem; - BMLoop *l = f->l_first; - - do { - uint id = (uint)BM_ELEM_GET_ID(bm, (BMElem *)l); - - if (BM_ELEM_FROM_ID(bm, id) != (BMElem *)l) { - bm_alloc_id(bm, (BMElem *)l); - } - } while ((l = l->next) != f->l_first); - } - else { - uint id = (uint)BM_ELEM_GET_ID(bm, elem); - - if (BM_ELEM_FROM_ID(bm, id) != elem) { - bm_alloc_id(bm, elem); - - id = (uint)BM_ELEM_GET_ID(bm, elem); -#ifdef WITH_BM_ID_FREELIST - max_id = MAX2(max_id, id); -#endif - } - } - } - } - -#ifdef WITH_BM_ID_FREELIST - max_id = MAX2(bm->idmap.maxid, max_id); - bm->idmap.maxid = max_id; -#endif - } - -#ifdef WITH_BM_ID_FREELIST - /*ensure correct id freelist*/ - if (bm->idmap.flag & BM_HAS_IDS) { - bm_update_idmap_cdlayers(bm); - bm_free_ids_check(bm, bm->idmap.maxid); - - MEM_SAFE_FREE(bm->idmap.freelist); - bm->idmap.freelist_len = 0; - bm->idmap.freelist_size = 0; - bm->idmap.freelist = NULL; - - memset(bm->idmap.free_ids, 0, bm->idmap.free_ids_size * sizeof(*bm->idmap.free_ids)); - - BLI_mempool_iter miter; - for (int i = 0; i < 4; i++) { - int htype = 1 << i; - - if (!(bm->idmap.flag & htype)) { - continue; - } - - BLI_mempool *pool = (&bm->vpool)[i]; - BLI_mempool_iternew(pool, &miter); - BMElem *elem = (BMElem *)BLI_mempool_iterstep(&miter); - -# if 0 - for (; elem; elem = (BMElem *)BLI_mempool_iterstep(&miter)) { - uint id = (uint)BM_ELEM_GET_ID(bm, elem); - - if (id > bm->idmap.maxid) { - printf("%s: corrupted id: %d > maxid(%d)\n", __func__, (int)id, (int)bm->idmap.maxid); - //BM_ELEM_CD_SET_INT(elem, bm->idmap.cd_id_off[elem->head.htype], 0); - bm_alloc_id(bm, elem); - } - } -# endif - - for (; elem; elem = (BMElem *)BLI_mempool_iterstep(&miter)) { - uint id = (uint)BM_ELEM_GET_ID(bm, elem); - - if ((id >> 2UL) < bm->idmap.free_ids_size) { - BLI_BITMAP_SET(bm->idmap.free_ids, id, true); - } - } - } - - for (uint i = 0; i < bm->idmap.maxid; i++) { - if (!BLI_BITMAP_TEST(bm->idmap.free_ids, i)) { - bm_id_freelist_push(bm, i); - } - } - } -#endif - - /* -------------------------------------------------------------------- */ - /* MSelect clears the array elements (avoid adding multiple times). - * - * Take care to keep this last and not use (v/e/ftable) after this. - */ - - if (me->mselect && me->totselect != 0) { - MSelect *msel; - for (i = 0, msel = me->mselect; i < me->totselect; i++, msel++) { - BMElem **ele_p; - switch (msel->type) { - case ME_VSEL: - ele_p = (BMElem **)&vtable[msel->index]; - break; - case ME_ESEL: - ele_p = (BMElem **)&etable[msel->index]; - break; - case ME_FSEL: - ele_p = (BMElem **)&ftable[msel->index]; - break; - default: - continue; - } - - if (*ele_p != NULL) { - BM_select_history_store_notest(bm, *ele_p); - *ele_p = NULL; - } - } - } - else { - BM_select_history_clear(bm); - } - - MEM_freeN(vtable); - MEM_freeN(etable); - if (ftable) { - MEM_freeN(ftable); - } - - if (params->copy_temp_cdlayers) { - bm_mark_temp_cdlayers(bm); - } - - if (bm->idmap.flag & BM_HAS_IDS) { - CustomData *cdatas[] = {&bm->vdata, &bm->edata, &bm->ldata, &bm->pdata}; - - for (int i = 0; i < 4; i++) { - int idx = CustomData_get_layer_index(cdatas[i], CD_MESH_ID); - - if (idx >= 0) { - // set layer flags - cdatas[i]->layers[idx].flag |= CD_FLAG_TEMPORARY | CD_FLAG_ELEM_NOCOPY; - } - } - } - - MEM_SAFE_FREE(cd_shape_key_offset); -} - -/** - * \brief BMesh -> Mesh - */ -BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert) -{ - const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX); - BMVert **vertMap = NULL; - BMVert *eve; - int i = 0; - BMIter iter; - - /* Caller needs to ensure this. */ - BLI_assert(ototvert > 0); - - vertMap = MEM_callocN(sizeof(*vertMap) * ototvert, "vertMap"); - if (cd_shape_keyindex_offset != -1) { - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - const int keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset); - if ((keyi != ORIGINDEX_NONE) && (keyi < ototvert) && - /* Not fool-proof, but chances are if we have many verts with the same index, - * we will want to use the first one, - * since the second is more likely to be a duplicate. */ - (vertMap[keyi] == NULL)) { - vertMap[keyi] = eve; - } - } - } - else { - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - if (i < ototvert) { - vertMap[i] = eve; - } - else { - break; - } - } - } - - return vertMap; -} - -/** - * Returns custom-data shapekey index from a keyblock or -1 - * \note could split this out into a more generic function. - */ -int bm_to_mesh_shape_layer_index_from_kb(BMesh *bm, KeyBlock *currkey) -{ - int i; - int j = 0; - - for (i = 0; i < bm->vdata.totlayer; i++) { - if (bm->vdata.layers[i].type == CD_SHAPEKEY) { - if (currkey->uid == bm->vdata.layers[i].uid) { - return j; - } - j++; - } - } - return -1; -} - -BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e) -{ - /* This is a cheap way to set the edge draw, its not precise and will - * pick the first 2 faces an edge uses. - * The dot comparison is a little arbitrary, but set so that a 5 subd - * IcoSphere won't vanish but subd 6 will (as with pre-bmesh Blender). */ - - if (/* (med->flag & ME_EDGEDRAW) && */ /* Assume to be true. */ - (e->l && (e->l != e->l->radial_next)) && - (dot_v3v3(e->l->f->no, e->l->radial_next->f->no) > 0.9995f)) { - med->flag &= ~ME_EDGEDRAW; - } - else { - med->flag |= ME_EDGEDRAW; - } -} - -/** - * - * \param bmain: May be NULL in case \a calc_object_remap parameter option is not set. - */ - -void BM_mesh_bm_to_me( - Main *bmain, Object *ob, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params) -{ - MEdge *med; - BMVert *v, *eve; - BMEdge *e; - BMFace *f; - BMIter iter; - int i, j; - - CustomData *srcdatas[] = {&bm->vdata, &bm->edata, &bm->ldata, &bm->pdata}; - - if (params->copy_temp_cdlayers) { - bm_unmark_temp_cdlayers(bm); - } - - // ensure multires space is correct - if (bm->haveMultiResSettings && bm->multiresSpace != MULTIRES_SPACE_TANGENT) { - BM_enter_multires_space(ob, bm, MULTIRES_SPACE_TANGENT); - } - - const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); - const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT); - const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE); - const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX); - - MVert *oldverts = NULL; - const int ototvert = me->totvert; - - if (me->key && (cd_shape_keyindex_offset != -1)) { - /* Keep the old verts in case we are working on* a key, which is done at the end. */ - - /* Use the array in-place instead of duplicating the array. */ -#if 0 - oldverts = MEM_dupallocN(me->mvert); -#else - oldverts = me->mvert; - me->mvert = NULL; - CustomData_update_typemap(&me->vdata); - CustomData_set_layer(&me->vdata, CD_MVERT, NULL); -#endif - } - - // undo mesh? - // bool non_id_mesh = GS(me->id.name) != ID_ME; - - /* Free custom data. */ - CustomData_free(&me->vdata, me->totvert); - CustomData_free(&me->edata, me->totedge); - CustomData_free(&me->fdata, me->totface); - CustomData_free(&me->ldata, me->totloop); - CustomData_free(&me->pdata, me->totpoly); - - /* Add new custom data. */ - me->totvert = bm->totvert; - me->totedge = bm->totedge; - me->totloop = bm->totloop; - me->totpoly = bm->totface; - /* Will be overwritten with a valid value if 'dotess' is set, otherwise we - * end up with 'me->totface' and me->mface == NULL which can crash T28625. */ - me->totface = 0; - me->act_face = -1; - - int id_flags[4] = {-1, -1, -1, -1}; - - { - CustomData_MeshMasks mask = CD_MASK_MESH; - CustomData_MeshMasks_update(&mask, ¶ms->cd_mask_extra); - CustomDataMask extra2 = !params->ignore_mesh_id_layers ? CD_MASK_MESH_ID : 0; - - // copy id layers? temporarily clear cd_temporary and cd_flag_elem_nocopy flags - if (!params->ignore_mesh_id_layers) { - for (int i = 0; i < 4; i++) { - int idx = CustomData_get_layer_index(srcdatas[i], CD_MESH_ID); - - if (idx >= 0) { - id_flags[i] = srcdatas[i]->layers[idx].flag; - srcdatas[i]->layers[idx].flag &= ~(CD_FLAG_TEMPORARY | CD_FLAG_ELEM_NOCOPY); - } - } - } - - CustomData_copy(&bm->vdata, &me->vdata, mask.vmask | extra2, CD_CALLOC, me->totvert); - CustomData_copy(&bm->edata, &me->edata, mask.emask | extra2, CD_CALLOC, me->totedge); - CustomData_copy(&bm->ldata, &me->ldata, mask.lmask | extra2, CD_CALLOC, me->totloop); - CustomData_copy(&bm->pdata, &me->pdata, mask.pmask | extra2, CD_CALLOC, me->totpoly); - } - - MVert *mvert = bm->totvert ? MEM_callocN(sizeof(MVert) * bm->totvert, "bm_to_me.vert") : NULL; - MEdge *medge = bm->totedge ? MEM_callocN(sizeof(MEdge) * bm->totedge, "bm_to_me.edge") : NULL; - MLoop *mloop = bm->totloop ? MEM_callocN(sizeof(MLoop) * bm->totloop, "bm_to_me.loop") : NULL; - MPoly *mpoly = bm->totface ? MEM_callocN(sizeof(MPoly) * bm->totface, "bm_to_me.poly") : NULL; - - CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert); - CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge); - CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, mloop, me->totloop); - CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, mpoly, me->totpoly); - - /* There is no way to tell if BMesh normals are dirty or not. Instead of calculating the normals - * on the BMesh possibly unnecessarily, just tag them dirty on the resulting mesh. */ - BKE_mesh_normals_tag_dirty(me); - - me->cd_flag = BM_mesh_cd_flag_from_bmesh(bm); - - /* This is called again, 'dotess' arg is used there. */ - BKE_mesh_update_customdata_pointers(me, 0); - - i = 0; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - copy_v3_v3(mvert->co, v->co); - - mvert->flag = BM_vert_flag_to_mflag(v); - - BM_elem_index_set(v, i); /* set_inline */ - - /* Copy over custom-data. */ - CustomData_from_bmesh_block(&bm->vdata, &me->vdata, v->head.data, i); - - if (cd_vert_bweight_offset != -1) { - mvert->bweight = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(v, cd_vert_bweight_offset); - } - - i++; - mvert++; - - BM_CHECK_ELEMENT(v); - } - bm->elem_index_dirty &= ~BM_VERT; - - med = medge; - i = 0; - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - med->v1 = BM_elem_index_get(e->v1); - med->v2 = BM_elem_index_get(e->v2); - - med->flag = BM_edge_flag_to_mflag(e); - - BM_elem_index_set(e, i); /* set_inline */ - - /* Copy over custom-data. */ - CustomData_from_bmesh_block(&bm->edata, &me->edata, e->head.data, i); - - bmesh_quick_edgedraw_flag(med, e); - - if (cd_edge_crease_offset != -1) { - med->crease = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(e, cd_edge_crease_offset); - } - if (cd_edge_bweight_offset != -1) { - med->bweight = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(e, cd_edge_bweight_offset); - } - - i++; - med++; - BM_CHECK_ELEMENT(e); - } - bm->elem_index_dirty &= ~BM_EDGE; - - i = 0; - j = 0; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - BMLoop *l_iter, *l_first; - mpoly->loopstart = j; - mpoly->totloop = f->len; - mpoly->mat_nr = f->mat_nr; - mpoly->flag = BM_face_flag_to_mflag(f); - - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - mloop->e = BM_elem_index_get(l_iter->e); - mloop->v = BM_elem_index_get(l_iter->v); - - /* Copy over custom-data. */ - CustomData_from_bmesh_block(&bm->ldata, &me->ldata, l_iter->head.data, j); - - j++; - mloop++; - BM_CHECK_ELEMENT(l_iter); - BM_CHECK_ELEMENT(l_iter->e); - BM_CHECK_ELEMENT(l_iter->v); - } while ((l_iter = l_iter->next) != l_first); - - if (f == bm->act_face) { - me->act_face = i; - } - - /* Copy over custom-data. */ - CustomData_from_bmesh_block(&bm->pdata, &me->pdata, f->head.data, i); - - i++; - mpoly++; - BM_CHECK_ELEMENT(f); - } - - /* Patch hook indices and vertex parents. */ - if (params->calc_object_remap && (ototvert > 0)) { - BLI_assert(bmain != NULL); - Object *ob; - ModifierData *md; - BMVert **vertMap = NULL; - - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - if ((ob->parent) && (ob->parent->data == me) && ELEM(ob->partype, PARVERT1, PARVERT3)) { - - if (vertMap == NULL) { - vertMap = bm_to_mesh_vertex_map(bm, ototvert); - } - - if (ob->par1 < ototvert) { - eve = vertMap[ob->par1]; - if (eve) { - ob->par1 = BM_elem_index_get(eve); - } - } - if (ob->par2 < ototvert) { - eve = vertMap[ob->par2]; - if (eve) { - ob->par2 = BM_elem_index_get(eve); - } - } - if (ob->par3 < ototvert) { - eve = vertMap[ob->par3]; - if (eve) { - ob->par3 = BM_elem_index_get(eve); - } - } - } - if (ob->data == me) { - for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Hook) { - HookModifierData *hmd = (HookModifierData *)md; - - if (vertMap == NULL) { - vertMap = bm_to_mesh_vertex_map(bm, ototvert); - } - - for (i = j = 0; i < hmd->totindex; i++) { - if (hmd->indexar[i] < ototvert) { - eve = vertMap[hmd->indexar[i]]; - - if (eve) { - hmd->indexar[j++] = BM_elem_index_get(eve); - } - } - else { - j++; - } - } - - hmd->totindex = j; - } - } - } - } - - if (vertMap) { - MEM_freeN(vertMap); - } - } - - BKE_mesh_update_customdata_pointers(me, false); - - { - BMEditSelection *selected; - me->totselect = BLI_listbase_count(&(bm->selected)); - - MEM_SAFE_FREE(me->mselect); - if (me->totselect != 0) { - me->mselect = MEM_mallocN(sizeof(MSelect) * me->totselect, "Mesh selection history"); - } - - for (i = 0, selected = bm->selected.first; selected; i++, selected = selected->next) { - if (selected->htype == BM_VERT) { - me->mselect[i].type = ME_VSEL; - } - else if (selected->htype == BM_EDGE) { - me->mselect[i].type = ME_ESEL; - } - else if (selected->htype == BM_FACE) { - me->mselect[i].type = ME_FSEL; - } - - me->mselect[i].index = BM_elem_index_get(selected->ele); - } - } - - /* See comment below, this logic is in twice. */ - - if (me->key) { - KeyBlock *currkey; - KeyBlock *actkey = BLI_findlink(&me->key->block, bm->shapenr - 1); - - float(*ofs)[3] = NULL; - - /* Go through and find any shape-key custom-data layers - * that might not have corresponding KeyBlocks, and add them if necessary. */ - for (i = 0; i < bm->vdata.totlayer; i++) { - if (bm->vdata.layers[i].type != CD_SHAPEKEY) { - continue; - } - - for (currkey = me->key->block.first; currkey; currkey = currkey->next) { - if (currkey->uid == bm->vdata.layers[i].uid) { - break; - } - } - - if (!currkey) { - currkey = BKE_keyblock_add(me->key, bm->vdata.layers[i].name); - currkey->uid = bm->vdata.layers[i].uid; - } - } - - /* Editing the base key should update others. */ - if (/* Only need offsets for relative shape keys. */ - (me->key->type == KEY_RELATIVE) && - - /* Unlikely, but the active key may not be valid if the - * BMesh and the mesh are out of sync. */ - (actkey != NULL) && - - /* Not used here, but 'oldverts' is used later for applying 'ofs'. */ - (oldverts != NULL) && - - /* Needed for referencing oldverts. */ - (cd_shape_keyindex_offset != -1)) { - - const bool act_is_basis = BKE_keyblock_is_basis(me->key, bm->shapenr - 1); - - /* Active key is a base. */ - if (act_is_basis) { - const float(*fp)[3] = actkey->data; - - ofs = MEM_callocN(sizeof(float[3]) * bm->totvert, "currkey->data"); - mvert = me->mvert; - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - const int keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset); - - /* Could use 'eve->co' or 'mvert->co', they're the same at this point. */ - if (keyi != ORIGINDEX_NONE && keyi < actkey->totelem) { - sub_v3_v3v3(ofs[i], mvert->co, fp[keyi]); - } - else { - /* If there are new vertices in the mesh, we can't propagate the offset - * because it will only work for the existing vertices and not the new - * ones, creating a mess when doing e.g. subdivide + translate. */ - MEM_freeN(ofs); - ofs = NULL; - break; - } - - mvert++; - } - } - } - - for (currkey = me->key->block.first; currkey; currkey = currkey->next) { - int keyi; - const float(*ofs_pt)[3] = ofs; - float *newkey, (*oldkey)[3], *fp; - - const int currkey_uuid = bm_to_mesh_shape_layer_index_from_kb(bm, currkey); - const int cd_shape_offset = (currkey_uuid == -1) ? -1 : - CustomData_get_n_offset(&bm->vdata, - CD_SHAPEKEY, - currkey_uuid); - const bool apply_offset = (cd_shape_offset != -1) && (ofs != NULL) && (currkey != actkey) && - (bm->shapenr - 1 == currkey->relative); - - fp = newkey = MEM_callocN(me->key->elemsize * bm->totvert, "currkey->data"); - oldkey = currkey->data; - - mvert = me->mvert; - BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { - - if (currkey == actkey) { - copy_v3_v3(fp, eve->co); - - if (actkey != me->key->refkey) { /* Important see bug T30771. */ - if (cd_shape_keyindex_offset != -1) { - if (oldverts) { - keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset); - if (keyi != ORIGINDEX_NONE && keyi < currkey->totelem) { /* Valid old vertex. */ - copy_v3_v3(mvert->co, oldverts[keyi].co); - } - } - } - } - } - else if (cd_shape_offset != -1) { - /* In most cases this runs. */ - copy_v3_v3(fp, BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset)); - } - else if ((oldkey != NULL) && (cd_shape_keyindex_offset != -1) && - ((keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset)) != ORIGINDEX_NONE) && - (keyi < currkey->totelem)) { - /* Old method of reconstructing keys via vertices original key indices, - * currently used if the new method above fails - * (which is theoretically possible in certain cases of undo). */ - copy_v3_v3(fp, oldkey[keyi]); - } - else { - /* Fail! fill in with dummy value. */ - copy_v3_v3(fp, mvert->co); - } - - /* Propagate edited basis offsets to other shapes. */ - if (apply_offset) { - add_v3_v3(fp, *ofs_pt++); - /* Apply back new coordinates shape-keys that have offset into BMesh. - * Otherwise, in case we call again #BM_mesh_bm_to_me on same BMesh, - * we'll apply diff from previous call to #BM_mesh_bm_to_me, - * to shape-key values from *original creation of the BMesh*. See T50524. */ - copy_v3_v3(BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset), fp); - } - - fp += 3; - mvert++; - } - - currkey->totelem = bm->totvert; - if (currkey->data) { - MEM_freeN(currkey->data); - } - currkey->data = newkey; - } - - if (ofs) { - MEM_freeN(ofs); - } - } - - /* Run this even when shape keys aren't used since it may be used for hooks or vertex parents. */ - if (params->update_shapekey_indices) { - /* We have written a new shape key, if this mesh is _not_ going to be freed, - * update the shape key indices to match the newly updated. */ - if (cd_shape_keyindex_offset != -1) { - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - BM_ELEM_CD_SET_INT(eve, cd_shape_keyindex_offset, i); - } - } - } - - if (oldverts != NULL) { - MEM_freeN(oldverts); - } - - /* Topology could be changed, ensure #CD_MDISPS are ok. */ - multires_topology_changed(me); - - /* To be removed as soon as COW is enabled by default. */ - BKE_mesh_runtime_clear_geometry(me); - - // restore original cd layer flags to bmesh id layers - if (!params->ignore_mesh_id_layers) { - for (int i = 0; i < 4; i++) { - int idx = CustomData_get_layer_index(srcdatas[i], CD_MESH_ID); - if (idx >= 0) { - srcdatas[i]->layers[idx].flag = id_flags[i]; - } - } - } - - if (params && params->copy_temp_cdlayers) { - bm_mark_temp_cdlayers(bm); - } -} - -void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *cd_mask_extra) -{ - /* Must be an empty mesh. */ - BLI_assert(me->totvert == 0); - BLI_assert(cd_mask_extra == NULL || (cd_mask_extra->vmask & CD_MASK_SHAPEKEY) == 0); - - me->totvert = bm->totvert; - me->totedge = bm->totedge; - me->totface = 0; - me->totloop = bm->totloop; - me->totpoly = bm->totface; - - CustomData_add_layer(&me->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, bm->totvert); - CustomData_add_layer(&me->edata, CD_ORIGINDEX, CD_CALLOC, NULL, bm->totedge); - CustomData_add_layer(&me->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, bm->totface); - - CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, bm->totvert); - CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, bm->totedge); - CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, NULL, bm->totloop); - CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, NULL, bm->totface); - - /* Don't process shape-keys, we only feed them through the modifier stack as needed, - * e.g. for applying modifiers or the like. */ - CustomData_MeshMasks mask = CD_MASK_DERIVEDMESH; - if (cd_mask_extra != NULL) { - CustomData_MeshMasks_update(&mask, cd_mask_extra); - } - mask.vmask &= ~CD_MASK_SHAPEKEY; - - CustomData_merge(&bm->vdata, &me->vdata, mask.vmask, CD_CALLOC, me->totvert); - CustomData_merge(&bm->edata, &me->edata, mask.emask, CD_CALLOC, me->totedge); - CustomData_merge(&bm->ldata, &me->ldata, mask.lmask, CD_CALLOC, me->totloop); - CustomData_merge(&bm->pdata, &me->pdata, mask.pmask, CD_CALLOC, me->totpoly); - - BKE_mesh_update_customdata_pointers(me, false); - - BMIter iter; - BMVert *eve; - BMEdge *eed; - BMFace *efa; - MVert *mvert = me->mvert; - MEdge *medge = me->medge; - MLoop *mloop = me->mloop; - MPoly *mpoly = me->mpoly; - int *index, add_orig; - unsigned int i, j; - - const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); - const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT); - const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE); - - BKE_mesh_normals_tag_dirty(me); - - me->runtime.deformed_only = true; - - /* Don't add origindex layer if one already exists. */ - add_orig = !CustomData_has_layer(&bm->pdata, CD_ORIGINDEX); - - index = CustomData_get_layer(&me->vdata, CD_ORIGINDEX); - - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - MVert *mv = &mvert[i]; - - copy_v3_v3(mv->co, eve->co); - - BM_elem_index_set(eve, i); /* set_inline */ - - mv->flag = BM_vert_flag_to_mflag(eve); - - if (cd_vert_bweight_offset != -1) { - mv->bweight = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eve, cd_vert_bweight_offset); - } - - if (add_orig) { - *index++ = i; - } - - CustomData_from_bmesh_block(&bm->vdata, &me->vdata, eve->head.data, i); - } - bm->elem_index_dirty &= ~BM_VERT; - - index = CustomData_get_layer(&me->edata, CD_ORIGINDEX); - BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) { - MEdge *med = &medge[i]; - - BM_elem_index_set(eed, i); /* set_inline */ - - med->v1 = BM_elem_index_get(eed->v1); - med->v2 = BM_elem_index_get(eed->v2); - - med->flag = BM_edge_flag_to_mflag(eed); - - /* Handle this differently to editmode switching, - * only enable draw for single user edges rather than calculating angle. */ - if ((med->flag & ME_EDGEDRAW) == 0) { - if (eed->l && eed->l == eed->l->radial_next) { - med->flag |= ME_EDGEDRAW; - } - } - - if (cd_edge_crease_offset != -1) { - med->crease = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_crease_offset); - } - if (cd_edge_bweight_offset != -1) { - med->bweight = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_bweight_offset); - } - - CustomData_from_bmesh_block(&bm->edata, &me->edata, eed->head.data, i); - if (add_orig) { - *index++ = i; - } - } - bm->elem_index_dirty &= ~BM_EDGE; - - index = CustomData_get_layer(&me->pdata, CD_ORIGINDEX); - j = 0; - BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { - BMLoop *l_iter; - BMLoop *l_first; - MPoly *mp = &mpoly[i]; - - BM_elem_index_set(efa, i); /* set_inline */ - - mp->totloop = efa->len; - mp->flag = BM_face_flag_to_mflag(efa); - mp->loopstart = j; - mp->mat_nr = efa->mat_nr; - - l_iter = l_first = BM_FACE_FIRST_LOOP(efa); - do { - mloop->v = BM_elem_index_get(l_iter->v); - mloop->e = BM_elem_index_get(l_iter->e); - CustomData_from_bmesh_block(&bm->ldata, &me->ldata, l_iter->head.data, j); - - BM_elem_index_set(l_iter, j); /* set_inline */ - - j++; - mloop++; - } while ((l_iter = l_iter->next) != l_first); - - CustomData_from_bmesh_block(&bm->pdata, &me->pdata, efa->head.data, i); - - if (add_orig) { - *index++ = i; - } - } - bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); - - me->cd_flag = BM_mesh_cd_flag_from_bmesh(bm); -} diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h index 98b1e307235..415bb5e9578 100644 --- a/source/blender/bmesh/intern/bmesh_private.h +++ b/source/blender/bmesh/intern/bmesh_private.h @@ -27,6 +27,10 @@ * parts of the bmesh internals. */ +#ifdef __cplusplus +extern "C" { +#endif + /* returns positive nonzero on error */ #if 1//def NDEBUG @@ -104,3 +108,7 @@ void poly_rotate_plane(const float normal[3], float (*verts)[3], uint nverts); /* include the rest of our private declarations */ #include "bmesh_structure.h" + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c index c337724d096..6bb2830c71b 100644 --- a/source/blender/bmesh/operators/bmo_create.c +++ b/source/blender/bmesh/operators/bmo_create.c @@ -17,7 +17,7 @@ /** \file * \ingroup bmesh * - * Create faces or edges (Fkey by default). + * Create faces or edges (F-key by default). */ #include "MEM_guardedalloc.h" diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c index 740815691cc..f6cdb18f982 100644 --- a/source/blender/bmesh/operators/bmo_hull.c +++ b/source/blender/bmesh/operators/bmo_hull.c @@ -30,7 +30,7 @@ # include "RBI_hull_api.h" -/* XXX: using 128 for totelem and pchunk of mempool, no idea what good +/* XXX: using 128 for totelem and `pchunk` of `mempool`, no idea what good * values would be though */ # include "bmesh.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 38e46ca95c6..cb43ef685d4 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -2542,17 +2542,10 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) bNodeTree *group_ntree = (bNodeTree *)id; build_nodetree(group_ntree); ComponentKey group_output_key(&group_ntree->id, NodeType::NTREE_OUTPUT); - /* The output of the current tree does not necessarily change when the output of the group - * changed. The parent node group is currently explicitly tagged for update in - * #ED_node_tree_propagate_change. In the future we could move this relation to the - * depsgraph, but then the depsgraph has to do some more static analysis of the node tree to - * see which groups the output actually depends on. - * - * Furthermore, shader nodes currently depend on relations being created from e.g. objects to - * nodes. Geometry nodes do not depend on these relations, because they are explicitly - * created by the modifier (which is the thing that actually depends on the objects). */ - const int relation_flag = (group_ntree->type == NTREE_SHADER) ? 0 : RELATION_FLAG_NO_FLUSH; - add_relation(group_output_key, ntree_output_key, "Group Node", relation_flag); + /* This relation is not necessary in all cases (e.g. when the group node is not connected to + * the output). Currently, we lack the infrastructure to check for these cases efficiently. + * That can be added later. */ + add_relation(group_output_key, ntree_output_key, "Group Node"); } else { BLI_assert_msg(0, "Unknown ID type used for node"); diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 7b55981ba6b..8dd7e3d7dbf 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -212,6 +212,7 @@ set(SRC intern/draw_manager_profiling.h intern/draw_manager_testing.h intern/draw_manager_text.h + intern/draw_shader_shared.h intern/draw_shader.h intern/draw_subdivision.h intern/draw_texture_pool.h @@ -233,6 +234,7 @@ set(SRC engines/image/image_space_node.hh engines/workbench/workbench_engine.h engines/workbench/workbench_private.h + engines/workbench/workbench_shader_shared.h engines/select/select_engine.h engines/select/select_private.h engines/overlay/overlay_engine.h @@ -245,268 +247,300 @@ set(LIB bf_windowmanager ) -data_to_c_simple(engines/eevee/shaders/ambient_occlusion_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/background_vert.glsl SRC) -data_to_c_simple(engines/eevee/shaders/common_uniforms_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/common_utiltex_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/lights_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/lightprobe_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/lightprobe_geom.glsl SRC) -data_to_c_simple(engines/eevee/shaders/lightprobe_vert.glsl SRC) -data_to_c_simple(engines/eevee/shaders/lightprobe_cube_display_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/lightprobe_cube_display_vert.glsl SRC) -data_to_c_simple(engines/eevee/shaders/lightprobe_grid_display_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/lightprobe_grid_display_vert.glsl SRC) -data_to_c_simple(engines/eevee/shaders/lightprobe_grid_fill_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/lightprobe_planar_display_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/lightprobe_planar_display_vert.glsl SRC) -data_to_c_simple(engines/eevee/shaders/lookdev_world_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/closure_eval_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/closure_eval_diffuse_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/closure_eval_glossy_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/closure_eval_refraction_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/closure_eval_translucent_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/closure_type_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_bloom_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_dof_bokeh_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_dof_dilate_tiles_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_dof_downsample_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_dof_filter_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_dof_flatten_tiles_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_dof_gather_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_dof_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_dof_reduce_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_dof_resolve_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_dof_scatter_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_dof_scatter_vert.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_dof_setup_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_reflection_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_reflection_resolve_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_reflection_trace_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_downsample_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_downsample_cube_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_gtao_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_velocity_resolve_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_velocity_tile_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_minmaxz_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_mist_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_motion_blur_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_subsurface_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_translucency_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/effect_temporal_aa.glsl SRC) -data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl SRC) -data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl SRC) -data_to_c_simple(engines/eevee/shaders/object_motion_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/object_motion_vert.glsl SRC) -data_to_c_simple(engines/eevee/shaders/prepass_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/prepass_vert.glsl SRC) -data_to_c_simple(engines/eevee/shaders/shadow_accum_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/shadow_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/shadow_vert.glsl SRC) -data_to_c_simple(engines/eevee/shaders/bsdf_lut_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/btdf_lut_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/bsdf_common_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/irradiance_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/octahedron_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/cubemap_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/bsdf_sampling_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/random_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/raytrace_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/renderpass_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/renderpass_postprocess_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/cryptomatte_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/ltc_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/ssr_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/surface_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/surface_geom.glsl SRC) -data_to_c_simple(engines/eevee/shaders/surface_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/surface_vert.glsl SRC) -data_to_c_simple(engines/eevee/shaders/update_noise_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/volumetric_accum_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/volumetric_lib.glsl SRC) -data_to_c_simple(engines/eevee/shaders/volumetric_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/volumetric_geom.glsl SRC) -data_to_c_simple(engines/eevee/shaders/volumetric_vert.glsl SRC) -data_to_c_simple(engines/eevee/shaders/volumetric_resolve_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/volumetric_scatter_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/volumetric_integration_frag.glsl SRC) +set(GLSL_SRC + engines/eevee/shaders/ambient_occlusion_lib.glsl + engines/eevee/shaders/background_vert.glsl + engines/eevee/shaders/common_uniforms_lib.glsl + engines/eevee/shaders/common_utiltex_lib.glsl + engines/eevee/shaders/lights_lib.glsl + engines/eevee/shaders/lightprobe_lib.glsl + engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl + engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl + engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl + engines/eevee/shaders/lightprobe_geom.glsl + engines/eevee/shaders/lightprobe_vert.glsl + engines/eevee/shaders/lightprobe_cube_display_frag.glsl + engines/eevee/shaders/lightprobe_cube_display_vert.glsl + engines/eevee/shaders/lightprobe_grid_display_frag.glsl + engines/eevee/shaders/lightprobe_grid_display_vert.glsl + engines/eevee/shaders/lightprobe_grid_fill_frag.glsl + engines/eevee/shaders/lightprobe_planar_display_frag.glsl + engines/eevee/shaders/lightprobe_planar_display_vert.glsl + engines/eevee/shaders/lookdev_world_frag.glsl + engines/eevee/shaders/closure_eval_lib.glsl + engines/eevee/shaders/closure_eval_diffuse_lib.glsl + engines/eevee/shaders/closure_eval_glossy_lib.glsl + engines/eevee/shaders/closure_eval_refraction_lib.glsl + engines/eevee/shaders/closure_eval_translucent_lib.glsl + engines/eevee/shaders/closure_type_lib.glsl + engines/eevee/shaders/effect_bloom_frag.glsl + engines/eevee/shaders/effect_dof_bokeh_frag.glsl + engines/eevee/shaders/effect_dof_dilate_tiles_frag.glsl + engines/eevee/shaders/effect_dof_downsample_frag.glsl + engines/eevee/shaders/effect_dof_filter_frag.glsl + engines/eevee/shaders/effect_dof_flatten_tiles_frag.glsl + engines/eevee/shaders/effect_dof_gather_frag.glsl + engines/eevee/shaders/effect_dof_lib.glsl + engines/eevee/shaders/effect_dof_reduce_frag.glsl + engines/eevee/shaders/effect_dof_resolve_frag.glsl + engines/eevee/shaders/effect_dof_scatter_frag.glsl + engines/eevee/shaders/effect_dof_scatter_vert.glsl + engines/eevee/shaders/effect_dof_setup_frag.glsl + engines/eevee/shaders/effect_reflection_lib.glsl + engines/eevee/shaders/effect_reflection_resolve_frag.glsl + engines/eevee/shaders/effect_reflection_trace_frag.glsl + engines/eevee/shaders/effect_downsample_frag.glsl + engines/eevee/shaders/effect_downsample_cube_frag.glsl + engines/eevee/shaders/effect_gtao_frag.glsl + engines/eevee/shaders/effect_velocity_resolve_frag.glsl + engines/eevee/shaders/effect_velocity_tile_frag.glsl + engines/eevee/shaders/effect_minmaxz_frag.glsl + engines/eevee/shaders/effect_mist_frag.glsl + engines/eevee/shaders/effect_motion_blur_frag.glsl + engines/eevee/shaders/effect_subsurface_frag.glsl + engines/eevee/shaders/effect_translucency_frag.glsl + engines/eevee/shaders/effect_temporal_aa.glsl + engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl + engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl + engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl + engines/eevee/shaders/object_motion_frag.glsl + engines/eevee/shaders/object_motion_vert.glsl + engines/eevee/shaders/prepass_frag.glsl + engines/eevee/shaders/prepass_vert.glsl + engines/eevee/shaders/shadow_accum_frag.glsl + engines/eevee/shaders/shadow_frag.glsl + engines/eevee/shaders/shadow_vert.glsl + engines/eevee/shaders/bsdf_lut_frag.glsl + engines/eevee/shaders/btdf_lut_frag.glsl + engines/eevee/shaders/bsdf_common_lib.glsl + engines/eevee/shaders/irradiance_lib.glsl + engines/eevee/shaders/octahedron_lib.glsl + engines/eevee/shaders/cubemap_lib.glsl + engines/eevee/shaders/bsdf_sampling_lib.glsl + engines/eevee/shaders/random_lib.glsl + engines/eevee/shaders/raytrace_lib.glsl + engines/eevee/shaders/renderpass_lib.glsl + engines/eevee/shaders/renderpass_postprocess_frag.glsl + engines/eevee/shaders/cryptomatte_frag.glsl + engines/eevee/shaders/ltc_lib.glsl + engines/eevee/shaders/ssr_lib.glsl + engines/eevee/shaders/surface_frag.glsl + engines/eevee/shaders/surface_geom.glsl + engines/eevee/shaders/surface_lib.glsl + engines/eevee/shaders/surface_vert.glsl + engines/eevee/shaders/update_noise_frag.glsl + engines/eevee/shaders/volumetric_accum_frag.glsl + engines/eevee/shaders/volumetric_lib.glsl + engines/eevee/shaders/volumetric_frag.glsl + engines/eevee/shaders/volumetric_geom.glsl + engines/eevee/shaders/volumetric_vert.glsl + engines/eevee/shaders/volumetric_resolve_frag.glsl + engines/eevee/shaders/volumetric_scatter_frag.glsl + engines/eevee/shaders/volumetric_integration_frag.glsl -data_to_c_simple(engines/workbench/shaders/workbench_cavity_lib.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_common_lib.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_composite_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_curvature_lib.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_data_lib.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_effect_cavity_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_effect_dof_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_effect_outline_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_effect_smaa_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_effect_smaa_vert.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_effect_taa_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_image_lib.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_matcap_lib.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_material_lib.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_merge_infront_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_prepass_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_prepass_hair_vert.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_prepass_vert.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_shader_interface_lib.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_shadow_caps_geom.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_shadow_debug_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_shadow_geom.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_shadow_vert.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_transparent_accum_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_transparent_resolve_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_volume_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_volume_vert.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_world_light_lib.glsl SRC) + engines/workbench/shaders/workbench_cavity_lib.glsl + engines/workbench/shaders/workbench_common_lib.glsl + engines/workbench/shaders/workbench_composite_frag.glsl + engines/workbench/shaders/workbench_curvature_lib.glsl + engines/workbench/shaders/workbench_data_lib.glsl + engines/workbench/shaders/workbench_effect_cavity_frag.glsl + engines/workbench/shaders/workbench_effect_dof_frag.glsl + engines/workbench/shaders/workbench_effect_outline_frag.glsl + engines/workbench/shaders/workbench_effect_smaa_frag.glsl + engines/workbench/shaders/workbench_effect_smaa_vert.glsl + engines/workbench/shaders/workbench_effect_taa_frag.glsl + engines/workbench/shaders/workbench_image_lib.glsl + engines/workbench/shaders/workbench_matcap_lib.glsl + engines/workbench/shaders/workbench_material_lib.glsl + engines/workbench/shaders/workbench_merge_infront_frag.glsl + engines/workbench/shaders/workbench_prepass_frag.glsl + engines/workbench/shaders/workbench_prepass_hair_vert.glsl + engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl + engines/workbench/shaders/workbench_prepass_vert.glsl + engines/workbench/shaders/workbench_shader_interface_lib.glsl + engines/workbench/shaders/workbench_shadow_caps_geom.glsl + engines/workbench/shaders/workbench_shadow_debug_frag.glsl + engines/workbench/shaders/workbench_shadow_geom.glsl + engines/workbench/shaders/workbench_shadow_vert.glsl + engines/workbench/shaders/workbench_transparent_accum_frag.glsl + engines/workbench/shaders/workbench_transparent_resolve_frag.glsl + engines/workbench/shaders/workbench_volume_frag.glsl + engines/workbench/shaders/workbench_volume_vert.glsl + engines/workbench/shaders/workbench_world_light_lib.glsl -data_to_c_simple(intern/shaders/common_colormanagement_lib.glsl SRC) -data_to_c_simple(intern/shaders/common_globals_lib.glsl SRC) -data_to_c_simple(intern/shaders/common_pointcloud_lib.glsl SRC) -data_to_c_simple(intern/shaders/common_hair_lib.glsl SRC) -data_to_c_simple(intern/shaders/common_hair_refine_vert.glsl SRC) -data_to_c_simple(intern/shaders/common_hair_refine_comp.glsl SRC) -data_to_c_simple(intern/shaders/common_math_lib.glsl SRC) -data_to_c_simple(intern/shaders/common_math_geom_lib.glsl SRC) -data_to_c_simple(intern/shaders/common_view_lib.glsl SRC) -data_to_c_simple(intern/shaders/common_fxaa_lib.glsl SRC) -data_to_c_simple(intern/shaders/common_smaa_lib.glsl SRC) -data_to_c_simple(intern/shaders/common_fullscreen_vert.glsl SRC) -data_to_c_simple(intern/shaders/common_subdiv_custom_data_interp_comp.glsl SRC) -data_to_c_simple(intern/shaders/common_subdiv_ibo_lines_comp.glsl SRC) -data_to_c_simple(intern/shaders/common_subdiv_ibo_tris_comp.glsl SRC) -data_to_c_simple(intern/shaders/common_subdiv_lib.glsl SRC) -data_to_c_simple(intern/shaders/common_subdiv_normals_accumulate_comp.glsl SRC) -data_to_c_simple(intern/shaders/common_subdiv_normals_finalize_comp.glsl SRC) -data_to_c_simple(intern/shaders/common_subdiv_patch_evaluation_comp.glsl SRC) -data_to_c_simple(intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl SRC) -data_to_c_simple(intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl SRC) -data_to_c_simple(intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl SRC) -data_to_c_simple(intern/shaders/common_subdiv_vbo_lnor_comp.glsl SRC) -data_to_c_simple(intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl SRC) + engines/workbench/workbench_shader_shared.h -data_to_c_simple(engines/gpencil/shaders/gpencil_frag.glsl SRC) -data_to_c_simple(engines/gpencil/shaders/gpencil_vert.glsl SRC) -data_to_c_simple(engines/gpencil/shaders/gpencil_antialiasing_frag.glsl SRC) -data_to_c_simple(engines/gpencil/shaders/gpencil_antialiasing_vert.glsl SRC) -data_to_c_simple(engines/gpencil/shaders/gpencil_common_lib.glsl SRC) -data_to_c_simple(engines/gpencil/shaders/gpencil_layer_blend_frag.glsl SRC) -data_to_c_simple(engines/gpencil/shaders/gpencil_mask_invert_frag.glsl SRC) -data_to_c_simple(engines/gpencil/shaders/gpencil_depth_merge_frag.glsl SRC) -data_to_c_simple(engines/gpencil/shaders/gpencil_depth_merge_vert.glsl SRC) -data_to_c_simple(engines/gpencil/shaders/gpencil_vfx_frag.glsl SRC) + intern/shaders/common_colormanagement_lib.glsl + intern/shaders/common_globals_lib.glsl + intern/shaders/common_pointcloud_lib.glsl + intern/shaders/common_hair_lib.glsl + intern/shaders/common_hair_refine_vert.glsl + intern/shaders/common_hair_refine_comp.glsl + intern/shaders/common_math_lib.glsl + intern/shaders/common_math_geom_lib.glsl + intern/shaders/common_view_lib.glsl + intern/shaders/common_fxaa_lib.glsl + intern/shaders/common_smaa_lib.glsl + intern/shaders/common_fullscreen_vert.glsl -data_to_c_simple(engines/select/shaders/selection_id_3D_vert.glsl SRC) -data_to_c_simple(engines/select/shaders/selection_id_frag.glsl SRC) + intern/shaders/common_subdiv_custom_data_interp_comp.glsl + intern/shaders/common_subdiv_ibo_lines_comp.glsl + intern/shaders/common_subdiv_ibo_tris_comp.glsl + intern/shaders/common_subdiv_lib.glsl + intern/shaders/common_subdiv_normals_accumulate_comp.glsl + intern/shaders/common_subdiv_normals_finalize_comp.glsl + intern/shaders/common_subdiv_patch_evaluation_comp.glsl + intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl + intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl + intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl + intern/shaders/common_subdiv_vbo_lnor_comp.glsl + intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl -data_to_c_simple(engines/basic/shaders/conservative_depth_geom.glsl SRC) -data_to_c_simple(engines/basic/shaders/depth_vert.glsl SRC) -data_to_c_simple(engines/basic/shaders/depth_frag.glsl SRC) + intern/draw_shader_shared.h -data_to_c_simple(engines/overlay/shaders/common_overlay_lib.glsl SRC) -data_to_c_simple(engines/overlay/shaders/antialiasing_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/antialiasing_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/armature_dof_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/armature_dof_solid_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/armature_envelope_outline_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/armature_envelope_solid_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/armature_envelope_solid_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/armature_shape_outline_geom.glsl SRC) -data_to_c_simple(engines/overlay/shaders/armature_shape_outline_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/armature_shape_solid_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/armature_shape_solid_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/armature_shape_wire_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/armature_sphere_outline_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/armature_sphere_solid_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/armature_sphere_solid_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/armature_stick_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/armature_stick_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/armature_wire_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/armature_wire_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/background_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/clipbound_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/depth_only_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_curve_handle_geom.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_curve_handle_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_curve_point_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_curve_wire_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_gpencil_canvas_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_gpencil_guide_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_gpencil_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_lattice_point_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_lattice_wire_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_mesh_common_lib.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_mesh_facefill_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_mesh_facefill_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_mesh_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_mesh_geom.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_mesh_normal_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_mesh_analysis_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_mesh_analysis_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_mesh_skin_root_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_mesh_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_particle_strand_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_particle_point_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_uv_edges_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_uv_edges_geom.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_uv_edges_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_uv_verts_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_uv_verts_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_uv_faces_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_uv_face_dots_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_uv_image_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_uv_image_mask_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_uv_stretching_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/extra_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/extra_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/extra_groundline_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/extra_lightprobe_grid_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/extra_loose_point_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/extra_loose_point_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/extra_point_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/extra_wire_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/extra_wire_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/facing_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/facing_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/grid_background_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/grid_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/grid_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/image_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/image_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/motion_path_line_geom.glsl SRC) -data_to_c_simple(engines/overlay/shaders/motion_path_line_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/motion_path_point_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/outline_detect_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/outline_prepass_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/outline_prepass_geom.glsl SRC) -data_to_c_simple(engines/overlay/shaders/outline_prepass_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/paint_face_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/paint_point_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/paint_texture_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/paint_texture_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/paint_vertcol_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/paint_vertcol_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/paint_weight_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/paint_weight_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/paint_wire_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/particle_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/particle_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/sculpt_mask_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/sculpt_mask_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/volume_velocity_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/volume_gridlines_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/wireframe_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/wireframe_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/xray_fade_frag.glsl SRC) + engines/gpencil/shaders/gpencil_frag.glsl + engines/gpencil/shaders/gpencil_vert.glsl + engines/gpencil/shaders/gpencil_antialiasing_frag.glsl + engines/gpencil/shaders/gpencil_antialiasing_vert.glsl + engines/gpencil/shaders/gpencil_common_lib.glsl + engines/gpencil/shaders/gpencil_layer_blend_frag.glsl + engines/gpencil/shaders/gpencil_mask_invert_frag.glsl + engines/gpencil/shaders/gpencil_depth_merge_frag.glsl + engines/gpencil/shaders/gpencil_depth_merge_vert.glsl + engines/gpencil/shaders/gpencil_vfx_frag.glsl -data_to_c_simple(engines/image/shaders/engine_image_frag.glsl SRC) -data_to_c_simple(engines/image/shaders/engine_image_vert.glsl SRC) + engines/select/shaders/selection_id_3D_vert.glsl + engines/select/shaders/selection_id_frag.glsl + + engines/basic/shaders/conservative_depth_geom.glsl + engines/basic/shaders/depth_vert.glsl + engines/basic/shaders/depth_frag.glsl + + engines/overlay/shaders/common_overlay_lib.glsl + engines/overlay/shaders/antialiasing_frag.glsl + engines/overlay/shaders/antialiasing_vert.glsl + engines/overlay/shaders/armature_dof_vert.glsl + engines/overlay/shaders/armature_dof_solid_frag.glsl + engines/overlay/shaders/armature_envelope_outline_vert.glsl + engines/overlay/shaders/armature_envelope_solid_frag.glsl + engines/overlay/shaders/armature_envelope_solid_vert.glsl + engines/overlay/shaders/armature_shape_outline_geom.glsl + engines/overlay/shaders/armature_shape_outline_vert.glsl + engines/overlay/shaders/armature_shape_solid_frag.glsl + engines/overlay/shaders/armature_shape_solid_vert.glsl + engines/overlay/shaders/armature_shape_wire_vert.glsl + engines/overlay/shaders/armature_sphere_outline_vert.glsl + engines/overlay/shaders/armature_sphere_solid_frag.glsl + engines/overlay/shaders/armature_sphere_solid_vert.glsl + engines/overlay/shaders/armature_stick_frag.glsl + engines/overlay/shaders/armature_stick_vert.glsl + engines/overlay/shaders/armature_wire_frag.glsl + engines/overlay/shaders/armature_wire_vert.glsl + engines/overlay/shaders/background_frag.glsl + engines/overlay/shaders/clipbound_vert.glsl + engines/overlay/shaders/depth_only_vert.glsl + engines/overlay/shaders/edit_curve_handle_geom.glsl + engines/overlay/shaders/edit_curve_handle_vert.glsl + engines/overlay/shaders/edit_curve_point_vert.glsl + engines/overlay/shaders/edit_curve_wire_vert.glsl + engines/overlay/shaders/edit_gpencil_canvas_vert.glsl + engines/overlay/shaders/edit_gpencil_guide_vert.glsl + engines/overlay/shaders/edit_gpencil_vert.glsl + engines/overlay/shaders/edit_lattice_point_vert.glsl + engines/overlay/shaders/edit_lattice_wire_vert.glsl + engines/overlay/shaders/edit_mesh_common_lib.glsl + engines/overlay/shaders/edit_mesh_facefill_frag.glsl + engines/overlay/shaders/edit_mesh_facefill_vert.glsl + engines/overlay/shaders/edit_mesh_frag.glsl + engines/overlay/shaders/edit_mesh_geom.glsl + engines/overlay/shaders/edit_mesh_normal_vert.glsl + engines/overlay/shaders/edit_mesh_analysis_frag.glsl + engines/overlay/shaders/edit_mesh_analysis_vert.glsl + engines/overlay/shaders/edit_mesh_skin_root_vert.glsl + engines/overlay/shaders/edit_mesh_vert.glsl + engines/overlay/shaders/edit_particle_strand_vert.glsl + engines/overlay/shaders/edit_particle_point_vert.glsl + engines/overlay/shaders/edit_uv_edges_vert.glsl + engines/overlay/shaders/edit_uv_edges_geom.glsl + engines/overlay/shaders/edit_uv_edges_frag.glsl + engines/overlay/shaders/edit_uv_verts_vert.glsl + engines/overlay/shaders/edit_uv_verts_frag.glsl + engines/overlay/shaders/edit_uv_faces_vert.glsl + engines/overlay/shaders/edit_uv_face_dots_vert.glsl + engines/overlay/shaders/edit_uv_image_vert.glsl + engines/overlay/shaders/edit_uv_image_mask_frag.glsl + engines/overlay/shaders/edit_uv_stretching_vert.glsl + engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl + engines/overlay/shaders/extra_frag.glsl + engines/overlay/shaders/extra_vert.glsl + engines/overlay/shaders/extra_groundline_vert.glsl + engines/overlay/shaders/extra_lightprobe_grid_vert.glsl + engines/overlay/shaders/extra_loose_point_frag.glsl + engines/overlay/shaders/extra_loose_point_vert.glsl + engines/overlay/shaders/extra_point_vert.glsl + engines/overlay/shaders/extra_wire_frag.glsl + engines/overlay/shaders/extra_wire_vert.glsl + engines/overlay/shaders/facing_frag.glsl + engines/overlay/shaders/facing_vert.glsl + engines/overlay/shaders/grid_background_frag.glsl + engines/overlay/shaders/grid_frag.glsl + engines/overlay/shaders/grid_vert.glsl + engines/overlay/shaders/image_vert.glsl + engines/overlay/shaders/image_frag.glsl + engines/overlay/shaders/motion_path_line_geom.glsl + engines/overlay/shaders/motion_path_line_vert.glsl + engines/overlay/shaders/motion_path_point_vert.glsl + engines/overlay/shaders/outline_detect_frag.glsl + engines/overlay/shaders/outline_prepass_frag.glsl + engines/overlay/shaders/outline_prepass_geom.glsl + engines/overlay/shaders/outline_prepass_vert.glsl + engines/overlay/shaders/paint_face_vert.glsl + engines/overlay/shaders/paint_point_vert.glsl + engines/overlay/shaders/paint_texture_frag.glsl + engines/overlay/shaders/paint_texture_vert.glsl + engines/overlay/shaders/paint_vertcol_frag.glsl + engines/overlay/shaders/paint_vertcol_vert.glsl + engines/overlay/shaders/paint_weight_frag.glsl + engines/overlay/shaders/paint_weight_vert.glsl + engines/overlay/shaders/paint_wire_vert.glsl + engines/overlay/shaders/particle_vert.glsl + engines/overlay/shaders/particle_frag.glsl + engines/overlay/shaders/sculpt_mask_vert.glsl + engines/overlay/shaders/sculpt_mask_frag.glsl + engines/overlay/shaders/volume_velocity_vert.glsl + engines/overlay/shaders/volume_gridlines_vert.glsl + engines/overlay/shaders/wireframe_vert.glsl + engines/overlay/shaders/wireframe_frag.glsl + engines/overlay/shaders/xray_fade_frag.glsl + + engines/image/shaders/engine_image_frag.glsl + engines/image/shaders/engine_image_vert.glsl +) + +set(GLSL_C) +foreach(GLSL_FILE ${GLSL_SRC}) + data_to_c_simple(${GLSL_FILE} GLSL_C) +endforeach() + +blender_add_lib(bf_draw_shaders "${GLSL_C}" "" "" "") + +list(APPEND LIB + bf_draw_shaders +) + +set(GLSL_SOURCE_CONTENT "") +foreach(GLSL_FILE ${GLSL_SRC}) + get_filename_component(GLSL_FILE_NAME ${GLSL_FILE} NAME) + string(REPLACE "." "_" GLSL_FILE_NAME_UNDERSCORES ${GLSL_FILE_NAME}) + string(APPEND GLSL_SOURCE_CONTENT "SHADER_SOURCE\(datatoc_${GLSL_FILE_NAME_UNDERSCORES}, \"${GLSL_FILE_NAME}\"\)\n") +endforeach() + +set(glsl_source_list_file "${CMAKE_CURRENT_BINARY_DIR}/glsl_draw_source_list.h") +file(GENERATE OUTPUT ${glsl_source_list_file} CONTENT "${GLSL_SOURCE_CONTENT}") +list(APPEND SRC ${glsl_source_list_file}) +list(APPEND INC ${CMAKE_CURRENT_BINARY_DIR}) + +target_include_directories(bf_draw_shaders PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) list(APPEND INC ) diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c index af5c6d07e59..fea3de7bc57 100644 --- a/source/blender/draw/engines/overlay/overlay_armature.c +++ b/source/blender/draw/engines/overlay/overlay_armature.c @@ -660,7 +660,7 @@ static void drw_shgroup_bone_custom_solid(ArmatureDrawContext *ctx, * by #data_eval. This is bad since it gives preference to an object's evaluated mesh over any * other data type, but supporting all evaluated geometry components would require a much larger * refactor of this area. */ - Mesh *mesh = BKE_object_get_evaluated_mesh(custom); + Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(custom); if (mesh == NULL) { return; } diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c index 389704b3d66..9899dce5df6 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.c +++ b/source/blender/draw/engines/overlay/overlay_shader.c @@ -323,7 +323,9 @@ GPUShader *OVERLAY_shader_edit_mesh_vert(void) datatoc_edit_mesh_common_lib_glsl, datatoc_edit_mesh_vert_glsl, NULL}, - .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL}, + .frag = (const char *[]){datatoc_common_globals_lib_glsl, + datatoc_gpu_shader_point_varying_color_frag_glsl, + NULL}, .defs = (const char *[]){sh_cfg->def, "#define VERT\n", NULL}, }); } diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl index 195d2a5a7b7..418c7bceb63 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl +++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl @@ -36,7 +36,7 @@ vec4 EDIT_MESH_edge_vertex_color(int vertex_flag) return color; } -vec4 EDIT_MESH_vertex_color(int vertex_flag) +vec4 EDIT_MESH_vertex_color(int vertex_flag, float vertex_crease) { if ((vertex_flag & VERT_ACTIVE) != 0) { return vec4(colorEditMeshActive.xyz, 1.0); @@ -45,6 +45,10 @@ vec4 EDIT_MESH_vertex_color(int vertex_flag) return colorVertexSelect; } else { + /* Full crease color if not selected nor active. */ + if (vertex_crease > 0.0) { + return mix(colorVertex, colorEdgeCrease, vertex_crease); + } return colorVertex; } } diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl index a3ff277b714..5cee976f9a8 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl @@ -13,6 +13,9 @@ in vec4 norAndFlag; #endif out vec4 finalColor; +#ifdef VERT +out float vertexCrease; +#endif #ifdef EDGE out vec4 finalColorOuter; #endif @@ -44,8 +47,9 @@ void main() ivec4 m_data = data & dataMask; #if defined(VERT) - finalColor = EDIT_MESH_vertex_color(m_data.y); - gl_PointSize = sizeVertex * 2.0; + vertexCrease = float(m_data.z >> 4) / 15.0; + finalColor = EDIT_MESH_vertex_color(m_data.y, vertexCrease); + gl_PointSize = sizeVertex * ((vertexCrease > 0.0) ? 3.0 : 2.0); /* Make selected and active vertex always on top. */ if ((data.x & VERT_SELECTED) != 0) { gl_Position.z -= 5e-7 * abs(gl_Position.w); @@ -65,9 +69,9 @@ void main() selectOverride = (m_data.y & EDGE_SELECTED); # endif - float crease = float(m_data.z) / 255.0; + float edge_crease = float(m_data.z & 0xF) / 15.0; float bweight = float(m_data.w) / 255.0; - finalColorOuter = EDIT_MESH_edge_color_outer(m_data.y, m_data.x, crease, bweight); + finalColorOuter = EDIT_MESH_edge_color_outer(m_data.y, m_data.x, edge_crease, bweight); if (finalColorOuter.a > 0.0) { gl_Position.z -= 5e-7 * abs(gl_Position.w); diff --git a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl index 8cbc8608f5b..9b142fe56b5 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl @@ -3,10 +3,6 @@ #define CAVITY_BUFFER_RANGE 4.0 -#ifdef WORKBENCH_ENCODE_NORMALS - -# define WB_Normal vec2 - /* From http://aras-p.info/texts/CompactNormalStorage.html * Using Method #4: Spheremap Transform */ vec3 workbench_normal_decode(vec4 enc) @@ -22,7 +18,7 @@ vec3 workbench_normal_decode(vec4 enc) /* From http://aras-p.info/texts/CompactNormalStorage.html * Using Method #4: Spheremap Transform */ -WB_Normal workbench_normal_encode(bool front_face, vec3 n) +vec2 workbench_normal_encode(bool front_face, vec3 n) { n = normalize(front_face ? n : -n); float p = sqrt(n.z * 8.0 + 8.0); @@ -30,13 +26,6 @@ WB_Normal workbench_normal_encode(bool front_face, vec3 n) return n.xy; } -#else -# define WB_Normal vec3 -/* Well just do nothing... */ -# define workbench_normal_encode(f, a) (a) -# define workbench_normal_decode(a) (a.xyz) -#endif /* WORKBENCH_ENCODE_NORMALS */ - /* Encoding into the alpha of a RGBA16F texture. (10bit mantissa) */ #define TARGET_BITCOUNT 8u #define METALLIC_BITS 3u /* Metallic channel is less important. */ diff --git a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl index 2e229d4d83a..c784c8b2db9 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl @@ -1,3 +1,5 @@ + +#ifndef WORKBENCH_SHADER_SHARED_H struct LightData { vec4 direction; vec4 specular_color; @@ -37,9 +39,10 @@ struct WorldData { int _pad2; }; -#define viewport_size_inv viewport_size.zw +# define viewport_size_inv viewport_size.zw layout(std140) uniform world_block { WorldData world_data; }; +#endif diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl index 328d50e69e0..0b571040df5 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl @@ -4,6 +4,8 @@ #pragma BLENDER_REQUIRE(workbench_cavity_lib.glsl) #pragma BLENDER_REQUIRE(workbench_curvature_lib.glsl) +#ifndef DRW_SHADER_SHARED_H + uniform sampler2D depthBuffer; uniform sampler2D normalBuffer; uniform usampler2D objectIdBuffer; @@ -12,6 +14,8 @@ in vec4 uvcoordsvar; out vec4 fragColor; +#endif + void main() { float cavity = 0.0, edges = 0.0, curvature = 0.0; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl index 57d648d3565..49e3f57ab2e 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl @@ -25,12 +25,14 @@ bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map) return true; } +#ifndef WORKBENCH_SHADER_SHARED_H uniform sampler2DArray imageTileArray; uniform sampler1DArray imageTileData; uniform sampler2D imageTexture; uniform float imageTransparencyCutoff = 0.1; uniform bool imagePremult; +#endif vec3 workbench_image_color(vec2 uvs) { diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl index 6d24b001d4d..7a3ebc4035e 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl @@ -4,9 +4,11 @@ #pragma BLENDER_REQUIRE(workbench_common_lib.glsl) #pragma BLENDER_REQUIRE(workbench_image_lib.glsl) +#ifndef WORKBENCH_SHADER_SHARED_H layout(location = 0) out vec4 materialData; -layout(location = 1) out WB_Normal normalData; +layout(location = 1) out vec2 normalData; layout(location = 2) out uint objectId; +#endif uniform bool useMatcap = false; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl index 3e1ea14f47c..c3faa3957ef 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl @@ -5,8 +5,10 @@ #pragma BLENDER_REQUIRE(workbench_material_lib.glsl) #pragma BLENDER_REQUIRE(workbench_image_lib.glsl) +#ifndef WORKBENCH_SHADER_SHARED_H uniform samplerBuffer ac; /* active color layer */ uniform samplerBuffer au; /* active texture layer */ +#endif /* From http://libnoise.sourceforge.net/noisegen/index.html */ float integer_noise(int n) @@ -71,8 +73,10 @@ void main() normal_interp = normalize(normal_world_to_view(nor)); -#ifdef OPAQUE_MATERIAL +#ifndef WORKBENCH_SHADER_SHARED_H +# ifdef OPAQUE_MATERIAL float metallic, roughness; +# endif #endif workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic); diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl index 6f61874b8f5..8efe10b8236 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl @@ -21,8 +21,10 @@ void main() uv_interp = vec2(0.0); -#ifdef OPAQUE_MATERIAL +#ifndef WORKBENCH_SHADER_SHARED_H +# ifdef OPAQUE_MATERIAL float metallic, roughness; +# endif #endif workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic); diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl index 1192081caf1..1f6a8a63944 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl @@ -5,10 +5,12 @@ #pragma BLENDER_REQUIRE(workbench_material_lib.glsl) #pragma BLENDER_REQUIRE(workbench_image_lib.glsl) +#ifndef WORKBENCH_SHADER_SHARED_H in vec3 pos; in vec3 nor; in vec4 ac; /* active color */ in vec2 au; /* active texture layer */ +#endif void main() { @@ -23,8 +25,10 @@ void main() normal_interp = normalize(normal_object_to_view(nor)); -#ifdef OPAQUE_MATERIAL +#ifndef WORKBENCH_SHADER_SHARED_H +# ifdef OPAQUE_MATERIAL float metallic, roughness; +# endif #endif workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic); diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl index 6bfa351aeb0..178e61c8a8d 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl @@ -1,15 +1,17 @@ +#ifndef WORKBENCH_SHADER_SHARED_H IN_OUT ShaderStageInterface { vec3 normal_interp; vec3 color_interp; float alpha_interp; vec2 uv_interp; -#ifdef TRANSPARENT_MATERIAL +# ifdef TRANSPARENT_MATERIAL flat float roughness; flat float metallic; -#else +# else flat float packed_rough_metal; -#endif +# endif flat int object_id; }; +#endif diff --git a/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl index 3f113fd4b2e..0062cbe17a2 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl @@ -6,6 +6,7 @@ #pragma BLENDER_REQUIRE(workbench_matcap_lib.glsl) #pragma BLENDER_REQUIRE(workbench_world_light_lib.glsl) +#ifndef WORKBENCH_SHADER_SHARED_H /* Revealage is actually stored in transparentAccum alpha channel. * This is a workaround to older hardware not having separate blend equation per render target. */ layout(location = 0) out vec4 transparentAccum; @@ -13,6 +14,7 @@ layout(location = 1) out vec4 revealageAccum; /* NOTE: Blending will be skipped on objectId because output is a non-normalized integer buffer. */ layout(location = 2) out uint objectId; +#endif /* Special function only to be used with calculate_transparent_weight(). */ float linear_zdepth(float depth, vec4 viewvecs[2], mat4 proj_mat) diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c index ea06e21e26e..68c74781d57 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c +++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c @@ -491,7 +491,8 @@ MeshRenderData *mesh_render_data_create(Mesh *me, mr->eed_act = BM_mesh_active_edge_get(mr->bm); mr->eve_act = BM_mesh_active_vert_get(mr->bm); - mr->crease_ofs = CustomData_get_offset(&mr->bm->edata, CD_CREASE); + mr->vert_crease_ofs = CustomData_get_offset(&mr->bm->vdata, CD_CREASE); + mr->edge_crease_ofs = CustomData_get_offset(&mr->bm->edata, CD_CREASE); mr->bweight_ofs = CustomData_get_offset(&mr->bm->edata, CD_BWEIGHT); #ifdef WITH_FREESTYLE mr->freestyle_edge_ofs = CustomData_get_offset(&mr->bm->edata, CD_FREESTYLE_EDGE); diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc index e975d213e22..37bc9435c76 100644 --- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc +++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc @@ -1693,7 +1693,8 @@ void draw_subdiv_init_mesh_render_data(DRWSubdivCache *cache, mr->eed_act = BM_mesh_active_edge_get(bm); mr->efa_act = BM_mesh_active_face_get(bm, false, true); mr->eve_act = BM_mesh_active_vert_get(bm); - mr->crease_ofs = CustomData_get_offset(&bm->edata, CD_CREASE); + mr->edge_crease_ofs = CustomData_get_offset(&bm->edata, CD_CREASE); + mr->vert_crease_ofs = CustomData_get_offset(&bm->vdata, CD_CREASE); mr->bweight_ofs = CustomData_get_offset(&bm->edata, CD_BWEIGHT); #ifdef WITH_FREESTYLE mr->freestyle_edge_ofs = CustomData_get_offset(&bm->edata, CD_FREESTYLE_EDGE); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 93f90d09b22..022d7127317 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -72,6 +72,7 @@ #include "GPU_framebuffer.h" #include "GPU_immediate.h" #include "GPU_matrix.h" +#include "GPU_shader_shared.h" #include "GPU_state.h" #include "GPU_uniform_buffer.h" #include "GPU_viewport.h" @@ -2758,11 +2759,15 @@ void DRW_draw_depth_object( GPU_framebuffer_clear_depth(depth_fb, 1.0f); GPU_depth_test(GPU_DEPTH_LESS_EQUAL); - const float(*world_clip_planes)[4] = NULL; - if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { + struct GPUClipPlanes planes; + const bool use_clipping_planes = RV3D_CLIPPING_ENABLED(v3d, rv3d); + if (use_clipping_planes) { GPU_clip_distances(6); ED_view3d_clipping_local(rv3d, object->obmat); - world_clip_planes = rv3d->clip_local; + for (int i = 0; i < 6; i++) { + copy_v4_v4(planes.world[i], rv3d->clip_local[i]); + } + copy_m4_m4(planes.ModelMatrix, object->obmat); } drw_batch_cache_validate(object); @@ -2784,14 +2789,19 @@ void DRW_draw_depth_object( BLI_task_graph_work_and_wait(task_graph); BLI_task_graph_free(task_graph); - const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED : - GPU_SHADER_CFG_DEFAULT; + const eGPUShaderConfig sh_cfg = use_clipping_planes ? GPU_SHADER_CFG_CLIPPED : + GPU_SHADER_CFG_DEFAULT; GPU_batch_program_set_builtin_with_config(batch, GPU_SHADER_3D_DEPTH_ONLY, sh_cfg); - if (world_clip_planes != NULL) { - GPU_batch_uniform_4fv_array(batch, "WorldClipPlanes", 6, world_clip_planes); + + GPUUniformBuf *ubo = NULL; + if (use_clipping_planes) { + ubo = GPU_uniformbuf_create_ex(sizeof(struct GPUClipPlanes), &planes, __func__); + GPU_batch_uniformbuf_bind(batch, "clipPlanes", ubo); } GPU_batch_draw(batch); + GPU_uniformbuf_free(ubo); + } break; case OB_CURVE: case OB_SURF: diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.h index 0ed52edd1d2..40007d7cd8e 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.h @@ -85,7 +85,8 @@ typedef struct MeshRenderData { const float (*bm_poly_centers)[3]; int *v_origindex, *e_origindex, *p_origindex; - int crease_ofs; + int edge_crease_ofs; + int vert_crease_ofs; int bweight_ofs; int freestyle_edge_ofs; int freestyle_face_ofs; @@ -309,6 +310,8 @@ void mesh_render_data_update_looptris(MeshRenderData *mr, typedef struct EditLoopData { uchar v_flag; uchar e_flag; + /* This is used for both vertex and edge creases. The edge crease value is stored in the bottom 4 + * bits, while the vertex crease is stored in the upper 4 bits. */ uchar crease; uchar bweight; } EditLoopData; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc index 3cc1375329e..0002b95c867 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc @@ -72,11 +72,11 @@ static void mesh_render_data_edge_flag(const MeshRenderData *mr, } } - /* Use a byte for value range */ - if (mr->crease_ofs != -1) { - float crease = BM_ELEM_CD_GET_FLOAT(eed, mr->crease_ofs); + /* Use half a byte for value range */ + if (mr->edge_crease_ofs != -1) { + float crease = BM_ELEM_CD_GET_FLOAT(eed, mr->edge_crease_ofs); if (crease > 0) { - eattr->crease = (uchar)(crease * 255.0f); + eattr->crease = (uchar)ceil(crease * 15.0f); } } /* Use a byte for value range */ @@ -107,6 +107,13 @@ static void mesh_render_data_vert_flag(const MeshRenderData *mr, if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { eattr->e_flag |= VFLAG_VERT_SELECTED; } + /* Use half a byte for value range */ + if (mr->vert_crease_ofs != -1) { + float crease = BM_ELEM_CD_GET_FLOAT(eve, mr->vert_crease_ofs); + if (crease > 0) { + eattr->crease |= (uchar)ceil(crease * 15.0f) << 4; + } + } } static GPUVertFormat *get_edit_data_format() diff --git a/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl b/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl index 8a7fb97d98c..53ec38fea0b 100644 --- a/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl +++ b/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl @@ -1,5 +1,7 @@ +#ifndef USE_GPU_SHADER_CREATE_INFO out vec4 uvcoordsvar; +#endif void main() { diff --git a/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl b/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl index 74b989441a2..2da16d3f6a9 100644 --- a/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl +++ b/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl @@ -2,6 +2,8 @@ /* NOTE: To be used with UNIFORM_RESOURCE_ID and INSTANCED_ATTR as define. */ #pragma BLENDER_REQUIRE(common_view_lib.glsl) +#ifndef DRW_SHADER_SHARED_H + in vec4 pos; /* Position and radius. */ /* ---- Instanced attribs ---- */ @@ -9,6 +11,8 @@ in vec4 pos; /* Position and radius. */ in vec3 pos_inst; in vec3 nor; +#endif + mat3 pointcloud_get_facing_matrix(vec3 p) { mat3 facing_mat; diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl index e9912ba7d9a..b0d405165f2 100644 --- a/source/blender/draw/intern/shaders/common_view_lib.glsl +++ b/source/blender/draw/intern/shaders/common_view_lib.glsl @@ -1,5 +1,7 @@ -#define COMMON_VIEW_LIB -#define DRW_RESOURCE_CHUNK_LEN 512 +/* Temporary until we fully make the switch. */ +#ifndef DRW_SHADER_SHARED_H + +# define DRW_RESOURCE_CHUNK_LEN 512 /* keep in sync with DRWManager.view_data */ layout(std140) uniform viewBlock @@ -22,6 +24,8 @@ layout(std140) uniform viewBlock vec4 CameraTexCoFactors; }; +#endif /* DRW_SHADER_SHARED_H */ + #define ViewNear (ViewVecs[0].w) #define ViewFar (ViewVecs[1].w) @@ -141,6 +145,10 @@ flat in int resourceIDFrag; /* clang-format off */ #if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && !defined(OS_MAC) && !defined(INSTANCED_ATTR) /* clang-format on */ + +/* Temporary until we fully make the switch. */ +# ifndef DRW_SHADER_SHARED_H + struct ObjectMatrices { mat4 drw_modelMatrix; mat4 drw_modelMatrixInverse; @@ -150,17 +158,23 @@ layout(std140) uniform modelBlock { ObjectMatrices drw_matrices[DRW_RESOURCE_CHUNK_LEN]; }; +# endif /* DRW_SHADER_SHARED_H */ # define ModelMatrix (drw_matrices[resource_id].drw_modelMatrix) # define ModelMatrixInverse (drw_matrices[resource_id].drw_modelMatrixInverse) #else /* GPU_INTEL */ + +/* Temporary until we fully make the switch. */ +# ifndef DRW_SHADER_SHARED_H /* Intel GPU seems to suffer performance impact when the model matrix is in UBO storage. * So for now we just force using the legacy path. */ /* Note that this is also a workaround of a problem on osx (amd or nvidia) * and older amd driver on windows. */ uniform mat4 ModelMatrix; uniform mat4 ModelMatrixInverse; +# endif /* DRW_SHADER_SHARED_H */ + #endif #define resource_handle (resourceChunk * DRW_RESOURCE_CHUNK_LEN + resource_id) diff --git a/source/blender/editors/asset/intern/asset_indexer.cc b/source/blender/editors/asset/intern/asset_indexer.cc index a9c6e3798c9..336ccff900c 100644 --- a/source/blender/editors/asset/intern/asset_indexer.cc +++ b/source/blender/editors/asset/intern/asset_indexer.cc @@ -39,6 +39,7 @@ #include "BKE_appdir.h" #include "BKE_asset.h" #include "BKE_asset_catalog.hh" +#include "BKE_idprop.hh" #include "BKE_preferences.h" #include "CLG_log.h" @@ -49,6 +50,7 @@ namespace blender::ed::asset::index { using namespace blender::io::serialize; using namespace blender::bke; +using namespace blender::bke::idprop; /** * \file asset_indexer.cc @@ -69,12 +71,13 @@ using namespace blender::bke; * "catalog_name": "", * "description": "", * "author": "", - * "tags": [""] + * "tags": [""], + * "properties": [..] * }] * } * \endcode * - * NOTE: entries, author, description and tags are optional attributes. + * NOTE: entries, author, description, tags and properties are optional attributes. * * NOTE: File browser uses name and idcode separate. Inside the index they are joined together like * #ID.name. @@ -88,6 +91,7 @@ constexpr StringRef ATTRIBUTE_ENTRIES_CATALOG_NAME("catalog_name"); constexpr StringRef ATTRIBUTE_ENTRIES_DESCRIPTION("description"); constexpr StringRef ATTRIBUTE_ENTRIES_AUTHOR("author"); constexpr StringRef ATTRIBUTE_ENTRIES_TAGS("tags"); +constexpr StringRef ATTRIBUTE_ENTRIES_PROPERTIES("properties"); /** Abstract class for #BlendFile and #AssetIndexFile. */ class AbstractFile { @@ -216,6 +220,20 @@ struct AssetEntryReader { BKE_asset_metadata_tag_add(asset_data, tag_name.c_str()); } } + + void add_properties_to_meta_data(AssetMetaData *asset_data) const + { + BLI_assert(asset_data->properties == nullptr); + const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr( + ATTRIBUTE_ENTRIES_PROPERTIES); + if (value_ptr == nullptr) { + return; + } + + const Value &value = *(value_ptr->get()); + IDProperty *properties = convert_from_serialize_value(value); + asset_data->properties = properties; + } }; struct AssetEntryWriter { @@ -274,6 +292,15 @@ struct AssetEntryWriter { tag_items.append_as(new StringValue(tag->name)); } } + + void add_properties(const IDProperty *properties) + { + std::unique_ptr value = convert_to_serialize_values(properties); + if (value == nullptr) { + return; + } + attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_PROPERTIES, value.release())); + } }; static void init_value_from_file_indexer_entry(AssetEntryWriter &result, @@ -298,6 +325,10 @@ static void init_value_from_file_indexer_entry(AssetEntryWriter &result, result.add_tags(&asset_data.tags); } + if (asset_data.properties != nullptr) { + result.add_properties(asset_data.properties); + } + /* TODO: asset_data.IDProperties */ } @@ -363,6 +394,7 @@ static void init_indexer_entry_from_value(FileIndexerEntry &indexer_entry, asset_data->catalog_id = entry.get_catalog_id(); entry.add_tags_to_meta_data(asset_data); + entry.add_properties_to_meta_data(asset_data); } static int init_indexer_entries_from_value(FileIndexerEntries &indexer_entries, diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc index 1bfdd83b8e3..c075ae390d9 100644 --- a/source/blender/editors/asset/intern/asset_list.cc +++ b/source/blender/editors/asset/intern/asset_list.cc @@ -49,10 +49,6 @@ #include "ED_asset_list.hh" #include "asset_library_reference.hh" -/* Enable asset indexing. Currently disabled as ID properties aren't indexed yet and is needed for - * object snapping. See {D12990}. */ -//#define SPACE_FILE_ENABLE_ASSET_INDEXING - namespace blender::ed::asset { /* -------------------------------------------------------------------- */ @@ -174,9 +170,7 @@ void AssetList::setup() "", ""); -#ifdef SPACE_FILE_ENABLE_ASSET_INDEXING filelist_setindexer(files, &file_indexer_asset); -#endif char path[FILE_MAXDIR] = ""; if (user_library) { diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index a034e4bb10e..a70bc1c0350 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -4953,19 +4953,22 @@ bool ed_editnurb_spin( if ((a & 1) == 0) { rotateflagNurb(editnurb, SELECT, cent, scalemat1); - weightflagNurb(editnurb, SELECT, 0.25 * M_SQRT2); + weightflagNurb(editnurb, SELECT, 0.5 * M_SQRT2); } else { rotateflagNurb(editnurb, SELECT, cent, scalemat2); - weightflagNurb(editnurb, SELECT, 4.0 / M_SQRT2); + weightflagNurb(editnurb, SELECT, 2.0 / M_SQRT2); } } if (ok) { LISTBASE_FOREACH (Nurb *, nu, editnurb) { if (ED_curve_nurb_select_check(v3d, nu)) { - nu->orderv = 4; - nu->flagv |= CU_NURB_CYCLIC; + nu->orderv = 3; + /* It is challenging to create a good approximation of a circle with uniform knots vector + * (which is forced in Blender for cyclic NURBS curves). Here a NURBS circle is constructed + * by connecting four Bezier arcs. */ + nu->flagv |= CU_NURB_CYCLIC | CU_NURB_BEZIER; BKE_nurb_knot_calc_v(nu); } } diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c index 614805a70f5..daef4a21692 100644 --- a/source/blender/editors/curve/editcurve_add.c +++ b/source/blender/editors/curve/editcurve_add.c @@ -306,9 +306,9 @@ Nurb *ED_curve_add_nurbs_primitive( else if (cutype == CU_NURBS) { /* nurb */ nu->pntsu = 8; nu->pntsv = 1; - nu->orderu = 4; + nu->orderu = 3; nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * nu->pntsu, "addNurbprim6"); - nu->flagu = CU_NURB_CYCLIC; + nu->flagu = CU_NURB_CYCLIC | CU_NURB_BEZIER; bp = nu->bp; for (a = 0; a < 8; a++) { @@ -322,7 +322,7 @@ Nurb *ED_curve_add_nurbs_primitive( bp->vec[2] += 0.25f * nurbcircle[a][1] * grid; } if (a & 1) { - bp->vec[3] = 0.25 * M_SQRT2; + bp->vec[3] = 0.5 * M_SQRT2; } else { bp->vec[3] = 1.0; diff --git a/source/blender/editors/geometry/CMakeLists.txt b/source/blender/editors/geometry/CMakeLists.txt index de382b72de7..dbe1e85c61c 100644 --- a/source/blender/editors/geometry/CMakeLists.txt +++ b/source/blender/editors/geometry/CMakeLists.txt @@ -20,10 +20,12 @@ set(INC ../../blenkernel ../../blenlib ../../depsgraph + ../../functions ../../makesdna ../../makesrna ../../windowmanager ../../../../intern/atomic + ../../../../intern/guardedalloc ) set(INC_SYS diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc index 1329c162398..41bb1f2027d 100644 --- a/source/blender/editors/geometry/geometry_attributes.cc +++ b/source/blender/editors/geometry/geometry_attributes.cc @@ -21,10 +21,20 @@ * \ingroup edgeometry */ +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" + #include "BKE_attribute.h" #include "BKE_context.h" +#include "BKE_deform.h" +#include "BKE_geometry_set.hh" #include "BKE_object.h" +#include "BKE_object_deform.h" #include "BKE_paint.h" +#include "BKE_report.h" #include "RNA_access.h" #include "RNA_define.h" @@ -36,11 +46,19 @@ #include "WM_types.h" #include "DNA_mesh_types.h" +#include "UI_interface.h" +#include "UI_resources.h" #include "ED_object.h" #include "geometry_intern.hh" +namespace blender::ed::geometry { + +using fn::CPPType; +using fn::GArray; +using fn::GVArray; + /*********************** Attribute Operators ************************/ static bool geometry_attributes_poll(bContext *C) @@ -80,7 +98,7 @@ static const EnumPropertyItem *geometry_attribute_domain_itemf(bContext *C, return DummyRNA_NULL_items; } - return rna_enum_attribute_domain_itemf(static_cast(ob->data), r_free); + return rna_enum_attribute_domain_itemf(static_cast(ob->data), false, r_free); } static int geometry_attribute_add_exec(bContext *C, wmOperator *op) @@ -166,7 +184,8 @@ static void next_color_attr(struct ID *id, CustomDataLayer *layer, bool is_rende return; } - AttributeDomainMask domain_mask = (AttributeDomainMask)(ATTR_DOMAIN_MASK_POINT | ATTR_DOMAIN_MASK_CORNER); + AttributeDomainMask domain_mask = (AttributeDomainMask)(ATTR_DOMAIN_MASK_POINT | + ATTR_DOMAIN_MASK_CORNER); CustomDataMask type_mask = (CustomDataMask)(CD_MASK_PROP_COLOR | CD_MASK_MLOOPCOL); int length = BKE_id_attributes_length(id, domain_mask, type_mask); @@ -188,11 +207,10 @@ static void next_color_attrs(struct ID *id, CustomDataLayer *layer) next_color_attr(id, layer, true); /* render */ } - static int geometry_color_attribute_add_exec(bContext *C, wmOperator *op) - { +{ Object *ob = ED_object_context(C); - ID *id = static_cast(ob->data); + ID *id = static_cast(ob->data); char name[MAX_NAME]; RNA_string_get(op->ptr, "name", name); @@ -317,7 +335,7 @@ void GEOMETRY_OT_attribute_remove(wmOperatorType *ot) static int geometry_color_attribute_remove_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); - ID *id = static_cast(ob->data); + ID *id = static_cast(ob->data); CustomDataLayer *layer = BKE_id_attributes_active_color_get(id); if (layer == NULL) { @@ -341,6 +359,30 @@ static int geometry_color_attribute_remove_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +enum class ConvertAttributeMode { + Generic, + UVMap, + VertexGroup, + VertexColor, +}; + +static bool geometry_attribute_convert_poll(bContext *C) +{ + if (!geometry_attributes_poll(C)) { + return false; + } + + Object *ob = ED_object_context(C); + ID *data = static_cast(ob->data); + if (GS(data->name) != ID_ME) { + return false; + } + CustomDataLayer *layer = BKE_id_attributes_active_get(data); + if (layer == nullptr) { + return false; + } + return true; +} static bool geometry_color_attributes_remove_poll(bContext *C) { if (!geometry_attributes_poll(C)) { @@ -348,7 +390,7 @@ static bool geometry_color_attributes_remove_poll(bContext *C) } Object *ob = ED_object_context(C); - ID *data = (ob) ? static_cast(ob->data) : NULL; + ID *data = (ob) ? static_cast(ob->data) : NULL; if (BKE_id_attributes_active_color_get(data) != NULL) { return true; } @@ -370,3 +412,160 @@ void GEOMETRY_OT_color_attribute_remove(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +static int geometry_attribute_convert_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_context(C); + ID *ob_data = static_cast(ob->data); + CustomDataLayer *layer = BKE_id_attributes_active_get(ob_data); + const std::string name = layer->name; + + const ConvertAttributeMode mode = static_cast( + RNA_enum_get(op->ptr, "mode")); + + Mesh *mesh = reinterpret_cast(ob_data); + MeshComponent mesh_component; + mesh_component.replace(mesh, GeometryOwnershipType::Editable); + + /* General conversion steps are always the same: + * 1. Convert old data to right domain and data type. + * 2. Copy the data into a new array so that it does not depend on the old attribute anymore. + * 3. Delete the old attribute. + * 4. Create a new attribute based on the previously copied data. */ + switch (mode) { + case ConvertAttributeMode::Generic: { + const AttributeDomain dst_domain = static_cast( + RNA_enum_get(op->ptr, "domain")); + const CustomDataType dst_type = static_cast( + RNA_enum_get(op->ptr, "data_type")); + + if (ELEM(dst_type, CD_PROP_STRING, CD_MLOOPCOL)) { + BKE_report(op->reports, RPT_ERROR, "Cannot convert to the selected type"); + return OPERATOR_CANCELLED; + } + + GVArray src_varray = mesh_component.attribute_get_for_read(name, dst_domain, dst_type); + const CPPType &cpp_type = src_varray.type(); + void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__); + src_varray.materialize_to_uninitialized(new_data); + mesh_component.attribute_try_delete(name); + mesh_component.attribute_try_create(name, dst_domain, dst_type, AttributeInitMove(new_data)); + break; + } + case ConvertAttributeMode::UVMap: { + MLoopUV *dst_uvs = static_cast( + MEM_calloc_arrayN(mesh->totloop, sizeof(MLoopUV), __func__)); + VArray src_varray = mesh_component.attribute_get_for_read( + name, ATTR_DOMAIN_CORNER, {0.0f, 0.0f}); + for (const int i : IndexRange(mesh->totloop)) { + copy_v2_v2(dst_uvs[i].uv, src_varray[i]); + } + mesh_component.attribute_try_delete(name); + CustomData_add_layer_named( + &mesh->ldata, CD_MLOOPUV, CD_ASSIGN, dst_uvs, mesh->totloop, name.c_str()); + break; + } + case ConvertAttributeMode::VertexColor: { + MLoopCol *dst_colors = static_cast( + MEM_calloc_arrayN(mesh->totloop, sizeof(MLoopCol), __func__)); + VArray src_varray = mesh_component.attribute_get_for_read( + 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 src_weights(mesh->totvert); + VArray src_varray = mesh_component.attribute_get_for_read( + name, ATTR_DOMAIN_POINT, 0.0f); + src_varray.materialize(src_weights); + mesh_component.attribute_try_delete(name); + + bDeformGroup *defgroup = BKE_object_defgroup_new(ob, name.c_str()); + const int defgroup_index = BLI_findindex(BKE_id_defgroup_list_get(&mesh->id), defgroup); + MDeformVert *dverts = BKE_object_defgroup_data_create(&mesh->id); + for (const int i : IndexRange(mesh->totvert)) { + const float weight = src_weights[i]; + if (weight > 0.0f) { + BKE_defvert_add_index_notest(dverts + i, defgroup_index, weight); + } + } + break; + } + } + + int *active_index = BKE_id_attributes_active_index_p(&mesh->id); + if (*active_index > 0) { + *active_index -= 1; + } + + DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_GEOM | ND_DATA, &mesh->id); +} + +static void geometry_attribute_convert_ui(bContext *UNUSED(C), wmOperator *op) +{ + uiLayout *layout = op->layout; + + uiItemR(layout, op->ptr, "mode", 0, nullptr, ICON_NONE); + + const ConvertAttributeMode mode = static_cast( + RNA_enum_get(op->ptr, "mode")); + + if (mode == ConvertAttributeMode::Generic) { + uiItemR(layout, op->ptr, "domain", 0, nullptr, ICON_NONE); + uiItemR(layout, op->ptr, "data_type", 0, nullptr, ICON_NONE); + } +} + +static int geometry_attribute_convert_invoke(bContext *C, + wmOperator *op, + const wmEvent *UNUSED(event)) +{ + return WM_operator_props_dialog_popup(C, op, 300); +} + +void GEOMETRY_OT_attribute_convert(wmOperatorType *ot) +{ + ot->name = "Convert Attribute"; + ot->description = "Change how the attribute is stored"; + ot->idname = "GEOMETRY_OT_attribute_convert"; + + ot->invoke = geometry_attribute_convert_invoke; + ot->exec = geometry_attribute_convert_exec; + ot->poll = geometry_attribute_convert_poll; + ot->ui = geometry_attribute_convert_ui; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + static EnumPropertyItem mode_items[] = { + {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, "Vertex Color", ""}, + {0, nullptr, 0, nullptr, nullptr}, + }; + + PropertyRNA *prop; + + RNA_def_enum( + ot->srna, "mode", mode_items, static_cast(ConvertAttributeMode::Generic), "Mode", ""); + + prop = RNA_def_enum(ot->srna, + "domain", + rna_enum_attribute_domain_items, + ATTR_DOMAIN_POINT, + "Domain", + "Which geometry element to move the attribute to"); + RNA_def_enum_funcs(prop, geometry_attribute_domain_itemf); + + RNA_def_enum( + ot->srna, "data_type", rna_enum_attribute_type_items, CD_PROP_FLOAT, "Data Type", ""); +} + +} // namespace blender::ed::geometry diff --git a/source/blender/editors/geometry/geometry_intern.hh b/source/blender/editors/geometry/geometry_intern.hh index b10aebcec02..3934a9aba38 100644 --- a/source/blender/editors/geometry/geometry_intern.hh +++ b/source/blender/editors/geometry/geometry_intern.hh @@ -25,9 +25,13 @@ struct wmOperatorType; +namespace blender::ed::geometry { + /* *** geometry_attributes.cc *** */ void GEOMETRY_OT_attribute_add(struct wmOperatorType *ot); void GEOMETRY_OT_color_attribute_add(struct wmOperatorType *ot); void GEOMETRY_OT_attribute_remove(struct wmOperatorType *ot); void GEOMETRY_OT_color_attribute_remove(struct wmOperatorType *ot); +void GEOMETRY_OT_attribute_convert(struct wmOperatorType *ot); +} // namespace blender::ed::geometry diff --git a/source/blender/editors/geometry/geometry_ops.cc b/source/blender/editors/geometry/geometry_ops.cc index e0236658725..11d4a0f22a3 100644 --- a/source/blender/editors/geometry/geometry_ops.cc +++ b/source/blender/editors/geometry/geometry_ops.cc @@ -31,8 +31,11 @@ void ED_operatortypes_geometry(void) { + using namespace blender::ed::geometry; + WM_operatortype_append(GEOMETRY_OT_attribute_add); WM_operatortype_append(GEOMETRY_OT_color_attribute_add); WM_operatortype_append(GEOMETRY_OT_attribute_remove); WM_operatortype_append(GEOMETRY_OT_color_attribute_remove); + WM_operatortype_append(GEOMETRY_OT_attribute_convert); } diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 6f63529298c..23b579b94f1 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -61,9 +61,12 @@ #include "WM_api.h" +#include "GPU_batch.h" #include "GPU_immediate.h" #include "GPU_matrix.h" +#include "GPU_shader_shared.h" #include "GPU_state.h" +#include "GPU_uniform_buffer.h" #include "ED_gpencil.h" #include "ED_screen.h" @@ -189,21 +192,27 @@ static void gpencil_draw_stroke_3d(tGPDdraw *tgpw, }; immBindBuiltinProgram(GPU_SHADER_GPENCIL_STROKE); - immUniform2fv("Viewport", viewport); - immUniform1f("pixsize", tgpw->rv3d->pixsize); + float obj_scale = tgpw->ob ? (tgpw->ob->scale[0] + tgpw->ob->scale[1] + tgpw->ob->scale[2]) / 3.0f : 1.0f; - immUniform1f("objscale", obj_scale); + struct GPencilStrokeData gpencil_stroke_data; + copy_v2_v2(gpencil_stroke_data.viewport, viewport); + gpencil_stroke_data.pixsize = tgpw->rv3d->pixsize; + gpencil_stroke_data.objscale = obj_scale; int keep_size = (int)((tgpw->gpd) && (tgpw->gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS)); - immUniform1i("keep_size", keep_size); - immUniform1f("pixfactor", tgpw->gpd->pixfactor); + gpencil_stroke_data.keep_size = keep_size; + gpencil_stroke_data.pixfactor = tgpw->gpd->pixfactor; /* xray mode always to 3D space to avoid wrong zdepth calculation (T60051) */ - immUniform1i("xraymode", GP_XRAY_3DSPACE); - immUniform1i("caps_start", (int)tgpw->gps->caps[0]); - immUniform1i("caps_end", (int)tgpw->gps->caps[1]); - immUniform1i("fill_stroke", (int)tgpw->is_fill_stroke); + gpencil_stroke_data.xraymode = GP_XRAY_3DSPACE; + gpencil_stroke_data.caps_start = tgpw->gps->caps[0]; + gpencil_stroke_data.caps_end = tgpw->gps->caps[1]; + gpencil_stroke_data.fill_stroke = tgpw->is_fill_stroke; + + GPUUniformBuf *ubo = GPU_uniformbuf_create_ex( + sizeof(struct GPencilStrokeData), &gpencil_stroke_data, __func__); + immBindUniformBuf("gpencil_stroke_data", ubo); /* draw stroke curve */ immBeginAtMost(GPU_PRIM_LINE_STRIP_ADJ, totpoints + cyclic_add + 2); @@ -255,6 +264,8 @@ static void gpencil_draw_stroke_3d(tGPDdraw *tgpw, immEnd(); immUnbindProgram(); + + GPU_uniformbuf_free(ubo); } /* ----- Strokes Drawing ------ */ diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c index e1907dd1514..3cc47198cbc 100644 --- a/source/blender/editors/gpencil/editaction_gpencil.c +++ b/source/blender/editors/gpencil/editaction_gpencil.c @@ -454,9 +454,10 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode) /* get frame to copy data into (if no frame returned, then just ignore) */ gpf = BKE_gpencil_layer_frame_get(gpld, gpfs->framenum, GP_GETFRAME_ADD_NEW); - /* Ensure to use same keyframe type. */ - gpf->key_type = gpfs->key_type; if (gpf) { + /* Ensure to use same keyframe type. */ + gpf->key_type = gpfs->key_type; + bGPDstroke *gps, *gpsn; /* This should be the right frame... as it may be a pre-existing frame, diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h index 8f2a189e35e..61dd0adc84d 100644 --- a/source/blender/editors/include/BIF_glutil.h +++ b/source/blender/editors/include/BIF_glutil.h @@ -54,6 +54,36 @@ typedef struct IMMDrawPixelsTexState { */ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin); +/** + * Unlike the `immDrawPixelsTexTiled` functions, this doesn't do tiled drawing, but draws into a + * full texture. + * + * Use the currently bound shader. + * + * Use #immDrawPixelsTexSetup to bind the shader you want before calling #immDrawPixelsTex. + * + * If using a special shader double check it uses the same attributes "pos" "texCoord" and uniform + * "image". + * + * If color is NULL then use white by default + * + * Unless state->do_shader_unbind is explicitly set to `false`, the shader is unbound when + * finished. + */ +void immDrawPixelsTexScaledFullSize(const IMMDrawPixelsTexState *state, + const float x, + const float y, + const int img_w, + const int img_h, + const eGPUTextureFormat gpu_format, + const bool use_filter, + const void *rect, + const float scaleX, + const float scaleY, + const float xzoom, + const float yzoom, + const float color[4]); + /** * #immDrawPixelsTex - Functions like a limited #glDrawPixels, but actually draws the * image using textures, which can be tremendously faster on low-end @@ -68,45 +98,45 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin); * model-view and projection matrices are assumed to define a * 1-to-1 mapping to screen space. */ -void immDrawPixelsTex(IMMDrawPixelsTexState *state, - float x, - float y, - int img_w, - int img_h, - eGPUTextureFormat gpu_format, - bool use_filter, - void *rect, - float xzoom, - float yzoom, - const float color[4]); -void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state, - float x, - float y, - int img_w, - int img_h, - eGPUTextureFormat gpu_format, - bool use_filter, - void *rect, - float clip_min_x, - float clip_min_y, - float clip_max_x, - float clip_max_y, - float xzoom, - float yzoom, - const float color[4]); -void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state, - float x, - float y, - int img_w, - int img_h, - eGPUTextureFormat gpu_format, - bool use_filter, - void *rect, - float scaleX, - float scaleY, - float xzoom, - float yzoom, - const float color[4]); +void immDrawPixelsTexTiled(IMMDrawPixelsTexState *state, + float x, + float y, + int img_w, + int img_h, + eGPUTextureFormat gpu_format, + bool use_filter, + void *rect, + float xzoom, + float yzoom, + const float color[4]); +void immDrawPixelsTexTiled_clipping(IMMDrawPixelsTexState *state, + float x, + float y, + int img_w, + int img_h, + eGPUTextureFormat gpu_format, + bool use_filter, + void *rect, + float clip_min_x, + float clip_min_y, + float clip_max_x, + float clip_max_y, + float xzoom, + float yzoom, + const float color[4]); +void immDrawPixelsTexTiled_scaling(IMMDrawPixelsTexState *state, + float x, + float y, + int img_w, + int img_h, + eGPUTextureFormat gpu_format, + bool use_filter, + void *rect, + float scaleX, + float scaleY, + float xzoom, + float yzoom, + const float color[4]); /** * Use the currently bound shader. * @@ -118,26 +148,26 @@ void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state, * * If color is NULL then use white by default * - * Be also aware that this function unbinds the shader when - * it's finished. + * Unless state->do_shader_unbind is explicitly set to `false`, the shader is unbound when + * finished. */ -void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state, - float x, - float y, - int img_w, - int img_h, - eGPUTextureFormat gpu_format, - bool use_filter, - void *rect, - float scaleX, - float scaleY, - float clip_min_x, - float clip_min_y, - float clip_max_x, - float clip_max_y, - float xzoom, - float yzoom, - const float color[4]); +void immDrawPixelsTexTiled_scaling_clipping(IMMDrawPixelsTexState *state, + float x, + float y, + int img_w, + int img_h, + eGPUTextureFormat gpu_format, + bool use_filter, + void *rect, + float scaleX, + float scaleY, + float clip_min_x, + float clip_min_y, + float clip_max_x, + float clip_max_y, + float xzoom, + float yzoom, + const float color[4]); /* Image buffer drawing functions, with display transform * diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h index db1ba80dd3c..181b6848ac7 100644 --- a/source/blender/editors/include/ED_node.h +++ b/source/blender/editors/include/ED_node.h @@ -101,11 +101,6 @@ void ED_node_socket_draw(struct bNodeSocket *sock, void ED_node_tree_update(const struct bContext *C); void ED_node_tag_update_id(struct ID *id); -/** - * Sort nodes by selection: unselected nodes first, then selected, - * then the active node at the very end. Relative order is kept intact. - */ -void ED_node_sort(struct bNodeTree *ntree); float ED_node_grid_size(void); /* node_relationships.c */ @@ -142,8 +137,6 @@ void ED_node_composit_default(const struct bContext *C, struct Scene *scene); * Called from shading buttons or header. */ void ED_node_texture_default(const struct bContext *C, struct Tex *tex); -bool ED_node_select_check(const ListBase *lb); -void ED_node_select_all(ListBase *lb, int action); void ED_node_post_apply_transform(struct bContext *C, struct bNodeTree *ntree); void ED_node_set_active(struct Main *bmain, struct SpaceNode *snode, diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index b76f882e706..573f9b4939b 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -54,7 +54,8 @@ typedef enum { TFM_TILT, TFM_TRACKBALL, TFM_PUSHPULL, - TFM_CREASE, + TFM_EDGE_CREASE, + TFM_VERT_CREASE, TFM_MIRROR, TFM_BONESIZE, TFM_BONE_ENVELOPE, diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 9ce07cd2e07..3796fa51499 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -2426,6 +2426,13 @@ void uiTemplateCacheFileProcedural(uiLayout *layout, */ void uiTemplateCacheFileTimeSettings(uiLayout *layout, struct PointerRNA *fileptr); +/** + * Draw the override layers related properties of the CacheFile. + */ +void uiTemplateCacheFileLayers(uiLayout *layout, + const struct bContext *C, + struct PointerRNA *fileptr); + /* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */ #define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list" enum uiTemplateListFlags { diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 587db16a80b..d94deb28b63 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -680,8 +680,43 @@ static float ui_but_get_float_precision(uiBut *but) return but->a2; } +static float ui_but_get_float_step_size(uiBut *but) +{ + if (but->type == UI_BTYPE_NUM) { + return ((uiButNumber *)but)->step_size; + } + + return but->a1; +} + +static bool ui_but_hide_fraction(uiBut *but, double value) +{ + /* Hide the fraction if both the value and the step are exact integers. */ + if (floor(value) == value) { + const float step = ui_but_get_float_step_size(but) * UI_PRECISION_FLOAT_SCALE; + + if (floorf(step) == step) { + /* Don't hide if it has any unit except frame count. */ + switch (UI_but_unit_type_get(but)) { + case PROP_UNIT_NONE: + case PROP_UNIT_TIME: + return true; + + default: + return false; + } + } + } + + return false; +} + static int ui_but_calc_float_precision(uiBut *but, double value) { + if (ui_but_hide_fraction(but, value)) { + return 0; + } + int prec = (int)ui_but_get_float_precision(but); /* first check for various special cases: @@ -2832,8 +2867,14 @@ void ui_but_string_get_ex(uiBut *but, } if (ui_but_is_float(but)) { - int prec = (float_precision == -1) ? ui_but_calc_float_precision(but, value) : - float_precision; + int prec = float_precision; + + if (float_precision == -1) { + prec = ui_but_calc_float_precision(but, value); + } + else if (!use_exp_float && ui_but_hide_fraction(but, value)) { + prec = 0; + } if (ui_but_is_unit(but)) { ui_get_but_string_unit(but, str, maxlen, value, false, prec); diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index 285c82b0fb3..f7492e56b62 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -57,6 +57,7 @@ #include "GPU_immediate.h" #include "GPU_immediate_util.h" #include "GPU_matrix.h" +#include "GPU_shader_shared.h" #include "GPU_state.h" #include "UI_interface.h" @@ -324,17 +325,17 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(region), } IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); - immDrawPixelsTex(&state, - (float)rect->xmin, - (float)rect->ymin, - ibuf->x, - ibuf->y, - GPU_RGBA8, - false, - ibuf->rect, - 1.0f, - 1.0f, - col); + immDrawPixelsTexTiled(&state, + (float)rect->xmin, + (float)rect->ymin, + ibuf->x, + ibuf->y, + GPU_RGBA8, + false, + ibuf->rect, + 1.0f, + 1.0f, + col); GPU_blend(GPU_BLEND_NONE); @@ -1384,10 +1385,16 @@ void ui_draw_but_UNITVEC(uiBut *but, GPU_matrix_scale_1f(size); GPUBatch *sphere = GPU_batch_preset_sphere(2); + struct SimpleLightingData simple_lighting_data; + copy_v4_fl4(simple_lighting_data.color, diffuse[0], diffuse[1], diffuse[2], 1.0f); + copy_v3_v3(simple_lighting_data.light, light); + GPUUniformBuf *ubo = GPU_uniformbuf_create_ex( + sizeof(struct SimpleLightingData), &simple_lighting_data, __func__); + GPU_batch_program_set_builtin(sphere, GPU_SHADER_SIMPLE_LIGHTING); - GPU_batch_uniform_4f(sphere, "color", diffuse[0], diffuse[1], diffuse[2], 1.0f); - GPU_batch_uniform_3fv(sphere, "light", light); + GPU_batch_uniformbuf_bind(sphere, "simple_lighting_data", ubo); GPU_batch_draw(sphere); + GPU_uniformbuf_free(ubo); /* Restore. */ GPU_face_culling(GPU_CULL_NONE); @@ -2128,17 +2135,17 @@ void ui_draw_but_TRACKPREVIEW(ARegion *UNUSED(region), } IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); - immDrawPixelsTex(&state, - rect.xmin, - rect.ymin + 1, - drawibuf->x, - drawibuf->y, - GPU_RGBA8, - true, - drawibuf->rect, - 1.0f, - 1.0f, - NULL); + immDrawPixelsTexTiled(&state, + rect.xmin, + rect.ymin + 1, + drawibuf->x, + drawibuf->y, + GPU_RGBA8, + true, + drawibuf->rect, + 1.0f, + 1.0f, + NULL); /* draw cross for pixel position */ GPU_matrix_translate_2f(rect.xmin + scopes->track_pos[0], rect.ymin + scopes->track_pos[1]); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 94da0de97f7..28896bfc040 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -5484,7 +5484,7 @@ static int ui_do_but_NUM( log10f(number_but->step_size)); } else { - value_step = (double)number_but->step_size * UI_PRECISION_FLOAT_SCALE; + value_step = (double)(number_but->step_size * UI_PRECISION_FLOAT_SCALE); } BLI_assert(value_step > 0.0f); const double value_test = (but->drawflag & UI_BUT_ACTIVE_LEFT) ? diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index ca5d08ba40e..0f5b4a1a0f1 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -31,6 +31,7 @@ #include "GPU_batch_presets.h" #include "GPU_immediate.h" #include "GPU_matrix.h" +#include "GPU_shader_shared.h" #include "GPU_state.h" #include "GPU_texture.h" @@ -1478,24 +1479,16 @@ PreviewImage *UI_icon_to_preview(int icon_id) return NULL; } -/** - * Version of #icon_draw_rect() that uses the GPU for scaling. This is only used for - * #ICON_TYPE_IMBUF because it's a back-ported fix for performance issues, see T92922. Only - * File/Asset Browser use #ICON_TYPE_IMBUF right now, which makes implications more predictable. - * - * TODO(Julian): This code is mostly duplicated. #icon_draw_rect() should be ported to use the GPU - * instead (D13144). - */ -static void icon_draw_rect_fast(float x, - float y, - int w, - int h, - float UNUSED(aspect), - int rw, - int rh, - uint *rect, - float alpha, - const float desaturate) +static void icon_draw_rect(float x, + float y, + int w, + int h, + float UNUSED(aspect), + int rw, + int rh, + uint *rect, + float alpha, + const float desaturate) { int draw_w = w; int draw_h = h; @@ -1546,81 +1539,10 @@ static void icon_draw_rect_fast(float x, immUniform1f("factor", desaturate); } - immDrawPixelsTexScaled( + immDrawPixelsTexScaledFullSize( &state, draw_x, draw_y, rw, rh, GPU_RGBA8, true, rect, scale_x, scale_y, 1.0f, 1.0f, col); } -static void icon_draw_rect(float x, - float y, - int w, - int h, - float UNUSED(aspect), - int rw, - int rh, - uint *rect, - float alpha, - const float desaturate) -{ - ImBuf *ima = NULL; - int draw_w = w; - int draw_h = h; - int draw_x = x; - /* We need to round y, to avoid the icon jittering in some cases. */ - int draw_y = round_fl_to_int(y); - - /* sanity check */ - if (w <= 0 || h <= 0 || w > 2000 || h > 2000) { - printf("%s: icons are %i x %i pixels?\n", __func__, w, h); - BLI_assert_msg(0, "invalid icon size"); - return; - } - /* modulate color */ - const float col[4] = {alpha, alpha, alpha, alpha}; - - /* rect contains image in 'rendersize', we only scale if needed */ - if (rw != w || rh != h) { - /* preserve aspect ratio and center */ - if (rw > rh) { - draw_w = w; - draw_h = (int)(((float)rh / (float)rw) * (float)w); - draw_y += (h - draw_h) / 2; - } - else if (rw < rh) { - draw_w = (int)(((float)rw / (float)rh) * (float)h); - draw_h = h; - draw_x += (w - draw_w) / 2; - } - /* If the image is squared, the `draw_*` initialization values are good. */ - - /* first allocate imbuf for scaling and copy preview into it */ - ima = IMB_allocImBuf(rw, rh, 32, IB_rect); - memcpy(ima->rect, rect, rw * rh * sizeof(uint)); - IMB_scaleImBuf(ima, draw_w, draw_h); /* scale it */ - rect = ima->rect; - } - - /* draw */ - eGPUBuiltinShader shader; - if (desaturate != 0.0f) { - shader = GPU_SHADER_2D_IMAGE_DESATURATE_COLOR; - } - else { - shader = GPU_SHADER_2D_IMAGE_COLOR; - } - IMMDrawPixelsTexState state = immDrawPixelsTexSetup(shader); - - if (shader == GPU_SHADER_2D_IMAGE_DESATURATE_COLOR) { - immUniform1f("factor", desaturate); - } - - immDrawPixelsTex( - &state, draw_x, draw_y, draw_w, draw_h, GPU_RGBA8, false, rect, 1.0f, 1.0f, col); - - if (ima) { - IMB_freeImBuf(ima); - } -} - /* High enough to make a difference, low enough so that * small draws are still efficient with the use of glUniform. * NOTE TODO: We could use UBO but we would need some triple @@ -1661,18 +1583,21 @@ static void icon_draw_cache_texture_flush_ex(GPUTexture *texture, GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR); GPU_shader_bind(shader); - const int img_binding = GPU_shader_get_texture_binding(shader, "image"); - const int data_loc = GPU_shader_get_uniform(shader, "calls_data"); + const int data_loc = GPU_shader_get_uniform_block(shader, "multi_rect_data"); + GPUUniformBuf *ubo = GPU_uniformbuf_create_ex( + sizeof(struct MultiRectCallData), texture_draw_calls->drawcall_cache, __func__); + GPU_uniformbuf_bind(ubo, data_loc); + const int img_binding = GPU_shader_get_texture_binding(shader, "image"); GPU_texture_bind_ex(texture, GPU_SAMPLER_ICON, img_binding, false); - GPU_shader_uniform_vector( - shader, data_loc, 4, ICON_DRAW_CACHE_SIZE * 3, (float *)texture_draw_calls->drawcall_cache); GPUBatch *quad = GPU_batch_preset_quad(); GPU_batch_set_shader(quad, shader); GPU_batch_draw_instanced(quad, texture_draw_calls->calls); GPU_texture_unbind(texture); + GPU_uniformbuf_unbind(ubo); + GPU_uniformbuf_free(ubo); texture_draw_calls->calls = 0; } @@ -1874,9 +1799,7 @@ static void icon_draw_size(float x, ImBuf *ibuf = icon->obj; GPU_blend(GPU_BLEND_ALPHA_PREMULT); - /* These icons are only used by the File/Asset Browser currently. Without this `_fast()` - * version, there may be performance issues, see T92922. */ - icon_draw_rect_fast(x, y, w, h, aspect, ibuf->x, ibuf->y, ibuf->rect, alpha, desaturate); + icon_draw_rect(x, y, w, h, aspect, ibuf->x, ibuf->y, ibuf->rect, alpha, desaturate); GPU_blend(GPU_BLEND_ALPHA); } else if (di->type == ICON_TYPE_VECTOR) { diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 96f9ce38dbc..dd28e3eca81 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -1538,6 +1538,9 @@ uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_bl uiButTreeRow *ui_block_view_find_treerow_in_old_block(const uiBlock *new_block, const uiTreeViewItemHandle *new_item_handle); +/* interface_templates.c */ +struct uiListType *UI_UL_cache_file_layers(void); + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc index 13e539b5095..817599605a9 100644 --- a/source/blender/editors/interface/interface_template_list.cc +++ b/source/blender/editors/interface/interface_template_list.cc @@ -1322,6 +1322,7 @@ PointerRNA *UI_list_custom_drag_operator_set(uiList *ui_list, void ED_uilisttypes_ui() { WM_uilisttype_add(UI_UL_asset_view()); + WM_uilisttype_add(UI_UL_cache_file_layers()); } /** \} */ diff --git a/source/blender/editors/interface/interface_template_search_menu.cc b/source/blender/editors/interface/interface_template_search_menu.cc index 7a079e01e61..0ce3a0d8af1 100644 --- a/source/blender/editors/interface/interface_template_search_menu.cc +++ b/source/blender/editors/interface/interface_template_search_menu.cc @@ -465,6 +465,9 @@ static MenuSearch_Data *menu_items_from_ui_create( const char *idname_array[] = { /* While we could include this, it's just showing filenames to load. */ "TOPBAR_MT_file_open_recent", + /* Showing undo history is not helpful since users may accidentally undo + * an action they intend to run. */ + "TOPBAR_MT_undo_history", }; for (int i = 0; i < ARRAY_SIZE(idname_array); i++) { MenuType *mt = WM_menutype_find(idname_array[i], false); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 00e9a75848a..8330f8c0db7 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -6474,6 +6474,67 @@ void uiTemplateCacheFileTimeSettings(uiLayout *layout, PointerRNA *fileptr) uiLayoutSetActive(row, !RNA_boolean_get(fileptr, "is_sequence")); } +static void cache_file_layer_item(uiList *UNUSED(ui_list), + bContext *UNUSED(C), + uiLayout *layout, + PointerRNA *UNUSED(dataptr), + PointerRNA *itemptr, + int UNUSED(icon), + PointerRNA *UNUSED(active_dataptr), + const char *UNUSED(active_propname), + int UNUSED(index), + int UNUSED(flt_flag)) +{ + uiLayout *row = uiLayoutRow(layout, true); + uiItemR(row, itemptr, "hide_layer", UI_ITEM_R_NO_BG, "", ICON_NONE); + uiItemR(row, itemptr, "filepath", UI_ITEM_R_NO_BG, "", ICON_NONE); +} + +uiListType *UI_UL_cache_file_layers() +{ + uiListType *list_type = (uiListType *)MEM_callocN(sizeof(*list_type), __func__); + + BLI_strncpy(list_type->idname, "UI_UL_cache_file_layers", sizeof(list_type->idname)); + list_type->draw_item = cache_file_layer_item; + + return list_type; +} + +void uiTemplateCacheFileLayers(uiLayout *layout, const bContext *C, PointerRNA *fileptr) +{ + /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */ + uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr); + + uiLayout *row = uiLayoutRow(layout, false); + uiLayout *col = uiLayoutColumn(row, true); + + uiTemplateList(col, + (bContext *)C, + "UI_UL_cache_file_layers", + "cache_file_layers", + fileptr, + "layers", + fileptr, + "active_index", + "", + 1, + 5, + UILST_LAYOUT_DEFAULT, + 1, + UI_TEMPLATE_LIST_FLAG_NONE); + + col = uiLayoutColumn(row, true); + uiItemO(col, "", ICON_ADD, "cachefile.layer_add"); + uiItemO(col, "", ICON_REMOVE, "cachefile.layer_remove"); + + CacheFile *file = fileptr->data; + if (BLI_listbase_count(&file->layers) > 1) { + uiItemS_ex(col, 1.0f); + uiItemO(col, "", ICON_TRIA_UP, "cachefile.layer_move"); + uiItemO(col, "", ICON_TRIA_DOWN, "cachefile.layer_move"); + } +} + bool uiTemplateCacheFilePointer(PointerRNA *ptr, const char *propname, PointerRNA *r_file_ptr) { PropertyRNA *prop = RNA_struct_find_property(ptr, propname); diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c index bf20c1f6438..4f71a804986 100644 --- a/source/blender/editors/io/io_cache.c +++ b/source/blender/editors/io/io_cache.c @@ -26,6 +26,7 @@ #include "DNA_cachefile_types.h" #include "DNA_space_types.h" +#include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_string.h" @@ -36,6 +37,7 @@ #include "BKE_report.h" #include "RNA_access.h" +#include "RNA_define.h" #include "DEG_depsgraph.h" @@ -46,6 +48,12 @@ #include "io_cache.h" +static void reload_cachefile(bContext *C, CacheFile *cache_file) +{ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + BKE_cachefile_reload(depsgraph, cache_file); +} + static void cachefile_init(bContext *C, wmOperator *op) { PropertyPointerRNA *pprop; @@ -146,8 +154,7 @@ static int cachefile_reload_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; } - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - BKE_cachefile_reload(depsgraph, cache_file); + reload_cachefile(C, cache_file); return OPERATOR_FINISHED; } @@ -164,3 +171,160 @@ void CACHEFILE_OT_reload(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/* ***************************** Add Layer Operator **************************** */ + +static int cachefile_layer_open_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + char filepath[FILE_MAX]; + Main *bmain = CTX_data_main(C); + + BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath)); + BLI_path_extension_replace(filepath, sizeof(filepath), ".abc"); + RNA_string_set(op->ptr, "filepath", filepath); + } + + /* There is no more CacheFile set when returning from the file selector, so store it here. */ + op->customdata = CTX_data_edit_cachefile(C); + + WM_event_add_fileselect(C, op); + + return OPERATOR_RUNNING_MODAL; + + UNUSED_VARS(event); +} + +static int cachefile_layer_add_exec(bContext *C, wmOperator *op) +{ + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + BKE_report(op->reports, RPT_ERROR, "No filename given"); + return OPERATOR_CANCELLED; + } + + CacheFile *cache_file = op->customdata; + + if (!cache_file) { + return OPERATOR_CANCELLED; + } + + char filename[FILE_MAX]; + RNA_string_get(op->ptr, "filepath", filename); + + CacheFileLayer *layer = BKE_cachefile_add_layer(cache_file, filename); + + if (!layer) { + WM_report(RPT_ERROR, "Could not add a layer to the cache file"); + return OPERATOR_CANCELLED; + } + + reload_cachefile(C, cache_file); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + return OPERATOR_FINISHED; +} + +void CACHEFILE_OT_layer_add(wmOperatorType *ot) +{ + ot->name = "Add layer"; + ot->description = "Add an override layer to the archive"; + ot->idname = "CACHEFILE_OT_layer_add"; + + /* api callbacks */ + ot->invoke = cachefile_layer_open_invoke; + ot->exec = cachefile_layer_add_exec; + + WM_operator_properties_filesel(ot, + FILE_TYPE_ALEMBIC | FILE_TYPE_FOLDER, + FILE_BLENDER, + FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, + FILE_DEFAULTDISPLAY, + FILE_SORT_DEFAULT); +} + +/* ***************************** Remove Layer Operator **************************** */ + +static int cachefile_layer_remove_exec(bContext *C, wmOperator *UNUSED(op)) +{ + CacheFile *cache_file = CTX_data_edit_cachefile(C); + + if (!cache_file) { + return OPERATOR_CANCELLED; + } + + CacheFileLayer *layer = BKE_cachefile_get_active_layer(cache_file); + BKE_cachefile_remove_layer(cache_file, layer); + + reload_cachefile(C, cache_file); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + return OPERATOR_FINISHED; +} + +void CACHEFILE_OT_layer_remove(wmOperatorType *ot) +{ + ot->name = "Add layer"; + ot->description = "Remove an override layer to the archive"; + ot->idname = "CACHEFILE_OT_layer_remove"; + + /* api callbacks */ + ot->exec = cachefile_layer_remove_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/* ***************************** Move Layer Operator **************************** */ + +static int cachefile_layer_move_exec(bContext *C, wmOperator *op) +{ + CacheFile *cache_file = CTX_data_edit_cachefile(C); + + if (!cache_file) { + return OPERATOR_CANCELLED; + } + + CacheFileLayer *layer = BKE_cachefile_get_active_layer(cache_file); + + if (!layer) { + return OPERATOR_CANCELLED; + } + + const int dir = RNA_enum_get(op->ptr, "direction"); + + if (BLI_listbase_link_move(&cache_file->layers, layer, dir)) { + cache_file->active_layer = BLI_findindex(&cache_file->layers, layer) + 1; + /* Only reload if something moved, might be expensive. */ + reload_cachefile(C, cache_file); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + } + + return OPERATOR_FINISHED; +} + +void CACHEFILE_OT_layer_move(wmOperatorType *ot) +{ + static const EnumPropertyItem layer_slot_move[] = { + {-1, "UP", 0, "Up", ""}, + {1, "DOWN", 0, "Down", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + ot->name = "Move layer"; + ot->description = + "Move layer in the list, layers further down the list will overwrite data from the layers " + "higher up"; + ot->idname = "CACHEFILE_OT_layer_move"; + + /* api callbacks */ + ot->exec = cachefile_layer_move_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_enum(ot->srna, + "direction", + layer_slot_move, + 0, + "Direction", + "Direction to move the active vertex group towards"); +} diff --git a/source/blender/editors/io/io_cache.h b/source/blender/editors/io/io_cache.h index be6e31842af..297e065434f 100644 --- a/source/blender/editors/io/io_cache.h +++ b/source/blender/editors/io/io_cache.h @@ -27,3 +27,7 @@ struct wmOperatorType; void CACHEFILE_OT_open(struct wmOperatorType *ot); void CACHEFILE_OT_reload(struct wmOperatorType *ot); + +void CACHEFILE_OT_layer_add(struct wmOperatorType *ot); +void CACHEFILE_OT_layer_remove(struct wmOperatorType *ot); +void CACHEFILE_OT_layer_move(struct wmOperatorType *ot); diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c index 5dff0b69c2a..d9bbd7d8692 100644 --- a/source/blender/editors/io/io_ops.c +++ b/source/blender/editors/io/io_ops.c @@ -69,5 +69,10 @@ void ED_operatortypes_io(void) WM_operatortype_append(CACHEFILE_OT_open); WM_operatortype_append(CACHEFILE_OT_reload); + + WM_operatortype_append(CACHEFILE_OT_layer_add); + WM_operatortype_append(CACHEFILE_OT_layer_remove); + WM_operatortype_append(CACHEFILE_OT_layer_move); + WM_operatortype_append(WM_OT_obj_export); } diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c index dcd5b90bc04..0e207df7f94 100644 --- a/source/blender/editors/mask/mask_draw.c +++ b/source/blender/editors/mask/mask_draw.c @@ -768,7 +768,8 @@ void ED_mask_draw_region( IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR); GPU_shader_uniform_vector( state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red); - immDrawPixelsTex(&state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, NULL); + immDrawPixelsTexTiled( + &state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, NULL); GPU_matrix_pop(); diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index f10f1607d14..906e3c50d72 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -690,12 +690,12 @@ static void undomesh_to_editmesh(UndoMesh *um, Object *ob, BMEditMesh *em, Key * em_tmp = BKE_editmesh_create(bm); *em = *em_tmp; - /* Calculate face normals and tessellation at once since it's multi-threaded. - * The vertex normals are stored in the undo-mesh, so this doesn't need to be updated. */ - BKE_editmesh_looptri_calc_ex(em, - &(const struct BMeshCalcTessellation_Params){ - .face_normals = true, - }); + /* Normals should not be stored in the undo mesh, so recalculate them. The edit + * mesh is expected to have valid normals and there is no tracked dirty state. */ + BLI_assert(BKE_mesh_vertex_normals_are_dirty(&um->me)); + + /* Calculate face normals and tessellation at once since it's multi-threaded. */ + BKE_editmesh_looptri_and_normals_calc(em); em->selectmode = um->selectmode; bm->selectmode = um->selectmode; diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index 1b6b0c78037..a5e6e7f0852 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -108,8 +108,10 @@ typedef struct { ListBase data; /** Clear the images before baking */ bool bake_clear; - /** Bake-filter, aka margin */ - int bake_filter; + /** margin size in pixels*/ + int bake_margin; + /** margin type */ + char bake_margin_type; /** mode of baking (displacement, normals, AO) */ short mode; /** Use low-resolution mesh when baking displacement maps */ @@ -372,7 +374,8 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op) /* copy data stored in job descriptor */ bkr.scene = scene; - bkr.bake_filter = scene->r.bake_filter; + bkr.bake_margin = scene->r.bake_margin; + bkr.bake_margin_type = scene->r.bake_margin_type; bkr.mode = scene->r.bake_mode; bkr.use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH; bkr.bias = scene->r.bake_biasdist; @@ -416,7 +419,8 @@ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj) /* backup scene settings, so their changing in UI would take no effect on baker */ bkj->scene = scene; - bkj->bake_filter = scene->r.bake_filter; + bkj->bake_margin = scene->r.bake_margin; + bkj->bake_margin_type = scene->r.bake_margin_type; bkj->mode = scene->r.bake_mode; bkj->use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH; bkj->bake_clear = scene->r.bake_flag & R_BAKE_CLEAR; @@ -477,7 +481,8 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa /* copy data stored in job descriptor */ bkr.scene = bkj->scene; - bkr.bake_filter = bkj->bake_filter; + bkr.bake_margin = bkj->bake_margin; + bkr.bake_margin_type = bkj->bake_margin_type; bkr.mode = bkj->mode; bkr.use_lores_mesh = bkj->use_lores_mesh; bkr.user_scale = bkj->user_scale; diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index 700a4094f01..22c2c1ad189 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -89,6 +89,7 @@ typedef struct BakeAPIRender { eScenePassType pass_type; int pass_filter; int margin; + eBakeMarginType margin_type; bool is_clear; bool is_selected_to_active; @@ -184,8 +185,11 @@ static bool write_internal_bake_pixels(Image *image, const int width, const int height, const int margin, + const char margin_type, const bool is_clear, - const bool is_noncolor) + const bool is_noncolor, + Mesh const *mesh, + char const *uv_layer) { ImBuf *ibuf; void *lock; @@ -281,7 +285,7 @@ static bool write_internal_bake_pixels(Image *image, /* margins */ if (margin > 0) { - RE_bake_margin(ibuf, mask_buffer, margin); + RE_bake_margin(ibuf, mask_buffer, margin, margin_type, mesh, uv_layer); } ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; @@ -327,8 +331,11 @@ static bool write_external_bake_pixels(const char *filepath, const int width, const int height, const int margin, + const int margin_type, ImageFormatData *im_format, - const bool is_noncolor) + const bool is_noncolor, + Mesh const *mesh, + char const *uv_layer) { ImBuf *ibuf = NULL; bool ok = false; @@ -385,7 +392,7 @@ static bool write_external_bake_pixels(const char *filepath, mask_buffer = MEM_callocN(sizeof(char) * num_pixels, "Bake Mask"); RE_bake_mask_fill(pixel_array, num_pixels, mask_buffer); - RE_bake_margin(ibuf, mask_buffer, margin); + RE_bake_margin(ibuf, mask_buffer, margin, margin_type, mesh, uv_layer); if (mask_buffer) { MEM_freeN(mask_buffer); @@ -770,6 +777,7 @@ static bool bake_targets_output_internal(const BakeAPIRender *bkr, ReportList *reports) { bool all_ok = true; + const Mesh *me = (Mesh *)ob->data; for (int i = 0; i < targets->num_images; i++) { BakeImage *bk_image = &targets->images[i]; @@ -780,8 +788,11 @@ static bool bake_targets_output_internal(const BakeAPIRender *bkr, bk_image->width, bk_image->height, bkr->margin, + bkr->margin_type, bkr->is_clear, - targets->is_noncolor); + targets->is_noncolor, + me, + bkr->uv_layer); /* might be read by UI to set active image for display */ bake_update_image(bkr->area, bk_image->image); @@ -895,8 +906,11 @@ static bool bake_targets_output_external(const BakeAPIRender *bkr, bk_image->width, bk_image->height, bkr->margin, + bkr->margin_type, &bake->im_format, - targets->is_noncolor); + targets->is_noncolor, + me, + bkr->uv_layer); if (!ok) { BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\"", name); @@ -1625,6 +1639,7 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr) bkr->pass_type = RNA_enum_get(op->ptr, "type"); bkr->pass_filter = RNA_enum_get(op->ptr, "pass_filter"); bkr->margin = RNA_int_get(op->ptr, "margin"); + bkr->margin_type = RNA_enum_get(op->ptr, "margin_type"); bkr->save_mode = (eBakeSaveMode)RNA_enum_get(op->ptr, "save_mode"); bkr->target = (eBakeTarget)RNA_enum_get(op->ptr, "target"); @@ -1818,6 +1833,11 @@ static void bake_set_props(wmOperator *op, Scene *scene) RNA_property_int_set(op->ptr, prop, bake->margin); } + prop = RNA_struct_find_property(op->ptr, "margin_type"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_enum_set(op->ptr, prop, bake->margin_type); + } + prop = RNA_struct_find_property(op->ptr, "use_selected_to_active"); if (!RNA_property_is_set(op->ptr, prop)) { RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_TO_ACTIVE) != 0); @@ -2008,6 +2028,12 @@ void OBJECT_OT_bake(wmOperatorType *ot) "Extends the baked result as a post process filter", 0, 64); + RNA_def_enum(ot->srna, + "margin_type", + rna_enum_bake_margin_type_items, + R_BAKE_EXTEND, + "Margin Type", + "Which algorithm to use to generate the margin"); RNA_def_boolean(ot->srna, "use_selected_to_active", false, diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index c320313643d..6d04bd3f9d5 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -811,8 +811,8 @@ static int apply_objects_internal(bContext *C, /* adjust data */ BKE_mesh_transform(me, mat, true); - /* update normals */ - BKE_mesh_calc_normals(me); + /* If normal layers exist, they are now dirty. */ + BKE_mesh_normals_tag_dirty(me); } else if (ob->type == OB_ARMATURE) { bArmature *arm = ob->data; diff --git a/source/blender/editors/render/render_preview.cc b/source/blender/editors/render/render_preview.cc index 4f94927533b..79c3b2f7ac6 100644 --- a/source/blender/editors/render/render_preview.cc +++ b/source/blender/editors/render/render_preview.cc @@ -687,17 +687,17 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect RE_AcquiredResultGet32(re, &rres, (uint *)rect_byte, 0); IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); - immDrawPixelsTex(&state, - fx, - fy, - rres.rectx, - rres.recty, - GPU_RGBA8, - false, - rect_byte, - 1.0f, - 1.0f, - nullptr); + immDrawPixelsTexTiled(&state, + fx, + fy, + rres.rectx, + rres.recty, + GPU_RGBA8, + false, + rect_byte, + 1.0f, + 1.0f, + nullptr); MEM_freeN(rect_byte); diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index 5f523df18d1..63b7fbc14a7 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -64,7 +64,7 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin) state.shader = GPU_shader_get_builtin_shader(builtin); - /* Shader will be unbind by immUnbindProgram in immDrawPixelsTexScaled_clipping */ + /* Shader will be unbind by immUnbindProgram in a `immDrawPixelsTex` function. */ immBindBuiltinProgram(builtin); immUniform1i("image", 0); state.do_shader_unbind = true; @@ -72,23 +72,92 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin) return state; } -void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state, - float x, - float y, - int img_w, - int img_h, - eGPUTextureFormat gpu_format, - bool use_filter, - void *rect, - float scaleX, - float scaleY, - float clip_min_x, - float clip_min_y, - float clip_max_x, - float clip_max_y, - float xzoom, - float yzoom, - const float color[4]) +void immDrawPixelsTexScaledFullSize(const IMMDrawPixelsTexState *state, + const float x, + const float y, + const int img_w, + const int img_h, + const eGPUTextureFormat gpu_format, + const bool use_filter, + const void *rect, + const float scaleX, + const float scaleY, + const float xzoom, + const float yzoom, + const float color[4]) +{ + static const float white[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + const float draw_width = img_w * scaleX * xzoom; + const float draw_height = img_h * scaleY * yzoom; + /* Down-scaling with regular bi-linear interpolation (i.e. #GL_LINEAR) doesn't give good + * filtering results. Mipmaps can be used to get better results (i.e. #GL_LINEAR_MIPMAP_LINEAR), + * so always use mipmaps when filtering. */ + const bool use_mipmap = use_filter && ((draw_width < img_w) || (draw_height < img_h)); + + GPUTexture *tex = GPU_texture_create_2d("immDrawPixels", img_w, img_h, 1, gpu_format, NULL); + + const bool use_float_data = ELEM(gpu_format, GPU_RGBA16F, GPU_RGB16F, GPU_R16F); + eGPUDataFormat gpu_data_format = (use_float_data) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE; + GPU_texture_update(tex, gpu_data_format, rect); + + GPU_texture_filter_mode(tex, use_filter); + if (use_mipmap) { + GPU_texture_generate_mipmap(tex); + GPU_texture_mipmap_mode(tex, true, true); + } + GPU_texture_wrap_mode(tex, false, true); + + GPU_texture_bind(tex, 0); + + /* optional */ + /* NOTE: Shader could be null for GLSL OCIO drawing, it is fine, since + * it does not need color. + */ + if (state->shader != NULL && GPU_shader_get_uniform(state->shader, "color") != -1) { + immUniformColor4fv((color) ? color : white); + } + + uint pos = state->pos, texco = state->texco; + + immBegin(GPU_PRIM_TRI_FAN, 4); + immAttr2f(texco, 0.0f, 0.0f); + immVertex2f(pos, x, y); + + immAttr2f(texco, 1.0f, 0.0f); + immVertex2f(pos, x + draw_width, y); + + immAttr2f(texco, 1.0f, 1.0f); + immVertex2f(pos, x + draw_width, y + draw_height); + + immAttr2f(texco, 0.0f, 1.0f); + immVertex2f(pos, x, y + draw_height); + immEnd(); + + if (state->do_shader_unbind) { + immUnbindProgram(); + } + + GPU_texture_unbind(tex); + GPU_texture_free(tex); +} + +void immDrawPixelsTexTiled_scaling_clipping(IMMDrawPixelsTexState *state, + float x, + float y, + int img_w, + int img_h, + eGPUTextureFormat gpu_format, + bool use_filter, + void *rect, + float scaleX, + float scaleY, + float clip_min_x, + float clip_min_y, + float clip_max_x, + float clip_max_y, + float xzoom, + float yzoom, + const float color[4]) { int subpart_x, subpart_y, tex_w = 256, tex_h = 256; int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y; @@ -242,103 +311,103 @@ void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state, GPU_unpack_row_length_set(0); } -void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state, - float x, - float y, - int img_w, - int img_h, - eGPUTextureFormat gpu_format, - bool use_filter, - void *rect, - float scaleX, - float scaleY, - float xzoom, - float yzoom, - const float color[4]) +void immDrawPixelsTexTiled_scaling(IMMDrawPixelsTexState *state, + float x, + float y, + int img_w, + int img_h, + eGPUTextureFormat gpu_format, + bool use_filter, + void *rect, + float scaleX, + float scaleY, + float xzoom, + float yzoom, + const float color[4]) { - immDrawPixelsTexScaled_clipping(state, - x, - y, - img_w, - img_h, - gpu_format, - use_filter, - rect, - scaleX, - scaleY, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - xzoom, - yzoom, - color); + immDrawPixelsTexTiled_scaling_clipping(state, + x, + y, + img_w, + img_h, + gpu_format, + use_filter, + rect, + scaleX, + scaleY, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + xzoom, + yzoom, + color); } -void immDrawPixelsTex(IMMDrawPixelsTexState *state, - float x, - float y, - int img_w, - int img_h, - eGPUTextureFormat gpu_format, - bool use_filter, - void *rect, - float xzoom, - float yzoom, - const float color[4]) +void immDrawPixelsTexTiled(IMMDrawPixelsTexState *state, + float x, + float y, + int img_w, + int img_h, + eGPUTextureFormat gpu_format, + bool use_filter, + void *rect, + float xzoom, + float yzoom, + const float color[4]) { - immDrawPixelsTexScaled_clipping(state, - x, - y, - img_w, - img_h, - gpu_format, - use_filter, - rect, - 1.0f, - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - xzoom, - yzoom, - color); + immDrawPixelsTexTiled_scaling_clipping(state, + x, + y, + img_w, + img_h, + gpu_format, + use_filter, + rect, + 1.0f, + 1.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + xzoom, + yzoom, + color); } -void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state, - float x, - float y, - int img_w, - int img_h, - eGPUTextureFormat gpu_format, - bool use_filter, - void *rect, - float clip_min_x, - float clip_min_y, - float clip_max_x, - float clip_max_y, - float xzoom, - float yzoom, - const float color[4]) +void immDrawPixelsTexTiled_clipping(IMMDrawPixelsTexState *state, + float x, + float y, + int img_w, + int img_h, + eGPUTextureFormat gpu_format, + bool use_filter, + void *rect, + float clip_min_x, + float clip_min_y, + float clip_max_x, + float clip_max_y, + float xzoom, + float yzoom, + const float color[4]) { - immDrawPixelsTexScaled_clipping(state, - x, - y, - img_w, - img_h, - gpu_format, - use_filter, - rect, - 1.0f, - 1.0f, - clip_min_x, - clip_min_y, - clip_max_x, - clip_max_y, - xzoom, - yzoom, - color); + immDrawPixelsTexTiled_scaling_clipping(state, + x, + y, + img_w, + img_h, + gpu_format, + use_filter, + rect, + 1.0f, + 1.0f, + clip_min_x, + clip_min_y, + clip_max_x, + clip_max_y, + xzoom, + yzoom, + color); } /* **** Color management helper functions for GLSL display/transform ***** */ @@ -409,40 +478,40 @@ void ED_draw_imbuf_clipping(ImBuf *ibuf, } if (format != 0) { - immDrawPixelsTex_clipping(&state, - x, - y, - ibuf->x, - ibuf->y, - format, - use_filter, - ibuf->rect_float, - clip_min_x, - clip_min_y, - clip_max_x, - clip_max_y, - zoom_x, - zoom_y, - NULL); + immDrawPixelsTexTiled_clipping(&state, + x, + y, + ibuf->x, + ibuf->y, + format, + use_filter, + ibuf->rect_float, + clip_min_x, + clip_min_y, + clip_max_x, + clip_max_y, + zoom_x, + zoom_y, + NULL); } } else if (ibuf->rect) { /* ibuf->rect is always RGBA */ - immDrawPixelsTex_clipping(&state, - x, - y, - ibuf->x, - ibuf->y, - GPU_RGBA8, - use_filter, - ibuf->rect, - clip_min_x, - clip_min_y, - clip_max_x, - clip_max_y, - zoom_x, - zoom_y, - NULL); + immDrawPixelsTexTiled_clipping(&state, + x, + y, + ibuf->x, + ibuf->y, + GPU_RGBA8, + use_filter, + ibuf->rect, + clip_min_x, + clip_min_y, + clip_max_x, + clip_max_y, + zoom_x, + zoom_y, + NULL); } IMB_colormanagement_finish_glsl_draw(); @@ -461,21 +530,21 @@ void ED_draw_imbuf_clipping(ImBuf *ibuf, if (display_buffer) { IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); - immDrawPixelsTex_clipping(&state, - x, - y, - ibuf->x, - ibuf->y, - GPU_RGBA8, - use_filter, - display_buffer, - clip_min_x, - clip_min_y, - clip_max_x, - clip_max_y, - zoom_x, - zoom_y, - NULL); + immDrawPixelsTexTiled_clipping(&state, + x, + y, + ibuf->x, + ibuf->y, + GPU_RGBA8, + use_filter, + display_buffer, + clip_min_x, + clip_min_y, + clip_max_x, + clip_max_y, + zoom_x, + zoom_y, + NULL); } IMB_display_buffer_release(cache_handle); diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 931e7a68466..e1b9454bc0e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -1846,6 +1846,10 @@ void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache, const float angle); void SCULPT_cache_free(SculptSession *ss, struct Object *ob, StrokeCache *cache); +/* -------------------------------------------------------------------- */ +/** \name Sculpt Undo + * \{ */ + /* -------------------------------------------------------------------- */ /** \name Sculpt Undo * \{ */ @@ -1859,6 +1863,8 @@ void SCULPT_undo_push_end_ex(struct Object *ob, const bool use_nested_undo); /** \} */ +/** \} */ + void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3]); /** @@ -1962,7 +1968,7 @@ void SCULPT_OT_ipmask_filter(struct wmOperatorType *ot); /* Detail size. */ /* -------------------------------------------------------------------- */ -/** \name Dyntopo/Retopo Operators +/** \name Dyntopo/Retopology Operators * \{ */ void SCULPT_OT_detail_flood_fill(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index dd1b4e10e60..14c786e5dea 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -403,19 +403,19 @@ static void file_draw_preview(const SpaceFile *sfile, } IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); - immDrawPixelsTexScaled(&state, - (float)xco, - (float)yco, - imb->x, - imb->y, - GPU_RGBA8, - true, - imb->rect, - scale, - scale, - 1.0f, - 1.0f, - col); + immDrawPixelsTexTiled_scaling(&state, + (float)xco, + (float)yco, + imb->x, + imb->y, + GPU_RGBA8, + true, + imb->rect, + scale, + scale, + 1.0f, + 1.0f, + col); GPU_blend(GPU_BLEND_ALPHA); @@ -906,7 +906,8 @@ void file_draw_list(const bContext *C, ARegion *region) * since it's filelist_file_cache_block() and filelist_cache_previews_update() * which controls previews task. */ { - const bool previews_running = filelist_cache_previews_running(files); + const bool previews_running = filelist_cache_previews_running(files) && + !filelist_cache_previews_done(files); // printf("%s: preview task: %d\n", __func__, previews_running); if (previews_running && !sfile->previews_timer) { sfile->previews_timer = WM_event_add_timer_notifier( diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 0c4db167a0e..2d31e8030a4 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -339,7 +339,10 @@ typedef struct FileListEntryCache { /* Previews handling. */ TaskPool *previews_pool; ThreadQueue *previews_done; - size_t previews_todo_count; + /** Counter for previews that are not fully loaded and ready to display yet. So includes all + * previews either in `previews_pool` or `previews_done`. #filelist_cache_previews_update() makes + * previews in `preview_done` ready for display, so the counter is decremented there. */ + int previews_todo_count; } FileListEntryCache; /* FileListCache.flags */ @@ -1647,7 +1650,6 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat preview_taskdata->preview = NULL; BLI_thread_queue_push(cache->previews_done, preview); - atomic_fetch_and_sub_z(&cache->previews_todo_count, 1); // printf("%s: End (%d)...\n", __func__, threadid); } @@ -1689,6 +1691,7 @@ static void filelist_cache_previews_clear(FileListEntryCache *cache) } MEM_freeN(preview); } + cache->previews_todo_count = 0; } } @@ -1759,7 +1762,6 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry preview->icon_id = BKE_icon_imbuf_create(imbuf); } BLI_thread_queue_push(cache->previews_done, preview); - atomic_fetch_and_sub_z(&cache->previews_todo_count, 1); } else { if (entry->redirection_path) { @@ -1780,6 +1782,7 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry true, filelist_cache_preview_freef); } + cache->previews_todo_count++; } static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size) @@ -1877,8 +1880,6 @@ FileList *filelist_new(short type) p->filelist.nbr_entries = FILEDIR_NBR_ENTRIES_UNSET; filelist_settype(p, type); - p->indexer = &file_indexer_noop; - return p; } @@ -1890,6 +1891,7 @@ void filelist_settype(FileList *filelist, short type) filelist->type = type; filelist->tags = 0; + filelist->indexer = &file_indexer_noop; switch (filelist->type) { case FILE_MAIN: filelist->check_dir_fn = filelist_checkdir_main; @@ -2694,6 +2696,7 @@ bool filelist_cache_previews_update(FileList *filelist) } MEM_freeN(preview); + cache->previews_todo_count--; } return changed; @@ -2715,7 +2718,7 @@ bool filelist_cache_previews_done(FileList *filelist) } return (cache->previews_pool == NULL) || (cache->previews_done == NULL) || - (cache->previews_todo_count == (size_t)BLI_thread_queue_len(cache->previews_done)); + (cache->previews_todo_count == 0); } /* would recognize .blend as well */ diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index bbf3c6f768c..97a5f173ffd 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -57,14 +57,11 @@ #include "UI_view2d.h" #include "GPU_framebuffer.h" +#include "file_indexer.h" #include "file_intern.h" /* own include */ #include "filelist.h" #include "fsmenu.h" -/* Enable asset indexing. Currently disabled as ID properties aren't indexed yet and is needed for - * object snapping. See {D12990}. */ -//#define SPACE_FILE_ENABLE_ASSET_INDEXING - static ARegion *file_ui_region_ensure(ScrArea *area, ARegion *region_prev) { ARegion *region; @@ -359,11 +356,11 @@ static void file_refresh(const bContext *C, ScrArea *area) sfile->files, asset_params->asset_catalog_visibility, &asset_params->catalog_id); } -#ifdef SPACE_FILE_ENABLE_ASSET_INDEXING if (ED_fileselect_is_asset_browser(sfile)) { - filelist_setindexer(sfile->files, &file_indexer_asset); + const bool use_asset_indexer = !USER_EXPERIMENTAL_TEST(&U, no_asset_indexing); + filelist_setindexer(sfile->files, + use_asset_indexer ? &file_indexer_asset : &file_indexer_noop); } -#endif /* Update the active indices of bookmarks & co. */ sfile->systemnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_SYSTEM, params->dir); diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt index 94b67e43651..41d6388c947 100644 --- a/source/blender/editors/space_node/CMakeLists.txt +++ b/source/blender/editors/space_node/CMakeLists.txt @@ -51,7 +51,6 @@ set(SRC node_relationships.cc node_select.cc node_templates.cc - node_toolbar.cc node_view.cc space_node.cc diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index ba1c0b41a98..94da7d55e5d 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -51,7 +51,9 @@ #include "GPU_immediate.h" #include "GPU_matrix.h" #include "GPU_platform.h" +#include "GPU_shader_shared.h" #include "GPU_state.h" +#include "GPU_uniform_buffer.h" #include "DRW_engine.h" @@ -77,7 +79,7 @@ #include "NOD_texture.h" #include "node_intern.hh" /* own include */ -using blender::float2; +namespace blender::ed::space_node { /* Default flags for uiItemR(). Name is kept short since this is used a lot in this file. */ #define DEFAULT_FLAGS UI_ITEM_R_SPLIT_EMPTY_NAME @@ -158,6 +160,8 @@ static void node_buts_curvefloat(uiLayout *layout, bContext *UNUSED(C), PointerR uiTemplateCurveMapping(layout, ptr, "mapping", 0, false, false, false, false); } +} // namespace blender::ed::space_node + #define SAMPLE_FLT_ISNONE FLT_MAX /* Bad bad, 2.5 will do better? ... no it won't! */ static float _sample_col[4] = {SAMPLE_FLT_ISNONE}; @@ -171,6 +175,8 @@ void ED_node_sample_set(const float col[4]) } } +namespace blender::ed::space_node { + static void node_buts_curvecol(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; @@ -1099,8 +1105,12 @@ static void node_socket_undefined_interface_draw_color(bContext *UNUSED(C), /** \} */ +} // namespace blender::ed::space_node + void ED_node_init_butfuncs() { + using namespace blender::ed::space_node; + /* Fallback types for undefined tree, nodes, sockets * Defined in blenkernel, but not registered in type hashes. */ @@ -1133,9 +1143,11 @@ void ED_init_custom_node_type(bNodeType *UNUSED(ntype)) void ED_init_custom_node_socket_type(bNodeSocketType *stype) { - stype->draw = node_socket_button_label; + stype->draw = blender::ed::space_node::node_socket_button_label; } +namespace blender::ed::space_node { + static const float virtual_node_socket_color[4] = {0.2, 0.2, 0.2, 1.0}; /* maps standard socket integer type to a color */ @@ -1418,14 +1430,6 @@ static void std_node_socket_interface_draw(bContext *UNUSED(C), uiLayout *layout uiItemR(layout, ptr, "hide_value", DEFAULT_FLAGS, nullptr, 0); } -void ED_init_standard_node_socket_type(bNodeSocketType *stype) -{ - stype->draw = std_node_socket_draw; - stype->draw_color = std_node_socket_draw_color; - stype->interface_draw = std_node_socket_interface_draw; - stype->interface_draw_color = std_node_socket_interface_draw_color; -} - static void node_socket_virtual_draw_color(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PointerRNA *UNUSED(node_ptr), @@ -1434,12 +1438,26 @@ static void node_socket_virtual_draw_color(bContext *UNUSED(C), copy_v4_v4(r_color, virtual_node_socket_color); } +} // namespace blender::ed::space_node + +void ED_init_standard_node_socket_type(bNodeSocketType *stype) +{ + using namespace blender::ed::space_node; + stype->draw = std_node_socket_draw; + stype->draw_color = std_node_socket_draw_color; + stype->interface_draw = std_node_socket_interface_draw; + stype->interface_draw_color = std_node_socket_interface_draw_color; +} + void ED_init_node_socket_type_virtual(bNodeSocketType *stype) { + using namespace blender::ed::space_node; stype->draw = node_socket_button_label; stype->draw_color = node_socket_virtual_draw_color; } +namespace blender::ed::space_node { + /* ************** Generic drawing ************** */ void draw_nodespace_back_pix(const bContext &C, @@ -1873,23 +1891,29 @@ static void nodelink_batch_draw(const SpaceNode &snode) } GPU_blend(GPU_BLEND_ALPHA); + NodeLinkInstanceData node_link_data; - float colors[6][4] = {{0.0f}}; - UI_GetThemeColor4fv(TH_WIRE_INNER, colors[nodelink_get_color_id(TH_WIRE_INNER)]); - UI_GetThemeColor4fv(TH_WIRE, colors[nodelink_get_color_id(TH_WIRE)]); - UI_GetThemeColor4fv(TH_ACTIVE, colors[nodelink_get_color_id(TH_ACTIVE)]); - UI_GetThemeColor4fv(TH_EDGE_SELECT, colors[nodelink_get_color_id(TH_EDGE_SELECT)]); - UI_GetThemeColor4fv(TH_REDALERT, colors[nodelink_get_color_id(TH_REDALERT)]); + UI_GetThemeColor4fv(TH_WIRE_INNER, node_link_data.colors[nodelink_get_color_id(TH_WIRE_INNER)]); + UI_GetThemeColor4fv(TH_WIRE, node_link_data.colors[nodelink_get_color_id(TH_WIRE)]); + UI_GetThemeColor4fv(TH_ACTIVE, node_link_data.colors[nodelink_get_color_id(TH_ACTIVE)]); + UI_GetThemeColor4fv(TH_EDGE_SELECT, + node_link_data.colors[nodelink_get_color_id(TH_EDGE_SELECT)]); + UI_GetThemeColor4fv(TH_REDALERT, node_link_data.colors[nodelink_get_color_id(TH_REDALERT)]); + node_link_data.expandSize = snode.runtime->aspect * LINK_WIDTH; + node_link_data.arrowSize = ARROW_SIZE; + + GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(sizeof(node_link_data), &node_link_data, __func__); GPU_vertbuf_data_len_set(g_batch_link.inst_vbo, g_batch_link.count); GPU_vertbuf_use(g_batch_link.inst_vbo); /* force update. */ GPU_batch_program_set_builtin(g_batch_link.batch, GPU_SHADER_2D_NODELINK_INST); - GPU_batch_uniform_4fv_array(g_batch_link.batch, "colors", 6, colors); - GPU_batch_uniform_1f(g_batch_link.batch, "expandSize", snode.runtime->aspect * LINK_WIDTH); - GPU_batch_uniform_1f(g_batch_link.batch, "arrowSize", ARROW_SIZE); + GPU_batch_uniformbuf_bind(g_batch_link.batch, "node_link_data", ubo); GPU_batch_draw(g_batch_link.batch); + GPU_uniformbuf_unbind(ubo); + GPU_uniformbuf_free(ubo); + nodelink_batch_reset(); GPU_blend(GPU_BLEND_NONE); @@ -2060,19 +2084,32 @@ void node_draw_link_bezier(const bContext &C, copy_v4_v4(colors[2], link_preselection_highlight_color); } + NodeLinkData node_link_data; + for (int i = 0; i < 4; i++) { + copy_v2_v2(node_link_data.bezierPts[i], vec[i]); + } + for (int i = 0; i < 3; i++) { + copy_v4_v4(node_link_data.colors[i], colors[i]); + } + node_link_data.doArrow = drawarrow; + node_link_data.doMuted = drawmuted; + node_link_data.dim_factor = dim_factor; + node_link_data.thickness = thickness; + node_link_data.dash_factor = dash_factor; + node_link_data.dash_alpha = dash_alpha; + node_link_data.expandSize = snode.runtime->aspect * LINK_WIDTH; + node_link_data.arrowSize = ARROW_SIZE; + GPUBatch *batch = g_batch_link.batch_single; + GPUUniformBuf *ubo = GPU_uniformbuf_create_ex( + sizeof(NodeLinkData), &node_link_data, __func__); + GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_NODELINK); - GPU_batch_uniform_2fv_array(batch, "bezierPts", 4, vec); - GPU_batch_uniform_4fv_array(batch, "colors", 3, colors); - GPU_batch_uniform_1f(batch, "expandSize", snode.runtime->aspect * LINK_WIDTH); - GPU_batch_uniform_1f(batch, "arrowSize", ARROW_SIZE); - GPU_batch_uniform_1i(batch, "doArrow", drawarrow); - GPU_batch_uniform_1i(batch, "doMuted", drawmuted); - GPU_batch_uniform_1f(batch, "dim_factor", dim_factor); - GPU_batch_uniform_1f(batch, "thickness", thickness); - GPU_batch_uniform_1f(batch, "dash_factor", dash_factor); - GPU_batch_uniform_1f(batch, "dash_alpha", dash_alpha); + GPU_batch_uniformbuf_bind(batch, "node_link_data", ubo); GPU_batch_draw(batch); + + GPU_uniformbuf_unbind(ubo); + GPU_uniformbuf_free(ubo); } } } @@ -2127,6 +2164,8 @@ void node_draw_link(const bContext &C, node_draw_link_bezier(C, v2d, snode, link, th_col1, th_col2, th_col3); } +} // namespace blender::ed::space_node + void ED_node_draw_snap(View2D *v2d, const float cent[2], float size, NodeBorder border, uint pos) { immBegin(GPU_PRIM_LINES, 4); diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc index be29c125e5a..8e88f1fad5a 100644 --- a/source/blender/editors/space_node/node_add.cc +++ b/source/blender/editors/space_node/node_add.cc @@ -62,6 +62,8 @@ /** \name Utilities * \{ */ +namespace blender::ed::space_node { + bNode *node_add_node(const bContext &C, const char *idname, int type, float locx, float locy) { SpaceNode &snode = *CTX_wm_space_node(&C); @@ -1046,3 +1048,5 @@ void NODE_OT_new_node_tree(wmOperatorType *ot) } /** \} */ + +} // namespace blender::ed::space_node diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index e9a385c525b..82da890fa9b 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -88,13 +88,6 @@ #include "node_intern.hh" /* own include */ -using blender::Array; -using blender::float2; -using blender::Map; -using blender::Set; -using blender::Span; -using blender::Vector; -using blender::VectorSet; using blender::fn::CPPType; using blender::fn::FieldCPPType; using blender::fn::FieldInput; @@ -115,6 +108,8 @@ float ED_node_grid_size() void ED_node_tree_update(const bContext *C) { + using namespace blender::ed::space_node; + SpaceNode *snode = CTX_wm_space_node(C); if (snode) { snode_set_context(*C); @@ -176,6 +171,8 @@ void ED_node_tag_update_id(ID *id) } } +namespace blender::ed::space_node { + static bool compare_nodes(const bNode *a, const bNode *b) { /* These tell if either the node or any of the parent nodes is selected. @@ -232,14 +229,14 @@ static bool compare_nodes(const bNode *a, const bNode *b) return false; } -void ED_node_sort(bNodeTree *ntree) +void node_sort(bNodeTree &ntree) { /* Merge sort is the algorithm of choice here. */ - int totnodes = BLI_listbase_count(&ntree->nodes); + int totnodes = BLI_listbase_count(&ntree.nodes); int k = 1; while (k < totnodes) { - bNode *first_a = (bNode *)ntree->nodes.first; + bNode *first_a = (bNode *)ntree.nodes.first; bNode *first_b = first_a; do { @@ -266,8 +263,8 @@ void ED_node_sort(bNodeTree *ntree) bNode *tmp = node_b; node_b = node_b->next; b++; - BLI_remlink(&ntree->nodes, tmp); - BLI_insertlinkbefore(&ntree->nodes, node_a, tmp); + BLI_remlink(&ntree.nodes, tmp); + BLI_insertlinkbefore(&ntree.nodes, node_a, tmp); } } @@ -1071,8 +1068,12 @@ static void node_socket_draw_nested(const bContext &C, UI_block_emboss_set(&block, old_emboss); } +} // namespace blender::ed::space_node + void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4], float scale) { + using namespace blender::ed::space_node; + const float size = 2.25f * NODE_SOCKSIZE * scale; rcti draw_rect = *rect; float outline_color[4] = {0}; @@ -1119,6 +1120,8 @@ void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[ GPU_blend(state); } +namespace blender::ed::space_node { + /* ************** Socket callbacks *********** */ static void node_draw_preview_background(rctf *rect) @@ -1169,17 +1172,17 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv) GPU_blend(GPU_BLEND_ALPHA); IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); - immDrawPixelsTex(&state, - draw_rect.xmin, - draw_rect.ymin, - preview->xsize, - preview->ysize, - GPU_RGBA8, - true, - preview->rect, - scale, - scale, - nullptr); + immDrawPixelsTexTiled(&state, + draw_rect.xmin, + draw_rect.ymin, + preview->xsize, + preview->ysize, + GPU_RGBA8, + true, + preview->rect, + scale, + scale, + nullptr); GPU_blend(GPU_BLEND_NONE); @@ -2879,3 +2882,5 @@ void node_draw_space(const bContext &C, ARegion ®ion) /* Scrollers. */ UI_view2d_scrollers_draw(&v2d, nullptr); } + +} // namespace blender::ed::space_node diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index 57ac6b2e9bf..6275e7e4656 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -76,10 +76,9 @@ #include "NOD_texture.h" #include "node_intern.hh" /* own include */ -#define USE_ESC_COMPO +namespace blender::ed::space_node { -using blender::float2; -using blender::Map; +#define USE_ESC_COMPO /* ***************** composite job manager ********************** */ @@ -320,8 +319,12 @@ static void compo_startjob(void *cjv, ntree->progress = nullptr; } +} // namespace blender::ed::space_node + void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene *scene_owner) { + using namespace blender::ed::space_node; + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); @@ -361,6 +364,8 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene WM_jobs_start(CTX_wm_manager(C), wm_job); } +namespace blender::ed::space_node { + /* ***************************************** */ bool composite_node_active(bContext *C) @@ -411,18 +416,20 @@ static void send_notifiers_after_tree_change(ID *id, bNodeTree *ntree) } } +} // namespace blender::ed::space_node + void ED_node_tree_propagate_change(const bContext *C, Main *bmain, bNodeTree *root_ntree) { if (C != nullptr) { SpaceNode *snode = CTX_wm_space_node(C); if (snode != nullptr && root_ntree != nullptr) { - send_notifiers_after_tree_change(snode->id, root_ntree); + blender::ed::space_node::send_notifiers_after_tree_change(snode->id, root_ntree); } } NodeTreeUpdateExtraParams params = {nullptr}; params.tree_changed_fn = [](ID *id, bNodeTree *ntree, void *UNUSED(user_data)) { - send_notifiers_after_tree_change(id, ntree); + blender::ed::space_node::send_notifiers_after_tree_change(id, ntree); DEG_id_tag_update(&ntree->id, ID_RECALC_COPY_ON_WRITE); }; params.tree_output_changed_fn = [](ID *UNUSED(id), bNodeTree *ntree, void *UNUSED(user_data)) { @@ -589,6 +596,8 @@ void ED_node_texture_default(const bContext *C, Tex *tex) BKE_ntree_update_main_tree(CTX_data_main(C), tex->nodetree, nullptr); } +namespace blender::ed::space_node { + /** * Here we set the active tree(s), even called for each redraw now, so keep it fast :) */ @@ -631,6 +640,8 @@ void snode_set_context(const bContext &C) } } +} // namespace blender::ed::space_node + void ED_node_set_active( Main *bmain, SpaceNode *snode, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed) { @@ -796,6 +807,8 @@ void ED_node_post_apply_transform(bContext *UNUSED(C), bNodeTree *UNUSED(ntree)) // node_update_nodetree(C, ntree, 0.0f, 0.0f); } +namespace blender::ed::space_node { + /* ***************** generic operator functions for nodes ***************** */ #if 0 /* UNUSED */ @@ -1381,7 +1394,7 @@ void NODE_OT_duplicate(wmOperatorType *ot) ot->srna, "keep_inputs", false, "Keep Inputs", "Keep the input links to duplicated nodes"); } -bool ED_node_select_check(const ListBase *lb) +static bool node_select_check(const ListBase *lb) { LISTBASE_FOREACH (const bNode *, node, lb) { if (node->flag & NODE_SELECT) { @@ -1392,10 +1405,10 @@ bool ED_node_select_check(const ListBase *lb) return false; } -void ED_node_select_all(ListBase *lb, int action) +void node_select_all(ListBase *lb, int action) { if (action == SEL_TOGGLE) { - if (ED_node_select_check(lb)) { + if (node_select_check(lb)) { action = SEL_DESELECT; } else { @@ -2040,18 +2053,15 @@ void NODE_OT_output_file_move_active_socket(wmOperatorType *ot) static int node_copy_color_exec(bContext *C, wmOperator *UNUSED(op)) { - SpaceNode *snode = CTX_wm_space_node(C); - bNodeTree *ntree = snode->edittree; + SpaceNode &snode = *CTX_wm_space_node(C); + bNodeTree &ntree = *snode.edittree; - if (!ntree) { - return OPERATOR_CANCELLED; - } - bNode *node = nodeGetActive(ntree); + bNode *node = nodeGetActive(&ntree); if (!node) { return OPERATOR_CANCELLED; } - LISTBASE_FOREACH (bNode *, node_iter, &ntree->nodes) { + LISTBASE_FOREACH (bNode *, node_iter, &ntree.nodes) { if (node_iter->flag & NODE_SELECT && node_iter != node) { if (node->flag & NODE_CUSTOM_COLOR) { node_iter->flag |= NODE_CUSTOM_COLOR; @@ -2063,7 +2073,7 @@ static int node_copy_color_exec(bContext *C, wmOperator *UNUSED(op)) } } - ED_node_sort(ntree); + node_sort(ntree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); return OPERATOR_FINISHED; @@ -2932,3 +2942,4 @@ void NODE_OT_cryptomatte_layer_remove(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +} // namespace blender::ed::space_node 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 6f96e08d749..542e6fd748f 100644 --- a/source/blender/editors/space_node/node_geometry_attribute_search.cc +++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc @@ -46,13 +46,11 @@ #include "node_intern.hh" -using blender::IndexRange; -using blender::Map; -using blender::Set; -using blender::StringRef; namespace geo_log = blender::nodes::geometry_nodes_eval_log; using geo_log::GeometryAttributeInfo; +namespace blender::ed::space_node { + struct AttributeSearchData { const bNodeTree *tree; const bNode *node; @@ -139,3 +137,5 @@ void node_geometry_add_attribute_search_button(const bContext &UNUSED(C), attribute_search_exec_fn, nullptr); } + +} // namespace blender::ed::space_node diff --git a/source/blender/editors/space_node/node_gizmo.cc b/source/blender/editors/space_node/node_gizmo.cc index 4e5c5694aff..8c60d100b26 100644 --- a/source/blender/editors/space_node/node_gizmo.cc +++ b/source/blender/editors/space_node/node_gizmo.cc @@ -43,6 +43,8 @@ #include "node_intern.hh" +namespace blender::ed::space_node { + /* -------------------------------------------------------------------- */ /** \name Local Utilities * \{ */ @@ -636,3 +638,5 @@ void NODE_GGT_backdrop_corner_pin(wmGizmoGroupType *gzgt) } /** \} */ + +} // namespace blender::ed::space_node diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc index 02d68189997..73e419d667a 100644 --- a/source/blender/editors/space_node/node_group.cc +++ b/source/blender/editors/space_node/node_group.cc @@ -62,9 +62,7 @@ #include "NOD_socket.h" #include "node_intern.hh" /* own include */ -using blender::float2; -using blender::Map; -using blender::Vector; +namespace blender::ed::space_node { /* -------------------------------------------------------------------- */ /** \name Local Utilities @@ -1109,3 +1107,5 @@ void NODE_OT_group_insert(wmOperatorType *ot) } /** \} */ + +} // namespace blender::ed::space_node diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh index 740d1fbb6f9..c161fc70402 100644 --- a/source/blender/editors/space_node/node_intern.hh +++ b/source/blender/editors/space_node/node_intern.hh @@ -45,10 +45,15 @@ struct wmGizmoGroupType; struct wmKeyConfig; struct wmWindow; +/* Outside of blender namespace to avoid Python documentation build error with `ctypes`. */ +extern const char *node_context_dir[]; + +namespace blender::ed::space_node { + /** Temporary data used in node link drag modal operator. */ struct bNodeLinkDrag { /** Links dragged by the operator. */ - blender::Vector links; + Vector links; bool from_multi_input_socket; eNodeSocketInOut in_out; @@ -82,7 +87,7 @@ struct SpaceNode_Runtime { float aspect; /** Mouse position for drawing socket-less links and adding nodes. */ - blender::float2 cursor; + float2 cursor; /** For auto compositing. */ bool recalc; @@ -107,12 +112,12 @@ ENUM_OPERATORS(NodeResizeDirection, NODE_RESIZE_LEFT); /** * Transform between View2Ds in the tree path. */ -blender::float2 space_node_group_offset(const SpaceNode &snode); +float2 space_node_group_offset(const SpaceNode &snode); float node_socket_calculate_height(const bNodeSocket &socket); -blender::float2 node_link_calculate_multi_input_position(const blender::float2 &socket_position, - int index, - int total_inputs); +float2 node_link_calculate_multi_input_position(const float2 &socket_position, + int index, + int total_inputs); int node_get_resize_cursor(NodeResizeDirection directions); NodeResizeDirection node_get_resize_direction(const bNode *node, int x, int y); @@ -127,13 +132,17 @@ void node_socket_color_get(const bContext &C, float r_color[4]); void node_draw_space(const bContext &C, ARegion ®ion); -void node_set_cursor(wmWindow &win, SpaceNode &snode, const blender::float2 &cursor); -/* DPI scaled coords */ -blender::float2 node_to_view(const bNode &node, const blender::float2 &co); -void node_to_updated_rect(const bNode &node, rctf &r_rect); -blender::float2 node_from_view(const bNode &node, const blender::float2 &co); +/** + * Sort nodes by selection: unselected nodes first, then selected, + * then the active node at the very end. Relative order is kept intact. + */ +void node_sort(bNodeTree &ntree); -void node_toolbar_register(ARegionType *art); +void node_set_cursor(wmWindow &win, SpaceNode &snode, const float2 &cursor); +/* DPI scaled coords */ +float2 node_to_view(const bNode &node, const float2 &co); +void node_to_updated_rect(const bNode &node, rctf &r_rect); +float2 node_from_view(const bNode &node, const float2 &co); void node_operatortypes(); void node_keymap(wmKeyConfig *keyconf); @@ -206,6 +215,8 @@ void draw_nodespace_back_pix(const bContext &C, SpaceNode &snode, bNodeInstanceKey parent_key); +void node_select_all(ListBase *lb, int action); + /** * XXX Does some additional initialization on top of #nodeAddNode * Can be used with both custom and static nodes, @@ -231,7 +242,7 @@ void NODE_OT_group_edit(wmOperatorType *ot); void sort_multi_input_socket_links(SpaceNode &snode, bNode &node, bNodeLink *drag_link, - const blender::float2 *cursor); + const float2 *cursor); void NODE_OT_link(wmOperatorType *ot); void NODE_OT_link_make(wmOperatorType *ot); @@ -261,7 +272,7 @@ int node_render_changed_exec(bContext *, wmOperator *); bool node_find_indicated_socket(SpaceNode &snode, bNode **nodep, bNodeSocket **sockp, - const blender::float2 &cursor, + const float2 &cursor, eNodeSocketInOut in_out); float node_link_dim_factor(const View2D &v2d, const bNodeLink &link); bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link); @@ -317,8 +328,6 @@ void node_geometry_add_attribute_search_button(const bContext &C, PointerRNA &socket_ptr, uiLayout &layout); -extern const char *node_context_dir[]; - /* Nodes draw without dpi - the view zoom is flexible. */ #define HIDDEN_RAD (0.75f * U.widget_unit) #define BASIS_RAD (0.2f * U.widget_unit) @@ -333,8 +342,6 @@ extern const char *node_context_dir[]; #define NODE_RESIZE_MARGIN (0.20f * U.widget_unit) #define NODE_LINK_RESOL 12 -namespace blender::ed::space_node { - Vector context_path_for_space_node(const bContext &C); void invoke_node_link_drag_add_menu(bContext &C, diff --git a/source/blender/editors/space_node/node_ops.cc b/source/blender/editors/space_node/node_ops.cc index a6264f151e4..2ca475f6948 100644 --- a/source/blender/editors/space_node/node_ops.cc +++ b/source/blender/editors/space_node/node_ops.cc @@ -35,6 +35,8 @@ #include "node_intern.hh" /* own include */ +namespace blender::ed::space_node { + void node_operatortypes() { WM_operatortype_append(NODE_OT_select); @@ -127,6 +129,17 @@ void node_operatortypes() WM_operatortype_append(NODE_OT_cryptomatte_layer_remove); } +void node_keymap(struct wmKeyConfig *keyconf) +{ + /* Entire Editor only ----------------- */ + WM_keymap_ensure(keyconf, "Node Generic", SPACE_NODE, 0); + + /* Main Region only ----------------- */ + WM_keymap_ensure(keyconf, "Node Editor", SPACE_NODE, 0); +} + +} // namespace blender::ed::space_node + void ED_operatormacros_node() { wmOperatorType *ot; @@ -203,12 +216,3 @@ void ED_operatormacros_node() WM_operatortype_macro_define(ot, "NODE_OT_links_detach"); WM_operatortype_macro_define(ot, "NODE_OT_translate_attach"); } - -void node_keymap(struct wmKeyConfig *keyconf) -{ - /* Entire Editor only ----------------- */ - WM_keymap_ensure(keyconf, "Node Generic", SPACE_NODE, 0); - - /* Main Region only ----------------- */ - WM_keymap_ensure(keyconf, "Node Editor", SPACE_NODE, 0); -} diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index 4055dfdbf9e..fd9420b173d 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -68,10 +68,6 @@ #include "node_intern.hh" /* own include */ using namespace blender::nodes::node_tree_ref_types; -using blender::float2; -using blender::StringRef; -using blender::StringRefNull; -using blender::Vector; /* -------------------------------------------------------------------- */ /** \name Add Node @@ -100,6 +96,8 @@ static void clear_picking_highlight(ListBase *links) } } +namespace blender::ed::space_node { + static bNodeLink *create_drag_link(bNode &node, bNodeSocket &sock) { bNodeLink *oplink = MEM_cnew(__func__); @@ -212,7 +210,10 @@ static bool socket_is_available(bNodeTree *UNUSED(ntree), bNodeSocket *sock, con } if (!allow_used && (sock->flag & SOCK_IN_USE)) { - return false; + /* Multi input sockets are available (even if used). */ + if (!(sock->flag & SOCK_MULTI_INPUT)) { + return false; + } } return true; @@ -452,7 +453,7 @@ static void snode_autoconnect(Main &bmain, /** \name Link Viewer Operator * \{ */ -namespace blender::ed::nodes::viewer_linking { +namespace viewer_linking { /* Depending on the node tree type, different socket types are supported by viewer nodes. */ static bool socket_can_be_viewed(const OutputSocketRef &socket) @@ -719,7 +720,7 @@ static int node_link_viewer(const bContext &C, bNode &bnode_to_view) return link_socket_to_viewer(C, viewer_bnode, bnode_to_view, bsocket_to_view); } -} // namespace blender::ed::nodes::viewer_linking +} // namespace viewer_linking static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -732,7 +733,7 @@ static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op)) ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - if (blender::ed::nodes::viewer_linking::node_link_viewer(*C, *node) == OPERATOR_CANCELLED) { + if (viewer_linking::node_link_viewer(*C, *node) == OPERATOR_CANCELLED) { return OPERATOR_CANCELLED; } @@ -1073,12 +1074,10 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event) if (should_create_drag_link_search_menu(*snode.edittree, *nldrag)) { bNodeLink &link = *nldrag->links.first(); if (nldrag->in_out == SOCK_OUT) { - blender::ed::space_node::invoke_node_link_drag_add_menu( - *C, *link.fromnode, *link.fromsock, cursor); + invoke_node_link_drag_add_menu(*C, *link.fromnode, *link.fromsock, cursor); } else { - blender::ed::space_node::invoke_node_link_drag_add_menu( - *C, *link.tonode, *link.tosock, cursor); + invoke_node_link_drag_add_menu(*C, *link.tonode, *link.tosock, cursor); } } @@ -1585,14 +1584,14 @@ void NODE_OT_links_detach(wmOperatorType *ot) static int node_parent_set_exec(bContext *C, wmOperator *UNUSED(op)) { - SpaceNode *snode = CTX_wm_space_node(C); - bNodeTree *ntree = snode->edittree; - bNode *frame = nodeGetActive(ntree); + SpaceNode &snode = *CTX_wm_space_node(C); + bNodeTree &ntree = *snode.edittree; + bNode *frame = nodeGetActive(&ntree); if (!frame || frame->type != NODE_FRAME) { return OPERATOR_CANCELLED; } - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { if (node == frame) { continue; } @@ -1602,7 +1601,7 @@ static int node_parent_set_exec(bContext *C, wmOperator *UNUSED(op)) } } - ED_node_sort(ntree); + node_sort(ntree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); return OPERATOR_FINISHED; @@ -1699,7 +1698,7 @@ static int node_join_exec(bContext *C, wmOperator *UNUSED(op)) } } - ED_node_sort(&ntree); + node_sort(ntree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); return OPERATOR_FINISHED; @@ -1726,15 +1725,15 @@ void NODE_OT_join(wmOperatorType *ot) /** \name Attach Operator * \{ */ -static bNode *node_find_frame_to_attach(ARegion *region, - const bNodeTree *ntree, +static bNode *node_find_frame_to_attach(ARegion ®ion, + const bNodeTree &ntree, const int mouse_xy[2]) { /* convert mouse coordinates to v2d space */ float cursor[2]; - UI_view2d_region_to_view(®ion->v2d, UNPACK2(mouse_xy), &cursor[0], &cursor[1]); + UI_view2d_region_to_view(®ion.v2d, UNPACK2(mouse_xy), &cursor[0], &cursor[1]); - LISTBASE_FOREACH_BACKWARD (bNode *, frame, &ntree->nodes) { + LISTBASE_FOREACH_BACKWARD (bNode *, frame, &ntree.nodes) { /* skip selected, those are the nodes we want to attach */ if ((frame->type != NODE_FRAME) || (frame->flag & NODE_SELECT)) { continue; @@ -1749,13 +1748,13 @@ static bNode *node_find_frame_to_attach(ARegion *region, static int node_attach_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { - ARegion *region = CTX_wm_region(C); - SpaceNode *snode = CTX_wm_space_node(C); - bNodeTree *ntree = snode->edittree; + ARegion ®ion = *CTX_wm_region(C); + SpaceNode &snode = *CTX_wm_space_node(C); + bNodeTree &ntree = *snode.edittree; bNode *frame = node_find_frame_to_attach(region, ntree, event->mval); if (frame) { - LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree->nodes) { + LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) { if (node->flag & NODE_SELECT) { if (node->parent == nullptr) { /* disallow moving a parent into its child */ @@ -1785,7 +1784,7 @@ static int node_attach_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent } } - ED_node_sort(ntree); + node_sort(ntree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); return OPERATOR_FINISHED; @@ -1845,23 +1844,23 @@ static void node_detach_recursive(bNode *node) /* detach the root nodes in the current selection */ static int node_detach_exec(bContext *C, wmOperator *UNUSED(op)) { - SpaceNode *snode = CTX_wm_space_node(C); - bNodeTree *ntree = snode->edittree; + SpaceNode &snode = *CTX_wm_space_node(C); + bNodeTree &ntree = *snode.edittree; /* reset tags */ - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { node->done = 0; } /* detach nodes recursively * relative order is preserved here! */ - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { if (!(node->done & NODE_DETACH_DONE)) { node_detach_recursive(node); } } - ED_node_sort(ntree); + node_sort(ntree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); return OPERATOR_FINISHED; @@ -1946,8 +1945,12 @@ static bool ed_node_link_conditions(ScrArea *area, return true; } +} // namespace blender::ed::space_node + void ED_node_link_intersect_test(ScrArea *area, int test) { + using namespace blender::ed::space_node; + bNode *select; SpaceNode *snode; if (!ed_node_link_conditions(area, test, &snode, &select)) { @@ -2007,6 +2010,8 @@ void ED_node_link_intersect_test(ScrArea *area, int test) } } +namespace blender::ed::space_node { + /** \} */ /* -------------------------------------------------------------------- */ @@ -2046,20 +2051,17 @@ static int get_main_socket_priority(const bNodeSocket *socket) /** Get the "main" socket based on the node declaration or an heuristic. */ static bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) { - using namespace blender; - using namespace blender::nodes; - ListBase *sockets = (in_out == SOCK_IN) ? &node.inputs : &node.outputs; /* Try to get the main socket based on the socket declaration. */ nodeDeclarationEnsure(&ntree, &node); - const NodeDeclaration *node_decl = node.declaration; + const nodes::NodeDeclaration *node_decl = node.declaration; if (node_decl != nullptr) { - Span socket_decls = (in_out == SOCK_IN) ? node_decl->inputs() : - node_decl->outputs(); + Span socket_decls = (in_out == SOCK_IN) ? node_decl->inputs() : + node_decl->outputs(); int index; LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, index) { - const SocketDeclaration &socket_decl = *socket_decls[index]; + const nodes::SocketDeclaration &socket_decl = *socket_decls[index]; if (nodeSocketIsHidden(socket)) { continue; } @@ -2236,7 +2238,7 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd, /* frame attachment wasn't handled yet * so we search the frame that the node will be attached to later */ - insert.parent = node_find_frame_to_attach(region, ntree, mouse_xy); + insert.parent = node_find_frame_to_attach(*region, *ntree, mouse_xy); /* this makes sure nodes are also correctly offset when inserting a node on top of a frame * without actually making it a part of the frame (because mouse isn't intersecting it) @@ -2423,12 +2425,16 @@ void NODE_OT_insert_offset(wmOperatorType *ot) /** \} */ +} // namespace blender::ed::space_node + /* -------------------------------------------------------------------- */ /** \name Note Link Insert * \{ */ void ED_node_link_insert(Main *bmain, ScrArea *area) { + using namespace blender::ed::space_node; + bNode *select; SpaceNode *snode; if (!ed_node_link_conditions(area, true, &snode, &select)) { diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc index 803cf38c53a..46b9bd3de53 100644 --- a/source/blender/editors/space_node/node_select.cc +++ b/source/blender/editors/space_node/node_select.cc @@ -62,7 +62,7 @@ #include "node_intern.hh" /* own include */ -using blender::float2; +namespace blender::ed::space_node { /** * Function to detect if there is a visible view3d that uses workbench in texture mode. @@ -280,57 +280,51 @@ void node_deselect_all_output_sockets(SpaceNode &snode, const bool deselect_node /* Return true if we need redraw, otherwise false. */ -static bool node_select_grouped_type(SpaceNode *snode, bNode *node_act) +static bool node_select_grouped_type(bNodeTree &node_tree, bNode &node_act) { - bNode *node; bool changed = false; - - for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) { if ((node->flag & SELECT) == 0) { - if (node->type == node_act->type) { + if (node->type == node_act.type) { nodeSetSelected(node, true); changed = true; } } } - return changed; } -static bool node_select_grouped_color(SpaceNode *snode, bNode *node_act) +static bool node_select_grouped_color(bNodeTree &node_tree, bNode &node_act) { bool changed = false; - - LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { + LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) { if ((node->flag & SELECT) == 0) { - if (compare_v3v3(node->color, node_act->color, 0.005f)) { + if (compare_v3v3(node->color, node_act.color, 0.005f)) { nodeSetSelected(node, true); changed = true; } } } - return changed; } -static bool node_select_grouped_name(SpaceNode *snode, bNode *node_act, const bool from_right) +static bool node_select_grouped_name(bNodeTree &node_tree, bNode &node_act, const bool from_right) { - bNode *node; bool changed = false; const uint delims[] = {'.', '-', '_', '\0'}; size_t pref_len_act, pref_len_curr; const char *sep, *suf_act, *suf_curr; pref_len_act = BLI_str_partition_ex_utf8( - node_act->name, nullptr, delims, &sep, &suf_act, from_right); + node_act.name, nullptr, delims, &sep, &suf_act, from_right); /* NOTE: in case we are searching for suffix, and found none, use whole name as suffix. */ if (from_right && !(sep && suf_act)) { pref_len_act = 0; - suf_act = node_act->name; + suf_act = node_act.name; } - for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) { if (node->flag & SELECT) { continue; } @@ -345,7 +339,7 @@ static bool node_select_grouped_name(SpaceNode *snode, bNode *node_act, const bo if ((from_right && STREQ(suf_act, suf_curr)) || (!from_right && (pref_len_act == pref_len_curr) && - STREQLEN(node_act->name, node->name, pref_len_act))) { + STREQLEN(node_act.name, node->name, pref_len_act))) { nodeSetSelected(node, true); changed = true; } @@ -363,20 +357,20 @@ enum { static int node_select_grouped_exec(bContext *C, wmOperator *op) { - SpaceNode *snode = CTX_wm_space_node(C); - bNode *node_act = nodeGetActive(snode->edittree); + SpaceNode &snode = *CTX_wm_space_node(C); + bNodeTree &node_tree = *snode.edittree; + bNode *node_act = nodeGetActive(snode.edittree); if (node_act == nullptr) { return OPERATOR_CANCELLED; } - bNode *node; bool changed = false; const bool extend = RNA_boolean_get(op->ptr, "extend"); const int type = RNA_enum_get(op->ptr, "type"); if (!extend) { - for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) { nodeSetSelected(node, false); } } @@ -384,23 +378,23 @@ static int node_select_grouped_exec(bContext *C, wmOperator *op) switch (type) { case NODE_SELECT_GROUPED_TYPE: - changed = node_select_grouped_type(snode, node_act); + changed = node_select_grouped_type(node_tree, *node_act); break; case NODE_SELECT_GROUPED_COLOR: - changed = node_select_grouped_color(snode, node_act); + changed = node_select_grouped_color(node_tree, *node_act); break; case NODE_SELECT_GROUPED_PREFIX: - changed = node_select_grouped_name(snode, node_act, false); + changed = node_select_grouped_name(node_tree, *node_act, false); break; case NODE_SELECT_GROUPED_SUFIX: - changed = node_select_grouped_name(snode, node_act, true); + changed = node_select_grouped_name(node_tree, *node_act, true); break; default: break; } if (changed) { - ED_node_sort(snode->edittree); + node_sort(node_tree); WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr); return OPERATOR_FINISHED; } @@ -451,26 +445,26 @@ void NODE_OT_select_grouped(wmOperatorType *ot) void node_select_single(bContext &C, bNode &node) { Main *bmain = CTX_data_main(&C); - SpaceNode *snode = CTX_wm_space_node(&C); + SpaceNode &snode = *CTX_wm_space_node(&C); + bNodeTree &node_tree = *snode.edittree; const Object *ob = CTX_data_active_object(&C); const Scene *scene = CTX_data_scene(&C); const wmWindowManager *wm = CTX_wm_manager(&C); bool active_texture_changed = false; - bNode *tnode; - for (tnode = (bNode *)snode->edittree->nodes.first; tnode; tnode = tnode->next) { - if (tnode != &node) { - nodeSetSelected(tnode, false); + LISTBASE_FOREACH (bNode *, node_iter, &node_tree.nodes) { + if (node_iter != &node) { + nodeSetSelected(node_iter, false); } } nodeSetSelected(&node, true); - ED_node_set_active(bmain, snode, snode->edittree, &node, &active_texture_changed); - ED_node_set_active_viewer_key(snode); + ED_node_set_active(bmain, &snode, &node_tree, &node, &active_texture_changed); + ED_node_set_active_viewer_key(&snode); - ED_node_sort(snode->edittree); + node_sort(node_tree); if (active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) { - DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE); + DEG_id_tag_update(&node_tree.id, ID_RECALC_COPY_ON_WRITE); } WM_event_add_notifier(&C, NC_NODE | NA_SELECTED, nullptr); @@ -611,7 +605,7 @@ static int node_mouse_select(bContext *C, ED_spreadsheet_context_paths_set_geometry_node(&bmain, &snode, node); } ED_node_set_active_viewer_key(&snode); - ED_node_sort(snode.edittree); + node_sort(*snode.edittree); if ((active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) || viewer_node_changed) { DEG_id_tag_update(&snode.edittree->id, ID_RECALC_COPY_ON_WRITE); @@ -678,20 +672,21 @@ void NODE_OT_select(wmOperatorType *ot) static int node_box_select_exec(bContext *C, wmOperator *op) { - SpaceNode *snode = CTX_wm_space_node(C); - ARegion *region = CTX_wm_region(C); + SpaceNode &snode = *CTX_wm_space_node(C); + bNodeTree &node_tree = *snode.edittree; + const ARegion ®ion = *CTX_wm_region(C); rctf rectf; WM_operator_properties_border_to_rctf(op, &rectf); - UI_view2d_region_to_view_rctf(®ion->v2d, &rectf, &rectf); + UI_view2d_region_to_view_rctf(®ion.v2d, &rectf, &rectf); const eSelectOp sel_op = (eSelectOp)RNA_enum_get(op->ptr, "mode"); const bool select = (sel_op != SEL_OP_SUB); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - ED_node_select_all(&snode->edittree->nodes, SEL_DESELECT); + node_select_all(&node_tree.nodes, SEL_DESELECT); } - LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { + LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) { bool is_inside; if (node->type == NODE_FRAME) { is_inside = BLI_rctf_inside_rctf(&rectf, &node->totr); @@ -705,7 +700,7 @@ static int node_box_select_exec(bContext *C, wmOperator *op) } } - ED_node_sort(snode->edittree); + node_sort(node_tree); WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr); @@ -775,7 +770,7 @@ static int node_circleselect_exec(bContext *C, wmOperator *op) WM_gesture_is_modal_first((const wmGesture *)op->customdata)); const bool select = (sel_op != SEL_OP_SUB); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - ED_node_select_all(&snode->edittree->nodes, SEL_DESELECT); + node_select_all(&snode->edittree->nodes, SEL_DESELECT); } /* get operator properties */ @@ -850,7 +845,7 @@ static bool do_lasso_select_node(bContext *C, const bool select = (sel_op != SEL_OP_SUB); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - ED_node_select_all(&snode->edittree->nodes, SEL_DESELECT); + node_select_all(&snode->edittree->nodes, SEL_DESELECT); changed = true; } @@ -937,13 +932,13 @@ void NODE_OT_select_lasso(wmOperatorType *ot) static int node_select_all_exec(bContext *C, wmOperator *op) { - SpaceNode *snode = CTX_wm_space_node(C); - ListBase *node_lb = &snode->edittree->nodes; + SpaceNode &snode = *CTX_wm_space_node(C); + ListBase *node_lb = &snode.edittree->nodes; int action = RNA_enum_get(op->ptr, "action"); - ED_node_select_all(node_lb, action); + node_select_all(node_lb, action); - ED_node_sort(snode->edittree); + node_sort(*snode.edittree); WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr); return OPERATOR_FINISHED; @@ -974,15 +969,14 @@ void NODE_OT_select_all(wmOperatorType *ot) static int node_select_linked_to_exec(bContext *C, wmOperator *UNUSED(op)) { - SpaceNode *snode = CTX_wm_space_node(C); - bNodeLink *link; - bNode *node; + SpaceNode &snode = *CTX_wm_space_node(C); + bNodeTree &node_tree = *snode.edittree; - for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) { node->flag &= ~NODE_TEST; } - for (link = (bNodeLink *)snode->edittree->links.first; link; link = link->next) { + LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) { if (nodeLinkIsHidden(link)) { continue; } @@ -991,13 +985,13 @@ static int node_select_linked_to_exec(bContext *C, wmOperator *UNUSED(op)) } } - for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) { if (node->flag & NODE_TEST) { nodeSetSelected(node, true); } } - ED_node_sort(snode->edittree); + node_sort(node_tree); WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr); return OPERATOR_FINISHED; @@ -1026,15 +1020,14 @@ void NODE_OT_select_linked_to(wmOperatorType *ot) static int node_select_linked_from_exec(bContext *C, wmOperator *UNUSED(op)) { - SpaceNode *snode = CTX_wm_space_node(C); - bNodeLink *link; - bNode *node; + SpaceNode &snode = *CTX_wm_space_node(C); + bNodeTree &node_tree = *snode.edittree; - for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) { node->flag &= ~NODE_TEST; } - for (link = (bNodeLink *)snode->edittree->links.first; link; link = link->next) { + LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) { if (nodeLinkIsHidden(link)) { continue; } @@ -1043,13 +1036,13 @@ static int node_select_linked_from_exec(bContext *C, wmOperator *UNUSED(op)) } } - for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) { if (node->flag & NODE_TEST) { nodeSetSelected(node, true); } } - ED_node_sort(snode->edittree); + node_sort(node_tree); WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr); return OPERATOR_FINISHED; @@ -1316,3 +1309,5 @@ void NODE_OT_find_node(wmOperatorType *ot) } /** \} */ + +} diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc index 74c0d2124cd..113e2bd3bb3 100644 --- a/source/blender/editors/space_node/node_templates.cc +++ b/source/blender/editors/space_node/node_templates.cc @@ -53,9 +53,10 @@ #include "ED_undo.h" -using blender::Vector; using blender::nodes::NodeDeclaration; +namespace blender::ed::space_node { + /************************* Node Socket Manipulation **************************/ /* describes an instance of a node type and a specific socket to link */ @@ -716,9 +717,13 @@ static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_ ui_node_menu_column(arg, NODE_CLASS_GROUP, N_("Group")); } +} // namespace blender::ed::space_node + void uiTemplateNodeLink( uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input) { + using namespace blender::ed::space_node; + uiBlock *block = uiLayoutGetBlock(layout); NodeLinkArg *arg; uiBut *but; @@ -760,6 +765,8 @@ void uiTemplateNodeLink( } } +namespace blender::ed::space_node { + /**************************** Node Tree Layout *******************************/ static void ui_node_draw_input( @@ -912,9 +919,13 @@ static void ui_node_draw_input( node->flag &= ~NODE_TEST; } +} // namespace blender::ed::space_node + void uiTemplateNodeView( uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input) { + using namespace blender::ed::space_node; + bNode *tnode; if (!ntree) { diff --git a/source/blender/editors/space_node/node_toolbar.cc b/source/blender/editors/space_node/node_toolbar.cc deleted file mode 100644 index c32dcbef91b..00000000000 --- a/source/blender/editors/space_node/node_toolbar.cc +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2012 Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup nodes - */ - -#include "BLI_utildefines.h" - -#include "DNA_node_types.h" - -#include "BKE_context.h" -#include "BKE_screen.h" - -#include "WM_api.h" - -#include "node_intern.hh" /* own include */ - -/* ******************* node toolbar registration ************** */ - -void node_toolbar_register(ARegionType *UNUSED(art)) -{ -} diff --git a/source/blender/editors/space_node/node_view.cc b/source/blender/editors/space_node/node_view.cc index 12f390c47cd..9d99709a780 100644 --- a/source/blender/editors/space_node/node_view.cc +++ b/source/blender/editors/space_node/node_view.cc @@ -55,7 +55,7 @@ #include "node_intern.hh" /* own include */ -using blender::StringRef; +namespace blender::ed::space_node { /* -------------------------------------------------------------------- */ /** \name View All Operator @@ -444,6 +444,8 @@ static void sample_draw(const bContext *C, ARegion *region, void *arg_info) } } +} // namespace blender::ed::space_node + bool ED_space_node_get_position( Main *bmain, SpaceNode *snode, struct ARegion *region, const int mval[2], float fpos[2]) { @@ -526,6 +528,8 @@ bool ED_space_node_color_sample( return ret; } +namespace blender::ed::space_node { + static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event) { Main *bmain = CTX_data_main(C); @@ -783,3 +787,5 @@ void NODE_OT_geometry_node_view_legacy(wmOperatorType *ot) } /** \} */ + +} // namespace blender::ed::space_node diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc index 3d936aee8cb..f794a8ce294 100644 --- a/source/blender/editors/space_node/space_node.cc +++ b/source/blender/editors/space_node/space_node.cc @@ -206,6 +206,18 @@ void ED_node_set_active_viewer_key(SpaceNode *snode) } } +void ED_node_cursor_location_get(const SpaceNode *snode, float value[2]) +{ + copy_v2_v2(value, snode->runtime->cursor); +} + +void ED_node_cursor_location_set(SpaceNode *snode, const float value[2]) +{ + copy_v2_v2(snode->runtime->cursor, value); +} + +namespace blender::ed::space_node { + float2 space_node_group_offset(const SpaceNode &snode) { const bNodeTreePath *path = (bNodeTreePath *)snode.treepath.last; @@ -556,16 +568,6 @@ static void node_toolbar_region_draw(const bContext *C, ARegion *region) ED_region_panels(C, region); } -void ED_node_cursor_location_get(const SpaceNode *snode, float value[2]) -{ - copy_v2_v2(value, snode->runtime->cursor); -} - -void ED_node_cursor_location_set(SpaceNode *snode, const float value[2]) -{ - copy_v2_v2(snode->runtime->cursor, value); -} - static void node_cursor(wmWindow *win, ScrArea *area, ARegion *region) { SpaceNode *snode = (SpaceNode *)area->spacedata.first; @@ -814,8 +816,14 @@ static void node_region_listener(const wmRegionListenerParams *params) } } +} // namespace blender::ed::space_node + +/* Outside of blender namespace to avoid Python documentation build error with `ctypes`. */ const char *node_context_dir[] = { "selected_nodes", "active_node", "light", "material", "world", nullptr}; + +namespace blender::ed::space_node { + static int /*eContextResult*/ node_context(const bContext *C, const char *member, bContextDataResult *result) @@ -978,8 +986,12 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item, } } +} // namespace blender::ed::space_node + void ED_spacetype_node() { + using namespace blender::ed::space_node; + SpaceType *st = MEM_cnew("spacetype node"); ARegionType *art; @@ -1051,7 +1063,5 @@ void ED_spacetype_node() art->draw = node_toolbar_region_draw; BLI_addhead(&st->regiontypes, art); - node_toolbar_register(art); - BKE_spacetype_register(st); } diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index d43ff38edf9..3b5e16d84a9 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -39,6 +39,7 @@ #include "DNA_sound_types.h" #include "BKE_context.h" +#include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_lib_id.h" #include "BKE_main.h" @@ -46,6 +47,7 @@ #include "BKE_sound.h" #include "SEQ_add.h" +#include "SEQ_animation.h" #include "SEQ_clipboard.h" #include "SEQ_edit.h" #include "SEQ_effects.h" @@ -66,6 +68,7 @@ #include "RNA_enum_types.h" /* For menu, popup, icons, etc. */ +#include "ED_keyframing.h" #include "ED_numinput.h" #include "ED_outliner.h" #include "ED_screen.h" @@ -1655,6 +1658,35 @@ void SEQUENCER_OT_split(struct wmOperatorType *ot) /** \name Duplicate Strips Operator * \{ */ +static void sequencer_backup_original_animation(Scene *scene, ListBase *list) +{ + if (scene->adt == NULL || scene->adt->action == NULL || + BLI_listbase_is_empty(&scene->adt->action->curves)) { + return; + } + + BLI_movelisttolist(list, &scene->adt->action->curves); +} + +static void sequencer_restore_original_animation(Scene *scene, ListBase *list) +{ + if (scene->adt == NULL || scene->adt->action == NULL || BLI_listbase_is_empty(list)) { + return; + } + + BLI_movelisttolist(&scene->adt->action->curves, list); +} + +static void sequencer_duplicate_animation(Scene *scene, Sequence *seq, ListBase *curves_backup) +{ + GSet *fcurves = SEQ_fcurves_by_strip_get(seq, curves_backup); + GSET_FOREACH_BEGIN (FCurve *, fcu, fcurves) { + FCurve *fcu_cpy = BKE_fcurve_copy(fcu); + BLI_addtail(&scene->adt->action->curves, fcu_cpy); + } + GSET_FOREACH_END(); +} + static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); @@ -1665,32 +1697,44 @@ static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) } Sequence *active_seq = SEQ_select_active_get(scene); - ListBase duplicated = {NULL, NULL}; + ListBase duplicated_strips = {NULL, NULL}; - SEQ_sequence_base_dupli_recursive(scene, scene, &duplicated, ed->seqbasep, 0, 0); + SEQ_sequence_base_dupli_recursive(scene, scene, &duplicated_strips, ed->seqbasep, 0, 0); ED_sequencer_deselect_all(scene); - if (duplicated.first) { - Sequence *seq = duplicated.first; - /* Rely on the nseqbase list being added at the end. - * Their UUIDs has been re-generated by the SEQ_sequence_base_dupli_recursive(), */ - BLI_movelisttolist(ed->seqbasep, &duplicated); - - /* Handle duplicated strips: set active, select, ensure unique name and duplicate animation - * data. */ - for (; seq; seq = seq->next) { - if (active_seq != NULL && STREQ(seq->name, active_seq->name)) { - SEQ_select_active_set(scene, seq); - } - seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL + SEQ_LOCK); - SEQ_ensure_unique_name(seq, scene); - } - - WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); - return OPERATOR_FINISHED; + if (duplicated_strips.first == NULL) { + return OPERATOR_CANCELLED; } - return OPERATOR_CANCELLED; + /* Duplicate animation. + * First backup original curves from scene and duplicate strip curves from backup into scene. + * This way, when pasted strips are renamed, curves are renamed with them. Finally, restore + * original curves from backup. + */ + ListBase fcurves_original_backup = {NULL, NULL}; + sequencer_backup_original_animation(scene, &fcurves_original_backup); + + Sequence *seq = duplicated_strips.first; + + /* Rely on the nseqbase list being added at the end. + * Their UUIDs has been re-generated by the SEQ_sequence_base_dupli_recursive(), */ + BLI_movelisttolist(ed->seqbasep, &duplicated_strips); + + /* Handle duplicated strips: set active, select, ensure unique name and duplicate animation + * data. */ + for (; seq; seq = seq->next) { + if (active_seq != NULL && STREQ(seq->name, active_seq->name)) { + SEQ_select_active_set(scene, seq); + } + seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL + SEQ_LOCK); + sequencer_duplicate_animation(scene, seq, &fcurves_original_backup); + SEQ_ensure_unique_name(seq, scene); + } + + sequencer_restore_original_animation(scene, &fcurves_original_backup); + + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + return OPERATOR_FINISHED; } void SEQUENCER_OT_duplicate(wmOperatorType *ot) @@ -1905,7 +1949,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) } seq_next = seq->next; - SEQ_sequence_free(scene, seq, true); + SEQ_edit_flag_for_removal(scene, seqbase, seq); seq = seq_next; } else { @@ -1913,6 +1957,8 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) } } + SEQ_edit_remove_flagged_sequences(scene, seqbase); + SEQ_sort(seqbase); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -2441,6 +2487,22 @@ static void seq_copy_del_sound(Scene *scene, Sequence *seq) } } +static void sequencer_copy_animation(Scene *scene, Sequence *seq) +{ + if (scene->adt == NULL || scene->adt->action == NULL || + BLI_listbase_is_empty(&scene->adt->action->curves)) { + return; + } + + GSet *fcurves = SEQ_fcurves_by_strip_get(seq, &scene->adt->action->curves); + + GSET_FOREACH_BEGIN (FCurve *, fcu, fcurves) { + BLI_addtail(&fcurves_clipboard, BKE_fcurve_copy(fcu)); + } + GSET_FOREACH_END(); + BLI_gset_free(fcurves, NULL); +} + static int sequencer_copy_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -2467,8 +2529,10 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op) seqbase_clipboard_frame = scene->r.cfra; SEQ_clipboard_active_seq_name_store(scene); - /* Remove anything that references the current scene. */ LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) { + /* Copy curves. */ + sequencer_copy_animation(scene, seq); + /* Remove anything that references the current scene. */ seq_copy_del_sound(scene, seq); } @@ -2513,6 +2577,29 @@ void ED_sequencer_deselect_all(Scene *scene) } } +static void sequencer_paste_animation(bContext *C) +{ + if (BLI_listbase_is_empty(&fcurves_clipboard)) { + return; + } + + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + bAction *act; + + if (scene->adt != NULL && scene->adt->action != NULL) { + act = scene->adt->action; + } + else { + /* get action to add F-Curve+keyframe to */ + act = ED_id_action_ensure(bmain, &scene->id); + } + + LISTBASE_FOREACH (FCurve *, fcu, &fcurves_clipboard) { + BLI_addtail(&act->curves, BKE_fcurve_copy(fcu)); + } +} + static int sequencer_paste_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -2542,6 +2629,17 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op) ofs = scene->r.cfra - min_seq_startdisp; } + /* Paste animation. + * Note: Only fcurves are copied. Drivers and NLA action strips are not copied. + * First backup original curves from scene and move curves from clipboard into scene. This way, + * when pasted strips are renamed, pasted fcurves are renamed with them. Finally restore original + * curves from backup. + */ + + ListBase fcurves_original_backup = {NULL, NULL}; + sequencer_backup_original_animation(scene, &fcurves_original_backup); + sequencer_paste_animation(C); + /* Copy strips, temporarily restoring pointers to actual data-blocks. This * must happen on the clipboard itself, so that copying does user counting * on the actual data-blocks. */ @@ -2571,6 +2669,8 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op) } } + sequencer_restore_original_animation(scene, &fcurves_original_backup); + DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); diff --git a/source/blender/editors/space_sequencer/sequencer_thumbnails.c b/source/blender/editors/space_sequencer/sequencer_thumbnails.c index c6fecdb1fc6..82ba17d4db1 100644 --- a/source/blender/editors/space_sequencer/sequencer_thumbnails.c +++ b/source/blender/editors/space_sequencer/sequencer_thumbnails.c @@ -66,7 +66,7 @@ typedef struct ThumbDataItem { static void thumbnail_hash_data_free(void *val) { ThumbDataItem *item = val; - SEQ_sequence_free(item->scene, item->seq_dupli, 0); + SEQ_sequence_free(item->scene, item->seq_dupli); MEM_freeN(val); } diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c index 7f0f30624cb..82a0de9b845 100644 --- a/source/blender/editors/space_topbar/space_topbar.c +++ b/source/blender/editors/space_topbar/space_topbar.c @@ -243,8 +243,11 @@ static void undo_history_draw_menu(const bContext *C, Menu *menu) if (wm->undo_stack == NULL) { return; } + int undo_step_count = 0; - for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next) { + int undo_step_count_all = 0; + for (UndoStep *us = wm->undo_stack->steps.last; us; us = us->prev) { + undo_step_count_all += 1; if (us->skip) { continue; } @@ -255,10 +258,12 @@ static void undo_history_draw_menu(const bContext *C, Menu *menu) uiLayout *column = NULL; const int col_size = 20 + (undo_step_count / 12); - int i = 0; undo_step_count = 0; - for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) { + + /* Reverse the order so the most recent state is first in the menu. */ + int i = undo_step_count_all - 1; + for (UndoStep *us = wm->undo_stack->steps.last; us; us = us->prev, i--) { if (us->skip) { continue; } diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 5451aa5a2e0..243d4033cbc 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -87,7 +87,7 @@ typedef struct { } TransformMedian_Generic; typedef struct { - float location[3], bv_weight, be_weight, skin[2], crease; + float location[3], bv_weight, v_crease, be_weight, skin[2], e_crease; } TransformMedian_Mesh; typedef struct { @@ -319,6 +319,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float BMIter iter; const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); + const int cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE); const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN); const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT); const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE); @@ -335,6 +336,10 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float median->bv_weight += BM_ELEM_CD_GET_FLOAT(eve, cd_vert_bweight_offset); } + if (cd_vert_crease_offset != -1) { + median->v_crease += BM_ELEM_CD_GET_FLOAT(eve, cd_vert_crease_offset); + } + if (has_skinradius) { MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset); add_v2_v2(median->skin, vs->radius); /* Third val not used currently. */ @@ -352,7 +357,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float } if (cd_edge_crease_offset != -1) { - median->crease += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_crease_offset); + median->e_crease += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_crease_offset); } totedgedata++; @@ -489,11 +494,12 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float if (has_meshdata) { TransformMedian_Mesh *median = &median_basis.mesh; if (totedgedata) { - median->crease /= (float)totedgedata; + median->e_crease /= (float)totedgedata; median->be_weight /= (float)totedgedata; } if (tot) { median->bv_weight /= (float)tot; + median->v_crease /= (float)tot; if (has_skinradius) { median->skin[0] /= (float)tot; median->skin[1] /= (float)tot; @@ -683,6 +689,23 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float TIP_("Vertex weight used by Bevel modifier")); UI_but_number_step_size_set(but, 1); UI_but_number_precision_set(but, 2); + /* customdata layer added on demand */ + but = uiDefButF(block, + UI_BTYPE_NUM, + B_TRANSFORM_PANEL_MEDIAN, + tot == 1 ? IFACE_("Vertex Crease:") : IFACE_("Mean Vertex Crease:"), + 0, + yi -= buth + but_margin, + butw, + buth, + &ve_median->v_crease, + 0.0, + 1.0, + 0, + 0, + TIP_("Weight used by the Subdivision Surface modifier")); + UI_but_number_step_size_set(but, 1); + UI_but_number_precision_set(but, 2); } if (has_skinradius) { UI_block_align_begin(block); @@ -761,7 +784,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float yi -= buth + but_margin, butw, buth, - &ve_median->crease, + &ve_median->e_crease, 0.0, 1.0, 0, @@ -958,8 +981,9 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float const bool apply_vcos = (tot == 1) || (len_squared_v3(median_basis.generic.location) != 0.0f); if ((ob->type == OB_MESH) && - (apply_vcos || median_basis.mesh.bv_weight || median_basis.mesh.skin[0] || - median_basis.mesh.skin[1] || median_basis.mesh.be_weight || median_basis.mesh.crease)) { + (apply_vcos || median_basis.mesh.bv_weight || median_basis.mesh.v_crease || + median_basis.mesh.skin[0] || median_basis.mesh.skin[1] || median_basis.mesh.be_weight || + median_basis.mesh.e_crease)) { const TransformMedian_Mesh *median = &median_basis.mesh, *ve_median = &ve_median_basis.mesh; Mesh *me = ob->data; BMEditMesh *em = me->edit_mesh; @@ -969,18 +993,21 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float BMEdge *eed; int cd_vert_bweight_offset = -1; + int cd_vert_crease_offset = -1; int cd_vert_skin_offset = -1; int cd_edge_bweight_offset = -1; int cd_edge_crease_offset = -1; float scale_bv_weight = 1.0f; + float scale_v_crease = 1.0f; float scale_skin[2] = {1.0f, 1.0f}; float scale_be_weight = 1.0f; - float scale_crease = 1.0f; + float scale_e_crease = 1.0f; /* Vertices */ - if (apply_vcos || median->bv_weight || median->skin[0] || median->skin[1]) { + if (apply_vcos || median->bv_weight || median->v_crease || median->skin[0] || + median->skin[1]) { if (median->bv_weight) { BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_BWEIGHT); cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); @@ -989,6 +1016,14 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float scale_bv_weight = compute_scale_factor(ve_median->bv_weight, median->bv_weight); } + if (median->v_crease) { + BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_CREASE); + cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE); + BLI_assert(cd_vert_crease_offset != -1); + + scale_v_crease = compute_scale_factor(ve_median->v_crease, median->v_crease); + } + for (int i = 0; i < 2; i++) { if (median->skin[i]) { cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN); @@ -1011,6 +1046,11 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float apply_scale_factor_clamp(b_weight, tot, ve_median->bv_weight, scale_bv_weight); } + if (cd_vert_crease_offset != -1) { + float *crease = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_crease_offset); + apply_scale_factor_clamp(crease, tot, ve_median->v_crease, scale_v_crease); + } + if (cd_vert_skin_offset != -1) { MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset); @@ -1033,7 +1073,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float /* Edges */ - if (median->be_weight || median->crease) { + if (median->be_weight || median->e_crease) { if (median->be_weight) { BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT); cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT); @@ -1042,12 +1082,12 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float scale_be_weight = compute_scale_factor(ve_median->be_weight, median->be_weight); } - if (median->crease) { + if (median->e_crease) { BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE); cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE); BLI_assert(cd_edge_crease_offset != -1); - scale_crease = compute_scale_factor(ve_median->crease, median->crease); + scale_e_crease = compute_scale_factor(ve_median->e_crease, median->e_crease); } BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { @@ -1057,9 +1097,9 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float apply_scale_factor_clamp(b_weight, tot, ve_median->be_weight, scale_be_weight); } - if (median->crease != 0.0f) { + if (median->e_crease != 0.0f) { float *crease = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_crease_offset); - apply_scale_factor_clamp(crease, tot, ve_median->crease, scale_crease); + apply_scale_factor_clamp(crease, tot, ve_median->e_crease, scale_e_crease); } } } diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c index 255af3feca2..924e51a2b41 100644 --- a/source/blender/editors/transform/transform_convert_curve.c +++ b/source/blender/editors/transform/transform_convert_curve.c @@ -357,26 +357,6 @@ void createTransCurveVerts(TransInfo *t) for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) { if (bp->hide == 0) { if (is_prop_edit || (bp->f1 & SELECT)) { - float axismtx[3][3]; - - if (t->around == V3D_AROUND_LOCAL_ORIGINS) { - if (nu->pntsv == 1) { - float normal[3], plane[3]; - - BKE_nurb_bpoint_calc_normal(nu, bp, normal); - BKE_nurb_bpoint_calc_plane(nu, bp, plane); - - if (createSpaceNormalTangent(axismtx, normal, plane)) { - /* pass */ - } - else { - normalize_v3(normal); - axis_dominant_v3_to_m3(axismtx, normal); - invert_m3(axismtx); - } - } - } - copy_v3_v3(td->iloc, bp->vec); td->loc = bp->vec; copy_v3_v3(td->center, td->loc); @@ -400,9 +380,22 @@ void createTransCurveVerts(TransInfo *t) copy_m3_m3(td->smtx, smtx); copy_m3_m3(td->mtx, mtx); + if (t->around == V3D_AROUND_LOCAL_ORIGINS) { if (nu->pntsv == 1) { - copy_m3_m3(td->axismtx, axismtx); + float normal[3], plane[3]; + + BKE_nurb_bpoint_calc_normal(nu, bp, normal); + BKE_nurb_bpoint_calc_plane(nu, bp, plane); + + if (createSpaceNormalTangent(td->axismtx, normal, plane)) { + /* pass */ + } + else { + normalize_v3(normal); + axis_dominant_v3_to_m3(td->axismtx, normal); + invert_m3(td->axismtx); + } } } diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index c3d95e1ad98..55f2bfd37db 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -1465,7 +1465,7 @@ static void VertsToTransData(TransInfo *t, td->ext = NULL; td->val = NULL; td->extra = eve; - if (t->mode == TFM_BWEIGHT) { + if (t->mode == TFM_BWEIGHT || t->mode == TFM_VERT_CREASE) { td->val = bweight; td->ival = *bweight; } @@ -1606,10 +1606,15 @@ void createTransEditVerts(TransInfo *t) } int cd_vert_bweight_offset = -1; + int cd_vert_crease_offset = -1; if (t->mode == TFM_BWEIGHT) { BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT); cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); } + else if (t->mode == TFM_VERT_CREASE) { + BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_CREASE); + cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE); + } TransData *tob = tc->data; TransDataMirror *td_mirror = tc->data_mirror; @@ -1645,6 +1650,8 @@ void createTransEditVerts(TransInfo *t) else if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) { float *bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) : + (cd_vert_crease_offset != -1) ? + BM_ELEM_CD_GET_VOID_P(eve, cd_vert_crease_offset) : NULL; /* Do not use the island center in case we are using islands diff --git a/source/blender/editors/transform/transform_convert_mesh_edge.c b/source/blender/editors/transform/transform_convert_mesh_edge.c index 2db3e259153..2243f66cc7f 100644 --- a/source/blender/editors/transform/transform_convert_mesh_edge.c +++ b/source/blender/editors/transform/transform_convert_mesh_edge.c @@ -86,8 +86,8 @@ void createTransEdge(TransInfo *t) BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_BWEIGHT); cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT); } - else { /* if (t->mode == TFM_CREASE) { */ - BLI_assert(t->mode == TFM_CREASE); + else { /* if (t->mode == TFM_EDGE_CREASE) { */ + BLI_assert(t->mode == TFM_EDGE_CREASE); BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_CREASE); cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE); } diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c index 2244f82509f..01eae36e846 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.c +++ b/source/blender/editors/transform/transform_convert_sequencer.c @@ -34,6 +34,7 @@ #include "ED_markers.h" +#include "SEQ_animation.h" #include "SEQ_edit.h" #include "SEQ_effects.h" #include "SEQ_iterator.h" diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 43d894d60f2..d1cbab9ff8a 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -260,7 +260,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } /* Crease needs edge flag */ - if (ELEM(t->mode, TFM_CREASE, TFM_BWEIGHT)) { + if (ELEM(t->mode, TFM_EDGE_CREASE, TFM_BWEIGHT)) { t->options |= CTX_EDGE_DATA; } diff --git a/source/blender/editors/transform/transform_gizmo_extrude_3d.c b/source/blender/editors/transform/transform_gizmo_extrude_3d.c index 6e89c3de197..dee6e7281ef 100644 --- a/source/blender/editors/transform/transform_gizmo_extrude_3d.c +++ b/source/blender/editors/transform/transform_gizmo_extrude_3d.c @@ -82,6 +82,7 @@ typedef struct GizmoExtrudeGroup { float orient_matrix[3][3]; bool constraint_axis[3]; float value[4]; + int orient_type; } redo_xform; /* Depends on object type. */ @@ -310,6 +311,7 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup) RNA_float_get_array(op_xform->ptr, "orient_matrix", &ggd->redo_xform.orient_matrix[0][0]); RNA_boolean_get_array(op_xform->ptr, "constraint_axis", ggd->redo_xform.constraint_axis); RNA_float_get_array(op_xform->ptr, "value", ggd->redo_xform.value); + ggd->redo_xform.orient_type = RNA_enum_get(op_xform->ptr, "orient_type"); /* Set properties for redo. */ for (int i = 0; i < 3; i++) { @@ -435,7 +437,8 @@ static void gizmo_mesh_extrude_invoke_prepare(const bContext *UNUSED(C), if (gz == ggd->adjust[0]) { RNA_boolean_set_array(¯optr, "constraint_axis", ggd->redo_xform.constraint_axis); RNA_float_set_array(¯optr, "orient_matrix", &ggd->redo_xform.orient_matrix[0][0]); - RNA_enum_set(¯optr, "orient_type", V3D_ORIENT_NORMAL); + RNA_enum_set(¯optr, "orient_matrix_type", ggd->redo_xform.orient_type); + RNA_enum_set(¯optr, "orient_type", ggd->redo_xform.orient_type); } RNA_float_set_array(¯optr, "value", ggd->redo_xform.value); } diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index 2ab4cdff5e6..e1fea62ae54 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -1135,8 +1135,11 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode) case TFM_PUSHPULL: initPushPull(t); break; - case TFM_CREASE: - initCrease(t); + case TFM_EDGE_CREASE: + initEgdeCrease(t); + break; + case TFM_VERT_CREASE: + initVertCrease(t); break; case TFM_BONESIZE: initBoneSize(t); diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h index cdcda5a8648..16b26724c67 100644 --- a/source/blender/editors/transform/transform_mode.h +++ b/source/blender/editors/transform/transform_mode.h @@ -106,7 +106,8 @@ void initCurveShrinkFatten(TransInfo *t); void initBevelWeight(TransInfo *t); /* transform_mode_edge_crease.c */ -void initCrease(TransInfo *t); +void initEgdeCrease(TransInfo *t); +void initVertCrease(TransInfo *t); /* transform_mode_edge_rotate_normal.c */ void initNormalRotation(TransInfo *t); diff --git a/source/blender/editors/transform/transform_mode_edge_crease.c b/source/blender/editors/transform/transform_mode_edge_crease.c index debc2a1be3e..60b95a1d2da 100644 --- a/source/blender/editors/transform/transform_mode_edge_crease.c +++ b/source/blender/editors/transform/transform_mode_edge_crease.c @@ -157,9 +157,9 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2])) ED_area_status_text(t->area, str); } -void initCrease(TransInfo *t) +static void initCrease_ex(TransInfo *t, int mode) { - t->mode = TFM_CREASE; + t->mode = mode; t->transform = applyCrease; initMouseInputMode(t, &t->mouse, INPUT_SPRING_DELTA); @@ -176,4 +176,13 @@ void initCrease(TransInfo *t) t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; } +void initEgdeCrease(TransInfo *t) +{ + initCrease_ex(t, TFM_EDGE_CREASE); +} + +void initVertCrease(TransInfo *t) +{ + initCrease_ex(t, TFM_VERT_CREASE); +} /** \} */ diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 5ed340abf97..80feb934f1a 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -78,6 +78,7 @@ static const char OP_BONE_SIZE[] = "TRANSFORM_OT_bbone_resize"; static const char OP_EDGE_SLIDE[] = "TRANSFORM_OT_edge_slide"; static const char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide"; static const char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease"; +static const char OP_VERT_CREASE[] = "TRANSFORM_OT_vert_crease"; static const char OP_EDGE_BWEIGHT[] = "TRANSFORM_OT_edge_bevelweight"; static const char OP_SEQ_SLIDE[] = "TRANSFORM_OT_seq_slide"; static const char OP_NORMAL_ROTATION[] = "TRANSFORM_OT_rotate_normal"; @@ -98,6 +99,7 @@ static void TRANSFORM_OT_bbone_resize(struct wmOperatorType *ot); static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot); static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot); static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot); +static void TRANSFORM_OT_vert_crease(struct wmOperatorType *ot); static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot); static void TRANSFORM_OT_seq_slide(struct wmOperatorType *ot); static void TRANSFORM_OT_rotate_normal(struct wmOperatorType *ot); @@ -118,7 +120,8 @@ static TransformModeItem transform_modes[] = { {OP_BONE_SIZE, TFM_BONESIZE, TRANSFORM_OT_bbone_resize}, {OP_EDGE_SLIDE, TFM_EDGE_SLIDE, TRANSFORM_OT_edge_slide}, {OP_VERT_SLIDE, TFM_VERT_SLIDE, TRANSFORM_OT_vert_slide}, - {OP_EDGE_CREASE, TFM_CREASE, TRANSFORM_OT_edge_crease}, + {OP_EDGE_CREASE, TFM_EDGE_CREASE, TRANSFORM_OT_edge_crease}, + {OP_VERT_CREASE, TFM_VERT_CREASE, TRANSFORM_OT_vert_crease}, {OP_EDGE_BWEIGHT, TFM_BWEIGHT, TRANSFORM_OT_edge_bevelweight}, {OP_SEQ_SLIDE, TFM_SEQ_SLIDE, TRANSFORM_OT_seq_slide}, {OP_NORMAL_ROTATION, TFM_NORMAL_ROTATION, TRANSFORM_OT_rotate_normal}, @@ -139,7 +142,8 @@ const EnumPropertyItem rna_enum_transform_mode_types[] = { {TFM_TILT, "TILT", 0, "Tilt", ""}, {TFM_TRACKBALL, "TRACKBALL", 0, "Trackball", ""}, {TFM_PUSHPULL, "PUSHPULL", 0, "Push/Pull", ""}, - {TFM_CREASE, "CREASE", 0, "Crease", ""}, + {TFM_EDGE_CREASE, "CREASE", 0, "Crease", ""}, + {TFM_VERT_CREASE, "VERTEX_CREASE", 0, "Vertex Crease", ""}, {TFM_MIRROR, "MIRROR", 0, "Mirror", ""}, {TFM_BONESIZE, "BONE_SIZE", 0, "Bone Size", ""}, {TFM_BONE_ENVELOPE, "BONE_ENVELOPE", 0, "Bone Envelope", ""}, @@ -1196,6 +1200,29 @@ static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot) Transform_Properties(ot, P_SNAP); } +static void TRANSFORM_OT_vert_crease(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Crease"; + ot->description = "Change the crease of vertices"; + ot->idname = OP_VERT_CREASE; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + + /* api callbacks */ + ot->invoke = transform_invoke; + ot->exec = transform_exec; + ot->modal = transform_modal; + ot->cancel = transform_cancel; + ot->poll = ED_operator_editmesh; + ot->poll_property = transform_poll_property; + + RNA_def_float_factor(ot->srna, "value", 0, -1.0f, 1.0f, "Factor", "", -1.0f, 1.0f); + + WM_operatortype_props_advanced_begin(ot); + + Transform_Properties(ot, P_SNAP); +} + static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot) { /* identifiers */ diff --git a/source/blender/freestyle/CMakeLists.txt b/source/blender/freestyle/CMakeLists.txt index 47da6bc55f6..d16787714c9 100644 --- a/source/blender/freestyle/CMakeLists.txt +++ b/source/blender/freestyle/CMakeLists.txt @@ -595,6 +595,6 @@ endif() blender_add_lib(bf_freestyle "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") -if(COMMAND target_precompile_headers) +if(COMMAND target_precompile_headers) target_precompile_headers(bf_freestyle PRIVATE FRS_precomp.h) endif() diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c index b35ebd4be9a..6a3a27a6630 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c @@ -314,7 +314,9 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemR(layout, ptr, "source_object", 0, NULL, ICON_OBJECT_DATA); } else if (source_type == LRT_SOURCE_COLLECTION) { - uiItemR(layout, ptr, "source_collection", 0, NULL, ICON_OUTLINER_COLLECTION); + uiLayout *sub = uiLayoutRow(layout, true); + uiItemR(sub, ptr, "source_collection", 0, NULL, ICON_OUTLINER_COLLECTION); + uiItemR(sub, ptr, "use_invert_collection", 0, "", ICON_ARROW_LEFTRIGHT); } else { /* Source is Scene. */ @@ -407,6 +409,7 @@ static void options_panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemR(col, ptr, "use_clip_plane_boundaries", 0, NULL, ICON_NONE); uiItemR(col, ptr, "use_crease_on_smooth", 0, IFACE_("Crease On Smooth"), ICON_NONE); uiItemR(col, ptr, "use_crease_on_sharp", 0, IFACE_("Crease On Sharp"), ICON_NONE); + uiItemR(col, ptr, "use_back_face_culling", 0, NULL, ICON_NONE); } static void style_panel_draw(const bContext *UNUSED(C), Panel *panel) @@ -578,6 +581,7 @@ static void face_mark_panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemR(layout, ptr, "use_face_mark_invert", 0, NULL, ICON_NONE); uiItemR(layout, ptr, "use_face_mark_boundaries", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_face_mark_keep_contour", 0, NULL, ICON_NONE); } static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel) @@ -605,6 +609,7 @@ static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemR(col, ptr, "use_fuzzy_all", 0, NULL, ICON_NONE); uiItemR(col, ptr, "use_loose_edge_chain", 0, IFACE_("Loose Edges"), ICON_NONE); uiItemR(col, ptr, "use_loose_as_contour", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_detail_preserve", 0, NULL, ICON_NONE); uiItemR(col, ptr, "use_geometry_space_chain", 0, IFACE_("Geometry Space"), ICON_NONE); uiItemR(layout, diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h index 8c5820c9667..cb17d1d5f1a 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h +++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h @@ -300,14 +300,18 @@ typedef struct LineartRenderBuffer { bool use_loose_edge_chain; bool use_geometry_space_chain; bool use_image_boundary_trimming; + bool use_back_face_culling; bool filter_face_mark; bool filter_face_mark_invert; bool filter_face_mark_boundaries; + bool filter_face_mark_keep_contour; bool force_crease; bool sharp_as_crease; + bool chain_preserve_details; + /* Keep an copy of these data so when line art is running it's self-contained. */ bool cam_is_persp; float cam_obmat[4][4]; diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c index 0deb8b1c335..78ad895c93e 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c @@ -571,6 +571,57 @@ static void lineart_bounding_area_link_chain(LineartRenderBuffer *rb, LineartEdg } } +static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec, + LineartEdgeChainItem *last_matching_eci, + float distance_threshold, + bool preserve_details, + LineartEdgeChainItem **r_next_eci) +{ + float dist_accum = 0; + + int fixed_occ = last_matching_eci->occlusion; + unsigned char fixed_mask = last_matching_eci->material_mask_bits; + + LineartEdgeChainItem *can_skip_to = NULL; + LineartEdgeChainItem *last_eci = last_matching_eci; + for (LineartEdgeChainItem *eci = last_matching_eci->next; eci; eci = eci->next) { + dist_accum += len_v2v2(last_eci->pos, eci->pos); + if (dist_accum > distance_threshold) { + break; + } + last_eci = eci; + /* The reason for this is because we don't want visible segments to be "skipped" into + * connecting with invisible segments. */ + if (eci->occlusion < fixed_occ) { + break; + } + if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ) { + can_skip_to = eci; + } + } + if (can_skip_to) { + /* Either mark all in-between segments with the same occlusion and mask or delete those + * different ones. */ + LineartEdgeChainItem *next_eci; + for (LineartEdgeChainItem *eci = last_matching_eci->next; eci != can_skip_to; eci = next_eci) { + next_eci = eci->next; + if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ) { + continue; + } + if (preserve_details) { + eci->material_mask_bits = fixed_mask; + eci->occlusion = fixed_occ; + } + else { + BLI_remlink(&ec->chain, eci); + } + } + *r_next_eci = can_skip_to; + return true; + } + return false; +} + void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb) { LineartEdgeChain *ec, *new_ec; @@ -597,6 +648,13 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb) if (lineart_point_overlapping(next_eci, eci->pos[0], eci->pos[1], 1e-5)) { continue; } + if (lineart_chain_fix_ambiguous_segments(ec, + eci->prev, + rb->chaining_image_threshold, + rb->chain_preserve_details, + &next_eci)) { + continue; + } } else { /* Set the same occlusion level for the end vertex, so when further connection is needed diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index 77e1f408871..3fb7aade42c 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -1346,6 +1346,10 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far) /* Select the triangle in the array. */ tri = (void *)(((uchar *)eln->pointer) + rb->triangle_size * i); + if (tri->flags & LRT_CULL_DISCARD) { + continue; + } + LRT_CULL_DECIDE_INSIDE LRT_CULL_ENSURE_MEMORY lineart_triangle_cull_single(rb, @@ -1489,6 +1493,7 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb, FreestyleEdge *fel, *fer; bool face_mark_filtered = false; uint16_t edge_flag_result = 0; + bool only_contour = false; if (use_freestyle_face && rb->filter_face_mark) { fel = CustomData_bmesh_get(&bm_if_freestyle->pdata, ll->f->head.data, CD_FREESTYLE_FACE); @@ -1513,7 +1518,12 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb, face_mark_filtered = !face_mark_filtered; } if (!face_mark_filtered) { - return 0; + if (rb->filter_face_mark_keep_contour) { + only_contour = true; + } + else { + return 0; + } } } @@ -1536,8 +1546,31 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb, double dot_1 = 0, dot_2 = 0; double result; - if (rb->cam_is_persp) { - sub_v3_v3v3_db(view_vector, l->gloc, rb->camera_pos); + if (rb->use_contour || rb->use_back_face_culling) { + + if (rb->cam_is_persp) { + sub_v3_v3v3_db(view_vector, rb->camera_pos, l->gloc); + } + else { + view_vector = rb->view_vector; + } + + dot_1 = dot_v3v3_db(view_vector, tri1->gn); + dot_2 = dot_v3v3_db(view_vector, tri2->gn); + + if (rb->use_contour && (result = dot_1 * dot_2) <= 0 && (dot_1 + dot_2)) { + edge_flag_result |= LRT_EDGE_FLAG_CONTOUR; + } + + /* Because the ray points towards the camera, so backface is when dot value being negative.*/ + if (rb->use_back_face_culling) { + if (dot_1 < 0) { + tri1->flags |= LRT_CULL_DISCARD; + } + if (dot_2 < 0) { + tri2->flags |= LRT_CULL_DISCARD; + } + } } else { view_vector = rb->view_vector; @@ -1550,6 +1583,12 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb, edge_flag_result |= LRT_EDGE_FLAG_CONTOUR; } + /* For when face mark filtering decided that we discard the face but keep_contour option is on. + * so we still have correct full contour around the object. */ + if (only_contour) { + return edge_flag_result; + } + if (rb->use_crease) { if (rb->sharp_as_crease && !BM_elem_flag_test(e, BM_ELEM_SMOOTH)) { edge_flag_result |= LRT_EDGE_FLAG_CREASE; @@ -1876,7 +1915,8 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu bm); if (eflag) { /* Only allocate for feature lines (instead of all lines) to save memory. - * If allow duplicated edges, one edge gets added multiple times if it has multiple types. */ + * If allow duplicated edges, one edge gets added multiple times if it has multiple types. + */ allocate_la_e += rb->allow_duplicated_types ? lineart_edge_type_duplication_count(eflag) : 1; } /* Here we just use bm's flag for when loading actual lines, then we don't need to call @@ -2070,8 +2110,8 @@ static bool lineart_geometry_check_visible(double (*model_view_proj)[4], } bool cond[6] = {true, true, true, true, true, true}; - /* Because for a point to be inside clip space, it must satisfy `-Wc <= XYCc <= Wc`, here if all - * verts falls to the same side of the clip space border, we know it's outside view. */ + /* Because for a point to be inside clip space, it must satisfy `-Wc <= XYCc <= Wc`, here if + * all verts falls to the same side of the clip space border, we know it's outside view. */ for (int i = 0; i < 8; i++) { cond[0] &= (co[i][0] < -co[i][3]); cond[1] &= (co[i][0] > co[i][3]); @@ -2146,7 +2186,8 @@ static void lineart_main_load_geometries( int thread_count = rb->thread_count; - /* This memory is in render buffer memory pool. so we don't need to free those after loading. */ + /* This memory is in render buffer memory pool. so we don't need to free those after loading. + */ LineartObjectLoadTaskInfo *olti = lineart_mem_acquire( &rb->render_data_pool, sizeof(LineartObjectLoadTaskInfo) * thread_count); @@ -2429,8 +2470,9 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl), dot_f = dot_v3v3_db(Cv, tri->gn); /* NOTE(Yiming): When we don't use `dot_f==0` here, it's theoretically possible that _some_ - * faces in perspective mode would get erroneously caught in this condition where they really are - * legit faces that would produce occlusion, but haven't encountered those yet in my test files. + * faces in perspective mode would get erroneously caught in this condition where they really + * are legit faces that would produce occlusion, but haven't encountered those yet in my test + * files. */ if (fabs(dot_f) < FLT_EPSILON) { return false; @@ -2497,8 +2539,9 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl), return false; \ } - /* Determine the pair of edges that the line has crossed. The "|" symbol in the comment indicates - * triangle boundary. DBL_TRIANGLE_LIM is needed to for floating point precision tolerance. */ + /* Determine the pair of edges that the line has crossed. The "|" symbol in the comment + * indicates triangle boundary. DBL_TRIANGLE_LIM is needed to for floating point precision + * tolerance. */ if (st_l == 2) { /* Left side is in the triangle. */ @@ -3159,6 +3202,14 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene, rb->force_crease = (lmd->calculation_flags & LRT_USE_CREASE_ON_SMOOTH_SURFACES) != 0; rb->sharp_as_crease = (lmd->calculation_flags & LRT_USE_CREASE_ON_SHARP_EDGES) != 0; + rb->chain_preserve_details = (lmd->calculation_flags & LRT_CHAIN_PRESERVE_DETAILS) != 0; + + /* This is used to limit calculation to a certain level to save time, lines who have higher + * occlusion levels will get ignored. */ + rb->max_occlusion_level = lmd->level_end_override; + + rb->use_back_face_culling = (lmd->calculation_flags & LRT_USE_BACK_FACE_CULLING) != 0; + int16_t edge_types = lmd->edge_types_override; rb->use_contour = (edge_types & LRT_EDGE_FLAG_CONTOUR) != 0; @@ -3172,6 +3223,8 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene, rb->filter_face_mark = (lmd->calculation_flags & LRT_FILTER_FACE_MARK) != 0; rb->filter_face_mark_boundaries = (lmd->calculation_flags & LRT_FILTER_FACE_MARK_BOUNDARIES) != 0; + rb->filter_face_mark_keep_contour = (lmd->calculation_flags & + LRT_FILTER_FACE_MARK_KEEP_CONTOUR) != 0; rb->chain_data_pool = &lc->chain_data_pool; @@ -4177,12 +4230,6 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, * See definition of LineartTriangleThread for details. */ rb->triangle_size = lineart_triangle_size_get(scene, rb); - /* This is used to limit calculation to a certain level to save time, lines who have higher - * occlusion levels will get ignored. */ - rb->max_occlusion_level = (lmd->flags & LRT_GPENCIL_USE_CACHE) ? - lmd->level_end_override : - (lmd->use_multiple_levels ? lmd->level_end : lmd->level_start); - /* FIXME(Yiming): See definition of int #LineartRenderBuffer::_source_type for detailed. */ rb->_source_type = lmd->source_type; rb->_source_collection = lmd->source_collection; @@ -4254,8 +4301,8 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, if (rb->chain_smooth_tolerance > FLT_EPSILON) { /* Keeping UI range of 0-1 for ease of read while scaling down the actual value for best - * effective range in image-space (Coordinate only goes from -1 to 1). This value is somewhat - * arbitrary, but works best for the moment. */ + * effective range in image-space (Coordinate only goes from -1 to 1). This value is + * somewhat arbitrary, but works best for the moment. */ MOD_lineart_smooth_chains(rb, rb->chain_smooth_tolerance / 50); } @@ -4364,8 +4411,15 @@ static void lineart_gpencil_generate(LineartCache *cache, continue; } if (orig_col && ec->object_ref) { - if (!BKE_collection_has_object_recursive_instanced(orig_col, (Object *)ec->object_ref)) { - continue; + if (BKE_collection_has_object_recursive_instanced(orig_col, (Object *)ec->object_ref)) { + if (modifier_flags & LRT_GPENCIL_INVERT_COLLECTION) { + continue; + } + } + else { + if (!(modifier_flags & LRT_GPENCIL_INVERT_COLLECTION)) { + continue; + } } } if (mask_switches & LRT_GPENCIL_MATERIAL_MASK_ENABLE) { diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index add4078dfd3..9043a4b6edb 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -84,6 +84,8 @@ set(SRC intern/gpu_select_sample_query.cc intern/gpu_shader.cc intern/gpu_shader_builtin.c + intern/gpu_shader_create_info.cc + intern/gpu_shader_dependency.cc intern/gpu_shader_interface.cc intern/gpu_shader_log.cc intern/gpu_state.cc @@ -136,6 +138,7 @@ set(SRC GPU_primitive.h GPU_select.h GPU_shader.h + GPU_shader_shared.h GPU_state.h GPU_texture.h GPU_uniform_buffer.h @@ -160,6 +163,8 @@ set(SRC intern/gpu_private.h intern/gpu_query.hh intern/gpu_select_private.h + intern/gpu_shader_create_info.hh + intern/gpu_shader_create_info_private.hh intern/gpu_shader_interface.hh intern/gpu_shader_private.hh intern/gpu_state_private.hh @@ -198,174 +203,251 @@ if(NOT WITH_SYSTEM_GLEW) ) endif() -data_to_c_simple(shaders/gpu_shader_depth_only_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_uniform_color_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_checker_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_diag_stripes_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_simple_lighting_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_flat_color_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_flat_id_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_2D_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_2D_area_borders_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_2D_area_borders_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_2D_widget_base_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_2D_widget_base_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_2D_widget_shadow_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_2D_widget_shadow_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_2D_nodelink_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_2D_nodelink_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_2D_flat_color_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_2D_line_dashed_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_2D_smooth_color_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_2D_smooth_color_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_2D_image_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_2D_image_rect_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_2D_image_multi_rect_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_image_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_image_desaturate_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_image_overlays_merge_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_image_modulate_alpha_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_image_shuffle_color_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_image_color_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_image_varying_color_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_3D_image_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_3D_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_3D_normal_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_3D_flat_color_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_3D_polyline_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_3D_polyline_geom.glsl SRC) -data_to_c_simple(shaders/gpu_shader_3D_polyline_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_3D_smooth_color_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_3D_smooth_color_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_3D_passthrough_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl SRC) +set(GLSL_SRC + GPU_shader_shared.h -data_to_c_simple(shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl SRC) + shaders/gpu_shader_depth_only_frag.glsl + shaders/gpu_shader_uniform_color_frag.glsl + shaders/gpu_shader_checker_frag.glsl + shaders/gpu_shader_diag_stripes_frag.glsl + shaders/gpu_shader_simple_lighting_frag.glsl + shaders/gpu_shader_flat_color_frag.glsl + shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl + shaders/gpu_shader_flat_id_frag.glsl + shaders/gpu_shader_2D_vert.glsl + shaders/gpu_shader_2D_area_borders_vert.glsl + shaders/gpu_shader_2D_area_borders_frag.glsl + shaders/gpu_shader_2D_widget_base_vert.glsl + shaders/gpu_shader_2D_widget_base_frag.glsl + shaders/gpu_shader_2D_widget_shadow_vert.glsl + shaders/gpu_shader_2D_widget_shadow_frag.glsl + shaders/gpu_shader_2D_nodelink_frag.glsl + shaders/gpu_shader_2D_nodelink_vert.glsl + shaders/gpu_shader_2D_flat_color_vert.glsl + shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl + shaders/gpu_shader_2D_line_dashed_frag.glsl + shaders/gpu_shader_2D_smooth_color_vert.glsl + shaders/gpu_shader_2D_smooth_color_frag.glsl + shaders/gpu_shader_2D_image_vert.glsl + shaders/gpu_shader_2D_image_rect_vert.glsl + shaders/gpu_shader_2D_image_multi_rect_vert.glsl + shaders/gpu_shader_image_frag.glsl + shaders/gpu_shader_image_desaturate_frag.glsl + shaders/gpu_shader_image_overlays_merge_frag.glsl + shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl + shaders/gpu_shader_image_modulate_alpha_frag.glsl + shaders/gpu_shader_image_shuffle_color_frag.glsl + shaders/gpu_shader_image_color_frag.glsl + shaders/gpu_shader_image_varying_color_frag.glsl + shaders/gpu_shader_3D_image_vert.glsl + shaders/gpu_shader_3D_vert.glsl + shaders/gpu_shader_3D_normal_vert.glsl + shaders/gpu_shader_3D_flat_color_vert.glsl + shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl + shaders/gpu_shader_3D_polyline_frag.glsl + shaders/gpu_shader_3D_polyline_geom.glsl + shaders/gpu_shader_3D_polyline_vert.glsl + shaders/gpu_shader_3D_smooth_color_vert.glsl + shaders/gpu_shader_3D_smooth_color_frag.glsl + shaders/gpu_shader_3D_passthrough_vert.glsl + shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl -data_to_c_simple(shaders/gpu_shader_point_uniform_color_aa_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_point_varying_color_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl SRC) + shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl -data_to_c_simple(shaders/gpu_shader_text_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_text_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_keyframe_shape_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_keyframe_shape_frag.glsl SRC) + shaders/gpu_shader_point_uniform_color_aa_frag.glsl + shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl + shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl + shaders/gpu_shader_point_varying_color_frag.glsl + shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl + shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl + shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl + shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl + shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl + shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl -data_to_c_simple(shaders/gpu_shader_codegen_lib.glsl SRC) + shaders/gpu_shader_text_vert.glsl + shaders/gpu_shader_text_frag.glsl + shaders/gpu_shader_keyframe_shape_vert.glsl + shaders/gpu_shader_keyframe_shape_frag.glsl -data_to_c_simple(shaders/gpu_shader_geometry.glsl SRC) + shaders/gpu_shader_codegen_lib.glsl -data_to_c_simple(shaders/material/gpu_shader_material_add_shader.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_ambient_occlusion.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_anisotropic.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_attribute.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_background.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_bevel.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_wavelength.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_blackbody.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_bright_contrast.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_bump.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_camera.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_clamp.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_color_ramp.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_color_util.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_combine_hsv.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_combine_rgb.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_combine_xyz.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_diffuse.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_displacement.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_eevee_specular.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_emission.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_float_curve.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_fractal_noise.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_fresnel.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_gamma.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_geometry.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_glass.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_glossy.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_hair_info.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_hash.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_holdout.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_hue_sat_val.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_invert.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_layer_weight.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_light_falloff.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_light_path.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_mapping.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_map_range.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_math.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_math_util.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_mix_rgb.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_mix_shader.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_noise.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_normal.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_normal_map.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_object_info.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_output_aov.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_output_material.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_output_world.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_particle_info.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_principled.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_refraction.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_rgb_curves.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_rgb_to_bw.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_separate_hsv.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_separate_rgb.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_separate_xyz.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_set.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_shader_to_rgba.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_squeeze.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_subsurface_scattering.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_tangent.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_tex_brick.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_tex_checker.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_tex_environment.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_tex_gradient.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_tex_image.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_tex_magic.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_tex_musgrave.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_tex_noise.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_tex_sky.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_texture_coordinates.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_tex_voronoi.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_tex_wave.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_tex_white_noise.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_toon.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_translucent.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_transparent.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_uv_map.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_vector_curves.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_vector_displacement.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_vector_math.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_vector_rotate.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_velvet.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_vertex_color.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_volume_absorption.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_volume_info.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_volume_principled.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_volume_scatter.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_wireframe.glsl SRC) -data_to_c_simple(shaders/material/gpu_shader_material_world_normals.glsl SRC) + shaders/gpu_shader_geometry.glsl -data_to_c_simple(shaders/gpu_shader_gpencil_stroke_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_gpencil_stroke_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_gpencil_stroke_geom.glsl SRC) + shaders/material/gpu_shader_material_add_shader.glsl + shaders/material/gpu_shader_material_ambient_occlusion.glsl + shaders/material/gpu_shader_material_anisotropic.glsl + shaders/material/gpu_shader_material_attribute.glsl + shaders/material/gpu_shader_material_background.glsl + shaders/material/gpu_shader_material_bevel.glsl + shaders/material/gpu_shader_material_wavelength.glsl + shaders/material/gpu_shader_material_blackbody.glsl + shaders/material/gpu_shader_material_bright_contrast.glsl + shaders/material/gpu_shader_material_bump.glsl + shaders/material/gpu_shader_material_camera.glsl + shaders/material/gpu_shader_material_clamp.glsl + shaders/material/gpu_shader_material_color_ramp.glsl + shaders/material/gpu_shader_material_color_util.glsl + shaders/material/gpu_shader_material_combine_hsv.glsl + shaders/material/gpu_shader_material_combine_rgb.glsl + shaders/material/gpu_shader_material_combine_xyz.glsl + shaders/material/gpu_shader_material_diffuse.glsl + shaders/material/gpu_shader_material_displacement.glsl + shaders/material/gpu_shader_material_eevee_specular.glsl + shaders/material/gpu_shader_material_emission.glsl + shaders/material/gpu_shader_material_float_curve.glsl + shaders/material/gpu_shader_material_fractal_noise.glsl + shaders/material/gpu_shader_material_fresnel.glsl + shaders/material/gpu_shader_material_gamma.glsl + shaders/material/gpu_shader_material_geometry.glsl + shaders/material/gpu_shader_material_glass.glsl + shaders/material/gpu_shader_material_glossy.glsl + shaders/material/gpu_shader_material_hair_info.glsl + shaders/material/gpu_shader_material_hash.glsl + shaders/material/gpu_shader_material_holdout.glsl + shaders/material/gpu_shader_material_hue_sat_val.glsl + shaders/material/gpu_shader_material_invert.glsl + shaders/material/gpu_shader_material_layer_weight.glsl + shaders/material/gpu_shader_material_light_falloff.glsl + shaders/material/gpu_shader_material_light_path.glsl + shaders/material/gpu_shader_material_mapping.glsl + shaders/material/gpu_shader_material_map_range.glsl + shaders/material/gpu_shader_material_math.glsl + shaders/material/gpu_shader_material_math_util.glsl + shaders/material/gpu_shader_material_mix_rgb.glsl + shaders/material/gpu_shader_material_mix_shader.glsl + shaders/material/gpu_shader_material_noise.glsl + shaders/material/gpu_shader_material_normal.glsl + shaders/material/gpu_shader_material_normal_map.glsl + shaders/material/gpu_shader_material_object_info.glsl + shaders/material/gpu_shader_material_output_aov.glsl + shaders/material/gpu_shader_material_output_material.glsl + shaders/material/gpu_shader_material_output_world.glsl + shaders/material/gpu_shader_material_particle_info.glsl + shaders/material/gpu_shader_material_principled.glsl + shaders/material/gpu_shader_material_refraction.glsl + shaders/material/gpu_shader_material_rgb_curves.glsl + shaders/material/gpu_shader_material_rgb_to_bw.glsl + shaders/material/gpu_shader_material_separate_hsv.glsl + shaders/material/gpu_shader_material_separate_rgb.glsl + shaders/material/gpu_shader_material_separate_xyz.glsl + shaders/material/gpu_shader_material_set.glsl + shaders/material/gpu_shader_material_shader_to_rgba.glsl + shaders/material/gpu_shader_material_squeeze.glsl + shaders/material/gpu_shader_material_subsurface_scattering.glsl + shaders/material/gpu_shader_material_tangent.glsl + shaders/material/gpu_shader_material_tex_brick.glsl + shaders/material/gpu_shader_material_tex_checker.glsl + shaders/material/gpu_shader_material_tex_environment.glsl + shaders/material/gpu_shader_material_tex_gradient.glsl + shaders/material/gpu_shader_material_tex_image.glsl + shaders/material/gpu_shader_material_tex_magic.glsl + shaders/material/gpu_shader_material_tex_musgrave.glsl + shaders/material/gpu_shader_material_tex_noise.glsl + shaders/material/gpu_shader_material_tex_sky.glsl + shaders/material/gpu_shader_material_texture_coordinates.glsl + shaders/material/gpu_shader_material_tex_voronoi.glsl + shaders/material/gpu_shader_material_tex_wave.glsl + shaders/material/gpu_shader_material_tex_white_noise.glsl + shaders/material/gpu_shader_material_toon.glsl + shaders/material/gpu_shader_material_translucent.glsl + shaders/material/gpu_shader_material_transparent.glsl + shaders/material/gpu_shader_material_uv_map.glsl + shaders/material/gpu_shader_material_vector_curves.glsl + shaders/material/gpu_shader_material_vector_displacement.glsl + shaders/material/gpu_shader_material_vector_math.glsl + shaders/material/gpu_shader_material_vector_rotate.glsl + 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 + shaders/material/gpu_shader_material_world_normals.glsl -data_to_c_simple(shaders/gpu_shader_cfg_world_clip_lib.glsl SRC) -data_to_c_simple(shaders/gpu_shader_colorspace_lib.glsl SRC) + shaders/gpu_shader_gpencil_stroke_vert.glsl + shaders/gpu_shader_gpencil_stroke_frag.glsl + shaders/gpu_shader_gpencil_stroke_geom.glsl -data_to_c_simple(shaders/gpu_shader_common_obinfos_lib.glsl SRC) + shaders/gpu_shader_cfg_world_clip_lib.glsl + shaders/gpu_shader_colorspace_lib.glsl + shaders/gpu_shader_common_obinfos_lib.glsl + + intern/gpu_shader_shared_utils.h +) + +set(GLSL_C) +foreach(GLSL_FILE ${GLSL_SRC}) + data_to_c_simple(${GLSL_FILE} GLSL_C) +endforeach() + +blender_add_lib(bf_gpu_shaders "${GLSL_C}" "" "" "") + +list(APPEND LIB + bf_gpu_shaders +) + +set(GLSL_SOURCE_CONTENT "") +foreach(GLSL_FILE ${GLSL_SRC}) + get_filename_component(GLSL_FILE_NAME ${GLSL_FILE} NAME) + string(REPLACE "." "_" GLSL_FILE_NAME_UNDERSCORES ${GLSL_FILE_NAME}) + string(APPEND GLSL_SOURCE_CONTENT "SHADER_SOURCE\(datatoc_${GLSL_FILE_NAME_UNDERSCORES}, \"${GLSL_FILE_NAME}\"\)\n") +endforeach() + +set(glsl_source_list_file "${CMAKE_CURRENT_BINARY_DIR}/glsl_gpu_source_list.h") +file(GENERATE OUTPUT ${glsl_source_list_file} CONTENT "${GLSL_SOURCE_CONTENT}") +list(APPEND SRC ${glsl_source_list_file}) +list(APPEND INC ${CMAKE_CURRENT_BINARY_DIR}) + +set(SHADER_CREATE_INFOS +#../draw/engines/workbench/shaders/workbench_effect_cavity_info.hh +#../draw/engines/workbench/shaders/workbench_prepass_info.hh +../draw/intern/shaders/draw_fullscreen_info.hh +../draw/intern/shaders/draw_view_info.hh +../draw/intern/shaders/draw_object_infos_info.hh + +shaders/infos/gpu_clip_planes_info.hh +shaders/infos/gpu_srgb_to_framebuffer_space_info.hh +shaders/infos/gpu_shader_3D_image_modulate_alpha_info.hh +shaders/infos/gpu_shader_2D_checker_info.hh +shaders/infos/gpu_shader_2D_diag_stripes_info.hh +shaders/infos/gpu_shader_2D_uniform_color_info.hh +shaders/infos/gpu_shader_2D_flat_color_info.hh +shaders/infos/gpu_shader_2D_smooth_color_info.hh +shaders/infos/gpu_shader_2D_image_overlays_merge_info.hh +shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh +shaders/infos/gpu_shader_2D_image_info.hh +shaders/infos/gpu_shader_2D_image_color_info.hh +shaders/infos/gpu_shader_2D_image_desaturate_color_info.hh +shaders/infos/gpu_shader_2D_image_shuffle_color_info.hh +shaders/infos/gpu_shader_2D_image_rect_color_info.hh +shaders/infos/gpu_shader_text_info.hh +shaders/infos/gpu_shader_keyframe_shape_info.hh +shaders/infos/gpu_shader_3D_flat_color_info.hh +shaders/infos/gpu_shader_3D_uniform_color_info.hh +shaders/infos/gpu_shader_3D_smooth_color_info.hh +shaders/infos/gpu_shader_3D_depth_only_info.hh +shaders/infos/gpu_shader_2D_point_varying_size_varying_color_info.hh +shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_aa_info.hh +shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_outline_aa_info.hh +shaders/infos/gpu_shader_2D_area_borders_info.hh +shaders/infos/gpu_shader_2D_image_multi_rect_color_info.hh +shaders/infos/gpu_shader_instance_varying_color_varying_size_info.hh +shaders/infos/gpu_shader_3D_point_info.hh +shaders/infos/gpu_shader_2D_nodelink_info.hh +shaders/infos/gpu_shader_gpencil_stroke_info.hh +shaders/infos/gpu_shader_simple_lighting_info.hh +) + +set(SHADER_CREATE_INFOS_CONTENT "") +foreach(DESCRIPTOR_FILE ${SHADER_CREATE_INFOS}) +string(APPEND SHADER_CREATE_INFOS_CONTENT "#include \"${DESCRIPTOR_FILE}\"\n") +endforeach() + +set(shader_create_info_list_file "${CMAKE_CURRENT_BINARY_DIR}/gpu_shader_create_info_list.hh") +file(GENERATE OUTPUT ${shader_create_info_list_file} CONTENT "${SHADER_CREATE_INFOS_CONTENT}") if(WITH_MOD_FLUID) add_definitions(-DWITH_FLUID) @@ -378,11 +460,48 @@ if(WITH_IMAGE_DDS) endif() blender_add_lib(bf_gpu "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") +target_link_libraries(bf_gpu PUBLIC + bf_draw_shaders + bf_gpu_shaders +) if(CXX_WARN_NO_SUGGEST_OVERRIDE) target_compile_options(bf_gpu PRIVATE $<$:-Wsuggest-override>) endif() + + +if(WITH_GPU_SHADER_BUILDER) + add_executable(shader_builder + intern/gpu_shader_builder.cc + intern/gpu_shader_builder_stubs.cc + ${shader_create_info_list_file} + ) + + target_link_libraries(shader_builder PUBLIC + bf_blenkernel + ${PLATFORM_LINKLIBS} + ) + target_include_directories(shader_builder PRIVATE ${INC} ${CMAKE_CURRENT_BINARY_DIR}) + + set(BAKED_CREATE_INFOS_FILE ${CMAKE_CURRENT_BINARY_DIR}/shader_baked.hh) + + add_custom_command( + OUTPUT + ${BAKED_CREATE_INFOS_FILE} + COMMAND + "$" ${BAKED_CREATE_INFOS_FILE} + DEPENDS shader_builder + ) + set(GPU_SHADER_INFO_SRC + intern/gpu_shader_info_baked.cc + ${BAKED_CREATE_INFOS_FILE} + ) + + blender_add_lib(bf_gpu_shader_infos "${GPU_SHADER_INFO_SRC}" "" "" "") +endif() + + if(WITH_GTESTS) if(WITH_OPENGL_DRAW_TESTS) set(TEST_SRC diff --git a/source/blender/gpu/GPU_immediate.h b/source/blender/gpu/GPU_immediate.h index a175fc65ba4..1b288d19c4a 100644 --- a/source/blender/gpu/GPU_immediate.h +++ b/source/blender/gpu/GPU_immediate.h @@ -122,6 +122,7 @@ void immUniformMatrix4fv(const char *name, const float data[4][4]); void immBindTexture(const char *name, GPUTexture *tex); void immBindTextureSampler(const char *name, GPUTexture *tex, eGPUSamplerState state); +void immBindUniformBuf(const char *name, GPUUniformBuf *ubo); /* Convenience functions for setting "uniform vec4 color". */ /* The RGB functions have implicit alpha = 1.0. */ diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index f36c8f99064..97b9b26ba2a 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -30,6 +30,8 @@ extern "C" { struct GPUIndexBuf; struct GPUVertBuf; +/** Opaque type hiding #blender::gpu::shader::ShaderCreateInfo */ +typedef struct GPUShaderCreateInfo GPUShaderCreateInfo; /** Opaque type hiding #blender::gpu::Shader */ typedef struct GPUShader GPUShader; @@ -66,6 +68,7 @@ GPUShader *GPU_shader_create_ex(const char *vertcode, const char **tf_names, int tf_count, const char *shname); +GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info); struct GPU_ShaderCreateFromArray_Params { const char **vert, **geom, **frag, **defs; diff --git a/source/blender/gpu/intern/gpu_capabilities_private.hh b/source/blender/gpu/intern/gpu_capabilities_private.hh index 95cf7fd335d..1f94b6715f1 100644 --- a/source/blender/gpu/intern/gpu_capabilities_private.hh +++ b/source/blender/gpu/intern/gpu_capabilities_private.hh @@ -29,10 +29,10 @@ namespace blender::gpu { /** * This includes both hardware capabilities & workarounds. - * Try to limit these to the implementation codebase (i.e.: gpu/opengl/). + * Try to limit these to the implementation code-base (i.e.: `gpu/opengl/`). * Only add workarounds here if they are common to all implementation or * if you need access to it outside of the GPU module. - * Same goes for capabilities (i.e.: texture size) + * Same goes for capabilities (i.e.: texture size). */ struct GPUCapabilities { int max_texture_size = 0; diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc index 7ca93252683..e28776c87b3 100644 --- a/source/blender/gpu/intern/gpu_immediate.cc +++ b/source/blender/gpu/intern/gpu_immediate.cc @@ -629,6 +629,12 @@ void immBindTextureSampler(const char *name, GPUTexture *tex, eGPUSamplerState s GPU_texture_bind_ex(tex, state, binding, true); } +void immBindUniformBuf(const char *name, GPUUniformBuf *ubo) +{ + int binding = GPU_shader_get_uniform_block_binding(imm->shader, name); + GPU_uniformbuf_bind(ubo, binding); +} + /* --- convenience functions for setting "uniform vec4 color" --- */ void immUniformColor4f(float r, float g, float b, float a) diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index 0eb2fe57c28..5815fb10b0c 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -32,6 +32,8 @@ #include "intern/gpu_codegen.h" #include "intern/gpu_material_library.h" #include "intern/gpu_private.h" +#include "intern/gpu_shader_create_info_private.hh" +#include "intern/gpu_shader_dependency_private.h" /** * although the order of initialization and shutdown should not matter @@ -49,6 +51,9 @@ void GPU_init(void) initialized = true; + gpu_shader_dependency_init(); + gpu_shader_create_info_init(); + gpu_codegen_init(); gpu_material_library_init(); @@ -70,6 +75,9 @@ void GPU_exit(void) gpu_material_library_exit(); gpu_codegen_exit(); + gpu_shader_dependency_exit(); + gpu_shader_create_info_exit(); + initialized = false; } diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc index 3f5a639d2a0..3b41e804fd4 100644 --- a/source/blender/gpu/intern/gpu_shader.cc +++ b/source/blender/gpu/intern/gpu_shader.cc @@ -31,10 +31,32 @@ #include "gpu_backend.hh" #include "gpu_context_private.hh" +#include "gpu_shader_create_info.hh" +#include "gpu_shader_create_info_private.hh" +#include "gpu_shader_dependency_private.h" #include "gpu_shader_private.hh" +#include + extern "C" char datatoc_gpu_shader_colorspace_lib_glsl[]; +namespace blender::gpu { + +std::string Shader::defines_declare(const shader::ShaderCreateInfo &info) const +{ + std::string defines; + for (const auto &def : info.defines_) { + defines += "#define "; + defines += def[0]; + defines += " "; + defines += def[1]; + defines += "\n"; + } + return defines; +} + +} // namespace blender::gpu + using namespace blender; using namespace blender::gpu; @@ -59,6 +81,8 @@ static void standard_defines(Vector &sources) BLI_assert(sources.size() == 0); /* Version needs to be first. Exact values will be added by implementation. */ sources.append("version"); + /* Define to identify code usage in shading language. */ + sources.append("#define GPU_SHADER\n"); /* some useful defines to detect GPU type */ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) { sources.append("#define GPU_ATI\n"); @@ -225,6 +249,174 @@ GPUShader *GPU_shader_create_compute(const char *computecode, shname); } +GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info) +{ + using namespace blender::gpu::shader; + const ShaderCreateInfo &info = *reinterpret_cast(_info); + + const_cast(info).finalize(); + + /* At least a vertex shader and a fragment shader are required, or only a compute shader. */ + if (info.compute_source_.is_empty()) { + if (info.vertex_source_.is_empty()) { + printf("Missing vertex shader in %s.\n", info.name_.c_str()); + } + if (info.fragment_source_.is_empty()) { + printf("Missing fragment shader in %s.\n", info.name_.c_str()); + } + BLI_assert(!info.vertex_source_.is_empty() && !info.fragment_source_.is_empty()); + } + else { + if (!info.vertex_source_.is_empty()) { + printf("Compute shader has vertex_source_ shader attached in %s.\n", info.name_.c_str()); + } + if (!info.geometry_source_.is_empty()) { + printf("Compute shader has geometry_source_ shader attached in %s.\n", info.name_.c_str()); + } + if (!info.fragment_source_.is_empty()) { + printf("Compute shader has fragment_source_ shader attached in %s.\n", info.name_.c_str()); + } + BLI_assert(info.vertex_source_.is_empty() && info.geometry_source_.is_empty() && + info.fragment_source_.is_empty()); + } + + Shader *shader = GPUBackend::get()->shader_alloc(info.name_.c_str()); + + std::string defines = shader->defines_declare(info); + std::string resources = shader->resources_declare(info); + char *shader_shared_utils = nullptr; + + defines += "#define USE_GPU_SHADER_CREATE_INFO\n"; + + Vector typedefs; + for (auto filename : info.typedef_sources_) { + typedefs.append(gpu_shader_dependency_get_source(filename.c_str())); + } + if (!typedefs.is_empty()) { + shader_shared_utils = gpu_shader_dependency_get_source("gpu_shader_shared_utils.h"); + } + + if (!info.vertex_source_.is_empty()) { + uint32_t builtins = 0; + std::string interface = shader->vertex_interface_declare(info); + char *code = gpu_shader_dependency_get_resolved_source(info.vertex_source_.c_str(), &builtins); + + Vector sources; + standard_defines(sources); + sources.append("#define GPU_VERTEX_SHADER\n"); + if (!info.geometry_source_.is_empty()) { + sources.append("#define USE_GEOMETRY_SHADER\n"); + } + sources.append(defines.c_str()); + if (!typedefs.is_empty()) { + sources.append(shader_shared_utils); + } + for (auto *types : typedefs) { + sources.append(types); + } + sources.append(resources.c_str()); + sources.append(interface.c_str()); + sources.append(code); + + shader->vertex_shader_from_glsl(sources); + + free(code); + } + + if (!info.fragment_source_.is_empty()) { + uint32_t builtins = 0; + std::string interface = shader->fragment_interface_declare(info); + char *code = gpu_shader_dependency_get_resolved_source(info.fragment_source_.c_str(), + &builtins); + + Vector sources; + standard_defines(sources); + sources.append("#define GPU_FRAGMENT_SHADER\n"); + if (!info.geometry_source_.is_empty()) { + sources.append("#define USE_GEOMETRY_SHADER\n"); + } + sources.append(defines.c_str()); + if (!typedefs.is_empty()) { + sources.append(shader_shared_utils); + } + for (auto *types : typedefs) { + sources.append(types); + } + sources.append(resources.c_str()); + sources.append(interface.c_str()); + sources.append(code); + + shader->fragment_shader_from_glsl(sources); + + free(code); + } + + if (!info.geometry_source_.is_empty()) { + uint32_t builtins = 0; + std::string interface = shader->geometry_interface_declare(info); + std::string layout = shader->geometry_layout_declare(info); + char *code = gpu_shader_dependency_get_resolved_source(info.geometry_source_.c_str(), + &builtins); + + Vector sources; + standard_defines(sources); + sources.append("#define GPU_GEOMETRY_SHADER\n"); + sources.append(defines.c_str()); + if (!typedefs.is_empty()) { + sources.append(shader_shared_utils); + } + for (auto *types : typedefs) { + sources.append(types); + } + sources.append(resources.c_str()); + sources.append(layout.c_str()); + sources.append(interface.c_str()); + sources.append(code); + + shader->geometry_shader_from_glsl(sources); + + free(code); + } + + if (!info.compute_source_.is_empty()) { + uint32_t builtins = 0; + char *code = gpu_shader_dependency_get_resolved_source(info.compute_source_.c_str(), + &builtins); + + Vector sources; + standard_defines(sources); + sources.append("#define GPU_COMPUTE_SHADER\n"); + sources.append(defines.c_str()); + if (!typedefs.is_empty()) { + sources.append(shader_shared_utils); + } + for (auto *types : typedefs) { + sources.append(types); + } + sources.append(resources.c_str()); + sources.append(code); + + shader->compute_shader_from_glsl(sources); + + free(code); + } + + for (auto *types : typedefs) { + free(types); + } + + if (shader_shared_utils) { + free(shader_shared_utils); + } + + if (!shader->finalize(&info)) { + delete shader; + return nullptr; + } + + return wrap(shader); +} + GPUShader *GPU_shader_create_from_python(const char *vertcode, const char *fragcode, const char *geomcode, diff --git a/source/blender/gpu/intern/gpu_shader_builtin.c b/source/blender/gpu/intern/gpu_shader_builtin.c index 24ca691be78..9c8dbf8401f 100644 --- a/source/blender/gpu/intern/gpu_shader_builtin.c +++ b/source/blender/gpu/intern/gpu_shader_builtin.c @@ -41,6 +41,9 @@ #include "GPU_texture.h" #include "GPU_uniform_buffer.h" +/* TODO(jbakker): Need a better way to retrieve create_infos. */ +#include "gpu_shader_create_info_private.hh" + /* Adjust these constants as needed. */ #define MAX_DEFINE_LENGTH 256 #define MAX_EXT_DEFINE_LENGTH 512 @@ -145,137 +148,97 @@ typedef struct { const char *frag; /** Optional. */ const char *defs; + + const char *create_info; + const char *clipped_create_info; } GPUShaderStages; static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { [GPU_SHADER_TEXT] = { .name = "GPU_SHADER_TEXT", - .vert = datatoc_gpu_shader_text_vert_glsl, - .frag = datatoc_gpu_shader_text_frag_glsl, + .create_info = "gpu_shader_text", }, [GPU_SHADER_KEYFRAME_SHAPE] = { .name = "GPU_SHADER_KEYFRAME_SHAPE", - .vert = datatoc_gpu_shader_keyframe_shape_vert_glsl, - .frag = datatoc_gpu_shader_keyframe_shape_frag_glsl, + .create_info = "gpu_shader_keyframe_shape", }, [GPU_SHADER_SIMPLE_LIGHTING] = { .name = "GPU_SHADER_SIMPLE_LIGHTING", - .vert = datatoc_gpu_shader_3D_normal_vert_glsl, - .frag = datatoc_gpu_shader_simple_lighting_frag_glsl, + .create_info = "gpu_shader_simple_lighting", }, [GPU_SHADER_3D_IMAGE_MODULATE_ALPHA] = { - .vert = datatoc_gpu_shader_3D_image_vert_glsl, - .frag = datatoc_gpu_shader_image_modulate_alpha_frag_glsl, + .name = "GPU_SHADER_3D_IMAGE_MODULATE_ALPHA", + .create_info = "gpu_shader_3D_image_modulate_alpha", }, [GPU_SHADER_2D_CHECKER] = { .name = "GPU_SHADER_2D_CHECKER", - .vert = datatoc_gpu_shader_2D_vert_glsl, - .frag = datatoc_gpu_shader_checker_frag_glsl, + .create_info = "gpu_shader_2D_checker", }, [GPU_SHADER_2D_DIAG_STRIPES] = { .name = "GPU_SHADER_2D_DIAG_STRIPES", - .vert = datatoc_gpu_shader_2D_vert_glsl, - .frag = datatoc_gpu_shader_diag_stripes_frag_glsl, + .create_info = "gpu_shader_2D_diag_stripes", }, - [GPU_SHADER_2D_UNIFORM_COLOR] = - { - .name = "GPU_SHADER_2D_UNIFORM_COLOR", - .vert = datatoc_gpu_shader_2D_vert_glsl, - .frag = datatoc_gpu_shader_uniform_color_frag_glsl, - }, - [GPU_SHADER_2D_FLAT_COLOR] = - { - .name = "GPU_SHADER_2D_FLAT_COLOR", - .vert = datatoc_gpu_shader_2D_flat_color_vert_glsl, - .frag = datatoc_gpu_shader_flat_color_frag_glsl, - }, - [GPU_SHADER_2D_SMOOTH_COLOR] = - { - .name = "GPU_SHADER_2D_SMOOTH_COLOR", - .vert = datatoc_gpu_shader_2D_smooth_color_vert_glsl, - .frag = datatoc_gpu_shader_2D_smooth_color_frag_glsl, - }, + [GPU_SHADER_2D_UNIFORM_COLOR] = {.name = "GPU_SHADER_2D_UNIFORM_COLOR", + .create_info = "gpu_shader_2D_uniform_color"}, + [GPU_SHADER_2D_FLAT_COLOR] = {.name = "GPU_SHADER_2D_FLAT_COLOR", + .create_info = "gpu_shader_2D_flat_color"}, + [GPU_SHADER_2D_SMOOTH_COLOR] = {.name = "GPU_SHADER_2D_SMOOTH_COLOR", + .create_info = "gpu_shader_2D_smooth_color"}, [GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE] = { .name = "GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE", +#ifdef __APPLE__ + /* GPUShaderCreateInfo is disabled on MacOS due to mismatch with OCIO shader. See + * T95052 for more details. */ .vert = datatoc_gpu_shader_2D_image_vert_glsl, .frag = datatoc_gpu_shader_image_overlays_merge_frag_glsl, +#else + .create_info = "gpu_shader_2D_image_overlays_merge", +#endif }, [GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE] = - { - .name = "GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE", - .vert = datatoc_gpu_shader_2D_vert_glsl, - .frag = datatoc_gpu_shader_image_overlays_stereo_merge_frag_glsl, - }, - [GPU_SHADER_2D_IMAGE] = - { - .name = "GPU_SHADER_2D_IMAGE", - .vert = datatoc_gpu_shader_2D_image_vert_glsl, - .frag = datatoc_gpu_shader_image_frag_glsl, - }, - [GPU_SHADER_2D_IMAGE_COLOR] = - { - .name = "GPU_SHADER_2D_IMAGE_COLOR", - .vert = datatoc_gpu_shader_2D_image_vert_glsl, - .frag = datatoc_gpu_shader_image_color_frag_glsl, - }, - [GPU_SHADER_2D_IMAGE_DESATURATE_COLOR] = - { - .name = "GPU_SHADER_2D_IMAGE_DESATURATE_COLOR", - .vert = datatoc_gpu_shader_2D_image_vert_glsl, - .frag = datatoc_gpu_shader_image_desaturate_frag_glsl, - }, + {.name = "GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE", + .create_info = "gpu_shader_2D_image_overlays_stereo_merge"}, + [GPU_SHADER_2D_IMAGE] = {.name = "GPU_SHADER_2D_IMAGE", .create_info = "gpu_shader_2D_image"}, + [GPU_SHADER_2D_IMAGE_COLOR] = {.name = "GPU_SHADER_2D_IMAGE_COLOR", + .create_info = "gpu_shader_2D_image_color"}, + [GPU_SHADER_2D_IMAGE_DESATURATE_COLOR] = {.name = "GPU_SHADER_2D_IMAGE_DESATURATE_COLOR", + .create_info = + "gpu_shader_2D_image_desaturate_color"}, [GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR] = { .name = "GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR", - .vert = datatoc_gpu_shader_2D_image_vert_glsl, - .frag = datatoc_gpu_shader_image_shuffle_color_frag_glsl, - }, - [GPU_SHADER_2D_IMAGE_RECT_COLOR] = - { - .name = "GPU_SHADER_2D_IMAGE_RECT_COLOR", - .vert = datatoc_gpu_shader_2D_image_rect_vert_glsl, - .frag = datatoc_gpu_shader_image_color_frag_glsl, - }, - [GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR] = - { - .name = "GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR", - .vert = datatoc_gpu_shader_2D_image_multi_rect_vert_glsl, - .frag = datatoc_gpu_shader_image_varying_color_frag_glsl, + .create_info = "gpu_shader_2D_image_shuffle_color", }, + [GPU_SHADER_2D_IMAGE_RECT_COLOR] = {.name = "GPU_SHADER_2D_IMAGE_RECT_COLOR", + .create_info = "gpu_shader_2D_image_rect_color"}, + [GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR] = {.name = "GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR", + .create_info = + "gpu_shader_2D_image_multi_rect_color"}, [GPU_SHADER_3D_UNIFORM_COLOR] = { .name = "GPU_SHADER_3D_UNIFORM_COLOR", - .vert = datatoc_gpu_shader_3D_vert_glsl, - .frag = datatoc_gpu_shader_uniform_color_frag_glsl, - }, - [GPU_SHADER_3D_FLAT_COLOR] = - { - .name = "GPU_SHADER_3D_FLAT_COLOR", - .vert = datatoc_gpu_shader_3D_flat_color_vert_glsl, - .frag = datatoc_gpu_shader_flat_color_frag_glsl, - }, - [GPU_SHADER_3D_SMOOTH_COLOR] = - { - .name = "GPU_SHADER_3D_SMOOTH_COLOR", - .vert = datatoc_gpu_shader_3D_smooth_color_vert_glsl, - .frag = datatoc_gpu_shader_3D_smooth_color_frag_glsl, - }, - [GPU_SHADER_3D_DEPTH_ONLY] = - { - .name = "GPU_SHADER_3D_DEPTH_ONLY", - .vert = datatoc_gpu_shader_3D_vert_glsl, - .frag = datatoc_gpu_shader_depth_only_frag_glsl, + .create_info = "gpu_shader_3D_uniform_color", + .clipped_create_info = "gpu_shader_3D_uniform_color_clipped", }, + [GPU_SHADER_3D_FLAT_COLOR] = {.name = "GPU_SHADER_3D_FLAT_COLOR", + .create_info = "gpu_shader_3D_flat_color", + .clipped_create_info = "gpu_shader_3D_flat_color_clipped"}, + [GPU_SHADER_3D_SMOOTH_COLOR] = {.name = "GPU_SHADER_3D_SMOOTH_COLOR", + .create_info = "gpu_shader_3D_smooth_color", + .clipped_create_info = "gpu_shader_3D_smooth_color_clipped"}, + [GPU_SHADER_3D_DEPTH_ONLY] = {.name = "GPU_SHADER_3D_DEPTH_ONLY", + .create_info = "gpu_shader_3D_depth_only", + .clipped_create_info = "gpu_shader_3D_depth_only_clipped"}, [GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR] = { .name = "GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR", @@ -333,33 +296,23 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { [GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA] = { .name = "GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA", - .vert = datatoc_gpu_shader_2D_point_uniform_size_aa_vert_glsl, - .frag = datatoc_gpu_shader_point_uniform_color_aa_frag_glsl, + .create_info = "gpu_shader_2D_point_uniform_size_uniform_color_aa", }, [GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA] = { .name = "GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA", - .vert = datatoc_gpu_shader_2D_point_uniform_size_outline_aa_vert_glsl, - .frag = datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl, + .create_info = "gpu_shader_2D_point_uniform_size_uniform_color_outline_aa", }, [GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR] = - { - .name = "GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR", - .vert = datatoc_gpu_shader_3D_point_fixed_size_varying_color_vert_glsl, - .frag = datatoc_gpu_shader_point_varying_color_frag_glsl, - }, + {.name = "GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR", + .create_info = "gpu_shader_3D_point_fixed_size_varying_color"}, [GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR] = - { - .name = "GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR", - .vert = datatoc_gpu_shader_3D_point_varying_size_varying_color_vert_glsl, - .frag = datatoc_gpu_shader_point_varying_color_frag_glsl, - }, + {.name = "GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR", + .create_info = "gpu_shader_3D_point_varying_size_varying_color"}, [GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA] = - { - .name = "GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA", - .vert = datatoc_gpu_shader_3D_point_uniform_size_aa_vert_glsl, - .frag = datatoc_gpu_shader_point_uniform_color_aa_frag_glsl, - }, + {.name = "GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA", + .create_info = "gpu_shader_3D_point_uniform_size_uniform_color_aa", + .clipped_create_info = "gpu_shader_3D_point_uniform_size_uniform_color_aa_clipped"}, [GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE] = { @@ -369,12 +322,8 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { .defs = "#define UNIFORM_SCALE\n", }, - [GPU_SHADER_2D_AREA_BORDERS] = - { - .name = "GPU_SHADER_2D_AREA_BORDERS", - .vert = datatoc_gpu_shader_2D_area_borders_vert_glsl, - .frag = datatoc_gpu_shader_2D_area_borders_frag_glsl, - }, + [GPU_SHADER_2D_AREA_BORDERS] = {.name = "GPU_SHADER_2D_AREA_BORDERS", + .create_info = "gpu_shader_2D_area_borders"}, [GPU_SHADER_2D_WIDGET_BASE] = { .name = "GPU_SHADER_2D_WIDGET_BASE", @@ -394,27 +343,14 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { .vert = datatoc_gpu_shader_2D_widget_shadow_vert_glsl, .frag = datatoc_gpu_shader_2D_widget_shadow_frag_glsl, }, - [GPU_SHADER_2D_NODELINK] = - { - .name = "GPU_SHADER_2D_NODELINK", - .vert = datatoc_gpu_shader_2D_nodelink_vert_glsl, - .frag = datatoc_gpu_shader_2D_nodelink_frag_glsl, - }, - [GPU_SHADER_2D_NODELINK_INST] = - { - .name = "GPU_SHADER_2D_NODELINK_INST", - .vert = datatoc_gpu_shader_2D_nodelink_vert_glsl, - .frag = datatoc_gpu_shader_2D_nodelink_frag_glsl, - .defs = "#define USE_INSTANCE\n", - }, + [GPU_SHADER_2D_NODELINK] = {.name = "GPU_SHADER_2D_NODELINK", + .create_info = "gpu_shader_2D_nodelink"}, - [GPU_SHADER_GPENCIL_STROKE] = - { - .name = "GPU_SHADER_GPENCIL_STROKE", - .vert = datatoc_gpu_shader_gpencil_stroke_vert_glsl, - .geom = datatoc_gpu_shader_gpencil_stroke_geom_glsl, - .frag = datatoc_gpu_shader_gpencil_stroke_frag_glsl, - }, + [GPU_SHADER_2D_NODELINK_INST] = {.name = "GPU_SHADER_2D_NODELINK_INST", + .create_info = "gpu_shader_2D_nodelink_inst"}, + + [GPU_SHADER_GPENCIL_STROKE] = {.name = "GPU_SHADER_GPENCIL_STROKE", + .create_info = "gpu_shader_gpencil_stroke"}, }; GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader, @@ -429,14 +365,20 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader, /* common case */ if (sh_cfg == GPU_SHADER_CFG_DEFAULT) { - *sh_p = GPU_shader_create_from_arrays_named( - stages->name, - { - .vert = (const char *[]){stages->vert, NULL}, - .geom = (const char *[]){stages->geom, NULL}, - .frag = (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL}, - .defs = (const char *[]){stages->defs, NULL}, - }); + if (stages->create_info != NULL) { + *sh_p = GPU_shader_create_from_info(gpu_shader_create_info_get(stages->create_info)); + } + else { + *sh_p = GPU_shader_create_from_arrays_named( + stages->name, + { + .vert = (const char *[]){stages->vert, NULL}, + .geom = (const char *[]){stages->geom, NULL}, + .frag = + (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL}, + .defs = (const char *[]){stages->defs, NULL}, + }); + } } else if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { /* Remove eventually, for now ensure support for each shader has been added. */ @@ -448,17 +390,24 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader, GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA, GPU_SHADER_3D_FLAT_COLOR, GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR)); - const char *world_clip_lib = datatoc_gpu_shader_cfg_world_clip_lib_glsl; - const char *world_clip_def = "#define USE_WORLD_CLIP_PLANES\n"; /* In rare cases geometry shaders calculate clipping themselves. */ - *sh_p = GPU_shader_create_from_arrays_named( - stages->name, - { - .vert = (const char *[]){world_clip_lib, stages->vert, NULL}, - .geom = (const char *[]){stages->geom ? world_clip_lib : NULL, stages->geom, NULL}, - .frag = (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL}, - .defs = (const char *[]){world_clip_def, stages->defs, NULL}, - }); + if (stages->clipped_create_info != NULL) { + *sh_p = GPU_shader_create_from_info( + gpu_shader_create_info_get(stages->clipped_create_info)); + } + else { + const char *world_clip_lib = datatoc_gpu_shader_cfg_world_clip_lib_glsl; + const char *world_clip_def = "#define USE_WORLD_CLIP_PLANES\n"; + *sh_p = GPU_shader_create_from_arrays_named( + stages->name, + { + .vert = (const char *[]){world_clip_lib, stages->vert, NULL}, + .geom = (const char *[]){stages->geom ? world_clip_lib : NULL, stages->geom, NULL}, + .frag = + (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL}, + .defs = (const char *[]){world_clip_def, stages->defs, NULL}, + }); + } } else { BLI_assert(0); diff --git a/source/blender/gpu/intern/gpu_shader_interface.hh b/source/blender/gpu/intern/gpu_shader_interface.hh index 4bd8f245e2b..735b8fea71d 100644 --- a/source/blender/gpu/intern/gpu_shader_interface.hh +++ b/source/blender/gpu/intern/gpu_shader_interface.hh @@ -34,6 +34,7 @@ #include "BLI_utildefines.h" #include "GPU_shader.h" +#include "gpu_shader_create_info.hh" namespace blender::gpu { @@ -50,6 +51,7 @@ typedef struct ShaderInput { * Base class which is then specialized for each implementation (GL, VK, ...). */ class ShaderInterface { + friend shader::ShaderCreateInfo; /* TODO(fclem): should be protected. */ public: /** Flat array. In this order: Attributes, Ubos, Uniforms. */ @@ -72,6 +74,7 @@ class ShaderInterface { public: ShaderInterface(); + ShaderInterface(const shader::ShaderCreateInfo &info); virtual ~ShaderInterface(); void debug_print(); @@ -129,6 +132,10 @@ class ShaderInterface { static inline const char *builtin_uniform_block_name(GPUUniformBlockBuiltin u); inline uint32_t set_input_name(ShaderInput *input, char *name, uint32_t name_len) const; + inline void copy_input_name(ShaderInput *input, + const StringRefNull &name, + char *name_buffer, + uint32_t &name_buffer_offset) const; /** * Finalize interface construction by sorting the #ShaderInputs for faster lookups. @@ -216,8 +223,12 @@ inline uint32_t ShaderInterface::set_input_name(ShaderInput *input, { /* remove "[0]" from array name */ if (name[name_len - 1] == ']') { - name[name_len - 3] = '\0'; - name_len -= 3; + for (; name_len > 1; name_len--) { + if (name[name_len] == '[') { + name[name_len] = '\0'; + break; + } + } } input->name_offset = (uint32_t)(name - name_buffer_); @@ -225,6 +236,17 @@ inline uint32_t ShaderInterface::set_input_name(ShaderInput *input, return name_len + 1; /* include NULL terminator */ } +inline void ShaderInterface::copy_input_name(ShaderInput *input, + const StringRefNull &name, + char *name_buffer, + uint32_t &name_buffer_offset) const +{ + uint32_t name_len = name.size(); + /* Copy include NULL terminator. */ + memcpy(name_buffer + name_buffer_offset, name.c_str(), name_len + 1); + name_buffer_offset += set_input_name(input, name_buffer + name_buffer_offset, name_len); +} + inline const ShaderInput *ShaderInterface::input_lookup(const ShaderInput *const inputs, const uint inputs_len, const char *name) const diff --git a/source/blender/gpu/intern/gpu_shader_private.hh b/source/blender/gpu/intern/gpu_shader_private.hh index 498dd8f3877..7837af0dcf2 100644 --- a/source/blender/gpu/intern/gpu_shader_private.hh +++ b/source/blender/gpu/intern/gpu_shader_private.hh @@ -24,9 +24,12 @@ #include "BLI_string_ref.hh" #include "GPU_shader.h" +#include "gpu_shader_create_info.hh" #include "gpu_shader_interface.hh" #include "gpu_vertex_buffer_private.hh" +#include + namespace blender { namespace gpu { @@ -53,7 +56,7 @@ class Shader { virtual void geometry_shader_from_glsl(MutableSpan sources) = 0; virtual void fragment_shader_from_glsl(MutableSpan sources) = 0; virtual void compute_shader_from_glsl(MutableSpan sources) = 0; - virtual bool finalize() = 0; + virtual bool finalize(const shader::ShaderCreateInfo *info = nullptr) = 0; virtual void transform_feedback_names_set(Span name_list, eGPUShaderTFBType geom_type) = 0; @@ -68,6 +71,13 @@ class Shader { virtual void vertformat_from_shader(GPUVertFormat *) const = 0; + std::string defines_declare(const shader::ShaderCreateInfo &info) const; + virtual std::string resources_declare(const shader::ShaderCreateInfo &info) const = 0; + virtual std::string vertex_interface_declare(const shader::ShaderCreateInfo &info) const = 0; + virtual std::string fragment_interface_declare(const shader::ShaderCreateInfo &info) const = 0; + virtual std::string geometry_interface_declare(const shader::ShaderCreateInfo &info) const = 0; + virtual std::string geometry_layout_declare(const shader::ShaderCreateInfo &info) const = 0; + /* DEPRECATED: Kept only because of BGL API. */ virtual int program_handle_get() const = 0; diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index 7bb88894b81..1a445ebd7eb 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -246,6 +246,7 @@ static void detect_workarounds() GLContext::debug_layer_support = false; GLContext::direct_state_access_support = false; GLContext::fixed_restart_index_support = false; + GLContext::geometry_shader_invocations = false; GLContext::multi_bind_support = false; GLContext::multi_draw_indirect_support = false; GLContext::shader_draw_parameters_support = false; @@ -434,6 +435,8 @@ bool GLContext::clear_texture_support = false; bool GLContext::copy_image_support = false; bool GLContext::debug_layer_support = false; bool GLContext::direct_state_access_support = false; +bool GLContext::explicit_location_support = false; +bool GLContext::geometry_shader_invocations = false; bool GLContext::fixed_restart_index_support = false; bool GLContext::multi_bind_support = false; bool GLContext::multi_draw_indirect_support = false; @@ -492,6 +495,8 @@ void GLBackend::capabilities_init() GLContext::copy_image_support = GLEW_ARB_copy_image; GLContext::debug_layer_support = GLEW_VERSION_4_3 || GLEW_KHR_debug || GLEW_ARB_debug_output; GLContext::direct_state_access_support = GLEW_ARB_direct_state_access; + GLContext::explicit_location_support = GLEW_VERSION_4_3; + GLContext::geometry_shader_invocations = GLEW_ARB_gpu_shader5; GLContext::fixed_restart_index_support = GLEW_ARB_ES3_compatibility; GLContext::multi_bind_support = GLEW_ARB_multi_bind; GLContext::multi_draw_indirect_support = GLEW_ARB_multi_draw_indirect; diff --git a/source/blender/gpu/opengl/gl_context.hh b/source/blender/gpu/opengl/gl_context.hh index 656f4a1caf2..dd22418972b 100644 --- a/source/blender/gpu/opengl/gl_context.hh +++ b/source/blender/gpu/opengl/gl_context.hh @@ -69,6 +69,8 @@ class GLContext : public Context { static bool copy_image_support; static bool debug_layer_support; static bool direct_state_access_support; + static bool explicit_location_support; + static bool geometry_shader_invocations; static bool fixed_restart_index_support; static bool multi_bind_support; static bool multi_draw_indirect_support; diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index d0da4504b40..3fd271592b2 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -46,6 +46,7 @@ using namespace blender; using namespace blender::gpu; +using namespace blender::gpu::shader; /* -------------------------------------------------------------------- */ /** \name Creation / Destruction @@ -78,6 +79,444 @@ GLShader::~GLShader() /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Create Info + * \{ */ + +static const char *to_string(const Interpolation &interp) +{ + switch (interp) { + case Interpolation::SMOOTH: + return "smooth"; + case Interpolation::FLAT: + return "flat"; + case Interpolation::NO_PERSPECTIVE: + return "noperspective"; + default: + return "unkown"; + } +} + +static const char *to_string(const Type &type) +{ + switch (type) { + case Type::FLOAT: + return "float"; + case Type::VEC2: + return "vec2"; + case Type::VEC3: + return "vec3"; + case Type::VEC4: + return "vec4"; + case Type::MAT3: + return "mat3"; + case Type::MAT4: + return "mat4"; + case Type::UINT: + return "uint"; + case Type::UVEC2: + return "uvec2"; + case Type::UVEC3: + return "uvec3"; + case Type::UVEC4: + return "uvec4"; + case Type::INT: + return "int"; + case Type::IVEC2: + return "ivec2"; + case Type::IVEC3: + return "ivec3"; + case Type::IVEC4: + return "ivec4"; + case Type::BOOL: + return "bool"; + default: + return "unkown"; + } +} + +static const char *to_string(const PrimitiveIn &layout) +{ + switch (layout) { + case PrimitiveIn::POINTS: + return "points"; + case PrimitiveIn::LINES: + return "lines"; + case PrimitiveIn::LINES_ADJACENCY: + return "lines_adjacency"; + case PrimitiveIn::TRIANGLES: + return "triangles"; + case PrimitiveIn::TRIANGLES_ADJACENCY: + return "triangles_adjacency"; + default: + return "unknown"; + } +} + +static const char *to_string(const PrimitiveOut &layout) +{ + switch (layout) { + case PrimitiveOut::POINTS: + return "points"; + case PrimitiveOut::LINE_STRIP: + return "line_strip"; + case PrimitiveOut::TRIANGLE_STRIP: + return "triangle_strip"; + default: + return "unknown"; + } +} + +static void print_image_type(std::ostream &os, + const ImageType &type, + const ShaderCreateInfo::Resource::BindType bind_type) +{ + switch (type) { + case ImageType::INT_BUFFER: + case ImageType::INT_1D: + case ImageType::INT_1D_ARRAY: + case ImageType::INT_2D: + case ImageType::INT_2D_ARRAY: + case ImageType::INT_3D: + case ImageType::INT_CUBE: + case ImageType::INT_CUBE_ARRAY: + os << "i"; + break; + case ImageType::UINT_BUFFER: + case ImageType::UINT_1D: + case ImageType::UINT_1D_ARRAY: + case ImageType::UINT_2D: + case ImageType::UINT_2D_ARRAY: + case ImageType::UINT_3D: + case ImageType::UINT_CUBE: + case ImageType::UINT_CUBE_ARRAY: + os << "u"; + break; + default: + break; + } + + if (bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) { + os << "image"; + } + else { + os << "sampler"; + } + + switch (type) { + case ImageType::FLOAT_BUFFER: + case ImageType::INT_BUFFER: + case ImageType::UINT_BUFFER: + os << "Buffer"; + break; + case ImageType::FLOAT_1D: + case ImageType::FLOAT_1D_ARRAY: + case ImageType::INT_1D: + case ImageType::INT_1D_ARRAY: + case ImageType::UINT_1D: + case ImageType::UINT_1D_ARRAY: + os << "1D"; + break; + case ImageType::FLOAT_2D: + case ImageType::FLOAT_2D_ARRAY: + case ImageType::INT_2D: + case ImageType::INT_2D_ARRAY: + case ImageType::UINT_2D: + case ImageType::UINT_2D_ARRAY: + case ImageType::SHADOW_2D: + case ImageType::SHADOW_2D_ARRAY: + os << "2D"; + break; + case ImageType::FLOAT_3D: + case ImageType::INT_3D: + case ImageType::UINT_3D: + os << "3D"; + break; + case ImageType::FLOAT_CUBE: + case ImageType::FLOAT_CUBE_ARRAY: + case ImageType::INT_CUBE: + case ImageType::INT_CUBE_ARRAY: + case ImageType::UINT_CUBE: + case ImageType::UINT_CUBE_ARRAY: + case ImageType::SHADOW_CUBE: + case ImageType::SHADOW_CUBE_ARRAY: + os << "Cube"; + break; + default: + break; + } + + switch (type) { + case ImageType::FLOAT_1D_ARRAY: + case ImageType::FLOAT_2D_ARRAY: + case ImageType::FLOAT_CUBE_ARRAY: + case ImageType::INT_1D_ARRAY: + case ImageType::INT_2D_ARRAY: + case ImageType::INT_CUBE_ARRAY: + case ImageType::UINT_1D_ARRAY: + case ImageType::UINT_2D_ARRAY: + case ImageType::UINT_CUBE_ARRAY: + case ImageType::SHADOW_2D_ARRAY: + case ImageType::SHADOW_CUBE_ARRAY: + os << "Array"; + break; + default: + break; + } + + switch (type) { + case ImageType::SHADOW_2D: + case ImageType::SHADOW_2D_ARRAY: + case ImageType::SHADOW_CUBE: + case ImageType::SHADOW_CUBE_ARRAY: + os << "Shadow"; + break; + default: + break; + } + os << " "; +} + +static std::ostream &print_qualifier(std::ostream &os, const Qualifier &qualifiers) +{ + if ((qualifiers & Qualifier::RESTRICT) != Qualifier::RESTRICT) { + os << "restrict"; + } + if ((qualifiers & Qualifier::READ_ONLY) != Qualifier::READ_ONLY) { + os << "readonly"; + } + if ((qualifiers & Qualifier::WRITE_ONLY) != Qualifier::WRITE_ONLY) { + os << "writeonly"; + } + return os << " "; +} + +static void print_resource(std::ostream &os, const ShaderCreateInfo::Resource &res) +{ + if (GLContext::explicit_location_support) { + os << "layout(binding = " << res.slot; + if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) { + os << ", " << res.image.format; + } + else if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) { + os << ", std140"; + } + else if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) { + os << ", std430"; + } + os << ") "; + } + else if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) { + os << "layout(std140) "; + } + + int64_t array_offset; + StringRef name_no_array; + + switch (res.bind_type) { + case ShaderCreateInfo::Resource::BindType::SAMPLER: + os << "uniform "; + print_image_type(os, res.sampler.type, res.bind_type); + os << res.sampler.name << ";\n"; + break; + case ShaderCreateInfo::Resource::BindType::IMAGE: + os << "uniform "; + print_qualifier(os, res.image.qualifiers); + print_image_type(os, res.image.type, res.bind_type); + os << res.image.name << ";\n"; + break; + case ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER: + array_offset = res.uniformbuf.name.find_first_of("["); + name_no_array = (array_offset == -1) ? res.uniformbuf.name : + StringRef(res.uniformbuf.name.c_str(), array_offset); + os << "uniform " << name_no_array << " { " << res.uniformbuf.type_name << " _" + << res.uniformbuf.name << "; };\n"; + break; + case ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER: + array_offset = res.storagebuf.name.find_first_of("["); + name_no_array = (array_offset == -1) ? res.storagebuf.name : + StringRef(res.storagebuf.name.c_str(), array_offset); + os << "buffer "; + print_qualifier(os, res.storagebuf.qualifiers); + os << name_no_array << " { " << res.storagebuf.type_name << " _" << res.storagebuf.name + << "; };\n"; + break; + } +} + +static void print_resource_alias(std::ostream &os, const ShaderCreateInfo::Resource &res) +{ + int64_t array_offset; + StringRef name_no_array; + + switch (res.bind_type) { + case ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER: + array_offset = res.uniformbuf.name.find_first_of("["); + name_no_array = (array_offset == -1) ? res.uniformbuf.name : + StringRef(res.uniformbuf.name.c_str(), array_offset); + os << "#define " << name_no_array << " (_" << name_no_array << ")\n"; + break; + case ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER: + array_offset = res.storagebuf.name.find_first_of("["); + name_no_array = (array_offset == -1) ? res.storagebuf.name : + StringRef(res.storagebuf.name.c_str(), array_offset); + os << "#define " << name_no_array << " (_" << name_no_array << ")\n"; + break; + default: + break; + } +} + +static void print_interface(std::ostream &os, + const StringRefNull &prefix, + const StageInterfaceInfo &iface, + const StringRefNull &suffix = "") +{ + /* TODO(fclem) Move that to interface check. */ + // if (iface.instance_name.is_empty()) { + // BLI_assert_msg(0, "Interfaces require an instance name for geometry shader."); + // std::cout << iface.name << ": Interfaces require an instance name for geometry shader.\n"; + // continue; + // } + os << prefix << " " << iface.name << "{" << std::endl; + for (const StageInterfaceInfo::InOut &inout : iface.inouts) { + os << " " << to_string(inout.interp) << " " << to_string(inout.type) << " " << inout.name + << ";\n"; + } + os << "}"; + os << (iface.instance_name.is_empty() ? "" : "\n") << iface.instance_name << suffix << ";\n"; +} + +std::string GLShader::resources_declare(const ShaderCreateInfo &info) const +{ + std::stringstream ss; + + /* NOTE: We define macros in GLSL to trigger compilation error if the resource names + * are reused for local variables. This is to match other backend behavior which needs accessors + * macros. */ + + ss << "\n/* Pass Resources. */\n"; + for (const ShaderCreateInfo::Resource &res : info.pass_resources_) { + print_resource(ss, res); + } + for (const ShaderCreateInfo::Resource &res : info.pass_resources_) { + print_resource_alias(ss, res); + } + ss << "\n/* Batch Resources. */\n"; + for (const ShaderCreateInfo::Resource &res : info.batch_resources_) { + print_resource(ss, res); + } + for (const ShaderCreateInfo::Resource &res : info.batch_resources_) { + print_resource_alias(ss, res); + } + ss << "\n/* Push Constants. */\n"; + for (const ShaderCreateInfo::PushConst &uniform : info.push_constants_) { + if (GLContext::explicit_location_support) { + ss << "layout(location = " << uniform.index << ") "; + } + ss << "uniform " << to_string(uniform.type) << " " << uniform.name; + if (uniform.array_size > 0) { + ss << "[" << uniform.array_size << "]"; + } + ss << ";\n"; + } + for (const ShaderCreateInfo::PushConst &uniform : info.push_constants_) { + ss << "#define " << uniform.name << " (" << uniform.name << ")\n"; + } + ss << "\n"; + return ss.str(); +} + +std::string GLShader::vertex_interface_declare(const ShaderCreateInfo &info) const +{ + std::stringstream ss; + + ss << "\n/* Inputs. */\n"; + for (const ShaderCreateInfo::VertIn &attr : info.vertex_inputs_) { + if (GLContext::explicit_location_support) { + ss << "layout(location = " << attr.index << ") "; + } + ss << "in " << to_string(attr.type) << " " << attr.name << ";\n"; + } + ss << "\n/* Interfaces. */\n"; + for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) { + print_interface(ss, "out", *iface); + } + ss << "\n"; + return ss.str(); +} + +std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) const +{ + std::stringstream ss; + ss << "\n/* Interfaces. */\n"; + const Vector &in_interfaces = (info.geometry_source_.is_empty()) ? + info.vertex_out_interfaces_ : + info.geometry_out_interfaces_; + for (const StageInterfaceInfo *iface : in_interfaces) { + print_interface(ss, "in", *iface); + } + ss << "\n/* Outputs. */\n"; + for (const ShaderCreateInfo::FragOut &output : info.fragment_outputs_) { + ss << "layout(location = " << output.index; + switch (output.blend) { + case DualBlend::SRC_0: + ss << ", index = 0"; + break; + case DualBlend::SRC_1: + ss << ", index = 1"; + break; + default: + break; + } + ss << ") "; + ss << "out " << to_string(output.type) << " " << output.name << ";\n"; + } + ss << "\n"; + return ss.str(); +} + +std::string GLShader::geometry_layout_declare(const ShaderCreateInfo &info) const +{ + int max_verts = info.geometry_layout_.max_vertices; + int invocations = info.geometry_layout_.invocations; + + if (GLContext::geometry_shader_invocations == false && invocations != -1) { + max_verts *= invocations; + invocations = -1; + } + + std::stringstream ss; + ss << "\n/* Geometry Layout. */\n"; + ss << "layout(" << to_string(info.geometry_layout_.primitive_in); + if (invocations != -1) { + ss << ", invocations = " << invocations; + } + ss << ") in;\n"; + + ss << "layout(" << to_string(info.geometry_layout_.primitive_out) + << ", max_vertices = " << max_verts << ") out;\n"; + ss << "\n"; + return ss.str(); +} + +std::string GLShader::geometry_interface_declare(const ShaderCreateInfo &info) const +{ + std::stringstream ss; + ss << "\n/* Interfaces. */\n"; + for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) { + print_interface(ss, "in", *iface, "[]"); + } + ss << "\n"; + for (const StageInterfaceInfo *iface : info.geometry_out_interfaces_) { + print_interface(ss, "out", *iface); + } + ss << "\n"; + return ss.str(); +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Shader stage creation * \{ */ @@ -92,7 +531,12 @@ static char *glsl_patch_default_get() size_t slen = 0; /* Version need to go first. */ - STR_CONCAT(patch, slen, "#version 330\n"); + if (GLEW_VERSION_4_3) { + STR_CONCAT(patch, slen, "#version 430\n"); + } + else { + STR_CONCAT(patch, slen, "#version 330\n"); + } /* Enable extensions for features that are not part of our base GLSL version * don't use an extension for something already available! */ @@ -108,6 +552,10 @@ static char *glsl_patch_default_get() STR_CONCAT(patch, slen, "#extension GL_ARB_shader_draw_parameters : enable\n"); STR_CONCAT(patch, slen, "#define GPU_ARB_shader_draw_parameters\n"); } + if (GLContext::geometry_shader_invocations) { + STR_CONCAT(patch, slen, "#extension GL_ARB_gpu_shader5 : enable\n"); + STR_CONCAT(patch, slen, "#define GPU_ARB_gpu_shader5\n"); + } if (GLContext::texture_cube_map_array_support) { STR_CONCAT(patch, slen, "#extension GL_ARB_texture_cube_map_array : enable\n"); STR_CONCAT(patch, slen, "#define GPU_ARB_texture_cube_map_array\n"); @@ -214,7 +662,7 @@ void GLShader::compute_shader_from_glsl(MutableSpan sources) compute_shader_ = this->create_shader_stage(GL_COMPUTE_SHADER, sources); } -ATTR_NO_ASAN bool GLShader::finalize() +ATTR_NO_ASAN bool GLShader::finalize(const shader::ShaderCreateInfo *info) { if (compilation_failed_) { return false; @@ -233,7 +681,12 @@ ATTR_NO_ASAN bool GLShader::finalize() return false; } - interface = new GLShaderInterface(shader_program_); + if (info != nullptr) { + interface = new GLShaderInterface(shader_program_, *info); + } + else { + interface = new GLShaderInterface(shader_program_); + } return true; } diff --git a/source/blender/gpu/opengl/gl_shader.hh b/source/blender/gpu/opengl/gl_shader.hh index 9ea1334b862..af92c77db54 100644 --- a/source/blender/gpu/opengl/gl_shader.hh +++ b/source/blender/gpu/opengl/gl_shader.hh @@ -27,6 +27,7 @@ #include "glew-mx.h" +#include "gpu_shader_create_info.hh" #include "gpu_shader_private.hh" namespace blender { @@ -36,6 +37,9 @@ namespace gpu { * Implementation of shader compilation and uniforms handling using OpenGL. */ class GLShader : public Shader { + friend shader::ShaderCreateInfo; + friend shader::StageInterfaceInfo; + private: /** Handle for full program (links shader stages below). */ GLuint shader_program_ = 0; @@ -58,7 +62,13 @@ class GLShader : public Shader { void geometry_shader_from_glsl(MutableSpan sources) override; void fragment_shader_from_glsl(MutableSpan sources) override; void compute_shader_from_glsl(MutableSpan sources) override; - bool finalize() override; + bool finalize(const shader::ShaderCreateInfo *info = nullptr) override; + + std::string resources_declare(const shader::ShaderCreateInfo &info) const override; + std::string vertex_interface_declare(const shader::ShaderCreateInfo &info) const override; + std::string fragment_interface_declare(const shader::ShaderCreateInfo &info) const override; + std::string geometry_interface_declare(const shader::ShaderCreateInfo &info) const override; + std::string geometry_layout_declare(const shader::ShaderCreateInfo &info) const override; /** Should be called before linking. */ void transform_feedback_names_set(Span name_list, diff --git a/source/blender/gpu/opengl/gl_shader_interface.cc b/source/blender/gpu/opengl/gl_shader_interface.cc index 9900a4e0766..2211c2fbb7c 100644 --- a/source/blender/gpu/opengl/gl_shader_interface.cc +++ b/source/blender/gpu/opengl/gl_shader_interface.cc @@ -25,7 +25,9 @@ #include "BLI_bitmap.h" +#include "gl_backend.hh" #include "gl_batch.hh" +#include "gl_context.hh" #include "gl_shader_interface.hh" @@ -323,6 +325,137 @@ GLShaderInterface::GLShaderInterface(GLuint program) this->sort_inputs(); } +GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateInfo &info) +{ + using namespace blender::gpu::shader; + + attr_len_ = info.vertex_inputs_.size(); + uniform_len_ = info.push_constants_.size(); + ubo_len_ = 0; + ssbo_len_ = 0; + + Vector all_resources; + all_resources.extend(info.pass_resources_); + all_resources.extend(info.batch_resources_); + + for (ShaderCreateInfo::Resource &res : all_resources) { + switch (res.bind_type) { + case ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER: + ubo_len_++; + break; + case ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER: + ssbo_len_++; + break; + case ShaderCreateInfo::Resource::BindType::SAMPLER: + uniform_len_++; + break; + case ShaderCreateInfo::Resource::BindType::IMAGE: + uniform_len_++; + break; + } + } + + BLI_assert_msg(ubo_len_ <= 16, "enabled_ubo_mask_ is uint16_t"); + + int input_tot_len = attr_len_ + ubo_len_ + uniform_len_ + ssbo_len_; + inputs_ = (ShaderInput *)MEM_callocN(sizeof(ShaderInput) * input_tot_len, __func__); + ShaderInput *input = inputs_; + + name_buffer_ = (char *)MEM_mallocN(info.interface_names_size_, "name_buffer"); + uint32_t name_buffer_offset = 0; + + /* Attributes */ + for (const ShaderCreateInfo::VertIn &attr : info.vertex_inputs_) { + copy_input_name(input, attr.name, name_buffer_, name_buffer_offset); + if (true || !GLContext::explicit_location_support) { + input->location = input->binding = glGetAttribLocation(program, attr.name.c_str()); + } + else { + input->location = input->binding = attr.index; + } + enabled_attr_mask_ |= (1 << input->location); + input++; + } + + /* Uniform Blocks */ + for (const ShaderCreateInfo::Resource &res : all_resources) { + if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) { + copy_input_name(input, res.uniformbuf.name, name_buffer_, name_buffer_offset); + if (true || !GLContext::explicit_location_support) { + input->location = glGetUniformBlockIndex(program, res.uniformbuf.name.c_str()); + glUniformBlockBinding(program, input->location, res.slot); + } + input->binding = res.slot; + enabled_ubo_mask_ |= (1 << input->binding); + input++; + } + } + + /* Uniforms & samplers & images */ + for (const ShaderCreateInfo::Resource &res : all_resources) { + if (res.bind_type == ShaderCreateInfo::Resource::BindType::SAMPLER) { + copy_input_name(input, res.sampler.name, name_buffer_, name_buffer_offset); + /* Until we make use of explicit uniform location or eliminate all + * sampler manually changing. */ + if (true || !GLContext::explicit_location_support) { + input->location = glGetUniformLocation(program, res.sampler.name.c_str()); + glUniform1i(input->location, res.slot); + } + input->binding = res.slot; + enabled_tex_mask_ |= (1ull << input->binding); + input++; + } + else if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) { + copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset); + /* Until we make use of explicit uniform location. */ + if (true || !GLContext::explicit_location_support) { + input->location = glGetUniformLocation(program, res.image.name.c_str()); + glUniform1i(input->location, res.slot); + } + input->binding = res.slot; + enabled_ima_mask_ |= (1 << input->binding); + input++; + } + } + for (const ShaderCreateInfo::PushConst &uni : info.push_constants_) { + copy_input_name(input, uni.name, name_buffer_, name_buffer_offset); + /* Until we make use of explicit uniform location. */ + if (true || !GLContext::explicit_location_support) { + input->location = glGetUniformLocation(program, uni.name.c_str()); + } + input->binding = -1; + input++; + } + + /* SSBOs */ + for (const ShaderCreateInfo::Resource &res : all_resources) { + if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) { + copy_input_name(input, res.storagebuf.name, name_buffer_, name_buffer_offset); + input->location = input->binding = res.slot; + enabled_ubo_mask_ |= (1 << input->binding); + input++; + } + } + + /* Builtin Uniforms */ + for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORMS; u_int++) { + GPUUniformBuiltin u = static_cast(u_int); + const ShaderInput *uni = this->uniform_get(builtin_uniform_name(u)); + builtins_[u] = (uni != nullptr) ? uni->location : -1; + } + + /* Builtin Uniforms Blocks */ + for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORM_BLOCKS; u_int++) { + GPUUniformBlockBuiltin u = static_cast(u_int); + const ShaderInput *block = this->ubo_get(builtin_uniform_block_name(u)); + builtin_blocks_[u] = (block != nullptr) ? block->binding : -1; + } + + this->sort_inputs(); + + // this->debug_print(); +} + GLShaderInterface::~GLShaderInterface() { for (auto *ref : refs_) { diff --git a/source/blender/gpu/opengl/gl_shader_interface.hh b/source/blender/gpu/opengl/gl_shader_interface.hh index 89a5b631047..94b6dd58316 100644 --- a/source/blender/gpu/opengl/gl_shader_interface.hh +++ b/source/blender/gpu/opengl/gl_shader_interface.hh @@ -34,6 +34,7 @@ #include "glew-mx.h" +#include "gpu_shader_create_info.hh" #include "gpu_shader_interface.hh" namespace blender::gpu { @@ -49,6 +50,7 @@ class GLShaderInterface : public ShaderInterface { Vector refs_; public: + GLShaderInterface(GLuint program, const shader::ShaderCreateInfo &info); GLShaderInterface(GLuint program); ~GLShaderInterface(); diff --git a/source/blender/gpu/shaders/gpu_shader_2D_area_borders_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_area_borders_frag.glsl index 5a36b414229..4ebcb9c397f 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_area_borders_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_area_borders_frag.glsl @@ -1,10 +1,11 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform vec4 color; uniform float scale; in vec2 uv; out vec4 fragColor; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl index d20ddcd27c0..c6f01d68eee 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl @@ -1,4 +1,4 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; uniform vec4 rect; @@ -8,6 +8,7 @@ uniform float scale; in vec2 pos; out vec2 uv; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl index df2507c0dc9..494ef8d888e 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl @@ -1,10 +1,11 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; in vec2 pos; in vec4 color; flat out vec4 finalColor; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl index bdc0d37a7ae..9851e08fe2e 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl @@ -4,7 +4,8 @@ */ /* Same as ICON_DRAW_CACHE_SIZE */ -#define MAX_CALLS 16 +#ifndef USE_GPU_SHADER_CREATE_INFO +# define MAX_CALLS 16 uniform vec4 calls_data[MAX_CALLS * 3]; @@ -12,12 +13,13 @@ out vec2 texCoord_interp; flat out vec4 finalColor; in vec2 pos; +#endif void main() { - vec4 rect = calls_data[gl_InstanceID * 3]; - vec4 tex = calls_data[gl_InstanceID * 3 + 1]; - finalColor = calls_data[gl_InstanceID * 3 + 2]; + vec4 rect = multi_rect_data.calls_data[gl_InstanceID * 3]; + vec4 tex = multi_rect_data.calls_data[gl_InstanceID * 3 + 1]; + finalColor = multi_rect_data.calls_data[gl_InstanceID * 3 + 2]; /* Use pos to select the right swizzle (instead of gl_VertexID) * in order to workaround an OSX driver bug. */ diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl index ab9c30505c2..d9a5aeeef46 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl @@ -3,11 +3,13 @@ * does not need any vertex input (producing less call to immBegin/End) */ +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; uniform vec4 rect_icon; uniform vec4 rect_geom; out vec2 texCoord_interp; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl index cdb066c9c52..0b5e3759dfb 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl @@ -1,10 +1,11 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; /* Keep in sync with intern/opencolorio/gpu_shader_display_transform_vertex.glsl */ in vec2 texCoord; in vec2 pos; out vec2 texCoord_interp; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl index 43f259671fa..af9a24d1280 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl @@ -6,6 +6,8 @@ * Dashed is performed in screen space. */ +#ifndef USE_GPU_SHADER_CREATE_INFO + uniform float dash_width; /* Simple mode, discarding non-dash parts (so no need for blending at all). */ @@ -23,6 +25,7 @@ noperspective in vec2 stipple_pos; flat in vec2 stipple_start; out vec4 fragColor; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl index 15362d020e4..9d52820188b 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl @@ -5,7 +5,7 @@ * * Dashed is performed in screen space. */ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; uniform vec4 color; @@ -18,6 +18,7 @@ flat out vec4 color_vert; /* We leverage hardware interpolation to compute distance along the line. */ noperspective out vec2 stipple_pos; /* In screen space */ flat out vec2 stipple_start; /* In screen space */ +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl index 134a7d00127..c4d56579b18 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl @@ -1,4 +1,4 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO in float colorGradient; in vec4 finalColor; in float lineU; @@ -8,6 +8,7 @@ flat in float dashAlpha; flat in int isMainLine; out vec4 fragColor; +#endif #define DASH_WIDTH 10.0 #define ANTIALIAS 1.0 diff --git a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl index 8325568988c..b83ea59a692 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl @@ -4,13 +4,15 @@ #define MID_VERTEX 65 +#ifndef USE_GPU_SHADER_CREATE_INFO + /* u is position along the curve, defining the tangent space. * v is "signed" distance (compressed to [0..1] range) from the pos in expand direction */ in vec2 uv; in vec2 pos; /* verts position in the curve tangent space */ in vec2 expand; -#ifdef USE_INSTANCE +# ifdef USE_INSTANCE /* Instance attrs. */ in vec2 P0; in vec2 P1; @@ -27,21 +29,10 @@ in float dash_alpha; uniform vec4 colors[6]; -# define colStart (colid_doarrow[0] < 3 ? start_color : colors[colid_doarrow[0]]) -# define colEnd (colid_doarrow[1] < 3 ? end_color : colors[colid_doarrow[1]]) -# define colShadow colors[colid_doarrow[2]] -# define doArrow (colid_doarrow[3] != 0) -# define doMuted (domuted[0] != 0) - -#else +# else /* Single curve drawcall, use uniform. */ uniform vec2 bezierPts[4]; -# define P0 bezierPts[0] -# define P1 bezierPts[1] -# define P2 bezierPts[2] -# define P3 bezierPts[3] - uniform vec4 colors[3]; uniform bool doArrow; uniform bool doMuted; @@ -50,11 +41,7 @@ uniform float thickness; uniform float dash_factor; uniform float dash_alpha; -# define colShadow colors[0] -# define colStart colors[1] -# define colEnd colors[2] - -#endif +# endif uniform float expandSize; uniform float arrowSize; @@ -67,6 +54,33 @@ flat out float lineLength; flat out float dashFactor; flat out float dashAlpha; flat out int isMainLine; +#endif + +#ifdef USE_INSTANCE +# define colStart (colid_doarrow[0] < 3 ? start_color : node_link_data.colors[colid_doarrow[0]]) +# define colEnd (colid_doarrow[1] < 3 ? end_color : node_link_data.colors[colid_doarrow[1]]) +# define colShadow node_link_data.colors[colid_doarrow[2]] +# define doArrow (colid_doarrow[3] != 0) +# define doMuted (domuted[0] != 0) + +#else +# define P0 node_link_data.bezierPts[0].xy +# define P1 node_link_data.bezierPts[1].xy +# define P2 node_link_data.bezierPts[2].xy +# define P3 node_link_data.bezierPts[3].xy +# define cols node_link_data.colors +# define doArrow node_link_data.doArrow +# define doMuted node_link_data.doMuted +# define dim_factor node_link_data.dim_factor +# define thickness node_link_data.thickness +# define dash_factor node_link_data.dash_factor +# define dash_alpha node_link_data.dash_alpha + +# define colShadow node_link_data.colors[0] +# define colStart node_link_data.colors[1] +# define colEnd node_link_data.colors[2] + +#endif /* Define where along the noodle the gradient will starts and ends. * Use 0.25 instead of 0.35-0.65, because of a visual shift issue. */ @@ -101,7 +115,7 @@ void main(void) vec2 normal = tangent.yx * vec2(-1.0, 1.0); /* Position vertex on the curve tangent space */ - point += (pos.x * tangent + pos.y * normal) * arrowSize; + point += (pos.x * tangent + pos.y * normal) * node_link_data.arrowSize; gl_Position = ModelViewProjectionMatrix * vec4(point, 0.0, 1.0); @@ -139,7 +153,7 @@ void main(void) finalColor[3] *= dim_factor; /* Expand into a line */ - gl_Position.xy += exp_axis * expandSize * expand_dist * thickness; + gl_Position.xy += exp_axis * node_link_data.expandSize * expand_dist * thickness; /* If the link is not muted or is not a reroute arrow the points are squashed to the center of * the line. Magic numbers are defined in drawnode.c */ diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl index 1453393aa9f..f2b6aa1f12c 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl @@ -1,9 +1,11 @@ +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; uniform float size; in vec2 pos; out vec2 radii; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl index 5c555b2d3e7..5d97fca1116 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl @@ -1,10 +1,11 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; uniform float size; uniform float outlineWidth; in vec2 pos; out vec4 radii; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl index 469370b9173..6ba6f980406 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl @@ -1,10 +1,11 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; in vec2 pos; in float size; in vec4 color; out vec4 finalColor; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl index 1333c00682c..4d887a37807 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl @@ -1,6 +1,7 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO noperspective in vec4 finalColor; out vec4 fragColor; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl index fcf436d50af..5d19aea9168 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl @@ -1,10 +1,11 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; in vec2 pos; in vec4 color; noperspective out vec4 finalColor; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl index de6547715f3..698f20ae1f9 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl @@ -1,11 +1,13 @@ +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; -#ifdef UV_POS +# ifdef UV_POS in vec2 u; -# define pos u -#else +# define pos u +# else in vec2 pos; +# endif #endif void main() diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl index 6dd0201535d..a03b88db342 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl @@ -1,3 +1,4 @@ +#ifndef USE_GPU_SHADER_CREATE_INFO uniform vec3 checkerColorAndSize; noperspective in vec2 uvInterp; @@ -12,6 +13,7 @@ flat in vec4 embossColor; flat in float lineWidth; out vec4 fragColor; +#endif vec3 compute_masks(vec2 uv) { diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl index b5036b51d9d..80b93baf20a 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl @@ -1,12 +1,13 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; -#define MAX_PARAM 12 -#ifdef USE_INSTANCE -# define MAX_INSTANCE 6 +# define MAX_PARAM 12 +# ifdef USE_INSTANCE +# define MAX_INSTANCE 6 uniform vec4 parameters[MAX_PARAM * MAX_INSTANCE]; -#else +# else uniform vec4 parameters[MAX_PARAM]; +# endif #endif /* gl_InstanceID is supposed to be 0 if not drawing instances, but this seems @@ -41,6 +42,7 @@ uniform vec4 parameters[MAX_PARAM]; #define doAlphaCheck (alphaDiscard < 0.0) #define discardFactor abs(alphaDiscard) +#ifndef USE_GPU_SHADER_CREATE_INFO noperspective out vec2 uvInterp; flat out vec2 outRectSize; flat out vec4 outRoundCorners; @@ -51,8 +53,9 @@ flat out float lineWidth; noperspective out float butCo; flat out float discardFac; -#ifdef OS_MAC +# ifdef OS_MAC in float dummy; +# endif #endif vec2 do_widget(void) diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl index e8a6a43191e..a624d3f2f8b 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl @@ -1,9 +1,11 @@ +#ifndef USE_GPU_SHADER_CREATE_INFO in float shadowFalloff; out vec4 fragColor; uniform float alpha; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl index dc2849c8aa9..d3eed997292 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl @@ -51,9 +51,12 @@ const vec2 cornervec[36] = vec2[36](vec2(0.0, 1.0), #define INNER_FLAG uint(1 << 10) /* is inner vert */ +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; uniform vec4 parameters[4]; +#endif + /* radi and rad per corner */ #define recti parameters[0] #define rect parameters[1] @@ -61,9 +64,11 @@ uniform vec4 parameters[4]; #define rads parameters[2].y #define roundCorners parameters[3] +#ifndef USE_GPU_SHADER_CREATE_INFO in uint vflag; out float shadowFalloff; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl index 16424ece2b6..1a87796f7c4 100644 --- a/source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl @@ -1,9 +1,10 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; uniform mat4 ModelMatrix; uniform vec4 ClipPlane; in vec3 pos; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl index 91f986d23ad..b6132113bc9 100644 --- a/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl @@ -1,13 +1,16 @@ +#pragma BLENDER_REQUIRE(gpu_shader_cfg_world_clip_lib.glsl) +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; -#ifdef USE_WORLD_CLIP_PLANES +# ifdef USE_WORLD_CLIP_PLANES uniform mat4 ModelMatrix; -#endif +# endif in vec3 pos; in vec4 color; flat out vec4 finalColor; +#endif void main() { @@ -16,6 +19,6 @@ void main() finalColor = color; #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * pos_4d).xyz); + world_clip_planes_calc_clip_distance((clipPlanes.ModelMatrix * pos_4d).xyz); #endif } diff --git a/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl index 0fb8d06e317..908d442739a 100644 --- a/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl @@ -1,9 +1,11 @@ +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; in vec2 texCoord; in vec3 pos; out vec2 texCoord_interp; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl index aefa47275f5..9328e0a13e9 100644 --- a/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl @@ -6,11 +6,13 @@ * Dashed is performed in screen space. */ +#ifndef USE_GPU_SHADER_CREATE_INFO + uniform mat4 ModelViewProjectionMatrix; -#ifdef USE_WORLD_CLIP_PLANES +# ifdef USE_WORLD_CLIP_PLANES uniform mat4 ModelMatrix; -#endif +# endif uniform vec4 color; uniform vec2 viewport_size; @@ -22,6 +24,7 @@ flat out vec4 color_vert; /* We leverage hardware interpolation to compute distance along the line. */ noperspective out vec2 stipple_pos; /* In screen space */ flat out vec2 stipple_start; /* In screen space */ +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl index 252fee87015..18fed69eff6 100644 --- a/source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl @@ -1,10 +1,11 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; uniform mat3 NormalMatrix; in vec3 pos; in vec3 nor; out vec3 normal; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl index 12594b04da9..52e9e71fdd8 100644 --- a/source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl @@ -1,9 +1,11 @@ -#ifdef USE_WORLD_CLIP_PLANES +#ifndef USE_GPU_SHADER_CREATE_INFO +# ifdef USE_WORLD_CLIP_PLANES uniform mat4 ModelMatrix; -#endif +# endif /* Does Nothing */ in vec3 pos; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl index 776656fc2df..504b3f75373 100644 --- a/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl @@ -1,9 +1,10 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; in vec3 pos; in vec4 color; out vec4 finalColor; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl index 5d67658c639..7f143ccc28d 100644 --- a/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl @@ -1,12 +1,15 @@ +#pragma BLENDER_REQUIRE(gpu_shader_cfg_world_clip_lib.glsl) +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; -#ifdef USE_WORLD_CLIP_PLANES +# ifdef USE_WORLD_CLIP_PLANES uniform mat4 ModelMatrix; -#endif +# endif uniform float size; in vec3 pos; out vec2 radii; +#endif void main() { @@ -25,6 +28,6 @@ void main() radii /= size; #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * pos_4d).xyz); + world_clip_planes_calc_clip_distance((clipPlanes.ModelMatrix * pos_4d).xyz); #endif } diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl index 3bc72535266..f048e143da7 100644 --- a/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl @@ -1,10 +1,11 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; in vec3 pos; in float size; in vec4 color; out vec4 finalColor; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl b/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl index 3ea8f7dbfbe..8687763f4c1 100644 --- a/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl @@ -1,14 +1,15 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform float lineWidth; uniform bool lineSmooth = true; in vec4 finalColor; noperspective in float smoothline; -#ifdef CLIP +# ifdef CLIP in float clip; -#endif +# endif out vec4 fragColor; +#endif #define SMOOTH_WIDTH 1.0 diff --git a/source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl b/source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl index 70026398937..627e91af4d6 100644 --- a/source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl +++ b/source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl @@ -1,4 +1,4 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO layout(lines) in; layout(triangle_strip, max_vertices = 4) out; @@ -7,17 +7,18 @@ uniform vec2 viewportSize; uniform float lineWidth; uniform bool lineSmooth = true; -#if !defined(UNIFORM) +# if !defined(UNIFORM) in vec4 finalColor_g[]; -#endif +# endif -#ifdef CLIP +# ifdef CLIP in float clip_g[]; out float clip; -#endif +# endif out vec4 finalColor; noperspective out float smoothline; +#endif #define SMOOTH_WIDTH 1.0 diff --git a/source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl index 28aa2a4ccc6..5c673494870 100644 --- a/source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl @@ -1,18 +1,19 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; uniform mat4 ModelMatrix; uniform vec4 ClipPlane; in vec3 pos; -#if !defined(UNIFORM) +# if !defined(UNIFORM) in vec4 color; out vec4 finalColor_g; -#endif +# endif -#ifdef CLIP +# ifdef CLIP out float clip_g; +# endif #endif void main() diff --git a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl index 3a2d96c9929..de555cc5706 100644 --- a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl @@ -1,6 +1,7 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO in vec4 finalColor; out vec4 fragColor; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl index 4eafb7b7be3..56a1210c957 100644 --- a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl @@ -1,14 +1,17 @@ +#pragma BLENDER_REQUIRE(gpu_shader_cfg_world_clip_lib.glsl) +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; -#ifdef USE_WORLD_CLIP_PLANES +# ifdef USE_WORLD_CLIP_PLANES uniform mat4 ModelMatrix; -#endif +# endif in vec3 pos; in vec4 color; out vec4 finalColor; +#endif void main() { @@ -16,6 +19,6 @@ void main() finalColor = color; #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz); + world_clip_planes_calc_clip_distance((clipPlanes.ModelMatrix * vec4(pos, 1.0)).xyz); #endif } diff --git a/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl index 70bb881ffea..1d7b7df49a8 100644 --- a/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl @@ -1,17 +1,20 @@ +#pragma BLENDER_REQUIRE(gpu_shader_cfg_world_clip_lib.glsl) +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; -#ifdef USE_WORLD_CLIP_PLANES +# ifdef USE_WORLD_CLIP_PLANES uniform mat4 ModelMatrix; -#endif +# endif in vec3 pos; +#endif void main() { gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz); + world_clip_planes_calc_clip_distance((clipPlanes.ModelMatrix * vec4(pos, 1.0)).xyz); #endif } diff --git a/source/blender/gpu/shaders/gpu_shader_cfg_world_clip_lib.glsl b/source/blender/gpu/shaders/gpu_shader_cfg_world_clip_lib.glsl index 46cf2fe09a2..cdc716db7a4 100644 --- a/source/blender/gpu/shaders/gpu_shader_cfg_world_clip_lib.glsl +++ b/source/blender/gpu/shaders/gpu_shader_cfg_world_clip_lib.glsl @@ -1,7 +1,9 @@ #ifdef USE_WORLD_CLIP_PLANES # if defined(GPU_VERTEX_SHADER) || defined(GPU_GEOMETRY_SHADER) +# ifndef USE_GPU_SHADER_CREATE_INFO uniform vec4 WorldClipPlanes[6]; +# endif # define _world_clip_planes_calc_clip_distance(wpos, _clipplanes) \ { \ @@ -14,6 +16,10 @@ uniform vec4 WorldClipPlanes[6]; gl_ClipDistance[5] = dot(_clipplanes[5], pos); \ } +/* When all shaders are builtin shaders are migrated this could be applied directly. */ +# ifdef USE_GPU_SHADER_CREATE_INFO +# define WorldClipPlanes clipPlanes.world +# endif /* HACK Dirty hack to be able to override the definition in common_view_lib.glsl. * Not doing this would require changing the include order in every shaders. */ # define world_clip_planes_calc_clip_distance(wpos) \ diff --git a/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl b/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl index 156b6cb75ab..9065da0275a 100644 --- a/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl @@ -1,9 +1,10 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform vec4 color1; uniform vec4 color2; uniform int size; out vec4 fragColor; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl b/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl index aae659516bb..74341701fb0 100644 --- a/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl +++ b/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl @@ -2,7 +2,9 @@ /* Undefine the macro that avoids compilation errors. */ #undef blender_srgb_to_framebuffer_space +#ifndef USE_GPU_SHADER_CREATE_INFO uniform bool srgbTarget = false; +#endif vec4 blender_srgb_to_framebuffer_space(vec4 color) { diff --git a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl index 9e1527a9e7f..f5b6de4899f 100644 --- a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl +++ b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl @@ -9,11 +9,14 @@ struct ObjectInfos { vec4 drw_Infos; }; +# ifndef USE_GPU_SHADER_CREATE_INFO layout(std140) uniform infoBlock { /* DRW_RESOURCE_CHUNK_LEN = 512 */ ObjectInfos drw_infos[512]; }; +# endif + # 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/gpu/shaders/gpu_shader_diag_stripes_frag.glsl b/source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl index 48979af4ad0..a4a24ed8e46 100644 --- a/source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl @@ -1,10 +1,11 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform vec4 color1; uniform vec4 color2; uniform int size1; uniform int size2; out vec4 fragColor; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl index 6f7d68856d5..d3d4b66589b 100644 --- a/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl @@ -1,6 +1,7 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO flat in vec4 finalColor; out vec4 fragColor; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl index 99d8b6ab685..1675de3d567 100644 --- a/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl @@ -1,6 +1,7 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO flat in vec4 finalColor; out vec4 fragColor; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl index 8e1287c483a..2aabdb84f16 100644 --- a/source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl @@ -1,6 +1,7 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO flat in uint finalId; out uint fragId; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_geometry.glsl b/source/blender/gpu/shaders/gpu_shader_geometry.glsl index 3b4e2e17ccc..4fdc14289e1 100644 --- a/source/blender/gpu/shaders/gpu_shader_geometry.glsl +++ b/source/blender/gpu/shaders/gpu_shader_geometry.glsl @@ -1,4 +1,4 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ProjectionMatrix; uniform int PrimitiveIdBase; @@ -19,6 +19,7 @@ out vec3 varposition; uniform bool osd_flat_shading; uniform int osd_fvar_count; +#endif #define INTERP_FACE_VARYING_2(result, fvarOffset, tessCoord) \ { \ @@ -38,8 +39,10 @@ uniform int osd_fvar_count; result = vec3(tmp, 0); \ } +#ifndef USE_GPU_SHADER_CREATE_INFO uniform samplerBuffer FVarDataBuffer; uniform isamplerBuffer FVarDataOffsetBuffer; +#endif out block { diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl index fc3f47c0aaa..37541bb91f3 100644 --- a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl @@ -1,16 +1,18 @@ +#ifndef USE_GPU_SHADER_CREATE_INFO in vec4 mColor; in vec2 mTexCoord; out vec4 fragColor; +#endif void main() { const vec2 center = vec2(0, 0.5); - vec4 tColor = vec4(mColor); + vec4 tColor = vec4(geometry_out.mColor); /* if alpha < 0, then encap */ - if (mColor.a < 0) { + if (geometry_out.mColor.a < 0) { tColor.a = tColor.a * -1.0; - float dist = length(mTexCoord - center); + float dist = length(geometry_out.mTexCoord - center); if (dist > 0.25) { discard; } diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl index b937323f62a..f076655b459 100644 --- a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl +++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl @@ -1,3 +1,4 @@ +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; uniform vec2 Viewport; uniform int xraymode; @@ -13,6 +14,7 @@ in float finalThickness[4]; out vec4 mColor; out vec2 mTexCoord; +#endif #define GP_XRAY_FRONT 0 #define GP_XRAY_3DSPACE 1 @@ -23,19 +25,19 @@ out vec2 mTexCoord; /* project 3d point to 2d on screen space */ vec2 toScreenSpace(vec4 vertex) { - return vec2(vertex.xy / vertex.w) * Viewport; + return vec2(vertex.xy / vertex.w) * gpencil_stroke_data.viewport; } /* get zdepth value */ float getZdepth(vec4 point) { - if (xraymode == GP_XRAY_FRONT) { + if (gpencil_stroke_data.xraymode == GP_XRAY_FRONT) { return 0.0; } - if (xraymode == GP_XRAY_3DSPACE) { + if (gpencil_stroke_data.xraymode == GP_XRAY_3DSPACE) { return (point.z / point.w); } - if (xraymode == GP_XRAY_BACK) { + if (gpencil_stroke_data.xraymode == GP_XRAY_BACK) { return 1.0; } @@ -75,7 +77,7 @@ void main(void) vec2 sp3 = toScreenSpace(P3); /* end of next segment */ /* culling outside viewport */ - vec2 area = Viewport * 4.0; + vec2 area = gpencil_stroke_data.viewport * 4.0; if (sp1.x < -area.x || sp1.x > area.x) { return; } @@ -112,8 +114,8 @@ void main(void) if (bn1 == 0) { bn1 = 1; } - float length_a = finalThickness[1] / an1; - float length_b = finalThickness[2] / bn1; + float length_a = geometry_in[1].finalThickness / an1; + float length_b = geometry_in[2].finalThickness / bn1; if (length_a <= 0.0) { length_a = 0.01; } @@ -124,41 +126,49 @@ void main(void) /* prevent excessively long miters at sharp corners */ if (dot(v0, v1) < -MiterLimit) { miter_a = n1; - length_a = finalThickness[1]; + length_a = geometry_in[1].finalThickness; /* close the gap */ if (dot(v0, n1) > 0) { - mTexCoord = vec2(0, 0); - mColor = finalColor[1]; - gl_Position = vec4((sp1 + finalThickness[1] * n0) / Viewport, getZdepth(P1), 1.0); + geometry_out.mTexCoord = vec2(0, 0); + geometry_out.mColor = geometry_in[1].finalColor; + gl_Position = vec4((sp1 + geometry_in[1].finalThickness * n0) / gpencil_stroke_data.viewport, + getZdepth(P1), + 1.0); EmitVertex(); - mTexCoord = vec2(0, 0); - mColor = finalColor[1]; - gl_Position = vec4((sp1 + finalThickness[1] * n1) / Viewport, getZdepth(P1), 1.0); + geometry_out.mTexCoord = vec2(0, 0); + geometry_out.mColor = geometry_in[1].finalColor; + gl_Position = vec4((sp1 + geometry_in[1].finalThickness * n1) / gpencil_stroke_data.viewport, + getZdepth(P1), + 1.0); EmitVertex(); - mTexCoord = vec2(0, 0.5); - mColor = finalColor[1]; - gl_Position = vec4(sp1 / Viewport, getZdepth(P1), 1.0); + geometry_out.mTexCoord = vec2(0, 0.5); + geometry_out.mColor = geometry_in[1].finalColor; + gl_Position = vec4(sp1 / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); EmitVertex(); EndPrimitive(); } else { - mTexCoord = vec2(0, 1); - mColor = finalColor[1]; - gl_Position = vec4((sp1 - finalThickness[1] * n1) / Viewport, getZdepth(P1), 1.0); + geometry_out.mTexCoord = vec2(0, 1); + geometry_out.mColor = geometry_in[1].finalColor; + gl_Position = vec4((sp1 - geometry_in[1].finalThickness * n1) / gpencil_stroke_data.viewport, + getZdepth(P1), + 1.0); EmitVertex(); - mTexCoord = vec2(0, 1); - mColor = finalColor[1]; - gl_Position = vec4((sp1 - finalThickness[1] * n0) / Viewport, getZdepth(P1), 1.0); + geometry_out.mTexCoord = vec2(0, 1); + geometry_out.mColor = geometry_in[1].finalColor; + gl_Position = vec4((sp1 - geometry_in[1].finalThickness * n0) / gpencil_stroke_data.viewport, + getZdepth(P1), + 1.0); EmitVertex(); - mTexCoord = vec2(0, 0.5); - mColor = finalColor[1]; - gl_Position = vec4(sp1 / Viewport, getZdepth(P1), 1.0); + geometry_out.mTexCoord = vec2(0, 0.5); + geometry_out.mColor = geometry_in[1].finalColor; + gl_Position = vec4(sp1 / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); EmitVertex(); EndPrimitive(); @@ -167,66 +177,74 @@ void main(void) if (dot(v1, v2) < -MiterLimit) { miter_b = n1; - length_b = finalThickness[2]; + length_b = geometry_in[2].finalThickness; } /* Generate the start end-cap (alpha < 0 used as end-cap flag). */ - float extend = (fill_stroke > 0) ? 2 : 1; - if ((caps_start != GPENCIL_FLATCAP) && is_equal(P0, P2)) { - mTexCoord = vec2(1, 0.5); - mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0); + float extend = gpencil_stroke_data.fill_stroke ? 2 : 1; + if ((gpencil_stroke_data.caps_start != GPENCIL_FLATCAP) && is_equal(P0, P2)) { + geometry_out.mTexCoord = vec2(1, 0.5); + geometry_out.mColor = vec4(geometry_in[1].finalColor.rgb, geometry_in[1].finalColor.a * -1.0); vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0 * extend; - gl_Position = vec4((sp1 + svn1) / Viewport, getZdepth(P1), 1.0); + gl_Position = vec4((sp1 + svn1) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); EmitVertex(); - mTexCoord = vec2(0, 0); - mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0); - gl_Position = vec4((sp1 - (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0); + geometry_out.mTexCoord = vec2(0, 0); + geometry_out.mColor = vec4(geometry_in[1].finalColor.rgb, geometry_in[1].finalColor.a * -1.0); + gl_Position = vec4( + (sp1 - (length_a * 2.0) * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); EmitVertex(); - mTexCoord = vec2(0, 1); - mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0); - gl_Position = vec4((sp1 + (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0); + geometry_out.mTexCoord = vec2(0, 1); + geometry_out.mColor = vec4(geometry_in[1].finalColor.rgb, geometry_in[1].finalColor.a * -1.0); + gl_Position = vec4( + (sp1 + (length_a * 2.0) * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); EmitVertex(); } /* generate the triangle strip */ - mTexCoord = vec2(0, 0); - mColor = finalColor[1]; - gl_Position = vec4((sp1 + length_a * miter_a) / Viewport, getZdepth(P1), 1.0); + geometry_out.mTexCoord = vec2(0, 0); + geometry_out.mColor = geometry_in[1].finalColor; + gl_Position = vec4( + (sp1 + length_a * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); EmitVertex(); - mTexCoord = vec2(0, 1); - mColor = finalColor[1]; - gl_Position = vec4((sp1 - length_a * miter_a) / Viewport, getZdepth(P1), 1.0); + geometry_out.mTexCoord = vec2(0, 1); + geometry_out.mColor = geometry_in[1].finalColor; + gl_Position = vec4( + (sp1 - length_a * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); EmitVertex(); - mTexCoord = vec2(0, 0); - mColor = finalColor[2]; - gl_Position = vec4((sp2 + length_b * miter_b) / Viewport, getZdepth(P2), 1.0); + geometry_out.mTexCoord = vec2(0, 0); + geometry_out.mColor = geometry_in[2].finalColor; + gl_Position = vec4( + (sp2 + length_b * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0); EmitVertex(); - mTexCoord = vec2(0, 1); - mColor = finalColor[2]; - gl_Position = vec4((sp2 - length_b * miter_b) / Viewport, getZdepth(P2), 1.0); + geometry_out.mTexCoord = vec2(0, 1); + geometry_out.mColor = geometry_in[2].finalColor; + gl_Position = vec4( + (sp2 - length_b * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0); EmitVertex(); /* Generate the end end-cap (alpha < 0 used as end-cap flag). */ - if ((caps_end != GPENCIL_FLATCAP) && is_equal(P1, P3)) { - mTexCoord = vec2(0, 1); - mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0); - gl_Position = vec4((sp2 + (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0); + if ((gpencil_stroke_data.caps_end != GPENCIL_FLATCAP) && is_equal(P1, P3)) { + geometry_out.mTexCoord = vec2(0, 1); + geometry_out.mColor = vec4(geometry_in[2].finalColor.rgb, geometry_in[2].finalColor.a * -1.0); + gl_Position = vec4( + (sp2 + (length_b * 2.0) * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0); EmitVertex(); - mTexCoord = vec2(0, 0); - mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0); - gl_Position = vec4((sp2 - (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0); + geometry_out.mTexCoord = vec2(0, 0); + geometry_out.mColor = vec4(geometry_in[2].finalColor.rgb, geometry_in[2].finalColor.a * -1.0); + gl_Position = vec4( + (sp2 - (length_b * 2.0) * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0); EmitVertex(); - mTexCoord = vec2(1, 0.5); - mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0); + geometry_out.mTexCoord = vec2(1, 0.5); + geometry_out.mColor = vec4(geometry_in[2].finalColor.rgb, geometry_in[2].finalColor.a * -1.0); vec2 svn2 = normalize(sp2 - sp1) * length_b * 4.0 * extend; - gl_Position = vec4((sp2 + svn2) / Viewport, getZdepth(P2), 1.0); + gl_Position = vec4((sp2 + svn2) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0); EmitVertex(); } diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl index 07b4ae52110..16e12b2989e 100644 --- a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl @@ -1,3 +1,4 @@ +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; uniform mat4 ProjectionMatrix; @@ -12,22 +13,21 @@ in float thickness; out vec4 finalColor; out float finalThickness; +#endif -#define TRUE 1 - -float defaultpixsize = pixsize * (1000.0 / pixfactor); +float defaultpixsize = gpencil_stroke_data.pixsize * (1000.0 / gpencil_stroke_data.pixfactor); void main(void) { gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); - finalColor = color; + geometry_in.finalColor = color; - if (keep_size == TRUE) { - finalThickness = thickness; + if (gpencil_stroke_data.keep_size) { + geometry_in.finalThickness = thickness; } else { float size = (ProjectionMatrix[3][3] == 0.0) ? (thickness / (gl_Position.z * defaultpixsize)) : (thickness / defaultpixsize); - finalThickness = max(size * objscale, 1.0); + geometry_in.finalThickness = max(size * gpencil_stroke_data.objscale, 1.0); } } diff --git a/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl index 6dc7a1618e1..1846dae346a 100644 --- a/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl @@ -1,9 +1,10 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO in vec2 texCoord_interp; out vec4 fragColor; uniform vec4 color; uniform sampler2D image; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl index dfbaaeda7b5..ad52b9819ab 100644 --- a/source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl @@ -1,10 +1,11 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform float factor; in vec2 texCoord_interp; out vec4 fragColor; uniform vec4 color; uniform sampler2D image; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_image_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_frag.glsl index aff6ddf01bf..befd6b57bf8 100644 --- a/source/blender/gpu/shaders/gpu_shader_image_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_image_frag.glsl @@ -1,8 +1,9 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO in vec2 texCoord_interp; out vec4 fragColor; uniform sampler2D image; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl index 613352b4ac8..ceebaae896d 100644 --- a/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl @@ -1,9 +1,11 @@ +#ifndef USE_GPU_SHADER_CREATE_INFO in vec2 texCoord_interp; out vec4 fragColor; uniform float alpha; uniform sampler2D image; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl index 7f3fe2f5252..2314dbbc5d5 100644 --- a/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl @@ -1,6 +1,7 @@ /* Merge overlays texture on top of image texture and transform to display space (assume sRGB) */ +#ifndef USE_GPU_SHADER_CREATE_INFO uniform sampler2D image_texture; uniform sampler2D overlays_texture; uniform bool display_transform; @@ -9,6 +10,7 @@ uniform bool overlay; in vec2 texCoord_interp; out vec4 fragColor; +#endif float linearrgb_to_srgb(float c) { diff --git a/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl index c6e9860d940..9b1e6fe9d23 100644 --- a/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl @@ -7,18 +7,20 @@ /* Composite stereo textures */ +#ifndef USE_GPU_SHADER_CREATE_INFO uniform sampler2D imageTexture; uniform sampler2D overlayTexture; uniform int stereoDisplaySettings; +layout(location = 0) out vec4 imageColor; +layout(location = 1) out vec4 overlayColor; +#endif + #define stereo_display_mode (stereoDisplaySettings & ((1 << 3) - 1)) #define stereo_interlace_mode ((stereoDisplaySettings >> 3) & ((1 << 3) - 1)) #define stereo_interlace_swap bool(stereoDisplaySettings >> 6) -layout(location = 0) out vec4 imageColor; -layout(location = 1) out vec4 overlayColor; - bool interlace(ivec2 texel) { int interlace_mode = stereo_interlace_mode; diff --git a/source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl index ed69184ef14..e8bfb70b897 100644 --- a/source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl @@ -1,15 +1,16 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO in vec2 texCoord_interp; out vec4 fragColor; uniform sampler2D image; uniform vec4 color; uniform vec4 shuffle; +#endif void main() { - vec4 sample = texture(image, texCoord_interp); - fragColor = vec4(sample.r * shuffle.r + sample.g * shuffle.g + sample.b * shuffle.b + - sample.a * shuffle.a) * + vec4 sampled_color = texture(image, texCoord_interp); + fragColor = vec4(sampled_color.r * shuffle.r + sampled_color.g * shuffle.g + + sampled_color.b * shuffle.b + sampled_color.a * shuffle.a) * color; } diff --git a/source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl index becf0fbd133..3058f73ab37 100644 --- a/source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl @@ -1,9 +1,10 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO in vec2 texCoord_interp; flat in vec4 finalColor; out vec4 fragColor; uniform sampler2D image; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl index 10228a1e985..14450037ca8 100644 --- a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl @@ -1,4 +1,4 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ViewProjectionMatrix; /* ---- Instantiated Attrs ---- */ @@ -7,13 +7,14 @@ in vec3 pos; /* ---- Per instance Attrs ---- */ in mat4 InstanceModelMatrix; in vec4 color; -#ifdef UNIFORM_SCALE +# ifdef UNIFORM_SCALE in float size; -#else +# else in vec3 size; -#endif +# endif flat out vec4 finalColor; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_keyframe_shape_frag.glsl b/source/blender/gpu/shaders/gpu_shader_keyframe_shape_frag.glsl index a3b61dca8b4..2a2eaab7340 100644 --- a/source/blender/gpu/shaders/gpu_shader_keyframe_shape_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_keyframe_shape_frag.glsl @@ -11,6 +11,7 @@ #define GPU_KEYFRAME_SHAPE_SQUARE \ (GPU_KEYFRAME_SHAPE_CLIPPED_VERTICAL | GPU_KEYFRAME_SHAPE_CLIPPED_HORIZONTAL) +#ifndef USE_GPU_SHADER_CREATE_INFO flat in vec4 radii; flat in vec4 thresholds; @@ -20,6 +21,7 @@ flat in vec4 finalOutlineColor; flat in int finalFlags; out vec4 fragColor; +#endif const float diagonal_scale = sqrt(0.5); diff --git a/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl b/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl index 18e8b76ba23..4ef3ff1a8d0 100644 --- a/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl @@ -11,15 +11,16 @@ #define GPU_KEYFRAME_SHAPE_SQUARE \ (GPU_KEYFRAME_SHAPE_CLIPPED_VERTICAL | GPU_KEYFRAME_SHAPE_CLIPPED_HORIZONTAL) -uniform mat4 ModelViewProjectionMatrix; -uniform vec2 ViewportSize = vec2(-1, -1); -uniform float outline_scale = 1.0; - const float line_falloff = 1.0; const float circle_scale = sqrt(2.0 / 3.1416); const float square_scale = sqrt(0.5); const float diagonal_scale = sqrt(0.5); +#ifndef USE_GPU_SHADER_CREATE_INFO +uniform mat4 ModelViewProjectionMatrix; +uniform vec2 ViewportSize = vec2(-1, -1); +uniform float outline_scale = 1.0; + in vec2 pos; in float size; in vec4 color; @@ -33,6 +34,7 @@ flat out int finalFlags; flat out vec4 radii; flat out vec4 thresholds; +#endif bool test(int bit) { diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl index 52d59d2030f..960b5e6efac 100644 --- a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl @@ -1,8 +1,9 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform vec4 color; in vec2 radii; out vec4 fragColor; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl index 2ece73b3845..cdf3aa8024d 100644 --- a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl @@ -1,9 +1,10 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform vec4 color; uniform vec4 outlineColor; in vec4 radii; out vec4 fragColor; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl index 86c0e5c950a..23e9f9bc20f 100644 --- a/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl @@ -1,6 +1,11 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO in vec4 finalColor; out vec4 fragColor; +#endif + +#if defined(VERT) +in float vertexCrease; +#endif void main() { @@ -13,5 +18,14 @@ void main() discard; } +#if defined(VERT) fragColor = finalColor; + + float midStroke = 0.5 * rad_squared; + if (vertexCrease > 0.0 && dist_squared > midStroke) { + fragColor.rgb = mix(finalColor.rgb, colorEdgeCrease.rgb, vertexCrease); + } +#else + fragColor = finalColor; +#endif } diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl index c9bd9e881bf..04a7e3d80d0 100644 --- a/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl @@ -1,8 +1,9 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO in vec4 radii; in vec4 fillColor; in vec4 outlineColor; out vec4 fragColor; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl b/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl index 6bce517fee3..6725bc82841 100644 --- a/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl @@ -1,18 +1,19 @@ - -#ifndef USE_INSTANCE_COLOR +#ifndef USE_GPU_SHADER_CREATE_INFO +# ifndef USE_INSTANCE_COLOR uniform vec4 color; -#endif +# endif uniform vec3 light; in vec3 normal; -#ifdef USE_INSTANCE_COLOR +# ifdef USE_INSTANCE_COLOR flat in vec4 finalColor; -# define color finalColor -#endif +# define color finalColor +# endif out vec4 fragColor; +#endif void main() { - fragColor = color; - fragColor.xyz *= clamp(dot(normalize(normal), light), 0.0, 1.0); + fragColor = simple_lighting_data.color; + fragColor.xyz *= clamp(dot(normalize(normal), simple_lighting_data.light), 0.0, 1.0); } diff --git a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl index 2568cd74445..1456bd0c732 100644 --- a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl @@ -1,4 +1,4 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO flat in vec4 color_flat; noperspective in vec2 texCoord_interp; flat in int glyph_offset; @@ -8,6 +8,7 @@ flat in int interp_size; out vec4 fragColor; uniform sampler2D glyph; +#endif const vec2 offsets4[4] = vec2[4]( vec2(-0.5, 0.5), vec2(0.5, 0.5), vec2(-0.5, -0.5), vec2(-0.5, -0.5)); diff --git a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl index 768638e5229..5b01fea5266 100644 --- a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl @@ -1,4 +1,4 @@ - +#ifndef USE_GPU_SHADER_CREATE_INFO uniform mat4 ModelViewProjectionMatrix; in vec4 pos; /* rect */ @@ -11,6 +11,7 @@ noperspective out vec2 texCoord_interp; flat out int glyph_offset; flat out ivec2 glyph_dim; flat out int interp_size; +#endif void main() { diff --git a/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl index 08623fa9935..b4a75cc489b 100644 --- a/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl @@ -1,7 +1,8 @@ +#ifndef USE_GPU_SHADER_CREATE_INFO uniform vec4 color; - out vec4 fragColor; +#endif void main() { diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl index 0f69a4b9aa0..c8219848e29 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl @@ -72,7 +72,7 @@ void node_tex_voronoi_smooth_f1_1d(vec3 coord, out float outRadius) { randomness = clamp(randomness, 0.0, 1.0); - smoothness = clamp(smoothness / 2.0, 0, 0.5); + smoothness = clamp(smoothness / 2.0, 0.0, 0.5); float scaledCoord = w * scale; float cellPosition = floor(scaledCoord); @@ -301,7 +301,7 @@ void node_tex_voronoi_smooth_f1_2d(vec3 coord, out float outRadius) { randomness = clamp(randomness, 0.0, 1.0); - smoothness = clamp(smoothness / 2.0, 0, 0.5); + smoothness = clamp(smoothness / 2.0, 0.0, 0.5); vec2 scaledCoord = coord.xy * scale; vec2 cellPosition = floor(scaledCoord); @@ -565,7 +565,7 @@ void node_tex_voronoi_smooth_f1_3d(vec3 coord, out float outRadius) { randomness = clamp(randomness, 0.0, 1.0); - smoothness = clamp(smoothness / 2.0, 0, 0.5); + smoothness = clamp(smoothness / 2.0, 0.0, 0.5); vec3 scaledCoord = coord * scale; vec3 cellPosition = floor(scaledCoord); @@ -852,7 +852,7 @@ void node_tex_voronoi_smooth_f1_4d(vec3 coord, out float outRadius) { randomness = clamp(randomness, 0.0, 1.0); - smoothness = clamp(smoothness / 2.0, 0, 0.5); + smoothness = clamp(smoothness / 2.0, 0.0, 0.5); vec4 scaledCoord = vec4(coord, w) * scale; vec4 cellPosition = floor(scaledCoord); diff --git a/source/blender/io/alembic/ABC_alembic.h b/source/blender/io/alembic/ABC_alembic.h index c1f3add377b..18b0c91b67c 100644 --- a/source/blender/io/alembic/ABC_alembic.h +++ b/source/blender/io/alembic/ABC_alembic.h @@ -26,6 +26,7 @@ extern "C" { #endif struct CacheArchiveHandle; +struct CacheFileLayer; struct CacheReader; struct ListBase; struct Main; @@ -102,6 +103,7 @@ bool ABC_import(struct bContext *C, struct CacheArchiveHandle *ABC_create_handle(struct Main *bmain, const char *filename, + const struct CacheFileLayer *layers, struct ListBase *object_paths); void ABC_free_handle(struct CacheArchiveHandle *handle); diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc index c1d3415b2c5..aa04f0038c9 100644 --- a/source/blender/io/alembic/exporter/abc_writer_mesh.cc +++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc @@ -76,10 +76,13 @@ static void get_topology(struct Mesh *mesh, std::vector &poly_verts, std::vector &loop_counts, bool &r_has_flat_shaded_poly); -static void get_creases(struct Mesh *mesh, - std::vector &indices, - std::vector &lengths, - std::vector &sharpnesses); +static void get_edge_creases(struct Mesh *mesh, + std::vector &indices, + std::vector &lengths, + std::vector &sharpnesses); +static void get_vert_creases(struct Mesh *mesh, + std::vector &indices, + std::vector &sharpnesses); static void get_loop_normals(struct Mesh *mesh, std::vector &normals, bool has_flat_shaded_poly); @@ -283,15 +286,16 @@ void ABCGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh) void ABCGenericMeshWriter::write_subd(HierarchyContext &context, struct Mesh *mesh) { - std::vector crease_sharpness; + std::vector edge_crease_sharpness, vert_crease_sharpness; std::vector points; std::vector poly_verts, loop_counts; - std::vector crease_indices, crease_lengths; + std::vector edge_crease_indices, edge_crease_lengths, vert_crease_indices; bool has_flat_poly = false; get_vertices(mesh, points); get_topology(mesh, poly_verts, loop_counts, has_flat_poly); - get_creases(mesh, crease_indices, crease_lengths, crease_sharpness); + get_edge_creases(mesh, edge_crease_indices, edge_crease_lengths, edge_crease_sharpness); + get_vert_creases(mesh, vert_crease_indices, vert_crease_sharpness); if (!frame_has_been_written_ && args_.export_params->face_sets) { write_face_sets(context.object, mesh, abc_subdiv_schema_); @@ -322,10 +326,15 @@ void ABCGenericMeshWriter::write_subd(HierarchyContext &context, struct Mesh *me write_generated_coordinates(abc_poly_mesh_schema_.getArbGeomParams(), m_custom_data_config); } - if (!crease_indices.empty()) { - subdiv_sample.setCreaseIndices(Int32ArraySample(crease_indices)); - subdiv_sample.setCreaseLengths(Int32ArraySample(crease_lengths)); - subdiv_sample.setCreaseSharpnesses(FloatArraySample(crease_sharpness)); + if (!edge_crease_indices.empty()) { + subdiv_sample.setCreaseIndices(Int32ArraySample(edge_crease_indices)); + subdiv_sample.setCreaseLengths(Int32ArraySample(edge_crease_lengths)); + subdiv_sample.setCreaseSharpnesses(FloatArraySample(edge_crease_sharpness)); + } + + if (!vert_crease_indices.empty()) { + subdiv_sample.setCornerIndices(Int32ArraySample(vert_crease_indices)); + subdiv_sample.setCornerSharpnesses(FloatArraySample(vert_crease_sharpness)); } update_bounding_box(context.object); @@ -477,10 +486,10 @@ static void get_topology(struct Mesh *mesh, } } -static void get_creases(struct Mesh *mesh, - std::vector &indices, - std::vector &lengths, - std::vector &sharpnesses) +static void get_edge_creases(struct Mesh *mesh, + std::vector &indices, + std::vector &lengths, + std::vector &sharpnesses) { const float factor = 1.0f / 255.0f; @@ -503,6 +512,29 @@ static void get_creases(struct Mesh *mesh, lengths.resize(sharpnesses.size(), 2); } +static void get_vert_creases(struct Mesh *mesh, + std::vector &indices, + std::vector &sharpnesses) +{ + indices.clear(); + sharpnesses.clear(); + + const float *creases = static_cast(CustomData_get_layer(&mesh->vdata, CD_CREASE)); + + if (!creases) { + return; + } + + for (int i = 0, v = mesh->totvert; i < v; i++) { + const float sharpness = creases[i]; + + if (sharpness != 0.0f) { + indices.push_back(i); + sharpnesses.push_back(sharpness); + } + } +} + static void get_loop_normals(struct Mesh *mesh, std::vector &normals, bool has_flat_shaded_poly) diff --git a/source/blender/io/alembic/intern/abc_reader_archive.cc b/source/blender/io/alembic/intern/abc_reader_archive.cc index 4951dc0e035..94def041285 100644 --- a/source/blender/io/alembic/intern/abc_reader_archive.cc +++ b/source/blender/io/alembic/intern/abc_reader_archive.cc @@ -23,6 +23,8 @@ #include "abc_reader_archive.h" +#include "Alembic/AbcCoreLayer/Read.h" + #include "BKE_main.h" #include "BLI_path_util.h" @@ -76,6 +78,46 @@ static IArchive open_archive(const std::string &filename, return IArchive(); } +ArchiveReader *ArchiveReader::get(struct Main *bmain, const std::vector &filenames) +{ + std::vector readers; + + for (const char *filename : filenames) { + auto reader = new ArchiveReader(bmain, filename); + + if (!reader->valid()) { + delete reader; + continue; + } + + readers.push_back(reader); + } + + if (readers.size() == 0) { + return nullptr; + } + + if (readers.size() == 1) { + return readers[0]; + } + + return new ArchiveReader(readers); +} + +ArchiveReader::ArchiveReader(const std::vector &readers) : m_readers(readers) +{ + Alembic::AbcCoreLayer::ArchiveReaderPtrs archives; + + for (auto &reader : readers) { + archives.push_back(reader->m_archive.getPtr()); + } + + Alembic::AbcCoreLayer::ReadArchive layer; + Alembic::AbcCoreAbstract::ArchiveReaderPtr arPtr = layer(archives); + + m_archive = IArchive(arPtr, kWrapExisting, ErrorHandler::kThrowPolicy); +} + ArchiveReader::ArchiveReader(struct Main *bmain, const char *filename) { char abs_filename[FILE_MAX]; @@ -96,6 +138,13 @@ ArchiveReader::ArchiveReader(struct Main *bmain, const char *filename) m_archive = open_archive(abs_filename, m_streams); } +ArchiveReader::~ArchiveReader() +{ + for (ArchiveReader *reader : m_readers) { + delete reader; + } +} + bool ArchiveReader::valid() const { return m_archive.valid(); diff --git a/source/blender/io/alembic/intern/abc_reader_archive.h b/source/blender/io/alembic/intern/abc_reader_archive.h index 67000194aa1..937e3a190cf 100644 --- a/source/blender/io/alembic/intern/abc_reader_archive.h +++ b/source/blender/io/alembic/intern/abc_reader_archive.h @@ -41,9 +41,17 @@ class ArchiveReader { std::ifstream m_infile; std::vector m_streams; - public: + std::vector m_readers; + + ArchiveReader(const std::vector &readers); + ArchiveReader(struct Main *bmain, const char *filename); + public: + static ArchiveReader *get(struct Main *bmain, const std::vector &filenames); + + ~ArchiveReader(); + bool valid() const; Alembic::Abc::IObject getTop(); diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc index 7c8ff2bab99..943ae12c8ff 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.cc +++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc @@ -45,6 +45,7 @@ #include "BKE_modifier.h" #include "BKE_object.h" +using Alembic::Abc::FloatArraySamplePtr; using Alembic::Abc::Int32ArraySamplePtr; using Alembic::Abc::IV3fArrayProperty; using Alembic::Abc::P3fArraySamplePtr; @@ -910,6 +911,32 @@ static void read_subd_sample(const std::string &iobject_full_name, } } +static void read_vertex_creases(Mesh *mesh, + const Int32ArraySamplePtr &indices, + const FloatArraySamplePtr &sharpnesses) +{ + if (!(indices && sharpnesses && indices->size() == sharpnesses->size() && + indices->size() != 0)) { + return; + } + + float *vertex_crease_data = (float *)CustomData_add_layer( + &mesh->vdata, CD_CREASE, CD_DEFAULT, nullptr, mesh->totvert); + const int totvert = mesh->totvert; + + for (int i = 0, v = indices->size(); i < v; ++i) { + const int idx = (*indices)[i]; + + if (idx >= totvert) { + continue; + } + + vertex_crease_data[idx] = (*sharpnesses)[i]; + } + + mesh->cd_flag |= ME_CDFLAG_VERT_CREASE; +} + /* ************************************************************************** */ AbcSubDReader::AbcSubDReader(const IObject &object, ImportSettings &settings) @@ -973,6 +1000,7 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec return; } + /* Read egde creases. */ Int32ArraySamplePtr indices = sample.getCreaseIndices(); Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses(); @@ -1003,6 +1031,8 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE; } + read_vertex_creases(mesh, sample.getCornerIndices(), sample.getCornerSharpnesses()); + if (m_settings->validate_meshes) { BKE_mesh_validate(mesh, false, false); } diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc index d7b176eea50..58fc4dd599d 100644 --- a/source/blender/io/alembic/intern/alembic_capi.cc +++ b/source/blender/io/alembic/intern/alembic_capi.cc @@ -159,11 +159,25 @@ static bool gather_objects_paths(const IObject &object, ListBase *object_paths) CacheArchiveHandle *ABC_create_handle(struct Main *bmain, const char *filename, + const CacheFileLayer *layers, ListBase *object_paths) { - ArchiveReader *archive = new ArchiveReader(bmain, filename); + std::vector filenames; + filenames.push_back(filename); - if (!archive->valid()) { + while (layers) { + if ((layers->flag & CACHEFILE_LAYER_HIDDEN) == 0) { + filenames.push_back(layers->filepath); + } + layers = layers->next; + } + + /* We need to reverse the order as overriding archives should come first. */ + std::reverse(filenames.begin(), filenames.end()); + + ArchiveReader *archive = ArchiveReader::get(bmain, filenames); + + if (!archive || !archive->valid()) { delete archive; return nullptr; } @@ -447,9 +461,9 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa WM_set_locked_interface(data->wm, true); - ArchiveReader *archive = new ArchiveReader(data->bmain, data->filename); + ArchiveReader *archive = ArchiveReader::get(data->bmain, {data->filename}); - if (!archive->valid()) { + if (!archive || !archive->valid()) { data->error_code = ABC_ARCHIVE_FAIL; delete archive; return; diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc index 53dbaac99fd..95b73c85da6 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.cc +++ b/source/blender/io/usd/intern/usd_reader_mesh.cc @@ -522,6 +522,38 @@ void USDMeshReader::read_colors(Mesh *mesh, const double motionSampleTime) } } +void USDMeshReader::read_vertex_creases(Mesh *mesh, const double motionSampleTime) +{ + pxr::VtIntArray corner_indices; + if (!mesh_prim_.GetCornerIndicesAttr().Get(&corner_indices, motionSampleTime)) { + return; + } + + pxr::VtIntArray corner_sharpnesses; + if (!mesh_prim_.GetCornerSharpnessesAttr().Get(&corner_sharpnesses, motionSampleTime)) { + return; + } + + /* It is fine to have fewer indices than vertices, but never the other way other. */ + if (corner_indices.size() > mesh->totvert) { + std::cerr << "WARNING: too many vertex crease for mesh " << prim_path_ << std::endl; + return; + } + + if (corner_indices.size() != corner_sharpnesses.size()) { + std::cerr << "WARNING: vertex crease indices and sharpnesses count mismatch for mesh " + << prim_path_ << std::endl; + return; + } + + float *creases = static_cast( + CustomData_add_layer(&mesh->vdata, CD_CREASE, CD_DEFAULT, nullptr, mesh->totvert)); + + for (size_t i = 0; i < corner_indices.size(); i++) { + creases[corner_indices[i]] = corner_sharpnesses[i]; + } +} + void USDMeshReader::process_normals_vertex_varying(Mesh *mesh) { if (!mesh) { @@ -640,6 +672,8 @@ void USDMeshReader::read_mesh_sample(ImportSettings *settings, mvert.co[1] = positions_[i][1]; mvert.co[2] = positions_[i][2]; } + + read_vertex_creases(mesh, motionSampleTime); } if (new_mesh || (settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) { diff --git a/source/blender/io/usd/intern/usd_reader_mesh.h b/source/blender/io/usd/intern/usd_reader_mesh.h index 9ed73ba5a28..c5869fcbd32 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.h +++ b/source/blender/io/usd/intern/usd_reader_mesh.h @@ -86,6 +86,7 @@ class USDMeshReader : public USDGeomReader { void read_mpolys(Mesh *mesh); void read_uvs(Mesh *mesh, double motionSampleTime, bool load_uvs = false); void read_colors(Mesh *mesh, double motionSampleTime); + void read_vertex_creases(Mesh *mesh, double motionSampleTime); void read_mesh_sample(ImportSettings *settings, Mesh *mesh, diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc index b21dd8ac1fd..b061a2ff795 100644 --- a/source/blender/io/usd/intern/usd_writer_mesh.cc +++ b/source/blender/io/usd/intern/usd_writer_mesh.cc @@ -110,6 +110,12 @@ struct USDMeshData { * single sharpness or a value per-edge, USD will encode either a single sharpness per crease on * a mesh, or sharpness's for all edges making up the creases on a mesh. */ pxr::VtFloatArray crease_sharpnesses; + + /* The lengths of this array specifies the number of sharp corners (or vertex crease) on the + * surface. Each value is the index of a vertex in the mesh's vertex list. */ + pxr::VtIntArray corner_indices; + /* The per-vertex sharpnesses. The lengths of this array must match that of `corner_indices`. */ + pxr::VtFloatArray corner_sharpnesses; }; void USDGenericMeshWriter::write_uv_maps(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh) @@ -214,6 +220,23 @@ void USDGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh) attr_crease_sharpness, pxr::VtValue(usd_mesh_data.crease_sharpnesses), timecode); } + if (!usd_mesh_data.corner_indices.empty() && + usd_mesh_data.corner_indices.size() == usd_mesh_data.corner_sharpnesses.size()) { + pxr::UsdAttribute attr_corner_indices = usd_mesh.CreateCornerIndicesAttr(pxr::VtValue(), true); + pxr::UsdAttribute attr_corner_sharpnesses = usd_mesh.CreateCornerSharpnessesAttr( + pxr::VtValue(), true); + + if (!attr_corner_indices.HasValue()) { + attr_corner_indices.Set(usd_mesh_data.corner_indices, defaultTime); + attr_corner_sharpnesses.Set(usd_mesh_data.corner_sharpnesses, defaultTime); + } + + usd_value_writer_.SetAttribute( + attr_corner_indices, pxr::VtValue(usd_mesh_data.corner_indices), timecode); + usd_value_writer_.SetAttribute( + attr_corner_sharpnesses, pxr::VtValue(usd_mesh_data.crease_sharpnesses), timecode); + } + if (usd_export_context_.export_params.export_uvmaps) { write_uv_maps(mesh, usd_mesh); } @@ -268,7 +291,7 @@ static void get_loops_polys(const Mesh *mesh, USDMeshData &usd_mesh_data) } } -static void get_creases(const Mesh *mesh, USDMeshData &usd_mesh_data) +static void get_edge_creases(const Mesh *mesh, USDMeshData &usd_mesh_data) { const float factor = 1.0f / 255.0f; @@ -293,11 +316,30 @@ static void get_creases(const Mesh *mesh, USDMeshData &usd_mesh_data) } } +static void get_vert_creases(const Mesh *mesh, USDMeshData &usd_mesh_data) +{ + const float *creases = static_cast(CustomData_get_layer(&mesh->vdata, CD_CREASE)); + + if (!creases) { + return; + } + + for (int i = 0, v = mesh->totvert; i < v; i++) { + const float sharpness = creases[i]; + + if (sharpness != 0.0f) { + usd_mesh_data.corner_indices.push_back(i); + usd_mesh_data.corner_sharpnesses.push_back(sharpness); + } + } +} + void USDGenericMeshWriter::get_geometry_data(const Mesh *mesh, USDMeshData &usd_mesh_data) { get_vertices(mesh, usd_mesh_data); get_loops_polys(mesh, usd_mesh_data); - get_creases(mesh, usd_mesh_data); + get_edge_creases(mesh, usd_mesh_data); + get_vert_creases(mesh, usd_mesh_data); } void USDGenericMeshWriter::assign_materials(const HierarchyContext &context, diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc index 45fa75c65b3..d31353c4a76 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc @@ -175,23 +175,13 @@ void OBJWriter::write_uv_coords(OBJMesh &r_obj_mesh_data) const } } -void OBJWriter::write_poly_normals(const OBJMesh &obj_mesh_data) const +void OBJWriter::write_poly_normals(OBJMesh &obj_mesh_data) { obj_mesh_data.ensure_mesh_normals(); - Vector lnormals; - const int tot_polygons = obj_mesh_data.tot_polygons(); - for (int i = 0; i < tot_polygons; i++) { - if (obj_mesh_data.is_ith_poly_smooth(i)) { - obj_mesh_data.calc_loop_normals(i, lnormals); - for (const float3 &lnormal : lnormals) { - file_handler_->write(lnormal[0], lnormal[1], lnormal[2]); - } - } - else { - float3 poly_normal = obj_mesh_data.calc_poly_normal(i); - file_handler_->write( - poly_normal[0], poly_normal[1], poly_normal[2]); - } + Vector normals; + obj_mesh_data.store_normal_coords_and_indices(normals); + for (const float3 &normal : normals) { + file_handler_->write(normal[0], normal[1], normal[2]); } } @@ -298,28 +288,17 @@ void OBJWriter::write_poly_elements(const OBJMesh &obj_mesh_data, const func_vert_uv_normal_indices poly_element_writer = get_poly_element_writer( obj_mesh_data.tot_uv_vertices()); - /* Number of normals may not be equal to number of polygons due to smooth shading. */ - int per_object_tot_normals = 0; const int tot_polygons = obj_mesh_data.tot_polygons(); for (int i = 0; i < tot_polygons; i++) { Vector poly_vertex_indices = obj_mesh_data.calc_poly_vertex_indices(i); Span poly_uv_indices = obj_mesh_data.calc_poly_uv_indices(i); - /* For an Object, a normal index depends on how many of its normals have been written before - * it. This is unknown because of smooth shading. So pass "per object total normals" - * and update it after each call. */ - int new_normals = 0; - Vector poly_normal_indices; - std::tie(new_normals, poly_normal_indices) = obj_mesh_data.calc_poly_normal_indices( - i, per_object_tot_normals); - per_object_tot_normals += new_normals; + Vector poly_normal_indices = obj_mesh_data.calc_poly_normal_indices(i); last_poly_smooth_group = write_smooth_group(obj_mesh_data, i, last_poly_smooth_group); last_poly_vertex_group = write_vertex_group(obj_mesh_data, i, last_poly_vertex_group); last_poly_mat_nr = write_poly_material(obj_mesh_data, i, last_poly_mat_nr, matname_fn); (this->*poly_element_writer)(poly_vertex_indices, poly_uv_indices, poly_normal_indices); } - /* Unusual: Other indices are updated in #OBJWriter::update_index_offsets. */ - index_offsets_.normal_offset += per_object_tot_normals; } void OBJWriter::write_edges_indices(const OBJMesh &obj_mesh_data) const @@ -390,7 +369,7 @@ void OBJWriter::update_index_offsets(const OBJMesh &obj_mesh_data) { index_offsets_.vertex_offset += obj_mesh_data.tot_vertices(); index_offsets_.uv_vertex_offset += obj_mesh_data.tot_uv_vertices(); - /* Normal index is updated right after writing the normals. */ + index_offsets_.normal_offset += obj_mesh_data.tot_normal_indices(); } /* -------------------------------------------------------------------- */ @@ -415,7 +394,7 @@ MTLWriter::MTLWriter(const char *obj_filepath) noexcept(false) if (!ok) { throw std::system_error(ENAMETOOLONG, std::system_category(), ""); } - file_handler_ = std::make_unique>(mtl_filepath_); + file_handler_ = std::make_unique>(mtl_filepath_); } void MTLWriter::write_header(const char *blen_filepath) const diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh index 3403d059068..7385d9fabe2 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh @@ -49,14 +49,14 @@ struct IndexOffsets { class OBJWriter : NonMovable, NonCopyable { private: const OBJExportParams &export_params_; - std::unique_ptr> file_handler_ = nullptr; + std::unique_ptr> file_handler_ = nullptr; IndexOffsets index_offsets_{0, 0, 0}; public: OBJWriter(const char *filepath, const OBJExportParams &export_params) noexcept(false) : export_params_(export_params) { - file_handler_ = std::make_unique>(filepath); + file_handler_ = std::make_unique>(filepath); } void write_header() const; @@ -79,13 +79,14 @@ class OBJWriter : NonMovable, NonCopyable { void write_vertex_coords(const OBJMesh &obj_mesh_data) const; /** * Write UV vertex coordinates for all vertices as `vt u v`. - * \note UV indices are stored here, but written later. + * \note UV indices are stored here, but written with polygons later. */ void write_uv_coords(OBJMesh &obj_mesh_data) const; /** * Write loop normals for smooth-shaded polygons, and polygon normals otherwise, as "vn x y z". + * \note Normal indices ares stored here, but written with polygons later. */ - void write_poly_normals(const OBJMesh &obj_mesh_data) const; + void write_poly_normals(OBJMesh &obj_mesh_data); /** * Write smooth group if polygon at the given index is shaded smooth else "s 0" */ @@ -171,7 +172,7 @@ class OBJWriter : NonMovable, NonCopyable { */ class MTLWriter : NonMovable, NonCopyable { private: - std::unique_ptr> file_handler_ = nullptr; + std::unique_ptr> file_handler_ = nullptr; std::string mtl_filepath_; Vector mtlmaterials_; /* Map from a Material* to an index into mtlmaterials_. */ diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh index 6d0ff1aa6a5..daae8ae52c8 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh @@ -26,6 +26,7 @@ #include #include "BLI_compiler_attrs.h" +#include "BLI_fileops.h" #include "BLI_string_ref.hh" #include "BLI_utility_mixins.hh" @@ -88,6 +89,7 @@ enum class eMTLSyntaxElement { template struct FileTypeTraits; +/* Used to prevent mixing of say OBJ file format with MTL syntax elements. */ template<> struct FileTypeTraits { using SyntaxType = eOBJSyntaxElement; }; @@ -96,15 +98,19 @@ template<> struct FileTypeTraits { using SyntaxType = eMTLSyntaxElement; }; -template struct Formatting { +struct FormattingSyntax { + /* Formatting syntax with the file format key like `newmtl %s\n`. */ const char *fmt = nullptr; + /* Number of arguments needed by the syntax. */ const int total_args = 0; - /* Fail to compile by default. */ - const bool is_type_valid = false; + /* Whether types of the given arguments are accepted by the syntax above. Fail to compile by + * default. + */ + const bool are_types_valid = false; }; /** - * Type dependent but always false. Use to add a conditional compile-time error. + * Type dependent but always false. Use to add a constexpr-conditional compile-time error. */ template struct always_false : std::false_type { }; @@ -118,9 +124,8 @@ constexpr bool is_type_integral = (... && std::is_integral_v>); template constexpr bool is_type_string_related = (... && std::is_constructible_v); -template -constexpr std::enable_if_t> -syntax_elem_to_formatting(const eOBJSyntaxElement key) +template +constexpr FormattingSyntax syntax_elem_to_formatting(const eOBJSyntaxElement key) { switch (key) { case eOBJSyntaxElement::vertex_coords: { @@ -130,7 +135,7 @@ syntax_elem_to_formatting(const eOBJSyntaxElement key) return {"vt %f %f\n", 2, is_type_float}; } case eOBJSyntaxElement::normal: { - return {"vn %f %f %f\n", 3, is_type_float}; + return {"vn %.4f %.4f %.4f\n", 3, is_type_float}; } case eOBJSyntaxElement::poly_element_begin: { return {"f", 0, is_type_string_related}; @@ -201,9 +206,8 @@ syntax_elem_to_formatting(const eOBJSyntaxElement key) } } -template -constexpr std::enable_if_t> -syntax_elem_to_formatting(const eMTLSyntaxElement key) +template +constexpr FormattingSyntax syntax_elem_to_formatting(const eMTLSyntaxElement key) { switch (key) { case eMTLSyntaxElement::newmtl: { @@ -261,21 +265,25 @@ syntax_elem_to_formatting(const eMTLSyntaxElement key) } } -template class FileHandler : NonCopyable, NonMovable { +/** + * File format and syntax agnostic file writer. + */ +template class FormattedFileHandler : NonCopyable, NonMovable { private: - FILE *outfile_ = nullptr; + std::FILE *outfile_ = nullptr; std::string outfile_path_; public: - FileHandler(std::string outfile_path) noexcept(false) : outfile_path_(std::move(outfile_path)) + FormattedFileHandler(std::string outfile_path) noexcept(false) + : outfile_path_(std::move(outfile_path)) { - outfile_ = std::fopen(outfile_path_.c_str(), "w"); + outfile_ = BLI_fopen(outfile_path_.c_str(), "w"); if (!outfile_) { - throw std::system_error(errno, std::system_category(), "Cannot open file"); + throw std::system_error(errno, std::system_category(), "Cannot open file " + outfile_path_); } } - ~FileHandler() + ~FormattedFileHandler() { if (outfile_ && std::fclose(outfile_)) { std::cerr << "Error: could not close the file '" << outfile_path_ @@ -283,17 +291,24 @@ template class FileHandler : NonCopyable, NonMovable { } } + /** + * Example invocation: `writer->write("foo")`. + * + * \param key Must match what the instance's filetype expects; i.e., `eMTLSyntaxElement` for + * `eFileType::MTL`. + */ template::SyntaxType key, typename... T> constexpr void write(T &&...args) const { - constexpr Formatting fmt_nargs_valid = syntax_elem_to_formatting( - key); - write__impl(fmt_nargs_valid.fmt, std::forward(args)...); - /* Types of all arguments and the number of arguments should match - * what the formatting specifies. */ - return std::enable_if_t < fmt_nargs_valid.is_type_valid && - (sizeof...(T) == fmt_nargs_valid.total_args), - void > (); + /* Get format syntax, number of arguments expected and whether types of given arguments are + * valid. + */ + constexpr FormattingSyntax fmt_nargs_valid = syntax_elem_to_formatting(key); + BLI_STATIC_ASSERT(fmt_nargs_valid.are_types_valid && + (sizeof...(T) == fmt_nargs_valid.total_args), + "Types of all arguments and the number of arguments should match what the " + "formatting specifies."); + write_impl(fmt_nargs_valid.fmt, std::forward(args)...); } private: @@ -301,11 +316,11 @@ template class FileHandler : NonCopyable, NonMovable { template using remove_cvref_t = std::remove_cv_t>; /** - * Make #std::string etc., usable for `fprintf` family. + * Make #std::string etc., usable for `fprintf` family. int float etc. are not affected. * \return: `const char *` or the original argument if the argument is * not related to #std::string. */ - template constexpr auto string_to_primitive(T &&arg) const + template constexpr auto convert_to_primitive(T &&arg) const { if constexpr (std::is_same_v, std::string> || std::is_same_v, blender::StringRefNull>) { @@ -319,21 +334,19 @@ template class FileHandler : NonCopyable, NonMovable { return; } else { + /* For int, float etc. */ return std::forward(arg); } } - template - constexpr std::enable_if_t<(total_args != 0), void> write__impl(const char *fmt, - T &&...args) const + template constexpr void write_impl(const char *fmt, T &&...args) const { - std::fprintf(outfile_, fmt, string_to_primitive(std::forward(args))...); - } - template - constexpr std::enable_if_t<(total_args == 0), void> write__impl(const char *fmt, - T &&...args) const - { - std::fputs(fmt, outfile_); + if constexpr (sizeof...(T) == 0) { + std::fputs(fmt, outfile_); + } + else { + std::fprintf(outfile_, fmt, convert_to_primitive(std::forward(args))...); + } } }; diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc index f11cd13ecdd..576d450e6b9 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc @@ -17,6 +17,8 @@ /** \file * \ingroup obj */ +/* Silence warnings from copying deprecated fields. Needed for an Object copy constructor use. */ +#define DNA_DEPRECATED_ALLOW #include "BKE_customdata.h" #include "BKE_deform.h" @@ -27,6 +29,7 @@ #include "BKE_object.h" #include "BLI_listbase.h" +#include "BLI_map.hh" #include "BLI_math.h" #include "DEG_depsgraph_query.h" @@ -41,20 +44,21 @@ namespace blender::io::obj { OBJMesh::OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Object *mesh_object) { - export_object_eval_ = DEG_get_evaluated_object(depsgraph, mesh_object); - export_mesh_eval_ = BKE_object_get_evaluated_mesh(export_object_eval_); + /* We need to copy the object because it may be in temporary space. */ + Object *obj_eval = DEG_get_evaluated_object(depsgraph, mesh_object); + export_object_eval_ = *obj_eval; + export_mesh_eval_ = BKE_object_get_evaluated_mesh(&export_object_eval_); mesh_eval_needs_free_ = false; if (!export_mesh_eval_) { /* Curves and NURBS surfaces need a new mesh when they're * exported in the form of vertices and edges. */ - export_mesh_eval_ = BKE_mesh_new_from_object(depsgraph, export_object_eval_, true, true); + export_mesh_eval_ = BKE_mesh_new_from_object(depsgraph, &export_object_eval_, true, true); /* Since a new mesh been allocated, it needs to be freed in the destructor. */ mesh_eval_needs_free_ = true; } - if (export_params.export_triangulated_mesh && - ELEM(export_object_eval_->type, OB_MESH, OB_SURF)) { + if (export_params.export_triangulated_mesh && ELEM(export_object_eval_.type, OB_MESH, OB_SURF)) { std::tie(export_mesh_eval_, mesh_eval_needs_free_) = triangulate_mesh_eval(); } set_world_axes_transform(export_params.forward_axis, export_params.up_axis); @@ -115,10 +119,10 @@ void OBJMesh::set_world_axes_transform(const eTransformAxisForward forward, mat3_from_axis_conversion(OBJ_AXIS_Y_FORWARD, OBJ_AXIS_Z_UP, forward, up, axes_transform); /* mat3_from_axis_conversion returns a transposed matrix! */ transpose_m3(axes_transform); - mul_m4_m3m4(world_and_axes_transform_, axes_transform, export_object_eval_->obmat); + mul_m4_m3m4(world_and_axes_transform_, axes_transform, export_object_eval_.obmat); /* mul_m4_m3m4 does not transform last row of obmat, i.e. location data. */ - mul_v3_m3v3(world_and_axes_transform_[3], axes_transform, export_object_eval_->obmat[3]); - world_and_axes_transform_[3][3] = export_object_eval_->obmat[3][3]; + mul_v3_m3v3(world_and_axes_transform_[3], axes_transform, export_object_eval_.obmat[3]); + world_and_axes_transform_[3][3] = export_object_eval_.obmat[3][3]; } int OBJMesh::tot_vertices() const @@ -146,6 +150,11 @@ int16_t OBJMesh::tot_materials() const return export_mesh_eval_->totcol; } +int OBJMesh::tot_normal_indices() const +{ + return tot_normal_indices_; +} + int OBJMesh::ith_smooth_group(const int poly_index) const { /* Calculate smooth groups first: #OBJMesh::calc_smooth_groups. */ @@ -179,8 +188,14 @@ void OBJMesh::calc_smooth_groups(const bool use_bitflags) const Material *OBJMesh::get_object_material(const int16_t mat_nr) const { - /* "+ 1" as material getter needs one-based indices. */ - const Material *r_mat = BKE_object_material_get(export_object_eval_, mat_nr + 1); + /** + * The const_cast is safe here because BKE_object_material_get won't change the object + * but it is a big can of worms to fix the declaration of that function right now. + * + * The call uses "+ 1" as material getter needs one-based indices. + */ + Object *obj = const_cast(&export_object_eval_); + const Material *r_mat = BKE_object_material_get(obj, mat_nr + 1); #ifdef DEBUG if (!r_mat) { std::cerr << "Material not found for mat_nr = " << mat_nr << std::endl; @@ -203,7 +218,7 @@ int16_t OBJMesh::ith_poly_matnr(const int poly_index) const const char *OBJMesh::get_object_name() const { - return export_object_eval_->id.name + 2; + return export_object_eval_.id.name + 2; } const char *OBJMesh::get_object_mesh_name() const @@ -297,6 +312,7 @@ Span OBJMesh::calc_poly_uv_indices(const int poly_index) const BLI_assert(poly_index < uv_indices_.size()); return uv_indices_[poly_index]; } + float3 OBJMesh::calc_poly_normal(const int poly_index) const { float3 r_poly_normal; @@ -308,41 +324,87 @@ float3 OBJMesh::calc_poly_normal(const int poly_index) const return r_poly_normal; } -void OBJMesh::calc_loop_normals(const int poly_index, Vector &r_loop_normals) const +/** Round \a f to \a round_digits decimal digits. */ +static float round_float_to_n_digits(const float f, int round_digits) { - r_loop_normals.clear(); - const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index]; - const float( - *lnors)[3] = (const float(*)[3])(CustomData_get_layer(&export_mesh_eval_->ldata, CD_NORMAL)); - for (int loop_of_poly = 0; loop_of_poly < mpoly.totloop; loop_of_poly++) { - float3 loop_normal; - copy_v3_v3(loop_normal, lnors[mpoly.loopstart + loop_of_poly]); - mul_mat3_m4_v3(world_and_axes_transform_, loop_normal); - r_loop_normals.append(loop_normal); - } + float scale = powf(10.0, round_digits); + return ceilf((scale * f - 0.49999999f)) / scale; } -std::pair> OBJMesh::calc_poly_normal_indices( - const int poly_index, const int object_tot_prev_normals) const +static float3 round_float3_to_n_digits(const float3 &v, int round_digits) +{ + float3 ans; + ans.x = round_float_to_n_digits(v.x, round_digits); + ans.y = round_float_to_n_digits(v.y, round_digits); + ans.z = round_float_to_n_digits(v.z, round_digits); + return ans; +} + +void OBJMesh::store_normal_coords_and_indices(Vector &r_normal_coords) +{ + /* We'll round normal components to 4 digits. + * This will cover up some minor differences + * between floating point calculations on different platforms. + * Since normals are normalized, there will be no perceptible loss + * of precision when rounding to 4 digits. */ + constexpr int round_digits = 4; + int cur_normal_index = 0; + Map normal_to_index; + /* We don't know how many unique normals there will be, but this is a guess.*/ + normal_to_index.reserve(export_mesh_eval_->totpoly); + loop_to_normal_index_.resize(export_mesh_eval_->totloop); + loop_to_normal_index_.fill(-1); + const float( + *lnors)[3] = (const float(*)[3])(CustomData_get_layer(&export_mesh_eval_->ldata, CD_NORMAL)); + for (int poly_index = 0; poly_index < export_mesh_eval_->totpoly; ++poly_index) { + const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index]; + bool need_per_loop_normals = is_ith_poly_smooth(poly_index); + if (need_per_loop_normals) { + for (int loop_of_poly = 0; loop_of_poly < mpoly.totloop; ++loop_of_poly) { + float3 loop_normal; + int loop_index = mpoly.loopstart + loop_of_poly; + BLI_assert(loop_index < export_mesh_eval_->totloop); + copy_v3_v3(loop_normal, lnors[loop_index]); + mul_mat3_m4_v3(world_and_axes_transform_, loop_normal); + float3 rounded_loop_normal = round_float3_to_n_digits(loop_normal, round_digits); + int loop_norm_index = normal_to_index.lookup_default(rounded_loop_normal, -1); + if (loop_norm_index == -1) { + loop_norm_index = cur_normal_index++; + normal_to_index.add(rounded_loop_normal, loop_norm_index); + r_normal_coords.append(rounded_loop_normal); + } + loop_to_normal_index_[loop_index] = loop_norm_index; + } + } + else { + float3 poly_normal = calc_poly_normal(poly_index); + float3 rounded_poly_normal = round_float3_to_n_digits(poly_normal, round_digits); + int poly_norm_index = normal_to_index.lookup_default(rounded_poly_normal, -1); + if (poly_norm_index == -1) { + poly_norm_index = cur_normal_index++; + normal_to_index.add(rounded_poly_normal, poly_norm_index); + r_normal_coords.append(rounded_poly_normal); + } + for (int i = 0; i < mpoly.totloop; ++i) { + int loop_index = mpoly.loopstart + i; + BLI_assert(loop_index < export_mesh_eval_->totloop); + loop_to_normal_index_[loop_index] = poly_norm_index; + } + } + } + tot_normal_indices_ = cur_normal_index; +} + +Vector OBJMesh::calc_poly_normal_indices(const int poly_index) const { const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index]; const int totloop = mpoly.totloop; Vector r_poly_normal_indices(totloop); - - if (is_ith_poly_smooth(poly_index)) { - for (int poly_loop_index = 0; poly_loop_index < totloop; poly_loop_index++) { - /* Using polygon loop index is fine because polygon/loop normals and their normal indices are - * written by looping over #Mesh.mpoly /#Mesh.mloop in the same order. */ - r_poly_normal_indices[poly_loop_index] = object_tot_prev_normals + poly_loop_index; - } - /* For a smooth-shaded polygon, #Mesh.totloop -many loop normals are written. */ - return {totloop, r_poly_normal_indices}; - } for (int poly_loop_index = 0; poly_loop_index < totloop; poly_loop_index++) { - r_poly_normal_indices[poly_loop_index] = object_tot_prev_normals; + int loop_index = mpoly.loopstart + poly_loop_index; + r_poly_normal_indices[poly_loop_index] = loop_to_normal_index_[loop_index]; } - /* For a flat-shaded polygon, one polygon normal is written. */ - return {1, r_poly_normal_indices}; + return r_poly_normal_indices; } int16_t OBJMesh::get_poly_deform_group_index(const int poly_index) const @@ -350,7 +412,7 @@ int16_t OBJMesh::get_poly_deform_group_index(const int poly_index) const BLI_assert(poly_index < export_mesh_eval_->totpoly); const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index]; const MLoop *mloop = &export_mesh_eval_->mloop[mpoly.loopstart]; - const Object *obj = export_object_eval_; + const Object *obj = &export_object_eval_; const int tot_deform_groups = BKE_object_defgroup_count(obj); /* Indices of the vector index into deform groups of an object; values are the] * number of vertex members in one deform group. */ @@ -391,7 +453,7 @@ int16_t OBJMesh::get_poly_deform_group_index(const int poly_index) const const char *OBJMesh::get_poly_deform_group_name(const int16_t def_group_index) const { const bDeformGroup &vertex_group = *(static_cast( - BLI_findlink(BKE_object_defgroup_list(export_object_eval_), def_group_index))); + BLI_findlink(BKE_object_defgroup_list(&export_object_eval_), def_group_index))); return vertex_group.name; } diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh index e6d2853d040..f3ace140006 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh @@ -32,6 +32,7 @@ #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_object_types.h" #include "IO_wavefront_obj.h" @@ -57,7 +58,11 @@ using unique_bmesh_ptr = std::unique_ptr; class OBJMesh : NonCopyable { private: - Object *export_object_eval_; + /** + * We need to copy the entire Object structure here because the dependency graph iterator + * sometimes builds an Object in a temporary space that doesn't persist. + */ + Object export_object_eval_; Mesh *export_mesh_eval_; /** * For curves which are converted to mesh, and triangulated meshes, a new mesh is allocated. @@ -77,6 +82,15 @@ class OBJMesh : NonCopyable { * Per-polygon-per-vertex UV vertex indices. */ Vector> uv_indices_; + /** + * Per-loop normal index. + */ + Vector loop_to_normal_index_; + /* + * Total number of normal indices (maximum entry, plus 1, in + * the loop_to_norm_index_ vector). + */ + int tot_normal_indices_ = 0; /** * Total smooth groups in an object. */ @@ -97,6 +111,7 @@ class OBJMesh : NonCopyable { int tot_vertices() const; int tot_polygons() const; int tot_uv_vertices() const; + int tot_normal_indices() const; int tot_edges() const; /** @@ -162,18 +177,16 @@ class OBJMesh : NonCopyable { */ float3 calc_poly_normal(int poly_index) const; /** - * Calculate a polygon's polygon/loop normal indices. - * \param object_tot_prev_normals Number of normals of this Object written so far. - * \return Number of distinct normal indices. + * Find the unique normals of the mesh and return them in \a r_normal_coords. + * Store the indices into that vector with for each loop in this #OBJMesh. */ - std::pair> calc_poly_normal_indices(int poly_index, - int object_tot_prev_normals) const; + void store_normal_coords_and_indices(Vector &r_normal_coords); /** - * Calculate loop normals of a polygon at the given index. - * - * Should be used for smooth-shaded polygons. + * Calculate a polygon's polygon/loop normal indices. + * \param poly_index Index of the polygon to calculate indices for. + * \return Vector of normal indices, aligned with vertices of polygon. */ - void calc_loop_normals(int poly_index, Vector &r_loop_normals) const; + Vector calc_poly_normal_indices(int poly_index) const; /** * Find the index of the vertex group with the maximum number of vertices in a polygon. * The index indices into the #Object.defbase. diff --git a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc index 595e6aaf4f2..0c753ccdcac 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc @@ -91,28 +91,29 @@ filter_supported_objects(Depsgraph *depsgraph, const OBJExportParams &export_par { Vector> r_exportable_meshes; Vector> r_exportable_nurbs; - const ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); - LISTBASE_FOREACH (const Base *, base, &view_layer->object_bases) { - Object *object_in_layer = base->object; - if (export_params.export_selected_objects && !(object_in_layer->base_flag & BASE_SELECTED)) { + const int deg_objects_visibility_flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | + DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | + DEG_ITER_OBJECT_FLAG_VISIBLE | + DEG_ITER_OBJECT_FLAG_DUPLI; + DEG_OBJECT_ITER_BEGIN (depsgraph, object, deg_objects_visibility_flags) { + if (export_params.export_selected_objects && !(object->base_flag & BASE_SELECTED)) { continue; } - switch (object_in_layer->type) { + switch (object->type) { case OB_SURF: /* Export in mesh form: vertices and polygons. */ ATTR_FALLTHROUGH; case OB_MESH: - r_exportable_meshes.append( - std::make_unique(depsgraph, export_params, object_in_layer)); + r_exportable_meshes.append(std::make_unique(depsgraph, export_params, object)); break; case OB_CURVE: { - Curve *curve = static_cast(object_in_layer->data); + Curve *curve = static_cast(object->data); Nurb *nurb{static_cast(curve->nurb.first)}; if (!nurb) { /* An empty curve. Not yet supported to export these as meshes. */ if (export_params.export_curves_as_nurbs) { r_exportable_nurbs.append( - std::make_unique(depsgraph, export_params, object_in_layer)); + std::make_unique(depsgraph, export_params, object)); } break; } @@ -121,18 +122,18 @@ filter_supported_objects(Depsgraph *depsgraph, const OBJExportParams &export_par if (export_params.export_curves_as_nurbs) { /* Export in parameter form: control points. */ r_exportable_nurbs.append( - std::make_unique(depsgraph, export_params, object_in_layer)); + std::make_unique(depsgraph, export_params, object)); } else { /* Export in mesh form: edges and vertices. */ r_exportable_meshes.append( - std::make_unique(depsgraph, export_params, object_in_layer)); + std::make_unique(depsgraph, export_params, object)); } break; case CU_BEZIER: /* Always export in mesh form: edges and vertices. */ r_exportable_meshes.append( - std::make_unique(depsgraph, export_params, object_in_layer)); + std::make_unique(depsgraph, export_params, object)); break; default: /* Other curve types are not supported. */ @@ -145,6 +146,7 @@ filter_supported_objects(Depsgraph *depsgraph, const OBJExportParams &export_par break; } } + DEG_OBJECT_ITER_END; return {std::move(r_exportable_meshes), std::move(r_exportable_nurbs)}; } diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc index 3b44a72ca0c..89e1de49511 100644 --- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc @@ -1,10 +1,8 @@ /* Apache License, Version 2.0 */ -#include #include #include #include -#include #include #include @@ -29,6 +27,8 @@ #include "obj_exporter_tests.hh" namespace blender::io::obj { +/* Set this true to keep comparison-failing test output in temp file directory. */ +constexpr bool save_failing_test_output = false; /* This is also the test name. */ class obj_exporter_test : public BlendfileLoadingBaseTest { @@ -58,7 +58,7 @@ TEST_F(obj_exporter_test, filter_objects_curves_as_mesh) return; } auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)}; - EXPECT_EQ(objmeshes.size(), 17); + EXPECT_EQ(objmeshes.size(), 19); EXPECT_EQ(objcurves.size(), 0); } @@ -71,7 +71,7 @@ TEST_F(obj_exporter_test, filter_objects_curves_as_nurbs) } _export.params.export_curves_as_nurbs = true; auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)}; - EXPECT_EQ(objmeshes.size(), 16); + EXPECT_EQ(objmeshes.size(), 18); EXPECT_EQ(objcurves.size(), 2); } @@ -183,15 +183,21 @@ static std::unique_ptr init_writer(const OBJExportParams ¶ms, } } -/* The following is relative to BKE_tempdir_base. */ -const char *const temp_file_path = "output.OBJ"; +/* The following is relative to BKE_tempdir_base. + * Use Latin Capital Letter A with Ogonek, Cyrillic Capital Letter Zhe + * at the end, to test I/O on non-English file names. */ +const char *const temp_file_path = "output\xc4\x84\xd0\x96.OBJ"; static std::string read_temp_file_in_string(const std::string &file_path) { - std::ifstream temp_stream(file_path); - std::ostringstream input_ss; - input_ss << temp_stream.rdbuf(); - return input_ss.str(); + std::string res; + size_t buffer_len; + void *buffer = BLI_file_read_text_as_mem(file_path.c_str(), 0, &buffer_len); + if (buffer != NULL) { + res.assign((const char *)buffer, buffer_len); + MEM_freeN(buffer); + } + return res; } TEST(obj_exporter_writer, header) @@ -294,8 +300,14 @@ class obj_exporter_regression_test : public obj_exporter_test { std::string golden_file_path = blender::tests::flags_test_asset_dir() + "/" + golden_obj; std::string golden_str = read_temp_file_in_string(golden_file_path); - ASSERT_TRUE(strings_equal_after_first_lines(output_str, golden_str)); - BLI_delete(out_file_path.c_str(), false, false); + bool are_equal = strings_equal_after_first_lines(output_str, golden_str); + if (save_failing_test_output && !are_equal) { + printf("failing test output in %s\n", out_file_path.c_str()); + } + ASSERT_TRUE(are_equal); + if (!save_failing_test_output || are_equal) { + BLI_delete(out_file_path.c_str(), false, false); + } if (!golden_mtl.empty()) { std::string out_mtl_file_path = tempdir + BLI_path_basename(golden_mtl.c_str()); std::string output_mtl_str = read_temp_file_in_string(out_mtl_file_path); @@ -390,7 +402,6 @@ TEST_F(obj_exporter_regression_test, cube_all_data_triangulated) _export.params); } -#if 0 TEST_F(obj_exporter_regression_test, suzanne_all_data) { OBJExportParamsDefault _export; @@ -415,6 +426,5 @@ TEST_F(obj_exporter_regression_test, all_objects) "io_tests/obj/all_objects.mtl", _export.params); } -#endif } // namespace blender::io::obj diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index a70befc155b..060b55ffe5c 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -147,17 +147,18 @@ typedef struct IDProperty { #define DEFAULT_ALLOC_FOR_NULL_STRINGS 64 /*->type*/ -enum { +typedef enum eIDPropertyType { IDP_STRING = 0, IDP_INT = 1, IDP_FLOAT = 2, + /** Array containing int, floats, doubles or groups. */ IDP_ARRAY = 5, IDP_GROUP = 6, IDP_ID = 7, IDP_DOUBLE = 8, IDP_IDPARRAY = 9, - IDP_NUMTYPES = 10, -}; +} eIDPropertyType; +#define IDP_NUMTYPES 10 /** Used by some IDP utils, keep values in sync with type enum above. */ enum { diff --git a/source/blender/makesdna/DNA_cachefile_types.h b/source/blender/makesdna/DNA_cachefile_types.h index 0f4c53a6e7e..65e1dd6c096 100644 --- a/source/blender/makesdna/DNA_cachefile_types.h +++ b/source/blender/makesdna/DNA_cachefile_types.h @@ -59,6 +59,18 @@ typedef struct CacheObjectPath { char path[4096]; } CacheObjectPath; +/* CacheFileLayer::flag */ +enum { CACHEFILE_LAYER_HIDDEN = (1 << 0) }; + +typedef struct CacheFileLayer { + struct CacheFileLayer *next, *prev; + + /** 1024 = FILE_MAX. */ + char filepath[1024]; + int flag; + int _pad; +} CacheFileLayer; + /* CacheFile::velocity_unit * Determines what temporal unit is used to interpret velocity vectors for motion blur effects. */ enum { @@ -73,6 +85,8 @@ typedef struct CacheFile { /** Paths of the objects inside of the archive referenced by this CacheFile. */ ListBase object_paths; + ListBase layers; + /** 1024 = FILE_MAX. */ char filepath[1024]; @@ -109,7 +123,10 @@ typedef struct CacheFile { /** Size in megabytes for the prefetch cache used by the Cycles Procedural. */ int prefetch_cache_size; - char _pad2[7]; + /** Index of the currently selected layer in the UI, starts at 1. */ + int active_layer; + + char _pad2[3]; char velocity_unit; /* Name of the velocity property in the archive. */ diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index 07251b76b17..adbb993ff2c 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -139,6 +139,10 @@ typedef enum CustomDataType { CD_SHAPE_KEYINDEX = 27, CD_SHAPEKEY = 28, CD_BWEIGHT = 29, + /* Usage of CD_CREASE depends on where on the Mesh the layer is added: + * - for vertex creasing, this is persistent data accross all modes and is stored in the file, + * - for egde creasing, it is runtime data which is only used in edit-mode before being copied to + * MEdge when exiting edit-mode. */ CD_CREASE = 30, CD_ORIGSPACE_MLOOP = 31, CD_PREVIEW_MLOOPCOL = 32, diff --git a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h index 88eb164c2b4..c51a615bfb6 100644 --- a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h +++ b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h @@ -315,7 +315,8 @@ .opacity = 1.0f, \ .flags = LRT_GPENCIL_MATCH_OUTPUT_VGROUP, \ .crease_threshold = DEG2RAD(140.0f), \ - .calculation_flags = LRT_ALLOW_DUPLI_OBJECTS | LRT_ALLOW_CLIPPING_BOUNDARIES | LRT_USE_CREASE_ON_SHARP_EDGES, \ + .calculation_flags = LRT_ALLOW_DUPLI_OBJECTS | LRT_ALLOW_CLIPPING_BOUNDARIES | \ + LRT_USE_CREASE_ON_SHARP_EDGES | LRT_FILTER_FACE_MARK_KEEP_CONTOUR, \ .angle_splitting_threshold = DEG2RAD(60.0f), \ .chaining_image_threshold = 0.001f, \ .chain_smooth_tolerance = 0.2f,\ diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h index 0f69a256f56..b361372ff8b 100644 --- a/source/blender/makesdna/DNA_gpencil_modifier_types.h +++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h @@ -989,6 +989,7 @@ typedef enum eLineArtGPencilModifierFlags { LRT_GPENCIL_IS_BAKED = (1 << 3), LRT_GPENCIL_USE_CACHE = (1 << 4), LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA = (1 << 5), + LRT_GPENCIL_INVERT_COLLECTION = (1 << 6), } eLineArtGPencilModifierFlags; typedef enum eLineartGpencilMaskSwitches { diff --git a/source/blender/makesdna/DNA_lineart_types.h b/source/blender/makesdna/DNA_lineart_types.h index d4440592a00..3e77d566d27 100644 --- a/source/blender/makesdna/DNA_lineart_types.h +++ b/source/blender/makesdna/DNA_lineart_types.h @@ -50,7 +50,10 @@ typedef enum eLineartMainFlags { LRT_USE_CREASE_ON_SMOOTH_SURFACES = (1 << 15), LRT_USE_CREASE_ON_SHARP_EDGES = (1 << 16), LRT_USE_CUSTOM_CAMERA = (1 << 17), + LRT_FILTER_FACE_MARK_KEEP_CONTOUR = (1 << 18), + LRT_USE_BACK_FACE_CULLING = (1 << 19), LRT_USE_IMAGE_BOUNDARY_TRIMMING = (1 << 20), + LRT_CHAIN_PRESERVE_DETAILS = (1 << 22), } eLineartMainFlags; typedef enum eLineartEdgeFlag { diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 55c04c9bcfa..3e683209125 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -442,6 +442,7 @@ enum { ME_CDFLAG_VERT_BWEIGHT = 1 << 0, ME_CDFLAG_EDGE_BWEIGHT = 1 << 1, ME_CDFLAG_EDGE_CREASE = 1 << 2, + ME_CDFLAG_VERT_CREASE = 1 << 3, }; /** #Mesh.remesh_mode */ diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 114e350b582..10058204e88 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1503,6 +1503,11 @@ typedef struct NodeGeometryCurveSelectHandles { uint8_t mode; } NodeGeometryCurveSelectHandles; +typedef struct NodeGeometryCurvePrimitiveArc { + /* GeometryNodeCurvePrimitiveArcMode. */ + uint8_t mode; +} NodeGeometryCurvePrimitiveArc; + typedef struct NodeGeometryCurvePrimitiveLine { /* GeometryNodeCurvePrimitiveLineMode. */ uint8_t mode; @@ -2237,6 +2242,11 @@ typedef enum GeometryNodeMeshLineCountMode { GEO_NODE_MESH_LINE_COUNT_RESOLUTION = 1, } GeometryNodeMeshLineCountMode; +typedef enum GeometryNodeCurvePrimitiveArcMode { + GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS = 0, + GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_RADIUS = 1, +} GeometryNodeCurvePrimitiveArcMode; + typedef enum GeometryNodeCurvePrimitiveLineMode { GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS = 0, GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION = 1 @@ -2331,6 +2341,11 @@ typedef enum GeometryNodeRealizeInstancesFlag { GEO_NODE_REALIZE_INSTANCES_LEGACY_BEHAVIOR = (1 << 0), } GeometryNodeRealizeInstancesFlag; +typedef enum GeometryNodeScaleElementsMode { + GEO_NODE_SCALE_ELEMENTS_UNIFORM = 0, + GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS = 1, +} GeometryNodeScaleElementsMode; + #ifdef __cplusplus } #endif diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h index 030fd29264b..d312bebdba7 100644 --- a/source/blender/makesdna/DNA_scene_defaults.h +++ b/source/blender/makesdna/DNA_scene_defaults.h @@ -47,6 +47,7 @@ .width = 512, \ .height = 512, \ .margin = 16, \ + .margin_type = R_BAKE_ADJACENT_FACES, \ .normal_space = R_BAKE_SPACE_TANGENT, \ .normal_swizzle = {R_BAKE_POSX, R_BAKE_POSY, R_BAKE_POSZ}, \ } @@ -102,7 +103,8 @@ .dither_intensity = 1.0f, \ \ .bake_mode = 0, \ - .bake_filter = 16, \ + .bake_margin = 16, \ + .bake_margin_type = R_BAKE_ADJACENT_FACES, \ .bake_flag = R_BAKE_CLEAR, \ .bake_samples = 256, \ .bake_biasdist = 0.001f, \ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 42cd3e7d224..aab8ad915ed 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -563,11 +563,18 @@ typedef struct BakeData { char target; char save_mode; - char _pad[6]; + char margin_type; + char _pad[5]; struct Object *cage_object; } BakeData; +/** #BakeData.margin_type (char) */ +typedef enum eBakeMarginType { + R_BAKE_ADJACENT_FACES = 0, + R_BAKE_EXTEND = 1, +} eBakeMarginType; + /** #BakeData.normal_swizzle (char) */ typedef enum eBakeNormalSwizzle { R_BAKE_POSX = 0, @@ -715,7 +722,9 @@ typedef struct RenderData { /* Bake Render options */ short bake_mode, bake_flag; - short bake_filter, bake_samples; + short bake_margin, bake_samples; + short bake_margin_type; + char _pad9[6]; float bake_biasdist, bake_user_scale; /* path to render output */ diff --git a/source/blender/makesdna/DNA_sculpt_brush_types.h b/source/blender/makesdna/DNA_sculpt_brush_types.h index 98f5a951484..cd762bcafb4 100644 --- a/source/blender/makesdna/DNA_sculpt_brush_types.h +++ b/source/blender/makesdna/DNA_sculpt_brush_types.h @@ -127,7 +127,7 @@ static_assert(offsetof(BrushChannel, type) - offsetof(BrushChannel, mappings) == #endif // BrushChannel->flag -enum { +typedef enum { BRUSH_CHANNEL_INHERIT = 1 << 0, BRUSH_CHANNEL_INHERIT_IF_UNSET = 1 << 1, BRUSH_CHANNEL_NO_MAPPINGS = 1 << 2, @@ -136,7 +136,7 @@ enum { BRUSH_CHANNEL_SHOW_IN_WORKSPACE = 1 << 6, BRUSH_CHANNEL_SHOW_IN_HEADER = 1 << 7, BRUSH_CHANNEL_SHOW_IN_CONTEXT_MENU = 1 << 8, -}; +} eBrushChannelFlag; // BrushChannelType->type enum { diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 5a963e1f37e..917e9218996 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -65,7 +65,14 @@ struct wmTimer; typedef struct SpaceProperties_Runtime SpaceProperties_Runtime; /** Defined in `node_intern.hh`. */ +#ifdef __cplusplus +namespace blender::ed::space_node { +struct SpaceNode_Runtime; +} // namespace blender::nodes +using SpaceNode_Runtime = blender::ed::space_node::SpaceNode_Runtime; +#else typedef struct SpaceNode_Runtime SpaceNode_Runtime; +#endif /** Defined in `file_intern.h`. */ typedef struct SpaceFile_Runtime SpaceFile_Runtime; diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index e8615c24534..98dfb0b5c03 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -655,6 +655,7 @@ typedef struct UserDef_Experimental { char use_cycles_debug; char use_geometry_nodes_legacy; char show_asset_debug_info; + char no_asset_indexing; char SANITIZE_AFTER_HERE; /* The following options are automatically sanitized (set to 0) * when the release cycle is not alpha. */ @@ -665,9 +666,8 @@ typedef struct UserDef_Experimental { char use_sculpt_tools_tilt; char use_extended_asset_browser; char use_override_templates; + char use_sculpt_uvsmooth; - char use_geometry_nodes_fields; - char _pad[8]; /** `makesdna` does not allow empty structs. */ } UserDef_Experimental; diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h index c5769d7eee4..cb8052856a7 100644 --- a/source/blender/makesdna/intern/dna_rename_defs.h +++ b/source/blender/makesdna/intern/dna_rename_defs.h @@ -107,6 +107,7 @@ DNA_STRUCT_RENAME_ELEM(ParticleSettings, dup_group, instance_collection) DNA_STRUCT_RENAME_ELEM(ParticleSettings, dup_ob, instance_object) DNA_STRUCT_RENAME_ELEM(ParticleSettings, dupliweights, instance_weights) DNA_STRUCT_RENAME_ELEM(RigidBodyWorld, steps_per_second, substeps_per_frame) +DNA_STRUCT_RENAME_ELEM(RenderData, bake_filter, bake_margin) DNA_STRUCT_RENAME_ELEM(SpaceSeq, overlay_type, overlay_frame_type) DNA_STRUCT_RENAME_ELEM(SurfaceDeformModifierData, numverts, num_bind_verts) DNA_STRUCT_RENAME_ELEM(Text, name, filepath) diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 50efb74c23e..13135c59ac3 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -108,6 +108,7 @@ extern StructRNA RNA_BuildModifier; extern StructRNA RNA_ByteColorAttribute; extern StructRNA RNA_ByteColorAttributeValue; extern StructRNA RNA_CacheFile; +extern StructRNA RNA_CacheFileLayer; extern StructRNA RNA_Camera; extern StructRNA RNA_CameraDOFSettings; extern StructRNA RNA_CastModifier; diff --git a/source/blender/makesrna/RNA_enum_items.h b/source/blender/makesrna/RNA_enum_items.h index 531af92c544..baa9ddba1be 100644 --- a/source/blender/makesrna/RNA_enum_items.h +++ b/source/blender/makesrna/RNA_enum_items.h @@ -72,6 +72,7 @@ DEF_ENUM(rna_enum_image_generated_type_items) DEF_ENUM(rna_enum_normal_space_items) DEF_ENUM(rna_enum_normal_swizzle_items) DEF_ENUM(rna_enum_bake_save_mode_items) +DEF_ENUM(rna_enum_bake_margin_type_items) DEF_ENUM(rna_enum_bake_target_items) DEF_ENUM(rna_enum_views_format_items) diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index da07f1043a7..fcae1009c8b 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -35,7 +35,9 @@ struct bNodeType; #define DEF_ENUM(id) extern const EnumPropertyItem id[]; #include "RNA_enum_items.h" -extern const EnumPropertyItem *rna_enum_attribute_domain_itemf(struct ID *id, bool *r_free); +extern const EnumPropertyItem *rna_enum_attribute_domain_itemf(struct ID *id, + bool include_instances, + bool *r_free); /** * For ID filters (#FILTER_ID_AC, #FILTER_ID_AR, ...) an int isn't enough. This version allows 64 diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index 96e37dfebbb..6b134977c5a 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -907,7 +907,7 @@ static void rna_def_action(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_float_sdna(prop, NULL, "frame_start"); RNA_def_property_float_funcs(prop, NULL, "rna_Action_start_frame_set", NULL); - RNA_def_property_ui_range(prop, MINFRAME, MAXFRAME, 100, 0); + RNA_def_property_ui_range(prop, MINFRAME, MAXFRAME, 100, 2); RNA_def_property_ui_text( prop, "Start Frame", "The start frame of the manually set intended playback range"); RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); @@ -916,7 +916,7 @@ static void rna_def_action(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_float_sdna(prop, NULL, "frame_end"); RNA_def_property_float_funcs(prop, NULL, "rna_Action_end_frame_set", NULL); - RNA_def_property_ui_range(prop, MINFRAME, MAXFRAME, 100, 0); + RNA_def_property_ui_range(prop, MINFRAME, MAXFRAME, 100, 2); RNA_def_property_ui_text( prop, "End Frame", "The end frame of the manually set intended playback range"); RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c index 1511921cef0..0525d2f6fb1 100644 --- a/source/blender/makesrna/intern/rna_animviz.c +++ b/source/blender/makesrna/intern/rna_animviz.c @@ -207,6 +207,8 @@ static void rna_def_animviz_paths(BlenderRNA *brna) RNA_def_struct_ui_text( srna, "Motion Path Settings", "Motion Path settings for animation visualization"); + RNA_define_lib_overridable(true); + /* Enums */ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "path_type"); @@ -301,6 +303,8 @@ static void rna_def_animviz_paths(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text( prop, "Has Motion Paths", "Are there any bone paths that will need updating (read-only)"); + + RNA_define_lib_overridable(false); } /* --- */ @@ -312,6 +316,7 @@ void rna_def_animviz_common(StructRNA *srna) prop = RNA_def_property(srna, "animation_visualization", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "avs"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Animation Visualization", "Animation data for this data-block"); } @@ -328,6 +333,7 @@ static void rna_def_animviz(BlenderRNA *brna) /* motion path settings (nested struct) */ prop = RNA_def_property(srna, "motion_path", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_struct_type(prop, "AnimVizMotionPaths"); RNA_def_property_pointer_funcs(prop, "rna_AnimViz_motion_paths_get", NULL, NULL, NULL); RNA_def_property_ui_text(prop, "Motion Paths", "Motion Path settings for visualization"); diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c index 883aea21ff4..58be91a9794 100644 --- a/source/blender/makesrna/intern/rna_attribute.c +++ b/source/blender/makesrna/intern/rna_attribute.c @@ -271,7 +271,9 @@ static int rna_Attribute_type_get(PointerRNA *ptr) return layer->type; } -const EnumPropertyItem *rna_enum_attribute_domain_itemf(ID *id, bool *r_free) +const EnumPropertyItem *rna_enum_attribute_domain_itemf(ID *id, + bool include_instances, + bool *r_free) { EnumPropertyItem *item = NULL; const EnumPropertyItem *domain_item = NULL; @@ -293,6 +295,9 @@ const EnumPropertyItem *rna_enum_attribute_domain_itemf(ID *id, bool *r_free) if (id_type == ID_ME && ELEM(domain_item->value, ATTR_DOMAIN_CURVE)) { continue; } + if (!include_instances && domain_item->value == ATTR_DOMAIN_INSTANCE) { + continue; + } if (domain_item->value == ATTR_DOMAIN_POINT && id_type == ID_ME) { RNA_enum_item_add(&item, &totitem, &mesh_vertex_domain_item); @@ -312,7 +317,7 @@ static const EnumPropertyItem *rna_Attribute_domain_itemf(bContext *UNUSED(C), PropertyRNA *UNUSED(prop), bool *r_free) { - return rna_enum_attribute_domain_itemf(ptr->owner_id, r_free); + return rna_enum_attribute_domain_itemf(ptr->owner_id, true, r_free); } static int rna_Attribute_domain_get(PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_cachefile.c b/source/blender/makesrna/intern/rna_cachefile.c index 74d924b8937..2f8fc004d85 100644 --- a/source/blender/makesrna/intern/rna_cachefile.c +++ b/source/blender/makesrna/intern/rna_cachefile.c @@ -32,6 +32,7 @@ #ifdef RNA_RUNTIME +# include "BLI_math.h" # include "BLI_string.h" # include "BKE_cachefile.h" @@ -54,6 +55,14 @@ static void rna_CacheFile_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poin WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); } +static void rna_CacheFileLayer_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +{ + CacheFile *cache_file = (CacheFile *)ptr->owner_id; + + DEG_id_tag_update(&cache_file->id, ID_RECALC_COPY_ON_WRITE); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); +} + static void rna_CacheFile_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr) { rna_CacheFile_update(bmain, scene, ptr); @@ -66,6 +75,91 @@ static void rna_CacheFile_object_paths_begin(CollectionPropertyIterator *iter, P rna_iterator_listbase_begin(iter, &cache_file->object_paths, NULL); } +static PointerRNA rna_CacheFile_active_layer_get(PointerRNA *ptr) +{ + CacheFile *cache_file = (CacheFile *)ptr->owner_id; + return rna_pointer_inherit_refine( + ptr, &RNA_CacheFileLayer, BKE_cachefile_get_active_layer(cache_file)); +} + +static void rna_CacheFile_active_layer_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *reports) +{ + CacheFile *cache_file = (CacheFile *)ptr->owner_id; + int index = BLI_findindex(&cache_file->layers, value.data); + if (index == -1) { + BKE_reportf(reports, + RPT_ERROR, + "Layer '%s' not found in object '%s'", + ((CacheFileLayer *)value.data)->filepath, + cache_file->id.name + 2); + return; + } + + cache_file->active_layer = index + 1; +} + +static int rna_CacheFile_active_layer_index_get(PointerRNA *ptr) +{ + CacheFile *cache_file = (CacheFile *)ptr->owner_id; + return cache_file->active_layer - 1; +} + +static void rna_CacheFile_active_layer_index_set(PointerRNA *ptr, int value) +{ + CacheFile *cache_file = (CacheFile *)ptr->owner_id; + cache_file->active_layer = value + 1; +} + +static void rna_CacheFile_active_layer_index_range( + PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax)) +{ + CacheFile *cache_file = (CacheFile *)ptr->owner_id; + + *min = 0; + *max = max_ii(0, BLI_listbase_count(&cache_file->layers) - 1); +} + +static void rna_CacheFileLayer_hidden_flag_set(PointerRNA *ptr, const bool value) +{ + CacheFileLayer *layer = (CacheFileLayer *)ptr->data; + + if (value) { + layer->flag |= CACHEFILE_LAYER_HIDDEN; + } + else { + layer->flag &= ~CACHEFILE_LAYER_HIDDEN; + } +} + +static CacheFileLayer *rna_CacheFile_layer_new(CacheFile *cache_file, + bContext *C, + ReportList *reports, + const char *filepath) +{ + CacheFileLayer *layer = BKE_cachefile_add_layer(cache_file, filepath); + if (layer == NULL) { + BKE_reportf( + reports, RPT_ERROR, "Cannot add a layer to CacheFile '%s'", cache_file->id.name + 2); + return NULL; + } + + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + BKE_cachefile_reload(depsgraph, cache_file); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + return layer; +} + +static void rna_CacheFile_layer_remove(CacheFile *cache_file, bContext *C, PointerRNA *layer_ptr) +{ + CacheFileLayer *layer = layer_ptr->data; + BKE_cachefile_remove_layer(cache_file, layer); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + BKE_cachefile_reload(depsgraph, cache_file); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); +} + #else /* cachefile.object_paths */ @@ -94,6 +188,61 @@ static void rna_def_cachefile_object_paths(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_struct_ui_text(srna, "Object Paths", "Collection of object paths"); } +static void rna_def_cachefile_layer(BlenderRNA *brna) +{ + StructRNA *srna = RNA_def_struct(brna, "CacheFileLayer", NULL); + RNA_def_struct_sdna(srna, "CacheFileLayer"); + RNA_def_struct_ui_text( + srna, + "Cache Layer", + "Layer of the cache, used to load or override data from the first the first layer"); + + PropertyRNA *prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); + RNA_def_property_ui_text(prop, "File Path", "Path to the archive"); + RNA_def_property_update(prop, 0, "rna_CacheFileLayer_update"); + + prop = RNA_def_property(srna, "hide_layer", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", CACHEFILE_LAYER_HIDDEN); + RNA_def_property_boolean_funcs(prop, NULL, "rna_CacheFileLayer_hidden_flag_set"); + RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1); + RNA_def_property_ui_text(prop, "Hide Layer", "Do not load data from this layer"); + RNA_def_property_update(prop, 0, "rna_CacheFileLayer_update"); +} + +static void rna_def_cachefile_layers(BlenderRNA *brna, PropertyRNA *cprop) +{ + RNA_def_property_srna(cprop, "CacheFileLayers"); + StructRNA *srna = RNA_def_struct(brna, "CacheFileLayers", NULL); + RNA_def_struct_sdna(srna, "CacheFile"); + RNA_def_struct_ui_text(srna, "Cache Layers", "Collection of cache layers"); + + PropertyRNA *prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "CacheFileLayer"); + RNA_def_property_pointer_funcs( + prop, "rna_CacheFile_active_layer_get", "rna_CacheFile_active_layer_set", NULL, NULL); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Active Layer", "Active layer of the CacheFile"); + + /* Add a layer. */ + FunctionRNA *func = RNA_def_function(srna, "new", "rna_CacheFile_layer_new"); + RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT); + RNA_def_function_ui_description(func, "Add a new layer"); + PropertyRNA *parm = RNA_def_string( + func, "filepath", "File Path", 0, "", "File path to the archive used as a layer"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + /* Return type. */ + parm = RNA_def_pointer(func, "layer", "CacheFileLayer", "", "Newly created layer"); + RNA_def_function_return(func, parm); + + /* Remove a layer. */ + func = RNA_def_function(srna, "remove", "rna_CacheFile_layer_remove"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + RNA_def_function_ui_description(func, "Remove an existing layer from the cache file"); + parm = RNA_def_pointer(func, "layer", "CacheFileLayer", "", "Layer to remove"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); +} + static void rna_def_cachefile(BlenderRNA *brna) { StructRNA *srna = RNA_def_struct(brna, "CacheFile", "ID"); @@ -234,6 +383,23 @@ static void rna_def_cachefile(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_CacheFile_update"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + /* ----------------- Alembic Layers ----------------- */ + + prop = RNA_def_property(srna, "layers", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "layers", NULL); + RNA_def_property_struct_type(prop, "CacheFileLayer"); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); + RNA_def_property_ui_text(prop, "Cache Layers", "Layers of the cache"); + rna_def_cachefile_layers(brna, prop); + + prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_int_sdna(prop, NULL, "active_layer"); + RNA_def_property_int_funcs(prop, + "rna_CacheFile_active_layer_index_get", + "rna_CacheFile_active_layer_index_set", + "rna_CacheFile_active_layer_index_range"); + RNA_define_lib_overridable(false); rna_def_cachefile_object_paths(brna, prop); @@ -245,6 +411,7 @@ void RNA_def_cachefile(BlenderRNA *brna) { rna_def_cachefile(brna); rna_def_alembic_object_path(brna); + rna_def_cachefile_layer(brna); } #endif diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index d3175c445a9..0e2b64fbca4 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -1014,7 +1014,7 @@ static void rna_FKeyframe_points_add(ID *id, FCurve *fcu, Main *bmain, int tot) fcu->totvert += tot; while (tot--) { - /* defaults, no userprefs gives predictable results for API */ + /* Defaults, ignoring user-preference gives predictable results for API. */ bezt->f1 = bezt->f2 = bezt->f3 = SELECT; bezt->ipo = BEZT_IPO_BEZ; bezt->h1 = bezt->h2 = HD_AUTO_ANIM; diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index e06aac31124..e4e594cd8cf 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -3211,6 +3211,12 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna) prop, "Boundaries", "Filter feature lines based on face mark boundaries"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + prop = RNA_def_property(srna, "use_face_mark_keep_contour", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna( + prop, NULL, "calculation_flags", LRT_FILTER_FACE_MARK_KEEP_CONTOUR); + RNA_def_property_ui_text(prop, "Keep Contour", "Preserve contour lines while filtering"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + prop = RNA_def_property(srna, "chaining_image_threshold", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_ui_text( prop, @@ -3231,6 +3237,12 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna) prop, "Use Geometry Space", "Use geometry distance for chaining instead of image space"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + prop = RNA_def_property(srna, "use_detail_preserve", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_CHAIN_PRESERVE_DETAILS); + RNA_def_property_ui_text( + prop, "Preserve Details", "Keep the zig-zag \"noise\" in initial chaining"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + prop = RNA_def_property(srna, "use_overlap_edge_type_support", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_ALLOW_OVERLAP_EDGE_TYPES); RNA_def_property_ui_text(prop, @@ -3444,6 +3456,21 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna) prop, "Image Boundary Trimming", "Trim all edges right at the boundary of image(including overscan region)"); + + prop = RNA_def_property(srna, "use_back_face_culling", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_USE_BACK_FACE_CULLING); + RNA_def_property_ui_text( + prop, + "Back Face Culling", + "Remove all back faces to speed up calculation, this will create edges in " + "different occlusion levels than when disabled"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "use_invert_collection", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_GPENCIL_INVERT_COLLECTION); + RNA_def_property_ui_text(prop, + "Invert Collection Filtering", + "Select everything except lines from specified collection"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); RNA_define_lib_overridable(false); diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index a0aeead165b..f7f161dcb16 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -999,6 +999,30 @@ static int rna_MeshSkinVertexLayer_data_length(PointerRNA *ptr) /* End skin vertices */ +/* Vertex creases */ +DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_crease, vdata, CD_CREASE) + +static char *rna_VertCustomData_data_path(PointerRNA *ptr, const char *collection, int type); +static char *rna_MeshVertexCreaseLayer_path(PointerRNA *ptr) +{ + return rna_VertCustomData_data_path(ptr, "vertex_creases", CD_CREASE); +} + +static void rna_MeshVertexCreaseLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + Mesh *me = rna_mesh(ptr); + CustomDataLayer *layer = (CustomDataLayer *)ptr->data; + rna_iterator_array_begin(iter, layer->data, sizeof(float), me->totvert, 0, NULL); +} + +static int rna_MeshVertexCreaseLayer_data_length(PointerRNA *ptr) +{ + Mesh *me = rna_mesh(ptr); + return me->totvert; +} + +/* End vertex creases */ + /* Paint mask */ DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_paint_mask, vdata, CD_PAINT_MASK) @@ -1303,6 +1327,32 @@ static char *rna_LoopCustomData_data_path(PointerRNA *ptr, const char *collectio return NULL; } +static void rna_Mesh_vertex_normals_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + const Mesh *mesh = rna_mesh(ptr); + const float(*normals)[3] = BKE_mesh_vertex_normals_ensure(mesh); + rna_iterator_array_begin(iter, (void *)normals, sizeof(float[3]), mesh->totvert, false, NULL); +} + +static int rna_Mesh_vertex_normals_length(PointerRNA *ptr) +{ + const Mesh *mesh = rna_mesh(ptr); + return mesh->totvert; +} + +static void rna_Mesh_poly_normals_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + const Mesh *mesh = rna_mesh(ptr); + const float(*normals)[3] = BKE_mesh_poly_normals_ensure(mesh); + rna_iterator_array_begin(iter, (void *)normals, sizeof(float[3]), mesh->totpoly, false, NULL); +} + +static int rna_Mesh_poly_normals_length(PointerRNA *ptr) +{ + const Mesh *mesh = rna_mesh(ptr); + return mesh->totpoly; +} + static char *rna_MeshUVLoop_path(PointerRNA *ptr) { return rna_LoopCustomData_data_path(ptr, "uv_layers", CD_MLOOPUV); @@ -1664,6 +1714,7 @@ static void UNUSED_FUNCTION(rna_mesh_unused)(void) (void)rna_Mesh_face_map_active_index_set; (void)rna_Mesh_face_map_active_index_get; (void)rna_Mesh_face_map_active_set; + (void)rna_Mesh_vertex_crease_index_range; /* end unused function block */ } @@ -2535,6 +2586,20 @@ static void rna_def_mesh_polygons(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } +/* Defines a read-only vector type since normals should not be modified manually. */ +static void rna_def_normal_layer_value(BlenderRNA *brna) +{ + StructRNA *srna = RNA_def_struct(brna, "MeshNormalValue", NULL); + RNA_def_struct_sdna(srna, "vec3f"); + RNA_def_struct_ui_text(srna, "Mesh Normal Vector", "Vector in a mesh normal array"); + + PropertyRNA *prop = RNA_def_property(srna, "vector", PROP_FLOAT, PROP_DIRECTION); + RNA_def_property_ui_text(prop, "Vector", "3D vector"); + RNA_def_property_float_sdna(prop, NULL, "x"); + RNA_def_property_array(prop, 3); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); +} + static void rna_def_loop_colors(BlenderRNA *brna, PropertyRNA *cprop) { StructRNA *srna; @@ -2882,6 +2947,40 @@ static void rna_def_skin_vertices(BlenderRNA *brna, PropertyRNA *UNUSED(cprop)) RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all"); } +static void rna_def_vertex_creases(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "MeshVertexCreaseLayer", NULL); + RNA_def_struct_ui_text(srna, "Mesh Vertex Crease Layer", "Per-vertex crease"); + RNA_def_struct_sdna(srna, "CustomDataLayer"); + RNA_def_struct_path_func(srna, "rna_MeshVertexCreaseLayer_path"); + + prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "MeshVertexCrease"); + RNA_def_property_ui_text(prop, "Data", ""); + RNA_def_property_collection_funcs(prop, + "rna_MeshVertexCreaseLayer_data_begin", + "rna_iterator_array_next", + "rna_iterator_array_end", + "rna_iterator_array_get", + "rna_MeshVertexCreaseLayer_data_length", + NULL, + NULL, + NULL); + + /* VertexCrease struct */ + srna = RNA_def_struct(brna, "MeshVertexCrease", NULL); + RNA_def_struct_sdna(srna, "MFloatProperty"); + RNA_def_struct_ui_text(srna, "Float Property", ""); + + prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "f"); + RNA_def_property_ui_text(prop, "Value", ""); + RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all"); +} + static void rna_def_paint_mask(BlenderRNA *brna, PropertyRNA *UNUSED(cprop)) { StructRNA *srna; @@ -3032,6 +3131,40 @@ static void rna_def_mesh(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Polygons", "Polygons of the mesh"); rna_def_mesh_polygons(brna, prop); + rna_def_normal_layer_value(brna); + + prop = RNA_def_property(srna, "vertex_normals", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "MeshNormalValue"); + RNA_def_property_ui_text(prop, + "Vertex Normals", + "The normal direction of each vertex, defined as the average of the " + "surrounding face normals"); + RNA_def_property_collection_funcs(prop, + "rna_Mesh_vertex_normals_begin", + "rna_iterator_array_next", + "rna_iterator_array_end", + "rna_iterator_array_get", + "rna_Mesh_vertex_normals_length", + NULL, + NULL, + NULL); + + prop = RNA_def_property(srna, "polygon_normals", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "MeshNormalValue"); + RNA_def_property_ui_text(prop, + "Polygon Normals", + "The normal direction of each polygon, defined by the winding order " + "and position of its vertices"); + RNA_def_property_collection_funcs(prop, + "rna_Mesh_poly_normals_begin", + "rna_iterator_array_next", + "rna_iterator_array_end", + "rna_iterator_array_get", + "rna_Mesh_poly_normals_length", + NULL, + NULL, + NULL); + prop = RNA_def_property(srna, "loop_triangles", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "runtime.looptris.array", "runtime.looptris.len"); RNA_def_property_struct_type(prop, "MeshLoopTriangle"); @@ -3263,6 +3396,24 @@ static void rna_def_mesh(BlenderRNA *brna) rna_def_skin_vertices(brna, prop); /* End skin vertices */ + /* Vertex Crease */ + prop = RNA_def_property(srna, "vertex_creases", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "MeshVertexCreaseLayer"); + RNA_def_property_collection_sdna(prop, NULL, "vdata.layers", "vdata.totlayer"); + RNA_def_property_collection_funcs(prop, + "rna_Mesh_vertex_creases_begin", + NULL, + NULL, + NULL, + "rna_Mesh_vertex_creases_length", + NULL, + NULL, + NULL); + RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); + RNA_def_property_ui_text(prop, "Vertex Creases", "Sharpness of the vertices"); + rna_def_vertex_creases(brna); + /* End vertex crease */ + /* Paint mask */ prop = RNA_def_property(srna, "vertex_paint_masks", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "vdata.layers", "vdata.totlayer"); @@ -3479,6 +3630,10 @@ static void rna_def_mesh(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "cd_flag", ME_CDFLAG_EDGE_BWEIGHT); RNA_def_property_ui_text(prop, "Store Edge Bevel Weight", ""); + prop = RNA_def_property(srna, "use_customdata_vertex_crease", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "cd_flag", ME_CDFLAG_VERT_CREASE); + RNA_def_property_ui_text(prop, "Store Vertex Crease", ""); + prop = RNA_def_property(srna, "use_customdata_edge_crease", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "cd_flag", ME_CDFLAG_EDGE_CREASE); RNA_def_property_ui_text(prop, "Store Edge Crease", ""); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 39ed3610070..30b5827971a 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1758,7 +1758,7 @@ static void rna_def_modifier_subsurf(BlenderRNA *brna) prop = RNA_def_property(srna, "use_creases", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", eSubsurfModifierFlag_UseCrease); RNA_def_property_ui_text( - prop, "Use Creases", "Use mesh edge crease information to sharpen edges"); + prop, "Use Creases", "Use mesh crease information to sharpen edges or corners"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "use_custom_normals", PROP_BOOLEAN, PROP_NONE); @@ -1973,7 +1973,7 @@ static void rna_def_modifier_multires(BlenderRNA *brna) prop = RNA_def_property(srna, "use_creases", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", eMultiresModifierFlag_UseCrease); RNA_def_property_ui_text( - prop, "Use Creases", "Use mesh edge crease information to sharpen edges"); + prop, "Use Creases", "Use mesh crease information to sharpen edges or corners"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "use_custom_normals", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index ecbeadf1fa4..c506c35e281 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -10139,6 +10139,33 @@ static void def_geo_curve_primitive_circle(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } +static void def_geo_curve_primitive_arc(StructRNA *srna) +{ + static const EnumPropertyItem mode_items[] = { + + {GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS, + "POINTS", + ICON_NONE, + "Points", + "Define arc by 3 points on circle. Arc is calculated between start and end points"}, + {GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_RADIUS, + "RADIUS", + ICON_NONE, + "Radius", + "Define radius with a float"}, + {0, NULL, 0, NULL, NULL}, + }; + + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeGeometryCurvePrimitiveArc", "storage"); + + prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, mode_items); + RNA_def_property_ui_text(prop, "Mode", "Method used to determine radius and placement"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); +} + static void def_geo_curve_primitive_line(StructRNA *srna) { static const EnumPropertyItem mode_items[] = { @@ -11377,6 +11404,71 @@ static void def_geo_realize_instances(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update"); } +static void def_geo_field_at_index(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "custom1"); + RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items); + RNA_def_property_ui_text(prop, "Domain", "Domain the field is evaluated in"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update"); + + 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_GeometryNodeAttributeFill_type_itemf"); + RNA_def_property_ui_text(prop, "Data Type", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update"); +} + +static void def_geo_scale_elements(StructRNA *srna) +{ + PropertyRNA *prop; + + static const EnumPropertyItem domain_items[] = { + {ATTR_DOMAIN_FACE, + "FACE", + ICON_NONE, + "Face", + "Scale individual faces or neighboring face islands"}, + {ATTR_DOMAIN_EDGE, + "EDGE", + ICON_NONE, + "Edge", + "Scale individual edges or neighboring edge islands"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem scale_mode_items[] = { + {GEO_NODE_SCALE_ELEMENTS_UNIFORM, + "UNIFORM", + ICON_NONE, + "Uniform", + "Scale elements by the same factor in every direction"}, + {GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS, + "SINGLE_AXIS", + ICON_NONE, + "Single Axis", + "Scale elements in a single direction"}, + {0, NULL, 0, NULL, NULL}, + + }; + + prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "custom1"); + RNA_def_property_enum_items(prop, domain_items); + RNA_def_property_enum_default(prop, ATTR_DOMAIN_FACE); + RNA_def_property_ui_text(prop, "Domain", "Element type to transform"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update"); + + prop = RNA_def_property(srna, "scale_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "custom2"); + RNA_def_property_enum_items(prop, scale_mode_items); + RNA_def_property_ui_text(prop, "Scale Mode", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update"); +} + /* -------------------------------------------------------------------------- */ static void rna_def_shader_node(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 63c4774d0e5..ec20fa54a44 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -729,7 +729,7 @@ void rna_Object_me_eval_info( } if (me_eval) { - ret = BKE_mesh_runtime_debug_info(me_eval); + ret = BKE_mesh_debug_info(me_eval); if (ret) { strcpy(result, ret); MEM_freeN(ret); diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 285f6365ea1..3e150d03bf0 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -3117,7 +3117,11 @@ static void rna_def_number_property(StructRNA *srna, PropertyType type) prop = RNA_def_property(srna, "precision", PROP_INT, PROP_UNSIGNED); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_int_funcs(prop, "rna_FloatProperty_precision_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Precision", "Number of digits after the dot used by buttons"); + RNA_def_property_ui_text(prop, + "Precision", + "Number of digits after the dot used by buttons. Fraction is " + "automatically hidden for exact integer values of fields with unit " + "'NONE' or 'TIME' (frame count) and step divisible by 100"); } } diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 699c3f01db5..18972bb22ef 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -432,6 +432,16 @@ const EnumPropertyItem rna_enum_normal_swizzle_items[] = { {0, NULL, 0, NULL, NULL}, }; +const EnumPropertyItem rna_enum_bake_margin_type_items[] = { + {R_BAKE_ADJACENT_FACES, + "ADJACENT_FACES", + 0, + "Adjacent Faces", + "Use pixels from adjacent faces across UV seams"}, + {R_BAKE_EXTEND, "EXTEND", 0, "Extend", "Extend border pixels outwards"}, + {0, NULL, 0, NULL, NULL}, +}; + const EnumPropertyItem rna_enum_bake_target_items[] = { {R_BAKE_TARGET_IMAGE_TEXTURES, "IMAGE_TEXTURES", @@ -5078,6 +5088,11 @@ static void rna_def_bake_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Margin", "Extends the baked result as a post process filter"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + prop = RNA_def_property(srna, "margin_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_bake_margin_type_items); + RNA_def_property_ui_text(prop, "Margin Type", "Algorithm to extend the baked result"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + prop = RNA_def_property(srna, "max_ray_distance", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_range(prop, 0.0, FLT_MAX); RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 3); @@ -5869,6 +5884,16 @@ static void rna_def_scene_render_data(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem bake_margin_type_items[] = { + {R_BAKE_ADJACENT_FACES, + "ADJACENT_FACES", + 0, + "Adjacent Faces", + "Use pixels from adjacent faces across UV seams"}, + {R_BAKE_EXTEND, "EXTEND", 0, "Extend", "Extend border pixels outwards"}, + {0, NULL, 0, NULL, NULL}, + }; + static const EnumPropertyItem pixel_size_items[] = { {0, "AUTO", 0, "Automatic", "Automatic pixel size, depends on the user interface scale"}, {1, "1", 0, "1x", "Render at full resolution"}, @@ -6284,11 +6309,17 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "bake_margin", PROP_INT, PROP_PIXEL); - RNA_def_property_int_sdna(prop, NULL, "bake_filter"); + RNA_def_property_int_sdna(prop, NULL, "bake_margin"); RNA_def_property_range(prop, 0, 64); RNA_def_property_ui_text(prop, "Margin", "Extends the baked result as a post process filter"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + prop = RNA_def_property(srna, "bake_margin_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "bake_margin_type"); + RNA_def_property_enum_items(prop, bake_margin_type_items); + RNA_def_property_ui_text(prop, "Margin Type", "Algorithm to generate the margin"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + prop = RNA_def_property(srna, "bake_bias", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "bake_biasdist"); RNA_def_property_range(prop, 0.0, 1000.0); @@ -7903,8 +7934,10 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "clip"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "MovieClip"); - RNA_def_property_ui_text( - prop, "Active Movie Clip", "Active movie clip used for constraints and viewport drawing"); + RNA_def_property_ui_text(prop, + "Active Movie Clip", + "Active Movie Clip that can be used by motion tracking constraints " + "or as a camera's background image"); RNA_def_property_update(prop, NC_SCENE | ND_DRAW_RENDER_VIEWPORT, NULL); /* color management */ diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index d81b852c192..8ff65f7f8e2 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -752,7 +752,7 @@ static void rna_def_paint(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Cavity Mask", "Mask painting according to mesh geometry cavity"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); - prop = RNA_def_property(srna, "tile_offset", PROP_FLOAT, PROP_XYZ); + prop = RNA_def_property(srna, "tile_offset", PROP_FLOAT, PROP_XYZ_LENGTH); RNA_def_property_float_sdna(prop, NULL, "tile_offset"); RNA_def_property_array(prop, 3); RNA_def_property_range(prop, 0.01, FLT_MAX); diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index a406e867d6c..5bf778d1962 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -619,6 +619,19 @@ static void rna_uiTemplateCacheFileTimeSettings(uiLayout *layout, uiTemplateCacheFileTimeSettings(layout, &fileptr); } +static void rna_uiTemplateCacheFileLayers(uiLayout *layout, + bContext *C, + PointerRNA *ptr, + const char *propname) +{ + PointerRNA fileptr; + if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) { + return; + } + + uiTemplateCacheFileLayers(layout, C, &fileptr); +} + static void rna_uiTemplatePathBuilder(uiLayout *layout, PointerRNA *ptr, const char *propname, @@ -1847,6 +1860,11 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function_ui_description(func, "Show cache files time settings"); api_ui_item_rna_common(func); + func = RNA_def_function(srna, "template_cache_file_layers", "rna_uiTemplateCacheFileLayers"); + RNA_def_function_ui_description(func, "Show cache files override layers properties"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + api_ui_item_rna_common(func); + func = RNA_def_function(srna, "template_recent_files", "uiTemplateRecentFiles"); RNA_def_function_ui_description(func, "Show list of recently saved .blend files"); RNA_def_int(func, "rows", 5, 1, INT_MAX, "", "Maximum number of items to show", 1, INT_MAX); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index eb31e66a4c0..02119975ad3 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -6433,6 +6433,14 @@ static void rna_def_userdef_experimental(BlenderRNA *brna) "Enable some extra fields in the Asset Browser to aid in debugging"); RNA_def_property_update(prop, 0, "rna_userdef_ui_update"); + prop = RNA_def_property(srna, "use_asset_indexing", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "no_asset_indexing", 1); + RNA_def_property_ui_text(prop, + "Asset Indexing", + "Disabling the asset indexer forces every asset library refresh to " + "completely reread assets from disk"); + RNA_def_property_update(prop, 0, "rna_userdef_ui_update"); + prop = RNA_def_property(srna, "use_override_templates", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "use_override_templates", 1); RNA_def_property_ui_text( diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 8c128292fd7..c64a47fc2ab 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -965,7 +965,7 @@ static void rna_wmKeyMapItem_keymodifier_set(PointerRNA *ptr, int value) if (value == EVT_ESCKEY) { /* pass */ } - else if (value >= EVT_AKEY) { + else if (ISKEYBOARD(value) && !ISKEYMODIFIER(value)) { kmi->keymodifier = value; } else { diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc index ec797344f30..d7c253cb1f0 100644 --- a/source/blender/modifiers/intern/MOD_boolean.cc +++ b/source/blender/modifiers/intern/MOD_boolean.cc @@ -248,9 +248,14 @@ static BMesh *BMD_mesh_bm_create( BMeshCreateParams bmesh_create_params = {0}; BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params); - /* Needed so active layers are set based on `mesh` not `mesh_operand_ob`, - * otherwise the wrong active render layer is used, see T92384. */ - BM_mesh_copy_init_customdata_from_mesh(bm, mesh, &allocsize); + /* Keep `mesh` first, needed so active layers are set based on `mesh` not `mesh_operand_ob`, + * otherwise the wrong active render layer is used, see T92384. + * + * NOTE: while initializing customer data layers the is not essential, + * it avoids the overhead of having to re-allocate #BMHeader.data when the 2nd mesh is added + * (if it contains additional custom-data layers). */ + const Mesh *mesh_array[2] = {mesh, mesh_operand_ob}; + BM_mesh_copy_init_customdata_from_mesh_array(bm, mesh_array, ARRAY_SIZE(mesh_array), &allocsize); BMeshFromMeshParams bmesh_from_mesh_params = {0}; diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index 00f39e58b4d..e1459ccba6d 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -392,6 +392,22 @@ static void render_procedural_panel_draw(const bContext *C, Panel *panel) uiTemplateCacheFileProcedural(layout, C, &fileptr); } +static void override_layers_panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ob_ptr; + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr); + + PointerRNA fileptr; + if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) { + return; + } + + uiLayoutSetPropSep(layout, true); + uiTemplateCacheFileLayers(layout, C, &fileptr); +} + static void panelRegister(ARegionType *region_type) { PanelType *panel_type = modifier_panel_register( @@ -405,6 +421,12 @@ static void panelRegister(ARegionType *region_type) panel_type); modifier_subpanel_register( region_type, "velocity", "Velocity", NULL, velocity_panel_draw, panel_type); + modifier_subpanel_register(region_type, + "override_layers", + "Override Layers", + NULL, + override_layers_panel_draw, + panel_type); } static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md) diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c index 00870d076ef..b77f6b7e3e2 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.c +++ b/source/blender/modifiers/intern/MOD_subsurf.c @@ -85,6 +85,9 @@ static void requiredDataMask(Object *UNUSED(ob), r_cddata_masks->lmask |= CD_MASK_NORMAL; r_cddata_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL; } + if (smd->flags & eSubsurfModifierFlag_UseCrease) { + r_cddata_masks->vmask |= CD_MASK_CREASE; + } } static bool dependsOnNormals(ModifierData *md) diff --git a/source/blender/modifiers/intern/MOD_weld.cc b/source/blender/modifiers/intern/MOD_weld.cc index 3a06c6a649b..3199bdc834f 100644 --- a/source/blender/modifiers/intern/MOD_weld.cc +++ b/source/blender/modifiers/intern/MOD_weld.cc @@ -331,7 +331,7 @@ static void weld_assert_poly_no_vert_repetition(const WeldPoly &wp, } else { int i = 0; - while (weld_iter_loop_of_poly_next(&iter)) { + while (weld_iter_loop_of_poly_next(iter)) { verts[i++] = iter.v; } } @@ -676,7 +676,7 @@ static void weld_edge_groups_setup(const int medge_len, /** \name Weld Poly and Loop API * \{ */ -static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter, +static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter &iter, const WeldPoly &wp, Span wloop, Span mloop, @@ -687,19 +687,19 @@ static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter, return false; } - iter->loop_start = wp.loop_start; - iter->loop_end = wp.loop_end; - iter->wloop = wloop; - iter->mloop = mloop; - iter->loop_map = loop_map; - iter->group = group_buffer; + iter.loop_start = wp.loop_start; + iter.loop_end = wp.loop_end; + iter.wloop = wloop; + iter.mloop = mloop; + iter.loop_map = loop_map; + iter.group = group_buffer; int group_len = 0; if (group_buffer) { /* First loop group needs more attention. */ int loop_start, loop_end, l; - loop_start = iter->loop_start; - loop_end = l = iter->loop_end; + loop_start = iter.loop_start; + loop_end = l = iter.loop_end; while (l >= loop_start) { const int loop_ctx = loop_map[l]; if (loop_ctx != OUT_OF_CONTEXT) { @@ -715,30 +715,30 @@ static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter, group_len = loop_end - l; int i = 0; while (l < loop_end) { - iter->group[i++] = ++l; + iter.group[i++] = ++l; } } } - iter->group_len = group_len; + iter.group_len = group_len; - iter->l_next = iter->loop_start; + iter.l_next = iter.loop_start; #ifdef USE_WELD_DEBUG - iter->v = OUT_OF_CONTEXT; + iter.v = OUT_OF_CONTEXT; #endif return true; } -static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter) +static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter &iter) { - int loop_end = iter->loop_end; - Span wloop = iter->wloop; - Span loop_map = iter->loop_map; - int l = iter->l_curr = iter->l_next; - if (l == iter->loop_start) { + const int loop_end = iter.loop_end; + Span wloop = iter.wloop; + Span loop_map = iter.loop_map; + int l = iter.l_curr = iter.l_next; + if (l == iter.loop_start) { /* `grupo_len` is already calculated in the first loop */ } else { - iter->group_len = 0; + iter.group_len = 0; } while (l <= loop_end) { int l_next = l + 1; @@ -749,32 +749,32 @@ static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter) l_next = wl->loop_skip_to; } if (wl->flag == ELEM_COLLAPSED) { - if (iter->group) { - iter->group[iter->group_len++] = l; + if (iter.group) { + iter.group[iter.group_len++] = l; } l = l_next; continue; } #ifdef USE_WELD_DEBUG - BLI_assert(iter->v != wl->vert); + BLI_assert(iter.v != wl->vert); #endif - iter->v = wl->vert; - iter->e = wl->edge; - iter->type = 1; + iter.v = wl->vert; + iter.e = wl->edge; + iter.type = 1; } else { - const MLoop *ml = &iter->mloop[l]; + const MLoop &ml = iter.mloop[l]; #ifdef USE_WELD_DEBUG - BLI_assert((uint)iter->v != ml->v); + BLI_assert((uint)iter.v != ml.v); #endif - iter->v = ml->v; - iter->e = ml->e; - iter->type = 0; + iter.v = ml.v; + iter.e = ml.e; + iter.type = 0; } - if (iter->group) { - iter->group[iter->group_len++] = l; + if (iter.group) { + iter.group[iter.group_len++] = l; } - iter->l_next = l_next; + iter.l_next = l_next; return true; } @@ -1026,18 +1026,13 @@ static void weld_poly_loop_ctx_setup(Span mloop, MutableSpan r_vlinks, WeldMesh *r_weld_mesh) { - int poly_kill_len, loop_kill_len, wpoly_len, wpoly_new_len; - - WeldPoly *wpoly_new; - WeldLoop *wl; - MutableSpan wpoly = r_weld_mesh->wpoly; MutableSpan wloop = r_weld_mesh->wloop; - wpoly_new = r_weld_mesh->wpoly_new; - wpoly_len = r_weld_mesh->wpoly_len; - wpoly_new_len = 0; - poly_kill_len = 0; - loop_kill_len = 0; + WeldPoly *wpoly_new = r_weld_mesh->wpoly_new; + int wpoly_len = r_weld_mesh->wpoly_len; + int wpoly_new_len = 0; + int poly_kill_len = 0; + int loop_kill_len = 0; Span loop_map = r_weld_mesh->loop_map; @@ -1051,7 +1046,7 @@ static void weld_poly_loop_ctx_setup(Span mloop, int poly_len = wp.len; int ctx_verts_len = 0; - wl = &wloop[ctx_loops_ofs]; + WeldLoop *wl = &wloop[ctx_loops_ofs]; for (int l = ctx_loops_len; l--; wl++) { const int edge_dest = wl->edge; if (edge_dest == ELEM_COLLAPSED) { @@ -1108,7 +1103,7 @@ static void weld_poly_loop_ctx_setup(Span mloop, /* Setup Polygon Overlap. */ - int wpoly_and_new_len = wpoly_len + wpoly_new_len; + const int wpoly_and_new_len = wpoly_len + wpoly_new_len; r_vlinks.fill({0, 0}); MutableSpan v_links = r_vlinks; @@ -1116,8 +1111,8 @@ static void weld_poly_loop_ctx_setup(Span mloop, for (const int i : IndexRange(wpoly_and_new_len)) { const WeldPoly &wp = wpoly[i]; WeldLoopOfPolyIter iter; - if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr)) { - while (weld_iter_loop_of_poly_next(&iter)) { + if (weld_iter_loop_of_poly_begin(iter, wp, wloop, mloop, loop_map, nullptr)) { + while (weld_iter_loop_of_poly_next(iter)) { v_links[iter.v].len++; } } @@ -1135,8 +1130,8 @@ static void weld_poly_loop_ctx_setup(Span mloop, for (const int i : IndexRange(wpoly_and_new_len)) { const WeldPoly &wp = wpoly[i]; WeldLoopOfPolyIter iter; - if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr)) { - while (weld_iter_loop_of_poly_next(&iter)) { + if (weld_iter_loop_of_poly_begin(iter, wp, wloop, mloop, loop_map, nullptr)) { + while (weld_iter_loop_of_poly_next(iter)) { link_poly_buffer[v_links[iter.v].ofs++] = i; } } @@ -1159,8 +1154,8 @@ static void weld_poly_loop_ctx_setup(Span mloop, } WeldLoopOfPolyIter iter; - weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr); - weld_iter_loop_of_poly_next(&iter); + weld_iter_loop_of_poly_begin(iter, wp, wloop, mloop, loop_map, nullptr); + weld_iter_loop_of_poly_next(iter); struct WeldGroup *link_a = &v_links[iter.v]; polys_len_a = link_a->len; if (polys_len_a == 1) { @@ -1181,7 +1176,7 @@ static void weld_poly_loop_ctx_setup(Span mloop, } WeldLoopOfPolyIter iter_b = iter; - while (weld_iter_loop_of_poly_next(&iter_b)) { + while (weld_iter_loop_of_poly_next(iter_b)) { struct WeldGroup *link_b = &v_links[iter_b.v]; polys_len_b = link_b->len; if (polys_len_b == 1) { @@ -1253,15 +1248,15 @@ static void weld_poly_loop_ctx_setup(Span mloop, /** \name Weld Mesh API * \{ */ -static void weld_mesh_context_create(const Mesh *mesh, +static void weld_mesh_context_create(const Mesh &mesh, MutableSpan vert_dest_map, const int vert_kill_len, WeldMesh *r_weld_mesh) { - Span medge{mesh->medge, mesh->totedge}; - Span mpoly{mesh->mpoly, mesh->totpoly}; - Span mloop{mesh->mloop, mesh->totloop}; - const int mvert_len = mesh->totvert; + Span medge{mesh.medge, mesh.totedge}; + Span mpoly{mesh.mpoly, mesh.totpoly}; + Span mloop{mesh.mloop, mesh.totloop}; + const int mvert_len = mesh.totvert; Vector wvert = weld_vert_ctx_alloc_and_setup(vert_dest_map, vert_kill_len); r_weld_mesh->vert_kill_len = vert_kill_len; @@ -1686,7 +1681,7 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, } WeldMesh weld_mesh; - weld_mesh_context_create(mesh, vert_dest_map, vert_kill_len, &weld_mesh); + weld_mesh_context_create(*mesh, vert_dest_map, vert_kill_len, &weld_mesh); const int result_nverts = totvert - weld_mesh.vert_kill_len; const int result_nedges = totedge - weld_mesh.edge_kill_len; @@ -1740,7 +1735,7 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, dest_index = 0; for (int i = 0; i < totedge; i++) { - int source_index = i; + const int source_index = i; int count = 0; while (i < totedge && weld_mesh.edge_groups_map[i] == OUT_OF_CONTEXT) { edge_final[i] = dest_index + count; @@ -1787,8 +1782,8 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, Array group_buffer(weld_mesh.max_poly_len); for (const int i : mpoly.index_range()) { const MPoly &mp = mpoly[i]; - int loop_start = loop_cur; - int poly_ctx = weld_mesh.poly_map[i]; + const int loop_start = loop_cur; + const int poly_ctx = weld_mesh.poly_map[i]; if (poly_ctx == OUT_OF_CONTEXT) { int mp_loop_len = mp.totloop; CustomData_copy_data(&mesh->ldata, &result->ldata, mp.loopstart, loop_cur, mp_loop_len); @@ -1802,14 +1797,14 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const WeldPoly &wp = weld_mesh.wpoly[poly_ctx]; WeldLoopOfPolyIter iter; if (!weld_iter_loop_of_poly_begin( - &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer.data())) { + iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer.data())) { continue; } if (wp.poly_dst != OUT_OF_CONTEXT) { continue; } - while (weld_iter_loop_of_poly_next(&iter)) { + while (weld_iter_loop_of_poly_next(iter)) { customdata_weld( &mesh->ldata, &result->ldata, group_buffer.data(), iter.group_len, loop_cur); int v = vert_final[iter.v]; @@ -1834,17 +1829,17 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, for (const int i : IndexRange(weld_mesh.wpoly_new_len)) { const WeldPoly &wp = weld_mesh.wpoly_new[i]; - int loop_start = loop_cur; + const int loop_start = loop_cur; WeldLoopOfPolyIter iter; if (!weld_iter_loop_of_poly_begin( - &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer.data())) { + iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer.data())) { continue; } if (wp.poly_dst != OUT_OF_CONTEXT) { continue; } - while (weld_iter_loop_of_poly_next(&iter)) { + while (weld_iter_loop_of_poly_next(iter)) { customdata_weld(&mesh->ldata, &result->ldata, group_buffer.data(), iter.group_len, loop_cur); int v = vert_final[iter.v]; int e = edge_final[iter.e]; diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index 96a5e1d87a6..9c9e3876662 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -77,6 +77,7 @@ void register_node_type_geo_curve_fill(void); void register_node_type_geo_curve_fillet(void); void register_node_type_geo_curve_handle_type_selection(void); void register_node_type_geo_curve_length(void); +void register_node_type_geo_curve_primitive_arc(void); void register_node_type_geo_curve_primitive_bezier_segment(void); void register_node_type_geo_curve_primitive_circle(void); void register_node_type_geo_curve_primitive_line(void); @@ -98,6 +99,8 @@ void register_node_type_geo_delete_geometry(void); void register_node_type_geo_distribute_points_on_faces(void); void register_node_type_geo_dual_mesh(void); void register_node_type_geo_edge_split(void); +void register_node_type_geo_field_at_index(void); +void register_node_type_geo_flip_faces(void); void register_node_type_geo_geometry_to_instance(void); void register_node_type_geo_image_texture(void); void register_node_type_geo_input_curve_handles(void); @@ -153,6 +156,7 @@ void register_node_type_geo_raycast(void); void register_node_type_geo_realize_instances(void); void register_node_type_geo_rotate_instances(void); void register_node_type_geo_sample_texture(void); +void register_node_type_geo_scale_elements(void); void register_node_type_geo_scale_instances(void); void register_node_type_geo_select_by_handle_type(void); void register_node_type_geo_separate_components(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index e3566f81e2d..06a1cf90fca 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -335,6 +335,7 @@ DefNode(GeometryNode, GEO_NODE_CONVEX_HULL, 0, "CONVEX_HULL", ConvexHull, "Conve DefNode(GeometryNode, GEO_NODE_CURVE_ENDPOINT_SELECTION, 0, "CURVE_ENDPOINT_SELECTION", CurveEndpointSelection, "Endpoint Selection", "") DefNode(GeometryNode, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, def_geo_curve_handle_type_selection, "CURVE_HANDLE_TYPE_SELECTION", CurveHandleTypeSelection, "Handle Type Selection", "") DefNode(GeometryNode, GEO_NODE_CURVE_LENGTH, 0, "CURVE_LENGTH", CurveLength, "Curve Length", "") +DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_ARC, def_geo_curve_primitive_arc, "CURVE_PRIMITIVE_ARC", CurveArc, "Arc", "") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, def_geo_curve_primitive_bezier_segment, "CURVE_PRIMITIVE_BEZIER_SEGMENT", CurvePrimitiveBezierSegment, "Bezier Segment", "") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, def_geo_curve_primitive_circle, "CURVE_PRIMITIVE_CIRCLE", CurvePrimitiveCircle, "Curve Circle", "") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_LINE, def_geo_curve_primitive_line, "CURVE_PRIMITIVE_LINE", CurvePrimitiveLine, "Curve Line", "") @@ -351,8 +352,10 @@ DefNode(GeometryNode, GEO_NODE_DELETE_GEOMETRY, def_geo_delete_geometry, "DELETE DefNode(GeometryNode, GEO_NODE_DISTRIBUTE_POINTS_ON_FACES, def_geo_distribute_points_on_faces, "DISTRIBUTE_POINTS_ON_FACES", DistributePointsOnFaces, "Distribute Points on Faces", "") DefNode(GeometryNode, GEO_NODE_ACCUMULATE_FIELD, def_geo_accumulate_field, "ACCUMULATE_FIELD", AccumulateField, "Accumulate Field", "") DefNode(GeometryNode, GEO_NODE_DUAL_MESH, 0, "DUAL_MESH", DualMesh, "Dual Mesh", "") +DefNode(GeometryNode, GEO_NODE_FIELD_AT_INDEX, def_geo_field_at_index, "FIELD_AT_INDEX", FieldAtIndex, "Field at Index", "") DefNode(GeometryNode, GEO_NODE_FILL_CURVE, def_geo_curve_fill, "FILL_CURVE", FillCurve, "Fill Curve", "") DefNode(GeometryNode, GEO_NODE_FILLET_CURVE, def_geo_curve_fillet, "FILLET_CURVE", FilletCurve, "Fillet Curve", "") +DefNode(GeometryNode, GEO_NODE_FLIP_FACES, 0, "FLIP_FACES", FlipFaces, "Flip Faces", "") DefNode(GeometryNode, GEO_NODE_GEOMETRY_TO_INSTANCE, 0, "GEOMETRY_TO_INSTANCE", GeometryToInstance, "Geometry to Instance", "") DefNode(GeometryNode, GEO_NODE_IMAGE_TEXTURE, def_geo_image_texture, "IMAGE_TEXTURE", ImageTexture, "Image Texture", "") DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_HANDLES, 0, "INPUT_CURVE_HANDLES", InputCurveHandlePositions, "Curve Handle Positions", "") @@ -404,6 +407,7 @@ DefNode(GeometryNode, GEO_NODE_RESAMPLE_CURVE, def_geo_curve_resample, "RESAMPLE DefNode(GeometryNode, GEO_NODE_REVERSE_CURVE, 0, "REVERSE_CURVE", ReverseCurve, "Reverse Curve", "") DefNode(GeometryNode, GEO_NODE_ROTATE_INSTANCES, 0, "ROTATE_INSTANCES", RotateInstances, "Rotate Instances", "") DefNode(GeometryNode, GEO_NODE_SAMPLE_CURVE, def_geo_curve_sample, "SAMPLE_CURVE", SampleCurve, "Sample Curve", "") +DefNode(GeometryNode, GEO_NODE_SCALE_ELEMENTS, def_geo_scale_elements, "SCALE_ELEMENTS", ScaleElements, "Scale Elements", "") DefNode(GeometryNode, GEO_NODE_SCALE_INSTANCES, 0, "SCALE_INSTANCES", ScaleInstances, "Scale Instances", "") DefNode(GeometryNode, GEO_NODE_SEPARATE_COMPONENTS, 0, "SEPARATE_COMPONENTS", SeparateComponents, "Separate Components", "") DefNode(GeometryNode, GEO_NODE_SEPARATE_GEOMETRY, def_geo_separate_geometry, "SEPARATE_GEOMETRY", SeparateGeometry, "Separate Geometry", "") diff --git a/source/blender/nodes/composite/nodes/node_composite_scene_time.cc b/source/blender/nodes/composite/nodes/node_composite_scene_time.cc index 845390665f2..5c53c1df237 100644 --- a/source/blender/nodes/composite/nodes/node_composite_scene_time.cc +++ b/source/blender/nodes/composite/nodes/node_composite_scene_time.cc @@ -36,4 +36,4 @@ void register_node_type_cmp_scene_time() cmp_node_type_base(&ntype, CMP_NODE_SCENE_TIME, "Scene Time", NODE_CLASS_INPUT); ntype.declare = blender::nodes::cmp_node_scene_time_declare; nodeRegisterType(&ntype); -} \ No newline at end of file +} diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt index d692bd050c8..37b43c26a86 100644 --- a/source/blender/nodes/geometry/CMakeLists.txt +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -95,6 +95,7 @@ set(SRC nodes/node_geo_curve_fillet.cc nodes/node_geo_curve_handle_type_selection.cc nodes/node_geo_curve_length.cc + nodes/node_geo_curve_primitive_arc.cc nodes/node_geo_curve_primitive_bezier_segment.cc nodes/node_geo_curve_primitive_circle.cc nodes/node_geo_curve_primitive_line.cc @@ -116,6 +117,8 @@ set(SRC nodes/node_geo_distribute_points_on_faces.cc nodes/node_geo_dual_mesh.cc nodes/node_geo_edge_split.cc + nodes/node_geo_field_at_index.cc + nodes/node_geo_flip_faces.cc nodes/node_geo_geometry_to_instance.cc nodes/node_geo_image_texture.cc nodes/node_geo_input_curve_handles.cc @@ -164,6 +167,7 @@ set(SRC nodes/node_geo_raycast.cc nodes/node_geo_realize_instances.cc nodes/node_geo_rotate_instances.cc + nodes/node_geo_scale_elements.cc nodes/node_geo_scale_instances.cc nodes/node_geo_separate_components.cc nodes/node_geo_separate_geometry.cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc index 9001cb2d1f2..840dfd2fbd3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc @@ -48,8 +48,8 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); - uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); } static void node_init(bNodeTree *UNUSED(tree), bNode *node) diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc index b4ca51d0fa7..74bdce4cef3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc @@ -43,7 +43,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node) NodeGeometryCurveSetHandles *data = MEM_cnew(__func__); data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO; - data->mode = GEO_NODE_CURVE_HANDLE_LEFT; + data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT; node->storage = data; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc index a257af4391c..d17657bfa3a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc @@ -44,7 +44,7 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_input(N_("Selection")).default_value(true).hide_value().supports_field(); b.add_input(N_("Distance Min")).min(0.0f).subtype(PROP_DISTANCE); b.add_input(N_("Density Max")).default_value(10.0f).min(0.0f); - b.add_input(N_("Density")).default_value(10.0f).supports_field(); + b.add_input(N_("Density")).default_value(10.0f).min(0.0f).supports_field(); b.add_input(N_("Density Factor")) .default_value(1.0f) .min(0.0f) diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc index 2d16c60ba86..4b6ed7b77b7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc @@ -25,11 +25,18 @@ namespace blender::nodes::node_geo_input_mesh_edge_angle_cc { static void node_declare(NodeDeclarationBuilder &b) { - b.add_output(N_("Angle")) + b.add_output(N_("Unsigned Angle")) .field_source() .description( - "The angle in radians between two faces where they meet at an edge. Flat edges and " - "Non-manifold edges have an angle of zero"); + "The shortest angle in radians between two faces where they meet at an edge. Flat edges " + "and Non-manifold edges have an angle of zero. Computing this value is faster than the " + "signed angle"); + b.add_output(N_("Signed Angle")) + .field_source() + .description( + "The signed angle in radians between two faces where they meet at an edge. Flat edges " + "and Non-manifold edges have an angle of zero. Concave angles are positive and convex " + "angles are negative. Computing this value is slower than the unsigned angle"); } struct EdgeMapEntry { @@ -38,9 +45,31 @@ struct EdgeMapEntry { int face_index_2; }; +static Array create_edge_map(const Span polys, + const Span loops, + const int total_edges) +{ + Array edge_map(total_edges, {0, 0, 0}); + + for (const int i_poly : polys.index_range()) { + const MPoly &mpoly = polys[i_poly]; + for (const MLoop &loop : loops.slice(mpoly.loopstart, mpoly.totloop)) { + EdgeMapEntry &entry = edge_map[loop.e]; + if (entry.face_count == 0) { + entry.face_index_1 = i_poly; + } + else if (entry.face_count == 1) { + entry.face_index_2 = i_poly; + } + entry.face_count++; + } + } + return edge_map; +} + class AngleFieldInput final : public GeometryFieldInput { public: - AngleFieldInput() : GeometryFieldInput(CPPType::get(), "Angle Field") + AngleFieldInput() : GeometryFieldInput(CPPType::get(), "Unsigned Angle Field") { category_ = Category::Generated; } @@ -61,34 +90,18 @@ class AngleFieldInput final : public GeometryFieldInput { Span polys{mesh->mpoly, mesh->totpoly}; Span loops{mesh->mloop, mesh->totloop}; - Array edge_map(mesh->totedge, {0, 0, 0}); - - for (const int i_poly : polys.index_range()) { - const MPoly &mpoly = polys[i_poly]; - for (const MLoop &loop : loops.slice(mpoly.loopstart, mpoly.totloop)) { - EdgeMapEntry &entry = edge_map[loop.e]; - if (entry.face_count == 0) { - entry.face_index_1 = i_poly; - } - else if (entry.face_count == 1) { - entry.face_index_2 = i_poly; - } - entry.face_count++; - } - } + Array edge_map = create_edge_map(polys, loops, mesh->totedge); auto angle_fn = [edge_map, polys, loops, mesh](const int i) -> float { - if (edge_map[i].face_count == 2) { - const MPoly &mpoly_1 = polys[edge_map[i].face_index_1]; - const MPoly &mpoly_2 = polys[edge_map[i].face_index_2]; - float3 normal_1, normal_2; - BKE_mesh_calc_poly_normal(&mpoly_1, &loops[mpoly_1.loopstart], mesh->mvert, normal_1); - BKE_mesh_calc_poly_normal(&mpoly_2, &loops[mpoly_2.loopstart], mesh->mvert, normal_2); - return angle_normalized_v3v3(normal_1, normal_2); - } - else { + if (edge_map[i].face_count != 2) { return 0.0f; } + const MPoly &mpoly_1 = polys[edge_map[i].face_index_1]; + const MPoly &mpoly_2 = polys[edge_map[i].face_index_2]; + float3 normal_1, normal_2; + BKE_mesh_calc_poly_normal(&mpoly_1, &loops[mpoly_1.loopstart], mesh->mvert, normal_1); + BKE_mesh_calc_poly_normal(&mpoly_2, &loops[mpoly_2.loopstart], mesh->mvert, normal_2); + return angle_normalized_v3v3(normal_1, normal_2); }; VArray angles = VArray::ForFunc(mesh->totedge, angle_fn); @@ -108,10 +121,91 @@ class AngleFieldInput final : public GeometryFieldInput { } }; +class SignedAngleFieldInput final : public GeometryFieldInput { + public: + SignedAngleFieldInput() : GeometryFieldInput(CPPType::get(), "Signed Angle Field") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask UNUSED(mask)) const final + { + if (component.type() != GEO_COMPONENT_TYPE_MESH) { + return {}; + } + + const MeshComponent &mesh_component = static_cast(component); + const Mesh *mesh = mesh_component.get_for_read(); + if (mesh == nullptr) { + return {}; + } + + Span polys{mesh->mpoly, mesh->totpoly}; + Span loops{mesh->mloop, mesh->totloop}; + Array edge_map = create_edge_map(polys, loops, mesh->totedge); + + auto angle_fn = [edge_map, polys, loops, mesh](const int i) -> float { + if (edge_map[i].face_count != 2) { + return 0.0f; + } + const MPoly &mpoly_1 = polys[edge_map[i].face_index_1]; + const MPoly &mpoly_2 = polys[edge_map[i].face_index_2]; + + /* Find the normals of the 2 polys. */ + float3 poly_1_normal, poly_2_normal; + BKE_mesh_calc_poly_normal(&mpoly_1, &loops[mpoly_1.loopstart], mesh->mvert, poly_1_normal); + BKE_mesh_calc_poly_normal(&mpoly_2, &loops[mpoly_2.loopstart], mesh->mvert, poly_2_normal); + + /* Find the centerpoint of the axis edge */ + const float3 edge_centerpoint = (float3(mesh->mvert[mesh->medge[i].v1].co) + + float3(mesh->mvert[mesh->medge[i].v2].co)) * + 0.5f; + + /* Get the centerpoint of poly 2 and subtract the edge centerpoint to get a tangent + * normal for poly 2. */ + float3 poly_center_2; + BKE_mesh_calc_poly_center(&mpoly_2, &loops[mpoly_2.loopstart], mesh->mvert, poly_center_2); + const float3 poly_2_tangent = math::normalize(poly_center_2 - edge_centerpoint); + const float concavity = math::dot(poly_1_normal, poly_2_tangent); + + /* Get the unsigned angle between the two polys */ + const float angle = angle_normalized_v3v3(poly_1_normal, poly_2_normal); + + if (angle == 0.0f || angle == 2.0f * M_PI || concavity < 0) { + return angle; + } + return -angle; + }; + + VArray angles = VArray::ForFunc(mesh->totedge, angle_fn); + return component.attribute_try_adapt_domain( + std::move(angles), ATTR_DOMAIN_EDGE, domain); + } + + uint64_t hash() const override + { + /* Some random constant hash. */ + return 68465416863; + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + return dynamic_cast(&other) != nullptr; + } +}; + static void node_geo_exec(GeoNodeExecParams params) { - Field angle_field{std::make_shared()}; - params.set_output("Angle", std::move(angle_field)); + if (params.output_is_required("Unsigned Angle")) { + Field angle_field{std::make_shared()}; + params.set_output("Unsigned Angle", std::move(angle_field)); + } + if (params.output_is_required("Signed Angle")) { + Field angle_field{std::make_shared()}; + params.set_output("Signed Angle", std::move(angle_field)); + } } } // namespace blender::nodes::node_geo_input_mesh_edge_angle_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc index 629279a44e9..68bb93bbb64 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc @@ -27,10 +27,13 @@ namespace blender::nodes::node_geo_input_mesh_island_cc { static void node_declare(NodeDeclarationBuilder &b) { - b.add_output(N_("Index")) + b.add_output(N_("Island Index")) .field_source() .description(N_("Island indices are based on the order of the lowest-numbered vertex " "contained in each island")); + b.add_output(N_("Island Count")) + .field_source() + .description(N_("The total number of mesh islands")); } class IslandFieldInput final : public GeometryFieldInput { @@ -81,10 +84,63 @@ class IslandFieldInput final : public GeometryFieldInput { } }; +class IslandCountFieldInput final : public GeometryFieldInput { + public: + IslandCountFieldInput() : GeometryFieldInput(CPPType::get(), "Island Count") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask UNUSED(mask)) const final + { + if (component.type() != GEO_COMPONENT_TYPE_MESH) { + return {}; + } + const MeshComponent &mesh_component = static_cast(component); + const Mesh *mesh = mesh_component.get_for_read(); + if (mesh == nullptr) { + return {}; + } + + DisjointSet islands(mesh->totvert); + for (const int i : IndexRange(mesh->totedge)) { + islands.join(mesh->medge[i].v1, mesh->medge[i].v2); + } + + Set island_list; + for (const int i_vert : IndexRange(mesh->totvert)) { + const int64_t root = islands.find_root(i_vert); + island_list.add(root); + } + + return VArray::ForSingle(island_list.size(), + mesh_component.attribute_domain_size(domain)); + } + + uint64_t hash() const override + { + /* Some random hash. */ + return 45634572457; + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + return dynamic_cast(&other) != nullptr; + } +}; + static void node_geo_exec(GeoNodeExecParams params) { - Field island_field{std::make_shared()}; - params.set_output("Index", std::move(island_field)); + if (params.output_is_required("Island Index")) { + Field field{std::make_shared()}; + params.set_output("Island Index", std::move(field)); + } + if (params.output_is_required("Island Count")) { + Field field{std::make_shared()}; + params.set_output("Island Count", std::move(field)); + } } } // namespace blender::nodes::node_geo_input_mesh_island_cc diff --git a/source/blender/nodes/intern/node_socket_declarations.cc b/source/blender/nodes/intern/node_socket_declarations.cc index 4fef5b96e9f..1e6b77a9620 100644 --- a/source/blender/nodes/intern/node_socket_declarations.cc +++ b/source/blender/nodes/intern/node_socket_declarations.cc @@ -509,7 +509,8 @@ bool Shader::can_connect(const bNodeSocket &socket) const } /* Basic types can convert to shaders, but not the other way around. */ if (in_out_ == SOCK_IN) { - return ELEM(socket.type, SOCK_VECTOR, SOCK_RGBA, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN); + return ELEM( + socket.type, SOCK_VECTOR, SOCK_RGBA, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_SHADER); } return socket.type == SOCK_SHADER; } diff --git a/source/blender/nodes/shader/node_shader_tree.cc b/source/blender/nodes/shader/node_shader_tree.cc index 8f1bb1dcd9a..5c3c5889c98 100644 --- a/source/blender/nodes/shader/node_shader_tree.cc +++ b/source/blender/nodes/shader/node_shader_tree.cc @@ -418,6 +418,22 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree) } } +static void ntree_shader_groups_remove_muted_links(bNodeTree *ntree) +{ + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == NODE_GROUP) { + if (node->id != nullptr) { + ntree_shader_groups_remove_muted_links(reinterpret_cast(node->id)); + } + } + } + LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { + if (link->flag & NODE_LINK_MUTED) { + nodeRemLink(ntree, link); + } + } +} + static void flatten_group_do(bNodeTree *ntree, bNode *gnode) { LinkNode *group_interface_nodes = nullptr; @@ -875,6 +891,7 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree, bNode *output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE); + ntree_shader_groups_remove_muted_links(localtree); ntree_shader_groups_expand_inputs(localtree); ntree_shader_groups_flatten(localtree); diff --git a/source/blender/python/gpu/gpu_py_framebuffer.c b/source/blender/python/gpu/gpu_py_framebuffer.c index a9347b71723..412fcac02ca 100644 --- a/source/blender/python/gpu/gpu_py_framebuffer.c +++ b/source/blender/python/gpu/gpu_py_framebuffer.c @@ -530,6 +530,7 @@ static PyObject *pygpu_framebuffer_read_color(BPyGPUFrameBuffer *self, PyErr_SetString(PyExc_BufferError, "the buffer size is smaller than expected"); return NULL; } + Py_INCREF(py_buffer); } else { py_buffer = BPyGPU_Buffer_CreatePyObject( @@ -590,6 +591,7 @@ static PyObject *pygpu_framebuffer_read_depth(BPyGPUFrameBuffer *self, PyErr_SetString(PyExc_BufferError, "the buffer size is smaller than expected"); return NULL; } + Py_INCREF(py_buffer); } else { py_buffer = BPyGPU_Buffer_CreatePyObject(GPU_DATA_FLOAT, (Py_ssize_t[]){h, w}, 2, NULL); diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index ed9547ee13f..fe7183441d1 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -2609,7 +2609,9 @@ static int bpy_prop_arg_parse_tag_defines(PyObject *o, void *p) " :type step: int\n" #define BPY_PROPDEF_FLOAT_PREC_DOC \ - " :arg precision: Maximum number of decimal digits to display, in [0, 6].\n" \ + " :arg precision: Maximum number of decimal digits to display, in [0, 6]. Fraction is " \ + "automatically hidden for exact integer values of fields with unit 'NONE' or 'TIME' (frame " \ + "count) and step divisible by 100.\n" \ " :type precision: int\n" #define BPY_PROPDEF_UPDATE_DOC \ diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt index 494415a4077..a7c1b12982c 100644 --- a/source/blender/render/CMakeLists.txt +++ b/source/blender/render/CMakeLists.txt @@ -49,6 +49,7 @@ set(SRC intern/pipeline.c intern/render_result.c intern/texture_image.c + intern/texture_margin.cc intern/texture_pointdensity.c intern/texture_procedural.c intern/zbuf.c @@ -58,6 +59,7 @@ set(SRC RE_multires_bake.h RE_pipeline.h RE_texture.h + RE_texture_margin.h intern/pipeline.h intern/render_result.h diff --git a/source/blender/render/RE_bake.h b/source/blender/render/RE_bake.h index b7ce3da71ff..d61c0a8bf90 100644 --- a/source/blender/render/RE_bake.h +++ b/source/blender/render/RE_bake.h @@ -27,6 +27,7 @@ struct Depsgraph; struct ImBuf; struct Mesh; struct Render; +struct MLoopUV; #ifdef __cplusplus extern "C" { @@ -112,7 +113,12 @@ void RE_bake_pixels_populate(struct Mesh *me, void RE_bake_mask_fill(const BakePixel pixel_array[], size_t num_pixels, char *mask); -void RE_bake_margin(struct ImBuf *ibuf, char *mask, int margin); +void RE_bake_margin(struct ImBuf *ibuf, + char *mask, + int margin, + char margin_type, + struct Mesh const *me, + char const *uv_layer); void RE_bake_normal_world_to_object(const BakePixel pixel_array[], size_t num_pixels, diff --git a/source/blender/render/RE_multires_bake.h b/source/blender/render/RE_multires_bake.h index 42ee2c57fbb..6df80c27c40 100644 --- a/source/blender/render/RE_multires_bake.h +++ b/source/blender/render/RE_multires_bake.h @@ -33,7 +33,8 @@ extern "C" { typedef struct MultiresBakeRender { Scene *scene; DerivedMesh *lores_dm, *hires_dm; - int bake_filter; /* Bake-filter, aka margin */ + int bake_margin; + char bake_margin_type; int lvl, tot_lvl; short mode; bool use_lores_mesh; /* Use low-resolution mesh when baking displacement maps */ diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c index 5bca68a9c69..beecef3ecc1 100644 --- a/source/blender/render/intern/bake.c +++ b/source/blender/render/intern/bake.c @@ -83,6 +83,7 @@ #include "IMB_imbuf_types.h" #include "RE_bake.h" +#include "RE_texture_margin.h" /* local include */ #include "render_types.h" @@ -154,10 +155,24 @@ void RE_bake_mask_fill(const BakePixel pixel_array[], const size_t num_pixels, c } } -void RE_bake_margin(ImBuf *ibuf, char *mask, const int margin) +void RE_bake_margin(ImBuf *ibuf, + char *mask, + const int margin, + const char margin_type, + Mesh const *me, + char const *uv_layer) { /* margin */ - IMB_filter_extend(ibuf, mask, margin); + switch (margin_type) { + case R_BAKE_ADJACENT_FACES: + RE_generate_texturemargin_adjacentfaces(ibuf, mask, margin, me, uv_layer); + break; + default: + /* fall through */ + case R_BAKE_EXTEND: + IMB_filter_extend(ibuf, mask, margin); + break; + } if (ibuf->planes != R_IMF_PLANES_RGBA) { /* clear alpha added by filtering */ diff --git a/source/blender/render/intern/multires_bake.c b/source/blender/render/intern/multires_bake.c index d3e7dca2035..5cf328a3a73 100644 --- a/source/blender/render/intern/multires_bake.c +++ b/source/blender/render/intern/multires_bake.c @@ -47,6 +47,7 @@ #include "RE_multires_bake.h" #include "RE_pipeline.h" #include "RE_texture.h" +#include "RE_texture_margin.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -1296,14 +1297,23 @@ static void apply_ao_callback(DerivedMesh *lores_dm, /* ******$***************** Post processing ************************* */ -static void bake_ibuf_filter(ImBuf *ibuf, char *mask, const int filter) +static void bake_ibuf_filter( + ImBuf *ibuf, char *mask, const int margin, const char margin_type, DerivedMesh *dm) { /* must check before filtering */ const bool is_new_alpha = (ibuf->planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(ibuf); - /* Margin */ - if (filter) { - IMB_filter_extend(ibuf, mask, filter); + if (margin) { + switch (margin_type) { + case R_BAKE_ADJACENT_FACES: + RE_generate_texturemargin_adjacentfaces_dm(ibuf, mask, margin, dm); + break; + default: + /* fall through */ + case R_BAKE_EXTEND: + IMB_filter_extend(ibuf, mask, margin); + break; + } } /* if the bake results in new alpha then change the image setting */ @@ -1311,7 +1321,7 @@ static void bake_ibuf_filter(ImBuf *ibuf, char *mask, const int filter) ibuf->planes = R_IMF_PLANES_RGBA; } else { - if (filter && ibuf->planes != R_IMF_PLANES_RGBA) { + if (margin && ibuf->planes != R_IMF_PLANES_RGBA) { /* clear alpha added by filtering */ IMB_rectfill_alpha(ibuf, 1.0f); } @@ -1460,7 +1470,8 @@ static void finish_images(MultiresBakeRender *bkr, MultiresBakeResult *result) result->height_max); } - bake_ibuf_filter(ibuf, userdata->mask_buffer, bkr->bake_filter); + bake_ibuf_filter( + ibuf, userdata->mask_buffer, bkr->bake_margin, bkr->bake_margin_type, bkr->lores_dm); ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; BKE_image_mark_dirty(ima, ibuf); diff --git a/source/blender/sequencer/CMakeLists.txt b/source/blender/sequencer/CMakeLists.txt index eccc336141a..54524e453d4 100644 --- a/source/blender/sequencer/CMakeLists.txt +++ b/source/blender/sequencer/CMakeLists.txt @@ -46,6 +46,7 @@ set(INC_SYS set(SRC SEQ_add.h + SEQ_animation.h SEQ_clipboard.h SEQ_edit.h SEQ_effects.h @@ -62,6 +63,7 @@ set(SRC SEQ_transform.h SEQ_utils.h + intern/animation.c intern/clipboard.c intern/disk_cache.c intern/disk_cache.h diff --git a/source/blender/sequencer/SEQ_clipboard.h b/source/blender/sequencer/SEQ_clipboard.h index 72388c5db64..dc78f8cc1a2 100644 --- a/source/blender/sequencer/SEQ_clipboard.h +++ b/source/blender/sequencer/SEQ_clipboard.h @@ -33,6 +33,7 @@ struct Scene; struct Sequence; extern struct ListBase seqbase_clipboard; +extern struct ListBase fcurves_clipboard; extern int seqbase_clipboard_frame; void SEQ_clipboard_pointers_store(struct Main *bmain, struct ListBase *seqbase); void SEQ_clipboard_pointers_restore(struct ListBase *seqbase, struct Main *bmain); diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h index 1229f6f7bea..2e340049dbd 100644 --- a/source/blender/sequencer/SEQ_sequencer.h +++ b/source/blender/sequencer/SEQ_sequencer.h @@ -84,7 +84,7 @@ struct ListBase *SEQ_active_seqbase_get(const struct Editing *ed); */ void SEQ_seqbase_active_set(struct Editing *ed, struct ListBase *seqbase); struct Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int type); -void SEQ_sequence_free(struct Scene *scene, struct Sequence *seq, bool do_clean_animdata); +void SEQ_sequence_free(struct Scene *scene, struct Sequence *seq); /** * Create and initialize #MetaStack, append it to `ed->metastack` ListBase * @@ -107,8 +107,6 @@ struct MetaStack *SEQ_meta_stack_active_get(const struct Editing *ed); * \param ms: meta stack */ void SEQ_meta_stack_free(struct Editing *ed, struct MetaStack *ms); -void SEQ_offset_animdata(struct Scene *scene, struct Sequence *seq, int ofs); -void SEQ_dupe_animdata(struct Scene *scene, const char *name_src, const char *name_dst); struct Sequence *SEQ_sequence_dupli_recursive(const struct Scene *scene_src, struct Scene *scene_dst, struct ListBase *new_seq_list, diff --git a/source/blender/sequencer/intern/clipboard.c b/source/blender/sequencer/intern/clipboard.c index 73e0f616da4..886ee89595b 100644 --- a/source/blender/sequencer/intern/clipboard.c +++ b/source/blender/sequencer/intern/clipboard.c @@ -28,6 +28,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_anim_types.h" #include "DNA_scene_types.h" #include "DNA_sequence_types.h" #include "DNA_sound_types.h" @@ -35,6 +36,7 @@ #include "BLI_listbase.h" #include "BLI_string.h" +#include "BKE_fcurve.h" #include "BKE_main.h" #include "BKE_movieclip.h" #include "BKE_scene.h" @@ -58,6 +60,7 @@ */ ListBase seqbase_clipboard; +ListBase fcurves_clipboard; int seqbase_clipboard_frame; static char seq_clipboard_active_seq_name[SEQ_NAME_MAXSTR]; @@ -65,15 +68,17 @@ void seq_clipboard_pointers_free(struct ListBase *seqbase); void SEQ_clipboard_free(void) { - Sequence *seq, *nseq; - seq_clipboard_pointers_free(&seqbase_clipboard); - for (seq = seqbase_clipboard.first; seq; seq = nseq) { - nseq = seq->next; - seq_free_sequence_recurse(NULL, seq, false, true); + LISTBASE_FOREACH_MUTABLE (Sequence *, seq, &seqbase_clipboard) { + seq_free_sequence_recurse(NULL, seq, false); } BLI_listbase_clear(&seqbase_clipboard); + + LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, &fcurves_clipboard) { + BKE_fcurve_free(fcu); + } + BLI_listbase_clear(&fcurves_clipboard); } #define ID_PT (*id_pt) diff --git a/source/blender/sequencer/intern/proxy.c b/source/blender/sequencer/intern/proxy.c index 30afa3f9c59..2cb2ba13fb5 100644 --- a/source/blender/sequencer/intern/proxy.c +++ b/source/blender/sequencer/intern/proxy.c @@ -591,7 +591,7 @@ void SEQ_proxy_rebuild_finish(SeqIndexBuildContext *context, bool stop) IMB_anim_index_rebuild_finish(context->index_context, stop); } - seq_free_sequence_recurse(NULL, context->seq, true, true); + seq_free_sequence_recurse(NULL, context->seq, true); MEM_freeN(context); } diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c index e4120a3cf95..f0a45355143 100644 --- a/source/blender/sequencer/intern/sequencer.c +++ b/source/blender/sequencer/intern/sequencer.c @@ -34,10 +34,7 @@ #include "DNA_sound_types.h" #include "BLI_listbase.h" -#include "BLI_string.h" -#include "BKE_animsys.h" -#include "BKE_fcurve.h" #include "BKE_idprop.h" #include "BKE_lib_id.h" #include "BKE_sound.h" @@ -65,8 +62,6 @@ #include "sequencer.h" #include "utils.h" -static void seq_free_animdata(Scene *scene, Sequence *seq); - /* -------------------------------------------------------------------- */ /** \name Allocate / Free Functions * \{ */ @@ -156,8 +151,7 @@ Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int static void seq_sequence_free_ex(Scene *scene, Sequence *seq, const bool do_cache, - const bool do_id_user, - const bool do_clean_animdata) + const bool do_id_user) { if (seq->strip) { seq_free_strip(seq->strip); @@ -191,11 +185,6 @@ static void seq_sequence_free_ex(Scene *scene, if (seq->scene_sound && ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) { BKE_sound_remove_scene_sound(scene, seq->scene_sound); } - - /* XXX This must not be done in BKE code. */ - if (do_clean_animdata) { - seq_free_animdata(scene, seq); - } } if (seq->prop) { @@ -223,24 +212,21 @@ static void seq_sequence_free_ex(Scene *scene, MEM_freeN(seq); } -void SEQ_sequence_free(Scene *scene, Sequence *seq, const bool do_clean_animdata) +void SEQ_sequence_free(Scene *scene, Sequence *seq) { - seq_sequence_free_ex(scene, seq, true, true, do_clean_animdata); + seq_sequence_free_ex(scene, seq, true, true); } -void seq_free_sequence_recurse(Scene *scene, - Sequence *seq, - const bool do_id_user, - const bool do_clean_animdata) +void seq_free_sequence_recurse(Scene *scene, Sequence *seq, const bool do_id_user) { Sequence *iseq, *iseq_next; for (iseq = seq->seqbase.first; iseq; iseq = iseq_next) { iseq_next = iseq->next; - seq_free_sequence_recurse(scene, iseq, do_id_user, do_clean_animdata); + seq_free_sequence_recurse(scene, iseq, do_id_user); } - seq_sequence_free_ex(scene, seq, false, do_id_user, do_clean_animdata); + seq_sequence_free_ex(scene, seq, false, do_id_user); } Editing *SEQ_editing_get(const Scene *scene) @@ -276,7 +262,7 @@ void SEQ_editing_free(Scene *scene, const bool do_id_user) /* handle cache freeing above */ LISTBASE_FOREACH_MUTABLE (Sequence *, seq, &ed->seqbase) { - seq_free_sequence_recurse(scene, seq, do_id_user, false); + seq_free_sequence_recurse(scene, seq, do_id_user); } BLI_freelistN(&ed->metastack); @@ -623,120 +609,6 @@ bool SEQ_valid_strip_channel(Sequence *seq) return true; } -/* r_prefix + [" + escaped_name + "] + \0 */ -#define SEQ_RNAPATH_MAXSTR ((30 + 2 + (SEQ_NAME_MAXSTR * 2) + 2) + 1) - -static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char *name) -{ - char name_esc[SEQ_NAME_MAXSTR * 2]; - - BLI_str_escape(name_esc, name, sizeof(name_esc)); - return BLI_snprintf_rlen( - str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc); -} - -void SEQ_offset_animdata(Scene *scene, Sequence *seq, int ofs) -{ - /* XXX: hackish function needed for transforming strips! - * TODO: have some better solution. */ - - char str[SEQ_RNAPATH_MAXSTR]; - size_t str_len; - FCurve *fcu; - - if (scene->adt == NULL || ofs == 0 || scene->adt->action == NULL) { - return; - } - - str_len = sequencer_rna_path_prefix(str, seq->name + 2); - - for (fcu = scene->adt->action->curves.first; fcu; fcu = fcu->next) { - if (STREQLEN(fcu->rna_path, str, str_len)) { - unsigned int i; - if (fcu->bezt) { - for (i = 0; i < fcu->totvert; i++) { - BezTriple *bezt = &fcu->bezt[i]; - bezt->vec[0][0] += ofs; - bezt->vec[1][0] += ofs; - bezt->vec[2][0] += ofs; - } - } - if (fcu->fpt) { - for (i = 0; i < fcu->totvert; i++) { - FPoint *fpt = &fcu->fpt[i]; - fpt->vec[0] += ofs; - } - } - } - } - - DEG_id_tag_update(&scene->adt->action->id, ID_RECALC_ANIMATION); -} - -void SEQ_dupe_animdata(Scene *scene, const char *name_src, const char *name_dst) -{ - char str_from[SEQ_RNAPATH_MAXSTR]; - size_t str_from_len; - FCurve *fcu; - FCurve *fcu_last; - FCurve *fcu_cpy; - ListBase lb = {NULL, NULL}; - - if (scene->adt == NULL || scene->adt->action == NULL) { - return; - } - - str_from_len = sequencer_rna_path_prefix(str_from, name_src); - - fcu_last = scene->adt->action->curves.last; - - for (fcu = scene->adt->action->curves.first; fcu && fcu->prev != fcu_last; fcu = fcu->next) { - if (STREQLEN(fcu->rna_path, str_from, str_from_len)) { - fcu_cpy = BKE_fcurve_copy(fcu); - BLI_addtail(&lb, fcu_cpy); - } - } - - /* notice validate is 0, keep this because the seq may not be added to the scene yet */ - BKE_animdata_fix_paths_rename( - &scene->id, scene->adt, NULL, "sequence_editor.sequences_all", name_src, name_dst, 0, 0, 0); - - /* add the original fcurves back */ - BLI_movelisttolist(&scene->adt->action->curves, &lb); -} - -/* XXX: hackish function needed to remove all fcurves belonging to a sequencer strip. */ -static void seq_free_animdata(Scene *scene, Sequence *seq) -{ - char str[SEQ_RNAPATH_MAXSTR]; - size_t str_len; - FCurve *fcu; - - if (scene->adt == NULL || scene->adt->action == NULL) { - return; - } - - str_len = sequencer_rna_path_prefix(str, seq->name + 2); - - fcu = scene->adt->action->curves.first; - - while (fcu) { - if (STREQLEN(fcu->rna_path, str, str_len)) { - FCurve *next_fcu = fcu->next; - - BLI_remlink(&scene->adt->action->curves, fcu); - BKE_fcurve_free(fcu); - - fcu = next_fcu; - } - else { - fcu = fcu->next; - } - } -} - -#undef SEQ_RNAPATH_MAXSTR - SequencerToolSettings *SEQ_tool_settings_copy(SequencerToolSettings *tool_settings) { SequencerToolSettings *tool_settings_copy = MEM_dupallocN(tool_settings); diff --git a/source/blender/sequencer/intern/sequencer.h b/source/blender/sequencer/intern/sequencer.h index aff81255d7d..7d7ecbc8178 100644 --- a/source/blender/sequencer/intern/sequencer.h +++ b/source/blender/sequencer/intern/sequencer.h @@ -34,10 +34,7 @@ struct Sequence; * Cache must be freed before calling this function * since it leaves the seqbase in an invalid state. */ -void seq_free_sequence_recurse(struct Scene *scene, - struct Sequence *seq, - bool do_id_user, - bool do_clean_animdata); +void seq_free_sequence_recurse(struct Scene *scene, struct Sequence *seq, bool do_id_user); #ifdef __cplusplus } diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c index cf303e5be4e..0479d3012fa 100644 --- a/source/blender/sequencer/intern/strip_edit.c +++ b/source/blender/sequencer/intern/strip_edit.c @@ -43,6 +43,7 @@ #include "utils.h" #include "SEQ_add.h" +#include "SEQ_animation.h" #include "SEQ_edit.h" #include "SEQ_effects.h" #include "SEQ_iterator.h" @@ -199,8 +200,9 @@ void SEQ_edit_remove_flagged_sequences(Scene *scene, ListBase *seqbase) if (seq->type == SEQ_TYPE_META) { SEQ_edit_remove_flagged_sequences(scene, &seq->seqbase); } + SEQ_free_animdata(scene, seq); BLI_remlink(seqbase, seq); - SEQ_sequence_free(scene, seq, true); + SEQ_sequence_free(scene, seq); SEQ_sequence_lookup_tag(scene, SEQ_LOOKUP_TAG_INVALID); } } diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c index ce5917b999f..432fc1c166f 100644 --- a/source/blender/sequencer/intern/strip_transform.c +++ b/source/blender/sequencer/intern/strip_transform.c @@ -33,6 +33,7 @@ #include "BKE_scene.h" #include "BKE_sound.h" +#include "SEQ_animation.h" #include "SEQ_effects.h" #include "SEQ_iterator.h" #include "SEQ_relations.h" diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c index 156c6ac4cb9..140aa2d67c5 100644 --- a/source/blender/sequencer/intern/utils.c +++ b/source/blender/sequencer/intern/utils.c @@ -35,10 +35,12 @@ #include "BLI_blenlib.h" +#include "BKE_animsys.h" #include "BKE_image.h" #include "BKE_main.h" #include "BKE_scene.h" +#include "SEQ_animation.h" #include "SEQ_edit.h" #include "SEQ_iterator.h" #include "SEQ_relations.h" @@ -583,7 +585,8 @@ void SEQ_ensure_unique_name(Sequence *seq, Scene *scene) BLI_strncpy_utf8(name, seq->name + 2, sizeof(name)); SEQ_sequence_base_unique_name_recursive(scene, &scene->ed->seqbase, seq); - SEQ_dupe_animdata(scene, name, seq->name + 2); + BKE_animdata_fix_paths_rename( + &scene->id, scene->adt, NULL, "sequence_editor.sequences_all", name, seq->name + 2, 0, 0, 0); if (seq->type == SEQ_TYPE_META) { LISTBASE_FOREACH (Sequence *, seq_child, &seq->seqbase) { diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index f2459b7fdc9..96cb66b44ea 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -748,19 +748,19 @@ static void wm_drag_draw_icon(bContext *UNUSED(C), float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); - immDrawPixelsTexScaled(&state, - x, - y, - drag->imb->x, - drag->imb->y, - GPU_RGBA8, - false, - drag->imb->rect, - drag->scale, - drag->scale, - 1.0f, - 1.0f, - col); + immDrawPixelsTexTiled_scaling(&state, + x, + y, + drag->imb->x, + drag->imb->y, + GPU_RGBA8, + false, + drag->imb->rect, + drag->scale, + drag->scale, + 1.0f, + 1.0f, + col); } else { int padding = 4 * UI_DPI_FAC; diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index f2d955b218f..3b8bd2ef2ae 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -1521,11 +1521,29 @@ static void wm_history_file_update(void) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Save Main Blend-File (internal) Screen-Shot +/** \name Thumbnail Generation: Screen-Shot / Camera View + * + * Thumbnail Sizes + * =============== + * + * - `PREVIEW_RENDER_LARGE_HEIGHT * 2` is used to render a large thumbnail, + * giving some over-sampling when scaled down: + * + * - There are two outputs for this thumbnail: + * + * - An image is saved to the thumbnail cache, sized at #PREVIEW_RENDER_LARGE_HEIGHT. + * + * - A smaller thumbnail is stored in the `.blend` file it's self, sized at #BLEN_THUMB_SIZE. + * The size is kept small to prevent thumbnails bloating the size of `.blend` files. + * + * The this thumbnail will be extracted if the file is shared or the local thumbnail cache + * is cleared. see: `blendthumb_extract.cc` for logic that extracts the thumbnail. * - * Screen-shot the active window. * \{ */ +/** + * Screen-shot the active window. + */ static ImBuf *blend_file_thumb_from_screenshot(bContext *C, BlendThumbnail **r_thumb) { *r_thumb = NULL; @@ -1571,15 +1589,11 @@ static ImBuf *blend_file_thumb_from_screenshot(bContext *C, BlendThumbnail **r_t return ibuf; } -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Save Main Blend-File (internal) Camera View - * +/** * Render the current scene with the active camera. - * \{ */ - -/* screen can be NULL */ + * + * \param screen: can be NULL. + */ static ImBuf *blend_file_thumb_from_camera(const bContext *C, Scene *scene, bScreen *screen, @@ -1617,7 +1631,6 @@ static ImBuf *blend_file_thumb_from_camera(const bContext *C, return NULL; } - /* gets scaled to BLEN_THUMB_SIZE */ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); /* Note that with scaling, this ends up being 0.5, @@ -1689,6 +1702,12 @@ static ImBuf *blend_file_thumb_from_camera(const bContext *C, return ibuf; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Write Main Blend-File (internal) + * \{ */ + bool write_crash_blend(void) { char path[FILE_MAX]; @@ -2017,7 +2036,7 @@ void wm_autosave_delete(void) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Initialize WM_OT_open_xxx properties +/** \name Initialize `WM_OT_open_*` Properties * * Check if load_ui was set by the caller. * Fall back to user preference when file flags not specified. diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index 47f51214a8e..7f923d4af60 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -412,7 +412,7 @@ static void draw_filled_lasso(wmGesture *gt) GPU_shader_uniform_vector( state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red); - immDrawPixelsTex( + immDrawPixelsTexTiled( &state, rect.xmin, rect.ymin, w, h, GPU_R8, false, pixel_buf, 1.0f, 1.0f, NULL); GPU_shader_unbind(); diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index 4ed1b7b9d0d..e58e051c66e 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -29,7 +29,7 @@ extern "C" { #endif -/* customdata type */ +/** #wmEvent.customdata type */ enum { EVT_DATA_TIMER = 2, EVT_DATA_DRAGDROP = 3, @@ -37,7 +37,11 @@ enum { EVT_DATA_XR = 5, }; -/* tablet active, matches GHOST_TTabletMode */ +/** + * #wmTabletData.active tablet active, matches #GHOST_TTabletMode. + * + * Typically access via `event->tablet.active`. + */ enum { EVT_TABLET_NONE = 0, EVT_TABLET_STYLUS = 1, @@ -95,10 +99,14 @@ enum { TABLET_STYLUS = 0x001a, TABLET_ERASER = 0x001b, - /* *** Start of keyboard codes. *** */ +/* *** Start of keyboard codes. *** */ + +/* Minimum keyboard value (inclusive). */ +#define _EVT_KEYBOARD_MIN 0x0020 /* Standard keyboard. - * From 0x0020 to 0x00ff, and 0x012c to 0x0143 for function keys! */ + * - 0x0020 to 0x00ff [#_EVT_KEYBOARD_MIN to #_EVT_KEYBOARD_MAX] inclusive - for keys. + * - 0x012c to 0x0143 [#EVT_F1KEY to #EVT_F24KEY] inclusive - for function keys. */ EVT_ZEROKEY = 0x0030, /* '0' (48). */ EVT_ONEKEY = 0x0031, /* '1' (49). */ @@ -210,6 +218,12 @@ enum { EVT_LEFTBRACKETKEY = 0x00eb, /* 235 */ EVT_RIGHTBRACKETKEY = 0x00ec, /* 236 */ +/* Maximum keyboard value (inclusive). */ +#define _EVT_KEYBOARD_MAX 0x00ff /* 255 */ + + /* WARNING: 0x010x are used for internal events + * (but are still stored in the key-map). */ + EVT_F1KEY = 0x012c, /* 300 */ EVT_F2KEY = 0x012d, /* 301 */ EVT_F3KEY = 0x012e, /* 302 */ @@ -237,60 +251,65 @@ enum { /* *** End of keyboard codes. *** */ - /* NDOF (from SpaceNavigator & friends) - * These should be kept in sync with GHOST_NDOFManager.h + /* NDOF (from "Space Navigator" & friends) + * These must be kept in sync with `GHOST_NDOFManager.h`. * Ordering matters, exact values do not. */ + NDOF_MOTION = 0x0190, /* 400 */ + +#define _NDOF_MIN NDOF_MOTION + /* used internally, never sent */ NDOF_BUTTON_NONE = NDOF_MOTION, /* these two are available from any 3Dconnexion device */ - NDOF_BUTTON_MENU, - NDOF_BUTTON_FIT, + + NDOF_BUTTON_MENU = 0x0191, /* 401 */ + NDOF_BUTTON_FIT = 0x0192, /* 402 */ /* standard views */ - NDOF_BUTTON_TOP, - NDOF_BUTTON_BOTTOM, - NDOF_BUTTON_LEFT, - NDOF_BUTTON_RIGHT, - NDOF_BUTTON_FRONT, - NDOF_BUTTON_BACK, + NDOF_BUTTON_TOP = 0x0193, /* 403 */ + NDOF_BUTTON_BOTTOM = 0x0194, /* 404 */ + NDOF_BUTTON_LEFT = 0x0195, /* 405 */ + NDOF_BUTTON_RIGHT = 0x0196, /* 406 */ + NDOF_BUTTON_FRONT = 0x0197, /* 407 */ + NDOF_BUTTON_BACK = 0x0198, /* 408 */ /* more views */ - NDOF_BUTTON_ISO1, - NDOF_BUTTON_ISO2, + NDOF_BUTTON_ISO1 = 0x0199, /* 409 */ + NDOF_BUTTON_ISO2 = 0x019a, /* 410 */ /* 90 degree rotations */ - NDOF_BUTTON_ROLL_CW, - NDOF_BUTTON_ROLL_CCW, - NDOF_BUTTON_SPIN_CW, - NDOF_BUTTON_SPIN_CCW, - NDOF_BUTTON_TILT_CW, - NDOF_BUTTON_TILT_CCW, + NDOF_BUTTON_ROLL_CW = 0x019b, /* 411 */ + NDOF_BUTTON_ROLL_CCW = 0x019c, /* 412 */ + NDOF_BUTTON_SPIN_CW = 0x019d, /* 413 */ + NDOF_BUTTON_SPIN_CCW = 0x019e, /* 414 */ + NDOF_BUTTON_TILT_CW = 0x019f, /* 415 */ + NDOF_BUTTON_TILT_CCW = 0x01a0, /* 416 */ /* device control */ - NDOF_BUTTON_ROTATE, - NDOF_BUTTON_PANZOOM, - NDOF_BUTTON_DOMINANT, - NDOF_BUTTON_PLUS, - NDOF_BUTTON_MINUS, + NDOF_BUTTON_ROTATE = 0x01a1, /* 417 */ + NDOF_BUTTON_PANZOOM = 0x01a2, /* 418 */ + NDOF_BUTTON_DOMINANT = 0x01a3, /* 419 */ + NDOF_BUTTON_PLUS = 0x01a4, /* 420 */ + NDOF_BUTTON_MINUS = 0x01a5, /* 421 */ /* keyboard emulation */ - NDOF_BUTTON_ESC, - NDOF_BUTTON_ALT, - NDOF_BUTTON_SHIFT, - NDOF_BUTTON_CTRL, + NDOF_BUTTON_ESC = 0x01a6, /* 422 */ + NDOF_BUTTON_ALT = 0x01a7, /* 423 */ + NDOF_BUTTON_SHIFT = 0x01a8, /* 424 */ + NDOF_BUTTON_CTRL = 0x01a9, /* 425 */ /* general-purpose buttons */ - NDOF_BUTTON_1, - NDOF_BUTTON_2, - NDOF_BUTTON_3, - NDOF_BUTTON_4, - NDOF_BUTTON_5, - NDOF_BUTTON_6, - NDOF_BUTTON_7, - NDOF_BUTTON_8, - NDOF_BUTTON_9, - NDOF_BUTTON_10, + NDOF_BUTTON_1 = 0x01aa, /* 426 */ + NDOF_BUTTON_2 = 0x01ab, /* 427 */ + NDOF_BUTTON_3 = 0x01ac, /* 428 */ + NDOF_BUTTON_4 = 0x01ad, /* 429 */ + NDOF_BUTTON_5 = 0x01ae, /* 430 */ + NDOF_BUTTON_6 = 0x01af, /* 431 */ + NDOF_BUTTON_7 = 0x01b0, /* 432 */ + NDOF_BUTTON_8 = 0x01b1, /* 433 */ + NDOF_BUTTON_9 = 0x01b2, /* 434 */ + NDOF_BUTTON_10 = 0x01b3, /* 435 */ /* more general-purpose buttons */ - NDOF_BUTTON_A, - NDOF_BUTTON_B, - NDOF_BUTTON_C, - /* the end */ - NDOF_LAST, + NDOF_BUTTON_A = 0x01b4, /* 436 */ + NDOF_BUTTON_B = 0x01b5, /* 437 */ + NDOF_BUTTON_C = 0x01b6, /* 438 */ + +#define _NDOF_MAX NDOF_BUTTON_C /* ********** End of Input devices. ********** */ @@ -318,13 +337,13 @@ enum { EVT_ACTIONZONE_REGION = 0x5001, /* 20481 */ EVT_ACTIONZONE_FULLSCREEN = 0x5011, /* 20497 */ - /* NOTE: these values are saved in keymap files, do not change them but just add new ones */ + /* NOTE: these values are saved in key-map files, do not change them but just add new ones. */ /* Tweak events: * Sent as additional event with the mouse coordinates * from where the initial click was placed. */ - /* tweak events for L M R mousebuttons */ + /* Tweak events for L M R mouse-buttons. */ EVT_TWEAK_L = 0x5002, /* 20482 */ EVT_TWEAK_M = 0x5003, /* 20483 */ EVT_TWEAK_R = 0x5004, /* 20484 */ @@ -348,9 +367,11 @@ enum { /* ********** End of Blender internal events. ********** */ }; -/* *********** wmEvent.type helpers. ********** */ +/* -------------------------------------------------------------------- */ +/** \name #wmEvent.type Helpers + * \{ */ -/* test whether the event is timer event */ +/** Test whether the event is timer event. */ #define ISTIMER(event_type) ((event_type) >= TIMER && (event_type) <= TIMERF) /* for event checks */ @@ -359,22 +380,24 @@ enum { // #define ISTEXTINPUT(event_type) ((event_type) >= ' ' && (event_type) <= 255) /* NOTE: an alternative could be to check `event->utf8_buf`. */ -/* test whether the event is a key on the keyboard */ +/** Test whether the event is a key on the keyboard (including modifier keys). */ #define ISKEYBOARD(event_type) \ - (((event_type) >= 0x0020 && (event_type) <= 0x00ff) || \ - ((event_type) >= 0x012c && (event_type) <= 0x0143)) + (((event_type) >= _EVT_KEYBOARD_MIN && (event_type) <= _EVT_KEYBOARD_MAX) || \ + ((event_type) >= EVT_F1KEY && (event_type) <= EVT_F24KEY)) -/* test whether the event is a modifier key */ +/** Test whether the event is a modifier key. */ #define ISKEYMODIFIER(event_type) \ (((event_type) >= EVT_LEFTCTRLKEY && (event_type) <= EVT_LEFTSHIFTKEY) || \ (event_type) == EVT_OSKEY) -/* test whether the event is a mouse button */ +/** Test whether the event is a mouse button. */ #define ISMOUSE(event_type) \ (((event_type) >= LEFTMOUSE && (event_type) <= BUTTON7MOUSE) || (event_type) == MOUSESMARTZOOM) - +/** Test whether the event is a mouse wheel. */ #define ISMOUSE_WHEEL(event_type) ((event_type) >= WHEELUPMOUSE && (event_type) <= WHEELOUTMOUSE) +/** Test whether the event is a mouse (track-pad) gesture. */ #define ISMOUSE_GESTURE(event_type) ((event_type) >= MOUSEPAN && (event_type) <= MOUSEROTATE) +/** Test whether the event is a mouse button (excluding mouse-wheel). */ #define ISMOUSE_BUTTON(event_type) \ (ELEM(event_type, \ LEFTMOUSE, \ @@ -385,16 +408,16 @@ enum { BUTTON6MOUSE, \ BUTTON7MOUSE)) -/* test whether the event is tweak event */ +/** Test whether the event is tweak event. */ #define ISTWEAK(event_type) ((event_type) >= EVT_TWEAK_L && (event_type) <= EVT_TWEAK_R) -/* test whether the event is a NDOF event */ -#define ISNDOF(event_type) ((event_type) >= NDOF_MOTION && (event_type) < NDOF_LAST) +/** Test whether the event is a NDOF event. */ +#define ISNDOF(event_type) ((event_type) >= _NDOF_MIN && (event_type) <= _NDOF_MAX) #define IS_EVENT_ACTIONZONE(event_type) \ ELEM(event_type, EVT_ACTIONZONE_AREA, EVT_ACTIONZONE_REGION, EVT_ACTIONZONE_FULLSCREEN) -/* test whether event type is acceptable as hotkey, excluding modifiers */ +/** Test whether event type is acceptable as hotkey (excluding modifiers). */ #define ISHOTKEY(event_type) \ ((ISKEYBOARD(event_type) || ISMOUSE(event_type) || ISNDOF(event_type)) && \ (ISKEYMODIFIER(event_type) == false)) @@ -409,23 +432,23 @@ enum { #define IS_EVENT_MOD(...) VA_NARGS_CALL_OVERLOAD(_VA_IS_EVENT_MOD, __VA_ARGS__) enum eEventType_Mask { - /* ISKEYMODIFIER */ + /** #ISKEYMODIFIER */ EVT_TYPE_MASK_KEYBOARD_MODIFIER = (1 << 0), - /* ISKEYBOARD */ + /** #ISKEYBOARD */ EVT_TYPE_MASK_KEYBOARD = (1 << 1), - /* ISMOUSE_WHEEL */ + /** #ISMOUSE_WHEEL */ EVT_TYPE_MASK_MOUSE_WHEEL = (1 << 2), - /* ISMOUSE_BUTTON */ + /** #ISMOUSE_BUTTON */ EVT_TYPE_MASK_MOUSE_GESTURE = (1 << 3), - /* ISMOUSE_GESTURE */ + /** #ISMOUSE_GESTURE */ EVT_TYPE_MASK_MOUSE_BUTTON = (1 << 4), - /* ISMOUSE */ + /** #ISMOUSE */ EVT_TYPE_MASK_MOUSE = (1 << 5), - /* ISNDOF */ + /** #ISNDOF */ EVT_TYPE_MASK_NDOF = (1 << 6), - /* ISTWEAK */ + /** #ISTWEAK */ EVT_TYPE_MASK_TWEAK = (1 << 7), - /* IS_EVENT_ACTIONZONE */ + /** #IS_EVENT_ACTIONZONE */ EVT_TYPE_MASK_ACTIONZONE = (1 << 8), }; #define EVT_TYPE_MASK_ALL \ @@ -438,7 +461,11 @@ enum eEventType_Mask { bool WM_event_type_mask_test(int event_type, enum eEventType_Mask mask); -/* ********** wmEvent.val ********** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #wmEvent.val Values + * \{ */ /* Gestures */ /* NOTE: these values are saved in keymap files, do not change them but just add new ones */ @@ -505,6 +532,8 @@ enum { GESTURE_MODAL_FLIP = 14, }; +/** \} */ + #ifdef __cplusplus } #endif diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index a5d20e1fa37..0609b8fd792 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -656,11 +656,11 @@ if(UNIX AND NOT APPLE) # Install to the same directory as the source, so debian-like # distros are happy with their policy. set(_suffix "site-packages") - if(${PYTHON_NUMPY_PATH} MATCHES "dist-packages") + if(${PYTHON_ZSTANDARD_PATH} MATCHES "dist-packages") set(_suffix "dist-packages") endif() install( - DIRECTORY ${PYTHON_NUMPY_PATH}/zstandard + DIRECTORY ${PYTHON_ZSTANDARD_PATH}/zstandard DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/${_suffix} PATTERN ".svn" EXCLUDE PATTERN "__pycache__" EXCLUDE # * any cache * diff --git a/tests/python/bl_alembic_io_test.py b/tests/python/bl_alembic_io_test.py index c0d0bcdea70..da75d4f0731 100644 --- a/tests/python/bl_alembic_io_test.py +++ b/tests/python/bl_alembic_io_test.py @@ -357,6 +357,58 @@ class CameraExportImportTest(unittest.TestCase): self.assertAlmostEqual(1, actual_scale.z, delta=delta_scale) +class OverrideLayersTest(AbstractAlembicTest): + def test_import_layer(self): + fname = 'cube-base-file.abc' + fname_layer = 'cube-hi-res.abc' + abc = self.testdir / fname + abc_layer = self.testdir / fname_layer + + # We need a cache reader to ensure that the data will be updated after adding a layer. + res = bpy.ops.wm.alembic_import(filepath=str(abc), as_background_job=False, always_add_cache_reader=True) + self.assertEqual({'FINISHED'}, res) + + # Check that the file loaded ok. + cube = bpy.context.active_object + depsgraph = bpy.context.evaluated_depsgraph_get() + scene = bpy.context.scene + cube_eval = cube.evaluated_get(depsgraph) + mesh = cube_eval.to_mesh() + + # The base file should be a default cube. + self.assertEqual(len(mesh.vertices), 8) + self.assertEqual(len(mesh.edges), 12) + self.assertEqual(len(mesh.polygons), 6) + + # Add a layer. + cache_file = bpy.data.cache_files[fname] + self.assertEqual(len(cache_file.layers), 0) + + layer = cache_file.layers.new(filepath=str(abc_layer)) + self.assertEqual(len(cache_file.layers), 1) + self.assertIsNotNone(layer) + + # The layer added a higher res version of the mesh. + depsgraph = bpy.context.evaluated_depsgraph_get() + cube_eval = cube.evaluated_get(depsgraph) + mesh = cube_eval.to_mesh() + self.assertEqual(len(mesh.vertices), 26) + self.assertEqual(len(mesh.edges), 48) + self.assertEqual(len(mesh.polygons), 24) + + # Remove the layer. + cache_file.layers.remove(layer) + self.assertEqual(len(cache_file.layers), 0) + + # We should have reverted to the default cube. + depsgraph = bpy.context.evaluated_depsgraph_get() + cube_eval = cube.evaluated_get(depsgraph) + mesh = cube_eval.to_mesh() + self.assertEqual(len(mesh.vertices), 8) + self.assertEqual(len(mesh.edges), 12) + self.assertEqual(len(mesh.polygons), 6) + + def main(): global args import argparse