WIP: Brush assets project #106303

Draft
Julian Eisel wants to merge 351 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:
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.exit(1)

View File

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

View File

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

View File

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

View File

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

View File

@ -7,76 +7,82 @@
#define vector3 point
float safe_noise(float p)
float safe_noise(float co)
{
float f = noise("noise", p);
if (isinf(f)) {
return 0.5;
}
return f;
/* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
* representation issues. */
float p = fmod(co, 100000.0);
return noise("noise", p);
}
float safe_noise(vector2 p)
float safe_noise(vector2 co)
{
float f = noise("noise", p.x, p.y);
if (isinf(f)) {
return 0.5;
}
return f;
/* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0, however at such scales this
* usually shouldn't be noticeable. */
vector2 p = fmod(co, 100000.0);
return noise("noise", p.x, p.y);
}
float safe_noise(vector3 p)
float safe_noise(vector3 co)
{
float f = noise("noise", p);
if (isinf(f)) {
return 0.5;
}
return f;
/* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0, however at such scales this
* usually shouldn't be noticeable. */
vector3 p = fmod(co, 100000.0);
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);
if (isinf(f)) {
return 0.5;
}
return f;
/* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0, however at such scales this
* usually shouldn't be noticeable. */
vector4 p = fmod(co, 100000.0);
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);
if (isinf(f)) {
return 0.0;
}
return f;
/* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
* representation issues. */
float p = fmod(co, 100000.0);
return noise("snoise", p);
}
float safe_snoise(vector2 p)
float safe_snoise(vector2 co)
{
float f = noise("snoise", p.x, p.y);
if (isinf(f)) {
return 0.0;
}
return f;
/* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0, however at such scales this
* usually shouldn't be noticeable. */
vector2 p = fmod(co, 100000.0);
return noise("snoise", p.x, p.y);
}
float safe_snoise(vector3 p)
float safe_snoise(vector3 co)
{
float f = noise("snoise", p);
if (isinf(f)) {
return 0.0;
}
return f;
/* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0, however at such scales this
* usually shouldn't be noticeable. */
vector3 p = fmod(co, 100000.0);
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);
if (isinf(f)) {
return 0.0;
}
return f;
/* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
* representation issues. This causes discontinuities every 100000.0, however at such scales this
* usually shouldn't be noticeable. */
vector4 p = fmod(co, 100000.0);
return noise("snoise", vector3(p.x, p.y, p.z), p.w);
}
#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)
{
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)
@ -694,7 +699,12 @@ ccl_device_inline float noise_1d(float 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)
@ -704,7 +714,12 @@ ccl_device_inline float noise_2d(float2 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)
@ -714,7 +729,12 @@ ccl_device_inline float noise_3d(float3 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)

View File

