WIP: Brush assets project #106303

Draft
Julian Eisel wants to merge 381 commits from brush-assets-project into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
159 changed files with 2157 additions and 1024 deletions
Showing only changes of commit 0656847bc9 - Show all commits

View File

@ -115,7 +115,8 @@ def git_branch(git_command: str) -> str:
try: try:
branch = subprocess.check_output([git_command, "rev-parse", "--abbrev-ref", "HEAD"]) branch = subprocess.check_output([git_command, "rev-parse", "--abbrev-ref", "HEAD"])
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError:
# No need to print the exception, error text is written to the output already.
sys.stderr.write("Failed to get Blender git branch\n") sys.stderr.write("Failed to get Blender git branch\n")
sys.exit(1) sys.exit(1)

View File

@ -16,10 +16,11 @@ This ``directory`` and ``files`` properties now will be used by the
""" """
import bpy import bpy
from bpy_extras.io_utils import ImportHelper
from mathutils import Vector from mathutils import Vector
class ShaderScriptImport(bpy.types.Operator): class ShaderScriptImport(bpy.types.Operator, ImportHelper):
"""Test importer that creates scripts nodes from .txt files""" """Test importer that creates scripts nodes from .txt files"""
bl_idname = "shader.script_import" bl_idname = "shader.script_import"
bl_label = "Import a text file as a script node" bl_label = "Import a text file as a script node"
@ -28,8 +29,11 @@ class ShaderScriptImport(bpy.types.Operator):
This Operator can import multiple .txt files, we need following directory and files This Operator can import multiple .txt files, we need following directory and files
properties that the file handler will use to set files path data properties that the file handler will use to set files path data
""" """
directory: bpy.props.StringProperty(subtype='FILE_PATH', options={'SKIP_SAVE'}) directory: bpy.props.StringProperty(subtype='FILE_PATH', options={'SKIP_SAVE', 'HIDDEN'})
files: bpy.props.CollectionProperty(type=bpy.types.OperatorFileListElement, options={'SKIP_SAVE'}) files: bpy.props.CollectionProperty(type=bpy.types.OperatorFileListElement, options={'SKIP_SAVE', 'HIDDEN'})
"""Allow the user to select if the node's label is set or not"""
set_label: bpy.props.BoolProperty(name="Set Label", default=False)
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
@ -57,23 +61,26 @@ class ShaderScriptImport(bpy.types.Operator):
filepath = os.path.join(self.directory, file.name) filepath = os.path.join(self.directory, file.name)
text_node.filepath = filepath text_node.filepath = filepath
text_node.location = Vector((x, y)) text_node.location = Vector((x, y))
# Set the node's title to the file name
if self.set_label:
text_node.label = file.name
x += 20.0 x += 20.0
y -= 20.0 y -= 20.0
return {'FINISHED'} return {'FINISHED'}
""" """
By default the file handler invokes the operator with the directory and files properties set. Use ImportHelper's invoke_popup() to handle the invocation so that this operator's properties
In this example if this properties are set the operator is executed, if not the are shown in a popup. This allows the user to configure additional settings on the operator like
file select window is invoked. the `set_label` property. Consider having a draw() method on the operator in order to layout the
This depends on setting ``options={'SKIP_SAVE'}`` to the properties options to avoid properties in the UI appropriately.
to reuse filepath data between operator calls.
If filepath information is not provided the file select window will be invoked instead.
""" """
def invoke(self, context, event): def invoke(self, context, event):
if self.directory: return self.invoke_popup(context)
return self.execute(context)
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
class SHADER_FH_script_import(bpy.types.FileHandler): class SHADER_FH_script_import(bpy.types.FileHandler):

View File

@ -219,10 +219,6 @@ endif()
if(WITH_CYCLES_OSL) if(WITH_CYCLES_OSL)
add_definitions(-DWITH_OSL) add_definitions(-DWITH_OSL)
# osl 1.9.x
add_definitions(-DOSL_STATIC_BUILD)
# pre 1.9
add_definitions(-DOSL_STATIC_LIBRARY)
include_directories( include_directories(
SYSTEM SYSTEM
${OSL_INCLUDE_DIR} ${OSL_INCLUDE_DIR}

View File

@ -142,6 +142,12 @@ if(WITH_OPENIMAGEDENOISE)
) )
endif() endif()
if(WITH_CYCLES_OSL)
list(APPEND LIB
${OSL_LIBRARIES}
)
endif()
blender_add_lib(bf_intern_cycles "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") blender_add_lib(bf_intern_cycles "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
add_dependencies(bf_intern_cycles bf_rna) add_dependencies(bf_intern_cycles bf_rna)

View File

@ -203,6 +203,13 @@ if(WITH_OPENIMAGEDENOISE)
) )
endif() endif()
if(WITH_CYCLES_OSL)
list(APPEND LIB
${OSL_LIBRARIES}
)
endif()
include_directories(${INC}) include_directories(${INC})
include_directories(SYSTEM ${INC_SYS}) include_directories(SYSTEM ${INC_SYS})

View File

@ -7,76 +7,82 @@
#define vector3 point #define vector3 point
float safe_noise(float p) float safe_noise(float co)
{ {
float f = noise("noise", p); /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
if (isinf(f)) { * representation issues. */
return 0.5; float p = fmod(co, 100000.0);
}
return f; return noise("noise", p);
} }
float safe_noise(vector2 p) float safe_noise(vector2 co)
{ {
float f = noise("noise", p.x, p.y); /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
if (isinf(f)) { * representation issues. This causes discontinuities every 100000.0, however at such scales this
return 0.5; * usually shouldn't be noticeable. */
} vector2 p = fmod(co, 100000.0);
return f;
return noise("noise", p.x, p.y);
} }
float safe_noise(vector3 p) float safe_noise(vector3 co)
{ {
float f = noise("noise", p); /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
if (isinf(f)) { * representation issues. This causes discontinuities every 100000.0, however at such scales this
return 0.5; * usually shouldn't be noticeable. */
} vector3 p = fmod(co, 100000.0);
return f;
return noise("noise", p);
} }
float safe_noise(vector4 p) float safe_noise(vector4 co)
{ {
float f = noise("noise", vector3(p.x, p.y, p.z), p.w); /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
if (isinf(f)) { * representation issues. This causes discontinuities every 100000.0, however at such scales this
return 0.5; * usually shouldn't be noticeable. */
} vector4 p = fmod(co, 100000.0);
return f;
return noise("noise", vector3(p.x, p.y, p.z), p.w);
} }
float safe_snoise(float p) float safe_snoise(float co)
{ {
float f = noise("snoise", p); /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
if (isinf(f)) { * representation issues. */
return 0.0; float p = fmod(co, 100000.0);
}
return f; return noise("snoise", p);
} }
float safe_snoise(vector2 p) float safe_snoise(vector2 co)
{ {
float f = noise("snoise", p.x, p.y); /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
if (isinf(f)) { * representation issues. This causes discontinuities every 100000.0, however at such scales this
return 0.0; * usually shouldn't be noticeable. */
} vector2 p = fmod(co, 100000.0);
return f;
return noise("snoise", p.x, p.y);
} }
float safe_snoise(vector3 p) float safe_snoise(vector3 co)
{ {
float f = noise("snoise", p); /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
if (isinf(f)) { * representation issues. This causes discontinuities every 100000.0, however at such scales this
return 0.0; * usually shouldn't be noticeable. */
} vector3 p = fmod(co, 100000.0);
return f;
return noise("snoise", p);
} }
float safe_snoise(vector4 p) float safe_snoise(vector4 co)
{ {
float f = noise("snoise", vector3(p.x, p.y, p.z), p.w); /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
if (isinf(f)) { * representation issues. This causes discontinuities every 100000.0, however at such scales this
return 0.0; * usually shouldn't be noticeable. */
} vector4 p = fmod(co, 100000.0);
return f;
return noise("snoise", vector3(p.x, p.y, p.z), p.w);
} }
#define NOISE_FBM(T) \ #define NOISE_FBM(T) \

View File

@ -684,7 +684,12 @@ ccl_device_inline float noise_scale4(float result)
ccl_device_inline float snoise_1d(float p) ccl_device_inline float snoise_1d(float p)
{ {
return noise_scale1(ensure_finite(perlin_1d(p))); /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
* representation issues. */
/* The 1D variant of fmod is called fmodf. */
p = fmodf(p, 100000.0f);
return noise_scale1(perlin_1d(p));
} }
ccl_device_inline float noise_1d(float p) ccl_device_inline float noise_1d(float p)
@ -694,7 +699,12 @@ ccl_device_inline float noise_1d(float p)
ccl_device_inline float snoise_2d(float2 p) ccl_device_inline float snoise_2d(float2 p)
{ {
return noise_scale2(ensure_finite(perlin_2d(p.x, p.y))); /* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0f, however at such scales
* this usually shouldn't be noticeable. */
p = fmod(p, 100000.0f);
return noise_scale2(perlin_2d(p.x, p.y));
} }
ccl_device_inline float noise_2d(float2 p) ccl_device_inline float noise_2d(float2 p)
@ -704,7 +714,12 @@ ccl_device_inline float noise_2d(float2 p)
ccl_device_inline float snoise_3d(float3 p) ccl_device_inline float snoise_3d(float3 p)
{ {
return noise_scale3(ensure_finite(perlin_3d(p.x, p.y, p.z))); /* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0f, however at such scales
* this usually shouldn't be noticeable. */
p = fmod(p, 100000.0f);
return noise_scale3(perlin_3d(p.x, p.y, p.z));
} }
ccl_device_inline float noise_3d(float3 p) ccl_device_inline float noise_3d(float3 p)
@ -714,7 +729,12 @@ ccl_device_inline float noise_3d(float3 p)
ccl_device_inline float snoise_4d(float4 p) ccl_device_inline float snoise_4d(float4 p)
{ {
return noise_scale4(ensure_finite(perlin_4d(p.x, p.y, p.z, p.w))); /* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0f, however at such scales
* this usually shouldn't be noticeable. */
p = fmod(p, 100000.0f);
return noise_scale4(perlin_4d(p.x, p.y, p.z, p.w));
} }
ccl_device_inline float noise_4d(float4 p) ccl_device_inline float noise_4d(float4 p)

View File

@ -107,6 +107,7 @@ endif()
if(WITH_CYCLES_OSL) if(WITH_CYCLES_OSL)
list(APPEND LIB list(APPEND LIB
cycles_kernel_osl cycles_kernel_osl
${OSL_LIBRARIES}
) )
endif() endif()

View File