@ -107,6 +107,7 @@ endif()
if(WITH_CYCLES_OSL)
list(APPEND LIB
cycles_kernel_osl
${OSL_LIBRARIES}
)
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);
}
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)
{
return make_float2(fabsf(a.x), fabsf(a.y));

View File

@ -309,6 +309,11 @@ ccl_device_inline float3 fabs(const float3 a)
# 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)
{
# ifdef __KERNEL_SSE__

View File

@ -465,6 +465,11 @@ ccl_device_inline float4 fabs(const float4 a)
# 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)
{
# ifdef __KERNEL_SSE__

View File

@ -210,7 +210,7 @@ rbCollisionShape *RB_shape_new_cylinder(float radius, float height);
/* Setup (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) ---------- */
@ -244,7 +244,7 @@ float RB_shape_get_margin(rbCollisionShape *shape);
void RB_shape_set_margin(rbCollisionShape *shape, float value);
void RB_shape_trimesh_update(rbCollisionShape *shape,
float *vertices,
const float *vertices,
int num_verts,
int vert_stride,
const float min[3],

View File

@ -712,7 +712,7 @@ rbCollisionShape *RB_shape_new_cylinder(float radius, float height)
/* Setup (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();
@ -800,7 +800,7 @@ rbCollisionShape *RB_shape_new_trimesh(rbMeshData *mesh)
}
void RB_shape_trimesh_update(rbCollisionShape *shape,
float *vertices,
const float *vertices,
int num_verts,
int vert_stride,
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,
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):
@ -96,12 +99,29 @@ class ImportHelper:
description="Filepath used for importing the file",
maxlen=1024,
subtype='FILE_PATH',
options={'SKIP_PRESET', 'HIDDEN'}
)
def invoke(self, context, _event):
context.window_manager.fileselect_add(self)
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):
return _check_axis_conversion(self)
@ -394,6 +414,19 @@ def unpack_face_list(list_of_tuples):
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(
name="Path Mode",
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),
("wm.context_toggle", {"type": 'H', "value": 'PRESS'},
{"properties": [("data_path", 'space_data.params.show_hidden')]}),
("file.directory_new", {"type": 'I', "value": 'PRESS'},
{"properties": [("confirm", False)]}),
("file.directory_new", {"type": 'I', "value": 'PRESS'}, None),
("file.rename", {"type": 'F2', "value": 'PRESS'}, None),
("file.delete", {"type": 'X', "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):
return (
"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_sculpt_box_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_lasso_mask(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),
("wm.context_toggle", {"type": 'H', "value": 'PRESS'},
{"properties": [("data_path", 'space_data.params.show_hidden')]}),
("file.directory_new", {"type": 'I', "value": 'PRESS'},
{"properties": [("confirm", False)]}),
("file.directory_new", {"type": 'I', "value": 'PRESS'}, None),
("file.rename", {"type": 'F2', "value": 'PRESS'}, None),
("file.delete", {"type": 'DEL', "value": 'PRESS'}, 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):
pin_armature = getattr(context, 'armature', None)
pin_armature = getattr(context, "armature", None)
if pin_armature:
return pin_armature
if context.object and context.object.type == 'ARMATURE':
return context.object.data
ob = context.object
if ob and ob.type == 'ARMATURE':
return ob.data
return None

View File

@ -270,8 +270,8 @@ class WM_OT_blend_strings_utf8_validate(Operator):
continue
if prop.type == 'STRING':
val_bytes = item.path_resolve(prop.identifier, False).as_bytes()
val_utf8 = val_bytes.decode('utf-8', 'replace')
val_bytes_valid = val_utf8.encode('utf-8')
val_utf8 = val_bytes.decode("utf-8", "replace")
val_bytes_valid = val_utf8.encode("utf-8")
if val_bytes_valid != val_bytes:
print("found bad utf8 encoded string %r, fixing to %r (%r)..."
"" % (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.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':
group.is_type_curve = True
elif ob_type == 'POINTCLOUD':
@ -56,7 +57,7 @@ def geometry_node_group_empty_tool_new(context):
else:
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'}:
group.is_mode_sculpt = True
elif mode == 'EDIT':

View File

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

View File

@ -31,10 +31,11 @@ class VIEW3D_OT_edit_mesh_extrude_individual_move(Operator):
def execute(self, context):
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'}
mesh = context.object.data
mesh = ob.data
select_mode = context.tool_settings.mesh_select_mode
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):
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'}
mesh = context.object.data
mesh = ob.data
totface = mesh.total_face_sel
totedge = mesh.total_edge_sel

View File

@ -3367,10 +3367,13 @@ class WM_MT_splash_about(Menu):
col.scale_y = 0.8
col.label(text=iface_("Version: %s") % bpy.app.version_string, translate=False)
col.separator(factor=2.5)
col.label(text=iface_("Date: %s %s") % (bpy.app.build_commit_date.decode('utf-8', 'replace'),
bpy.app.build_commit_time.decode('utf-8', 'replace')), 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)
col.label(text=iface_("Date: %s %s") % (
bpy.app.build_commit_date.decode("utf-8", "replace"),
bpy.app.build_commit_time.decode("utf-8", "replace")),
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
# 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):
layout = self.layout
grease_pencil = context.object.data
ob = context.object
grease_pencil = ob.data
space = context.space_data
if space.type == 'PROPERTIES':

View File

@ -417,20 +417,23 @@ class AnnotationDataPanel:
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, context):
if context.space_data.type not in {
space = context.space_data
if space.type not in {
'VIEW_3D',
'TOPBAR',
'SEQUENCE_EDITOR',
'IMAGE_EDITOR',
'NODE_EDITOR',
'PROPERTIES'}:
self.layout.prop(context.space_data, "show_annotation", text="")
'PROPERTIES',
}:
self.layout.prop(space, "show_annotation", text="")
def draw(self, context):
layout = self.layout
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.
gpd_owner = context.annotation_data_owner
@ -441,7 +444,7 @@ class AnnotationDataPanel:
col = layout.column()
col.label(text="Data Source:")
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
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":
layout.prop(gp_settings, "use_keep_caps_eraser")
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):

View File

@ -258,9 +258,9 @@ class ToolSelectPanelHelper:
# 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
# (_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])
# so if item is still a function (e.g._defs_XXX.generate_from_brushes)
# seems like we cannot expand here (have no context yet)

View File

@ -1423,6 +1423,21 @@ class _defs_sculpt:
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
def mask_border():
def draw_settings(_context, layout, tool):
@ -1862,6 +1877,15 @@ class _defs_paint_grease_pencil:
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:
@ -3162,7 +3186,8 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
),
(
_defs_sculpt.hide_border,
_defs_sculpt.hide_lasso
_defs_sculpt.hide_lasso,
_defs_sculpt.hide_line,
),
(
_defs_sculpt.face_set_box,
@ -3235,6 +3260,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
None,
_defs_paint_grease_pencil.draw,
_defs_paint_grease_pencil.erase,
_defs_paint_grease_pencil.tint,
],
'PAINT_GPENCIL': [
_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)
datablock_types = (
("use_duplicate_action", "Action", 'ACTION', ''),
("use_duplicate_armature", "Armature", 'OUTLINER_DATA_ARMATURE', ''),
("use_duplicate_camera", "Camera", 'OUTLINER_DATA_CAMERA', ''),
("use_duplicate_curve", "Curve", 'OUTLINER_DATA_CURVE', ''),
("use_duplicate_curves", "Curves", 'OUTLINER_DATA_CURVES', ''),
("use_duplicate_grease_pencil", "Grease Pencil", 'OUTLINER_OB_GREASEPENCIL', ''),
("use_duplicate_lattice", "Lattice", 'OUTLINER_DATA_LATTICE', ''),
("use_duplicate_action", "Action", 'ACTION', ""),
("use_duplicate_armature", "Armature", 'OUTLINER_DATA_ARMATURE', ""),
("use_duplicate_camera", "Camera", 'OUTLINER_DATA_CAMERA', ""),
("use_duplicate_curve", "Curve", 'OUTLINER_DATA_CURVE', ""),
("use_duplicate_curves", "Curves", 'OUTLINER_DATA_CURVES', ""),
("use_duplicate_grease_pencil", "Grease Pencil", 'OUTLINER_OB_GREASEPENCIL', ""),
("use_duplicate_lattice", "Lattice", 'OUTLINER_DATA_LATTICE', ""),
(None, None, None, None),
("use_duplicate_light", "Light", 'OUTLINER_DATA_LIGHT', ''),
("use_duplicate_lightprobe", "Light Probe", 'OUTLINER_DATA_LIGHTPROBE', ''),
("use_duplicate_material", "Material", 'MATERIAL_DATA', ''),
("use_duplicate_mesh", "Mesh", 'OUTLINER_DATA_MESH', ''),
("use_duplicate_metaball", "Metaball", 'OUTLINER_DATA_META', ''),
("use_duplicate_node_tree", "Node Tree", 'NODETREE', ''),
("use_duplicate_particle", "Particle", 'PARTICLES', ''),
("use_duplicate_light", "Light", 'OUTLINER_DATA_LIGHT', ""),
("use_duplicate_lightprobe", "Light Probe", 'OUTLINER_DATA_LIGHTPROBE', ""),
("use_duplicate_material", "Material", 'MATERIAL_DATA', ""),
("use_duplicate_mesh", "Mesh", 'OUTLINER_DATA_MESH', ""),
("use_duplicate_metaball", "Metaball", 'OUTLINER_DATA_META', ""),
("use_duplicate_node_tree", "Node Tree", 'NODETREE', ""),
("use_duplicate_particle", "Particle", 'PARTICLES', ""),
(None, None, None, None),
("use_duplicate_pointcloud", "Point Cloud", 'OUTLINER_DATA_POINTCLOUD', ''),
("use_duplicate_speaker", "Speaker", 'OUTLINER_DATA_SPEAKER', ''),
("use_duplicate_surface", "Surface", 'OUTLINER_DATA_SURFACE', ''),
("use_duplicate_text", "Text", 'OUTLINER_DATA_FONT', ''),
("use_duplicate_volume", "Volume", 'OUTLINER_DATA_VOLUME', 'i18n_contexts.id_id'),
("use_duplicate_pointcloud", "Point Cloud", 'OUTLINER_DATA_POINTCLOUD', ""),
("use_duplicate_speaker", "Speaker", 'OUTLINER_DATA_SPEAKER', ""),
("use_duplicate_surface", "Surface", 'OUTLINER_DATA_SURFACE', ""),
("use_duplicate_text", "Text", 'OUTLINER_DATA_FONT', ""),
("use_duplicate_volume", "Volume", 'OUTLINER_DATA_VOLUME', "i18n_contexts.id_id"),
)
col = flow.column()
@ -2727,7 +2727,7 @@ class USERPREF_PT_experimental_debugging(ExperimentalPanel, Panel):
# Class Registration
# 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 = (
USERPREF_PT_theme_user_interface,
*ThemeGenericClassGenerator.generate_panel_classes_for_wcols(),

View File

@ -139,17 +139,20 @@ class VIEW3D_HT_tool_header(Header):
return row, sub
if mode_string == 'EDIT_ARMATURE':
ob = context.object
_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':
ob = context.object
_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'}:
# Mesh Modes, Use Mesh Symmetry
ob = context.object
row, sub = row_for_mirror()
sub.prop(context.object, "use_mesh_mirror_x", text="X", toggle=True)
sub.prop(context.object, "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_x", text="X", toggle=True)
sub.prop(ob, "use_mesh_mirror_y", text="Y", toggle=True)
sub.prop(ob, "use_mesh_mirror_z", text="Z", toggle=True)
if mode_string == 'EDIT_MESH':
tool_settings = context.tool_settings
layout.prop(tool_settings, "use_mesh_automerge", text="")
@ -160,12 +163,13 @@ class VIEW3D_HT_tool_header(Header):
elif mode_string == 'PAINT_VERTEX':
row.popover(panel="VIEW3D_PT_tools_vertexpaint_symmetry_for_topbar", text="")
elif mode_string == 'SCULPT_CURVES':
ob = context.object
_row, sub = row_for_mirror()
sub.prop(context.object.data, "use_mirror_x", text="X", toggle=True)
sub.prop(context.object.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_x", text="X", toggle=True)
sub.prop(ob.data, "use_mirror_y", text="Y", 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.
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:
return False
ob = context.object
gp_settings = brush.gpencil_settings
row = layout.row(align=True)
settings = tool_settings.gpencil_paint
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 (
brush_basic__draw_color_selector,
)
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.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)
if grease_pencil_tool == 'TINT':
UnifiedPaintPanel.prop_unified_color(row, context, brush, "color", text="")
from bl_ui.properties_paint_common import (
brush_basic__draw_color_selector,
brush_basic_grease_pencil_paint_settings,
@ -2717,6 +2725,8 @@ class VIEW3D_MT_object(Menu):
def draw(self, context):
layout = self.layout
ob = context.object
layout.menu("VIEW3D_MT_transform_object")
layout.operator_menu_enum("object.origin_set", text="Set Origin", property="type")
layout.menu("VIEW3D_MT_mirror")
@ -2752,7 +2762,7 @@ class VIEW3D_MT_object(Menu):
layout.separator()
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_flat")
@ -3568,6 +3578,12 @@ class VIEW3D_MT_sculpt(Menu):
props = layout.operator("paint.hide_show_lasso_gesture", text="Lasso 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()
props = layout.operator("sculpt.face_set_change_visibility", text="Toggle Visibility")
@ -4078,9 +4094,10 @@ class VIEW3D_MT_bone_collections(Menu):
@classmethod
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
if context.object.data.library:
if ob.data.library:
return False
return True
@ -4534,7 +4551,8 @@ class VIEW3D_MT_edit_mesh_extrude(Menu):
tool_settings = context.tool_settings
select_mode = tool_settings.mesh_select_mode
mesh = context.object.data
ob = context.object
mesh = ob.data
if mesh.total_face_sel:
layout.operator("view3d.edit_mesh_extrude_move_normal", text="Extrude Faces")
@ -7728,13 +7746,16 @@ class VIEW3D_PT_overlay_gpencil_options(Panel):
@classmethod
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):
layout = self.layout
view = context.space_data
overlay = view.overlay
ob = context.object
layout.label(text={
'PAINT_GPENCIL': iface_("Draw 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, "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()
col = split.column()
col.prop(overlay, "use_gpencil_edit_lines", text="Edit Lines")
col = split.column()
col.prop(overlay, "use_gpencil_multiedit_line_only", text="Only in Multiframe")
if context.object.mode == 'EDIT_GPENCIL':
gpd = context.object.data
if ob.mode == 'EDIT_GPENCIL':
gpd = ob.data
split = layout.split()
col = split.column()
col.prop(overlay, "use_gpencil_show_directions")
@ -7788,10 +7809,10 @@ class VIEW3D_PT_overlay_gpencil_options(Panel):
# Handles for Curve Edit
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)
if context.object.mode in {'PAINT_GPENCIL', 'VERTEX_GPENCIL'}:
if ob.mode in {'PAINT_GPENCIL', 'VERTEX_GPENCIL'}:
layout.label(text="Vertex Paint")
row = layout.row()
shading = VIEW3D_PT_shading.get_shading(context)
@ -7807,20 +7828,23 @@ class VIEW3D_PT_overlay_grease_pencil_options(Panel):
@classmethod
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):
layout = self.layout
view = context.space_data
overlay = view.overlay
ob = context.object
layout.label(text={
'PAINT_GREASE_PENCIL': iface_("Draw Grease Pencil"),
'EDIT_GREASE_PENCIL': iface_("Edit Grease Pencil"),
'OBJECT': iface_("Grease Pencil"),
}[context.mode], translate=False)
if context.object.mode in {'EDIT'}:
if ob.mode in {'EDIT'}:
split = layout.split()
col = split.column()
col.prop(overlay, "use_gpencil_edit_lines", text="Edit Lines")
@ -8706,7 +8730,7 @@ class TOPBAR_PT_gpencil_materials(GreasePencilMaterialsPanel, Panel):
@classmethod
def poll(cls, context):
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):

View File

@ -610,7 +610,7 @@ class VIEW3D_PT_slots_paint_canvas(SelectPaintSlotHelper, View3DPanel, Panel):
def draw_header(self, context):
paint = context.tool_settings.paint_mode
ob = context.object
me = context.object.data
me = ob.data
mat = ob.active_material
label = iface_("Canvas")
@ -641,7 +641,8 @@ class VIEW3D_PT_slots_color_attributes(Panel):
)
def draw(self, context):
mesh = context.object.data
ob = context.object
mesh = ob.data
layout = self.layout
row = layout.row()
@ -1119,7 +1120,9 @@ class VIEW3D_PT_sculpt_symmetry(Panel, View3DPaintPanel):
sculpt = context.tool_settings.sculpt
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_y", text="Y", 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
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):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
curves = context.object.data
ob = context.object
curves = ob.data
row = layout.row(align=True, heading="Mirror")
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
wpaint = tool_settings.weight_paint
mesh = context.object.data
ob = context.object
mesh = ob.data
layout.prop(mesh, "use_mirror_vertex_groups")
draw_vpaint_symmetry(layout, wpaint, context.object)
draw_vpaint_symmetry(layout, wpaint, ob)
row = layout.row()
row.active = mesh.use_mirror_vertex_groups
@ -1288,7 +1295,9 @@ class VIEW3D_PT_tools_vertexpaint_symmetry(Panel, View3DPaintPanel):
tool_settings = context.tool_settings
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):
@ -1353,7 +1362,8 @@ class VIEW3D_PT_tools_imagepaint_symmetry(Panel, View3DPaintPanel):
col = split.column()
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_y", text="Y", 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
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
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
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
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
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
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
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
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
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
if brush.gpencil_tool == 'TINT':

View File

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

View File

@ -18,13 +18,13 @@ namespace blender::bke {
struct EditMeshData {
/** when set, \a vertexNos, faceNos are lazy initialized */
Array<float3> vertexCos;
Array<float3> vert_positions;
/** lazy initialize (when \a vertexCos is set) */
Array<float3> vertexNos;
Array<float3> faceNos;
/** also lazy init but don't depend on \a vertexCos */
Array<float3> faceCos;
/** lazy initialize (when \a vert_positions is set) */
Array<float3> vert_normals;
Array<float3> face_normals;
/** also lazy init but don't depend on \a vert_positions */
Array<float3> face_centers;
};
} // 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_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 */
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,
const blender::Span<bool> sharp_faces,
CustomData *loopdata,
const CustomData *loopdata,
bool calc_active_tangent,
const char (*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME],
int tangent_names_len,
@ -72,7 +72,7 @@ void BKE_mesh_calc_loop_tangents(Mesh *mesh_eval,
int tangent_names_len);
/* 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,
int numLoopData,
const char *layer_name);

View File

@ -24,7 +24,7 @@
struct BMEditMesh;
struct BVHCache;
struct Mesh;
struct ShrinkwrapBoundaryData;
class ShrinkwrapBoundaryData;
struct SubdivCCG;
struct SubsurfRuntimeData;
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.
* 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.
* 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);

View File

@ -200,8 +200,8 @@ struct ModifierTypeInfo {
/********************* Deform modifier functions *********************/
/**
* Apply a deformation to the positions in the \a vertexCos array. If the \a mesh argument is
* non-null, if will contain proper (not wrapped) mesh data. The \a vertexCos array may or may
* 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 positions array may or may
* not be the same as the mesh's position attribute.
*/
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_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_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_mat4(Object *ob, float r_mat[4][4]);
void BKE_object_to_mat3(const Object *ob, float r_mat[3][3]);
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
* supplied.
@ -319,7 +319,7 @@ blender::Vector<Base *> BKE_object_pose_base_array_get(const Scene *scene,
ViewLayer *view_layer,
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()`.
@ -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.
* 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? */
@ -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_editmesh_eval_final(const Object *object);
Mesh *BKE_object_get_editmesh_eval_cage(const Object *object);
const Mesh *BKE_object_get_editmesh_eval_final(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.
* 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. */
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);
/**

View File

@ -47,7 +47,15 @@ struct ShrinkwrapBoundaryVertData {
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. */
blender::BitVector<> edge_is_boundary;
/* 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
* 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
* 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,
const Object *ob,
ModifierData *md,
@ -1022,7 +1010,7 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final)
case ME_WRAPPER_TYPE_BMESH: {
BMEditMesh &em = *mesh_final->runtime->edit_mesh;
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_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) {
case ME_WRAPPER_TYPE_BMESH:
if (mesh->runtime->edit_data->vertexCos.is_empty()) {
mesh->runtime->edit_data->vertexCos = editbmesh_vert_coords_alloc(
mesh->runtime->edit_mesh);
if (mesh->runtime->edit_data->vert_positions.is_empty()) {
mesh->runtime->edit_data->vert_positions = BM_mesh_vert_coords_alloc(
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_SUBD:
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. */
if (reset || brush_prev == nullptr) {
BKE_paint_brush_set(vertexpaint, deft_vertex);
if ((reset == false) && (brush_prev != nullptr)) {
BKE_paint_brush_set(vertexpaint, brush_prev);
}
else {
if (brush_prev != nullptr) {
BKE_paint_brush_set(vertexpaint, brush_prev);
}
BKE_paint_brush_set(vertexpaint, deft_vertex);
}
}
@ -1603,13 +1601,11 @@ void BKE_brush_gpencil_sculpt_presets(Main *bmain, ToolSettings *ts, const bool
}
/* Set default brush. */
if (reset || brush_prev == nullptr) {
BKE_paint_brush_set(sculptpaint, deft_sculpt);
if ((reset == false) && (brush_prev != nullptr)) {
BKE_paint_brush_set(sculptpaint, brush_prev);
}
else {
if (brush_prev != nullptr) {
BKE_paint_brush_set(sculptpaint, brush_prev);
}
BKE_paint_brush_set(sculptpaint, deft_sculpt);
}
}
@ -1648,13 +1644,11 @@ void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts, const bool
}
/* Set default brush. */
if (reset || brush_prev == nullptr) {
BKE_paint_brush_set(weightpaint, deft_weight);
if ((reset == false) && (brush_prev != nullptr)) {
BKE_paint_brush_set(weightpaint, brush_prev);
}
else {
if (brush_prev != nullptr) {
BKE_paint_brush_set(weightpaint, brush_prev);
}
BKE_paint_brush_set(weightpaint, deft_weight);
}
}

View File

@ -1424,7 +1424,7 @@ bool data_transfer_layersmapping_vgroups(ListBase *r_map,
MDeformVert *data_dst = static_cast<MDeformVert *>(
CustomData_get_layer_for_write(cd_dst, CD_MDEFORMVERT, num_elem_dst));
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 *>(
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 */
struct PaintUVPoint {
/* Pixel / mesh data */
/** tri index on domain derived mesh */
/** Triangle index on domain evaluated mesh. */
uint tri_index;
uint pixel_index;
/* 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);
}
/* apply displacing vertex surface to the derived mesh */
/** Apply displacing vertex surface to the evaluated-mesh. */
static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Mesh *result)
{
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);
}
/*
* 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)
{
@ -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(
DynamicPaintModifierData *pmd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *mesh)
@ -2103,7 +2103,7 @@ static void dynamicPaint_frameUpdate(
DynamicPaintCanvasSettings *canvas = pmd->canvas;
DynamicPaintSurface *surface = static_cast<DynamicPaintSurface *>(canvas->surfaces.first);
/* update derived mesh copy */
/* update evaluated-mesh copy */
canvas_copyMesh(canvas, mesh);
/* in case image sequence baking, stop here */
@ -3855,7 +3855,8 @@ static void dynamicPaint_brushMeshCalculateVelocity(Depsgraph *depsgraph,
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) {
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;
for (index = 0; index < canvasNumOfVerts; index++) {
@ -6404,7 +6405,7 @@ int dynamicPaint_calculateFrame(
{
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) {
dynamicPaint_applySurfaceDisplace(surface, dynamicPaint_canvas_mesh_get(surface->canvas));
}

View File

@ -27,6 +27,10 @@
#include "DEG_depsgraph_query.hh"
using blender::Array;
using blender::float3;
using blender::Span;
BMEditMesh *BKE_editmesh_create(BMesh *bm)
{
BMEditMesh *em = MEM_new<BMEditMesh>(__func__);
@ -124,7 +128,7 @@ void BKE_editmesh_free_data(BMEditMesh *em)
struct CageUserData {
int totvert;
float (*cos_cage)[3];
blender::MutableSpan<float3> positions_cage;
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)) {
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(
Depsgraph *depsgraph, BMEditMesh *em, Scene *scene, Object *ob, int *r_vert_len))[3]
Array<float3> BKE_editmesh_vert_coords_alloc(Depsgraph *depsgraph,
BMEditMesh *em,
Scene *scene,
Object *ob)
{
Mesh *cage = editbmesh_get_eval_cage(depsgraph, scene, ob, em, &CD_MASK_BAREMESH);
float(*cos_cage)[3] = static_cast<float(*)[3]>(
MEM_callocN(sizeof(*cos_cage) * em->bm->totvert, __func__));
Array<float3> positions_cage(em->bm->totvert);
/* 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. */
@ -154,38 +159,29 @@ float (*BKE_editmesh_vert_coords_alloc(
CageUserData data;
data.totvert = em->bm->totvert;
data.cos_cage = cos_cage;
data.positions_cage = positions_cage;
data.visit_bitmap = visit_bitmap;
BKE_mesh_foreach_mapped_vert(cage, cage_mapped_verts_callback, &data, MESH_FOREACH_NOP);
MEM_freeN(visit_bitmap);
if (r_vert_len) {
*r_vert_len = em->bm->totvert;
}
return cos_cage;
return positions_cage;
}
const float (*BKE_editmesh_vert_coords_when_deformed(Depsgraph *depsgraph,
BMEditMesh *em,
Scene *scene,
Object *ob,
int *r_vert_len,
bool *r_is_alloc))[3]
Span<float3> BKE_editmesh_vert_coords_when_deformed(
Depsgraph *depsgraph, BMEditMesh *em, Scene *scene, Object *ob, Array<float3> &r_alloc)
{
const float(*coords)[3] = nullptr;
*r_is_alloc = false;
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object_eval);
Mesh *mesh_cage = BKE_object_get_editmesh_eval_cage(ob);
const Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object_eval);
const Mesh *mesh_cage = BKE_object_get_editmesh_eval_cage(ob);
Span<float3> vert_positions;
if (mesh_cage && mesh_cage->runtime->deformed_only) {
BLI_assert(BKE_mesh_wrapper_vert_len(mesh_cage) == em->bm->totvert);
/* 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) &&
(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 {
/* Constructive modifiers have been used, we need to allocate coordinates. */
*r_is_alloc = true;
coords = BKE_editmesh_vert_coords_alloc(depsgraph, em, scene, ob, r_vert_len);
r_alloc = BKE_editmesh_vert_coords_alloc(depsgraph, em, scene, ob);
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)

View File

@ -23,12 +23,12 @@
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;
}
BMesh *bm = em.bm;
emd.faceNos.reinitialize(bm->totface);
emd.face_normals.reinitialize(bm->totface);
BM_mesh_elem_index_ensure(bm, BM_VERT);
BMFace *efa;
@ -36,15 +36,17 @@ void BKE_editmesh_cache_ensure_face_normals(BMEditMesh &em, blender::bke::EditMe
int i;
BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
BM_elem_index_set(efa, i); /* set_inline */
BM_face_calc_normal_vcos(
bm, efa, emd.faceNos[i], reinterpret_cast<const float(*)[3]>(emd.vertexCos.data()));
BM_face_calc_normal_vcos(bm,
efa,
emd.face_normals[i],
reinterpret_cast<const float(*)[3]>(emd.vert_positions.data()));
}
bm->elem_index_dirty &= ~BM_FACE;
}
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;
}
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. */
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_verts_calc_normal_vcos(bm,
reinterpret_cast<const float(*)[3]>(emd.faceNos.data()),
reinterpret_cast<const float(*)[3]>(emd.vertexCos.data()),
reinterpret_cast<float(*)[3]>(emd.vertexNos.data()));
reinterpret_cast<const float(*)[3]>(emd.face_normals.data()),
reinterpret_cast<const float(*)[3]>(emd.vert_positions.data()),
reinterpret_cast<float(*)[3]>(emd.vert_normals.data()));
}
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;
}
BMesh *bm = em.bm;
emd.faceCos.reinitialize(bm->totface);
emd.face_centers.reinitialize(bm->totface);
BMFace *efa;
BMIter fiter;
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_face_calc_center_median(efa, emd.faceCos[i]);
BM_face_calc_center_median(efa, emd.face_centers[i]);
}
}
else {
BM_mesh_elem_index_ensure(bm, BM_VERT);
BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
BM_face_calc_center_median_vcos(
bm, efa, emd.faceCos[i], reinterpret_cast<const float(*)[3]>(emd.vertexCos.data()));
BM_face_calc_center_median_vcos(bm, efa, emd.face_centers[i], emd.vert_positions);
}
}
}
@ -102,7 +103,7 @@ std::optional<blender::Bounds<blender::float3>> BKE_editmesh_cache_calc_minmax(
return std::nullopt;
}
if (emd.vertexCos.is_empty()) {
if (emd.vert_positions.is_empty()) {
BMVert *eve;
BMIter iter;
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::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;
}
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. */
if (ob->type == OB_MESH && ob->mode == OB_MODE_EDIT) {
Mesh *mesh = static_cast<Mesh *>(ob->data);
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
const Mesh *mesh = static_cast<const Mesh *>(ob->data);
const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
if (mesh->runtime->edit_mesh && editmesh_eval_final) {
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));
ID *data = get_evaluated_object_data_with_materials(ob);
const short *tot_slots_data_ptr = BKE_id_material_len_p(data);
const ID *data = get_evaluated_object_data_with_materials(ob);
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;
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 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_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);
}
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,
* 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) {
BKE_mesh_wrapper_ensure_mdata(mesh);
BKE_mesh_wrapper_ensure_mdata(const_cast<Mesh *>(mesh));
}
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(
@ -828,12 +828,11 @@ static Mesh *mesh_new_from_mesh_object(Depsgraph *depsgraph,
if (preserve_all_data_layers || 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
* viewport is using for visualization. */
if (mesh_input->runtime->edit_mesh != nullptr) {
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object);
if (editmesh_eval_final != nullptr) {
if (const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object)) {
mesh_input = editmesh_eval_final;
}
}

View File

@ -41,12 +41,12 @@ void BKE_mesh_foreach_mapped_vert(
BMIter iter;
BMVert *eve;
int i;
if (!mesh->runtime->edit_data->vertexCos.is_empty()) {
const blender::Span<blender::float3> positions = mesh->runtime->edit_data->vertexCos;
if (!mesh->runtime->edit_data->vert_positions.is_empty()) {
const blender::Span<blender::float3> positions = mesh->runtime->edit_data->vert_positions;
blender::Span<blender::float3> vert_normals;
if (flag & MESH_FOREACH_USE_NORMAL) {
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) {
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;
BMEdge *eed;
int i;
if (!mesh->runtime->edit_data->vertexCos.is_empty()) {
const blender::Span<blender::float3> positions = mesh->runtime->edit_data->vertexCos;
if (!mesh->runtime->edit_data->vert_positions.is_empty()) {
const blender::Span<blender::float3> positions = mesh->runtime->edit_data->vert_positions;
BM_mesh_elem_index_ensure(bm, BM_VERT);
BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
func(user_data,
@ -159,7 +159,7 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
BMIter iter;
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. */
blender::Span<blender::float3> corner_normals;
@ -243,11 +243,11 @@ void BKE_mesh_foreach_mapped_face_center(
int i;
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) {
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()) {

View File

@ -297,7 +297,7 @@ static void DM_calc_loop_tangents_thread(TaskPool *__restrict /*pool*/, void *ta
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,
int numLoopData,
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 blender::Span<bool> sharp_faces,
CustomData *loopdata,
const CustomData *loopdata,
bool calc_active_tangent,
const char (*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME],
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) {
int tan_index = CustomData_get_named_layer_index(
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 */
/* 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) {
int tan_index = CustomData_get_named_layer_index(
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 */
}
}

View File

@ -124,8 +124,8 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *mesh)
BKE_mesh_ensure_default_orig_index_customdata_no_check(mesh);
blender::bke::EditMeshData &edit_data = *mesh->runtime->edit_data;
if (!edit_data.vertexCos.is_empty()) {
mesh->vert_positions_for_write().copy_from(edit_data.vertexCos);
if (!edit_data.vert_positions.is_empty()) {
mesh->vert_positions_for_write().copy_from(edit_data.vert_positions);
mesh->runtime->is_original_bmesh = false;
}
@ -148,35 +148,31 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *mesh)
/** \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) {
case ME_WRAPPER_TYPE_BMESH:
if (mesh->runtime->edit_data->vertexCos.is_empty()) {
return nullptr;
}
return reinterpret_cast<const float(*)[3]>(mesh->runtime->edit_data->vertexCos.data());
return mesh->runtime->edit_data->vert_positions;
case ME_WRAPPER_TYPE_MDATA:
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) {
case ME_WRAPPER_TYPE_BMESH:
BKE_editmesh_cache_ensure_face_normals(*mesh->runtime->edit_mesh, *mesh->runtime->edit_data);
if (mesh->runtime->edit_data->faceNos.is_empty()) {
return nullptr;
}
return reinterpret_cast<const float(*)[3]>(mesh->runtime->edit_data->faceNos.data());
return mesh->runtime->edit_data->face_normals;
case ME_WRAPPER_TYPE_MDATA:
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)
@ -184,9 +180,9 @@ void BKE_mesh_wrapper_tag_positions_changed(Mesh *mesh)
switch (mesh->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH:
if (mesh->runtime->edit_data) {
mesh->runtime->edit_data->vertexNos = {};
mesh->runtime->edit_data->faceCos = {};
mesh->runtime->edit_data->faceNos = {};
mesh->runtime->edit_data->vert_normals = {};
mesh->runtime->edit_data->face_centers = {};
mesh->runtime->edit_data->face_normals = {};
}
break;
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: {
BMesh *bm = mesh->runtime->edit_mesh->bm;
const blender::bke::EditMeshData &edit_data = *mesh->runtime->edit_data;
if (!edit_data.vertexCos.is_empty()) {
positions.copy_from(edit_data.vertexCos);
if (!edit_data.vert_positions.is_empty()) {
positions.copy_from(edit_data.vert_positions);
}
else {
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;
BLI_assert(vert_coords_len == bm->totvert);
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++) {
mul_v3_m4v3(vert_coords[i], mat, edit_data.vertexCos[i]);
mul_v3_m4v3(vert_coords[i], mat, edit_data.vert_positions[i]);
}
}
else {

View File

@ -879,7 +879,7 @@ static void modwrap_dependsOnNormals(Mesh *mesh)
switch (mesh->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH: {
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.
* If that changes we'll need to recalculate. */
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)) {
/* 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. */
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) {

View File

@ -2764,7 +2764,7 @@ void BKE_object_obdata_size_init(Object *ob, const float size)
/** \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;
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
}
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 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);
}
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];
@ -2987,7 +2987,7 @@ void BKE_object_matrix_local_get(Object *ob, float r_mat[4][4])
/**
* \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;
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;
}
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;
@ -3056,7 +3056,7 @@ static void ob_parbone(Object *ob, Object *par, float r_mat[4][4])
}
/* 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) {
CLOG_WARN(
&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);
if (par->type == OB_MESH) {
Mesh *mesh = (Mesh *)par->data;
BMEditMesh *em = mesh->runtime->edit_mesh;
Mesh *mesh_eval = (em) ? BKE_object_get_editmesh_eval_final(par) :
BKE_object_get_evaluated_mesh(par);
const Mesh *mesh = (const Mesh *)par->data;
const BMEditMesh *em = mesh->runtime->edit_mesh;
const Mesh *mesh_eval = (em) ? BKE_object_get_editmesh_eval_final(par) :
BKE_object_get_evaluated_mesh(par);
if (mesh_eval) {
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 (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 {
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 */
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 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
* (without its own matrix applied)
*/
static void solve_parenting(
Object *ob, Object *par, const bool set_origin, float r_obmat[4][4], float r_originmat[3][3])
static void solve_parenting(const Object *ob,
Object *par,
const bool set_origin,
float r_obmat[4][4],
float r_originmat[3][3])
{
float totmat[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);
}
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) {
Object *par = ob->parent;
@ -4202,7 +4205,7 @@ Mesh *BKE_object_get_original_mesh(const Object *object)
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(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);
}
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(object->type == OB_MESH);
@ -4229,6 +4232,13 @@ Mesh *BKE_object_get_editmesh_eval_cage(const Object *object)
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)
{
ID *data = (ID *)object->data;
@ -4806,7 +4816,7 @@ int BKE_object_scenes_users_get(Main *bmain, Object *ob)
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;
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;
uint i;
Mesh *mesh_eval = ob->runtime->mesh_deform_eval ? ob->runtime->mesh_deform_eval :
BKE_object_get_evaluated_mesh(ob);
const Mesh *mesh_eval = BKE_object_get_mesh_deform_eval(ob) ?
BKE_object_get_mesh_deform_eval(ob) :
BKE_object_get_evaluated_mesh(ob);
const int *index;
if (mesh_eval &&

View File

@ -472,11 +472,11 @@ static const Mesh *mesh_data_from_duplicator_object(Object *ob,
*r_em = em;
mesh_eval = nullptr;
if ((emd != nullptr) && !emd->vertexCos.is_empty()) {
*r_vert_coords = reinterpret_cast<const float(*)[3]>(emd->vertexCos.data());
if ((emd != nullptr) && !emd->vert_positions.is_empty()) {
*r_vert_coords = reinterpret_cast<const float(*)[3]>(emd->vert_positions.data());
if (r_vert_normals != nullptr) {
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);
Sculpt *sd = scene->toolsettings->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);
MultiresModifierData *mmd = sculpt_multires_modifier_get(scene, ob, true);
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->totvert = mesh_eval->verts_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
* and tools use the Face Sets data from the base mesh when Multires is active. */
ss->vert_positions = mesh->vert_positions_for_write();
ss->faces = mesh->faces();
ss->corner_verts = mesh->corner_verts();
ss->vert_positions = mesh_orig->vert_positions_for_write();
ss->faces = mesh_orig->faces();
ss->corner_verts = mesh_orig->corner_verts();
}
else {
ss->totvert = mesh->verts_num;
ss->faces_num = mesh->faces_num;
ss->totfaces = mesh->faces_num;
ss->vert_positions = mesh->vert_positions_for_write();
ss->faces = mesh->faces();
ss->corner_verts = mesh->corner_verts();
ss->totvert = mesh_orig->verts_num;
ss->faces_num = mesh_orig->faces_num;
ss->totfaces = mesh_orig->faces_num;
ss->vert_positions = mesh_orig->vert_positions_for_write();
ss->faces = mesh_orig->faces();
ss->corner_verts = mesh_orig->corner_verts();
ss->multires.active = false;
ss->multires.modifier = nullptr;
ss->multires.level = 0;
CustomDataLayer *layer;
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) {
ss->vcol = static_cast<MPropCol *>(layer->data);
}
@ -1830,13 +1830,14 @@ static void sculpt_update_object(Depsgraph *depsgraph,
/* Sculpt Face Sets. */
if (use_face_sets) {
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 {
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();
@ -1850,7 +1851,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
sculpt_update_persistent_base(ob);
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) {
@ -1862,7 +1863,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
bool used_me_eval = false;
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.
* 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);
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();
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) ?
Span(static_cast<const float3 *>(ss->shapekey_active->data),
mesh->verts_num) :
mesh->vert_positions();
mesh_orig->verts_num) :
mesh_orig->vert_positions();
BKE_crazyspace_build_sculpt(depsgraph, scene, ob, ss->deform_imats, 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()) {
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 (ss->shapekey_active) {
bool pbvh_deformed = BKE_pbvh_is_deformed(ss->pbvh);
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 (!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);
}
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);
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());
}
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);
}
}

View File

@ -44,7 +44,6 @@
#include "BKE_mesh.hh"
#include "BKE_mesh_runtime.hh"
#include "BKE_object.hh"
#include "BKE_object_types.hh"
#include "BKE_pointcache.h"
#include "BKE_report.hh"
#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 */
/* 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);
switch (ob->rigidbody_object->mesh_source) {
case RBO_MESH_DEFORM:
return ob->runtime->mesh_deform_eval;
return BKE_object_get_mesh_deform_eval(ob);
case RBO_MESH_FINAL:
return BKE_object_get_evaluated_mesh(ob);
case RBO_MESH_BASE:
@ -366,13 +365,13 @@ static rbCollisionShape *rigidbody_get_shape_convexhull_from_mesh(Object *ob,
bool *can_embed)
{
rbCollisionShape *shape = nullptr;
Mesh *mesh = nullptr;
float(*positions)[3] = nullptr;
const Mesh *mesh = nullptr;
const float(*positions)[3] = nullptr;
int totvert = 0;
if (ob->type == OB_MESH && ob->data) {
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;
totvert = (mesh) ? mesh->verts_num : 0;
}
@ -399,7 +398,7 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
rbCollisionShape *shape = nullptr;
if (ob->type == OB_MESH) {
Mesh *mesh = rigidbody_get_mesh(ob);
const Mesh *mesh = rigidbody_get_mesh(ob);
if (mesh == nullptr) {
return nullptr;
}
@ -668,7 +667,7 @@ void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
case RB_SHAPE_CONVEXH:
case RB_SHAPE_TRIMESH: {
if (ob->type == OB_MESH) {
Mesh *mesh = rigidbody_get_mesh(ob);
const Mesh *mesh = rigidbody_get_mesh(ob);
if (mesh == nullptr) {
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_TRIMESH: {
if (ob->type == OB_MESH) {
Mesh *mesh = rigidbody_get_mesh(ob);
const Mesh *mesh = rigidbody_get_mesh(ob);
if (mesh == nullptr) {
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;
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) {
float(*positions)[3] = reinterpret_cast<float(*)[3]>(
mesh->vert_positions_for_write().data());
const float(*positions)[3] = reinterpret_cast<const float(*)[3]>(
mesh->vert_positions().data());
int totvert = mesh->verts_num;
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);
}
/* 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 int3 edges = bke::mesh::corner_tri_get_real_edges(
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"));
}
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);
/* 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)
{
/* 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;
}
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;
}
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;
}
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;
}

View File

@ -22,6 +22,10 @@
#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_chunksize_default = {512, 1024, 2048, 512};
@ -1328,23 +1332,21 @@ void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags)
/** \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;
BMVert *v;
int 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]>(
MEM_mallocN(bm->totvert * sizeof(*vert_coords), __func__));
BM_mesh_vert_coords_get(bm, vert_coords);
*r_vert_len = bm->totvert;
return vert_coords;
Array<float3> positions(bm->totvert);
BM_mesh_vert_coords_get(bm, positions);
return positions;
}
void BM_mesh_vert_coords_apply(BMesh *bm, const float (*vert_coords)[3])

View File

@ -8,6 +8,10 @@
* \ingroup bmesh
*/
#include "BLI_array.hh"
#include "BLI_math_vector_types.hh"
#include "BLI_span.hh"
#include "bmesh_class.hh"
struct BMAllocTemplate;
@ -197,8 +201,8 @@ extern const BMAllocTemplate bm_mesh_chunksize_default;
VA_NARGS_CALL_OVERLOAD(_VA_BMALLOC_TEMPLATE_FROM_ME_, __VA_ARGS__)
/* Vertex coords access. */
void BM_mesh_vert_coords_get(BMesh *bm, float (*vert_coords)[3]);
float (*BM_mesh_vert_coords_alloc(BMesh *bm, int *r_vert_len))[3];
void BM_mesh_vert_coords_get(BMesh *bm, blender::MutableSpan<blender::float3> positions);
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_with_mat4(BMesh *bm,
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)
*/
static void bm_face_calc_poly_center_median_vertex_cos(const BMFace *f,
float r_cent[3],
float const (*vertexCos)[3])
static void bm_face_calc_poly_center_median_vertex_cos(
const BMFace *f, float r_cent[3], const blender::Span<blender::float3> vert_positions)
{
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 */
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
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);
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,
const BMFace *f,
float r_cent[3],
float const (*vertexCos)[3])
const blender::Span<blender::float3> vert_positions)
{
/* must have valid index data */
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);
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);
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,
const BMFace *f,
float r_cent[3],
float const (*vertexCos)[3])
const blender::Span<blender::float3> vert_positions)
{
/* must have valid index data */
BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
(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,

View File

@ -11,6 +11,8 @@
struct Heap;
#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.
@ -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,
const BMFace *f,
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
*/
@ -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,
const BMFace *f,
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
* 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_volume_comp.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_finalize_comp.glsl
engines/eevee_next/shaders/eevee_shadow_tilemap_init_comp.glsl

View File

@ -87,6 +87,8 @@
#define SHADOW_TILEDATA_PER_TILEMAP \
(SHADOW_TILEMAP_LOD0_LEN + SHADOW_TILEMAP_LOD1_LEN + SHADOW_TILEMAP_LOD2_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
/* Useful for debugging the tile-copy version of the shadow rendering without making debugging
* tools unresponsive. */

View File

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

View File

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

View File

@ -1231,8 +1231,6 @@ struct ShadowTileData {
uint3 page;
/** Page index inside pages_cached_buf. Only valid if `is_cached` is true. */
uint cache_index;
/** LOD pointed to LOD 0 tile page. (cube-map only). */
uint lod;
/** If the tile is needed for rendering. */
bool is_used;
/** 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;
tile.page = shadow_page_unpack(data);
/* -- 12 bits -- */
BLI_STATIC_ASSERT(SHADOW_TILEMAP_LOD < 8, "Update page packing")
tile.lod = (data >> 12u) & 7u;
/* Unused bits. */
/* -- 15 bits -- */
BLI_STATIC_ASSERT(SHADOW_MAX_PAGE <= 4096, "Update page packing")
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.
* So we have to mask the result. */
data = shadow_page_pack(tile.page) & uint(SHADOW_MAX_PAGE - 1);
data |= (tile.lod & 7u) << 12u;
data |= (tile.cache_index & 4095u) << 15u;
data |= (tile.is_used ? uint(SHADOW_IS_USED) : 0);
data |= (tile.is_allocated ? uint(SHADOW_IS_ALLOCATED) : 0);
@ -1309,6 +1305,89 @@ static inline ShadowTileDataPacked shadow_tile_pack(ShadowTileData tile)
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 {
/* Number of shadow rays to shoot for each light. */
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 |
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
* 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
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.cache_index);
#endif
@ -41,10 +40,6 @@ void debug_tile_print(ShadowTileData tile, ivec4 tile_coord)
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) {
/* Updated. */
return vec3(0.5, 1, 0);
@ -63,6 +58,17 @@ vec3 debug_tile_state_color(ShadowTileData tile)
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)
{
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));
}
@ -106,6 +112,26 @@ bool debug_tilemaps(vec3 P, LightData light)
int tilemap = px.x / SHADOW_TILEMAP_RES;
int tilemap_index = light.tilemap_index + tilemap;
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. */
ShadowTileMapData tilemap = tilemaps_buf[tilemap_index];
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_mul = vec4(0.0);
#ifdef DRW_DEBUG_PRINT
# ifdef DRW_DEBUG_PRINT
if (all(equal(ivec2(gl_FragCoord.xy), ivec2(0)))) {
drw_print(light.object_mat);
}
#endif
# endif
return true;
}
#endif
}
return false;
}
void debug_tile_state(vec3 P, LightData light)
{
ShadowTileData tile = debug_tile_get(P, light);
out_color_add = vec4(debug_tile_state_color(tile), 0) * 0.5;
ShadowSamplingTile tile = debug_tile_get(P, light);
out_color_add = vec4(debug_tile_state_color(light.type, tile), 0) * 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)
{
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_mul = vec4(0.5);
}

View File

@ -21,7 +21,7 @@ struct ShadowSampleParams {
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. */
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;
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;
}

View File

@ -26,7 +26,6 @@ void main()
ShadowTileData tile = shadow_tile_unpack(tiles_buf[tile_index]);
if (tile.is_used && !tile.is_allocated) {
shadow_page_alloc(tile);
tile.lod = lod;
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);
int lod_max = is_cubemap ? SHADOW_TILEMAP_LOD : 0;
int valid_tile_index = -1;
uint valid_lod = 0u;
/* 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.
* 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)) {
/* Save highest lod for this thread. */
valid_tile_index = tile_index;
valid_lod = uint(lod);
}
}
/* Store the highest LOD valid page for rendering. */
uint tile_packed = (valid_tile_index != -1) ? tiles_buf[valid_tile_index] : SHADOW_NO_DATA;
imageStore(tilemaps_img, atlas_texel, uvec4(tile_packed));
ShadowTileDataPacked tile_packed = (valid_tile_index != -1) ? tiles_buf[valid_tile_index] :
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)))) {
/* 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. */
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.
* Can be disabled to check if the clip-map is well centered. */
tile_co = clamp(tile_co, ivec2(0), ivec2(SHADOW_TILEMAP_RES - 1));
uint tile_data =
texelFetch(tilemaps_tx, shadow_tile_coord_in_atlas(tile_co, tilemap_index), 0).x;
return shadow_tile_unpack(tile_data);
ivec2 texel = shadow_tile_coord_in_atlas(tile_co, tilemap_index);
uint tile_data = texelFetch(tilemaps_tx, texel, 0).x;
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));
/* Using bitwise ops is way faster than integer ops. */
const int page_shift = SHADOW_PAGE_LOD;
const int page_mask = ~(0xFFFFFFFF << SHADOW_PAGE_LOD);
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;
}
int page_mask = ~(0xFFFFFFFF << (SHADOW_PAGE_LOD + int(tile.lod)));
ivec2 texel_page = (texel_coord & page_mask) >> int(tile.lod);
/* Shift LOD0 pixels so that they get wrapped at the right position for the given LOD. */
/* TODO convert everything to uint to avoid signed int operations. */
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);
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 {
params = shadow_punctual_sample_params_get(light, P);
}
ShadowTileData tile = shadow_tile_data_get(shadow_tilemaps_tx, params);
if (!tile.is_allocated) {
ShadowSamplingTile tile = shadow_tile_data_get(shadow_tilemaps_tx, params);
if (!tile.is_valid) {
return vec3(0.0);
}

View File

@ -195,6 +195,13 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tilemap_finalize)
.additional_info("eevee_shared")
.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. */
GPU_SHADER_CREATE_INFO(eevee_shadow_page_clear)
.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. */
Mesh *mesh = (Mesh *)ob->data;
if (BMEditMesh *em = mesh->runtime->edit_mesh) {
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_final = BKE_object_get_editmesh_eval_final(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_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;
if (is_mesh) {
/* 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) {
BLI_assert(mesh->runtime->edit_mesh);
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_final = BKE_object_get_editmesh_eval_final(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);
if (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)
{
if (mesh->runtime->edit_mesh != nullptr) {
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object);
if (editmesh_eval_final != nullptr) {
if (const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object)) {
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(*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_normals = reinterpret_cast<const float(*)[3]>(mr.bm_vert_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;
if (is_editmode) {
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_final = BKE_object_get_editmesh_eval_final(object);
const Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(object);
BLI_assert(editmesh_eval_cage && editmesh_eval_final);
mr->bm = mesh->runtime->edit_mesh->bm;
@ -573,15 +572,14 @@ MeshRenderData *mesh_render_data_create(Object *object,
if (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_face_normals(*mr->edit_bmesh, *emd);
}
mr->bm_vert_coords = mr->edit_data->vertexCos;
mr->bm_vert_normals = mr->edit_data->vertexNos;
mr->bm_face_normals = mr->edit_data->faceNos;
mr->bm_face_centers = mr->edit_data->faceCos;
mr->bm_vert_coords = mr->edit_data->vert_positions;
mr->bm_vert_normals = mr->edit_data->vert_normals;
mr->bm_face_normals = mr->edit_data->face_normals;
}
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. */
if (cache.cd_needed.orco != 0) {
/* 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) {
/* Skip orco calculation */
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;
if (is_editmode && is_mode_active) {
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_final = BKE_object_get_editmesh_eval_final(ob);
const Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob);
do_cage = editmesh_eval_final != editmesh_eval_cage;
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,
Mesh *mesh,
const Mesh *mesh,
uint32_t *flags_data)
{
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,
MeshRenderData &mr,
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,
Mesh *mesh,
const Mesh *mesh,
MeshRenderData &mr)
{
if (cache.extra_coarse_face_data == nullptr) {
@ -839,7 +839,7 @@ static DRWSubdivCache &mesh_batch_cache_ensure_subdiv_cache(MeshBatchCache &mbc)
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)) {
return;
@ -1167,7 +1167,7 @@ static void build_vertex_face_adjacency_maps(DRWSubdivCache &cache)
static bool draw_subdiv_build_cache(DRWSubdivCache &cache,
Subdiv *subdiv,
Mesh *mesh_eval,
const Mesh *mesh_eval,
const SubsurfRuntimeData *runtime_data)
{
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.
*/
static void draw_subdiv_cache_ensure_mat_offsets(DRWSubdivCache &cache,
Mesh *mesh_eval,
const Mesh *mesh_eval,
uint mat_len)
{
draw_subdiv_cache_free_material_data(cache);
@ -2108,7 +2108,7 @@ static bool draw_subdiv_create_requested_buffers(Object *ob,
return false;
}
Mesh *mesh_eval = mesh;
const Mesh *mesh_eval = mesh;
BMesh *bm = nullptr;
if (mesh->runtime->edit_mesh) {
mesh_eval = BKE_object_get_editmesh_eval_final(ob);

View File

@ -46,6 +46,9 @@
#include "draw_manager_text.hh"
#include "intern/bmesh_polygon.hh"
using blender::float3;
using blender::Span;
struct ViewCachedString {
float vec[3];
union {
@ -255,7 +258,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
*/
DRWTextStore *dt = DRW_text_cache_ensure();
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;
float v1[3], v2[3], v3[3], vmid[3], fvec[3];
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];
/* allow for displaying shape keys and deform mods */
BMIter iter;
const float(*vert_coords)[3] = BKE_mesh_wrapper_vert_coords(mesh);
const bool use_coords = (vert_coords != nullptr);
const Span<float3> vert_positions = BKE_mesh_wrapper_vert_coords(mesh);
const bool use_coords = !vert_positions.is_empty();
/* when 2 or more edge-info options are enabled, space apart */
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];
if (vert_coords) {
copy_v3_v3(v1, vert_coords[BM_elem_index_get(eed->v1)]);
copy_v3_v3(v2, vert_coords[BM_elem_index_get(eed->v2)]);
if (use_coords) {
copy_v3_v3(v1, vert_positions[BM_elem_index_get(eed->v1)]);
copy_v3_v3(v2, vert_positions[BM_elem_index_get(eed->v2)]);
}
else {
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);
const float(*face_normals)[3] = nullptr;
Span<float3> face_normals;
if (use_coords) {
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) {
@ -395,9 +400,9 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
{
float v1_clip[3], v2_clip[3];
if (vert_coords) {
copy_v3_v3(v1, vert_coords[BM_elem_index_get(eed->v1)]);
copy_v3_v3(v2, vert_coords[BM_elem_index_get(eed->v2)]);
if (use_coords) {
copy_v3_v3(v1, vert_positions[BM_elem_index_get(eed->v1)]);
copy_v3_v3(v2, vert_positions[BM_elem_index_get(eed->v2)]);
}
else {
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++) {
if (use_coords) {
copy_v3_v3(v1, vert_coords[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(v3, vert_coords[BM_elem_index_get(ltri_array[j][2]->v)]);
copy_v3_v3(v1, vert_positions[BM_elem_index_get(ltri_array[j][0]->v)]);
copy_v3_v3(v2, vert_positions[BM_elem_index_get(ltri_array[j][1]->v)]);
copy_v3_v3(v3, vert_positions[BM_elem_index_get(ltri_array[j][2]->v)]);
}
else {
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 */
if (is_first) {
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 {
BM_face_calc_center_bounds(efa, vmid);
@ -545,9 +550,9 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
is_first = false;
}
if (use_coords) {
copy_v3_v3(v1, vert_coords[BM_elem_index_get(loop->prev->v)]);
copy_v3_v3(v2, vert_coords[BM_elem_index_get(loop->v)]);
copy_v3_v3(v3, vert_coords[BM_elem_index_get(loop->next->v)]);
copy_v3_v3(v1, vert_positions[BM_elem_index_get(loop->prev->v)]);
copy_v3_v3(v2, vert_positions[BM_elem_index_get(loop->v)]);
copy_v3_v3(v3, vert_positions[BM_elem_index_get(loop->next->v)]);
}
else {
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) {
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
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 {
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];
if (use_coords) {
copy_v3_v3(v1, vert_coords[BM_elem_index_get(eed->v1)]);
copy_v3_v3(v2, vert_coords[BM_elem_index_get(eed->v2)]);
copy_v3_v3(v1, vert_positions[BM_elem_index_get(eed->v1)]);
copy_v3_v3(v2, vert_positions[BM_elem_index_get(eed->v2)]);
}
else {
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 (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 {
BM_face_calc_center_median(f, v1);

View File

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

View File

@ -197,7 +197,7 @@ static DRWShadingGroup *drw_volume_object_mesh_init(Scene *scene,
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);
}
@ -384,7 +384,7 @@ PassType *drw_volume_object_mesh_init(PassType &ps,
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);
}

View File

@ -80,7 +80,6 @@ struct MeshRenderData {
Span<float3> bm_vert_coords;
Span<float3> bm_vert_normals;
Span<float3> bm_face_normals;
Span<float3> bm_face_centers;
Array<float3> bm_loop_normals;
const int *v_origindex, *e_origindex, *p_origindex;
@ -90,7 +89,7 @@ struct MeshRenderData {
int freestyle_edge_ofs;
int freestyle_face_ofs;
/** Mesh */
Mesh *mesh;
const Mesh *mesh;
Span<float3> vert_positions;
Span<int2> edges;
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_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. */
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
* UV layer. */
CustomData *cd_ldata = (mr.extract_type == MR_EXTRACT_MESH) ? &mr.mesh->corner_data :
&mr.bm->ldata;
const CustomData *cd_ldata = (mr.extract_type == MR_EXTRACT_MESH) ? &mr.mesh->corner_data :
&mr.bm->ldata;
uint32_t uv_layers = cache.cd_used.uv;
/* 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_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);
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)),
GPU_vertbuf_get_vertex_len(vbo));
if (mr.extract_type == MR_EXTRACT_MESH) {
array_utils::gather(
mr.vert_positions, mr.corner_verts, vbo_data.take_front(mr.corner_verts.size()));
extract_mesh_loose_edge_positions(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()));
threading::memory_bandwidth_bound_task(
mr.vert_positions.size_in_bytes() + mr.corner_verts.size_in_bytes() +
vbo_data.size_in_bytes() + mr.loose_edges.size(),
[&]() {
array_utils::gather(
mr.vert_positions, mr.corner_verts, vbo_data.take_front(mr.corner_verts.size()));
extract_mesh_loose_edge_positions(
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 {
*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);
Mesh *coarse_mesh = mr.mesh;
const Mesh *coarse_mesh = mr.mesh;
/* First, interpolate mask if available. */
gpu::VertBuf *mask_vbo = nullptr;

View File

@ -38,10 +38,10 @@ static void extract_tan_init_common(const MeshRenderData &mr,
{
GPU_vertformat_deinterleave(format);
CustomData *cd_ldata = (mr.extract_type == MR_EXTRACT_BMESH) ? &mr.bm->ldata :
&mr.mesh->corner_data;
CustomData *cd_vdata = (mr.extract_type == MR_EXTRACT_BMESH) ? &mr.bm->vdata :
&mr.mesh->vert_data;
const CustomData *cd_ldata = (mr.extract_type == MR_EXTRACT_BMESH) ? &mr.bm->ldata :
&mr.mesh->corner_data;
const CustomData *cd_vdata = (mr.extract_type == MR_EXTRACT_BMESH) ? &mr.bm->vdata :
&mr.mesh->vert_data;
uint32_t tan_layers = cache.cd_used.tan;
const float(*orco)[3] = (const float(*)[3])CustomData_get_layer(cd_vdata, CD_ORCO);
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]);
}
}
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;
}
@ -118,6 +120,7 @@ static void extract_tan_init_common(const MeshRenderData &mr,
&tangent_mask);
}
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()),
mr.faces,
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
* found, false otherwise. */
static bool mesh_extract_uv_format_init(GPUVertFormat *format,
MeshBatchCache &cache,
CustomData *cd_ldata,
eMRExtractType extract_type,
const MeshBatchCache &cache,
const CustomData *cd_ldata,
const eMRExtractType extract_type,
uint32_t &r_uv_layers)
{
GPU_vertformat_deinterleave(format);
@ -89,8 +89,8 @@ static void extract_uv_init(const MeshRenderData &mr,
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buf);
GPUVertFormat format = {0};
CustomData *cd_ldata = (mr.extract_type == MR_EXTRACT_BMESH) ? &mr.bm->ldata :
&mr.mesh->corner_data;
const CustomData *cd_ldata = (mr.extract_type == MR_EXTRACT_BMESH) ? &mr.bm->ldata :
&mr.mesh->corner_data;
int v_len = mr.corners_num;
uint32_t uv_layers = cache.cd_used.uv;
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 * /*data*/)
{
Mesh *coarse_mesh = subdiv_cache.mesh;
const Mesh *coarse_mesh = subdiv_cache.mesh;
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buffer);
GPUVertFormat format = {0};

View File

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

View File

@ -10,7 +10,7 @@
#include "BKE_node.hh"
#include "BKE_object.hh"
#include "DEG_depsgraph.hh"
#include "BLI_vector.hh"
#include "RNA_define.hh"
@ -1164,6 +1164,375 @@ static void 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)
{
GPU_render_begin();

View File

@ -390,46 +390,44 @@ static void updateDuplicateSubtarget(EditBone *dup_bone,
*/
EditBone *oldtarget, *newtarget;
bPoseChannel *pchan;
ListBase *conlist;
if ((pchan = BKE_pose_channel_ensure(ob->pose, dup_bone->name))) {
if ((conlist = &pchan->constraints)) {
LISTBASE_FOREACH (bConstraint *, curcon, conlist) {
/* does this constraint have a subtarget in
* this armature?
*/
ListBase targets = {nullptr, nullptr};
ListBase *conlist = &pchan->constraints;
LISTBASE_FOREACH (bConstraint *, curcon, conlist) {
/* does this constraint have a subtarget in
* this armature?
*/
ListBase targets = {nullptr, nullptr};
if (BKE_constraint_targets_get(curcon, &targets)) {
LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
if ((ct->tar == ob) && (ct->subtarget[0])) {
oldtarget = get_named_editbone(editbones, ct->subtarget);
if (oldtarget) {
/* was the subtarget bone duplicated too? If
* so, update the constraint to point at the
* duplicate of the old subtarget.
*/
if (oldtarget->temp.ebone) {
newtarget = oldtarget->temp.ebone;
if (BKE_constraint_targets_get(curcon, &targets)) {
LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
if ((ct->tar == ob) && (ct->subtarget[0])) {
oldtarget = get_named_editbone(editbones, ct->subtarget);
if (oldtarget) {
/* was the subtarget bone duplicated too? If
* so, update the constraint to point at the
* duplicate of the old subtarget.
*/
if (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);
}
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;
}
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)
{
/* identifiers */
@ -796,13 +782,11 @@ void ARMATURE_OT_separate(wmOperatorType *ot)
ot->description = "Isolate selected bones into a separate armature";
/* callbacks */
ot->invoke = separate_armature_invoke;
ot->exec = separate_armature_exec;
ot->poll = ED_operator_editarmature;
/* flags */
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