@ -198,6 +198,11 @@ ccl_device_inline float2 clamp(const float2 a, const float2 mn, const float2 mx)
return min(max(a, mn), mx); return min(max(a, mn), mx);
} }
ccl_device_inline float2 fmod(const float2 a, const float b)
{
return make_float2(fmodf(a.x, b), fmodf(a.y, b));
}
ccl_device_inline float2 fabs(const float2 a) ccl_device_inline float2 fabs(const float2 a)
{ {
return make_float2(fabsf(a.x), fabsf(a.y)); return make_float2(fabsf(a.x), fabsf(a.y));

View File

@ -309,6 +309,11 @@ ccl_device_inline float3 fabs(const float3 a)
# endif # endif
} }
ccl_device_inline float3 fmod(const float3 a, const float b)
{
return make_float3(fmodf(a.x, b), fmodf(a.y, b), fmodf(a.z, b));
}
ccl_device_inline float3 sqrt(const float3 a) ccl_device_inline float3 sqrt(const float3 a)
{ {
# ifdef __KERNEL_SSE__ # ifdef __KERNEL_SSE__

View File

@ -465,6 +465,11 @@ ccl_device_inline float4 fabs(const float4 a)
# endif # endif
} }
ccl_device_inline float4 fmod(const float4 a, const float b)
{
return make_float4(fmodf(a.x, b), fmodf(a.y, b), fmodf(a.z, b), fmodf(a.w, b));
}
ccl_device_inline float4 floor(const float4 a) ccl_device_inline float4 floor(const float4 a)
{ {
# ifdef __KERNEL_SSE__ # ifdef __KERNEL_SSE__

View File

@ -210,7 +210,7 @@ rbCollisionShape *RB_shape_new_cylinder(float radius, float height);
/* Setup (Convex Hull) ------------ */ /* Setup (Convex Hull) ------------ */
rbCollisionShape *RB_shape_new_convex_hull( rbCollisionShape *RB_shape_new_convex_hull(
float *verts, int stride, int count, float margin, bool *can_embed); const float *verts, int stride, int count, float margin, bool *can_embed);
/* Setup (Triangle Mesh) ---------- */ /* Setup (Triangle Mesh) ---------- */
@ -244,7 +244,7 @@ float RB_shape_get_margin(rbCollisionShape *shape);
void RB_shape_set_margin(rbCollisionShape *shape, float value); void RB_shape_set_margin(rbCollisionShape *shape, float value);
void RB_shape_trimesh_update(rbCollisionShape *shape, void RB_shape_trimesh_update(rbCollisionShape *shape,
float *vertices, const float *vertices,
int num_verts, int num_verts,
int vert_stride, int vert_stride,
const float min[3], const float min[3],

View File

@ -712,7 +712,7 @@ rbCollisionShape *RB_shape_new_cylinder(float radius, float height)
/* Setup (Convex Hull) ------------ */ /* Setup (Convex Hull) ------------ */
rbCollisionShape *RB_shape_new_convex_hull( rbCollisionShape *RB_shape_new_convex_hull(
float *verts, int stride, int count, float margin, bool *can_embed) const float *verts, int stride, int count, float margin, bool *can_embed)
{ {
btConvexHullComputer hull_computer = btConvexHullComputer(); btConvexHullComputer hull_computer = btConvexHullComputer();
@ -800,7 +800,7 @@ rbCollisionShape *RB_shape_new_trimesh(rbMeshData *mesh)
} }
void RB_shape_trimesh_update(rbCollisionShape *shape, void RB_shape_trimesh_update(rbCollisionShape *shape,
float *vertices, const float *vertices,
int num_verts, int num_verts,
int vert_stride, int vert_stride,
const float min[3], const float min[3],

@ -1 +1 @@
Subproject commit 1d44611dd36032c1889c66d673801ef7d699f592 Subproject commit 0b910c0a718a1d54d07ecf95c63617576ee9a847

Binary file not shown.

View File

@ -23,7 +23,10 @@ from bpy.props import (
EnumProperty, EnumProperty,
StringProperty, StringProperty,
) )
from bpy.app.translations import pgettext_data as data_ from bpy.app.translations import (
pgettext_iface as iface_,
pgettext_data as data_,
)
def _check_axis_conversion(op): def _check_axis_conversion(op):
@ -96,12 +99,29 @@ class ImportHelper:
description="Filepath used for importing the file", description="Filepath used for importing the file",
maxlen=1024, maxlen=1024,
subtype='FILE_PATH', subtype='FILE_PATH',
options={'SKIP_PRESET', 'HIDDEN'}
) )
def invoke(self, context, _event): def invoke(self, context, _event):
context.window_manager.fileselect_add(self) context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'} return {'RUNNING_MODAL'}
def invoke_popup(self, context, confirm_text=""):
if self.properties.is_property_set("filepath"):
title = self.filepath
if len(self.files) > 1:
title = iface_("Import {} files").format(len(self.files))
if not confirm_text:
confirm_text = self.bl_label
confirm_text = iface_(confirm_text)
return context.window_manager.invoke_props_dialog(
self, confirm_text=confirm_text, title=title, translate=False)
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
def check(self, _context): def check(self, _context):
return _check_axis_conversion(self) return _check_axis_conversion(self)
@ -394,6 +414,19 @@ def unpack_face_list(list_of_tuples):
return flat_ls return flat_ls
def poll_file_object_drop(context):
"""
A default implementation for FileHandler poll_drop methods. Allows for both the 3D Viewport and
the Outliner (in ViewLayer display mode) to be targets for file drag and drop.
"""
area = context.area
if not area:
return False
is_v3d = area.type == 'VIEW_3D'
is_outliner_view_layer = area.type == 'OUTLINER' and area.spaces.active.display_mode == 'VIEW_LAYER'
return is_v3d or is_outliner_view_layer
path_reference_mode = EnumProperty( path_reference_mode = EnumProperty(
name="Path Mode", name="Path Mode",
description="Method used to reference paths", description="Method used to reference paths",

View File

@ -2330,8 +2330,7 @@ def km_file_browser(params):
("file.next", {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True}, None), ("file.next", {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True}, None),
("wm.context_toggle", {"type": 'H', "value": 'PRESS'}, ("wm.context_toggle", {"type": 'H', "value": 'PRESS'},
{"properties": [("data_path", 'space_data.params.show_hidden')]}), {"properties": [("data_path", 'space_data.params.show_hidden')]}),
("file.directory_new", {"type": 'I', "value": 'PRESS'}, ("file.directory_new", {"type": 'I', "value": 'PRESS'}, None),
{"properties": [("confirm", False)]}),
("file.rename", {"type": 'F2', "value": 'PRESS'}, None), ("file.rename", {"type": 'F2', "value": 'PRESS'}, None),
("file.delete", {"type": 'X', "value": 'PRESS'}, None), ("file.delete", {"type": 'X', "value": 'PRESS'}, None),
("file.delete", {"type": 'DEL', "value": 'PRESS'}, None), ("file.delete", {"type": 'DEL', "value": 'PRESS'}, None),
@ -7917,6 +7916,21 @@ def km_3d_view_tool_sculpt_lasso_hide(params):
) )
def km_3d_view_tool_sculpt_line_hide(params):
return (
"3D View Tool: Sculpt, Line Hide",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
{"items": [
("paint.hide_show_line_gesture", params.tool_maybe_tweak_event,
{"properties": [("action", 'HIDE')]}),
("paint.hide_show_line_gesture", {**params.tool_maybe_tweak_event, "ctrl": True},
{"properties": [("action", 'SHOW')]}),
("paint.hide_show_all", {"type": params.select_mouse, "value": params.select_mouse_value},
{"properties": [("action", 'SHOW')]}),
]},
)
def km_3d_view_tool_sculpt_box_mask(params): def km_3d_view_tool_sculpt_box_mask(params):
return ( return (
"3D View Tool: Sculpt, Box Mask", "3D View Tool: Sculpt, Box Mask",
@ -8763,6 +8777,7 @@ def generate_keymaps(params=None):
km_3d_view_tool_edit_curves_draw(params), km_3d_view_tool_edit_curves_draw(params),
km_3d_view_tool_sculpt_box_hide(params), km_3d_view_tool_sculpt_box_hide(params),
km_3d_view_tool_sculpt_lasso_hide(params), km_3d_view_tool_sculpt_lasso_hide(params),
km_3d_view_tool_sculpt_line_hide(params),
km_3d_view_tool_sculpt_box_mask(params), km_3d_view_tool_sculpt_box_mask(params),
km_3d_view_tool_sculpt_lasso_mask(params), km_3d_view_tool_sculpt_lasso_mask(params),
km_3d_view_tool_sculpt_box_face_set(params), km_3d_view_tool_sculpt_box_face_set(params),

View File

@ -1240,8 +1240,7 @@ def km_file_browser(params):
("file.next", {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True}, None), ("file.next", {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True}, None),
("wm.context_toggle", {"type": 'H', "value": 'PRESS'}, ("wm.context_toggle", {"type": 'H', "value": 'PRESS'},
{"properties": [("data_path", 'space_data.params.show_hidden')]}), {"properties": [("data_path", 'space_data.params.show_hidden')]}),
("file.directory_new", {"type": 'I', "value": 'PRESS'}, ("file.directory_new", {"type": 'I', "value": 'PRESS'}, None),
{"properties": [("confirm", False)]}),
("file.rename", {"type": 'F2', "value": 'PRESS'}, None), ("file.rename", {"type": 'F2', "value": 'PRESS'}, None),
("file.delete", {"type": 'DEL', "value": 'PRESS'}, None), ("file.delete", {"type": 'DEL', "value": 'PRESS'}, None),
("file.smoothscroll", {"type": 'TIMER1', "value": 'ANY', "any": True}, None), ("file.smoothscroll", {"type": 'TIMER1', "value": 'ANY', "any": True}, None),

View File

@ -530,11 +530,12 @@ class ARMATURE_OT_copy_bone_color_to_selected(Operator):
def _armature_from_context(context): def _armature_from_context(context):
pin_armature = getattr(context, 'armature', None) pin_armature = getattr(context, "armature", None)
if pin_armature: if pin_armature:
return pin_armature return pin_armature
if context.object and context.object.type == 'ARMATURE': ob = context.object
return context.object.data if ob and ob.type == 'ARMATURE':
return ob.data
return None return None

View File

@ -270,8 +270,8 @@ class WM_OT_blend_strings_utf8_validate(Operator):
continue continue
if prop.type == 'STRING': if prop.type == 'STRING':
val_bytes = item.path_resolve(prop.identifier, False).as_bytes() val_bytes = item.path_resolve(prop.identifier, False).as_bytes()
val_utf8 = val_bytes.decode('utf-8', 'replace') val_utf8 = val_bytes.decode("utf-8", "replace")
val_bytes_valid = val_utf8.encode('utf-8') val_bytes_valid = val_utf8.encode("utf-8")
if val_bytes_valid != val_bytes: if val_bytes_valid != val_bytes:
print("found bad utf8 encoded string %r, fixing to %r (%r)..." print("found bad utf8 encoded string %r, fixing to %r (%r)..."
"" % (val_bytes, val_bytes_valid, val_utf8)) "" % (val_bytes, val_bytes_valid, val_utf8))

View File

@ -48,7 +48,8 @@ def geometry_node_group_empty_tool_new(context):
group.use_fake_user = True group.use_fake_user = True
group.is_tool = True group.is_tool = True
ob_type = context.object.type if context.object else 'MESH' ob = context.object
ob_type = ob.type if ob else 'MESH'
if ob_type == 'CURVES': if ob_type == 'CURVES':
group.is_type_curve = True group.is_type_curve = True
elif ob_type == 'POINTCLOUD': elif ob_type == 'POINTCLOUD':
@ -56,7 +57,7 @@ def geometry_node_group_empty_tool_new(context):
else: else:
group.is_type_mesh = True group.is_type_mesh = True
mode = context.object.mode if context.object else 'OBJECT' mode = ob.mode if ob else 'OBJECT'
if mode in {'SCULPT', 'SCULPT_CURVES'}: if mode in {'SCULPT', 'SCULPT_CURVES'}:
group.is_mode_sculpt = True group.is_mode_sculpt = True
elif mode == 'EDIT': elif mode == 'EDIT':

View File

@ -145,7 +145,7 @@ class AddPresetBase:
file_preset.write("%s = %r\n" % (rna_path_step, value)) file_preset.write("%s = %r\n" % (rna_path_step, value))
file_preset = open(filepath, 'w', encoding="utf-8") file_preset = open(filepath, "w", encoding="utf-8")
file_preset.write("import bpy\n") file_preset.write("import bpy\n")
if hasattr(self, "preset_defines"): if hasattr(self, "preset_defines"):

View File

@ -674,7 +674,7 @@ class PREFERENCES_OT_addon_install(Operator):
# check to see if the file is in compressed format (.zip) # check to see if the file is in compressed format (.zip)
if zipfile.is_zipfile(pyfile): if zipfile.is_zipfile(pyfile):
try: try:
file_to_extract = zipfile.ZipFile(pyfile, 'r') file_to_extract = zipfile.ZipFile(pyfile, "r")
except BaseException: except BaseException:
traceback.print_exc() traceback.print_exc()
return {'CANCELLED'} return {'CANCELLED'}
@ -926,7 +926,7 @@ class PREFERENCES_OT_app_template_install(Operator):
# check to see if the file is in compressed format (.zip) # check to see if the file is in compressed format (.zip)
if zipfile.is_zipfile(filepath): if zipfile.is_zipfile(filepath):
try: try:
file_to_extract = zipfile.ZipFile(filepath, 'r') file_to_extract = zipfile.ZipFile(filepath, "r")
except BaseException: except BaseException:
traceback.print_exc() traceback.print_exc()
return {'CANCELLED'} return {'CANCELLED'}

View File

@ -31,10 +31,11 @@ class VIEW3D_OT_edit_mesh_extrude_individual_move(Operator):
def execute(self, context): def execute(self, context):
from bpy_extras.object_utils import object_report_if_active_shape_key_is_locked from bpy_extras.object_utils import object_report_if_active_shape_key_is_locked
if object_report_if_active_shape_key_is_locked(context.object, self): ob = context.object
if object_report_if_active_shape_key_is_locked(ob, self):
return {'CANCELLED'} return {'CANCELLED'}
mesh = context.object.data mesh = ob.data
select_mode = context.tool_settings.mesh_select_mode select_mode = context.tool_settings.mesh_select_mode
totface = mesh.total_face_sel totface = mesh.total_face_sel
@ -99,10 +100,11 @@ class VIEW3D_OT_edit_mesh_extrude_move(Operator):
def extrude_region(operator, context, use_vert_normals, dissolve_and_intersect): def extrude_region(operator, context, use_vert_normals, dissolve_and_intersect):
from bpy_extras.object_utils import object_report_if_active_shape_key_is_locked from bpy_extras.object_utils import object_report_if_active_shape_key_is_locked
if object_report_if_active_shape_key_is_locked(context.object, operator): ob = context.object
if object_report_if_active_shape_key_is_locked(ob, operator):
return {'CANCELLED'} return {'CANCELLED'}
mesh = context.object.data mesh = ob.data
totface = mesh.total_face_sel totface = mesh.total_face_sel
totedge = mesh.total_edge_sel totedge = mesh.total_edge_sel

View File

@ -3367,10 +3367,13 @@ class WM_MT_splash_about(Menu):
col.scale_y = 0.8 col.scale_y = 0.8
col.label(text=iface_("Version: %s") % bpy.app.version_string, translate=False) col.label(text=iface_("Version: %s") % bpy.app.version_string, translate=False)
col.separator(factor=2.5) col.separator(factor=2.5)
col.label(text=iface_("Date: %s %s") % (bpy.app.build_commit_date.decode('utf-8', 'replace'), col.label(text=iface_("Date: %s %s") % (
bpy.app.build_commit_time.decode('utf-8', 'replace')), translate=False) bpy.app.build_commit_date.decode("utf-8", "replace"),
col.label(text=iface_("Hash: %s") % bpy.app.build_hash.decode('ascii'), translate=False) bpy.app.build_commit_time.decode("utf-8", "replace")),
col.label(text=iface_("Branch: %s") % bpy.app.build_branch.decode('utf-8', 'replace'), translate=False) translate=False
)
col.label(text=iface_("Hash: %s") % bpy.app.build_hash.decode("ascii"), translate=False)
col.label(text=iface_("Branch: %s") % bpy.app.build_branch.decode("utf-8", "replace"), translate=False)
# This isn't useful information on MS-Windows or Apple systems as dynamically switching # This isn't useful information on MS-Windows or Apple systems as dynamically switching
# between windowing systems is only supported between X11/WAYLAND. # between windowing systems is only supported between X11/WAYLAND.

View File

@ -82,7 +82,8 @@ class GREASE_PENCIL_MT_grease_pencil_add_layer_extra(Menu):
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
grease_pencil = context.object.data ob = context.object
grease_pencil = ob.data
space = context.space_data space = context.space_data
if space.type == 'PROPERTIES': if space.type == 'PROPERTIES':

View File

@ -417,20 +417,23 @@ class AnnotationDataPanel:
bl_options = {'DEFAULT_CLOSED'} bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, context): def draw_header(self, context):
if context.space_data.type not in { space = context.space_data
if space.type not in {
'VIEW_3D', 'VIEW_3D',
'TOPBAR', 'TOPBAR',
'SEQUENCE_EDITOR', 'SEQUENCE_EDITOR',
'IMAGE_EDITOR', 'IMAGE_EDITOR',
'NODE_EDITOR', 'NODE_EDITOR',
'PROPERTIES'}: 'PROPERTIES',
self.layout.prop(context.space_data, "show_annotation", text="") }:
self.layout.prop(space, "show_annotation", text="")
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
layout.use_property_decorate = False layout.use_property_decorate = False
space = context.space_data
is_clip_editor = context.space_data.type == 'CLIP_EDITOR' is_clip_editor = space.type == 'CLIP_EDITOR'
# Grease Pencil owner. # Grease Pencil owner.
gpd_owner = context.annotation_data_owner gpd_owner = context.annotation_data_owner
@ -441,7 +444,7 @@ class AnnotationDataPanel:
col = layout.column() col = layout.column()
col.label(text="Data Source:") col.label(text="Data Source:")
row = col.row() row = col.row()
row.prop(context.space_data, "annotation_source", expand=True) row.prop(space, "annotation_source", expand=True)
# Only allow adding annotation ID if its owner exist # Only allow adding annotation ID if its owner exist
if context.annotation_data_owner is None: if context.annotation_data_owner is None:

View File

@ -1480,6 +1480,10 @@ def brush_basic_grease_pencil_paint_settings(layout, context, brush, *, compact=
if gp_settings.eraser_mode == "HARD": if gp_settings.eraser_mode == "HARD":
layout.prop(gp_settings, "use_keep_caps_eraser") layout.prop(gp_settings, "use_keep_caps_eraser")
layout.prop(gp_settings, "use_active_layer_only") layout.prop(gp_settings, "use_active_layer_only")
elif grease_pencil_tool == 'TINT':
layout.prop(gp_settings, "vertex_mode", text="Mode")
layout.popover("VIEW3D_PT_tools_brush_settings_advanced", text="Brush")
layout.popover("VIEW3D_PT_tools_brush_falloff")
def brush_basic_gpencil_sculpt_settings(layout, _context, brush, *, compact=False): def brush_basic_gpencil_sculpt_settings(layout, _context, brush, *, compact=False):

View File

@ -258,9 +258,9 @@ class ToolSelectPanelHelper:
# tool flattening # tool flattening
# #
# usually 'tools' is already expanded into `ToolDef` # usually "tools" is already expanded into `ToolDef`
# but when registering a tool, this can still be a function # but when registering a tool, this can still be a function
# (_tools_flatten is usually called with cls.tools_from_context(context) # (`_tools_flatten` is usually called with `cls.tools_from_context(context)`
# [that already yields from the function]) # [that already yields from the function])
# so if item is still a function (e.g._defs_XXX.generate_from_brushes) # so if item is still a function (e.g._defs_XXX.generate_from_brushes)
# seems like we cannot expand here (have no context yet) # seems like we cannot expand here (have no context yet)

View File

@ -1423,6 +1423,21 @@ class _defs_sculpt:
draw_settings=draw_settings, draw_settings=draw_settings,
) )
@ToolDef.from_fn
def hide_line():
def draw_settings(_context, layout, tool):
props = tool.operator_properties("paint.hide_show_line_gesture")
layout.prop(props, "use_limit_to_segment", expand=False)
return dict(
idname="builtin.line_hide",
label="Line Hide",
icon="ops.sculpt.line_hide",
widget=None,
keymap=(),
draw_settings=draw_settings,
)
@ToolDef.from_fn @ToolDef.from_fn
def mask_border(): def mask_border():
def draw_settings(_context, layout, tool): def draw_settings(_context, layout, tool):
@ -1862,6 +1877,15 @@ class _defs_paint_grease_pencil:
data_block='ERASE', data_block='ERASE',
) )
@ToolDef.from_fn
def tint():
return dict(
idname="builtin_brush.Tint",
label="Tint",
icon="brush.gpencil_draw.tint",
data_block='TINT',
)
class _defs_image_generic: class _defs_image_generic:
@ -3162,7 +3186,8 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
), ),
( (
_defs_sculpt.hide_border, _defs_sculpt.hide_border,
_defs_sculpt.hide_lasso _defs_sculpt.hide_lasso,
_defs_sculpt.hide_line,
), ),
( (
_defs_sculpt.face_set_box, _defs_sculpt.face_set_box,
@ -3235,6 +3260,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
None, None,
_defs_paint_grease_pencil.draw, _defs_paint_grease_pencil.draw,
_defs_paint_grease_pencil.erase, _defs_paint_grease_pencil.erase,
_defs_paint_grease_pencil.tint,
], ],
'PAINT_GPENCIL': [ 'PAINT_GPENCIL': [
_defs_view3d_generic.cursor, _defs_view3d_generic.cursor,

View File

@ -409,27 +409,27 @@ class USERPREF_PT_edit_objects_duplicate_data(EditingPanel, CenterAlignMixIn, Pa
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True) flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
datablock_types = ( datablock_types = (
("use_duplicate_action", "Action", 'ACTION', ''), ("use_duplicate_action", "Action", 'ACTION', ""),
("use_duplicate_armature", "Armature", 'OUTLINER_DATA_ARMATURE', ''), ("use_duplicate_armature", "Armature", 'OUTLINER_DATA_ARMATURE', ""),
("use_duplicate_camera", "Camera", 'OUTLINER_DATA_CAMERA', ''), ("use_duplicate_camera", "Camera", 'OUTLINER_DATA_CAMERA', ""),
("use_duplicate_curve", "Curve", 'OUTLINER_DATA_CURVE', ''), ("use_duplicate_curve", "Curve", 'OUTLINER_DATA_CURVE', ""),
("use_duplicate_curves", "Curves", 'OUTLINER_DATA_CURVES', ''), ("use_duplicate_curves", "Curves", 'OUTLINER_DATA_CURVES', ""),
("use_duplicate_grease_pencil", "Grease Pencil", 'OUTLINER_OB_GREASEPENCIL', ''), ("use_duplicate_grease_pencil", "Grease Pencil", 'OUTLINER_OB_GREASEPENCIL', ""),
("use_duplicate_lattice", "Lattice", 'OUTLINER_DATA_LATTICE', ''), ("use_duplicate_lattice", "Lattice", 'OUTLINER_DATA_LATTICE', ""),
(None, None, None, None), (None, None, None, None),
("use_duplicate_light", "Light", 'OUTLINER_DATA_LIGHT', ''), ("use_duplicate_light", "Light", 'OUTLINER_DATA_LIGHT', ""),
("use_duplicate_lightprobe", "Light Probe", 'OUTLINER_DATA_LIGHTPROBE', ''), ("use_duplicate_lightprobe", "Light Probe", 'OUTLINER_DATA_LIGHTPROBE', ""),
("use_duplicate_material", "Material", 'MATERIAL_DATA', ''), ("use_duplicate_material", "Material", 'MATERIAL_DATA', ""),
("use_duplicate_mesh", "Mesh", 'OUTLINER_DATA_MESH', ''), ("use_duplicate_mesh", "Mesh", 'OUTLINER_DATA_MESH', ""),
("use_duplicate_metaball", "Metaball", 'OUTLINER_DATA_META', ''), ("use_duplicate_metaball", "Metaball", 'OUTLINER_DATA_META', ""),
("use_duplicate_node_tree", "Node Tree", 'NODETREE', ''), ("use_duplicate_node_tree", "Node Tree", 'NODETREE', ""),
("use_duplicate_particle", "Particle", 'PARTICLES', ''), ("use_duplicate_particle", "Particle", 'PARTICLES', ""),
(None, None, None, None), (None, None, None, None),
("use_duplicate_pointcloud", "Point Cloud", 'OUTLINER_DATA_POINTCLOUD', ''), ("use_duplicate_pointcloud", "Point Cloud", 'OUTLINER_DATA_POINTCLOUD', ""),
("use_duplicate_speaker", "Speaker", 'OUTLINER_DATA_SPEAKER', ''), ("use_duplicate_speaker", "Speaker", 'OUTLINER_DATA_SPEAKER', ""),
("use_duplicate_surface", "Surface", 'OUTLINER_DATA_SURFACE', ''), ("use_duplicate_surface", "Surface", 'OUTLINER_DATA_SURFACE', ""),
("use_duplicate_text", "Text", 'OUTLINER_DATA_FONT', ''), ("use_duplicate_text", "Text", 'OUTLINER_DATA_FONT', ""),
("use_duplicate_volume", "Volume", 'OUTLINER_DATA_VOLUME', 'i18n_contexts.id_id'), ("use_duplicate_volume", "Volume", 'OUTLINER_DATA_VOLUME', "i18n_contexts.id_id"),
) )
col = flow.column() col = flow.column()
@ -2727,7 +2727,7 @@ class USERPREF_PT_experimental_debugging(ExperimentalPanel, Panel):
# Class Registration # Class Registration
# Order of registration defines order in UI, # Order of registration defines order in UI,
# so dynamically generated classes are 'injected' in the intended order. # so dynamically generated classes are "injected" in the intended order.
classes = ( classes = (
USERPREF_PT_theme_user_interface, USERPREF_PT_theme_user_interface,
*ThemeGenericClassGenerator.generate_panel_classes_for_wcols(), *ThemeGenericClassGenerator.generate_panel_classes_for_wcols(),

View File

@ -139,17 +139,20 @@ class VIEW3D_HT_tool_header(Header):
return row, sub return row, sub
if mode_string == 'EDIT_ARMATURE': if mode_string == 'EDIT_ARMATURE':
ob = context.object
_row, sub = row_for_mirror() _row, sub = row_for_mirror()
sub.prop(context.object.data, "use_mirror_x", text="X", toggle=True) sub.prop(ob.data, "use_mirror_x", text="X", toggle=True)
elif mode_string == 'POSE': elif mode_string == 'POSE':
ob = context.object
_row, sub = row_for_mirror() _row, sub = row_for_mirror()
sub.prop(context.object.pose, "use_mirror_x", text="X", toggle=True) sub.prop(ob.pose, "use_mirror_x", text="X", toggle=True)
elif mode_string in {'EDIT_MESH', 'PAINT_WEIGHT', 'SCULPT', 'PAINT_VERTEX', 'PAINT_TEXTURE'}: elif mode_string in {'EDIT_MESH', 'PAINT_WEIGHT', 'SCULPT', 'PAINT_VERTEX', 'PAINT_TEXTURE'}:
# Mesh Modes, Use Mesh Symmetry # Mesh Modes, Use Mesh Symmetry
ob = context.object
row, sub = row_for_mirror() row, sub = row_for_mirror()
sub.prop(context.object, "use_mesh_mirror_x", text="X", toggle=True) sub.prop(ob, "use_mesh_mirror_x", text="X", toggle=True)
sub.prop(context.object, "use_mesh_mirror_y", text="Y", toggle=True) sub.prop(ob, "use_mesh_mirror_y", text="Y", toggle=True)
sub.prop(context.object, "use_mesh_mirror_z", text="Z", toggle=True) sub.prop(ob, "use_mesh_mirror_z", text="Z", toggle=True)
if mode_string == 'EDIT_MESH': if mode_string == 'EDIT_MESH':
tool_settings = context.tool_settings tool_settings = context.tool_settings
layout.prop(tool_settings, "use_mesh_automerge", text="") layout.prop(tool_settings, "use_mesh_automerge", text="")
@ -160,12 +163,13 @@ class VIEW3D_HT_tool_header(Header):
elif mode_string == 'PAINT_VERTEX': elif mode_string == 'PAINT_VERTEX':
row.popover(panel="VIEW3D_PT_tools_vertexpaint_symmetry_for_topbar", text="") row.popover(panel="VIEW3D_PT_tools_vertexpaint_symmetry_for_topbar", text="")
elif mode_string == 'SCULPT_CURVES': elif mode_string == 'SCULPT_CURVES':
ob = context.object
_row, sub = row_for_mirror() _row, sub = row_for_mirror()
sub.prop(context.object.data, "use_mirror_x", text="X", toggle=True) sub.prop(ob.data, "use_mirror_x", text="X", toggle=True)
sub.prop(context.object.data, "use_mirror_y", text="Y", toggle=True) sub.prop(ob.data, "use_mirror_y", text="Y", toggle=True)
sub.prop(context.object.data, "use_mirror_z", text="Z", toggle=True) sub.prop(ob.data, "use_mirror_z", text="Z", toggle=True)
layout.prop(context.object.data, "use_sculpt_collision", icon='MOD_PHYSICS', icon_only=True, toggle=True) layout.prop(ob.data, "use_sculpt_collision", icon='MOD_PHYSICS', icon_only=True, toggle=True)
# Expand panels from the side-bar as popovers. # Expand panels from the side-bar as popovers.
popover_kw = {"space_type": 'VIEW_3D', "region_type": 'UI', "category": "Tool"} popover_kw = {"space_type": 'VIEW_3D', "region_type": 'UI', "category": "Tool"}
@ -373,19 +377,20 @@ class _draw_tool_settings_context_mode:
if brush is None: if brush is None:
return False return False
ob = context.object
gp_settings = brush.gpencil_settings gp_settings = brush.gpencil_settings
row = layout.row(align=True) row = layout.row(align=True)
settings = tool_settings.gpencil_paint settings = tool_settings.gpencil_paint
row.template_ID_preview(settings, "brush", rows=3, cols=8, hide_buttons=True) row.template_ID_preview(settings, "brush", rows=3, cols=8, hide_buttons=True)
if context.object and brush.gpencil_tool in {'FILL', 'DRAW'}: if ob and brush.gpencil_tool in {'FILL', 'DRAW'}:
from bl_ui.properties_paint_common import ( from bl_ui.properties_paint_common import (
brush_basic__draw_color_selector, brush_basic__draw_color_selector,
) )
brush_basic__draw_color_selector(context, layout, brush, gp_settings, None) brush_basic__draw_color_selector(context, layout, brush, gp_settings, None)
if context.object and brush.gpencil_tool == 'TINT': if ob and brush.gpencil_tool == 'TINT':
row.separator(factor=0.4) row.separator(factor=0.4)
row.prop_with_popover(brush, "color", text="", panel="TOPBAR_PT_gpencil_vertexcolor") row.prop_with_popover(brush, "color", text="", panel="TOPBAR_PT_gpencil_vertexcolor")
@ -604,6 +609,9 @@ class _draw_tool_settings_context_mode:
) )
brush_basic__draw_color_selector(context, layout, brush, brush.gpencil_settings, None) brush_basic__draw_color_selector(context, layout, brush, brush.gpencil_settings, None)
if grease_pencil_tool == 'TINT':
UnifiedPaintPanel.prop_unified_color(row, context, brush, "color", text="")
from bl_ui.properties_paint_common import ( from bl_ui.properties_paint_common import (
brush_basic__draw_color_selector, brush_basic__draw_color_selector,
brush_basic_grease_pencil_paint_settings, brush_basic_grease_pencil_paint_settings,
@ -2717,6 +2725,8 @@ class VIEW3D_MT_object(Menu):
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
ob = context.object
layout.menu("VIEW3D_MT_transform_object") layout.menu("VIEW3D_MT_transform_object")
layout.operator_menu_enum("object.origin_set", text="Set Origin", property="type") layout.operator_menu_enum("object.origin_set", text="Set Origin", property="type")
layout.menu("VIEW3D_MT_mirror") layout.menu("VIEW3D_MT_mirror")
@ -2752,7 +2762,7 @@ class VIEW3D_MT_object(Menu):
layout.separator() layout.separator()
layout.operator("object.shade_smooth") layout.operator("object.shade_smooth")
if context.object and context.object.type == 'MESH': if ob and ob.type == 'MESH':
layout.operator("object.shade_smooth_by_angle") layout.operator("object.shade_smooth_by_angle")
layout.operator("object.shade_flat") layout.operator("object.shade_flat")
@ -3568,6 +3578,12 @@ class VIEW3D_MT_sculpt(Menu):
props = layout.operator("paint.hide_show_lasso_gesture", text="Lasso Show") props = layout.operator("paint.hide_show_lasso_gesture", text="Lasso Show")
props.action = 'SHOW' props.action = 'SHOW'
props = layout.operator("paint.hide_show_line_gesture", text="Line Hide")
props.action = 'HIDE'
props = layout.operator("paint.hide_show_line_gesture", text="Line Show")
props.action = 'SHOW'
layout.separator() layout.separator()
props = layout.operator("sculpt.face_set_change_visibility", text="Toggle Visibility") props = layout.operator("sculpt.face_set_change_visibility", text="Toggle Visibility")
@ -4078,9 +4094,10 @@ class VIEW3D_MT_bone_collections(Menu):
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
if not context.object or context.object.type != 'ARMATURE': ob = context.object
if not (ob and ob.type == 'ARMATURE'):
return False return False
if context.object.data.library: if ob.data.library:
return False return False
return True return True
@ -4534,7 +4551,8 @@ class VIEW3D_MT_edit_mesh_extrude(Menu):
tool_settings = context.tool_settings tool_settings = context.tool_settings
select_mode = tool_settings.mesh_select_mode select_mode = tool_settings.mesh_select_mode
mesh = context.object.data ob = context.object
mesh = ob.data
if mesh.total_face_sel: if mesh.total_face_sel:
layout.operator("view3d.edit_mesh_extrude_move_normal", text="Extrude Faces") layout.operator("view3d.edit_mesh_extrude_move_normal", text="Extrude Faces")
@ -7728,13 +7746,16 @@ class VIEW3D_PT_overlay_gpencil_options(Panel):
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return context.object and context.object.type == 'GPENCIL' ob = context.object
return ob and ob.type == 'GPENCIL'
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
view = context.space_data view = context.space_data
overlay = view.overlay overlay = view.overlay
ob = context.object
layout.label(text={ layout.label(text={
'PAINT_GPENCIL': iface_("Draw Grease Pencil"), 'PAINT_GPENCIL': iface_("Draw Grease Pencil"),
'EDIT_GPENCIL': iface_("Edit Grease Pencil"), 'EDIT_GPENCIL': iface_("Edit Grease Pencil"),
@ -7767,15 +7788,15 @@ class VIEW3D_PT_overlay_gpencil_options(Panel):
sub.prop(overlay, "gpencil_fade_objects", text="Fade Inactive Objects", slider=True) sub.prop(overlay, "gpencil_fade_objects", text="Fade Inactive Objects", slider=True)
sub.prop(overlay, "use_gpencil_fade_gp_objects", text="", icon='OUTLINER_OB_GREASEPENCIL') sub.prop(overlay, "use_gpencil_fade_gp_objects", text="", icon='OUTLINER_OB_GREASEPENCIL')
if context.object.mode in {'EDIT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL', 'VERTEX_GPENCIL'}: if ob.mode in {'EDIT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL', 'VERTEX_GPENCIL'}:
split = layout.split() split = layout.split()
col = split.column() col = split.column()
col.prop(overlay, "use_gpencil_edit_lines", text="Edit Lines") col.prop(overlay, "use_gpencil_edit_lines", text="Edit Lines")
col = split.column() col = split.column()
col.prop(overlay, "use_gpencil_multiedit_line_only", text="Only in Multiframe") col.prop(overlay, "use_gpencil_multiedit_line_only", text="Only in Multiframe")
if context.object.mode == 'EDIT_GPENCIL': if ob.mode == 'EDIT_GPENCIL':
gpd = context.object.data gpd = ob.data
split = layout.split() split = layout.split()
col = split.column() col = split.column()
col.prop(overlay, "use_gpencil_show_directions") col.prop(overlay, "use_gpencil_show_directions")
@ -7788,10 +7809,10 @@ class VIEW3D_PT_overlay_gpencil_options(Panel):
# Handles for Curve Edit # Handles for Curve Edit
layout.prop(overlay, "display_handle", text="Handles") layout.prop(overlay, "display_handle", text="Handles")
if context.object.mode == 'SCULPT_GPENCIL': if ob.mode == 'SCULPT_GPENCIL':
layout.prop(overlay, "vertex_opacity", text="Vertex Opacity", slider=True) layout.prop(overlay, "vertex_opacity", text="Vertex Opacity", slider=True)
if context.object.mode in {'PAINT_GPENCIL', 'VERTEX_GPENCIL'}: if ob.mode in {'PAINT_GPENCIL', 'VERTEX_GPENCIL'}:
layout.label(text="Vertex Paint") layout.label(text="Vertex Paint")
row = layout.row() row = layout.row()
shading = VIEW3D_PT_shading.get_shading(context) shading = VIEW3D_PT_shading.get_shading(context)
@ -7807,20 +7828,23 @@ class VIEW3D_PT_overlay_grease_pencil_options(Panel):
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return context.object and context.object.type == 'GREASEPENCIL' ob = context.object
return ob and ob.type == 'GREASEPENCIL'
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
view = context.space_data view = context.space_data
overlay = view.overlay overlay = view.overlay
ob = context.object
layout.label(text={ layout.label(text={
'PAINT_GREASE_PENCIL': iface_("Draw Grease Pencil"), 'PAINT_GREASE_PENCIL': iface_("Draw Grease Pencil"),
'EDIT_GREASE_PENCIL': iface_("Edit Grease Pencil"), 'EDIT_GREASE_PENCIL': iface_("Edit Grease Pencil"),
'OBJECT': iface_("Grease Pencil"), 'OBJECT': iface_("Grease Pencil"),
}[context.mode], translate=False) }[context.mode], translate=False)
if context.object.mode in {'EDIT'}: if ob.mode in {'EDIT'}:
split = layout.split() split = layout.split()
col = split.column() col = split.column()
col.prop(overlay, "use_gpencil_edit_lines", text="Edit Lines") col.prop(overlay, "use_gpencil_edit_lines", text="Edit Lines")
@ -8706,7 +8730,7 @@ class TOPBAR_PT_gpencil_materials(GreasePencilMaterialsPanel, Panel):
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
ob = context.object ob = context.object
return ob and (ob.type == 'GPENCIL' or ob.type == 'GREASEPENCIL') return ob and ob.type in {'GPENCIL', 'GREASEPENCIL'}
class TOPBAR_PT_gpencil_vertexcolor(GreasePencilVertexcolorPanel, Panel): class TOPBAR_PT_gpencil_vertexcolor(GreasePencilVertexcolorPanel, Panel):

View File

@ -610,7 +610,7 @@ class VIEW3D_PT_slots_paint_canvas(SelectPaintSlotHelper, View3DPanel, Panel):
def draw_header(self, context): def draw_header(self, context):
paint = context.tool_settings.paint_mode paint = context.tool_settings.paint_mode
ob = context.object ob = context.object
me = context.object.data me = ob.data
mat = ob.active_material mat = ob.active_material
label = iface_("Canvas") label = iface_("Canvas")
@ -641,7 +641,8 @@ class VIEW3D_PT_slots_color_attributes(Panel):
) )
def draw(self, context): def draw(self, context):
mesh = context.object.data ob = context.object
mesh = ob.data
layout = self.layout layout = self.layout
row = layout.row() row = layout.row()
@ -1119,7 +1120,9 @@ class VIEW3D_PT_sculpt_symmetry(Panel, View3DPaintPanel):
sculpt = context.tool_settings.sculpt sculpt = context.tool_settings.sculpt
row = layout.row(align=True, heading="Mirror") row = layout.row(align=True, heading="Mirror")
mesh = context.object.data
ob = context.object
mesh = ob.data
row.prop(mesh, "use_mirror_x", text="X", toggle=True) row.prop(mesh, "use_mirror_x", text="X", toggle=True)
row.prop(mesh, "use_mirror_y", text="Y", toggle=True) row.prop(mesh, "use_mirror_y", text="Y", toggle=True)
row.prop(mesh, "use_mirror_z", text="Z", toggle=True) row.prop(mesh, "use_mirror_z", text="Z", toggle=True)
@ -1162,14 +1165,16 @@ class VIEW3D_PT_curves_sculpt_symmetry(Panel, View3DPaintPanel):
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return context.object and context.object.type == 'CURVES' ob = context.object
return ob and ob.type == 'CURVES'
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
layout.use_property_split = True layout.use_property_split = True
layout.use_property_decorate = False layout.use_property_decorate = False
curves = context.object.data ob = context.object
curves = ob.data
row = layout.row(align=True, heading="Mirror") row = layout.row(align=True, heading="Mirror")
row.prop(curves, "use_mirror_x", text="X", toggle=True) row.prop(curves, "use_mirror_x", text="X", toggle=True)
@ -1206,11 +1211,13 @@ class VIEW3D_PT_tools_weightpaint_symmetry(Panel, View3DPaintPanel):
tool_settings = context.tool_settings tool_settings = context.tool_settings
wpaint = tool_settings.weight_paint wpaint = tool_settings.weight_paint
mesh = context.object.data
ob = context.object
mesh = ob.data
layout.prop(mesh, "use_mirror_vertex_groups") layout.prop(mesh, "use_mirror_vertex_groups")
draw_vpaint_symmetry(layout, wpaint, context.object) draw_vpaint_symmetry(layout, wpaint, ob)
row = layout.row() row = layout.row()
row.active = mesh.use_mirror_vertex_groups row.active = mesh.use_mirror_vertex_groups
@ -1288,7 +1295,9 @@ class VIEW3D_PT_tools_vertexpaint_symmetry(Panel, View3DPaintPanel):
tool_settings = context.tool_settings tool_settings = context.tool_settings
vpaint = tool_settings.vertex_paint vpaint = tool_settings.vertex_paint
draw_vpaint_symmetry(layout, vpaint, context.object) ob = context.object
draw_vpaint_symmetry(layout, vpaint, ob)
class VIEW3D_PT_tools_vertexpaint_symmetry_for_topbar(Panel): class VIEW3D_PT_tools_vertexpaint_symmetry_for_topbar(Panel):
@ -1353,7 +1362,8 @@ class VIEW3D_PT_tools_imagepaint_symmetry(Panel, View3DPaintPanel):
col = split.column() col = split.column()
row = col.row(align=True) row = col.row(align=True)
mesh = context.object.data ob = context.object
mesh = ob.data
row.prop(mesh, "use_mirror_x", text="X", toggle=True) row.prop(mesh, "use_mirror_x", text="X", toggle=True)
row.prop(mesh, "use_mirror_y", text="Y", toggle=True) row.prop(mesh, "use_mirror_y", text="Y", toggle=True)
row.prop(mesh, "use_mirror_z", text="Z", toggle=True) row.prop(mesh, "use_mirror_z", text="Z", toggle=True)
@ -1933,7 +1943,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_paint_falloff(GreasePencilBrushFalloff
from bl_ui.space_toolsystem_common import ToolSelectPanelHelper from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
tool = ToolSelectPanelHelper.tool_active_from_context(context) tool = ToolSelectPanelHelper.tool_active_from_context(context)
if tool and tool.idname != 'builtin_brush.Tint': if tool and tool.idname != "builtin_brush.Tint":
return False return False
gptool = brush.gpencil_tool gptool = brush.gpencil_tool
@ -2344,7 +2354,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_mixcolor(View3DPanel, Panel):
from bl_ui.space_toolsystem_common import ToolSelectPanelHelper from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
tool = ToolSelectPanelHelper.tool_active_from_context(context) tool = ToolSelectPanelHelper.tool_active_from_context(context)
if tool and tool.idname in {'builtin.cutter', 'builtin.eyedropper', 'builtin.interpolate'}: if tool and tool.idname in {"builtin.cutter", "builtin.eyedropper", "builtin.interpolate"}:
return False return False
if brush.gpencil_tool == 'TINT': if brush.gpencil_tool == 'TINT':
@ -2405,7 +2415,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_mix_palette(View3DPanel, Panel):
from bl_ui.space_toolsystem_common import ToolSelectPanelHelper from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
tool = ToolSelectPanelHelper.tool_active_from_context(context) tool = ToolSelectPanelHelper.tool_active_from_context(context)
if tool and tool.idname in {'builtin.cutter', 'builtin.eyedropper', 'builtin.interpolate'}: if tool and tool.idname in {"builtin.cutter", "builtin.eyedropper", "builtin.interpolate"}:
return False return False
if brush.gpencil_tool == 'TINT': if brush.gpencil_tool == 'TINT':
@ -2570,7 +2580,7 @@ class VIEW3D_PT_tools_grease_pencil_v3_brush_mixcolor(View3DPanel, Panel):
from bl_ui.space_toolsystem_common import ToolSelectPanelHelper from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
tool = ToolSelectPanelHelper.tool_active_from_context(context) tool = ToolSelectPanelHelper.tool_active_from_context(context)
if tool and tool.idname in {'builtin.cutter', 'builtin.eyedropper', 'builtin.interpolate'}: if tool and tool.idname in {"builtin.cutter", "builtin.eyedropper", "builtin.interpolate"}:
return False return False
if brush.gpencil_tool == 'TINT': if brush.gpencil_tool == 'TINT':
@ -2627,7 +2637,7 @@ class VIEW3D_PT_tools_grease_pencil_v3_brush_mix_palette(View3DPanel, Panel):
from bl_ui.space_toolsystem_common import ToolSelectPanelHelper from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
tool = ToolSelectPanelHelper.tool_active_from_context(context) tool = ToolSelectPanelHelper.tool_active_from_context(context)
if tool and tool.idname in {'builtin.cutter', 'builtin.eyedropper', 'builtin.interpolate'}: if tool and tool.idname in {"builtin.cutter", "builtin.eyedropper", "builtin.interpolate"}:
return False return False
if brush.gpencil_tool == 'TINT': if brush.gpencil_tool == 'TINT':

View File

@ -15,6 +15,7 @@
#include <array> #include <array>
#include "BLI_array.hh" #include "BLI_array.hh"
#include "BLI_math_vector_types.hh"
#include "DNA_customdata_types.h" #include "DNA_customdata_types.h"
@ -103,14 +104,16 @@ BMEditMesh *BKE_editmesh_from_object(Object *ob);
*/ */
void BKE_editmesh_free_data(BMEditMesh *em); void BKE_editmesh_free_data(BMEditMesh *em);
float (*BKE_editmesh_vert_coords_alloc( blender::Array<blender::float3> BKE_editmesh_vert_coords_alloc(Depsgraph *depsgraph,
Depsgraph *depsgraph, BMEditMesh *em, Scene *scene, Object *ob, int *r_vert_len))[3]; BMEditMesh *em,
float (*BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em, int *r_vert_len))[3]; Scene *scene,
const float (*BKE_editmesh_vert_coords_when_deformed(Depsgraph *depsgraph, Object *ob);
BMEditMesh *em, blender::Array<blender::float3> BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em);
Scene *scene, blender::Span<blender::float3> BKE_editmesh_vert_coords_when_deformed(
Object *obedit, Depsgraph *depsgraph,
int *r_vert_len, BMEditMesh *em,
bool *r_is_alloc))[3]; Scene *scene,
Object *obedit,
blender::Array<blender::float3> &r_alloc);
void BKE_editmesh_lnorspace_update(BMEditMesh *em); void BKE_editmesh_lnorspace_update(BMEditMesh *em);

View File

@ -18,13 +18,13 @@ namespace blender::bke {
struct EditMeshData { struct EditMeshData {
/** when set, \a vertexNos, faceNos are lazy initialized */ /** when set, \a vertexNos, faceNos are lazy initialized */
Array<float3> vertexCos; Array<float3> vert_positions;
/** lazy initialize (when \a vertexCos is set) */ /** lazy initialize (when \a vert_positions is set) */
Array<float3> vertexNos; Array<float3> vert_normals;
Array<float3> faceNos; Array<float3> face_normals;
/** also lazy init but don't depend on \a vertexCos */ /** also lazy init but don't depend on \a vert_positions */
Array<float3> faceCos; Array<float3> face_centers;
}; };
} // namespace blender::bke } // namespace blender::bke

View File

@ -199,7 +199,7 @@ Mesh *BKE_mesh_new_from_object_to_bmain(Main *bmain,
void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob); void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob);
void BKE_mesh_nomain_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb); void BKE_mesh_nomain_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb);
/* vertex level transformations & checks (no derived mesh) */ /* Vertex level transformations & checks (no evaluated mesh). */
/* basic vertex data functions */ /* basic vertex data functions */
void BKE_mesh_transform(Mesh *mesh, const float mat[4][4], bool do_keys); void BKE_mesh_transform(Mesh *mesh, const float mat[4][4], bool do_keys);

View File

@ -53,7 +53,7 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3],
uint corner_tris_len, uint corner_tris_len,
const blender::Span<bool> sharp_faces, const blender::Span<bool> sharp_faces,
CustomData *loopdata, const CustomData *loopdata,
bool calc_active_tangent, bool calc_active_tangent,
const char (*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME], const char (*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME],
int tangent_names_len, int tangent_names_len,
@ -72,7 +72,7 @@ void BKE_mesh_calc_loop_tangents(Mesh *mesh_eval,
int tangent_names_len); int tangent_names_len);
/* Helpers */ /* Helpers */
void BKE_mesh_add_loop_tangent_named_layer_for_uv(CustomData *uv_data, void BKE_mesh_add_loop_tangent_named_layer_for_uv(const CustomData *uv_data,
CustomData *tan_data, CustomData *tan_data,
int numLoopData, int numLoopData,
const char *layer_name); const char *layer_name);

View File

@ -24,7 +24,7 @@
struct BMEditMesh; struct BMEditMesh;
struct BVHCache; struct BVHCache;
struct Mesh; struct Mesh;
struct ShrinkwrapBoundaryData; class ShrinkwrapBoundaryData;
struct SubdivCCG; struct SubdivCCG;
struct SubsurfRuntimeData; struct SubsurfRuntimeData;
namespace blender::bke { namespace blender::bke {

View File

@ -26,15 +26,15 @@ int BKE_mesh_wrapper_face_len(const Mesh *mesh);
/** /**
* Return a contiguous array of vertex position values, if available. * Return a contiguous array of vertex position values, if available.
* Otherwise, vertex positions are stored in BMesh vertices. * Otherwise, vertex positions are stored in BMesh vertices and this returns null.
*/ */
const float (*BKE_mesh_wrapper_vert_coords(const Mesh *mesh))[3]; blender::Span<blender::float3> BKE_mesh_wrapper_vert_coords(const Mesh *mesh);
/** /**
* Return a contiguous array of face normal values, if available. * Return a contiguous array of face normal values, if available.
* Otherwise, normals are stored in BMesh faces. * Otherwise, normals are stored in BMesh faces and this returns null.
*/ */
const float (*BKE_mesh_wrapper_face_normals(Mesh *mesh))[3]; blender::Span<blender::float3> BKE_mesh_wrapper_face_normals(Mesh *mesh);
void BKE_mesh_wrapper_tag_positions_changed(Mesh *mesh); void BKE_mesh_wrapper_tag_positions_changed(Mesh *mesh);

View File

@ -200,8 +200,8 @@ struct ModifierTypeInfo {
/********************* Deform modifier functions *********************/ /********************* Deform modifier functions *********************/
/** /**
* Apply a deformation to the positions in the \a vertexCos array. If the \a mesh argument is * Apply a deformation to the positions in the \a positions array. If the \a mesh argument is
* non-null, if will contain proper (not wrapped) mesh data. The \a vertexCos array may or may * non-null, if will contain proper (not wrapped) mesh data. The \a positions array may or may
* not be the same as the mesh's position attribute. * not be the same as the mesh's position attribute.
*/ */
void (*deform_verts)(ModifierData *md, void (*deform_verts)(ModifierData *md,

View File

@ -242,11 +242,11 @@ Object *BKE_object_duplicate(Main *bmain,
*/ */
void BKE_object_obdata_size_init(Object *ob, float size); void BKE_object_obdata_size_init(Object *ob, float size);
void BKE_object_scale_to_mat3(Object *ob, float r_mat[3][3]); void BKE_object_scale_to_mat3(const Object *ob, float r_mat[3][3]);
void BKE_object_rot_to_mat3(const Object *ob, float r_mat[3][3], bool use_drot); void BKE_object_rot_to_mat3(const Object *ob, float r_mat[3][3], bool use_drot);
void BKE_object_mat3_to_rot(Object *ob, float r_mat[3][3], bool use_compat); void BKE_object_mat3_to_rot(Object *ob, float r_mat[3][3], bool use_compat);
void BKE_object_to_mat3(Object *ob, float r_mat[3][3]); void BKE_object_to_mat3(const Object *ob, float r_mat[3][3]);
void BKE_object_to_mat4(Object *ob, float r_mat[4][4]); void BKE_object_to_mat4(const Object *ob, float r_mat[4][4]);
/** /**
* Applies the global transformation \a mat to the \a ob using a relative parent space if * Applies the global transformation \a mat to the \a ob using a relative parent space if
* supplied. * supplied.
@ -319,7 +319,7 @@ blender::Vector<Base *> BKE_object_pose_base_array_get(const Scene *scene,
ViewLayer *view_layer, ViewLayer *view_layer,
View3D *v3d); View3D *v3d);
void BKE_object_get_parent_matrix(Object *ob, Object *par, float r_parentmat[4][4]); void BKE_object_get_parent_matrix(const Object *ob, Object *par, float r_parentmat[4][4]);
/** /**
* Compute object world transform and store it in `ob->object_to_world().ptr()`. * Compute object world transform and store it in `ob->object_to_world().ptr()`.
@ -334,7 +334,7 @@ void BKE_object_where_is_calc_time(Depsgraph *depsgraph, Scene *scene, Object *o
* No changes to object and its parent would be done. * No changes to object and its parent would be done.
* Used for bundles orientation in 3d space relative to parented blender camera. * Used for bundles orientation in 3d space relative to parented blender camera.
*/ */
void BKE_object_where_is_calc_mat4(Object *ob, float r_obmat[4][4]); void BKE_object_where_is_calc_mat4(const Object *ob, float r_obmat[4][4]);
/* Possibly belong in its own module? */ /* Possibly belong in its own module? */
@ -522,8 +522,9 @@ Mesh *BKE_object_get_pre_modified_mesh(const Object *object);
*/ */
Mesh *BKE_object_get_original_mesh(const Object *object); Mesh *BKE_object_get_original_mesh(const Object *object);
Mesh *BKE_object_get_editmesh_eval_final(const Object *object); const Mesh *BKE_object_get_editmesh_eval_final(const Object *object);
Mesh *BKE_object_get_editmesh_eval_cage(const Object *object); const Mesh *BKE_object_get_editmesh_eval_cage(const Object *object);
const Mesh *BKE_object_get_mesh_deform_eval(const Object *object);
/* Lattice accessors. /* Lattice accessors.
* These functions return either the regular lattice, or the edit-mode lattice, * These functions return either the regular lattice, or the edit-mode lattice,
@ -576,7 +577,7 @@ bool BKE_object_moves_in_time(const Object *object, bool recurse_parent);
/** Return the number of scenes using (instantiating) that object in their collections. */ /** Return the number of scenes using (instantiating) that object in their collections. */
int BKE_object_scenes_users_get(Main *bmain, Object *ob); int BKE_object_scenes_users_get(Main *bmain, Object *ob);
MovieClip *BKE_object_movieclip_get(Scene *scene, Object *ob, bool use_default); MovieClip *BKE_object_movieclip_get(Scene *scene, const Object *ob, bool use_default);
void BKE_object_runtime_reset(Object *object); void BKE_object_runtime_reset(Object *object);
/** /**

View File

@ -47,7 +47,15 @@ struct ShrinkwrapBoundaryVertData {
float normal_plane[3]; float normal_plane[3];
}; };
struct ShrinkwrapBoundaryData { class ShrinkwrapBoundaryData {
public:
/* Returns true if there is boundary information. If there is no boundary information, then the
* mesh from which this data is created from has no boundaries. */
inline bool has_boundary() const
{
return !edge_is_boundary.is_empty();
}
/* True if the edge belongs to exactly one face. */ /* True if the edge belongs to exactly one face. */
blender::BitVector<> edge_is_boundary; blender::BitVector<> edge_is_boundary;
/* True if the triangle has any boundary edges. */ /* True if the triangle has any boundary edges. */

View File

@ -75,7 +75,7 @@ void BKE_tracking_settings_init(struct MovieTracking *tracking);
* Get transformation matrix for a given object which is used * Get transformation matrix for a given object which is used
* for parenting motion tracker reconstruction to 3D world. * for parenting motion tracker reconstruction to 3D world.
*/ */
void BKE_tracking_get_camera_object_matrix(struct Object *camera_object, float mat[4][4]); void BKE_tracking_get_camera_object_matrix(const struct Object *camera_object, float mat[4][4]);
/** /**
* Get projection matrix for camera specified by given tracking object * Get projection matrix for camera specified by given tracking object
* and frame number. * and frame number.

View File

@ -981,18 +981,6 @@ static void mesh_calc_modifiers(Depsgraph *depsgraph,
} }
} }
static blender::Array<float3> editbmesh_vert_coords_alloc(const BMEditMesh *em)
{
blender::Array<float3> cos(em->bm->totvert);
BMIter iter;
BMVert *eve;
int i;
BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
cos[i] = eve->co;
}
return cos;
}
bool editbmesh_modifier_is_enabled(const Scene *scene, bool editbmesh_modifier_is_enabled(const Scene *scene,
const Object *ob, const Object *ob,
ModifierData *md, ModifierData *md,
@ -1022,7 +1010,7 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final)
case ME_WRAPPER_TYPE_BMESH: { case ME_WRAPPER_TYPE_BMESH: {
BMEditMesh &em = *mesh_final->runtime->edit_mesh; BMEditMesh &em = *mesh_final->runtime->edit_mesh;
blender::bke::EditMeshData &emd = *mesh_final->runtime->edit_data; blender::bke::EditMeshData &emd = *mesh_final->runtime->edit_data;
if (!emd.vertexCos.is_empty()) { if (!emd.vert_positions.is_empty()) {
BKE_editmesh_cache_ensure_vert_normals(em, emd); BKE_editmesh_cache_ensure_vert_normals(em, emd);
BKE_editmesh_cache_ensure_face_normals(em, emd); BKE_editmesh_cache_ensure_face_normals(em, emd);
} }
@ -1047,11 +1035,11 @@ static MutableSpan<float3> mesh_wrapper_vert_coords_ensure_for_write(Mesh *mesh)
{ {
switch (mesh->runtime->wrapper_type) { switch (mesh->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH: case ME_WRAPPER_TYPE_BMESH:
if (mesh->runtime->edit_data->vertexCos.is_empty()) { if (mesh->runtime->edit_data->vert_positions.is_empty()) {
mesh->runtime->edit_data->vertexCos = editbmesh_vert_coords_alloc( mesh->runtime->edit_data->vert_positions = BM_mesh_vert_coords_alloc(
mesh->runtime->edit_mesh); mesh->runtime->edit_mesh->bm);
} }
return mesh->runtime->edit_data->vertexCos; return mesh->runtime->edit_data->vert_positions;
case ME_WRAPPER_TYPE_MDATA: case ME_WRAPPER_TYPE_MDATA:
case ME_WRAPPER_TYPE_SUBD: case ME_WRAPPER_TYPE_SUBD:
return mesh->vert_positions_for_write(); return mesh->vert_positions_for_write();

View File

@ -1526,13 +1526,11 @@ void BKE_brush_gpencil_vertex_presets(Main *bmain, ToolSettings *ts, const bool
} }
/* Set default Vertex brush. */ /* Set default Vertex brush. */
if (reset || brush_prev == nullptr) { if ((reset == false) && (brush_prev != nullptr)) {
BKE_paint_brush_set(vertexpaint, deft_vertex); BKE_paint_brush_set(vertexpaint, brush_prev);
} }
else { else {
if (brush_prev != nullptr) { BKE_paint_brush_set(vertexpaint, deft_vertex);
BKE_paint_brush_set(vertexpaint, brush_prev);
}
} }
} }
@ -1603,13 +1601,11 @@ void BKE_brush_gpencil_sculpt_presets(Main *bmain, ToolSettings *ts, const bool
} }
/* Set default brush. */ /* Set default brush. */
if (reset || brush_prev == nullptr) { if ((reset == false) && (brush_prev != nullptr)) {
BKE_paint_brush_set(sculptpaint, deft_sculpt); BKE_paint_brush_set(sculptpaint, brush_prev);
} }
else { else {
if (brush_prev != nullptr) { BKE_paint_brush_set(sculptpaint, deft_sculpt);
BKE_paint_brush_set(sculptpaint, brush_prev);
}
} }
} }
@ -1648,13 +1644,11 @@ void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts, const bool
} }
/* Set default brush. */ /* Set default brush. */
if (reset || brush_prev == nullptr) { if ((reset == false) && (brush_prev != nullptr)) {
BKE_paint_brush_set(weightpaint, deft_weight); BKE_paint_brush_set(weightpaint, brush_prev);
} }
else { else {
if (brush_prev != nullptr) { BKE_paint_brush_set(weightpaint, deft_weight);
BKE_paint_brush_set(weightpaint, brush_prev);
}
} }
} }

View File

@ -1424,7 +1424,7 @@ bool data_transfer_layersmapping_vgroups(ListBase *r_map,
MDeformVert *data_dst = static_cast<MDeformVert *>( MDeformVert *data_dst = static_cast<MDeformVert *>(
CustomData_get_layer_for_write(cd_dst, CD_MDEFORMVERT, num_elem_dst)); CustomData_get_layer_for_write(cd_dst, CD_MDEFORMVERT, num_elem_dst));
if (data_dst && use_dupref_dst && r_map) { if (data_dst && use_dupref_dst && r_map) {
/* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ /* If dest is an evaluated mesh, we do not want to overwrite cdlayers of org mesh! */
data_dst = static_cast<MDeformVert *>( data_dst = static_cast<MDeformVert *>(
CustomData_get_layer_for_write(cd_dst, CD_MDEFORMVERT, num_elem_dst)); CustomData_get_layer_for_write(cd_dst, CD_MDEFORMVERT, num_elem_dst));
} }

View File

@ -218,7 +218,7 @@ struct PaintBakeData {
/** UV Image sequence format point */ /** UV Image sequence format point */
struct PaintUVPoint { struct PaintUVPoint {
/* Pixel / mesh data */ /* Pixel / mesh data */
/** tri index on domain derived mesh */ /** Triangle index on domain evaluated mesh. */
uint tri_index; uint tri_index;
uint pixel_index; uint pixel_index;
/* vertex indexes */ /* vertex indexes */
@ -1825,7 +1825,7 @@ static void dynamic_paint_apply_surface_displace_cb(void *__restrict userdata,
madd_v3_v3fl(data->vert_positions[i], data->vert_normals[i], -val); madd_v3_v3fl(data->vert_positions[i], data->vert_normals[i], -val);
} }
/* apply displacing vertex surface to the derived mesh */ /** Apply displacing vertex surface to the evaluated-mesh. */
static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Mesh *result) static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Mesh *result)
{ {
PaintSurfaceData *sData = surface->data; PaintSurfaceData *sData = surface->data;
@ -1911,8 +1911,8 @@ static void dynamic_paint_apply_surface_wave_cb(void *__restrict userdata,
madd_v3_v3fl(data->vert_positions[i], data->vert_normals[i], wPoint[i].height); madd_v3_v3fl(data->vert_positions[i], data->vert_normals[i], wPoint[i].height);
} }
/* /**
* Apply canvas data to the object derived mesh * Apply canvas data to the object evaluated-mesh.
*/ */
static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *ob, Mesh *mesh) static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *ob, Mesh *mesh)
{ {
@ -2094,7 +2094,7 @@ static void canvas_copyMesh(DynamicPaintCanvasSettings *canvas, Mesh *mesh)
} }
/* /*
* Updates derived mesh copy and processes dynamic paint step / caches. * Updates evaluated-mesh copy and processes dynamic paint step / caches.
*/ */
static void dynamicPaint_frameUpdate( static void dynamicPaint_frameUpdate(
DynamicPaintModifierData *pmd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *mesh) DynamicPaintModifierData *pmd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *mesh)
@ -2103,7 +2103,7 @@ static void dynamicPaint_frameUpdate(
DynamicPaintCanvasSettings *canvas = pmd->canvas; DynamicPaintCanvasSettings *canvas = pmd->canvas;
DynamicPaintSurface *surface = static_cast<DynamicPaintSurface *>(canvas->surfaces.first); DynamicPaintSurface *surface = static_cast<DynamicPaintSurface *>(canvas->surfaces.first);
/* update derived mesh copy */ /* update evaluated-mesh copy */
canvas_copyMesh(canvas, mesh); canvas_copyMesh(canvas, mesh);
/* in case image sequence baking, stop here */ /* in case image sequence baking, stop here */
@ -3855,7 +3855,8 @@ static void dynamicPaint_brushMeshCalculateVelocity(Depsgraph *depsgraph,
return; return;
} }
/* if mesh is constructive -> num of verts has changed, only use current frame derived mesh */ /* If mesh is constructive -> num of verts has changed,
* only use current frame evaluated-mesh. */
if (numOfVerts_p != numOfVerts_c) { if (numOfVerts_p != numOfVerts_c) {
positions_p = positions_c; positions_p = positions_c;
} }
@ -6174,7 +6175,7 @@ static bool dynamicPaint_generateBakeData(DynamicPaintSurface *surface,
} }
/* /*
* Make a transformed copy of canvas derived mesh vertices to avoid recalculation. * Make a transformed copy of canvas evaluated-mesh vertices to avoid recalculation.
*/ */
bData->mesh_bounds.valid = false; bData->mesh_bounds.valid = false;
for (index = 0; index < canvasNumOfVerts; index++) { for (index = 0; index < canvasNumOfVerts; index++) {
@ -6404,7 +6405,7 @@ int dynamicPaint_calculateFrame(
{ {
float timescale = 1.0f; float timescale = 1.0f;
/* apply previous displace on derivedmesh if incremental surface */ /* Apply previous displace on evaluated-mesh if incremental surface. */
if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL) { if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL) {
dynamicPaint_applySurfaceDisplace(surface, dynamicPaint_canvas_mesh_get(surface->canvas)); dynamicPaint_applySurfaceDisplace(surface, dynamicPaint_canvas_mesh_get(surface->canvas));
} }

View File

@ -27,6 +27,10 @@
#include "DEG_depsgraph_query.hh" #include "DEG_depsgraph_query.hh"
using blender::Array;
using blender::float3;
using blender::Span;
BMEditMesh *BKE_editmesh_create(BMesh *bm) BMEditMesh *BKE_editmesh_create(BMesh *bm)
{ {
BMEditMesh *em = MEM_new<BMEditMesh>(__func__); BMEditMesh *em = MEM_new<BMEditMesh>(__func__);
@ -124,7 +128,7 @@ void BKE_editmesh_free_data(BMEditMesh *em)
struct CageUserData { struct CageUserData {
int totvert; int totvert;
float (*cos_cage)[3]; blender::MutableSpan<float3> positions_cage;
BLI_bitmap *visit_bitmap; BLI_bitmap *visit_bitmap;
}; };
@ -137,16 +141,17 @@ static void cage_mapped_verts_callback(void *user_data,
if ((index >= 0 && index < data->totvert) && !BLI_BITMAP_TEST(data->visit_bitmap, index)) { if ((index >= 0 && index < data->totvert) && !BLI_BITMAP_TEST(data->visit_bitmap, index)) {
BLI_BITMAP_ENABLE(data->visit_bitmap, index); BLI_BITMAP_ENABLE(data->visit_bitmap, index);
copy_v3_v3(data->cos_cage[index], co); copy_v3_v3(data->positions_cage[index], co);
} }
} }
float (*BKE_editmesh_vert_coords_alloc( Array<float3> BKE_editmesh_vert_coords_alloc(Depsgraph *depsgraph,
Depsgraph *depsgraph, BMEditMesh *em, Scene *scene, Object *ob, int *r_vert_len))[3] BMEditMesh *em,
Scene *scene,
Object *ob)
{ {
Mesh *cage = editbmesh_get_eval_cage(depsgraph, scene, ob, em, &CD_MASK_BAREMESH); Mesh *cage = editbmesh_get_eval_cage(depsgraph, scene, ob, em, &CD_MASK_BAREMESH);
float(*cos_cage)[3] = static_cast<float(*)[3]>( Array<float3> positions_cage(em->bm->totvert);
MEM_callocN(sizeof(*cos_cage) * em->bm->totvert, __func__));
/* When initializing cage verts, we only want the first cage coordinate for each vertex, /* When initializing cage verts, we only want the first cage coordinate for each vertex,
* so that e.g. mirror or array use original vertex coordinates and not mirrored or duplicate. */ * so that e.g. mirror or array use original vertex coordinates and not mirrored or duplicate. */
@ -154,38 +159,29 @@ float (*BKE_editmesh_vert_coords_alloc(
CageUserData data; CageUserData data;
data.totvert = em->bm->totvert; data.totvert = em->bm->totvert;
data.cos_cage = cos_cage; data.positions_cage = positions_cage;
data.visit_bitmap = visit_bitmap; data.visit_bitmap = visit_bitmap;
BKE_mesh_foreach_mapped_vert(cage, cage_mapped_verts_callback, &data, MESH_FOREACH_NOP); BKE_mesh_foreach_mapped_vert(cage, cage_mapped_verts_callback, &data, MESH_FOREACH_NOP);
MEM_freeN(visit_bitmap); MEM_freeN(visit_bitmap);
if (r_vert_len) { return positions_cage;
*r_vert_len = em->bm->totvert;
}
return cos_cage;
} }
const float (*BKE_editmesh_vert_coords_when_deformed(Depsgraph *depsgraph, Span<float3> BKE_editmesh_vert_coords_when_deformed(
BMEditMesh *em, Depsgraph *depsgraph, BMEditMesh *em, Scene *scene, Object *ob, Array<float3> &r_alloc)
Scene *scene,
Object *ob,
int *r_vert_len,
bool *r_is_alloc))[3]
{ {
const float(*coords)[3] = nullptr;
*r_is_alloc = false;
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); const Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object_eval); const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object_eval);
Mesh *mesh_cage = BKE_object_get_editmesh_eval_cage(ob); const Mesh *mesh_cage = BKE_object_get_editmesh_eval_cage(ob);
Span<float3> vert_positions;
if (mesh_cage && mesh_cage->runtime->deformed_only) { if (mesh_cage && mesh_cage->runtime->deformed_only) {
BLI_assert(BKE_mesh_wrapper_vert_len(mesh_cage) == em->bm->totvert); BLI_assert(BKE_mesh_wrapper_vert_len(mesh_cage) == em->bm->totvert);
/* Deformed, and we have deformed coords already. */ /* Deformed, and we have deformed coords already. */
coords = BKE_mesh_wrapper_vert_coords(mesh_cage); vert_positions = BKE_mesh_wrapper_vert_coords(mesh_cage);
} }
else if ((editmesh_eval_final != nullptr) && else if ((editmesh_eval_final != nullptr) &&
(editmesh_eval_final->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH)) (editmesh_eval_final->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH))
@ -194,15 +190,15 @@ const float (*BKE_editmesh_vert_coords_when_deformed(Depsgraph *depsgraph,
} }
else { else {
/* Constructive modifiers have been used, we need to allocate coordinates. */ /* Constructive modifiers have been used, we need to allocate coordinates. */
*r_is_alloc = true; r_alloc = BKE_editmesh_vert_coords_alloc(depsgraph, em, scene, ob);
coords = BKE_editmesh_vert_coords_alloc(depsgraph, em, scene, ob, r_vert_len); return r_alloc.as_span();
} }
return coords; return vert_positions;
} }
float (*BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em, int *r_vert_len))[3] Array<float3> BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em)
{ {
return BM_mesh_vert_coords_alloc(em->bm, r_vert_len); return BM_mesh_vert_coords_alloc(em->bm);
} }
void BKE_editmesh_lnorspace_update(BMEditMesh *em) void BKE_editmesh_lnorspace_update(BMEditMesh *em)

View File

@ -23,12 +23,12 @@
void BKE_editmesh_cache_ensure_face_normals(BMEditMesh &em, blender::bke::EditMeshData &emd) void BKE_editmesh_cache_ensure_face_normals(BMEditMesh &em, blender::bke::EditMeshData &emd)
{ {
if (emd.vertexCos.is_empty() || !emd.faceNos.is_empty()) { if (emd.vert_positions.is_empty() || !emd.face_normals.is_empty()) {
return; return;
} }
BMesh *bm = em.bm; BMesh *bm = em.bm;
emd.faceNos.reinitialize(bm->totface); emd.face_normals.reinitialize(bm->totface);
BM_mesh_elem_index_ensure(bm, BM_VERT); BM_mesh_elem_index_ensure(bm, BM_VERT);
BMFace *efa; BMFace *efa;
@ -36,15 +36,17 @@ void BKE_editmesh_cache_ensure_face_normals(BMEditMesh &em, blender::bke::EditMe
int i; int i;
BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) { BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
BM_elem_index_set(efa, i); /* set_inline */ BM_elem_index_set(efa, i); /* set_inline */
BM_face_calc_normal_vcos( BM_face_calc_normal_vcos(bm,
bm, efa, emd.faceNos[i], reinterpret_cast<const float(*)[3]>(emd.vertexCos.data())); efa,
emd.face_normals[i],
reinterpret_cast<const float(*)[3]>(emd.vert_positions.data()));
} }
bm->elem_index_dirty &= ~BM_FACE; bm->elem_index_dirty &= ~BM_FACE;
} }
void BKE_editmesh_cache_ensure_vert_normals(BMEditMesh &em, blender::bke::EditMeshData &emd) void BKE_editmesh_cache_ensure_vert_normals(BMEditMesh &em, blender::bke::EditMeshData &emd)
{ {
if (emd.vertexCos.is_empty() || !emd.vertexNos.is_empty()) { if (emd.vert_positions.is_empty() || !emd.vert_normals.is_empty()) {
return; return;
} }
BMesh *bm = em.bm; BMesh *bm = em.bm;
@ -52,37 +54,36 @@ void BKE_editmesh_cache_ensure_vert_normals(BMEditMesh &em, blender::bke::EditMe
/* Calculate vertex normals from face normals. */ /* Calculate vertex normals from face normals. */
BKE_editmesh_cache_ensure_face_normals(em, emd); BKE_editmesh_cache_ensure_face_normals(em, emd);
emd.vertexNos.reinitialize(bm->totvert); emd.vert_normals.reinitialize(bm->totvert);
BM_mesh_elem_index_ensure(bm, BM_FACE); BM_mesh_elem_index_ensure(bm, BM_FACE);
BM_verts_calc_normal_vcos(bm, BM_verts_calc_normal_vcos(bm,
reinterpret_cast<const float(*)[3]>(emd.faceNos.data()), reinterpret_cast<const float(*)[3]>(emd.face_normals.data()),
reinterpret_cast<const float(*)[3]>(emd.vertexCos.data()), reinterpret_cast<const float(*)[3]>(emd.vert_positions.data()),
reinterpret_cast<float(*)[3]>(emd.vertexNos.data())); reinterpret_cast<float(*)[3]>(emd.vert_normals.data()));
} }
void BKE_editmesh_cache_ensure_face_centers(BMEditMesh &em, blender::bke::EditMeshData &emd) void BKE_editmesh_cache_ensure_face_centers(BMEditMesh &em, blender::bke::EditMeshData &emd)
{ {
if (!emd.faceCos.is_empty()) { if (!emd.face_centers.is_empty()) {
return; return;
} }
BMesh *bm = em.bm; BMesh *bm = em.bm;
emd.faceCos.reinitialize(bm->totface); emd.face_centers.reinitialize(bm->totface);
BMFace *efa; BMFace *efa;
BMIter fiter; BMIter fiter;
int i; int i;
if (emd.vertexCos.is_empty()) { if (emd.vert_positions.is_empty()) {
BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) { BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
BM_face_calc_center_median(efa, emd.faceCos[i]); BM_face_calc_center_median(efa, emd.face_centers[i]);
} }
} }
else { else {
BM_mesh_elem_index_ensure(bm, BM_VERT); BM_mesh_elem_index_ensure(bm, BM_VERT);
BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) { BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
BM_face_calc_center_median_vcos( BM_face_calc_center_median_vcos(bm, efa, emd.face_centers[i], emd.vert_positions);
bm, efa, emd.faceCos[i], reinterpret_cast<const float(*)[3]>(emd.vertexCos.data()));
} }
} }
} }
@ -102,7 +103,7 @@ std::optional<blender::Bounds<blender::float3>> BKE_editmesh_cache_calc_minmax(
return std::nullopt; return std::nullopt;
} }
if (emd.vertexCos.is_empty()) { if (emd.vert_positions.is_empty()) {
BMVert *eve; BMVert *eve;
BMIter iter; BMIter iter;
float3 min(std::numeric_limits<float>::max()); float3 min(std::numeric_limits<float>::max());
@ -113,7 +114,7 @@ std::optional<blender::Bounds<blender::float3>> BKE_editmesh_cache_calc_minmax(
return Bounds<float3>{min, max}; return Bounds<float3>{min, max};
} }
return bounds::min_max(emd.vertexCos.as_span()); return bounds::min_max(emd.vert_positions.as_span());
} }
/** \} */ /** \} */

View File

@ -727,13 +727,13 @@ Material *BKE_object_material_get(Object *ob, short act)
return ma_p ? *ma_p : nullptr; return ma_p ? *ma_p : nullptr;
} }
static ID *get_evaluated_object_data_with_materials(Object *ob) static const ID *get_evaluated_object_data_with_materials(Object *ob)
{ {
ID *data = static_cast<ID *>(ob->data); const ID *data = static_cast<ID *>(ob->data);
/* Meshes in edit mode need special handling. */ /* Meshes in edit mode need special handling. */
if (ob->type == OB_MESH && ob->mode == OB_MODE_EDIT) { if (ob->type == OB_MESH && ob->mode == OB_MODE_EDIT) {
Mesh *mesh = static_cast<Mesh *>(ob->data); const Mesh *mesh = static_cast<const Mesh *>(ob->data);
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob); const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
if (mesh->runtime->edit_mesh && editmesh_eval_final) { if (mesh->runtime->edit_mesh && editmesh_eval_final) {
data = &editmesh_eval_final->id; data = &editmesh_eval_final->id;
} }
@ -745,8 +745,8 @@ Material *BKE_object_material_get_eval(Object *ob, short act)
{ {
BLI_assert(DEG_is_evaluated_object(ob)); BLI_assert(DEG_is_evaluated_object(ob));
ID *data = get_evaluated_object_data_with_materials(ob); const ID *data = get_evaluated_object_data_with_materials(ob);
const short *tot_slots_data_ptr = BKE_id_material_len_p(data); const short *tot_slots_data_ptr = BKE_id_material_len_p(const_cast<ID *>(data));
const int tot_slots_data = tot_slots_data_ptr ? *tot_slots_data_ptr : 0; const int tot_slots_data = tot_slots_data_ptr ? *tot_slots_data_ptr : 0;
if (tot_slots_data == 0) { if (tot_slots_data == 0) {
@ -757,7 +757,7 @@ Material *BKE_object_material_get_eval(Object *ob, short act)
const int slot_index = clamp_i(act - 1, 0, tot_slots_data - 1); const int slot_index = clamp_i(act - 1, 0, tot_slots_data - 1);
const int tot_slots_object = ob->totcol; const int tot_slots_object = ob->totcol;
Material ***materials_data_ptr = BKE_id_material_array_p(data); Material ***materials_data_ptr = BKE_id_material_array_p(const_cast<ID *>(data));
Material **materials_data = materials_data_ptr ? *materials_data_ptr : nullptr; Material **materials_data = materials_data_ptr ? *materials_data_ptr : nullptr;
Material **materials_object = ob->mat; Material **materials_object = ob->mat;

View File

@ -769,15 +769,15 @@ static Mesh *mesh_new_from_mball_object(Object *object)
return BKE_mesh_copy_for_eval(mesh_eval); return BKE_mesh_copy_for_eval(mesh_eval);
} }
static Mesh *mesh_new_from_mesh(Object *object, Mesh *mesh) static Mesh *mesh_new_from_mesh(Object *object, const Mesh *mesh)
{ {
/* While we could copy this into the new mesh, /* While we could copy this into the new mesh,
* add the data to 'mesh' so future calls to this function don't need to re-convert the data. */ * add the data to 'mesh' so future calls to this function don't need to re-convert the data. */
if (mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) { if (mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) {
BKE_mesh_wrapper_ensure_mdata(mesh); BKE_mesh_wrapper_ensure_mdata(const_cast<Mesh *>(mesh));
} }
else { else {
mesh = BKE_mesh_wrapper_ensure_subdivision(mesh); mesh = BKE_mesh_wrapper_ensure_subdivision(const_cast<Mesh *>(mesh));
} }
Mesh *mesh_result = (Mesh *)BKE_id_copy_ex( Mesh *mesh_result = (Mesh *)BKE_id_copy_ex(
@ -828,12 +828,11 @@ static Mesh *mesh_new_from_mesh_object(Depsgraph *depsgraph,
if (preserve_all_data_layers || preserve_origindex) { if (preserve_all_data_layers || preserve_origindex) {
return mesh_new_from_mesh_object_with_layers(depsgraph, object, preserve_origindex); return mesh_new_from_mesh_object_with_layers(depsgraph, object, preserve_origindex);
} }
Mesh *mesh_input = (Mesh *)object->data; const Mesh *mesh_input = (const Mesh *)object->data;
/* If we are in edit mode, use evaluated mesh from edit structure, matching to what /* If we are in edit mode, use evaluated mesh from edit structure, matching to what
* viewport is using for visualization. */ * viewport is using for visualization. */
if (mesh_input->runtime->edit_mesh != nullptr) { if (mesh_input->runtime->edit_mesh != nullptr) {
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object); if (const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object)) {
if (editmesh_eval_final != nullptr) {
mesh_input = editmesh_eval_final; mesh_input = editmesh_eval_final;
} }
} }

View File

@ -41,12 +41,12 @@ void BKE_mesh_foreach_mapped_vert(
BMIter iter; BMIter iter;
BMVert *eve; BMVert *eve;
int i; int i;
if (!mesh->runtime->edit_data->vertexCos.is_empty()) { if (!mesh->runtime->edit_data->vert_positions.is_empty()) {
const blender::Span<blender::float3> positions = mesh->runtime->edit_data->vertexCos; const blender::Span<blender::float3> positions = mesh->runtime->edit_data->vert_positions;
blender::Span<blender::float3> vert_normals; blender::Span<blender::float3> vert_normals;
if (flag & MESH_FOREACH_USE_NORMAL) { if (flag & MESH_FOREACH_USE_NORMAL) {
BKE_editmesh_cache_ensure_vert_normals(*em, *mesh->runtime->edit_data); BKE_editmesh_cache_ensure_vert_normals(*em, *mesh->runtime->edit_data);
vert_normals = mesh->runtime->edit_data->vertexNos; vert_normals = mesh->runtime->edit_data->vert_normals;
} }
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? &vert_normals[i].x : nullptr; const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? &vert_normals[i].x : nullptr;
@ -100,8 +100,8 @@ void BKE_mesh_foreach_mapped_edge(
BMIter iter; BMIter iter;
BMEdge *eed; BMEdge *eed;
int i; int i;
if (!mesh->runtime->edit_data->vertexCos.is_empty()) { if (!mesh->runtime->edit_data->vert_positions.is_empty()) {
const blender::Span<blender::float3> positions = mesh->runtime->edit_data->vertexCos; const blender::Span<blender::float3> positions = mesh->runtime->edit_data->vert_positions;
BM_mesh_elem_index_ensure(bm, BM_VERT); BM_mesh_elem_index_ensure(bm, BM_VERT);
BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) { BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
func(user_data, func(user_data,
@ -159,7 +159,7 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
BMIter iter; BMIter iter;
BMFace *efa; BMFace *efa;
const blender::Span<blender::float3> positions = mesh->runtime->edit_data->vertexCos; const blender::Span<blender::float3> positions = mesh->runtime->edit_data->vert_positions;
/* XXX: investigate using EditMesh data. */ /* XXX: investigate using EditMesh data. */
blender::Span<blender::float3> corner_normals; blender::Span<blender::float3> corner_normals;
@ -243,11 +243,11 @@ void BKE_mesh_foreach_mapped_face_center(
int i; int i;
BKE_editmesh_cache_ensure_face_centers(*em, *mesh->runtime->edit_data); BKE_editmesh_cache_ensure_face_centers(*em, *mesh->runtime->edit_data);
face_centers = mesh->runtime->edit_data->faceCos; /* always set */ face_centers = mesh->runtime->edit_data->face_centers; /* always set */
if (flag & MESH_FOREACH_USE_NORMAL) { if (flag & MESH_FOREACH_USE_NORMAL) {
BKE_editmesh_cache_ensure_face_normals(*em, *mesh->runtime->edit_data); BKE_editmesh_cache_ensure_face_normals(*em, *mesh->runtime->edit_data);
face_normals = mesh->runtime->edit_data->faceNos; /* maybe nullptr */ face_normals = mesh->runtime->edit_data->face_normals; /* maybe nullptr */
} }
if (!face_normals.is_empty()) { if (!face_normals.is_empty()) {

View File

@ -297,7 +297,7 @@ static void DM_calc_loop_tangents_thread(TaskPool *__restrict /*pool*/, void *ta
mikk.genTangSpace(); mikk.genTangSpace();
} }
void BKE_mesh_add_loop_tangent_named_layer_for_uv(CustomData *uv_data, void BKE_mesh_add_loop_tangent_named_layer_for_uv(const CustomData *uv_data,
CustomData *tan_data, CustomData *tan_data,
int numLoopData, int numLoopData,
const char *layer_name) const char *layer_name)
@ -393,7 +393,7 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3],
const uint corner_tris_len, const uint corner_tris_len,
const blender::Span<bool> sharp_faces, const blender::Span<bool> sharp_faces,
CustomData *loopdata, const CustomData *loopdata,
bool calc_active_tangent, bool calc_active_tangent,
const char (*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME], const char (*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME],
int tangent_names_len, int tangent_names_len,
@ -554,7 +554,7 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3],
if (act_uv_index != -1) { if (act_uv_index != -1) {
int tan_index = CustomData_get_named_layer_index( int tan_index = CustomData_get_named_layer_index(
loopdata, CD_TANGENT, loopdata->layers[act_uv_index].name); loopdata, CD_TANGENT, loopdata->layers[act_uv_index].name);
CustomData_set_layer_active_index(loopdata, CD_TANGENT, tan_index); CustomData_set_layer_active_index(loopdata_out, CD_TANGENT, tan_index);
} /* else tangent has been built from orco */ } /* else tangent has been built from orco */
/* Update render layer index */ /* Update render layer index */
@ -564,7 +564,7 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3],
if (ren_uv_index != -1) { if (ren_uv_index != -1) {
int tan_index = CustomData_get_named_layer_index( int tan_index = CustomData_get_named_layer_index(
loopdata, CD_TANGENT, loopdata->layers[ren_uv_index].name); loopdata, CD_TANGENT, loopdata->layers[ren_uv_index].name);
CustomData_set_layer_render_index(loopdata, CD_TANGENT, tan_index); CustomData_set_layer_render_index(loopdata_out, CD_TANGENT, tan_index);
} /* else tangent has been built from orco */ } /* else tangent has been built from orco */
} }
} }

View File

@ -124,8 +124,8 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *mesh)
BKE_mesh_ensure_default_orig_index_customdata_no_check(mesh); BKE_mesh_ensure_default_orig_index_customdata_no_check(mesh);
blender::bke::EditMeshData &edit_data = *mesh->runtime->edit_data; blender::bke::EditMeshData &edit_data = *mesh->runtime->edit_data;
if (!edit_data.vertexCos.is_empty()) { if (!edit_data.vert_positions.is_empty()) {
mesh->vert_positions_for_write().copy_from(edit_data.vertexCos); mesh->vert_positions_for_write().copy_from(edit_data.vert_positions);
mesh->runtime->is_original_bmesh = false; mesh->runtime->is_original_bmesh = false;
} }
@ -148,35 +148,31 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *mesh)
/** \name Mesh Coordinate Access /** \name Mesh Coordinate Access
* \{ */ * \{ */
const float (*BKE_mesh_wrapper_vert_coords(const Mesh *mesh))[3] Span<float3> BKE_mesh_wrapper_vert_coords(const Mesh *mesh)
{ {
switch (mesh->runtime->wrapper_type) { switch (mesh->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH: case ME_WRAPPER_TYPE_BMESH:
if (mesh->runtime->edit_data->vertexCos.is_empty()) { return mesh->runtime->edit_data->vert_positions;
return nullptr;
}
return reinterpret_cast<const float(*)[3]>(mesh->runtime->edit_data->vertexCos.data());
case ME_WRAPPER_TYPE_MDATA: case ME_WRAPPER_TYPE_MDATA:
case ME_WRAPPER_TYPE_SUBD: case ME_WRAPPER_TYPE_SUBD:
return reinterpret_cast<const float(*)[3]>(mesh->vert_positions().data()); return mesh->vert_positions();
} }
return nullptr; BLI_assert_unreachable();
return {};
} }
const float (*BKE_mesh_wrapper_face_normals(Mesh *mesh))[3] Span<float3> BKE_mesh_wrapper_face_normals(Mesh *mesh)
{ {
switch (mesh->runtime->wrapper_type) { switch (mesh->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH: case ME_WRAPPER_TYPE_BMESH:
BKE_editmesh_cache_ensure_face_normals(*mesh->runtime->edit_mesh, *mesh->runtime->edit_data); BKE_editmesh_cache_ensure_face_normals(*mesh->runtime->edit_mesh, *mesh->runtime->edit_data);
if (mesh->runtime->edit_data->faceNos.is_empty()) { return mesh->runtime->edit_data->face_normals;
return nullptr;
}
return reinterpret_cast<const float(*)[3]>(mesh->runtime->edit_data->faceNos.data());
case ME_WRAPPER_TYPE_MDATA: case ME_WRAPPER_TYPE_MDATA:
case ME_WRAPPER_TYPE_SUBD: case ME_WRAPPER_TYPE_SUBD:
return reinterpret_cast<const float(*)[3]>(mesh->face_normals().data()); return mesh->face_normals();
} }
return nullptr; BLI_assert_unreachable();
return {};
} }
void BKE_mesh_wrapper_tag_positions_changed(Mesh *mesh) void BKE_mesh_wrapper_tag_positions_changed(Mesh *mesh)
@ -184,9 +180,9 @@ void BKE_mesh_wrapper_tag_positions_changed(Mesh *mesh)
switch (mesh->runtime->wrapper_type) { switch (mesh->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH: case ME_WRAPPER_TYPE_BMESH:
if (mesh->runtime->edit_data) { if (mesh->runtime->edit_data) {
mesh->runtime->edit_data->vertexNos = {}; mesh->runtime->edit_data->vert_normals = {};
mesh->runtime->edit_data->faceCos = {}; mesh->runtime->edit_data->face_centers = {};
mesh->runtime->edit_data->faceNos = {}; mesh->runtime->edit_data->face_normals = {};
} }
break; break;
case ME_WRAPPER_TYPE_MDATA: case ME_WRAPPER_TYPE_MDATA:
@ -202,8 +198,8 @@ void BKE_mesh_wrapper_vert_coords_copy(const Mesh *mesh, blender::MutableSpan<fl
case ME_WRAPPER_TYPE_BMESH: { case ME_WRAPPER_TYPE_BMESH: {
BMesh *bm = mesh->runtime->edit_mesh->bm; BMesh *bm = mesh->runtime->edit_mesh->bm;
const blender::bke::EditMeshData &edit_data = *mesh->runtime->edit_data; const blender::bke::EditMeshData &edit_data = *mesh->runtime->edit_data;
if (!edit_data.vertexCos.is_empty()) { if (!edit_data.vert_positions.is_empty()) {
positions.copy_from(edit_data.vertexCos); positions.copy_from(edit_data.vert_positions);
} }
else { else {
BMIter iter; BMIter iter;
@ -234,9 +230,9 @@ void BKE_mesh_wrapper_vert_coords_copy_with_mat4(const Mesh *mesh,
BMesh *bm = mesh->runtime->edit_mesh->bm; BMesh *bm = mesh->runtime->edit_mesh->bm;
BLI_assert(vert_coords_len == bm->totvert); BLI_assert(vert_coords_len == bm->totvert);
const blender::bke::EditMeshData &edit_data = *mesh->runtime->edit_data; const blender::bke::EditMeshData &edit_data = *mesh->runtime->edit_data;
if (!edit_data.vertexCos.is_empty()) { if (!edit_data.vert_positions.is_empty()) {
for (int i = 0; i < vert_coords_len; i++) { for (int i = 0; i < vert_coords_len; i++) {
mul_v3_m4v3(vert_coords[i], mat, edit_data.vertexCos[i]); mul_v3_m4v3(vert_coords[i], mat, edit_data.vert_positions[i]);
} }
} }
else { else {

View File

@ -879,7 +879,7 @@ static void modwrap_dependsOnNormals(Mesh *mesh)
switch (mesh->runtime->wrapper_type) { switch (mesh->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH: { case ME_WRAPPER_TYPE_BMESH: {
blender::bke::EditMeshData &edit_data = *mesh->runtime->edit_data; blender::bke::EditMeshData &edit_data = *mesh->runtime->edit_data;
if (!edit_data.vertexCos.is_empty()) { if (!edit_data.vert_positions.is_empty()) {
/* Note that 'ensure' is acceptable here since these values aren't modified in-place. /* Note that 'ensure' is acceptable here since these values aren't modified in-place.
* If that changes we'll need to recalculate. */ * If that changes we'll need to recalculate. */
BKE_editmesh_cache_ensure_vert_normals(*mesh->runtime->edit_mesh, edit_data); BKE_editmesh_cache_ensure_vert_normals(*mesh->runtime->edit_mesh, edit_data);
@ -952,10 +952,10 @@ Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval)
if ((ob_eval->type == OB_MESH) && (ob_eval->mode & OB_MODE_EDIT)) { if ((ob_eval->type == OB_MESH) && (ob_eval->mode & OB_MODE_EDIT)) {
/* In EditMode, evaluated mesh is stored in BMEditMesh, not the object... */ /* In EditMode, evaluated mesh is stored in BMEditMesh, not the object... */
BMEditMesh *em = BKE_editmesh_from_object(ob_eval); const BMEditMesh *em = BKE_editmesh_from_object(ob_eval);
/* 'em' might not exist yet in some cases, just after loading a .blend file, see #57878. */ /* 'em' might not exist yet in some cases, just after loading a .blend file, see #57878. */
if (em != nullptr) { if (em != nullptr) {
mesh = BKE_object_get_editmesh_eval_final(ob_eval); mesh = const_cast<Mesh *>(BKE_object_get_editmesh_eval_final(ob_eval));
} }
} }
if (mesh == nullptr) { if (mesh == nullptr) {

View File

@ -2764,7 +2764,7 @@ void BKE_object_obdata_size_init(Object *ob, const float size)
/** \name Object Matrix Get/Set API /** \name Object Matrix Get/Set API
* \{ */ * \{ */
void BKE_object_scale_to_mat3(Object *ob, float mat[3][3]) void BKE_object_scale_to_mat3(const Object *ob, float mat[3][3])
{ {
float3 vec; float3 vec;
mul_v3_v3v3(vec, ob->scale, ob->dscale); mul_v3_v3v3(vec, ob->scale, ob->dscale);
@ -2946,7 +2946,7 @@ void BKE_object_tfm_copy(Object *object_dst, const Object *object_src)
#undef TFMCPY4D #undef TFMCPY4D
} }
void BKE_object_to_mat3(Object *ob, float r_mat[3][3]) /* no parent */ void BKE_object_to_mat3(const Object *ob, float r_mat[3][3]) /* no parent */
{ {
float smat[3][3]; float smat[3][3];
float rmat[3][3]; float rmat[3][3];
@ -2959,7 +2959,7 @@ void BKE_object_to_mat3(Object *ob, float r_mat[3][3]) /* no parent */
mul_m3_m3m3(r_mat, rmat, smat); mul_m3_m3m3(r_mat, rmat, smat);
} }
void BKE_object_to_mat4(Object *ob, float r_mat[4][4]) void BKE_object_to_mat4(const Object *ob, float r_mat[4][4])
{ {
float tmat[3][3]; float tmat[3][3];
@ -2987,7 +2987,7 @@ void BKE_object_matrix_local_get(Object *ob, float r_mat[4][4])
/** /**
* \return success if \a mat is set. * \return success if \a mat is set.
*/ */
static bool ob_parcurve(Object *ob, Object *par, float r_mat[4][4]) static bool ob_parcurve(const Object *ob, Object *par, float r_mat[4][4])
{ {
Curve *cu = (Curve *)par->data; Curve *cu = (Curve *)par->data;
float vec[4], quat[4], radius, ctime; float vec[4], quat[4], radius, ctime;
@ -3046,7 +3046,7 @@ static bool ob_parcurve(Object *ob, Object *par, float r_mat[4][4])
return true; return true;
} }
static void ob_parbone(Object *ob, Object *par, float r_mat[4][4]) static void ob_parbone(const Object *ob, const Object *par, float r_mat[4][4])
{ {
float3 vec; float3 vec;
@ -3056,7 +3056,7 @@ static void ob_parbone(Object *ob, Object *par, float r_mat[4][4])
} }
/* Make sure the bone is still valid */ /* Make sure the bone is still valid */
bPoseChannel *pchan = BKE_pose_channel_find_name(par->pose, ob->parsubstr); const bPoseChannel *pchan = BKE_pose_channel_find_name(par->pose, ob->parsubstr);
if (!pchan || !pchan->bone) { if (!pchan || !pchan->bone) {
CLOG_WARN( CLOG_WARN(
&LOG, "Parent Bone: '%s' for Object: '%s' doesn't exist", ob->parsubstr, ob->id.name + 2); &LOG, "Parent Bone: '%s' for Object: '%s' doesn't exist", ob->parsubstr, ob->id.name + 2);
@ -3080,15 +3080,15 @@ static void ob_parbone(Object *ob, Object *par, float r_mat[4][4])
} }
} }
static void give_parvert(Object *par, int nr, float vec[3]) static void give_parvert(const Object *par, int nr, float vec[3])
{ {
zero_v3(vec); zero_v3(vec);
if (par->type == OB_MESH) { if (par->type == OB_MESH) {
Mesh *mesh = (Mesh *)par->data; const Mesh *mesh = (const Mesh *)par->data;
BMEditMesh *em = mesh->runtime->edit_mesh; const BMEditMesh *em = mesh->runtime->edit_mesh;
Mesh *mesh_eval = (em) ? BKE_object_get_editmesh_eval_final(par) : const Mesh *mesh_eval = (em) ? BKE_object_get_editmesh_eval_final(par) :
BKE_object_get_evaluated_mesh(par); BKE_object_get_evaluated_mesh(par);
if (mesh_eval) { if (mesh_eval) {
const Span<float3> positions = mesh_eval->vert_positions(); const Span<float3> positions = mesh_eval->vert_positions();
@ -3111,9 +3111,9 @@ static void give_parvert(Object *par, int nr, float vec[3])
} }
if (nr < numVerts) { if (nr < numVerts) {
if (mesh_eval && mesh_eval->runtime->edit_data && if (mesh_eval && mesh_eval->runtime->edit_data &&
!mesh_eval->runtime->edit_data->vertexCos.is_empty()) !mesh_eval->runtime->edit_data->vert_positions.is_empty())
{ {
add_v3_v3(vec, mesh_eval->runtime->edit_data->vertexCos[nr]); add_v3_v3(vec, mesh_eval->runtime->edit_data->vert_positions[nr]);
} }
else { else {
const BMVert *v = BM_vert_at_index(em->bm, nr); const BMVert *v = BM_vert_at_index(em->bm, nr);
@ -3201,7 +3201,7 @@ static void give_parvert(Object *par, int nr, float vec[3])
} }
} }
static void ob_parvert3(Object *ob, Object *par, float r_mat[4][4]) static void ob_parvert3(const Object *ob, const Object *par, float r_mat[4][4])
{ {
/* in local ob space */ /* in local ob space */
if (OB_TYPE_SUPPORT_PARVERT(par->type)) { if (OB_TYPE_SUPPORT_PARVERT(par->type)) {
@ -3222,7 +3222,7 @@ static void ob_parvert3(Object *ob, Object *par, float r_mat[4][4])
} }
} }
void BKE_object_get_parent_matrix(Object *ob, Object *par, float r_parentmat[4][4]) void BKE_object_get_parent_matrix(const Object *ob, Object *par, float r_parentmat[4][4])
{ {
float tmat[4][4]; float tmat[4][4];
float vec[3]; float vec[3];
@ -3277,8 +3277,11 @@ void BKE_object_get_parent_matrix(Object *ob, Object *par, float r_parentmat[4][
* \param r_originmat: Optional matrix that stores the space the object is in * \param r_originmat: Optional matrix that stores the space the object is in
* (without its own matrix applied) * (without its own matrix applied)
*/ */
static void solve_parenting( static void solve_parenting(const Object *ob,
Object *ob, Object *par, const bool set_origin, float r_obmat[4][4], float r_originmat[3][3]) Object *par,
const bool set_origin,
float r_obmat[4][4],
float r_originmat[3][3])
{ {
float totmat[4][4]; float totmat[4][4];
float tmat[4][4]; float tmat[4][4];
@ -3358,7 +3361,7 @@ void BKE_object_where_is_calc_time(Depsgraph *depsgraph, Scene *scene, Object *o
object_where_is_calc_ex(depsgraph, scene, ob, ctime, nullptr, nullptr); object_where_is_calc_ex(depsgraph, scene, ob, ctime, nullptr, nullptr);
} }
void BKE_object_where_is_calc_mat4(Object *ob, float r_obmat[4][4]) void BKE_object_where_is_calc_mat4(const Object *ob, float r_obmat[4][4])
{ {
if (ob->parent) { if (ob->parent) {
Object *par = ob->parent; Object *par = ob->parent;
@ -4202,7 +4205,7 @@ Mesh *BKE_object_get_original_mesh(const Object *object)
return result; return result;
} }
Mesh *BKE_object_get_editmesh_eval_final(const Object *object) const Mesh *BKE_object_get_editmesh_eval_final(const Object *object)
{ {
BLI_assert(!DEG_is_original_id(&object->id)); BLI_assert(!DEG_is_original_id(&object->id));
BLI_assert(object->type == OB_MESH); BLI_assert(object->type == OB_MESH);
@ -4217,7 +4220,7 @@ Mesh *BKE_object_get_editmesh_eval_final(const Object *object)
return reinterpret_cast<Mesh *>(object->runtime->data_eval); return reinterpret_cast<Mesh *>(object->runtime->data_eval);
} }
Mesh *BKE_object_get_editmesh_eval_cage(const Object *object) const Mesh *BKE_object_get_editmesh_eval_cage(const Object *object)
{ {
BLI_assert(!DEG_is_original_id(&object->id)); BLI_assert(!DEG_is_original_id(&object->id));
BLI_assert(object->type == OB_MESH); BLI_assert(object->type == OB_MESH);
@ -4229,6 +4232,13 @@ Mesh *BKE_object_get_editmesh_eval_cage(const Object *object)
return object->runtime->editmesh_eval_cage; return object->runtime->editmesh_eval_cage;
} }
const Mesh *BKE_object_get_mesh_deform_eval(const Object *object)
{
BLI_assert(!DEG_is_original_id(&object->id));
BLI_assert(object->type == OB_MESH);
return object->runtime->mesh_deform_eval;
}
Lattice *BKE_object_get_lattice(const Object *object) Lattice *BKE_object_get_lattice(const Object *object)
{ {
ID *data = (ID *)object->data; ID *data = (ID *)object->data;
@ -4806,7 +4816,7 @@ int BKE_object_scenes_users_get(Main *bmain, Object *ob)
return num_scenes; return num_scenes;
} }
MovieClip *BKE_object_movieclip_get(Scene *scene, Object *ob, bool use_default) MovieClip *BKE_object_movieclip_get(Scene *scene, const Object *ob, bool use_default)
{ {
MovieClip *clip = use_default ? scene->clip : nullptr; MovieClip *clip = use_default ? scene->clip : nullptr;
bConstraint *con = (bConstraint *)ob->constraints.first, *scon = nullptr; bConstraint *con = (bConstraint *)ob->constraints.first, *scon = nullptr;
@ -5039,8 +5049,9 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot)
Mesh *mesh = (Mesh *)ob->data; Mesh *mesh = (Mesh *)ob->data;
uint i; uint i;
Mesh *mesh_eval = ob->runtime->mesh_deform_eval ? ob->runtime->mesh_deform_eval : const Mesh *mesh_eval = BKE_object_get_mesh_deform_eval(ob) ?
BKE_object_get_evaluated_mesh(ob); BKE_object_get_mesh_deform_eval(ob) :
BKE_object_get_evaluated_mesh(ob);
const int *index; const int *index;
if (mesh_eval && if (mesh_eval &&

View File

@ -472,11 +472,11 @@ static const Mesh *mesh_data_from_duplicator_object(Object *ob,
*r_em = em; *r_em = em;
mesh_eval = nullptr; mesh_eval = nullptr;
if ((emd != nullptr) && !emd->vertexCos.is_empty()) { if ((emd != nullptr) && !emd->vert_positions.is_empty()) {
*r_vert_coords = reinterpret_cast<const float(*)[3]>(emd->vertexCos.data()); *r_vert_coords = reinterpret_cast<const float(*)[3]>(emd->vert_positions.data());
if (r_vert_normals != nullptr) { if (r_vert_normals != nullptr) {
BKE_editmesh_cache_ensure_vert_normals(*em, *emd); BKE_editmesh_cache_ensure_vert_normals(*em, *emd);
*r_vert_normals = reinterpret_cast<const float(*)[3]>(emd->vertexNos.data()); *r_vert_normals = reinterpret_cast<const float(*)[3]>(emd->vert_normals.data());
} }
} }
} }

View File

@ -1755,7 +1755,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
Scene *scene = DEG_get_input_scene(depsgraph); Scene *scene = DEG_get_input_scene(depsgraph);
Sculpt *sd = scene->toolsettings->sculpt; Sculpt *sd = scene->toolsettings->sculpt;
SculptSession *ss = ob->sculpt; SculptSession *ss = ob->sculpt;
Mesh *mesh = BKE_object_get_original_mesh(ob); Mesh *mesh_orig = BKE_object_get_original_mesh(ob);
Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval); Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
MultiresModifierData *mmd = sculpt_multires_modifier_get(scene, ob, true); MultiresModifierData *mmd = sculpt_multires_modifier_get(scene, ob, true);
const bool use_face_sets = (ob->mode & OB_MODE_SCULPT) != 0; const bool use_face_sets = (ob->mode & OB_MODE_SCULPT) != 0;
@ -1786,28 +1786,28 @@ static void sculpt_update_object(Depsgraph *depsgraph,
ss->multires.level = mmd->sculptlvl; ss->multires.level = mmd->sculptlvl;
ss->totvert = mesh_eval->verts_num; ss->totvert = mesh_eval->verts_num;
ss->faces_num = mesh_eval->faces_num; ss->faces_num = mesh_eval->faces_num;
ss->totfaces = mesh->faces_num; ss->totfaces = mesh_orig->faces_num;
/* These are assigned to the base mesh in Multires. This is needed because Face Sets operators /* These are assigned to the base mesh in Multires. This is needed because Face Sets operators
* and tools use the Face Sets data from the base mesh when Multires is active. */ * and tools use the Face Sets data from the base mesh when Multires is active. */
ss->vert_positions = mesh->vert_positions_for_write(); ss->vert_positions = mesh_orig->vert_positions_for_write();
ss->faces = mesh->faces(); ss->faces = mesh_orig->faces();
ss->corner_verts = mesh->corner_verts(); ss->corner_verts = mesh_orig->corner_verts();
} }
else { else {
ss->totvert = mesh->verts_num; ss->totvert = mesh_orig->verts_num;
ss->faces_num = mesh->faces_num; ss->faces_num = mesh_orig->faces_num;
ss->totfaces = mesh->faces_num; ss->totfaces = mesh_orig->faces_num;
ss->vert_positions = mesh->vert_positions_for_write(); ss->vert_positions = mesh_orig->vert_positions_for_write();
ss->faces = mesh->faces(); ss->faces = mesh_orig->faces();
ss->corner_verts = mesh->corner_verts(); ss->corner_verts = mesh_orig->corner_verts();
ss->multires.active = false; ss->multires.active = false;
ss->multires.modifier = nullptr; ss->multires.modifier = nullptr;
ss->multires.level = 0; ss->multires.level = 0;
CustomDataLayer *layer; CustomDataLayer *layer;
AttrDomain domain; AttrDomain domain;
if (BKE_pbvh_get_color_layer(mesh, &layer, &domain)) { if (BKE_pbvh_get_color_layer(mesh_orig, &layer, &domain)) {
if (layer->type == CD_PROP_COLOR) { if (layer->type == CD_PROP_COLOR) {
ss->vcol = static_cast<MPropCol *>(layer->data); ss->vcol = static_cast<MPropCol *>(layer->data);
} }
@ -1830,13 +1830,14 @@ static void sculpt_update_object(Depsgraph *depsgraph,
/* Sculpt Face Sets. */ /* Sculpt Face Sets. */
if (use_face_sets) { if (use_face_sets) {
ss->face_sets = static_cast<const int *>( ss->face_sets = static_cast<const int *>(
CustomData_get_layer_named(&mesh->face_data, CD_PROP_INT32, ".sculpt_face_set")); CustomData_get_layer_named(&mesh_orig->face_data, CD_PROP_INT32, ".sculpt_face_set"));
} }
else { else {
ss->face_sets = nullptr; ss->face_sets = nullptr;
} }
ss->hide_poly = (bool *)CustomData_get_layer_named(&mesh->face_data, CD_PROP_BOOL, ".hide_poly"); ss->hide_poly = (bool *)CustomData_get_layer_named(
&mesh_orig->face_data, CD_PROP_BOOL, ".hide_poly");
ss->subdiv_ccg = mesh_eval->runtime->subdiv_ccg.get(); ss->subdiv_ccg = mesh_eval->runtime->subdiv_ccg.get();
@ -1850,7 +1851,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
sculpt_update_persistent_base(ob); sculpt_update_persistent_base(ob);
if (ob->type == OB_MESH) { if (ob->type == OB_MESH) {
ss->vert_to_face_map = mesh->vert_to_face_map(); ss->vert_to_face_map = mesh_orig->vert_to_face_map();
} }
if (ss->pbvh) { if (ss->pbvh) {
@ -1862,7 +1863,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
bool used_me_eval = false; bool used_me_eval = false;
if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) { if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) {
Mesh *me_eval_deform = ob_eval->runtime->mesh_deform_eval; const Mesh *me_eval_deform = BKE_object_get_mesh_deform_eval(ob_eval);
/* If the fully evaluated mesh has the same topology as the deform-only version, use it. /* If the fully evaluated mesh has the same topology as the deform-only version, use it.
* This matters because crazyspace evaluation is very restrictive and excludes even modifiers * This matters because crazyspace evaluation is very restrictive and excludes even modifiers
@ -1873,7 +1874,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
{ {
BKE_sculptsession_free_deformMats(ss); BKE_sculptsession_free_deformMats(ss);
BLI_assert(me_eval_deform->verts_num == mesh->verts_num); BLI_assert(me_eval_deform->verts_num == mesh_orig->verts_num);
ss->deform_cos = mesh_eval->vert_positions(); ss->deform_cos = mesh_eval->vert_positions();
BKE_pbvh_vert_coords_apply(ss->pbvh, ss->deform_cos); BKE_pbvh_vert_coords_apply(ss->pbvh, ss->deform_cos);
@ -1887,8 +1888,8 @@ static void sculpt_update_object(Depsgraph *depsgraph,
ss->orig_cos = (ss->shapekey_active) ? ss->orig_cos = (ss->shapekey_active) ?
Span(static_cast<const float3 *>(ss->shapekey_active->data), Span(static_cast<const float3 *>(ss->shapekey_active->data),
mesh->verts_num) : mesh_orig->verts_num) :
mesh->vert_positions(); mesh_orig->vert_positions();
BKE_crazyspace_build_sculpt(depsgraph, scene, ob, ss->deform_imats, ss->deform_cos); BKE_crazyspace_build_sculpt(depsgraph, scene, ob, ss->deform_imats, ss->deform_cos);
BKE_pbvh_vert_coords_apply(ss->pbvh, ss->deform_cos); BKE_pbvh_vert_coords_apply(ss->pbvh, ss->deform_cos);
@ -1903,14 +1904,16 @@ static void sculpt_update_object(Depsgraph *depsgraph,
} }
if (ss->shapekey_active != nullptr && ss->deform_cos.is_empty()) { if (ss->shapekey_active != nullptr && ss->deform_cos.is_empty()) {
ss->deform_cos = Span(static_cast<const float3 *>(ss->shapekey_active->data), mesh->verts_num); ss->deform_cos = Span(static_cast<const float3 *>(ss->shapekey_active->data),
mesh_orig->verts_num);
} }
/* if pbvh is deformed, key block is already applied to it */ /* if pbvh is deformed, key block is already applied to it */
if (ss->shapekey_active) { if (ss->shapekey_active) {
bool pbvh_deformed = BKE_pbvh_is_deformed(ss->pbvh); bool pbvh_deformed = BKE_pbvh_is_deformed(ss->pbvh);
if (!pbvh_deformed || ss->deform_cos.is_empty()) { if (!pbvh_deformed || ss->deform_cos.is_empty()) {
const Span key_data(static_cast<const float3 *>(ss->shapekey_active->data), mesh->verts_num); const Span key_data(static_cast<const float3 *>(ss->shapekey_active->data),
mesh_orig->verts_num);
if (key_data.data() != nullptr) { if (key_data.data() != nullptr) {
if (!pbvh_deformed) { if (!pbvh_deformed) {
@ -2220,7 +2223,7 @@ static PBVH *build_pbvh_for_dynamic_topology(Object *ob)
ob->sculpt->attrs.dyntopo_node_id_face->bmesh_cd_offset); ob->sculpt->attrs.dyntopo_node_id_face->bmesh_cd_offset);
} }
static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform) static PBVH *build_pbvh_from_regular_mesh(Object *ob, const Mesh *me_eval_deform)
{ {
Mesh *mesh = BKE_object_get_original_mesh(ob); Mesh *mesh = BKE_object_get_original_mesh(ob);
PBVH *pbvh = pbvh::build_mesh(mesh); PBVH *pbvh = pbvh::build_mesh(mesh);
@ -2293,7 +2296,7 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime->subdiv_ccg.get()); pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime->subdiv_ccg.get());
} }
else if (ob->type == OB_MESH) { else if (ob->type == OB_MESH) {
Mesh *me_eval_deform = object_eval->runtime->mesh_deform_eval; const Mesh *me_eval_deform = BKE_object_get_mesh_deform_eval(object_eval);
pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform); pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform);
} }
} }

View File

@ -44,7 +44,6 @@
#include "BKE_mesh.hh" #include "BKE_mesh.hh"
#include "BKE_mesh_runtime.hh" #include "BKE_mesh_runtime.hh"
#include "BKE_object.hh" #include "BKE_object.hh"
#include "BKE_object_types.hh"
#include "BKE_pointcache.h" #include "BKE_pointcache.h"
#include "BKE_report.hh" #include "BKE_report.hh"
#include "BKE_rigidbody.h" #include "BKE_rigidbody.h"
@ -338,13 +337,13 @@ void BKE_rigidbody_object_copy(Main *bmain, Object *ob_dst, const Object *ob_src
/* Setup Utilities - Validate Sim Instances */ /* Setup Utilities - Validate Sim Instances */
/* get the appropriate evaluated mesh based on rigid body mesh source */ /* get the appropriate evaluated mesh based on rigid body mesh source */
static Mesh *rigidbody_get_mesh(Object *ob) static const Mesh *rigidbody_get_mesh(Object *ob)
{ {
BLI_assert(ob->type == OB_MESH); BLI_assert(ob->type == OB_MESH);
switch (ob->rigidbody_object->mesh_source) { switch (ob->rigidbody_object->mesh_source) {
case RBO_MESH_DEFORM: case RBO_MESH_DEFORM:
return ob->runtime->mesh_deform_eval; return BKE_object_get_mesh_deform_eval(ob);
case RBO_MESH_FINAL: case RBO_MESH_FINAL:
return BKE_object_get_evaluated_mesh(ob); return BKE_object_get_evaluated_mesh(ob);
case RBO_MESH_BASE: case RBO_MESH_BASE:
@ -366,13 +365,13 @@ static rbCollisionShape *rigidbody_get_shape_convexhull_from_mesh(Object *ob,
bool *can_embed) bool *can_embed)
{ {
rbCollisionShape *shape = nullptr; rbCollisionShape *shape = nullptr;
Mesh *mesh = nullptr; const Mesh *mesh = nullptr;
float(*positions)[3] = nullptr; const float(*positions)[3] = nullptr;
int totvert = 0; int totvert = 0;
if (ob->type == OB_MESH && ob->data) { if (ob->type == OB_MESH && ob->data) {
mesh = rigidbody_get_mesh(ob); mesh = rigidbody_get_mesh(ob);
positions = (mesh) ? reinterpret_cast<float(*)[3]>(mesh->vert_positions_for_write().data()) : positions = (mesh) ? reinterpret_cast<const float(*)[3]>(mesh->vert_positions().data()) :
nullptr; nullptr;
totvert = (mesh) ? mesh->verts_num : 0; totvert = (mesh) ? mesh->verts_num : 0;
} }
@ -399,7 +398,7 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
rbCollisionShape *shape = nullptr; rbCollisionShape *shape = nullptr;
if (ob->type == OB_MESH) { if (ob->type == OB_MESH) {
Mesh *mesh = rigidbody_get_mesh(ob); const Mesh *mesh = rigidbody_get_mesh(ob);
if (mesh == nullptr) { if (mesh == nullptr) {
return nullptr; return nullptr;
} }
@ -668,7 +667,7 @@ void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
case RB_SHAPE_CONVEXH: case RB_SHAPE_CONVEXH:
case RB_SHAPE_TRIMESH: { case RB_SHAPE_TRIMESH: {
if (ob->type == OB_MESH) { if (ob->type == OB_MESH) {
Mesh *mesh = rigidbody_get_mesh(ob); const Mesh *mesh = rigidbody_get_mesh(ob);
if (mesh == nullptr) { if (mesh == nullptr) {
return; return;
} }
@ -742,7 +741,7 @@ void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3])
case RB_SHAPE_CONVEXH: case RB_SHAPE_CONVEXH:
case RB_SHAPE_TRIMESH: { case RB_SHAPE_TRIMESH: {
if (ob->type == OB_MESH) { if (ob->type == OB_MESH) {
Mesh *mesh = rigidbody_get_mesh(ob); const Mesh *mesh = rigidbody_get_mesh(ob);
if (mesh == nullptr) { if (mesh == nullptr) {
return; return;
} }
@ -1763,10 +1762,10 @@ static void rigidbody_update_sim_ob(Depsgraph *depsgraph, Object *ob, RigidBodyO
const bool is_selected = base ? (base->flag & BASE_SELECTED) != 0 : false; const bool is_selected = base ? (base->flag & BASE_SELECTED) != 0 : false;
if (rbo->shape == RB_SHAPE_TRIMESH && rbo->flag & RBO_FLAG_USE_DEFORM) { if (rbo->shape == RB_SHAPE_TRIMESH && rbo->flag & RBO_FLAG_USE_DEFORM) {
Mesh *mesh = ob->runtime->mesh_deform_eval; const Mesh *mesh = BKE_object_get_mesh_deform_eval(ob);
if (mesh) { if (mesh) {
float(*positions)[3] = reinterpret_cast<float(*)[3]>( const float(*positions)[3] = reinterpret_cast<const float(*)[3]>(
mesh->vert_positions_for_write().data()); mesh->vert_positions().data());
int totvert = mesh->verts_num; int totvert = mesh->verts_num;
const std::optional<blender::Bounds<blender::float3>> bounds = BKE_object_boundbox_get(ob); const std::optional<blender::Bounds<blender::float3>> bounds = BKE_object_boundbox_get(ob);

View File

@ -1032,7 +1032,9 @@ static void mesh_corner_tris_target_project(void *userdata,
update_hit(nearest, index, co, hit_co, hit_no); update_hit(nearest, index, co, hit_co, hit_no);
} }
/* Boundary edges */ /* Boundary edges */
else if (tree->boundary && tree->boundary->tri_has_boundary[index]) { else if (tree->boundary && tree->boundary->has_boundary() &&
tree->boundary->tri_has_boundary[index])
{
const BitSpan is_boundary = tree->boundary->edge_is_boundary; const BitSpan is_boundary = tree->boundary->edge_is_boundary;
const int3 edges = bke::mesh::corner_tri_get_real_edges( const int3 edges = bke::mesh::corner_tri_get_real_edges(
data->edges, data->corner_verts, tree->corner_edges, tri); data->edges, data->corner_verts, tree->corner_edges, tri);

View File

@ -367,7 +367,7 @@ void BKE_tracking_settings_init(MovieTracking *tracking)
BKE_tracking_object_add(tracking, DATA_("Camera")); BKE_tracking_object_add(tracking, DATA_("Camera"));
} }
void BKE_tracking_get_camera_object_matrix(Object *camera_object, float mat[4][4]) void BKE_tracking_get_camera_object_matrix(const Object *camera_object, float mat[4][4])
{ {
BLI_assert(camera_object != nullptr); BLI_assert(camera_object != nullptr);
/* NOTE: Construct matrix from scratch rather than using obmat because the camera object here /* NOTE: Construct matrix from scratch rather than using obmat because the camera object here

View File

@ -490,21 +490,40 @@ BLI_INLINE float perlin_noise(float4 position)
float perlin_signed(float position) float perlin_signed(float position)
{ {
/* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
* representation issues. */
position = math::mod(position, 100000.0f);
return perlin_noise(position) * 0.2500f; return perlin_noise(position) * 0.2500f;
} }
float perlin_signed(float2 position) float perlin_signed(float2 position)
{ {
/* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0f, however at such scales
* this usually shouldn't be noticeable. */
position = math::mod(position, 100000.0f);
return perlin_noise(position) * 0.6616f; return perlin_noise(position) * 0.6616f;
} }
float perlin_signed(float3 position) float perlin_signed(float3 position)
{ {
/* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0f, however at such scales
* this usually shouldn't be noticeable. */
position = math::mod(position, 100000.0f);
return perlin_noise(position) * 0.9820f; return perlin_noise(position) * 0.9820f;
} }
float perlin_signed(float4 position) float perlin_signed(float4 position)
{ {
/* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0f, however at such scales
* this usually shouldn't be noticeable. */
position = math::mod(position, 100000.0f);
return perlin_noise(position) * 0.8344f; return perlin_noise(position) * 0.8344f;
} }

View File

@ -22,6 +22,10 @@
#include "bmesh.hh" #include "bmesh.hh"
using blender::Array;
using blender::float3;
using blender::MutableSpan;
const BMAllocTemplate bm_mesh_allocsize_default = {512, 1024, 2048, 512}; const BMAllocTemplate bm_mesh_allocsize_default = {512, 1024, 2048, 512};
const BMAllocTemplate bm_mesh_chunksize_default = {512, 1024, 2048, 512}; const BMAllocTemplate bm_mesh_chunksize_default = {512, 1024, 2048, 512};
@ -1328,23 +1332,21 @@ void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags)
/** \name BMesh Coordinate Access /** \name BMesh Coordinate Access
* \{ */ * \{ */
void BM_mesh_vert_coords_get(BMesh *bm, float (*vert_coords)[3]) void BM_mesh_vert_coords_get(BMesh *bm, MutableSpan<float3> positions)
{ {
BMIter iter; BMIter iter;
BMVert *v; BMVert *v;
int i; int i;
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
copy_v3_v3(vert_coords[i], v->co); positions[i] = v->co;
} }
} }
float (*BM_mesh_vert_coords_alloc(BMesh *bm, int *r_vert_len))[3] Array<float3> BM_mesh_vert_coords_alloc(BMesh *bm)
{ {
float(*vert_coords)[3] = static_cast<float(*)[3]>( Array<float3> positions(bm->totvert);
MEM_mallocN(bm->totvert * sizeof(*vert_coords), __func__)); BM_mesh_vert_coords_get(bm, positions);
BM_mesh_vert_coords_get(bm, vert_coords); return positions;
*r_vert_len = bm->totvert;
return vert_coords;
} }
void BM_mesh_vert_coords_apply(BMesh *bm, const float (*vert_coords)[3]) void BM_mesh_vert_coords_apply(BMesh *bm, const float (*vert_coords)[3])

View File

@ -8,6 +8,10 @@
* \ingroup bmesh * \ingroup bmesh
*/ */
#include "BLI_array.hh"
#include "BLI_math_vector_types.hh"
#include "BLI_span.hh"
#include "bmesh_class.hh" #include "bmesh_class.hh"
struct BMAllocTemplate; struct BMAllocTemplate;
@ -197,8 +201,8 @@ extern const BMAllocTemplate bm_mesh_chunksize_default;
VA_NARGS_CALL_OVERLOAD(_VA_BMALLOC_TEMPLATE_FROM_ME_, __VA_ARGS__) VA_NARGS_CALL_OVERLOAD(_VA_BMALLOC_TEMPLATE_FROM_ME_, __VA_ARGS__)
/* Vertex coords access. */ /* Vertex coords access. */
void BM_mesh_vert_coords_get(BMesh *bm, float (*vert_coords)[3]); void BM_mesh_vert_coords_get(BMesh *bm, blender::MutableSpan<blender::float3> positions);
float (*BM_mesh_vert_coords_alloc(BMesh *bm, int *r_vert_len))[3]; blender::Array<blender::float3> BM_mesh_vert_coords_alloc(BMesh *bm);
void BM_mesh_vert_coords_apply(BMesh *bm, const float (*vert_coords)[3]); void BM_mesh_vert_coords_apply(BMesh *bm, const float (*vert_coords)[3]);
void BM_mesh_vert_coords_apply_with_mat4(BMesh *bm, void BM_mesh_vert_coords_apply_with_mat4(BMesh *bm,
const float (*vert_coords)[3], const float (*vert_coords)[3],

View File

@ -90,9 +90,8 @@ static float bm_face_calc_poly_normal_vertex_cos(const BMFace *f,
/** /**
* \brief COMPUTE POLY CENTER (BMFace) * \brief COMPUTE POLY CENTER (BMFace)
*/ */
static void bm_face_calc_poly_center_median_vertex_cos(const BMFace *f, static void bm_face_calc_poly_center_median_vertex_cos(
float r_cent[3], const BMFace *f, float r_cent[3], const blender::Span<blender::float3> vert_positions)
float const (*vertexCos)[3])
{ {
const BMLoop *l_first, *l_iter; const BMLoop *l_first, *l_iter;
@ -101,7 +100,7 @@ static void bm_face_calc_poly_center_median_vertex_cos(const BMFace *f,
/* Newell's Method */ /* Newell's Method */
l_iter = l_first = BM_FACE_FIRST_LOOP(f); l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do { do {
add_v3_v3(r_cent, vertexCos[BM_elem_index_get(l_iter->v)]); add_v3_v3(r_cent, vert_positions[BM_elem_index_get(l_iter->v)]);
} while ((l_iter = l_iter->next) != l_first); } while ((l_iter = l_iter->next) != l_first);
mul_v3_fl(r_cent, 1.0f / f->len); mul_v3_fl(r_cent, 1.0f / f->len);
} }
@ -520,7 +519,7 @@ void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3])
void BM_face_calc_center_bounds_vcos(const BMesh *bm, void BM_face_calc_center_bounds_vcos(const BMesh *bm,
const BMFace *f, const BMFace *f,
float r_cent[3], float r_cent[3],
float const (*vertexCos)[3]) const blender::Span<blender::float3> vert_positions)
{ {
/* must have valid index data */ /* must have valid index data */
BLI_assert((bm->elem_index_dirty & BM_VERT) == 0); BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
@ -533,7 +532,7 @@ void BM_face_calc_center_bounds_vcos(const BMesh *bm,
l_iter = l_first = BM_FACE_FIRST_LOOP(f); l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do { do {
minmax_v3v3_v3(min, max, vertexCos[BM_elem_index_get(l_iter->v)]); minmax_v3v3_v3(min, max, vert_positions[BM_elem_index_get(l_iter->v)]);
} while ((l_iter = l_iter->next) != l_first); } while ((l_iter = l_iter->next) != l_first);
mid_v3_v3v3(r_cent, min, max); mid_v3_v3v3(r_cent, min, max);
@ -900,13 +899,13 @@ float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, fl
void BM_face_calc_center_median_vcos(const BMesh *bm, void BM_face_calc_center_median_vcos(const BMesh *bm,
const BMFace *f, const BMFace *f,
float r_cent[3], float r_cent[3],
float const (*vertexCos)[3]) const blender::Span<blender::float3> vert_positions)
{ {
/* must have valid index data */ /* must have valid index data */
BLI_assert((bm->elem_index_dirty & BM_VERT) == 0); BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
(void)bm; (void)bm;
bm_face_calc_poly_center_median_vertex_cos(f, r_cent, vertexCos); bm_face_calc_poly_center_median_vertex_cos(f, r_cent, vert_positions);
} }
void BM_face_normal_flip_ex(BMesh *bm, void BM_face_normal_flip_ex(BMesh *bm,

View File

@ -11,6 +11,8 @@
struct Heap; struct Heap;
#include "BLI_compiler_attrs.h" #include "BLI_compiler_attrs.h"
#include "BLI_math_vector_types.hh"
#include "BLI_span.hh"
/** /**
* For tools that insist on using triangles, ideally we would cache this data. * For tools that insist on using triangles, ideally we would cache this data.
@ -128,7 +130,7 @@ void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3]) ATTR_NONNULL()
void BM_face_calc_center_bounds_vcos(const BMesh *bm, void BM_face_calc_center_bounds_vcos(const BMesh *bm,
const BMFace *f, const BMFace *f,
float r_center[3], float r_center[3],
float const (*vertexCos)[3]) ATTR_NONNULL(); blender::Span<blender::float3> vert_positions) ATTR_NONNULL();
/** /**
* computes the center of a face, using the mean average * computes the center of a face, using the mean average
*/ */
@ -137,7 +139,8 @@ void BM_face_calc_center_median(const BMFace *f, float r_center[3]) ATTR_NONNULL
void BM_face_calc_center_median_vcos(const BMesh *bm, void BM_face_calc_center_median_vcos(const BMesh *bm,
const BMFace *f, const BMFace *f,
float r_center[3], float r_center[3],
float const (*vertexCos)[3]) ATTR_NONNULL(); const blender::Span<blender::float3> vert_positions)
ATTR_NONNULL();
/** /**
* computes the center of a face, using the mean average * computes the center of a face, using the mean average
* weighted by edge length * weighted by edge length

View File

@ -586,6 +586,7 @@ set(GLSL_SRC
engines/eevee_next/shaders/eevee_shadow_tag_usage_vert.glsl engines/eevee_next/shaders/eevee_shadow_tag_usage_vert.glsl
engines/eevee_next/shaders/eevee_shadow_tag_usage_volume_comp.glsl engines/eevee_next/shaders/eevee_shadow_tag_usage_volume_comp.glsl
engines/eevee_next/shaders/eevee_shadow_test.glsl engines/eevee_next/shaders/eevee_shadow_test.glsl
engines/eevee_next/shaders/eevee_shadow_tilemap_amend_comp.glsl
engines/eevee_next/shaders/eevee_shadow_tilemap_bounds_comp.glsl engines/eevee_next/shaders/eevee_shadow_tilemap_bounds_comp.glsl
engines/eevee_next/shaders/eevee_shadow_tilemap_finalize_comp.glsl engines/eevee_next/shaders/eevee_shadow_tilemap_finalize_comp.glsl
engines/eevee_next/shaders/eevee_shadow_tilemap_init_comp.glsl engines/eevee_next/shaders/eevee_shadow_tilemap_init_comp.glsl

View File

@ -87,6 +87,8 @@
#define SHADOW_TILEDATA_PER_TILEMAP \ #define SHADOW_TILEDATA_PER_TILEMAP \
(SHADOW_TILEMAP_LOD0_LEN + SHADOW_TILEMAP_LOD1_LEN + SHADOW_TILEMAP_LOD2_LEN + \ (SHADOW_TILEMAP_LOD0_LEN + SHADOW_TILEMAP_LOD1_LEN + SHADOW_TILEMAP_LOD2_LEN + \
SHADOW_TILEMAP_LOD3_LEN + SHADOW_TILEMAP_LOD4_LEN + SHADOW_TILEMAP_LOD5_LEN) SHADOW_TILEMAP_LOD3_LEN + SHADOW_TILEMAP_LOD4_LEN + SHADOW_TILEMAP_LOD5_LEN)
/* Maximum number of relative LOD distance we can store. */
#define SHADOW_TILEMAP_MAX_CLIPMAP_LOD 8
#if 0 #if 0
/* Useful for debugging the tile-copy version of the shadow rendering without making debugging /* Useful for debugging the tile-copy version of the shadow rendering without making debugging
* tools unresponsive. */ * tools unresponsive. */

View File

@ -241,6 +241,8 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_
return "eevee_shadow_page_free"; return "eevee_shadow_page_free";
case SHADOW_PAGE_MASK: case SHADOW_PAGE_MASK:
return "eevee_shadow_page_mask"; return "eevee_shadow_page_mask";
case SHADOW_TILEMAP_AMEND:
return "eevee_shadow_tilemap_amend";
case SHADOW_TILEMAP_BOUNDS: case SHADOW_TILEMAP_BOUNDS:
return "eevee_shadow_tilemap_bounds"; return "eevee_shadow_tilemap_bounds";
case SHADOW_TILEMAP_FINALIZE: case SHADOW_TILEMAP_FINALIZE:

View File

@ -120,6 +120,7 @@ enum eShaderType {
SHADOW_PAGE_MASK, SHADOW_PAGE_MASK,
SHADOW_PAGE_TILE_CLEAR, SHADOW_PAGE_TILE_CLEAR,
SHADOW_PAGE_TILE_STORE, SHADOW_PAGE_TILE_STORE,
SHADOW_TILEMAP_AMEND,
SHADOW_TILEMAP_BOUNDS, SHADOW_TILEMAP_BOUNDS,
SHADOW_TILEMAP_FINALIZE, SHADOW_TILEMAP_FINALIZE,
SHADOW_TILEMAP_INIT, SHADOW_TILEMAP_INIT,

View File

@ -1231,8 +1231,6 @@ struct ShadowTileData {
uint3 page; uint3 page;
/** Page index inside pages_cached_buf. Only valid if `is_cached` is true. */ /** Page index inside pages_cached_buf. Only valid if `is_cached` is true. */
uint cache_index; uint cache_index;
/** LOD pointed to LOD 0 tile page. (cube-map only). */
uint lod;
/** If the tile is needed for rendering. */ /** If the tile is needed for rendering. */
bool is_used; bool is_used;
/** True if an update is needed. This persists even if the tile gets unused. */ /** True if an update is needed. This persists even if the tile gets unused. */
@ -1279,8 +1277,7 @@ static inline ShadowTileData shadow_tile_unpack(ShadowTileDataPacked data)
ShadowTileData tile; ShadowTileData tile;
tile.page = shadow_page_unpack(data); tile.page = shadow_page_unpack(data);
/* -- 12 bits -- */ /* -- 12 bits -- */
BLI_STATIC_ASSERT(SHADOW_TILEMAP_LOD < 8, "Update page packing") /* Unused bits. */
tile.lod = (data >> 12u) & 7u;
/* -- 15 bits -- */ /* -- 15 bits -- */
BLI_STATIC_ASSERT(SHADOW_MAX_PAGE <= 4096, "Update page packing") BLI_STATIC_ASSERT(SHADOW_MAX_PAGE <= 4096, "Update page packing")
tile.cache_index = (data >> 15u) & 4095u; tile.cache_index = (data >> 15u) & 4095u;
@ -1299,7 +1296,6 @@ static inline ShadowTileDataPacked shadow_tile_pack(ShadowTileData tile)
/* NOTE: Page might be set to invalid values for tracking invalid usages. /* NOTE: Page might be set to invalid values for tracking invalid usages.
* So we have to mask the result. */ * So we have to mask the result. */
data = shadow_page_pack(tile.page) & uint(SHADOW_MAX_PAGE - 1); data = shadow_page_pack(tile.page) & uint(SHADOW_MAX_PAGE - 1);
data |= (tile.lod & 7u) << 12u;
data |= (tile.cache_index & 4095u) << 15u; data |= (tile.cache_index & 4095u) << 15u;
data |= (tile.is_used ? uint(SHADOW_IS_USED) : 0); data |= (tile.is_used ? uint(SHADOW_IS_USED) : 0);
data |= (tile.is_allocated ? uint(SHADOW_IS_ALLOCATED) : 0); data |= (tile.is_allocated ? uint(SHADOW_IS_ALLOCATED) : 0);
@ -1309,6 +1305,89 @@ static inline ShadowTileDataPacked shadow_tile_pack(ShadowTileData tile)
return data; return data;
} }
/**
* Decoded tile data structure.
* Similar to ShadowTileData, this one is only used for rendering and packed into `tilemap_tx`.
* This allow to reuse some bits for other purpose.
*/
struct ShadowSamplingTile {
/** Page inside the virtual shadow map atlas. */
uint3 page;
/** LOD pointed to LOD 0 tile page. */
uint lod;
/** Offset to the texel position to align with the LOD page start. (directional only). */
uint2 lod_offset;
/** If the tile is needed for rendering. */
bool is_valid;
};
/** \note Stored packed as a uint. */
#define ShadowSamplingTilePacked uint
/* NOTE: Trust the input to be in valid range [0, (1 << SHADOW_TILEMAP_MAX_CLIPMAP_LOD) - 1].
* Maximum LOD level index we can store is SHADOW_TILEMAP_MAX_CLIPMAP_LOD,
* so we need SHADOW_TILEMAP_MAX_CLIPMAP_LOD bits to store the offset in each dimension.
* Result fits into SHADOW_TILEMAP_MAX_CLIPMAP_LOD * 2 bits. */
static inline uint shadow_lod_offset_pack(uint2 ofs)
{
BLI_STATIC_ASSERT(SHADOW_TILEMAP_MAX_CLIPMAP_LOD <= 8, "Update page packing")
return ofs.x | (ofs.y << SHADOW_TILEMAP_MAX_CLIPMAP_LOD);
}
static inline uint2 shadow_lod_offset_unpack(uint data)
{
return (uint2(data) >> uint2(0, SHADOW_TILEMAP_MAX_CLIPMAP_LOD)) &
uint2((1 << SHADOW_TILEMAP_MAX_CLIPMAP_LOD) - 1);
}
static inline ShadowSamplingTile shadow_sampling_tile_unpack(ShadowSamplingTilePacked data)
{
ShadowSamplingTile tile;
tile.page = shadow_page_unpack(data);
/* -- 12 bits -- */
/* Max value is actually SHADOW_TILEMAP_MAX_CLIPMAP_LOD but we mask the bits. */
tile.lod = (data >> 12u) & 15u;
/* -- 16 bits -- */
tile.lod_offset = shadow_lod_offset_unpack(data >> 16u);
/* -- 32 bits -- */
tile.is_valid = data != 0u;
#ifndef GPU_SHADER
/* Make tests pass on CPU but it is not required for proper rendering. */
if (tile.lod == 0) {
tile.lod_offset.x = 0;
}
#endif
return tile;
}
static inline ShadowSamplingTilePacked shadow_sampling_tile_pack(ShadowSamplingTile tile)
{
if (!tile.is_valid) {
return 0u;
}
/* Tag a valid tile of LOD0 valid by setting their offset to 1.
* This doesn't change the sampling and allows to use of all bits for data.
* This makes sure no valid packed tile is 0u. */
if (tile.lod == 0) {
tile.lod_offset.x = 1;
}
uint data = shadow_page_pack(tile.page);
/* Max value is actually SHADOW_TILEMAP_MAX_CLIPMAP_LOD but we mask the bits. */
data |= (tile.lod & 15u) << 12u;
data |= shadow_lod_offset_pack(tile.lod_offset) << 16u;
return data;
}
static inline ShadowSamplingTile shadow_sampling_tile_create(ShadowTileData tile_data, uint lod)
{
ShadowSamplingTile tile;
tile.page = tile_data.page;
tile.lod = lod;
tile.lod_offset = uint2(0, 0); /* Computed during tilemap amend phase. */
/* At this point, it should be the case that all given tiles that have been tagged as used are
* ready for sampling. Otherwise tile_data should be SHADOW_NO_DATA. */
tile.is_valid = tile_data.is_used;
return tile;
}
struct ShadowSceneData { struct ShadowSceneData {
/* Number of shadow rays to shoot for each light. */ /* Number of shadow rays to shoot for each light. */
int ray_count; int ray_count;

View File

@ -1199,6 +1199,15 @@ void ShadowModule::end_sync()
sub.barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_UNIFORM | GPU_BARRIER_TEXTURE_FETCH | sub.barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_UNIFORM | GPU_BARRIER_TEXTURE_FETCH |
GPU_BARRIER_SHADER_IMAGE_ACCESS); GPU_BARRIER_SHADER_IMAGE_ACCESS);
} }
{
/* Amend tilemap_tx content to support clipmap LODs. */
PassSimple::Sub &sub = pass.sub("Amend");
sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_AMEND));
sub.bind_image("tilemaps_img", tilemap_pool.tilemap_tx);
sub.bind_resources(inst_.lights);
sub.dispatch(int3(1));
sub.barrier(GPU_BARRIER_TEXTURE_FETCH);
}
/* NOTE: We do not need to run the clear pass when using the TBDR update variant, as tiles /* NOTE: We do not need to run the clear pass when using the TBDR update variant, as tiles
* will be fully cleared as part of the shadow raster step. */ * will be fully cleared as part of the shadow raster step. */

View File

@ -33,7 +33,6 @@ void debug_tile_print(ShadowTileData tile, ivec4 tile_coord)
{ {
#ifdef DRW_DEBUG_PRINT #ifdef DRW_DEBUG_PRINT
drw_print("Tile (", tile_coord.x, ",", tile_coord.y, ") in Tilemap ", tile_coord.z, " : "); drw_print("Tile (", tile_coord.x, ",", tile_coord.y, ") in Tilemap ", tile_coord.z, " : ");
drw_print(tile.lod);
drw_print(tile.page); drw_print(tile.page);
drw_print(tile.cache_index); drw_print(tile.cache_index);
#endif #endif
@ -41,10 +40,6 @@ void debug_tile_print(ShadowTileData tile, ivec4 tile_coord)
vec3 debug_tile_state_color(ShadowTileData tile) vec3 debug_tile_state_color(ShadowTileData tile)
{ {
if (tile.lod > 0) {
/* Uses data from another LOD. */
return neon_gradient(float(tile.lod) / float(SHADOW_TILEMAP_LOD));
}
if (tile.do_update && tile.is_used) { if (tile.do_update && tile.is_used) {
/* Updated. */ /* Updated. */
return vec3(0.5, 1, 0); return vec3(0.5, 1, 0);
@ -63,6 +58,17 @@ vec3 debug_tile_state_color(ShadowTileData tile)
return col; return col;
} }
vec3 debug_tile_state_color(eLightType type, ShadowSamplingTile tile)
{
if (!tile.is_valid) {
return vec3(1, 0, 0);
}
/* Uses data from another LOD. */
return neon_gradient(float(tile.lod) / float((type == LIGHT_SUN) ?
SHADOW_TILEMAP_MAX_CLIPMAP_LOD :
SHADOW_TILEMAP_LOD));
}
ShadowSampleParams debug_shadow_sample_get(vec3 P, LightData light) ShadowSampleParams debug_shadow_sample_get(vec3 P, LightData light)
{ {
if (is_sun_light(light.type)) { if (is_sun_light(light.type)) {
@ -73,7 +79,7 @@ ShadowSampleParams debug_shadow_sample_get(vec3 P, LightData light)
} }
} }
ShadowTileData debug_tile_get(vec3 P, LightData light) ShadowSamplingTile debug_tile_get(vec3 P, LightData light)
{ {
return shadow_tile_data_get(shadow_tilemaps_tx, debug_shadow_sample_get(P, light)); return shadow_tile_data_get(shadow_tilemaps_tx, debug_shadow_sample_get(P, light));
} }
@ -106,6 +112,26 @@ bool debug_tilemaps(vec3 P, LightData light)
int tilemap = px.x / SHADOW_TILEMAP_RES; int tilemap = px.x / SHADOW_TILEMAP_RES;
int tilemap_index = light.tilemap_index + tilemap; int tilemap_index = light.tilemap_index + tilemap;
if ((px.y < SHADOW_TILEMAP_RES) && (tilemap_index <= light_tilemap_max_get(light))) { if ((px.y < SHADOW_TILEMAP_RES) && (tilemap_index <= light_tilemap_max_get(light))) {
#if 1
/* Debug values in the tilemap_tx. */
ivec2 tilemap_texel = shadow_tile_coord_in_atlas(px, tilemap_index);
ShadowSamplingTile tile = shadow_sampling_tile_unpack(
texelFetch(shadow_tilemaps_tx, tilemap_texel, 0).x);
/* Leave 1 px border between tile-maps. */
if (!any(equal(ivec2(gl_FragCoord.xy) % (SHADOW_TILEMAP_RES * debug_tile_size_px), ivec2(0))))
{
gl_FragDepth = 0.0;
out_color_add = vec4(debug_tile_state_color(light.type, tile), 0.0);
out_color_mul = vec4(0.0);
# ifdef DRW_DEBUG_PRINT
if (all(equal(ivec2(gl_FragCoord.xy), ivec2(0)))) {
drw_print(light.object_mat);
}
# endif
return true;
}
#else
/* Debug actual values in the tile-map buffer. */ /* Debug actual values in the tile-map buffer. */
ShadowTileMapData tilemap = tilemaps_buf[tilemap_index]; ShadowTileMapData tilemap = tilemaps_buf[tilemap_index];
int tile_index = shadow_tile_offset( int tile_index = shadow_tile_offset(
@ -118,21 +144,22 @@ bool debug_tilemaps(vec3 P, LightData light)
out_color_add = vec4(debug_tile_state_color(tile), 0.0); out_color_add = vec4(debug_tile_state_color(tile), 0.0);
out_color_mul = vec4(0.0); out_color_mul = vec4(0.0);
#ifdef DRW_DEBUG_PRINT # ifdef DRW_DEBUG_PRINT
if (all(equal(ivec2(gl_FragCoord.xy), ivec2(0)))) { if (all(equal(ivec2(gl_FragCoord.xy), ivec2(0)))) {
drw_print(light.object_mat); drw_print(light.object_mat);
} }
#endif # endif
return true; return true;
} }
#endif
} }
return false; return false;
} }
void debug_tile_state(vec3 P, LightData light) void debug_tile_state(vec3 P, LightData light)
{ {
ShadowTileData tile = debug_tile_get(P, light); ShadowSamplingTile tile = debug_tile_get(P, light);
out_color_add = vec4(debug_tile_state_color(tile), 0) * 0.5; out_color_add = vec4(debug_tile_state_color(light.type, tile), 0) * 0.5;
out_color_mul = vec4(0.5); out_color_mul = vec4(0.5);
} }
@ -146,7 +173,7 @@ void debug_atlas_values(vec3 P, LightData light)
void debug_random_tile_color(vec3 P, LightData light) void debug_random_tile_color(vec3 P, LightData light)
{ {
ShadowTileData tile = debug_tile_get(P, light); ShadowSamplingTile tile = debug_tile_get(P, light);
out_color_add = vec4(debug_random_color(ivec2(tile.page.xy)), 0) * 0.5; out_color_add = vec4(debug_random_color(ivec2(tile.page.xy)), 0) * 0.5;
out_color_mul = vec4(0.5); out_color_mul = vec4(0.5);
} }

View File

@ -21,7 +21,7 @@ struct ShadowSampleParams {
float z_range; float z_range;
}; };
ShadowTileData shadow_tile_data_get(usampler2D tilemaps_tx, ShadowSampleParams params) ShadowSamplingTile shadow_tile_data_get(usampler2D tilemaps_tx, ShadowSampleParams params)
{ {
/* Prevent out of bound access. Assumes the input is already non negative. */ /* Prevent out of bound access. Assumes the input is already non negative. */
vec2 tilemap_uv = min(params.uv.xy, vec2(0.99999)); vec2 tilemap_uv = min(params.uv.xy, vec2(0.99999));
@ -46,9 +46,9 @@ float shadow_read_depth(SHADOW_ATLAS_TYPE atlas_tx,
const int page_shift = SHADOW_PAGE_LOD; const int page_shift = SHADOW_PAGE_LOD;
ivec2 tile_coord = texel_coord >> page_shift; ivec2 tile_coord = texel_coord >> page_shift;
ShadowTileData tile = shadow_tile_load(tilemaps_tx, tile_coord, params.tilemap_index); ShadowSamplingTile tile = shadow_tile_load(tilemaps_tx, tile_coord, params.tilemap_index);
if (!tile.is_allocated) { if (!tile.is_valid) {
return -1.0; return -1.0;
} }

View File

@ -26,7 +26,6 @@ void main()
ShadowTileData tile = shadow_tile_unpack(tiles_buf[tile_index]); ShadowTileData tile = shadow_tile_unpack(tiles_buf[tile_index]);
if (tile.is_used && !tile.is_allocated) { if (tile.is_used && !tile.is_allocated) {
shadow_page_alloc(tile); shadow_page_alloc(tile);
tile.lod = lod;
tiles_buf[tile_index] = shadow_tile_pack(tile); tiles_buf[tile_index] = shadow_tile_pack(tile);
} }

View File

@ -0,0 +1,93 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/**
* Virtual shadow-mapping: Amend sampling tile atlas.
*
* In order to support sampling different LOD for clipmap shadow projections, we need to scan
* through the LOD tilemaps from lowest LOD to highest LOD, gathering the last valid tile along the
* way for the current destination tile. For each new level we gather the previous level tiles from
* local memory using the correct relative offset from the previous level as they might not be
* aligned.
*
* TODO(fclem): This shader **should** be dispatched for one thread-group per directional light.
* Currently this shader is dispatched with one thread-group for all directional light.
*/
#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_math_matrix_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_light_iter_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_shadow_tilemap_lib.glsl)
shared ShadowSamplingTilePacked tiles_local[SHADOW_TILEMAP_RES][SHADOW_TILEMAP_RES];
void main()
{
ivec2 tile_co = ivec2(gl_GlobalInvocationID.xy);
LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) {
LightData light = light_buf[l_idx];
/* This only works on clipmaps. Cascade have already the same LOD for every tilemaps. */
if (light.type != LIGHT_SUN) {
break;
}
ivec2 base_offset_neg = light_sun_data_get(light).clipmap_base_offset_neg;
ivec2 base_offset_pos = light_sun_data_get(light).clipmap_base_offset_pos;
/* LOD relative max with respect to clipmap_lod_min. */
int lod_max = light_sun_data_get(light).clipmap_lod_max -
light_sun_data_get(light).clipmap_lod_min;
/* Iterate in reverse. */
for (int lod = lod_max; lod >= 0; lod--) {
int tilemap_index = light.tilemap_index + lod;
ivec2 atlas_texel = shadow_tile_coord_in_atlas(tile_co, tilemap_index);
ShadowSamplingTilePacked tile_packed = imageLoad(tilemaps_img, atlas_texel).x;
ShadowSamplingTile tile = shadow_sampling_tile_unpack(tile_packed);
if (lod != lod_max && !tile.is_valid) {
/* Offset this LOD has with the previous one. In unit of tile of the current LOD. */
ivec2 offset_binary = ((base_offset_pos >> lod) & 1) - ((base_offset_neg >> lod) & 1);
ivec2 offset_centered = ivec2(SHADOW_TILEMAP_RES / 2) + offset_binary;
ivec2 tile_co_prev = (tile_co + offset_centered) >> 1;
/* Load tile from the previous LOD. */
ShadowSamplingTilePacked tile_prev_packed = tiles_local[tile_co_prev.y][tile_co_prev.x];
ShadowSamplingTile tile_prev = shadow_sampling_tile_unpack(tile_prev_packed);
/* We can only propagate LODs up to a certain level.
* Afterwards we run out of bits to store the offsets. */
if (tile_prev.is_valid && tile_prev.lod < SHADOW_TILEMAP_MAX_CLIPMAP_LOD - 1) {
/* Relative LOD. Used for reducing pixel rate at sampling time.
* Increase with each new invalid level. */
tile_prev.lod += 1;
/* The offset (in tile of current LOD) is equal to the offset from the bottom left corner
* of both LODs modulo the size of a tile of the source LOD (in tile of current LOD). */
/* Offset corner to center. */
tile_prev.lod_offset = uvec2(SHADOW_TILEMAP_RES / 2) << tile_prev.lod;
/* Align center of both LODs. */
tile_prev.lod_offset -= uvec2(SHADOW_TILEMAP_RES / 2);
/* Add the offset relative to the source LOD. */
tile_prev.lod_offset += uvec2(bitfieldExtract(base_offset_pos, lod, int(tile_prev.lod)) -
bitfieldExtract(base_offset_neg, lod, int(tile_prev.lod)));
/* Wrap to valid range. */
tile_prev.lod_offset &= ~(~0u << tile_prev.lod);
tile_prev_packed = shadow_sampling_tile_pack(tile_prev);
/* Replace the missing page with the one from the lower LOD. */
imageStore(tilemaps_img, atlas_texel, uvec4(tile_prev_packed));
/* Push this amended tile to the local tiles. */
tile_packed = tile_prev_packed;
tile.is_valid = true;
}
}
barrier();
tiles_local[tile_co.y][tile_co.x] = (tile.is_valid) ? tile_packed : SHADOW_NO_DATA;
barrier();
}
}
LIGHT_FOREACH_END
}

View File

@ -57,6 +57,7 @@ void main()
bool is_cubemap = (tilemap_data.projection_type == SHADOW_PROJECTION_CUBEFACE); bool is_cubemap = (tilemap_data.projection_type == SHADOW_PROJECTION_CUBEFACE);
int lod_max = is_cubemap ? SHADOW_TILEMAP_LOD : 0; int lod_max = is_cubemap ? SHADOW_TILEMAP_LOD : 0;
int valid_tile_index = -1; int valid_tile_index = -1;
uint valid_lod = 0u;
/* With all threads (LOD0 size dispatch) load each lod tile from the highest lod /* With all threads (LOD0 size dispatch) load each lod tile from the highest lod
* to the lowest, keeping track of the lowest one allocated which will be use for shadowing. * to the lowest, keeping track of the lowest one allocated which will be use for shadowing.
* This guarantee a O(1) lookup time. * This guarantee a O(1) lookup time.
@ -176,12 +177,17 @@ void main()
if (tile.is_used && tile.is_allocated && (!tile.do_update || lod_is_rendered)) { if (tile.is_used && tile.is_allocated && (!tile.do_update || lod_is_rendered)) {
/* Save highest lod for this thread. */ /* Save highest lod for this thread. */
valid_tile_index = tile_index; valid_tile_index = tile_index;
valid_lod = uint(lod);
} }
} }
/* Store the highest LOD valid page for rendering. */ /* Store the highest LOD valid page for rendering. */
uint tile_packed = (valid_tile_index != -1) ? tiles_buf[valid_tile_index] : SHADOW_NO_DATA; ShadowTileDataPacked tile_packed = (valid_tile_index != -1) ? tiles_buf[valid_tile_index] :
imageStore(tilemaps_img, atlas_texel, uvec4(tile_packed)); SHADOW_NO_DATA;
ShadowTileData tile_data = shadow_tile_unpack(tile_packed);
ShadowSamplingTile tile_sampling = shadow_sampling_tile_create(tile_data, valid_lod);
ShadowSamplingTilePacked tile_sampling_packed = shadow_sampling_tile_pack(tile_sampling);
imageStore(tilemaps_img, atlas_texel, uvec4(tile_sampling_packed));
if (all(equal(gl_GlobalInvocationID, uvec3(0)))) { if (all(equal(gl_GlobalInvocationID, uvec3(0)))) {
/* Clamp it as it can underflow if there is too much tile present on screen. */ /* Clamp it as it can underflow if there is too much tile present on screen. */

View File

@ -91,14 +91,14 @@ int shadow_tile_offset(ivec2 tile, int tiles_index, int lod)
* \{ */ * \{ */
/** \note: Will clamp if out of bounds. */ /** \note: Will clamp if out of bounds. */
ShadowTileData shadow_tile_load(usampler2D tilemaps_tx, ivec2 tile_co, int tilemap_index) ShadowSamplingTile shadow_tile_load(usampler2D tilemaps_tx, ivec2 tile_co, int tilemap_index)
{ {
/* NOTE(@fclem): This clamp can hide some small imprecision at clip-map transition. /* NOTE(@fclem): This clamp can hide some small imprecision at clip-map transition.
* Can be disabled to check if the clip-map is well centered. */ * Can be disabled to check if the clip-map is well centered. */
tile_co = clamp(tile_co, ivec2(0), ivec2(SHADOW_TILEMAP_RES - 1)); tile_co = clamp(tile_co, ivec2(0), ivec2(SHADOW_TILEMAP_RES - 1));
uint tile_data = ivec2 texel = shadow_tile_coord_in_atlas(tile_co, tilemap_index);
texelFetch(tilemaps_tx, shadow_tile_coord_in_atlas(tile_co, tilemap_index), 0).x; uint tile_data = texelFetch(tilemaps_tx, texel, 0).x;
return shadow_tile_unpack(tile_data); return shadow_sampling_tile_unpack(tile_data);
} }
/** /**

View File

@ -23,16 +23,19 @@ float shadow_read_depth_at_tilemap_uv(int tilemap_index, vec2 tilemap_uv)
ivec2 texel_coord = ivec2(tilemap_uv * float(SHADOW_MAP_MAX_RES)); ivec2 texel_coord = ivec2(tilemap_uv * float(SHADOW_MAP_MAX_RES));
/* Using bitwise ops is way faster than integer ops. */ /* Using bitwise ops is way faster than integer ops. */
const int page_shift = SHADOW_PAGE_LOD; const int page_shift = SHADOW_PAGE_LOD;
const int page_mask = ~(0xFFFFFFFF << SHADOW_PAGE_LOD);
ivec2 tile_coord = texel_coord >> page_shift; ivec2 tile_coord = texel_coord >> page_shift;
ShadowTileData tile = shadow_tile_load(shadow_tilemaps_tx, tile_coord, tilemap_index); ShadowSamplingTile tile = shadow_tile_load(shadow_tilemaps_tx, tile_coord, tilemap_index);
if (!tile.is_allocated) { if (!tile.is_valid) {
return -1.0; return -1.0;
} }
/* Shift LOD0 pixels so that they get wrapped at the right position for the given LOD. */
int page_mask = ~(0xFFFFFFFF << (SHADOW_PAGE_LOD + int(tile.lod))); /* TODO convert everything to uint to avoid signed int operations. */
ivec2 texel_page = (texel_coord & page_mask) >> int(tile.lod); texel_coord += ivec2(tile.lod_offset << SHADOW_PAGE_LOD);
/* Scale to LOD pixels (merge LOD0 pixels together) then mask to get pixel in page. */
ivec2 texel_page = (texel_coord >> int(tile.lod)) & page_mask;
ivec3 texel = ivec3((ivec2(tile.page.xy) << page_shift) | texel_page, tile.page.z); ivec3 texel = ivec3((ivec2(tile.page.xy) << page_shift) | texel_page, tile.page.z);
return uintBitsToFloat(texelFetch(shadow_atlas_tx, texel, 0).r); return uintBitsToFloat(texelFetch(shadow_atlas_tx, texel, 0).r);
@ -439,8 +442,8 @@ vec3 shadow_pcf_offset(LightData light, const bool is_directional, vec3 P, vec3
else { else {
params = shadow_punctual_sample_params_get(light, P); params = shadow_punctual_sample_params_get(light, P);
} }
ShadowTileData tile = shadow_tile_data_get(shadow_tilemaps_tx, params); ShadowSamplingTile tile = shadow_tile_data_get(shadow_tilemaps_tx, params);
if (!tile.is_allocated) { if (!tile.is_valid) {
return vec3(0.0); return vec3(0.0);
} }

View File

@ -195,6 +195,13 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tilemap_finalize)
.additional_info("eevee_shared") .additional_info("eevee_shared")
.compute_source("eevee_shadow_tilemap_finalize_comp.glsl"); .compute_source("eevee_shadow_tilemap_finalize_comp.glsl");
GPU_SHADER_CREATE_INFO(eevee_shadow_tilemap_amend)
.do_static_compilation(true)
.local_group_size(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES)
.image(0, GPU_R32UI, Qualifier::READ_WRITE, ImageType::UINT_2D, "tilemaps_img")
.additional_info("eevee_shared", "eevee_light_data", "draw_view")
.compute_source("eevee_shadow_tilemap_amend_comp.glsl");
/* AtomicMin clear implementation. */ /* AtomicMin clear implementation. */
GPU_SHADER_CREATE_INFO(eevee_shadow_page_clear) GPU_SHADER_CREATE_INFO(eevee_shadow_page_clear)
.do_static_compilation(true) .do_static_compilation(true)

View File

@ -237,8 +237,8 @@ static void overlay_edit_mesh_add_ob_to_pass(OVERLAY_PrivateData *pd, Object *ob
/* TODO: Should be its own function. */ /* TODO: Should be its own function. */
Mesh *mesh = (Mesh *)ob->data; Mesh *mesh = (Mesh *)ob->data;
if (BMEditMesh *em = mesh->runtime->edit_mesh) { if (BMEditMesh *em = mesh->runtime->edit_mesh) {
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob); const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob); const Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob);
has_edit_mesh_cage = editmesh_eval_cage && (editmesh_eval_cage != editmesh_eval_final); has_edit_mesh_cage = editmesh_eval_cage && (editmesh_eval_cage != editmesh_eval_final);
has_skin_roots = CustomData_get_offset(&em->bm->vdata, CD_MVERT_SKIN) != -1; has_skin_roots = CustomData_get_offset(&em->bm->vdata, CD_MVERT_SKIN) != -1;

View File

@ -177,11 +177,11 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
bool is_mesh_verts_only = false; bool is_mesh_verts_only = false;
if (is_mesh) { if (is_mesh) {
/* TODO: Should be its own function. */ /* TODO: Should be its own function. */
Mesh *mesh = static_cast<Mesh *>(ob->data); const Mesh *mesh = static_cast<const Mesh *>(ob->data);
if (is_edit_mode) { if (is_edit_mode) {
BLI_assert(mesh->runtime->edit_mesh); BLI_assert(mesh->runtime->edit_mesh);
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob); const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob); const Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob);
has_edit_mesh_cage = editmesh_eval_cage && (editmesh_eval_cage != editmesh_eval_final); has_edit_mesh_cage = editmesh_eval_cage && (editmesh_eval_cage != editmesh_eval_final);
if (editmesh_eval_final) { if (editmesh_eval_final) {
mesh = editmesh_eval_final; mesh = editmesh_eval_final;

View File

@ -336,8 +336,7 @@ void mesh_render_data_update_faces_sorted(MeshRenderData &mr,
const Mesh *editmesh_final_or_this(const Object *object, const Mesh *mesh) const Mesh *editmesh_final_or_this(const Object *object, const Mesh *mesh)
{ {
if (mesh->runtime->edit_mesh != nullptr) { if (mesh->runtime->edit_mesh != nullptr) {
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object); if (const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object)) {
if (editmesh_eval_final != nullptr) {
return editmesh_eval_final; return editmesh_eval_final;
} }
} }
@ -507,7 +506,7 @@ void mesh_render_data_update_normals(MeshRenderData &mr, const eMRDataType data_
const float(*vert_normals)[3] = nullptr; const float(*vert_normals)[3] = nullptr;
const float(*face_normals)[3] = nullptr; const float(*face_normals)[3] = nullptr;
if (mr.edit_data && !mr.edit_data->vertexCos.is_empty()) { if (mr.edit_data && !mr.edit_data->vert_positions.is_empty()) {
vert_coords = reinterpret_cast<const float(*)[3]>(mr.bm_vert_coords.data()); vert_coords = reinterpret_cast<const float(*)[3]>(mr.bm_vert_coords.data());
vert_normals = reinterpret_cast<const float(*)[3]>(mr.bm_vert_normals.data()); vert_normals = reinterpret_cast<const float(*)[3]>(mr.bm_vert_normals.data());
face_normals = reinterpret_cast<const float(*)[3]>(mr.bm_face_normals.data()); face_normals = reinterpret_cast<const float(*)[3]>(mr.bm_face_normals.data());
@ -559,8 +558,8 @@ MeshRenderData *mesh_render_data_create(Object *object,
mr->use_hide = use_hide; mr->use_hide = use_hide;
if (is_editmode) { if (is_editmode) {
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object); const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object);
Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(object); const Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(object);
BLI_assert(editmesh_eval_cage && editmesh_eval_final); BLI_assert(editmesh_eval_cage && editmesh_eval_final);
mr->bm = mesh->runtime->edit_mesh->bm; mr->bm = mesh->runtime->edit_mesh->bm;
@ -573,15 +572,14 @@ MeshRenderData *mesh_render_data_create(Object *object,
if (mr->edit_data) { if (mr->edit_data) {
bke::EditMeshData *emd = mr->edit_data; bke::EditMeshData *emd = mr->edit_data;
if (!emd->vertexCos.is_empty()) { if (!emd->vert_positions.is_empty()) {
BKE_editmesh_cache_ensure_vert_normals(*mr->edit_bmesh, *emd); BKE_editmesh_cache_ensure_vert_normals(*mr->edit_bmesh, *emd);
BKE_editmesh_cache_ensure_face_normals(*mr->edit_bmesh, *emd); BKE_editmesh_cache_ensure_face_normals(*mr->edit_bmesh, *emd);
} }
mr->bm_vert_coords = mr->edit_data->vertexCos; mr->bm_vert_coords = mr->edit_data->vert_positions;
mr->bm_vert_normals = mr->edit_data->vertexNos; mr->bm_vert_normals = mr->edit_data->vert_normals;
mr->bm_face_normals = mr->edit_data->faceNos; mr->bm_face_normals = mr->edit_data->face_normals;
mr->bm_face_centers = mr->edit_data->faceCos;
} }
int bm_ensure_types = BM_VERT | BM_EDGE | BM_LOOP | BM_FACE; int bm_ensure_types = BM_VERT | BM_EDGE | BM_LOOP | BM_FACE;

View File

@ -1407,7 +1407,8 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph *task_graph,
/* Modifiers will only generate an orco layer if the mesh is deformed. */ /* Modifiers will only generate an orco layer if the mesh is deformed. */
if (cache.cd_needed.orco != 0) { if (cache.cd_needed.orco != 0) {
/* Orco is always extracted from final mesh. */ /* Orco is always extracted from final mesh. */
Mesh *me_final = (mesh->runtime->edit_mesh) ? BKE_object_get_editmesh_eval_final(ob) : mesh; const Mesh *me_final = (mesh->runtime->edit_mesh) ? BKE_object_get_editmesh_eval_final(ob) :
mesh;
if (CustomData_get_layer(&me_final->vert_data, CD_ORCO) == nullptr) { if (CustomData_get_layer(&me_final->vert_data, CD_ORCO) == nullptr) {
/* Skip orco calculation */ /* Skip orco calculation */
cache.cd_needed.orco = 0; cache.cd_needed.orco = 0;
@ -1512,8 +1513,8 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph *task_graph,
bool do_cage = false, do_uvcage = false; bool do_cage = false, do_uvcage = false;
if (is_editmode && is_mode_active) { if (is_editmode && is_mode_active) {
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob); const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob); const Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob);
do_cage = editmesh_eval_final != editmesh_eval_cage; do_cage = editmesh_eval_final != editmesh_eval_cage;
do_uvcage = !(editmesh_eval_final->runtime->is_original_bmesh && do_uvcage = !(editmesh_eval_final->runtime->is_original_bmesh &&

View File

@ -750,7 +750,7 @@ static void draw_subdiv_cache_extra_coarse_face_data_bm(BMesh *bm,
} }
static void draw_subdiv_cache_extra_coarse_face_data_mesh(const MeshRenderData &mr, static void draw_subdiv_cache_extra_coarse_face_data_mesh(const MeshRenderData &mr,
Mesh *mesh, const Mesh *mesh,
uint32_t *flags_data) uint32_t *flags_data)
{ {
const OffsetIndices faces = mesh->faces(); const OffsetIndices faces = mesh->faces();
@ -771,7 +771,7 @@ static void draw_subdiv_cache_extra_coarse_face_data_mesh(const MeshRenderData &
} }
} }
static void draw_subdiv_cache_extra_coarse_face_data_mapped(Mesh *mesh, static void draw_subdiv_cache_extra_coarse_face_data_mapped(const Mesh *mesh,
BMesh *bm, BMesh *bm,
MeshRenderData &mr, MeshRenderData &mr,
uint32_t *flags_data) uint32_t *flags_data)
@ -797,7 +797,7 @@ static void draw_subdiv_cache_extra_coarse_face_data_mapped(Mesh *mesh,
} }
static void draw_subdiv_cache_update_extra_coarse_face_data(DRWSubdivCache &cache, static void draw_subdiv_cache_update_extra_coarse_face_data(DRWSubdivCache &cache,
Mesh *mesh, const Mesh *mesh,
MeshRenderData &mr) MeshRenderData &mr)
{ {
if (cache.extra_coarse_face_data == nullptr) { if (cache.extra_coarse_face_data == nullptr) {
@ -839,7 +839,7 @@ static DRWSubdivCache &mesh_batch_cache_ensure_subdiv_cache(MeshBatchCache &mbc)
return *subdiv_cache; return *subdiv_cache;
} }
static void draw_subdiv_invalidate_evaluator_for_orco(Subdiv *subdiv, Mesh *mesh) static void draw_subdiv_invalidate_evaluator_for_orco(Subdiv *subdiv, const Mesh *mesh)
{ {
if (!(subdiv && subdiv->evaluator)) { if (!(subdiv && subdiv->evaluator)) {
return; return;
@ -1167,7 +1167,7 @@ static void build_vertex_face_adjacency_maps(DRWSubdivCache &cache)
static bool draw_subdiv_build_cache(DRWSubdivCache &cache, static bool draw_subdiv_build_cache(DRWSubdivCache &cache,
Subdiv *subdiv, Subdiv *subdiv,
Mesh *mesh_eval, const Mesh *mesh_eval,
const SubsurfRuntimeData *runtime_data) const SubsurfRuntimeData *runtime_data)
{ {
SubdivToMeshSettings to_mesh_settings; SubdivToMeshSettings to_mesh_settings;
@ -2020,7 +2020,7 @@ void draw_subdiv_build_edituv_stretch_angle_buffer(const DRWSubdivCache &cache,
* since all sub-faces are contiguous, they all share the same offset. * since all sub-faces are contiguous, they all share the same offset.
*/ */
static void draw_subdiv_cache_ensure_mat_offsets(DRWSubdivCache &cache, static void draw_subdiv_cache_ensure_mat_offsets(DRWSubdivCache &cache,
Mesh *mesh_eval, const Mesh *mesh_eval,
uint mat_len) uint mat_len)
{ {
draw_subdiv_cache_free_material_data(cache); draw_subdiv_cache_free_material_data(cache);
@ -2108,7 +2108,7 @@ static bool draw_subdiv_create_requested_buffers(Object *ob,
return false; return false;
} }
Mesh *mesh_eval = mesh; const Mesh *mesh_eval = mesh;
BMesh *bm = nullptr; BMesh *bm = nullptr;
if (mesh->runtime->edit_mesh) { if (mesh->runtime->edit_mesh) {
mesh_eval = BKE_object_get_editmesh_eval_final(ob); mesh_eval = BKE_object_get_editmesh_eval_final(ob);

View File

@ -46,6 +46,9 @@
#include "draw_manager_text.hh" #include "draw_manager_text.hh"
#include "intern/bmesh_polygon.hh" #include "intern/bmesh_polygon.hh"
using blender::float3;
using blender::Span;
struct ViewCachedString { struct ViewCachedString {
float vec[3]; float vec[3];
union { union {
@ -255,7 +258,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
*/ */
DRWTextStore *dt = DRW_text_cache_ensure(); DRWTextStore *dt = DRW_text_cache_ensure();
const short txt_flag = DRW_TEXT_CACHE_GLOBALSPACE; const short txt_flag = DRW_TEXT_CACHE_GLOBALSPACE;
Mesh *mesh = BKE_object_get_editmesh_eval_cage(ob); const Mesh *mesh = BKE_object_get_editmesh_eval_cage(ob);
BMEditMesh *em = mesh->runtime->edit_mesh; BMEditMesh *em = mesh->runtime->edit_mesh;
float v1[3], v2[3], v3[3], vmid[3], fvec[3]; float v1[3], v2[3], v3[3], vmid[3], fvec[3];
char numstr[32]; /* Stores the measurement display text here */ char numstr[32]; /* Stores the measurement display text here */
@ -269,8 +272,8 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
float clip_planes[4][4]; float clip_planes[4][4];
/* allow for displaying shape keys and deform mods */ /* allow for displaying shape keys and deform mods */
BMIter iter; BMIter iter;
const float(*vert_coords)[3] = BKE_mesh_wrapper_vert_coords(mesh); const Span<float3> vert_positions = BKE_mesh_wrapper_vert_coords(mesh);
const bool use_coords = (vert_coords != nullptr); const bool use_coords = !vert_positions.is_empty();
/* when 2 or more edge-info options are enabled, space apart */ /* when 2 or more edge-info options are enabled, space apart */
short edge_tex_count = 0; short edge_tex_count = 0;
@ -329,9 +332,9 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
{ {
float v1_clip[3], v2_clip[3]; float v1_clip[3], v2_clip[3];
if (vert_coords) { if (use_coords) {
copy_v3_v3(v1, vert_coords[BM_elem_index_get(eed->v1)]); copy_v3_v3(v1, vert_positions[BM_elem_index_get(eed->v1)]);
copy_v3_v3(v2, vert_coords[BM_elem_index_get(eed->v2)]); copy_v3_v3(v2, vert_positions[BM_elem_index_get(eed->v2)]);
} }
else { else {
copy_v3_v3(v1, eed->v1->co); copy_v3_v3(v1, eed->v1->co);
@ -373,10 +376,12 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGEANG, col); UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGEANG, col);
const float(*face_normals)[3] = nullptr; Span<float3> face_normals;
if (use_coords) { if (use_coords) {
BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
face_normals = BKE_mesh_wrapper_face_normals(mesh); /* TODO: This is not const correct for wrapper meshes, but it should be okay because
* every evaluated object gets its own evaluated cage mesh (they are not shared). */
face_normals = BKE_mesh_wrapper_face_normals(const_cast<Mesh *>(mesh));
} }
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
@ -395,9 +400,9 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
{ {
float v1_clip[3], v2_clip[3]; float v1_clip[3], v2_clip[3];
if (vert_coords) { if (use_coords) {
copy_v3_v3(v1, vert_coords[BM_elem_index_get(eed->v1)]); copy_v3_v3(v1, vert_positions[BM_elem_index_get(eed->v1)]);
copy_v3_v3(v2, vert_coords[BM_elem_index_get(eed->v2)]); copy_v3_v3(v2, vert_positions[BM_elem_index_get(eed->v2)]);
} }
else { else {
copy_v3_v3(v1, eed->v1->co); copy_v3_v3(v1, eed->v1->co);
@ -462,9 +467,9 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
for (int j = 0; j < f_corner_tris_len; j++) { for (int j = 0; j < f_corner_tris_len; j++) {
if (use_coords) { if (use_coords) {
copy_v3_v3(v1, vert_coords[BM_elem_index_get(ltri_array[j][0]->v)]); copy_v3_v3(v1, vert_positions[BM_elem_index_get(ltri_array[j][0]->v)]);
copy_v3_v3(v2, vert_coords[BM_elem_index_get(ltri_array[j][1]->v)]); copy_v3_v3(v2, vert_positions[BM_elem_index_get(ltri_array[j][1]->v)]);
copy_v3_v3(v3, vert_coords[BM_elem_index_get(ltri_array[j][2]->v)]); copy_v3_v3(v3, vert_positions[BM_elem_index_get(ltri_array[j][2]->v)]);
} }
else { else {
copy_v3_v3(v1, ltri_array[j][0]->v->co); copy_v3_v3(v1, ltri_array[j][0]->v->co);
@ -537,7 +542,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
/* lazy init center calc */ /* lazy init center calc */
if (is_first) { if (is_first) {
if (use_coords) { if (use_coords) {
BM_face_calc_center_bounds_vcos(em->bm, efa, vmid, vert_coords); BM_face_calc_center_bounds_vcos(em->bm, efa, vmid, vert_positions);
} }
else { else {
BM_face_calc_center_bounds(efa, vmid); BM_face_calc_center_bounds(efa, vmid);
@ -545,9 +550,9 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
is_first = false; is_first = false;
} }
if (use_coords) { if (use_coords) {
copy_v3_v3(v1, vert_coords[BM_elem_index_get(loop->prev->v)]); copy_v3_v3(v1, vert_positions[BM_elem_index_get(loop->prev->v)]);
copy_v3_v3(v2, vert_coords[BM_elem_index_get(loop->v)]); copy_v3_v3(v2, vert_positions[BM_elem_index_get(loop->v)]);
copy_v3_v3(v3, vert_coords[BM_elem_index_get(loop->next->v)]); copy_v3_v3(v3, vert_positions[BM_elem_index_get(loop->next->v)]);
} }
else { else {
copy_v3_v3(v1, loop->prev->v->co); copy_v3_v3(v1, loop->prev->v->co);
@ -595,7 +600,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
BM_ITER_MESH_INDEX (v, &iter, em->bm, BM_VERTS_OF_MESH, i) { BM_ITER_MESH_INDEX (v, &iter, em->bm, BM_VERTS_OF_MESH, i) {
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
if (use_coords) { if (use_coords) {
copy_v3_v3(v1, vert_coords[BM_elem_index_get(v)]); copy_v3_v3(v1, vert_positions[BM_elem_index_get(v)]);
} }
else { else {
copy_v3_v3(v1, v->co); copy_v3_v3(v1, v->co);
@ -620,8 +625,8 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
float v1_clip[3], v2_clip[3]; float v1_clip[3], v2_clip[3];
if (use_coords) { if (use_coords) {
copy_v3_v3(v1, vert_coords[BM_elem_index_get(eed->v1)]); copy_v3_v3(v1, vert_positions[BM_elem_index_get(eed->v1)]);
copy_v3_v3(v2, vert_coords[BM_elem_index_get(eed->v2)]); copy_v3_v3(v2, vert_positions[BM_elem_index_get(eed->v2)]);
} }
else { else {
copy_v3_v3(v1, eed->v1->co); copy_v3_v3(v1, eed->v1->co);
@ -658,7 +663,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
if (use_coords) { if (use_coords) {
BM_face_calc_center_median_vcos(em->bm, f, v1, vert_coords); BM_face_calc_center_median_vcos(em->bm, f, v1, vert_positions);
} }
else { else {
BM_face_calc_center_median(f, v1); BM_face_calc_center_median(f, v1);

View File

@ -101,7 +101,7 @@ struct DRWSubdivLooseGeom {
* \{ */ * \{ */
struct DRWSubdivCache { struct DRWSubdivCache {
Mesh *mesh; const Mesh *mesh;
BMesh *bm; BMesh *bm;
Subdiv *subdiv; Subdiv *subdiv;
bool optimal_display; bool optimal_display;

View File

@ -197,7 +197,7 @@ static DRWShadingGroup *drw_volume_object_mesh_init(Scene *scene,
return nullptr; return nullptr;
} }
if (fds->fluid && (fds->type == FLUID_DOMAIN_TYPE_GAS)) { if (fds->type == FLUID_DOMAIN_TYPE_GAS) {
DRW_smoke_ensure(fmd, fds->flags & FLUID_DOMAIN_USE_NOISE); DRW_smoke_ensure(fmd, fds->flags & FLUID_DOMAIN_USE_NOISE);
} }
@ -384,7 +384,7 @@ PassType *drw_volume_object_mesh_init(PassType &ps,
return nullptr; return nullptr;
} }
if (fds->fluid && (fds->type == FLUID_DOMAIN_TYPE_GAS)) { if (fds->type == FLUID_DOMAIN_TYPE_GAS) {
DRW_smoke_ensure(fmd, fds->flags & FLUID_DOMAIN_USE_NOISE); DRW_smoke_ensure(fmd, fds->flags & FLUID_DOMAIN_USE_NOISE);
} }

View File

@ -80,7 +80,6 @@ struct MeshRenderData {
Span<float3> bm_vert_coords; Span<float3> bm_vert_coords;
Span<float3> bm_vert_normals; Span<float3> bm_vert_normals;
Span<float3> bm_face_normals; Span<float3> bm_face_normals;
Span<float3> bm_face_centers;
Array<float3> bm_loop_normals; Array<float3> bm_loop_normals;
const int *v_origindex, *e_origindex, *p_origindex; const int *v_origindex, *e_origindex, *p_origindex;
@ -90,7 +89,7 @@ struct MeshRenderData {
int freestyle_edge_ofs; int freestyle_edge_ofs;
int freestyle_face_ofs; int freestyle_face_ofs;
/** Mesh */ /** Mesh */
Mesh *mesh; const Mesh *mesh;
Span<float3> vert_positions; Span<float3> vert_positions;
Span<int2> edges; Span<int2> edges;
OffsetIndices<int> faces; OffsetIndices<int> faces;

View File

@ -268,7 +268,7 @@ static void extract_attr_init_subdiv(const DRWSubdivCache &subdiv_cache,
const DRW_Attributes *attrs_used = &cache.attr_used; const DRW_Attributes *attrs_used = &cache.attr_used;
const DRW_AttributeRequest &request = attrs_used->requests[index]; const DRW_AttributeRequest &request = attrs_used->requests[index];
Mesh *coarse_mesh = subdiv_cache.mesh; const Mesh *coarse_mesh = subdiv_cache.mesh;
/* Prepare VBO for coarse data. The compute shader only expects floats. */ /* Prepare VBO for coarse data. The compute shader only expects floats. */
gpu::VertBuf *src_data = GPU_vertbuf_calloc(); gpu::VertBuf *src_data = GPU_vertbuf_calloc();

View File

@ -253,8 +253,8 @@ static void extract_edituv_stretch_angle_init_subdiv(const DRWSubdivCache &subdi
/* UVs are stored contiguously so we need to compute the offset in the UVs buffer for the active /* UVs are stored contiguously so we need to compute the offset in the UVs buffer for the active
* UV layer. */ * UV layer. */
CustomData *cd_ldata = (mr.extract_type == MR_EXTRACT_MESH) ? &mr.mesh->corner_data : const CustomData *cd_ldata = (mr.extract_type == MR_EXTRACT_MESH) ? &mr.mesh->corner_data :
&mr.bm->ldata; &mr.bm->ldata;
uint32_t uv_layers = cache.cd_used.uv; uint32_t uv_layers = cache.cd_used.uv;
/* HACK to fix #68857 */ /* HACK to fix #68857 */

View File

@ -37,7 +37,7 @@ static void extract_orco_init(const MeshRenderData &mr,
GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr.corners_num); GPU_vertbuf_data_alloc(vbo, mr.corners_num);
CustomData *cd_vdata = &mr.mesh->vert_data; const CustomData *cd_vdata = &mr.mesh->vert_data;
MeshExtract_Orco_Data *data = static_cast<MeshExtract_Orco_Data *>(tls_data); MeshExtract_Orco_Data *data = static_cast<MeshExtract_Orco_Data *>(tls_data);
data->vbo_data = (float(*)[4])GPU_vertbuf_get_data(vbo); data->vbo_data = (float(*)[4])GPU_vertbuf_get_data(vbo);

View File

@ -48,14 +48,20 @@ static void extract_pos_init(const MeshRenderData &mr,
MutableSpan vbo_data(static_cast<float3 *>(GPU_vertbuf_get_data(vbo)), MutableSpan vbo_data(static_cast<float3 *>(GPU_vertbuf_get_data(vbo)),
GPU_vertbuf_get_vertex_len(vbo)); GPU_vertbuf_get_vertex_len(vbo));
if (mr.extract_type == MR_EXTRACT_MESH) { if (mr.extract_type == MR_EXTRACT_MESH) {
array_utils::gather( threading::memory_bandwidth_bound_task(
mr.vert_positions, mr.corner_verts, vbo_data.take_front(mr.corner_verts.size())); mr.vert_positions.size_in_bytes() + mr.corner_verts.size_in_bytes() +
extract_mesh_loose_edge_positions(mr.vert_positions, vbo_data.size_in_bytes() + mr.loose_edges.size(),
mr.edges, [&]() {
mr.loose_edges, array_utils::gather(
vbo_data.slice(mr.corners_num, mr.loose_edges.size() * 2)); mr.vert_positions, mr.corner_verts, vbo_data.take_front(mr.corner_verts.size()));
array_utils::gather( extract_mesh_loose_edge_positions(
mr.vert_positions, mr.loose_verts, vbo_data.take_back(mr.loose_verts.size())); mr.vert_positions,
mr.edges,
mr.loose_edges,
vbo_data.slice(mr.corners_num, mr.loose_edges.size() * 2));
array_utils::gather(
mr.vert_positions, mr.loose_verts, vbo_data.take_back(mr.loose_verts.size()));
});
} }
else { else {
*static_cast<float3 **>(tls_data) = vbo_data.data(); *static_cast<float3 **>(tls_data) = vbo_data.data();

View File

@ -117,7 +117,7 @@ static void extract_sculpt_data_init_subdiv(const DRWSubdivCache &subdiv_cache,
{ {
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buffer); gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buffer);
Mesh *coarse_mesh = mr.mesh; const Mesh *coarse_mesh = mr.mesh;
/* First, interpolate mask if available. */ /* First, interpolate mask if available. */
gpu::VertBuf *mask_vbo = nullptr; gpu::VertBuf *mask_vbo = nullptr;

View File

@ -38,10 +38,10 @@ static void extract_tan_init_common(const MeshRenderData &mr,
{ {
GPU_vertformat_deinterleave(format); GPU_vertformat_deinterleave(format);
CustomData *cd_ldata = (mr.extract_type == MR_EXTRACT_BMESH) ? &mr.bm->ldata : const CustomData *cd_ldata = (mr.extract_type == MR_EXTRACT_BMESH) ? &mr.bm->ldata :
&mr.mesh->corner_data; &mr.mesh->corner_data;
CustomData *cd_vdata = (mr.extract_type == MR_EXTRACT_BMESH) ? &mr.bm->vdata : const CustomData *cd_vdata = (mr.extract_type == MR_EXTRACT_BMESH) ? &mr.bm->vdata :
&mr.mesh->vert_data; &mr.mesh->vert_data;
uint32_t tan_layers = cache.cd_used.tan; uint32_t tan_layers = cache.cd_used.tan;
const float(*orco)[3] = (const float(*)[3])CustomData_get_layer(cd_vdata, CD_ORCO); const float(*orco)[3] = (const float(*)[3])CustomData_get_layer(cd_vdata, CD_ORCO);
float(*orco_allocated)[3] = nullptr; float(*orco_allocated)[3] = nullptr;
@ -96,7 +96,9 @@ static void extract_tan_init_common(const MeshRenderData &mr,
copy_v3_v3(orco_allocated[v], mr.vert_positions[v]); copy_v3_v3(orco_allocated[v], mr.vert_positions[v]);
} }
} }
BKE_mesh_orco_verts_transform(mr.mesh, orco_allocated, mr.verts_num, false); /* TODO: This is not thread-safe. Draw extraction should not modify the mesh. */
BKE_mesh_orco_verts_transform(
const_cast<Mesh *>(mr.mesh), orco_allocated, mr.verts_num, false);
orco = orco_allocated; orco = orco_allocated;
} }
@ -118,6 +120,7 @@ static void extract_tan_init_common(const MeshRenderData &mr,
&tangent_mask); &tangent_mask);
} }
else { else {
/* TODO: This is not thread-safe. Draw extraction should not modify the mesh. */
BKE_mesh_calc_loop_tangent_ex(reinterpret_cast<const float(*)[3]>(mr.vert_positions.data()), BKE_mesh_calc_loop_tangent_ex(reinterpret_cast<const float(*)[3]>(mr.vert_positions.data()),
mr.faces, mr.faces,
mr.corner_verts.data(), mr.corner_verts.data(),

View File

@ -22,9 +22,9 @@ namespace blender::draw {
/* Initialize the vertex format to be used for UVs. Return true if any UV layer is /* Initialize the vertex format to be used for UVs. Return true if any UV layer is
* found, false otherwise. */ * found, false otherwise. */
static bool mesh_extract_uv_format_init(GPUVertFormat *format, static bool mesh_extract_uv_format_init(GPUVertFormat *format,
MeshBatchCache &cache, const MeshBatchCache &cache,
CustomData *cd_ldata, const CustomData *cd_ldata,
eMRExtractType extract_type, const eMRExtractType extract_type,
uint32_t &r_uv_layers) uint32_t &r_uv_layers)
{ {
GPU_vertformat_deinterleave(format); GPU_vertformat_deinterleave(format);
@ -89,8 +89,8 @@ static void extract_uv_init(const MeshRenderData &mr,
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buf); gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buf);
GPUVertFormat format = {0}; GPUVertFormat format = {0};
CustomData *cd_ldata = (mr.extract_type == MR_EXTRACT_BMESH) ? &mr.bm->ldata : const CustomData *cd_ldata = (mr.extract_type == MR_EXTRACT_BMESH) ? &mr.bm->ldata :
&mr.mesh->corner_data; &mr.mesh->corner_data;
int v_len = mr.corners_num; int v_len = mr.corners_num;
uint32_t uv_layers = cache.cd_used.uv; uint32_t uv_layers = cache.cd_used.uv;
if (!mesh_extract_uv_format_init(&format, cache, cd_ldata, mr.extract_type, uv_layers)) { if (!mesh_extract_uv_format_init(&format, cache, cd_ldata, mr.extract_type, uv_layers)) {
@ -136,7 +136,7 @@ static void extract_uv_init_subdiv(const DRWSubdivCache &subdiv_cache,
void *buffer, void *buffer,
void * /*data*/) void * /*data*/)
{ {
Mesh *coarse_mesh = subdiv_cache.mesh; const Mesh *coarse_mesh = subdiv_cache.mesh;
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buffer); gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buffer);
GPUVertFormat format = {0}; GPUVertFormat format = {0};

View File

@ -159,7 +159,7 @@ static void extract_weights_init_subdiv(const DRWSubdivCache &subdiv_cache,
void *buffer, void *buffer,
void *_data) void *_data)
{ {
Mesh *coarse_mesh = subdiv_cache.mesh; const Mesh *coarse_mesh = subdiv_cache.mesh;
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buffer); gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buffer);
static GPUVertFormat format = {0}; static GPUVertFormat format = {0};

View File

@ -10,7 +10,7 @@
#include "BKE_node.hh" #include "BKE_node.hh"
#include "BKE_object.hh" #include "BKE_object.hh"
#include "DEG_depsgraph.hh" #include "BLI_vector.hh"
#include "RNA_define.hh" #include "RNA_define.hh"
@ -1164,6 +1164,375 @@ static void test_eevee_shadow_finalize()
} }
DRAW_TEST(eevee_shadow_finalize) DRAW_TEST(eevee_shadow_finalize)
static void test_eevee_shadow_tile_packing()
{
Vector<uint> test_values{0x00000000u, 0x00000001u, 0x0000000Fu, 0x000000FFu, 0xABCDEF01u,
0xAAAAAAAAu, 0xBBBBBBBBu, 0xCCCCCCCCu, 0xDDDDDDDDu, 0xEEEEEEEEu,
0xFFFFFFFFu, 0xDEADBEEFu, 0x8BADF00Du, 0xABADCAFEu, 0x0D15EA5Eu,
0xFEE1DEADu, 0xDEADC0DEu, 0xC00010FFu, 0xBBADBEEFu, 0xBAAAAAADu};
for (auto value : test_values) {
EXPECT_EQ(shadow_page_unpack(value),
shadow_page_unpack(shadow_page_pack(shadow_page_unpack(value))));
EXPECT_EQ(shadow_lod_offset_unpack(value),
shadow_lod_offset_unpack(shadow_lod_offset_pack(shadow_lod_offset_unpack(value))));
ShadowTileData expected_tile = shadow_tile_unpack(value);
ShadowTileData result_tile = shadow_tile_unpack(shadow_tile_pack(expected_tile));
EXPECT_EQ(expected_tile.page, result_tile.page);
EXPECT_EQ(expected_tile.cache_index, result_tile.cache_index);
EXPECT_EQ(expected_tile.is_used, result_tile.is_used);
EXPECT_EQ(expected_tile.do_update, result_tile.do_update);
EXPECT_EQ(expected_tile.is_allocated, result_tile.is_allocated);
EXPECT_EQ(expected_tile.is_rendered, result_tile.is_rendered);
EXPECT_EQ(expected_tile.is_cached, result_tile.is_cached);
ShadowSamplingTile expected_sampling_tile = shadow_sampling_tile_unpack(value);
ShadowSamplingTile result_sampling_tile = shadow_sampling_tile_unpack(
shadow_sampling_tile_pack(expected_sampling_tile));
EXPECT_EQ(expected_sampling_tile.page, result_sampling_tile.page);
EXPECT_EQ(expected_sampling_tile.lod, result_sampling_tile.lod);
EXPECT_EQ(expected_sampling_tile.lod_offset, result_sampling_tile.lod_offset);
EXPECT_EQ(expected_sampling_tile.is_valid, result_sampling_tile.is_valid);
}
}
DRAW_TEST(eevee_shadow_tile_packing)
static void test_eevee_shadow_tilemap_amend()
{
GPU_render_begin();
blender::Vector<uint32_t> tilemap_data(SHADOW_TILEMAP_RES * SHADOW_TILEMAP_RES *
SHADOW_TILEMAP_PER_ROW);
tilemap_data.fill(0);
auto pixel_get = [&](int x, int y, int tilemap_index) -> uint32_t & {
/* Note: assumes that tilemap_index is < SHADOW_TILEMAP_PER_ROW. */
return tilemap_data[y * SHADOW_TILEMAP_RES * SHADOW_TILEMAP_PER_ROW + x +
tilemap_index * SHADOW_TILEMAP_RES];
};
ShadowSamplingTile tile;
tile.lod = 0;
tile.lod_offset = uint2(0);
tile.is_valid = true;
tile.page = uint3(1, 0, 0);
pixel_get(16, 16, 2) = shadow_sampling_tile_pack(tile);
tile.page = uint3(2, 0, 0);
pixel_get(17, 16, 2) = shadow_sampling_tile_pack(tile);
tile.page = uint3(3, 0, 0);
pixel_get(20, 20, 1) = shadow_sampling_tile_pack(tile);
tile.page = uint3(4, 0, 0);
pixel_get(17, 16, 0) = shadow_sampling_tile_pack(tile);
Texture tilemap_tx = {"tilemap_tx"};
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_HOST_READ | GPU_TEXTURE_USAGE_SHADER_READ |
GPU_TEXTURE_USAGE_SHADER_WRITE;
int2 tilemap_res(SHADOW_TILEMAP_RES * SHADOW_TILEMAP_PER_ROW, SHADOW_TILEMAP_RES);
tilemap_tx.ensure_2d(GPU_R32UI, tilemap_res, usage);
GPU_texture_update_sub(
tilemap_tx, GPU_DATA_UINT, tilemap_data.data(), 0, 0, 0, tilemap_res.x, tilemap_res.y, 0);
/* Setup one directional light with 3 tilemaps. Fill only the needed data. */
LightData light;
light.type = LIGHT_SUN;
light.sun.clipmap_lod_min = 0;
light.sun.clipmap_lod_max = 2;
/* Shift LOD0 by 1 tile towards bottom. */
light.sun.clipmap_base_offset_neg = int2(0, 1 << 0);
/* Shift LOD1 by 1 tile towards right. */
light.sun.clipmap_base_offset_pos = int2(1 << 1, 0);
light.tilemap_index = 0;
LightDataBuf culling_light_buf = {"Lights_culled"};
culling_light_buf[0] = light;
culling_light_buf.push_update();
LightCullingDataBuf culling_data_buf = {"LightCull_data"};
culling_data_buf.local_lights_len = 0;
culling_data_buf.sun_lights_len = 1;
culling_data_buf.items_count = 1;
culling_data_buf.push_update();
/* Needed for validation. But not used since we use directionals. */
LightCullingZbinBuf culling_zbin_buf = {"LightCull_zbin"};
LightCullingTileBuf culling_tile_buf = {"LightCull_tile"};
GPUShader *sh = GPU_shader_create_from_info_name("eevee_shadow_tilemap_amend");
PassSimple pass("Test");
pass.shader_set(sh);
pass.bind_image("tilemaps_img", tilemap_tx);
pass.bind_ssbo(LIGHT_CULL_BUF_SLOT, culling_data_buf);
pass.bind_ssbo(LIGHT_BUF_SLOT, culling_light_buf);
pass.bind_ssbo(LIGHT_ZBIN_BUF_SLOT, culling_zbin_buf);
pass.bind_ssbo(LIGHT_TILE_BUF_SLOT, culling_tile_buf);
pass.dispatch(int3(1));
pass.barrier(GPU_BARRIER_TEXTURE_UPDATE);
Manager manager;
manager.submit(pass);
{
uint *pixels = tilemap_tx.read<uint32_t>(GPU_DATA_UINT);
auto stringify_tilemap = [&](int tilemap_index) -> std::string {
std::string result = "";
for (auto y : IndexRange(SHADOW_TILEMAP_RES)) {
for (auto x : IndexRange(SHADOW_TILEMAP_RES)) {
/* Note: assumes that tilemap_index is < SHADOW_TILEMAP_PER_ROW. */
int tile_ofs = y * SHADOW_TILEMAP_RES * SHADOW_TILEMAP_PER_ROW + x +
tilemap_index * SHADOW_TILEMAP_RES;
ShadowSamplingTile tile = shadow_sampling_tile_unpack(pixels[tile_ofs]);
result += std::to_string(tile.page.x + tile.page.y * SHADOW_PAGE_PER_ROW);
if (x + 1 == SHADOW_TILEMAP_RES / 2) {
result += " ";
}
}
result += "\n";
if (y + 1 == SHADOW_TILEMAP_RES / 2) {
result += "\n";
}
}
return result;
};
auto stringify_lod = [&](int tilemap_index) -> std::string {
std::string result = "";
for (auto y : IndexRange(SHADOW_TILEMAP_RES)) {
for (auto x : IndexRange(SHADOW_TILEMAP_RES)) {
/* Note: assumes that tilemap_index is < SHADOW_TILEMAP_PER_ROW. */
int tile_ofs = y * SHADOW_TILEMAP_RES * SHADOW_TILEMAP_PER_ROW + x +
tilemap_index * SHADOW_TILEMAP_RES;
ShadowSamplingTile tile = shadow_sampling_tile_unpack(pixels[tile_ofs]);
result += std::to_string(tile.lod);
if (x + 1 == SHADOW_TILEMAP_RES / 2) {
result += " ";
}
}
result += "\n";
if (y + 1 == SHADOW_TILEMAP_RES / 2) {
result += "\n";
}
}
return result;
};
auto stringify_offset = [&](int tilemap_index) -> std::string {
std::string result = "";
for (auto y : IndexRange(SHADOW_TILEMAP_RES)) {
for (auto x : IndexRange(SHADOW_TILEMAP_RES)) {
/* Note: assumes that tilemap_index is < SHADOW_TILEMAP_PER_ROW. */
int tile_ofs = y * SHADOW_TILEMAP_RES * SHADOW_TILEMAP_PER_ROW + x +
tilemap_index * SHADOW_TILEMAP_RES;
ShadowSamplingTile tile = shadow_sampling_tile_unpack(pixels[tile_ofs]);
result += std::to_string(tile.lod_offset.x + tile.lod_offset.y);
if (x + 1 == SHADOW_TILEMAP_RES / 2) {
result += " ";
}
}
result += "\n";
if (y + 1 == SHADOW_TILEMAP_RES / 2) {
result += "\n";
}
}
return result;
};
/** The layout of these expected strings is Y down. */
StringRefNull expected_pages_lod2 =
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"\n"
"0000000000000000 1200000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n";
StringRefNull expected_pages_lod1 =
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"\n"
"0000000000000001 1220000000000000\n"
"0000000000000001 1220000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000300000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n";
StringRefNull expected_pages_lod0 =
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"\n"
"0000000000000000 0400000000000000\n"
"0000000000000011 1122220000000000\n"
"0000000000000011 1122220000000000\n"
"0000000000000011 1122220000000000\n"
"0000000000000011 1122220000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000033000000\n"
"0000000000000000 0000000033000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n";
EXPECT_EQ(expected_pages_lod2, stringify_tilemap(2));
EXPECT_EQ(expected_pages_lod1, stringify_tilemap(1));
EXPECT_EQ(expected_pages_lod0, stringify_tilemap(0));
StringRefNull expected_lod_lod0 =
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"\n"
"0000000000000000 0000000000000000\n"
"0000000000000022 2222220000000000\n"
"0000000000000022 2222220000000000\n"
"0000000000000022 2222220000000000\n"
"0000000000000022 2222220000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000011000000\n"
"0000000000000000 0000000011000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n";
EXPECT_EQ(expected_lod_lod0, stringify_lod(0));
/* Offset for each axis are added together in this test. */
StringRefNull expected_offset_lod0 =
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"\n"
"0000000000000000 0000000000000000\n"
"0000000000000055 5555550000000000\n"
"0000000000000055 5555550000000000\n"
"0000000000000055 5555550000000000\n"
"0000000000000055 5555550000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000011000000\n"
"0000000000000000 0000000011000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n";
EXPECT_EQ(expected_offset_lod0, stringify_offset(0));
MEM_SAFE_FREE(pixels);
}
GPU_shader_free(sh);
DRW_shaders_free();
GPU_render_end();
}
DRAW_TEST(eevee_shadow_tilemap_amend)
static void test_eevee_shadow_page_mask_ex(int max_view_per_tilemap) static void test_eevee_shadow_page_mask_ex(int max_view_per_tilemap)
{ {
GPU_render_begin(); GPU_render_begin();

View File

@ -390,46 +390,44 @@ static void updateDuplicateSubtarget(EditBone *dup_bone,
*/ */
EditBone *oldtarget, *newtarget; EditBone *oldtarget, *newtarget;
bPoseChannel *pchan; bPoseChannel *pchan;
ListBase *conlist;
if ((pchan = BKE_pose_channel_ensure(ob->pose, dup_bone->name))) { if ((pchan = BKE_pose_channel_ensure(ob->pose, dup_bone->name))) {
if ((conlist = &pchan->constraints)) { ListBase *conlist = &pchan->constraints;
LISTBASE_FOREACH (bConstraint *, curcon, conlist) { LISTBASE_FOREACH (bConstraint *, curcon, conlist) {
/* does this constraint have a subtarget in /* does this constraint have a subtarget in
* this armature? * this armature?
*/ */
ListBase targets = {nullptr, nullptr}; ListBase targets = {nullptr, nullptr};
if (BKE_constraint_targets_get(curcon, &targets)) { if (BKE_constraint_targets_get(curcon, &targets)) {
LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) { LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
if ((ct->tar == ob) && (ct->subtarget[0])) { if ((ct->tar == ob) && (ct->subtarget[0])) {
oldtarget = get_named_editbone(editbones, ct->subtarget); oldtarget = get_named_editbone(editbones, ct->subtarget);
if (oldtarget) { if (oldtarget) {
/* was the subtarget bone duplicated too? If /* was the subtarget bone duplicated too? If
* so, update the constraint to point at the * so, update the constraint to point at the
* duplicate of the old subtarget. * duplicate of the old subtarget.
*/ */
if (oldtarget->temp.ebone) { if (oldtarget->temp.ebone) {
newtarget = oldtarget->temp.ebone; newtarget = oldtarget->temp.ebone;
STRNCPY(ct->subtarget, newtarget->name);
}
else if (lookup_mirror_subtarget) {
/* The subtarget was not selected for duplication, try to see if a mirror bone of
* the current target exists */
char name_flip[MAXBONENAME];
BLI_string_flip_side_name(name_flip, oldtarget->name, false, sizeof(name_flip));
newtarget = get_named_editbone(editbones, name_flip);
if (newtarget) {
STRNCPY(ct->subtarget, newtarget->name); STRNCPY(ct->subtarget, newtarget->name);
} }
else if (lookup_mirror_subtarget) {
/* The subtarget was not selected for duplication, try to see if a mirror bone of
* the current target exists */
char name_flip[MAXBONENAME];
BLI_string_flip_side_name(name_flip, oldtarget->name, false, sizeof(name_flip));
newtarget = get_named_editbone(editbones, name_flip);
if (newtarget) {
STRNCPY(ct->subtarget, newtarget->name);
}
}
} }
} }
} }
BKE_constraint_targets_flush(curcon, &targets, false);
} }
BKE_constraint_targets_flush(curcon, &targets, false);
} }
} }
} }

View File

@ -774,20 +774,6 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED; return OPERATOR_FINISHED;
} }
static int separate_armature_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
{
if (RNA_boolean_get(op->ptr, "confirm")) {
return WM_operator_confirm_ex(C,
op,
IFACE_("Move selected bones to a separate armature?"),
nullptr,
IFACE_("Separate"),
ALERT_ICON_NONE,
false);
}
return separate_armature_exec(C, op);
}
void ARMATURE_OT_separate(wmOperatorType *ot) void ARMATURE_OT_separate(wmOperatorType *ot)
{ {
/* identifiers */ /* identifiers */
@ -796,13 +782,11 @@ void ARMATURE_OT_separate(wmOperatorType *ot)
ot->description = "Isolate selected bones into a separate armature"; ot->description = "Isolate selected bones into a separate armature";
/* callbacks */ /* callbacks */
ot->invoke = separate_armature_invoke;
ot->exec = separate_armature_exec; ot->exec = separate_armature_exec;
ot->poll = ED_operator_editarmature; ot->poll = ED_operator_editarmature;
/* flags */ /* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_confirm_or_exec(ot);
} }
/** \} */ /** \} */

Some files were not shown because too many files have changed in this diff Show More