Anim: run bezier handle calculation in parallel #119388
|
@ -18,6 +18,11 @@
|
|||
path = lib/windows_x64
|
||||
url = https://projects.blender.org/blender/lib-windows_x64.git
|
||||
branch = main
|
||||
[submodule "lib/windows_arm64"]
|
||||
update = none
|
||||
path = lib/windows_arm64
|
||||
url = https://projects.blender.org/blender/lib-windows_arm64.git
|
||||
branch = main
|
||||
[submodule "release/datafiles/assets"]
|
||||
path = release/datafiles/assets
|
||||
url = https://projects.blender.org/blender/blender-assets.git
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"""
|
||||
Using Python Argument Parsing
|
||||
-----------------------------
|
||||
**Using Python Argument Parsing**
|
||||
|
||||
This example shows how the Python ``argparse`` module can be used with a custom command.
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"""
|
||||
Custom Commands
|
||||
---------------
|
||||
**Custom Commands**
|
||||
|
||||
Registering commands makes it possible to conveniently expose command line
|
||||
functionality via commands passed to (``-c`` / ``--command``).
|
||||
|
|
|
@ -252,8 +252,7 @@ def main():
|
|||
name, tp = arg
|
||||
tp_sub = None
|
||||
else:
|
||||
print(arg)
|
||||
assert 0
|
||||
assert False, "unreachable, unsupported 'arg' length found %d" % len(arg)
|
||||
|
||||
tp_str = ""
|
||||
|
||||
|
@ -322,8 +321,7 @@ def main():
|
|||
# but think the idea is that that pointer is for any type?
|
||||
tp_str = ":class:`bpy.types.bpy_struct`"
|
||||
else:
|
||||
print("Can't find", vars_dict_reverse[tp_sub])
|
||||
assert 0
|
||||
assert False, "unreachable, unknown type %r" % vars_dict_reverse[tp_sub]
|
||||
|
||||
elif tp == BMO_OP_SLOT_ELEMENT_BUF:
|
||||
assert tp_sub is not None
|
||||
|
@ -362,11 +360,9 @@ def main():
|
|||
elif tp_sub == BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL:
|
||||
tp_str += "unknown internal data, not compatible with python"
|
||||
else:
|
||||
print("Can't find", vars_dict_reverse[tp_sub])
|
||||
assert 0
|
||||
assert False, "unreachable, unknown type %r" % vars_dict_reverse[tp_sub]
|
||||
else:
|
||||
print("Can't find", vars_dict_reverse[tp])
|
||||
assert 0
|
||||
assert False, "unreachable, unknown type %r" % vars_dict_reverse[tp]
|
||||
|
||||
args_wash.append((name, default_value, tp_str, comment))
|
||||
return args_wash
|
||||
|
|
|
@ -198,7 +198,7 @@ void device_cuda_info(vector<DeviceInfo> &devices)
|
|||
VLOG_INFO << "Added device \"" << info.description << "\" with id \"" << info.id << "\".";
|
||||
|
||||
if (info.denoisers & DENOISER_OPENIMAGEDENOISE)
|
||||
VLOG_INFO << "Device with id \"" << info.id << "\" is supporting "
|
||||
VLOG_INFO << "Device with id \"" << info.id << "\" supports "
|
||||
<< denoiserTypeToHumanReadable(DENOISER_OPENIMAGEDENOISE) << ".";
|
||||
}
|
||||
|
||||
|
|
|
@ -211,7 +211,7 @@ void device_hip_info(vector<DeviceInfo> &devices)
|
|||
VLOG_INFO << "Added device \"" << info.description << "\" with id \"" << info.id << "\".";
|
||||
|
||||
if (info.denoisers & DENOISER_OPENIMAGEDENOISE)
|
||||
VLOG_INFO << "Device with id \"" << info.id << "\" is supporting "
|
||||
VLOG_INFO << "Device with id \"" << info.id << "\" supports "
|
||||
<< denoiserTypeToHumanReadable(DENOISER_OPENIMAGEDENOISE) << ".";
|
||||
}
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ void device_metal_info(vector<DeviceInfo> &devices)
|
|||
VLOG_INFO << "Added device \"" << info.description << "\" with id \"" << info.id << "\".";
|
||||
|
||||
if (info.denoisers & DENOISER_OPENIMAGEDENOISE)
|
||||
VLOG_INFO << "Device with id \"" << info.id << "\" is supporting "
|
||||
VLOG_INFO << "Device with id \"" << info.id << "\" supports "
|
||||
<< denoiserTypeToHumanReadable(DENOISER_OPENIMAGEDENOISE) << ".";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,7 +134,7 @@ static void device_iterator_cb(
|
|||
VLOG_INFO << "Added device \"" << info.description << "\" with id \"" << info.id << "\".";
|
||||
|
||||
if (info.denoisers & DENOISER_OPENIMAGEDENOISE)
|
||||
VLOG_INFO << "Device with id \"" << info.id << "\" is supporting "
|
||||
VLOG_INFO << "Device with id \"" << info.id << "\" supports "
|
||||
<< denoiserTypeToHumanReadable(DENOISER_OPENIMAGEDENOISE) << ".";
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit dc33a8704935c49dd7a8cf49197fdf42ff52622d
|
|
@ -297,7 +297,7 @@ def axis_conversion(from_forward='Y', from_up='Z', to_forward='Y', to_up='Z'):
|
|||
for i, axis_lut in enumerate(_axis_convert_lut):
|
||||
if value in axis_lut:
|
||||
return Matrix(_axis_convert_matrix[i])
|
||||
assert 0
|
||||
assert False, "unreachable"
|
||||
|
||||
|
||||
def axis_conversion_ensure(operator, forward_attr, up_attr):
|
||||
|
|
|
@ -375,7 +375,7 @@ def draw_keymaps(context, layout):
|
|||
|
||||
rowsub.menu("USERPREF_MT_keyconfigs", text=text)
|
||||
rowsub.operator("wm.keyconfig_preset_add", text="", icon='ADD')
|
||||
rowsub.operator("wm.keyconfig_preset_add", text="", icon='REMOVE').remove_active = True
|
||||
rowsub.operator("wm.keyconfig_preset_remove", text="", icon='REMOVE')
|
||||
|
||||
rowsub = split.row(align=True)
|
||||
rowsub.operator("preferences.keyconfig_import", text="Import...", icon='IMPORT')
|
||||
|
|
|
@ -768,7 +768,7 @@ def km_window(params):
|
|||
("wm.search_menu", {"type": 'SPACE', "value": 'PRESS'}, None),
|
||||
)
|
||||
else:
|
||||
assert False
|
||||
assert False, "unreachable"
|
||||
|
||||
return keymap
|
||||
|
||||
|
@ -3530,7 +3530,7 @@ def km_frames(params):
|
|||
("screen.animation_play", {"type": 'SPACE', "value": 'PRESS'}, None),
|
||||
)
|
||||
else:
|
||||
assert False
|
||||
assert False, "unreachable"
|
||||
|
||||
items.extend([
|
||||
("screen.animation_play", {"type": 'SPACE', "value": 'PRESS', "shift": True, "ctrl": True},
|
||||
|
|
|
@ -147,8 +147,7 @@ class AddTorus(Operator, object_utils.AddObjectHelper):
|
|||
)
|
||||
major_radius: FloatProperty(
|
||||
name="Major Radius",
|
||||
description=("Radius from the origin to the "
|
||||
"center of the cross sections"),
|
||||
description="Radius from the origin to the center of the cross sections",
|
||||
soft_min=0.0, soft_max=100.0,
|
||||
min=0.0, max=10_000.0,
|
||||
default=1.0,
|
||||
|
|
|
@ -760,8 +760,7 @@ class CLIP_OT_setup_tracking_scene(Operator):
|
|||
def setup_space(space):
|
||||
space.show_backdrop = True
|
||||
|
||||
CLIP_spaces_walk(context, True, 'NODE_EDITOR', 'NODE_EDITOR',
|
||||
setup_space)
|
||||
CLIP_spaces_walk(context, True, 'NODE_EDITOR', 'NODE_EDITOR', setup_space)
|
||||
|
||||
sc = context.space_data
|
||||
scene = context.scene
|
||||
|
@ -812,8 +811,7 @@ class CLIP_OT_setup_tracking_scene(Operator):
|
|||
tree.links.new(movieclip.outputs["Image"], distortion.inputs["Image"])
|
||||
|
||||
if need_stabilization:
|
||||
tree.links.new(distortion.outputs["Image"],
|
||||
stabilize.inputs["Image"])
|
||||
tree.links.new(distortion.outputs["Image"], stabilize.inputs["Image"])
|
||||
tree.links.new(stabilize.outputs["Image"], scale.inputs["Image"])
|
||||
else:
|
||||
tree.links.new(distortion.outputs["Image"], scale.inputs["Image"])
|
||||
|
|
|
@ -42,8 +42,7 @@ class ConsoleExec(Operator):
|
|||
if execute is not None:
|
||||
return execute(context, self.interactive)
|
||||
else:
|
||||
print("Error: bpy.ops.console.execute_%s - not found" %
|
||||
sc.language)
|
||||
print("Error: bpy.ops.console.execute_%s - not found" % sc.language)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
|
@ -65,8 +64,7 @@ class ConsoleAutocomplete(Operator):
|
|||
if autocomplete:
|
||||
return autocomplete(context)
|
||||
else:
|
||||
print("Error: bpy.ops.console.autocomplete_%s - not found" %
|
||||
sc.language)
|
||||
print("Error: bpy.ops.console.autocomplete_%s - not found" % sc.language)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
|
@ -88,8 +86,7 @@ class ConsoleCopyAsScript(Operator):
|
|||
if copy_as_script:
|
||||
return copy_as_script(context)
|
||||
else:
|
||||
print("Error: copy_as_script - not found for %r" %
|
||||
sc.language)
|
||||
print("Error: copy_as_script - not found for %r" % sc.language)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
|
@ -115,8 +112,7 @@ class ConsoleBanner(Operator):
|
|||
if banner:
|
||||
return banner(context)
|
||||
else:
|
||||
print("Error: bpy.ops.console.banner_%s - not found" %
|
||||
sc.language)
|
||||
print("Error: bpy.ops.console.banner_%s - not found" % sc.language)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
|
@ -144,8 +140,7 @@ class ConsoleLanguage(Operator):
|
|||
bpy.ops.console.banner()
|
||||
|
||||
# insert a new blank line
|
||||
bpy.ops.console.history_append(text="", current_character=0,
|
||||
remove_duplicates=True)
|
||||
bpy.ops.console.history_append(text="", current_character=0, remove_duplicates=True)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
|
|
@ -171,9 +171,7 @@ class MeshMirrorUV(Operator):
|
|||
self.report({'WARNING'},
|
||||
rpt_("%d mesh(es) with no active UV layer, "
|
||||
"%d duplicates found in %d mesh(es), mirror may be incomplete")
|
||||
% (total_no_active_UV,
|
||||
total_duplicates,
|
||||
meshes_with_duplicates))
|
||||
% (total_no_active_UV, total_duplicates, meshes_with_duplicates))
|
||||
elif total_no_active_UV:
|
||||
self.report({'WARNING'},
|
||||
rpt_("%d mesh(es) with no active UV layer")
|
||||
|
|
|
@ -58,8 +58,7 @@ class NodeAddOperator:
|
|||
# convert mouse position to the View2D for later node placement
|
||||
if context.region.type == 'WINDOW':
|
||||
# convert mouse position to the View2D for later node placement
|
||||
space.cursor_location_from_region(
|
||||
event.mouse_region_x, event.mouse_region_y)
|
||||
space.cursor_location_from_region(event.mouse_region_x, event.mouse_region_y)
|
||||
else:
|
||||
space.cursor_location = tree.view_center
|
||||
|
||||
|
|
|
@ -223,8 +223,7 @@ class SubdivisionSet(Operator):
|
|||
)
|
||||
relative: BoolProperty(
|
||||
name="Relative",
|
||||
description=("Apply the subdivision surface level as an offset "
|
||||
"relative to the current level"),
|
||||
description="Apply the subdivision surface level as an offset relative to the current level",
|
||||
default=False,
|
||||
)
|
||||
|
||||
|
@ -288,8 +287,7 @@ class SubdivisionSet(Operator):
|
|||
mod = obj.modifiers.new("Subdivision", 'SUBSURF')
|
||||
mod.levels = level
|
||||
except BaseException:
|
||||
self.report({'WARNING'},
|
||||
"Modifiers cannot be added to object: " + obj.name)
|
||||
self.report({'WARNING'}, "Modifiers cannot be added to object: " + obj.name)
|
||||
|
||||
for obj in context.selected_editable_objects:
|
||||
set_object_subd(obj)
|
||||
|
@ -325,8 +323,7 @@ class ShapeTransfer(Operator):
|
|||
)
|
||||
use_clamp: BoolProperty(
|
||||
name="Clamp Offset",
|
||||
description=("Clamp the transformation to the distance each "
|
||||
"vertex moves in the original shape"),
|
||||
description="Clamp the transformation to the distance each vertex moves in the original shape",
|
||||
default=False,
|
||||
)
|
||||
|
||||
|
@ -447,8 +444,7 @@ class ShapeTransfer(Operator):
|
|||
if use_clamp:
|
||||
# clamp to the same movement as the original
|
||||
# breaks copy between different scaled meshes.
|
||||
len_from = (orig_shape_coords[i] -
|
||||
orig_coords[i]).length
|
||||
len_from = (orig_shape_coords[i] - orig_coords[i]).length
|
||||
ofs = co - target_coords[i]
|
||||
ofs.length = len_from
|
||||
co = target_coords[i] + ofs
|
||||
|
|
|
@ -101,13 +101,7 @@ def worldspace_bounds_from_object_data(depsgraph, obj):
|
|||
return Vector((left, front, up)), Vector((right, back, down))
|
||||
|
||||
|
||||
def align_objects(context,
|
||||
align_x,
|
||||
align_y,
|
||||
align_z,
|
||||
align_mode,
|
||||
relative_to,
|
||||
bb_quality):
|
||||
def align_objects(context, align_x, align_y, align_z, align_mode, relative_to, bb_quality):
|
||||
|
||||
depsgraph = context.evaluated_depsgraph_get()
|
||||
scene = context.scene
|
||||
|
@ -115,8 +109,7 @@ def align_objects(context,
|
|||
cursor = scene.cursor.location
|
||||
|
||||
# We are accessing runtime data such as evaluated bounding box, so we need to
|
||||
# be sure it is properly updated and valid (bounding box might be lost on operator
|
||||
# redo).
|
||||
# be sure it is properly updated and valid (bounding box might be lost on operator redo).
|
||||
context.view_layer.update()
|
||||
|
||||
Left_Front_Up_SEL = [0.0, 0.0, 0.0]
|
||||
|
|
|
@ -277,9 +277,7 @@ class QuickExplode(ObjectModeOperator, Operator):
|
|||
|
||||
for obj in mesh_objects:
|
||||
if obj.particle_systems:
|
||||
self.report({'ERROR'},
|
||||
rpt_("Object %r already has a "
|
||||
"particle system") % obj.name)
|
||||
self.report({'ERROR'}, rpt_("Object %r already has a " "particle system") % obj.name)
|
||||
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
@ -518,8 +516,7 @@ class QuickSmoke(ObjectModeOperator, Operator):
|
|||
# Add Principled Volume
|
||||
node_principled = nodes.new(type='ShaderNodeVolumePrincipled')
|
||||
node_principled.location = grid_location(4, 1)
|
||||
links.new(node_principled.outputs["Volume"],
|
||||
node_out.inputs["Volume"])
|
||||
links.new(node_principled.outputs["Volume"], node_out.inputs["Volume"])
|
||||
|
||||
node_principled.inputs["Density"].default_value = 5.0
|
||||
|
||||
|
|
|
@ -6,8 +6,7 @@ from bpy.types import Operator
|
|||
from mathutils import Vector
|
||||
|
||||
|
||||
def randomize_selected(context, seed, delta,
|
||||
loc, rot, scale, scale_even, _scale_min):
|
||||
def randomize_selected(context, seed, delta, loc, rot, scale, scale_even, _scale_min):
|
||||
|
||||
import random
|
||||
from random import uniform
|
||||
|
@ -100,8 +99,7 @@ class RandomizeLocRotSize(Operator):
|
|||
)
|
||||
use_delta: BoolProperty(
|
||||
name="Transform Delta",
|
||||
description=("Randomize delta transform values "
|
||||
"instead of regular transform"),
|
||||
description="Randomize delta transform values instead of regular transform",
|
||||
default=False,
|
||||
)
|
||||
use_loc: BoolProperty(
|
||||
|
@ -111,8 +109,7 @@ class RandomizeLocRotSize(Operator):
|
|||
)
|
||||
loc: FloatVectorProperty(
|
||||
name="Location",
|
||||
description=("Maximum distance the objects "
|
||||
"can spread over each axis"),
|
||||
description="Maximum distance the objects can spread over each axis",
|
||||
min=-100.0,
|
||||
max=100.0,
|
||||
default=(0.0, 0.0, 0.0),
|
||||
|
@ -174,8 +171,7 @@ class RandomizeLocRotSize(Operator):
|
|||
# scale_min = self.scale_min
|
||||
scale_min = 0
|
||||
|
||||
randomize_selected(context, seed, delta,
|
||||
loc, rot, scale, scale_even, scale_min)
|
||||
randomize_selected(context, seed, delta, loc, rot, scale, scale_even, scale_min)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
|
|
@ -120,9 +120,7 @@ class AddPresetBase:
|
|||
|
||||
if is_xml:
|
||||
import rna_xml
|
||||
rna_xml.xml_file_write(context,
|
||||
filepath,
|
||||
preset_menu_class.preset_xml_map)
|
||||
rna_xml.xml_file_write(context, filepath, preset_menu_class.preset_xml_map)
|
||||
else:
|
||||
|
||||
def rna_recursive_attr_expand(value, rna_path_step, level):
|
||||
|
@ -169,15 +167,10 @@ class AddPresetBase:
|
|||
name = preset_menu_class.bl_label
|
||||
|
||||
# fairly sloppy but convenient.
|
||||
filepath = bpy.utils.preset_find(name,
|
||||
self.preset_subdir,
|
||||
ext=ext)
|
||||
filepath = bpy.utils.preset_find(name, self.preset_subdir, ext=ext)
|
||||
|
||||
if not filepath:
|
||||
filepath = bpy.utils.preset_find(name,
|
||||
self.preset_subdir,
|
||||
display_name=True,
|
||||
ext=ext)
|
||||
filepath = bpy.utils.preset_find(name, self.preset_subdir, display_name=True, ext=ext)
|
||||
|
||||
if not filepath:
|
||||
return {'CANCELLED'}
|
||||
|
@ -257,9 +250,7 @@ class ExecutePreset(Operator):
|
|||
|
||||
elif ext == ".xml":
|
||||
import rna_xml
|
||||
rna_xml.xml_file_run(context,
|
||||
filepath,
|
||||
preset_class.preset_xml_map)
|
||||
rna_xml.xml_file_run(context, filepath, preset_class.preset_xml_map)
|
||||
|
||||
if hasattr(preset_class, "post_cb"):
|
||||
preset_class.post_cb(context)
|
||||
|
@ -563,17 +554,44 @@ class AddPresetNodeColor(AddPresetBase, Operator):
|
|||
|
||||
|
||||
class AddPresetInterfaceTheme(AddPresetBase, Operator):
|
||||
"""Add or remove a theme preset"""
|
||||
"""Add a custom theme to the preset list"""
|
||||
bl_idname = "wm.interface_theme_preset_add"
|
||||
bl_label = "Add Theme Preset"
|
||||
bl_label = "Add Theme"
|
||||
preset_menu = "USERPREF_MT_interface_theme_presets"
|
||||
preset_subdir = "interface_theme"
|
||||
|
||||
|
||||
class RemovePresetInterfaceTheme(AddPresetBase, Operator):
|
||||
"""Remove a custom theme from the preset list"""
|
||||
bl_idname = "wm.interface_theme_preset_remove"
|
||||
bl_label = "Remove Theme"
|
||||
preset_menu = "USERPREF_MT_interface_theme_presets"
|
||||
preset_subdir = "interface_theme"
|
||||
|
||||
remove_active: BoolProperty(
|
||||
default=True,
|
||||
options={'HIDDEN', 'SKIP_SAVE'},
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
from bpy.utils import is_path_builtin
|
||||
preset_menu_class = getattr(bpy.types, cls.preset_menu)
|
||||
name = preset_menu_class.bl_label
|
||||
filepath = bpy.utils.preset_find(name, cls.preset_subdir, ext=".xml")
|
||||
if not bool(filepath) or is_path_builtin(filepath):
|
||||
cls.poll_message_set("Built-in themes cannot be removed")
|
||||
return False
|
||||
return True
|
||||
|
||||
def invoke(self, context, event):
|
||||
return context.window_manager.invoke_confirm(self, event, title="Remove Custom Theme", confirm_text="Delete")
|
||||
|
||||
|
||||
class AddPresetKeyconfig(AddPresetBase, Operator):
|
||||
"""Add or remove a Key-config Preset"""
|
||||
"""Add a custom keymap configuration to the preset list"""
|
||||
bl_idname = "wm.keyconfig_preset_add"
|
||||
bl_label = "Add Keyconfig Preset"
|
||||
bl_label = "Add Custom Keymap Configuration"
|
||||
preset_menu = "USERPREF_MT_keyconfigs"
|
||||
preset_subdir = "keyconfig"
|
||||
|
||||
|
@ -581,16 +599,43 @@ class AddPresetKeyconfig(AddPresetBase, Operator):
|
|||
bpy.ops.preferences.keyconfig_export(filepath=filepath)
|
||||
bpy.utils.keyconfig_set(filepath)
|
||||
|
||||
|
||||
class RemovePresetKeyconfig(AddPresetBase, Operator):
|
||||
"""Remove a custom keymap configuration from the preset list"""
|
||||
bl_idname = "wm.keyconfig_preset_remove"
|
||||
bl_label = "Remove Keymap Configuration"
|
||||
preset_menu = "USERPREF_MT_keyconfigs"
|
||||
preset_subdir = "keyconfig"
|
||||
|
||||
remove_active: BoolProperty(
|
||||
default=True,
|
||||
options={'HIDDEN', 'SKIP_SAVE'},
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
from bpy.utils import is_path_builtin
|
||||
keyconfigs = bpy.context.window_manager.keyconfigs
|
||||
preset_menu_class = getattr(bpy.types, cls.preset_menu)
|
||||
name = keyconfigs.active.name
|
||||
filepath = bpy.utils.preset_find(name, cls.preset_subdir, ext=".py")
|
||||
if not bool(filepath) or is_path_builtin(filepath):
|
||||
cls.poll_message_set("Built-in keymap configurations cannot be removed")
|
||||
return False
|
||||
return True
|
||||
|
||||
def pre_cb(self, context):
|
||||
keyconfigs = bpy.context.window_manager.keyconfigs
|
||||
if self.remove_active:
|
||||
preset_menu_class = getattr(bpy.types, self.preset_menu)
|
||||
preset_menu_class.bl_label = keyconfigs.active.name
|
||||
preset_menu_class = getattr(bpy.types, self.preset_menu)
|
||||
preset_menu_class.bl_label = keyconfigs.active.name
|
||||
|
||||
def post_cb(self, context):
|
||||
keyconfigs = bpy.context.window_manager.keyconfigs
|
||||
if self.remove_active:
|
||||
keyconfigs.remove(keyconfigs.active)
|
||||
keyconfigs.remove(keyconfigs.active)
|
||||
|
||||
def invoke(self, context, event):
|
||||
return context.window_manager.invoke_confirm(
|
||||
self, event, title="Remove Keymap Configuration", confirm_text="Delete")
|
||||
|
||||
|
||||
class AddPresetOperator(AddPresetBase, Operator):
|
||||
|
@ -811,7 +856,9 @@ classes = (
|
|||
AddPresetFluid,
|
||||
AddPresetHairDynamics,
|
||||
AddPresetInterfaceTheme,
|
||||
RemovePresetInterfaceTheme,
|
||||
AddPresetKeyconfig,
|
||||
RemovePresetKeyconfig,
|
||||
AddPresetNodeColor,
|
||||
AddPresetOperator,
|
||||
AddPresetRender,
|
||||
|
|
|
@ -434,8 +434,7 @@ class RandomizeUVTransform(Operator):
|
|||
)
|
||||
loc: FloatVectorProperty(
|
||||
name="Location",
|
||||
description=("Maximum distance the objects "
|
||||
"can spread over each axis"),
|
||||
description="Maximum distance the objects can spread over each axis",
|
||||
min=-100.0,
|
||||
max=100.0,
|
||||
size=2,
|
||||
|
|
|
@ -155,8 +155,7 @@ class VIEW3D_OT_edit_mesh_extrude_move(Operator):
|
|||
return {'FINISHED'}
|
||||
|
||||
def execute(self, context):
|
||||
return VIEW3D_OT_edit_mesh_extrude_move.extrude_region(
|
||||
self, context, False, self.dissolve_and_intersect)
|
||||
return VIEW3D_OT_edit_mesh_extrude_move.extrude_region(self, context, False, self.dissolve_and_intersect)
|
||||
|
||||
def invoke(self, context, _event):
|
||||
return self.execute(context)
|
||||
|
|
|
@ -2084,8 +2084,7 @@ class WM_OT_properties_edit_value(Operator):
|
|||
rna_item = eval("context.%s" % self.data_path)
|
||||
|
||||
if WM_OT_properties_edit.get_property_type(rna_item, self.property_name) == 'PYTHON':
|
||||
self.eval_string = WM_OT_properties_edit.convert_custom_property_to_string(rna_item,
|
||||
self.property_name)
|
||||
self.eval_string = WM_OT_properties_edit.convert_custom_property_to_string(rna_item, self.property_name)
|
||||
else:
|
||||
self.eval_string = ""
|
||||
|
||||
|
@ -2960,7 +2959,7 @@ class WM_OT_batch_rename(Operator):
|
|||
elif method == 'SUFFIX':
|
||||
name = name + text
|
||||
else:
|
||||
assert 0
|
||||
assert False, "unreachable"
|
||||
|
||||
elif ty == 'STRIP':
|
||||
chars = action.strip_chars
|
||||
|
@ -3005,9 +3004,9 @@ class WM_OT_batch_rename(Operator):
|
|||
elif method == 'TITLE':
|
||||
name = name.title()
|
||||
else:
|
||||
assert 0
|
||||
assert False, "unreachable"
|
||||
else:
|
||||
assert 0
|
||||
assert False, "unreachable"
|
||||
return name
|
||||
|
||||
def _data_update(self, context):
|
||||
|
|
|
@ -24,10 +24,8 @@ class CollectionButtonsPanel:
|
|||
def lineart_make_line_type_entry(col, line_type, text_disp, expand, search_from):
|
||||
col.prop(line_type, "use", text=text_disp)
|
||||
if line_type.use and expand:
|
||||
col.prop_search(line_type, "layer", search_from,
|
||||
"layers", icon='GREASEPENCIL')
|
||||
col.prop_search(line_type, "material", search_from,
|
||||
"materials", icon='SHADING_TEXTURE')
|
||||
col.prop_search(line_type, "layer", search_from, "layers", icon='GREASEPENCIL')
|
||||
col.prop_search(line_type, "material", search_from, "materials", icon='SHADING_TEXTURE')
|
||||
|
||||
|
||||
class COLLECTION_PT_collection_flags(CollectionButtonsPanel, Panel):
|
||||
|
|
|
@ -87,20 +87,13 @@ class DATA_UL_bone_collections(UIList):
|
|||
active_bone = armature.edit_bones.active or armature.bones.active
|
||||
has_active_bone = active_bone and bcoll.name in active_bone.collections
|
||||
|
||||
layout.prop(bcoll, "name", text="", emboss=False,
|
||||
icon='DOT' if has_active_bone else 'BLANK1')
|
||||
layout.prop(bcoll, "name", text="", emboss=False, icon='DOT' if has_active_bone else 'BLANK1')
|
||||
|
||||
if armature.override_library:
|
||||
icon = 'LIBRARY_DATA_OVERRIDE' if bcoll.is_local_override else 'BLANK1'
|
||||
layout.prop(
|
||||
bcoll,
|
||||
"is_local_override",
|
||||
text="",
|
||||
emboss=False,
|
||||
icon=icon)
|
||||
layout.prop(bcoll, "is_local_override", text="", emboss=False, icon=icon)
|
||||
|
||||
layout.prop(bcoll, "is_visible", text="", emboss=False,
|
||||
icon='HIDE_OFF' if bcoll.is_visible else 'HIDE_ON')
|
||||
layout.prop(bcoll, "is_visible", text="", emboss=False, icon='HIDE_OFF' if bcoll.is_visible else 'HIDE_ON')
|
||||
|
||||
|
||||
class DATA_PT_bone_collections(ArmatureButtonsPanel, Panel):
|
||||
|
|
|
@ -289,15 +289,12 @@ class BONE_PT_collections(BoneButtonsPanel, Panel):
|
|||
# Sub-layout that's dimmed when the bone collection's own visibility flag doesn't matter.
|
||||
sub_visible = row.row(align=True)
|
||||
sub_visible.active = (not is_solo_active) and bcoll.is_visible_ancestors
|
||||
sub_visible.prop(bcoll, "is_visible", text="",
|
||||
icon='HIDE_OFF' if bcoll.is_visible else 'HIDE_ON')
|
||||
sub_visible.prop(bcoll, "is_visible", text="", icon='HIDE_OFF' if bcoll.is_visible else 'HIDE_ON')
|
||||
|
||||
row.prop(bcoll, "is_solo", text="",
|
||||
icon='SOLO_ON' if bcoll.is_solo else 'SOLO_OFF')
|
||||
row.prop(bcoll, "is_solo", text="", icon='SOLO_ON' if bcoll.is_solo else 'SOLO_OFF')
|
||||
|
||||
# Unassignment operator, less safe so with a bit of spacing.
|
||||
props = bcoll_row.operator("armature.collection_unassign_named",
|
||||
text="", icon='X')
|
||||
props = bcoll_row.operator("armature.collection_unassign_named", text="", icon='X')
|
||||
props.name = bcoll.name
|
||||
props.bone_name = bone.name
|
||||
|
||||
|
@ -410,8 +407,7 @@ class BONE_PT_display_custom_shape(BoneButtonsPanel, Panel):
|
|||
sub.prop(pchan, "custom_shape_translation", text="Translation")
|
||||
sub.prop(pchan, "custom_shape_rotation_euler", text="Rotation")
|
||||
|
||||
sub.prop_search(pchan, "custom_shape_transform",
|
||||
ob.pose, "bones", text="Override Transform")
|
||||
sub.prop_search(pchan, "custom_shape_transform", ob.pose, "bones", text="Override Transform")
|
||||
sub.prop(pchan, "use_custom_shape_bone_size")
|
||||
|
||||
sub.separator()
|
||||
|
@ -559,8 +555,7 @@ class BONE_PT_custom_props(BoneButtonsPanel, rna_prop_ui.PropertyPanel, Panel):
|
|||
@classmethod
|
||||
def _poll(cls, context):
|
||||
context_path = cls._get_context_path(context)
|
||||
rna_item, _context_member = rna_prop_ui.rna_idprop_context_value(
|
||||
context, context_path, cls._property_type)
|
||||
rna_item, _context_member = rna_prop_ui.rna_idprop_context_value(context, context_path, cls._property_type)
|
||||
return bool(rna_item)
|
||||
|
||||
def draw(self, context):
|
||||
|
|
|
@ -156,8 +156,7 @@ class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel):
|
|||
@classmethod
|
||||
def poll(cls, context):
|
||||
render = context.scene.render
|
||||
return (super().poll(context) and render.use_multiview and
|
||||
render.views_format == 'STEREO_3D')
|
||||
return (super().poll(context) and render.use_multiview and render.views_format == 'STEREO_3D')
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
import bpy
|
||||
from bpy.types import Panel, Menu
|
||||
from bpy.types import Panel, Menu, UIList
|
||||
from rna_prop_ui import PropertyPanel
|
||||
|
||||
|
||||
|
@ -27,6 +27,39 @@ class LayerDataButtonsPanel:
|
|||
return grease_pencil and grease_pencil.layers.active
|
||||
|
||||
|
||||
class GREASE_PENCIL_UL_masks(UIList):
|
||||
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
|
||||
mask = item
|
||||
if self.layout_type in {'DEFAULT', 'COMPACT'}:
|
||||
row = layout.row(align=True)
|
||||
row.prop(mask, "name", text="", emboss=False, icon_value=icon)
|
||||
row.prop(mask, "invert", text="", emboss=False)
|
||||
row.prop(mask, "hide", text="", emboss=False)
|
||||
elif self.layout_type == 'GRID':
|
||||
layout.alignment = 'CENTER'
|
||||
layout.prop(mask, "name", text="", emboss=False, icon_value=icon)
|
||||
|
||||
|
||||
class GREASE_PENCIL_MT_layer_mask_add(Menu):
|
||||
bl_label = "Add Mask"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
grease_pencil = context.grease_pencil
|
||||
active_layer = grease_pencil.layers.active
|
||||
found = False
|
||||
for layer in grease_pencil.layers:
|
||||
if layer == active_layer or layer.name in active_layer.mask_layers:
|
||||
continue
|
||||
|
||||
found = True
|
||||
layout.operator("grease_pencil.layer_mask_add", text=layer.name).name = layer.name
|
||||
|
||||
if not found:
|
||||
layout.label(text="No layers to add")
|
||||
|
||||
|
||||
class DATA_PT_context_grease_pencil(DataButtonsPanel, Panel):
|
||||
bl_label = ""
|
||||
bl_options = {'HIDE_HEADER'}
|
||||
|
@ -91,14 +124,58 @@ class DATA_PT_grease_pencil_layers(DataButtonsPanel, Panel):
|
|||
|
||||
col.operator("grease_pencil.layer_remove", icon='REMOVE', text="")
|
||||
|
||||
# Layer main properties
|
||||
if layer:
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = True
|
||||
col = layout.column(align=True)
|
||||
if not layer:
|
||||
return
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(layer, "opacity", text="Opacity", slider=True)
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = True
|
||||
col = layout.column(align=True)
|
||||
|
||||
# Layer main properties
|
||||
row = layout.row(align=True)
|
||||
row.prop(layer, "blend_mode", text="Blend Mode")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(layer, "opacity", text="Opacity", slider=True)
|
||||
|
||||
|
||||
class DATA_PT_grease_pencil_layer_masks(LayerDataButtonsPanel, Panel):
|
||||
bl_label = "Masks"
|
||||
bl_parent_id = "DATA_PT_grease_pencil_layers"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw_header(self, context):
|
||||
grease_pencil = context.grease_pencil
|
||||
layer = grease_pencil.layers.active
|
||||
|
||||
self.layout.prop(layer, "use_masks", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
grease_pencil = context.grease_pencil
|
||||
layer = grease_pencil.layers.active
|
||||
|
||||
layout = self.layout
|
||||
layout.enabled = layer.use_masks
|
||||
|
||||
if not layer:
|
||||
return
|
||||
|
||||
rows = 4
|
||||
row = layout.row()
|
||||
col = row.column()
|
||||
col.template_list("GREASE_PENCIL_UL_masks", "", layer, "mask_layers", layer.mask_layers,
|
||||
"active_mask_index", rows=rows, sort_lock=True)
|
||||
|
||||
col = row.column(align=True)
|
||||
col.menu("GREASE_PENCIL_MT_layer_mask_add", icon='ADD', text="")
|
||||
col.operator("grease_pencil.layer_mask_remove", icon='REMOVE', text="")
|
||||
|
||||
col.separator()
|
||||
|
||||
sub = col.column(align=True)
|
||||
sub.operator("grease_pencil.layer_mask_reorder", icon='TRIA_UP', text="").direction = 'UP'
|
||||
sub.operator("grease_pencil.layer_mask_reorder", icon='TRIA_DOWN', text="").direction = 'DOWN'
|
||||
|
||||
|
||||
class DATA_PT_grease_pencil_layer_transform(LayerDataButtonsPanel, Panel):
|
||||
|
@ -153,16 +230,33 @@ class DATA_PT_grease_pencil_layer_relations(LayerDataButtonsPanel, Panel):
|
|||
col.prop_search(layer, "viewlayer_render", context.scene, "view_layers", text="View Layer")
|
||||
|
||||
|
||||
class DATA_PT_grease_pencil_settings(DataButtonsPanel, Panel):
|
||||
bl_label = "Settings"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
grease_pencil = context.grease_pencil
|
||||
col = layout.column(align=True)
|
||||
col.prop(grease_pencil, "stroke_depth_order", text="Stroke Depth Order")
|
||||
|
||||
|
||||
class DATA_PT_grease_pencil_custom_props(DataButtonsPanel, PropertyPanel, Panel):
|
||||
_context_path = "object.data"
|
||||
_property_type = bpy.types.GreasePencilv3
|
||||
|
||||
|
||||
classes = (
|
||||
GREASE_PENCIL_UL_masks,
|
||||
GREASE_PENCIL_MT_layer_mask_add,
|
||||
DATA_PT_context_grease_pencil,
|
||||
DATA_PT_grease_pencil_layers,
|
||||
DATA_PT_grease_pencil_layer_masks,
|
||||
DATA_PT_grease_pencil_layer_transform,
|
||||
DATA_PT_grease_pencil_layer_relations,
|
||||
DATA_PT_grease_pencil_settings,
|
||||
DATA_PT_grease_pencil_custom_props,
|
||||
GREASE_PENCIL_MT_grease_pencil_add_layer_extra,
|
||||
)
|
||||
|
|
|
@ -637,8 +637,7 @@ class MESH_UL_color_attributes(UIList, ColorAttributesListBase):
|
|||
sub = split.row()
|
||||
sub.alignment = 'RIGHT'
|
||||
sub.active = False
|
||||
sub.label(text="%s ▶ %s" % (iface_(domain_name), iface_(data_type.name)),
|
||||
translate=False)
|
||||
sub.label(text="%s ▶ %s" % (iface_(domain_name), iface_(data_type.name)), translate=False)
|
||||
|
||||
active_render = _index == data.color_attributes.render_color_index
|
||||
|
||||
|
|
|
@ -754,8 +754,7 @@ class VIEWLAYER_PT_freestyle_linestyle_color(ViewLayerFreestyleLineStyle, Panel)
|
|||
|
||||
elif modifier.type == 'MATERIAL':
|
||||
row = box.row()
|
||||
row.prop(modifier, "material_attribute",
|
||||
text="Material Attribute")
|
||||
row.prop(modifier, "material_attribute", text="Material Attribute")
|
||||
sub = box.column()
|
||||
sub.prop(modifier, "use_ramp")
|
||||
if modifier.material_attribute in {'LINE', 'DIFF', 'SPEC'}:
|
||||
|
|
|
@ -36,8 +36,7 @@ def draw_mask_context_menu(layout, _context):
|
|||
|
||||
|
||||
class MASK_UL_layers(UIList):
|
||||
def draw_item(self, _context, layout, _data, item, icon,
|
||||
_active_data, _active_propname, _index):
|
||||
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
|
||||
# assert(isinstance(item, bpy.types.MaskLayer)
|
||||
mask = item
|
||||
if self.layout_type in {'DEFAULT', 'COMPACT'}:
|
||||
|
@ -204,8 +203,7 @@ class MASK_PT_point:
|
|||
row = col.row()
|
||||
row.prop(parent, "type", expand=True)
|
||||
|
||||
col.prop_search(parent, "parent", tracking,
|
||||
"objects", icon='OBJECT_DATA', text="Object")
|
||||
col.prop_search(parent, "parent", tracking, "objects", icon='OBJECT_DATA', text="Object")
|
||||
|
||||
tracks_list = "tracks" if parent.type == 'POINT_TRACK' else "plane_tracks"
|
||||
|
||||
|
|
|
@ -391,8 +391,7 @@ class SmoothStrokePanel(BrushPanel):
|
|||
brush = settings.brush
|
||||
|
||||
self.layout.use_property_split = False
|
||||
self.layout.prop(brush, "use_smooth_stroke",
|
||||
text=self.bl_label if self.is_popover else "")
|
||||
self.layout.prop(brush, "use_smooth_stroke", text=self.bl_label if self.is_popover else "")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
@ -1344,8 +1343,7 @@ def brush_basic_gpencil_paint_settings(layout, context, brush, *, compact=False)
|
|||
|
||||
if gp_settings.use_pressure and not compact:
|
||||
col = layout.column()
|
||||
col.template_curve_mapping(gp_settings, "curve_sensitivity", brush=True,
|
||||
use_negative_slope=True)
|
||||
col.template_curve_mapping(gp_settings, "curve_sensitivity", brush=True, use_negative_slope=True)
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(gp_settings, "pen_strength", slider=True)
|
||||
|
@ -1353,8 +1351,7 @@ def brush_basic_gpencil_paint_settings(layout, context, brush, *, compact=False)
|
|||
|
||||
if gp_settings.use_strength_pressure and not compact:
|
||||
col = layout.column()
|
||||
col.template_curve_mapping(gp_settings, "curve_strength", brush=True,
|
||||
use_negative_slope=True)
|
||||
col.template_curve_mapping(gp_settings, "curve_strength", brush=True, use_negative_slope=True)
|
||||
|
||||
if brush.gpencil_tool == 'TINT':
|
||||
row = layout.row(align=True)
|
||||
|
@ -1415,8 +1412,7 @@ def brush_basic_grease_pencil_paint_settings(layout, context, brush, *, compact=
|
|||
|
||||
if brush.use_pressure_size and not compact:
|
||||
col = layout.column()
|
||||
col.template_curve_mapping(gp_settings, "curve_sensitivity", brush=True,
|
||||
use_negative_slope=True)
|
||||
col.template_curve_mapping(gp_settings, "curve_sensitivity", brush=True, use_negative_slope=True)
|
||||
|
||||
UnifiedPaintPanel.prop_unified(
|
||||
layout,
|
||||
|
@ -1431,8 +1427,7 @@ def brush_basic_grease_pencil_paint_settings(layout, context, brush, *, compact=
|
|||
|
||||
if brush.use_pressure_strength and not compact:
|
||||
col = layout.column()
|
||||
col.template_curve_mapping(gp_settings, "curve_strength", brush=True,
|
||||
use_negative_slope=True)
|
||||
col.template_curve_mapping(gp_settings, "curve_strength", brush=True, use_negative_slope=True)
|
||||
|
||||
if grease_pencil_tool == 'DRAW':
|
||||
layout.prop(gp_settings, "active_smooth_factor")
|
||||
|
|
|
@ -87,9 +87,7 @@ class PARTICLE_MT_context_menu(Menu):
|
|||
props.remove_target_particles = True
|
||||
|
||||
if psys is not None and psys.settings.type == 'HAIR':
|
||||
layout.operator(
|
||||
"curves.convert_from_particle_system",
|
||||
text="Convert to Curves")
|
||||
layout.operator("curves.convert_from_particle_system", text="Convert to Curves")
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
|
|
@ -151,8 +151,7 @@ class VIEWLAYER_PT_eevee_layer_passes_light(ViewLayerButtonsPanel, Panel):
|
|||
col.prop(view_layer, "use_pass_emit", text="Emission")
|
||||
col.prop(view_layer, "use_pass_environment")
|
||||
col.prop(view_layer, "use_pass_shadow")
|
||||
col.prop(view_layer, "use_pass_ambient_occlusion",
|
||||
text="Ambient Occlusion")
|
||||
col.prop(view_layer, "use_pass_ambient_occlusion", text="Ambient Occlusion")
|
||||
|
||||
|
||||
class VIEWLAYER_PT_eevee_next_layer_passes_light(ViewLayerButtonsPanel, Panel):
|
||||
|
@ -184,8 +183,7 @@ class VIEWLAYER_PT_eevee_next_layer_passes_light(ViewLayerButtonsPanel, Panel):
|
|||
col.prop(view_layer, "use_pass_emit", text="Emission")
|
||||
col.prop(view_layer, "use_pass_environment")
|
||||
col.prop(view_layer, "use_pass_shadow")
|
||||
col.prop(view_layer, "use_pass_ambient_occlusion",
|
||||
text="Ambient Occlusion")
|
||||
col.prop(view_layer, "use_pass_ambient_occlusion", text="Ambient Occlusion")
|
||||
|
||||
col = layout.column()
|
||||
col.active = view_layer.use_pass_ambient_occlusion
|
||||
|
@ -230,8 +228,7 @@ class ViewLayerAOVPanel(ViewLayerButtonsPanel, Panel):
|
|||
|
||||
row = layout.row()
|
||||
col = row.column()
|
||||
col.template_list("VIEWLAYER_UL_aov", "aovs", view_layer,
|
||||
"aovs", view_layer, "active_aov_index", rows=3)
|
||||
col.template_list("VIEWLAYER_UL_aov", "aovs", view_layer, "aovs", view_layer, "active_aov_index", rows=3)
|
||||
|
||||
col = row.column()
|
||||
sub = col.column(align=True)
|
||||
|
@ -240,8 +237,7 @@ class ViewLayerAOVPanel(ViewLayerButtonsPanel, Panel):
|
|||
|
||||
aov = view_layer.active_aov
|
||||
if aov and not aov.is_valid:
|
||||
layout.label(
|
||||
text="Conflicts with another render pass with the same name", icon='ERROR')
|
||||
layout.label(text="Conflicts with another render pass with the same name", icon='ERROR')
|
||||
|
||||
|
||||
class VIEWLAYER_PT_layer_passes_aov(ViewLayerAOVPanel):
|
||||
|
@ -271,8 +267,7 @@ class ViewLayerCryptomattePanel(ViewLayerButtonsPanel, Panel):
|
|||
col.prop(view_layer, "pass_cryptomatte_depth", text="Levels")
|
||||
|
||||
if context.engine == 'BLENDER_EEVEE':
|
||||
col.prop(view_layer, "use_pass_cryptomatte_accurate",
|
||||
text="Accurate Mode")
|
||||
col.prop(view_layer, "use_pass_cryptomatte_accurate", text="Accurate Mode")
|
||||
|
||||
|
||||
class VIEWLAYER_PT_layer_passes_cryptomatte(ViewLayerCryptomattePanel, Panel):
|
||||
|
|
|
@ -17,8 +17,7 @@ from bl_ui.properties_grease_pencil_common import (
|
|||
|
||||
|
||||
class CLIP_UL_tracking_objects(UIList):
|
||||
def draw_item(self, _context, layout, _data, item, _icon,
|
||||
_active_data, _active_propname, _index):
|
||||
def draw_item(self, _context, layout, _data, item, _icon, _active_data, _active_propname, _index):
|
||||
# assert(isinstance(item, bpy.types.MovieTrackingObject)
|
||||
tobj = item
|
||||
if self.layout_type in {'DEFAULT', 'COMPACT'}:
|
||||
|
@ -142,8 +141,7 @@ class CLIP_HT_header(Header):
|
|||
props = row.operator("clip.track_markers", text="", icon='TRACKING_BACKWARDS_SINGLE')
|
||||
props.backwards = True
|
||||
props.sequence = False
|
||||
props = row.operator("clip.track_markers", text="",
|
||||
icon='TRACKING_BACKWARDS')
|
||||
props = row.operator("clip.track_markers", text="", icon='TRACKING_BACKWARDS')
|
||||
props.backwards = True
|
||||
props.sequence = True
|
||||
props = row.operator("clip.track_markers", text="", icon='TRACKING_FORWARDS')
|
||||
|
@ -171,9 +169,7 @@ class CLIP_HT_header(Header):
|
|||
r = active_object.reconstruction
|
||||
|
||||
if r.is_valid and sc.view == 'CLIP':
|
||||
layout.label(text=rpt_("Solve error: %.2f px") %
|
||||
(r.average_error),
|
||||
translate=False)
|
||||
layout.label(text=rpt_("Solve error: %.2f px") % (r.average_error), translate=False)
|
||||
|
||||
row = layout.row()
|
||||
row.prop(sc, "pivot_point", text="", icon_only=True)
|
||||
|
@ -433,16 +429,12 @@ class CLIP_PT_tracking_settings(CLIP_PT_tracking_panel, Panel):
|
|||
|
||||
row = col.row(align=True)
|
||||
row.use_property_split = False
|
||||
row.prop(settings, "use_default_red_channel",
|
||||
text="R", toggle=True)
|
||||
row.prop(settings, "use_default_green_channel",
|
||||
text="G", toggle=True)
|
||||
row.prop(settings, "use_default_blue_channel",
|
||||
text="B", toggle=True)
|
||||
row.prop(settings, "use_default_red_channel", text="R", toggle=True)
|
||||
row.prop(settings, "use_default_green_channel", text="G", toggle=True)
|
||||
row.prop(settings, "use_default_blue_channel", text="B", toggle=True)
|
||||
|
||||
col.separator()
|
||||
col.operator("clip.track_settings_as_default",
|
||||
text="Copy from Active Track")
|
||||
col.operator("clip.track_settings_as_default", text="Copy from Active Track")
|
||||
|
||||
|
||||
class CLIP_PT_tracking_settings_extras(CLIP_PT_tracking_panel, Panel):
|
||||
|
@ -486,8 +478,7 @@ class CLIP_PT_tools_tracking(CLIP_PT_tracking_panel, Panel):
|
|||
props = row.operator("clip.track_markers", text="", icon='TRACKING_BACKWARDS_SINGLE')
|
||||
props.backwards = True
|
||||
props.sequence = False
|
||||
props = row.operator("clip.track_markers", text="",
|
||||
icon='TRACKING_BACKWARDS')
|
||||
props = row.operator("clip.track_markers", text="", icon='TRACKING_BACKWARDS')
|
||||
props.backwards = True
|
||||
props.sequence = True
|
||||
props = row.operator("clip.track_markers", text="", icon='TRACKING_FORWARDS')
|
||||
|
@ -712,8 +703,7 @@ class CLIP_PT_objects(CLIP_PT_clip_view_panel, Panel):
|
|||
tracking = sc.clip.tracking
|
||||
|
||||
row = layout.row()
|
||||
row.template_list("CLIP_UL_tracking_objects", "", tracking, "objects",
|
||||
tracking, "active_object_index", rows=1)
|
||||
row.template_list("CLIP_UL_tracking_objects", "", tracking, "objects", tracking, "active_object_index", rows=1)
|
||||
|
||||
sub = row.column(align=True)
|
||||
|
||||
|
@ -765,8 +755,7 @@ class CLIP_PT_track(CLIP_PT_tracking_panel, Panel):
|
|||
row.prop(act_track, "use_grayscale_preview", text="B/W", toggle=True)
|
||||
|
||||
row.separator()
|
||||
row.prop(act_track, "use_alpha_preview",
|
||||
text="", toggle=True, icon='IMAGE_ALPHA')
|
||||
row.prop(act_track, "use_alpha_preview", text="", toggle=True, icon='IMAGE_ALPHA')
|
||||
|
||||
layout.prop(act_track, "weight")
|
||||
layout.prop(act_track, "weight_stab")
|
||||
|
@ -810,8 +799,7 @@ class CLIP_PT_plane_track(CLIP_PT_tracking_panel, Panel):
|
|||
layout.prop(active_track, "name")
|
||||
layout.prop(active_track, "use_auto_keying")
|
||||
row = layout.row()
|
||||
row.template_ID(
|
||||
active_track, "image", new="image.new", open="image.open")
|
||||
row.template_ID(active_track, "image", new="image.new", open="image.open")
|
||||
row.menu("CLIP_MT_plane_track_image_context_menu", icon='DOWNARROW_HLT', text="")
|
||||
|
||||
row = layout.row()
|
||||
|
@ -1642,10 +1630,8 @@ class CLIP_MT_tracking_context_menu(Menu):
|
|||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("clip.disable_markers",
|
||||
text="Disable Markers").action = 'DISABLE'
|
||||
layout.operator("clip.disable_markers",
|
||||
text="Enable Markers").action = 'ENABLE'
|
||||
layout.operator("clip.disable_markers", text="Disable Markers").action = 'DISABLE'
|
||||
layout.operator("clip.disable_markers", text="Enable Markers").action = 'ENABLE'
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
@ -1655,8 +1641,7 @@ class CLIP_MT_tracking_context_menu(Menu):
|
|||
layout.separator()
|
||||
|
||||
layout.operator("clip.lock_tracks", text="Lock Tracks").action = 'LOCK'
|
||||
layout.operator("clip.lock_tracks",
|
||||
text="Unlock Tracks").action = 'UNLOCK'
|
||||
layout.operator("clip.lock_tracks", text="Unlock Tracks").action = 'UNLOCK'
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
|
|
@ -73,9 +73,7 @@ class CONSOLE_MT_language(Menu):
|
|||
languages.sort()
|
||||
|
||||
for language in languages:
|
||||
layout.operator("console.language",
|
||||
text=language.title(),
|
||||
translate=False).language = language
|
||||
layout.operator("console.language", text=language.title(), translate=False).language = language
|
||||
|
||||
|
||||
class CONSOLE_MT_console(Menu):
|
||||
|
|
|
@ -179,8 +179,7 @@ class DOPESHEET_PT_filters(DopesheetFilterPopoverBase, Panel):
|
|||
if ds_mode in {'DOPESHEET', 'ACTION', 'GPENCIL'}:
|
||||
layout.separator()
|
||||
generic_filters_only = ds_mode != 'DOPESHEET'
|
||||
DopesheetFilterPopoverBase.draw_search_filters(context, layout,
|
||||
generic_filters_only=generic_filters_only)
|
||||
DopesheetFilterPopoverBase.draw_search_filters(context, layout, generic_filters_only=generic_filters_only)
|
||||
|
||||
if ds_mode == 'DOPESHEET':
|
||||
layout.separator()
|
||||
|
|
|
@ -142,12 +142,10 @@ class FILEBROWSER_PT_filter(FileBrowserPanel, Panel):
|
|||
else:
|
||||
row = col.row()
|
||||
row.label(icon='FILE_BLEND')
|
||||
row.prop(params, "use_filter_blender",
|
||||
text=".blend Files", toggle=False)
|
||||
row.prop(params, "use_filter_blender", text=".blend Files", toggle=False)
|
||||
row = col.row()
|
||||
row.label(icon='FILE_BACKUP')
|
||||
row.prop(params, "use_filter_backup",
|
||||
text="Backup .blend Files", toggle=False)
|
||||
row.prop(params, "use_filter_backup", text="Backup .blend Files", toggle=False)
|
||||
row = col.row()
|
||||
row.label(icon='FILE_IMAGE')
|
||||
row.prop(params, "use_filter_image", text="Image Files", toggle=False)
|
||||
|
@ -156,8 +154,7 @@ class FILEBROWSER_PT_filter(FileBrowserPanel, Panel):
|
|||
row.prop(params, "use_filter_movie", text="Movie Files", toggle=False)
|
||||
row = col.row()
|
||||
row.label(icon='FILE_SCRIPT')
|
||||
row.prop(params, "use_filter_script",
|
||||
text="Script Files", toggle=False)
|
||||
row.prop(params, "use_filter_script", text="Script Files", toggle=False)
|
||||
row = col.row()
|
||||
row.label(icon='FILE_FONT')
|
||||
row.prop(params, "use_filter_font", text="Font Files", toggle=False)
|
||||
|
@ -176,8 +173,7 @@ class FILEBROWSER_PT_filter(FileBrowserPanel, Panel):
|
|||
if is_lib_browser:
|
||||
row = col.row()
|
||||
row.label(icon='BLANK1') # Indentation
|
||||
row.prop(params, "use_filter_blendid",
|
||||
text="Blender IDs", toggle=False)
|
||||
row.prop(params, "use_filter_blendid", text="Blender IDs", toggle=False)
|
||||
if params.use_filter_blendid:
|
||||
row = col.row()
|
||||
row.label(icon='BLANK1') # Indentation
|
||||
|
@ -281,10 +277,8 @@ class FILEBROWSER_MT_bookmarks_context_menu(Menu):
|
|||
layout.operator("file.bookmark_cleanup", icon='X', text="Cleanup")
|
||||
|
||||
layout.separator()
|
||||
layout.operator("file.bookmark_move", icon='TRIA_UP_BAR',
|
||||
text="Move to Top").direction = 'TOP'
|
||||
layout.operator("file.bookmark_move", icon='TRIA_DOWN_BAR',
|
||||
text="Move to Bottom").direction = 'BOTTOM'
|
||||
layout.operator("file.bookmark_move", icon='TRIA_UP_BAR', text="Move to Top").direction = 'TOP'
|
||||
layout.operator("file.bookmark_move", icon='TRIA_DOWN_BAR', text="Move to Bottom").direction = 'BOTTOM'
|
||||
|
||||
|
||||
class FILEBROWSER_PT_bookmarks_favorites(FileBrowserPanel, Panel):
|
||||
|
@ -314,15 +308,12 @@ class FILEBROWSER_PT_bookmarks_favorites(FileBrowserPanel, Panel):
|
|||
col = row.column(align=True)
|
||||
col.operator("file.bookmark_add", icon='ADD', text="")
|
||||
col.operator("file.bookmark_delete", icon='REMOVE', text="")
|
||||
col.menu("FILEBROWSER_MT_bookmarks_context_menu",
|
||||
icon='DOWNARROW_HLT', text="")
|
||||
col.menu("FILEBROWSER_MT_bookmarks_context_menu", icon='DOWNARROW_HLT', text="")
|
||||
|
||||
if num_rows > 1:
|
||||
col.separator()
|
||||
col.operator("file.bookmark_move", icon='TRIA_UP',
|
||||
text="").direction = 'UP'
|
||||
col.operator("file.bookmark_move", icon='TRIA_DOWN',
|
||||
text="").direction = 'DOWN'
|
||||
col.operator("file.bookmark_move", icon='TRIA_UP', text="").direction = 'UP'
|
||||
col.operator("file.bookmark_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
|
||||
else:
|
||||
layout.operator("file.bookmark_add", icon='ADD')
|
||||
|
||||
|
@ -553,10 +544,8 @@ class FILEBROWSER_MT_context_menu(FileBrowserMenu, Menu):
|
|||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("file.filenum", text="Increase Number",
|
||||
icon='ADD').increment = 1
|
||||
layout.operator("file.filenum", text="Decrease Number",
|
||||
icon='REMOVE').increment = -1
|
||||
layout.operator("file.filenum", text="Increase Number", icon='ADD').increment = 1
|
||||
layout.operator("file.filenum", text="Decrease Number", icon='REMOVE').increment = -1
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
|
|
@ -194,8 +194,7 @@ class IMAGE_MT_image(Menu):
|
|||
ima = sima.image
|
||||
show_render = sima.show_render
|
||||
|
||||
layout.operator("image.new", text="New",
|
||||
text_ctxt=i18n_contexts.id_image)
|
||||
layout.operator("image.new", text="New", text_ctxt=i18n_contexts.id_image)
|
||||
layout.operator("image.open", text="Open...", icon='FILE_FOLDER')
|
||||
|
||||
layout.operator("image.read_viewlayers")
|
||||
|
|
|
@ -81,9 +81,7 @@ class INFO_MT_area(Menu):
|
|||
layout.separator()
|
||||
|
||||
layout.operator("screen.screen_full_area")
|
||||
layout.operator(
|
||||
"screen.screen_full_area",
|
||||
text="Toggle Fullscreen Area").use_hide_panels = True
|
||||
layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
|
||||
layout.operator("screen.area_dupli")
|
||||
|
||||
layout.separator()
|
||||
|
|
|
@ -223,8 +223,7 @@ class OUTLINER_MT_collection(Menu):
|
|||
|
||||
space = context.space_data
|
||||
|
||||
layout.operator("outliner.collection_new", text="New",
|
||||
text_ctxt=i18n_contexts.id_collection).nested = True
|
||||
layout.operator("outliner.collection_new", text="New", text_ctxt=i18n_contexts.id_collection).nested = True
|
||||
layout.operator("outliner.collection_duplicate", text="Duplicate Collection")
|
||||
layout.operator("outliner.collection_duplicate_linked", text="Duplicate Linked")
|
||||
layout.operator("outliner.id_copy", text="Copy", icon='COPYDOWN')
|
||||
|
|
|
@ -31,14 +31,12 @@ class TEXT_HT_header(Header):
|
|||
row.operator("text.resolve_conflict", text="", icon='QUESTION')
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.template_ID(st, "text", new="text.new",
|
||||
unlink="text.unlink", open="text.open")
|
||||
row.template_ID(st, "text", new="text.new", unlink="text.unlink", open="text.open")
|
||||
|
||||
if text:
|
||||
is_osl = text.name.endswith((".osl", ".osl"))
|
||||
if is_osl:
|
||||
row.operator("node.shader_script_update",
|
||||
text="", icon='FILE_REFRESH')
|
||||
row.operator("node.shader_script_update", text="", icon='FILE_REFRESH')
|
||||
else:
|
||||
row = layout.row()
|
||||
row.active = is_syntax_highlight_supported
|
||||
|
@ -174,10 +172,8 @@ class TEXT_PT_find(Panel):
|
|||
row = layout.row(align=True)
|
||||
if not st.text:
|
||||
row.active = False
|
||||
row.prop(st, "use_match_case", text="Case",
|
||||
text_ctxt=i18n_contexts.id_text, toggle=True)
|
||||
row.prop(st, "use_find_wrap", text="Wrap",
|
||||
text_ctxt=i18n_contexts.id_text, toggle=True)
|
||||
row.prop(st, "use_match_case", text="Case", text_ctxt=i18n_contexts.id_text, toggle=True)
|
||||
row.prop(st, "use_find_wrap", text="Wrap", text_ctxt=i18n_contexts.id_text, toggle=True)
|
||||
row.prop(st, "use_find_all", text="All", toggle=True)
|
||||
|
||||
|
||||
|
@ -253,8 +249,7 @@ class TEXT_MT_text(Menu):
|
|||
st = context.space_data
|
||||
text = st.text
|
||||
|
||||
layout.operator("text.new", text="New",
|
||||
text_ctxt=i18n_contexts.id_text, icon='FILE_NEW')
|
||||
layout.operator("text.new", text="New", text_ctxt=i18n_contexts.id_text, icon='FILE_NEW')
|
||||
layout.operator("text.open", text="Open...", icon='FILE_FOLDER')
|
||||
|
||||
if text:
|
||||
|
|
|
@ -228,7 +228,7 @@ class TimelinePanelButtons:
|
|||
class TIME_PT_playback(TimelinePanelButtons, Panel):
|
||||
bl_label = "Playback"
|
||||
bl_region_type = 'HEADER'
|
||||
bl_ui_units_x = 11
|
||||
bl_ui_units_x = 13
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
|
|
@ -226,8 +226,7 @@ class ToolSelectPanelHelper:
|
|||
@staticmethod
|
||||
def _tool_class_from_space_type(space_type):
|
||||
return next(
|
||||
(cls for cls in ToolSelectPanelHelper.__subclasses__()
|
||||
if cls.bl_space_type == space_type),
|
||||
(cls for cls in ToolSelectPanelHelper.__subclasses__() if cls.bl_space_type == space_type),
|
||||
None,
|
||||
)
|
||||
|
||||
|
|
|
@ -33,17 +33,9 @@ class TOPBAR_HT_upper_bar(Header):
|
|||
layout.separator()
|
||||
|
||||
if not screen.show_fullscreen:
|
||||
layout.template_ID_tabs(
|
||||
window, "workspace",
|
||||
new="workspace.add",
|
||||
menu="TOPBAR_MT_workspace_menu",
|
||||
)
|
||||
layout.template_ID_tabs(window, "workspace", new="workspace.add", menu="TOPBAR_MT_workspace_menu")
|
||||
else:
|
||||
layout.operator(
|
||||
"screen.back_to_previous",
|
||||
icon='SCREEN_BACK',
|
||||
text="Back to Previous",
|
||||
)
|
||||
layout.operator("screen.back_to_previous", icon='SCREEN_BACK', text="Back to Previous")
|
||||
|
||||
def draw_right(self, context):
|
||||
layout = self.layout
|
||||
|
@ -58,8 +50,7 @@ class TOPBAR_HT_upper_bar(Header):
|
|||
layout.template_running_jobs()
|
||||
|
||||
# Active workspace view-layer is retrieved through window, not through workspace.
|
||||
layout.template_ID(window, "scene", new="scene.new",
|
||||
unlink="scene.delete")
|
||||
layout.template_ID(window, "scene", new="scene.new", unlink="scene.delete")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.template_search(
|
||||
|
@ -84,11 +75,9 @@ class TOPBAR_PT_tool_settings_extra(Panel):
|
|||
layout = self.layout
|
||||
|
||||
# Get the active tool
|
||||
space_type, mode = ToolSelectPanelHelper._tool_key_from_context(
|
||||
context)
|
||||
space_type, mode = ToolSelectPanelHelper._tool_key_from_context(context)
|
||||
cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
|
||||
item, tool, _ = cls._tool_get_active(
|
||||
context, space_type, mode, with_icon=True)
|
||||
item, tool, _ = cls._tool_get_active(context, space_type, mode, with_icon=True)
|
||||
if item is None:
|
||||
return
|
||||
|
||||
|
@ -110,8 +99,7 @@ class TOPBAR_PT_tool_fallback(Panel):
|
|||
ToolSelectPanelHelper.draw_fallback_tool_items(layout, context)
|
||||
if tool_settings.workspace_tool_type == 'FALLBACK':
|
||||
tool = context.tool
|
||||
ToolSelectPanelHelper.draw_active_tool_fallback(
|
||||
context, layout, tool)
|
||||
ToolSelectPanelHelper.draw_active_tool_fallback(context, layout, tool)
|
||||
|
||||
|
||||
class TOPBAR_PT_gpencil_layers(Panel):
|
||||
|
@ -156,8 +144,7 @@ class TOPBAR_PT_gpencil_layers(Panel):
|
|||
|
||||
srow = col.row(align=True)
|
||||
srow.prop(gpl, "opacity", text="Opacity", slider=True)
|
||||
srow.prop(gpl, "use_mask_layer", text="",
|
||||
icon='CLIPUV_DEHLT' if gpl.use_mask_layer else 'CLIPUV_HLT')
|
||||
srow.prop(gpl, "use_mask_layer", text="", icon='CLIPUV_DEHLT' if gpl.use_mask_layer else 'CLIPUV_HLT')
|
||||
|
||||
srow = col.row(align=True)
|
||||
srow.prop(gpl, "use_lights", text="Lights")
|
||||
|
@ -170,25 +157,20 @@ class TOPBAR_PT_gpencil_layers(Panel):
|
|||
|
||||
gpl = context.active_gpencil_layer
|
||||
if gpl:
|
||||
sub.menu("GPENCIL_MT_layer_context_menu",
|
||||
icon='DOWNARROW_HLT', text="")
|
||||
sub.menu("GPENCIL_MT_layer_context_menu", icon='DOWNARROW_HLT', text="")
|
||||
|
||||
if len(gpd.layers) > 1:
|
||||
col.separator()
|
||||
|
||||
sub = col.column(align=True)
|
||||
sub.operator("gpencil.layer_move",
|
||||
icon='TRIA_UP', text="").type = 'UP'
|
||||
sub.operator("gpencil.layer_move",
|
||||
icon='TRIA_DOWN', text="").type = 'DOWN'
|
||||
sub.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP'
|
||||
sub.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN'
|
||||
|
||||
col.separator()
|
||||
|
||||
sub = col.column(align=True)
|
||||
sub.operator("gpencil.layer_isolate", icon='HIDE_OFF',
|
||||
text="").affect_visibility = True
|
||||
sub.operator("gpencil.layer_isolate", icon='LOCKED',
|
||||
text="").affect_visibility = False
|
||||
sub.operator("gpencil.layer_isolate", icon='HIDE_OFF', text="").affect_visibility = True
|
||||
sub.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
|
||||
|
||||
|
||||
class TOPBAR_MT_editor_menus(Menu):
|
||||
|
@ -224,8 +206,7 @@ class TOPBAR_MT_blender(Menu):
|
|||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("preferences.app_template_install",
|
||||
text="Install Application Template...")
|
||||
layout.operator("preferences.app_template_install", text="Install Application Template...")
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
@ -343,16 +324,11 @@ class TOPBAR_MT_file_new(Menu):
|
|||
|
||||
# Draw application templates.
|
||||
if not use_more:
|
||||
props = layout.operator(
|
||||
"wm.read_homefile", text="General", icon=icon)
|
||||
props = layout.operator("wm.read_homefile", text="General", icon=icon)
|
||||
props.app_template = ""
|
||||
|
||||
for d in paths:
|
||||
props = layout.operator(
|
||||
"wm.read_homefile",
|
||||
text=bpy.path.display_name(iface_(d)),
|
||||
icon=icon,
|
||||
)
|
||||
props = layout.operator("wm.read_homefile", text=bpy.path.display_name(iface_(d)), icon=icon)
|
||||
props.app_template = d
|
||||
|
||||
layout.operator_context = 'EXEC_DEFAULT'
|
||||
|
@ -396,8 +372,7 @@ class TOPBAR_MT_file_defaults(Menu):
|
|||
layout.operator("wm.save_homefile")
|
||||
if app_template:
|
||||
display_name = bpy.path.display_name(iface_(app_template))
|
||||
props = layout.operator("wm.read_factory_settings",
|
||||
text="Load Factory Blender Settings")
|
||||
props = layout.operator("wm.read_factory_settings", text="Load Factory Blender Settings")
|
||||
props.app_template = app_template
|
||||
props = layout.operator("wm.read_factory_settings",
|
||||
text=iface_("Load Factory %s Settings",
|
||||
|
@ -435,8 +410,7 @@ class TOPBAR_MT_templates_more(Menu):
|
|||
bl_label = "Templates"
|
||||
|
||||
def draw(self, context):
|
||||
bpy.types.TOPBAR_MT_file_new.draw_ex(
|
||||
self.layout, context, use_more=True)
|
||||
bpy.types.TOPBAR_MT_file_new.draw_ex(self.layout, context, use_more=True)
|
||||
|
||||
|
||||
class TOPBAR_MT_file_import(Menu):
|
||||
|
@ -550,10 +524,8 @@ class TOPBAR_MT_render(Menu):
|
|||
|
||||
rd = context.scene.render
|
||||
|
||||
layout.operator("render.render", text="Render Image",
|
||||
icon='RENDER_STILL').use_viewport = True
|
||||
props = layout.operator(
|
||||
"render.render", text="Render Animation", icon='RENDER_ANIMATION')
|
||||
layout.operator("render.render", text="Render Image", icon='RENDER_STILL').use_viewport = True
|
||||
props = layout.operator("render.render", text="Render Animation", icon='RENDER_ANIMATION')
|
||||
props.animation = True
|
||||
props.use_viewport = True
|
||||
|
||||
|
@ -612,8 +584,7 @@ class TOPBAR_MT_edit(Menu):
|
|||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("screen.userpref_show",
|
||||
text="Preferences...", icon='PREFERENCES')
|
||||
layout.operator("screen.userpref_show", text="Preferences...", icon='PREFERENCES')
|
||||
|
||||
|
||||
class TOPBAR_MT_window(Menu):
|
||||
|
@ -634,10 +605,8 @@ class TOPBAR_MT_window(Menu):
|
|||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("screen.workspace_cycle",
|
||||
text="Next Workspace").direction = 'NEXT'
|
||||
layout.operator("screen.workspace_cycle",
|
||||
text="Previous Workspace").direction = 'PREV'
|
||||
layout.operator("screen.workspace_cycle", text="Next Workspace").direction = 'NEXT'
|
||||
layout.operator("screen.workspace_cycle", text="Previous Workspace").direction = 'PREV'
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
@ -718,8 +687,7 @@ class TOPBAR_MT_file_context_menu(Menu):
|
|||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("screen.userpref_show",
|
||||
text="Preferences...", icon='PREFERENCES')
|
||||
layout.operator("screen.userpref_show", text="Preferences...", icon='PREFERENCES')
|
||||
|
||||
|
||||
class TOPBAR_MT_workspace_menu(Menu):
|
||||
|
@ -728,26 +696,21 @@ class TOPBAR_MT_workspace_menu(Menu):
|
|||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
||||
layout.operator("workspace.duplicate",
|
||||
text="Duplicate", icon='DUPLICATE')
|
||||
layout.operator("workspace.duplicate", text="Duplicate", icon='DUPLICATE')
|
||||
if len(bpy.data.workspaces) > 1:
|
||||
layout.operator("workspace.delete", text="Delete", icon='REMOVE')
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("workspace.reorder_to_front",
|
||||
text="Reorder to Front", icon='TRIA_LEFT_BAR')
|
||||
layout.operator("workspace.reorder_to_back",
|
||||
text="Reorder to Back", icon='TRIA_RIGHT_BAR')
|
||||
layout.operator("workspace.reorder_to_front", text="Reorder to Front", icon='TRIA_LEFT_BAR')
|
||||
layout.operator("workspace.reorder_to_back", text="Reorder to Back", icon='TRIA_RIGHT_BAR')
|
||||
|
||||
layout.separator()
|
||||
|
||||
# For key binding discoverability.
|
||||
props = layout.operator("screen.workspace_cycle",
|
||||
text="Previous Workspace")
|
||||
props = layout.operator("screen.workspace_cycle", text="Previous Workspace")
|
||||
props.direction = 'PREV'
|
||||
props = layout.operator(
|
||||
"screen.workspace_cycle", text="Next Workspace")
|
||||
props = layout.operator("screen.workspace_cycle", text="Next Workspace")
|
||||
props.direction = 'NEXT'
|
||||
|
||||
|
||||
|
@ -762,8 +725,7 @@ class TOPBAR_PT_gpencil_primitive(Panel):
|
|||
|
||||
layout = self.layout
|
||||
# Curve
|
||||
layout.template_curve_mapping(
|
||||
settings, "thickness_primitive_curve", brush=True)
|
||||
layout.template_curve_mapping(settings, "thickness_primitive_curve", brush=True)
|
||||
|
||||
|
||||
# Only a popover
|
||||
|
|
|
@ -247,7 +247,7 @@ class USERPREF_PT_interface_text(InterfacePanel, CenterAlignMixIn, Panel):
|
|||
|
||||
|
||||
class USERPREF_PT_interface_translation(InterfacePanel, CenterAlignMixIn, Panel):
|
||||
bl_label = "Translation"
|
||||
bl_label = "Language"
|
||||
bl_translation_context = i18n_contexts.id_windowmanager
|
||||
|
||||
@classmethod
|
||||
|
@ -260,7 +260,7 @@ class USERPREF_PT_interface_translation(InterfacePanel, CenterAlignMixIn, Panel)
|
|||
|
||||
layout.prop(view, "language")
|
||||
|
||||
col = layout.column(heading="Affect")
|
||||
col = layout.column(heading="Translate")
|
||||
col.active = (bpy.app.translations.locale != "en_US")
|
||||
col.prop(view, "use_translate_tooltips", text="Tooltips")
|
||||
col.prop(view, "use_translate_interface", text="Interface")
|
||||
|
@ -876,7 +876,7 @@ class USERPREF_PT_theme(ThemePanel, Panel):
|
|||
row = split.row(align=True)
|
||||
row.menu("USERPREF_MT_interface_theme_presets", text=USERPREF_MT_interface_theme_presets.bl_label)
|
||||
row.operator("wm.interface_theme_preset_add", text="", icon='ADD')
|
||||
row.operator("wm.interface_theme_preset_add", text="", icon='REMOVE').remove_active = True
|
||||
row.operator("wm.interface_theme_preset_remove", text="", icon='REMOVE')
|
||||
|
||||
row = split.row(align=True)
|
||||
row.operator("preferences.theme_install", text="Install...", icon='IMPORT')
|
||||
|
@ -1021,8 +1021,7 @@ class USERPREF_PT_theme_interface_transparent_checker(ThemePanel, CenterAlignMix
|
|||
theme = context.preferences.themes[0]
|
||||
ui = theme.user_interface
|
||||
|
||||
flow = layout.grid_flow(
|
||||
row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
|
||||
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
|
||||
|
||||
col = flow.column(align=True)
|
||||
col.prop(ui, "transparent_checker_primary")
|
||||
|
|
|
@ -843,8 +843,7 @@ class VIEW3D_HT_header(Header):
|
|||
|
||||
# Curve edit sub-mode.
|
||||
row = layout.row(align=True)
|
||||
row.prop(gpd, "use_curve_edit", text="",
|
||||
icon='IPO_BEZIER')
|
||||
row.prop(gpd, "use_curve_edit", text="", icon='IPO_BEZIER')
|
||||
sub = row.row(align=True)
|
||||
sub.active = gpd.use_curve_edit
|
||||
sub.popover(
|
||||
|
@ -974,8 +973,7 @@ class VIEW3D_HT_header(Header):
|
|||
row.popover(panel="VIEW3D_PT_slots_projectpaint", icon=icon)
|
||||
row.popover(
|
||||
panel="VIEW3D_PT_mask",
|
||||
icon=VIEW3D_HT_header._texture_mask_icon(
|
||||
tool_settings.image_paint),
|
||||
icon=VIEW3D_HT_header._texture_mask_icon(tool_settings.image_paint),
|
||||
text="")
|
||||
else:
|
||||
# Transform settings depending on tool header visibility
|
||||
|
@ -3138,9 +3136,7 @@ class VIEW3D_MT_object_apply(Menu):
|
|||
text_ctxt=i18n_contexts.default,
|
||||
).target = 'MESH'
|
||||
layout.operator("object.duplicates_make_real")
|
||||
layout.operator("object.parent_inverse_apply",
|
||||
text="Parent Inverse",
|
||||
text_ctxt=i18n_contexts.default)
|
||||
layout.operator("object.parent_inverse_apply", text="Parent Inverse", text_ctxt=i18n_contexts.default)
|
||||
|
||||
layout.template_node_operator_asset_menu_items(catalog_path="Object/Apply")
|
||||
|
||||
|
@ -4113,8 +4109,7 @@ class VIEW3D_MT_bone_collections(Menu):
|
|||
layout.separator()
|
||||
|
||||
layout.operator("armature.collection_show_all")
|
||||
props = layout.operator("armature.collection_create_and_assign",
|
||||
text="Assign to New Collection")
|
||||
props = layout.operator("armature.collection_create_and_assign", text="Assign to New Collection")
|
||||
props.name = "New Collection"
|
||||
|
||||
|
||||
|
@ -4496,12 +4491,9 @@ class VIEW3D_MT_edit_mesh_context_menu(Menu):
|
|||
|
||||
col.separator()
|
||||
|
||||
col.operator("view3d.edit_mesh_extrude_move_normal",
|
||||
text="Extrude Faces")
|
||||
col.operator("view3d.edit_mesh_extrude_move_shrink_fatten",
|
||||
text="Extrude Faces Along Normals")
|
||||
col.operator("mesh.extrude_faces_move",
|
||||
text="Extrude Individual Faces")
|
||||
col.operator("view3d.edit_mesh_extrude_move_normal", text="Extrude Faces")
|
||||
col.operator("view3d.edit_mesh_extrude_move_shrink_fatten", text="Extrude Faces Along Normals")
|
||||
col.operator("mesh.extrude_faces_move", text="Extrude Individual Faces")
|
||||
|
||||
col.operator("mesh.inset")
|
||||
col.operator("mesh.poke")
|
||||
|
@ -4561,23 +4553,16 @@ class VIEW3D_MT_edit_mesh_extrude(Menu):
|
|||
mesh = context.object.data
|
||||
|
||||
if mesh.total_face_sel:
|
||||
layout.operator("view3d.edit_mesh_extrude_move_normal",
|
||||
text="Extrude Faces")
|
||||
layout.operator("view3d.edit_mesh_extrude_move_shrink_fatten",
|
||||
text="Extrude Faces Along Normals")
|
||||
layout.operator(
|
||||
"mesh.extrude_faces_move",
|
||||
text="Extrude Individual Faces")
|
||||
layout.operator("view3d.edit_mesh_extrude_manifold_normal",
|
||||
text="Extrude Manifold")
|
||||
layout.operator("view3d.edit_mesh_extrude_move_normal", text="Extrude Faces")
|
||||
layout.operator("view3d.edit_mesh_extrude_move_shrink_fatten", text="Extrude Faces Along Normals")
|
||||
layout.operator("mesh.extrude_faces_move", text="Extrude Individual Faces")
|
||||
layout.operator("view3d.edit_mesh_extrude_manifold_normal", text="Extrude Manifold")
|
||||
|
||||
if mesh.total_edge_sel and (select_mode[0] or select_mode[1]):
|
||||
layout.operator("mesh.extrude_edges_move",
|
||||
text="Extrude Edges")
|
||||
layout.operator("mesh.extrude_edges_move", text="Extrude Edges")
|
||||
|
||||
if mesh.total_vert_sel and select_mode[0]:
|
||||
layout.operator("mesh.extrude_vertices_move",
|
||||
text="Extrude Vertices")
|
||||
layout.operator("mesh.extrude_vertices_move", text="Extrude Vertices")
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
@ -4742,10 +4727,8 @@ class VIEW3D_MT_edit_mesh_faces(Menu):
|
|||
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
|
||||
layout.operator("view3d.edit_mesh_extrude_move_normal",
|
||||
text="Extrude Faces")
|
||||
layout.operator("view3d.edit_mesh_extrude_move_shrink_fatten",
|
||||
text="Extrude Faces Along Normals")
|
||||
layout.operator("view3d.edit_mesh_extrude_move_normal", text="Extrude Faces")
|
||||
layout.operator("view3d.edit_mesh_extrude_move_shrink_fatten", text="Extrude Faces Along Normals")
|
||||
layout.operator("mesh.extrude_faces_move", text="Extrude Individual Faces")
|
||||
|
||||
layout.separator()
|
||||
|
@ -5665,8 +5648,7 @@ class VIEW3D_MT_edit_gpencil_stroke(Menu):
|
|||
|
||||
layout.separator()
|
||||
|
||||
layout.operator_menu_enum("gpencil.stroke_join", "type", text="Join",
|
||||
text_ctxt=i18n_contexts.id_gpencil)
|
||||
layout.operator_menu_enum("gpencil.stroke_join", "type", text="Join", text_ctxt=i18n_contexts.id_gpencil)
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
@ -8156,8 +8138,7 @@ class VIEW3D_MT_gpencil_edit_context_menu(Menu):
|
|||
|
||||
# Removal Operators
|
||||
col.operator("gpencil.stroke_merge_by_distance").use_unselected = True
|
||||
col.operator_menu_enum("gpencil.stroke_join", "type", text="Join",
|
||||
text_ctxt=i18n_contexts.id_gpencil)
|
||||
col.operator_menu_enum("gpencil.stroke_join", "type", text="Join", text_ctxt=i18n_contexts.id_gpencil)
|
||||
|
||||
col.operator("gpencil.stroke_split", text="Split")
|
||||
col.operator("gpencil.stroke_separate", text="Separate").mode = 'STROKE'
|
||||
|
|
|
@ -743,8 +743,7 @@ class VIEW3D_PT_stencil_projectpaint(Panel):
|
|||
|
||||
def draw_header(self, context):
|
||||
ipaint = context.tool_settings.image_paint
|
||||
self.layout.prop(ipaint, "use_stencil_layer",
|
||||
text=self.bl_label if self.is_popover else "")
|
||||
self.layout.prop(ipaint, "use_stencil_layer", text=self.bl_label if self.is_popover else "")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
@ -926,8 +925,7 @@ class VIEW3D_PT_tools_brush_falloff_frontface(View3DPaintPanel, Panel):
|
|||
settings = self.paint_settings(context)
|
||||
brush = settings.brush
|
||||
|
||||
self.layout.prop(brush, "use_frontface_falloff",
|
||||
text=self.bl_label if self.is_popover else "")
|
||||
self.layout.prop(brush, "use_frontface_falloff", text=self.bl_label if self.is_popover else "")
|
||||
|
||||
def draw(self, context):
|
||||
settings = self.paint_settings(context)
|
||||
|
@ -956,8 +954,7 @@ class VIEW3D_PT_tools_brush_falloff_normal(View3DPaintPanel, Panel):
|
|||
tool_settings = context.tool_settings
|
||||
ipaint = tool_settings.image_paint
|
||||
|
||||
self.layout.prop(ipaint, "use_normal_falloff",
|
||||
text=self.bl_label if self.is_popover else "")
|
||||
self.layout.prop(ipaint, "use_normal_falloff", text=self.bl_label if self.is_popover else "")
|
||||
|
||||
def draw(self, context):
|
||||
tool_settings = context.tool_settings
|
||||
|
@ -1406,8 +1403,7 @@ class VIEW3D_PT_tools_imagepaint_options_cavity(Panel):
|
|||
tool_settings = context.tool_settings
|
||||
ipaint = tool_settings.image_paint
|
||||
|
||||
self.layout.prop(ipaint, "use_cavity",
|
||||
text=self.bl_label if self.is_popover else "")
|
||||
self.layout.prop(ipaint, "use_cavity", text=self.bl_label if self.is_popover else "")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
@ -1417,8 +1413,7 @@ class VIEW3D_PT_tools_imagepaint_options_cavity(Panel):
|
|||
|
||||
layout.active = ipaint.use_cavity
|
||||
|
||||
layout.template_curve_mapping(ipaint, "cavity_curve", brush=True,
|
||||
use_negative_slope=True)
|
||||
layout.template_curve_mapping(ipaint, "cavity_curve", brush=True, use_negative_slope=True)
|
||||
|
||||
|
||||
# TODO, move to space_view3d.py
|
||||
|
@ -1706,8 +1701,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_advanced(View3DPanel, Panel):
|
|||
|
||||
elif brush.gpencil_tool == 'FILL':
|
||||
row = col.row(align=True)
|
||||
row.prop(gp_settings, "fill_draw_mode", text="Boundary",
|
||||
text_ctxt=i18n_contexts.id_gpencil)
|
||||
row.prop(gp_settings, "fill_draw_mode", text="Boundary", text_ctxt=i18n_contexts.id_gpencil)
|
||||
row.prop(
|
||||
gp_settings,
|
||||
"show_fill_boundary",
|
||||
|
@ -1771,8 +1765,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_stabilizer(Panel, View3DPanel):
|
|||
brush = context.tool_settings.gpencil_paint.brush
|
||||
gp_settings = brush.gpencil_settings
|
||||
self.layout.use_property_split = False
|
||||
self.layout.prop(gp_settings, "use_settings_stabilizer",
|
||||
text=self.bl_label if self.is_popover else "")
|
||||
self.layout.prop(gp_settings, "use_settings_stabilizer", text=self.bl_label if self.is_popover else "")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
@ -1805,8 +1798,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_post_processing(View3DPanel, Panel):
|
|||
brush = context.tool_settings.gpencil_paint.brush
|
||||
gp_settings = brush.gpencil_settings
|
||||
self.layout.use_property_split = False
|
||||
self.layout.prop(gp_settings, "use_settings_postprocess",
|
||||
text=self.bl_label if self.is_popover else "")
|
||||
self.layout.prop(gp_settings, "use_settings_postprocess", text=self.bl_label if self.is_popover else "")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
@ -1861,8 +1853,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_random(View3DPanel, Panel):
|
|||
brush = context.tool_settings.gpencil_paint.brush
|
||||
gp_settings = brush.gpencil_settings
|
||||
self.layout.use_property_split = False
|
||||
self.layout.prop(gp_settings, "use_settings_random",
|
||||
text=self.bl_label if self.is_popover else "")
|
||||
self.layout.prop(gp_settings, "use_settings_random", text=self.bl_label if self.is_popover else "")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
@ -1882,24 +1873,21 @@ class VIEW3D_PT_tools_grease_pencil_brush_random(View3DPanel, Panel):
|
|||
row.prop(gp_settings, "use_stroke_random_radius", text="", icon='GP_SELECT_STROKES')
|
||||
row.prop(gp_settings, "use_random_press_radius", text="", icon='STYLUS_PRESSURE')
|
||||
if gp_settings.use_random_press_radius and self.is_popover is False:
|
||||
col.template_curve_mapping(gp_settings, "curve_random_pressure", brush=True,
|
||||
use_negative_slope=True)
|
||||
col.template_curve_mapping(gp_settings, "curve_random_pressure", brush=True, use_negative_slope=True)
|
||||
|
||||
row = col.row(align=True)
|
||||
row.prop(gp_settings, "random_strength", text="Strength", slider=True)
|
||||
row.prop(gp_settings, "use_stroke_random_strength", text="", icon='GP_SELECT_STROKES')
|
||||
row.prop(gp_settings, "use_random_press_strength", text="", icon='STYLUS_PRESSURE')
|
||||
if gp_settings.use_random_press_strength and self.is_popover is False:
|
||||
col.template_curve_mapping(gp_settings, "curve_random_strength", brush=True,
|
||||
use_negative_slope=True)
|
||||
col.template_curve_mapping(gp_settings, "curve_random_strength", brush=True, use_negative_slope=True)
|
||||
|
||||
row = col.row(align=True)
|
||||
row.prop(gp_settings, "uv_random", text="UV", slider=True)
|
||||
row.prop(gp_settings, "use_stroke_random_uv", text="", icon='GP_SELECT_STROKES')
|
||||
row.prop(gp_settings, "use_random_press_uv", text="", icon='STYLUS_PRESSURE')
|
||||
if gp_settings.use_random_press_uv and self.is_popover is False:
|
||||
col.template_curve_mapping(gp_settings, "curve_random_uv", brush=True,
|
||||
use_negative_slope=True)
|
||||
col.template_curve_mapping(gp_settings, "curve_random_uv", brush=True, use_negative_slope=True)
|
||||
|
||||
col.separator()
|
||||
|
||||
|
@ -1910,24 +1898,21 @@ class VIEW3D_PT_tools_grease_pencil_brush_random(View3DPanel, Panel):
|
|||
row.prop(gp_settings, "use_stroke_random_hue", text="", icon='GP_SELECT_STROKES')
|
||||
row.prop(gp_settings, "use_random_press_hue", text="", icon='STYLUS_PRESSURE')
|
||||
if gp_settings.use_random_press_hue and self.is_popover is False:
|
||||
col1.template_curve_mapping(gp_settings, "curve_random_hue", brush=True,
|
||||
use_negative_slope=True)
|
||||
col1.template_curve_mapping(gp_settings, "curve_random_hue", brush=True, use_negative_slope=True)
|
||||
|
||||
row = col1.row(align=True)
|
||||
row.prop(gp_settings, "random_saturation_factor", slider=True)
|
||||
row.prop(gp_settings, "use_stroke_random_sat", text="", icon='GP_SELECT_STROKES')
|
||||
row.prop(gp_settings, "use_random_press_sat", text="", icon='STYLUS_PRESSURE')
|
||||
if gp_settings.use_random_press_sat and self.is_popover is False:
|
||||
col1.template_curve_mapping(gp_settings, "curve_random_saturation", brush=True,
|
||||
use_negative_slope=True)
|
||||
col1.template_curve_mapping(gp_settings, "curve_random_saturation", brush=True, use_negative_slope=True)
|
||||
|
||||
row = col1.row(align=True)
|
||||
row.prop(gp_settings, "random_value_factor", slider=True)
|
||||
row.prop(gp_settings, "use_stroke_random_val", text="", icon='GP_SELECT_STROKES')
|
||||
row.prop(gp_settings, "use_random_press_val", text="", icon='STYLUS_PRESSURE')
|
||||
if gp_settings.use_random_press_val and self.is_popover is False:
|
||||
col1.template_curve_mapping(gp_settings, "curve_random_value", brush=True,
|
||||
use_negative_slope=True)
|
||||
col1.template_curve_mapping(gp_settings, "curve_random_value", brush=True, use_negative_slope=True)
|
||||
|
||||
col.separator()
|
||||
|
||||
|
@ -1935,8 +1920,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_random(View3DPanel, Panel):
|
|||
row.prop(gp_settings, "pen_jitter", slider=True)
|
||||
row.prop(gp_settings, "use_jitter_pressure", text="", icon='STYLUS_PRESSURE')
|
||||
if gp_settings.use_jitter_pressure and self.is_popover is False:
|
||||
col.template_curve_mapping(gp_settings, "curve_jitter", brush=True,
|
||||
use_negative_slope=True)
|
||||
col.template_curve_mapping(gp_settings, "curve_jitter", brush=True, use_negative_slope=True)
|
||||
|
||||
|
||||
class VIEW3D_PT_tools_grease_pencil_brush_paint_falloff(GreasePencilBrushFalloff, Panel, View3DPaintPanel):
|
||||
|
|
|
@ -138,7 +138,7 @@ class AssetLibrary {
|
|||
* Remove an asset from the library that was added using #add_external_asset() or
|
||||
* #add_local_id_asset(). Can usually be expected to be constant time complexity (worst case may
|
||||
* differ).
|
||||
* \note This is save to call if \a asset is freed (dangling reference), will not perform any
|
||||
* \note This is safe to call if \a asset is freed (dangling reference), will not perform any
|
||||
* change then.
|
||||
* \return True on success, false if the asset couldn't be found inside the library (also the
|
||||
* case when the reference is dangling).
|
||||
|
|
|
@ -207,14 +207,14 @@ AssetRepresentation &AssetLibrary::add_external_asset(StringRef relative_asset_p
|
|||
const int id_type,
|
||||
std::unique_ptr<AssetMetaData> metadata)
|
||||
{
|
||||
AssetIdentifier identifier = asset_identifier_from_library(relative_asset_path);
|
||||
AssetIdentifier identifier = this->asset_identifier_from_library(relative_asset_path);
|
||||
return asset_storage_->add_external_asset(
|
||||
std::move(identifier), name, id_type, std::move(metadata), *this);
|
||||
}
|
||||
|
||||
AssetRepresentation &AssetLibrary::add_local_id_asset(StringRef relative_asset_path, ID &id)
|
||||
{
|
||||
AssetIdentifier identifier = asset_identifier_from_library(relative_asset_path);
|
||||
AssetIdentifier identifier = this->asset_identifier_from_library(relative_asset_path);
|
||||
return asset_storage_->add_local_id_asset(std::move(identifier), id, *this);
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ bool AssetStorage::remove_asset(AssetRepresentation &asset)
|
|||
return external_assets_.remove_as(&asset);
|
||||
}
|
||||
|
||||
void AssetStorage::remap_ids_and_remove_invalid(const blender::bke::id::IDRemapper &mappings)
|
||||
void AssetStorage::remap_ids_and_remove_invalid(const bke::id::IDRemapper &mappings)
|
||||
{
|
||||
Set<AssetRepresentation *> removed_assets;
|
||||
|
||||
|
@ -61,7 +61,7 @@ void AssetStorage::remap_ids_and_remove_invalid(const blender::bke::id::IDRemapp
|
|||
}
|
||||
|
||||
for (AssetRepresentation *asset : removed_assets) {
|
||||
remove_asset(*asset);
|
||||
this->remove_asset(*asset);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -148,6 +148,7 @@ class Layer;
|
|||
bool is_selected() const; \
|
||||
void set_selected(bool selected); \
|
||||
bool use_onion_skinning() const; \
|
||||
bool use_masks() const; \
|
||||
bool is_child_of(const LayerGroup &group) const;
|
||||
|
||||
/* Implements the forwarding of the methods defined by #TREENODE_COMMON_METHODS. */
|
||||
|
@ -192,6 +193,10 @@ class Layer;
|
|||
{ \
|
||||
return this->as_node().use_onion_skinning(); \
|
||||
} \
|
||||
inline bool class_name::use_masks() const \
|
||||
{ \
|
||||
return this->as_node().use_masks(); \
|
||||
} \
|
||||
inline bool class_name::is_child_of(const LayerGroup &group) const \
|
||||
{ \
|
||||
return this->as_node().is_child_of(group); \
|
||||
|
@ -685,6 +690,11 @@ inline bool TreeNode::use_onion_skinning() const
|
|||
{
|
||||
return ((this->flag & GP_LAYER_TREE_NODE_USE_ONION_SKINNING) != 0);
|
||||
}
|
||||
inline bool TreeNode::use_masks() const
|
||||
{
|
||||
return ((this->flag & GP_LAYER_TREE_NODE_HIDE_MASKS) == 0) &&
|
||||
(!this->parent_group() || this->parent_group()->as_node().use_masks());
|
||||
}
|
||||
inline bool TreeNode::is_child_of(const LayerGroup &group) const
|
||||
{
|
||||
if (const LayerGroup *parent = this->parent_group()) {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_anim_data.hh"
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_customdata.hh"
|
||||
#include "BKE_deform.hh"
|
||||
|
@ -628,14 +629,12 @@ LayerMask::LayerMask()
|
|||
|
||||
LayerMask::LayerMask(StringRefNull name) : LayerMask()
|
||||
{
|
||||
this->layer_name = BLI_strdup(name.c_str());
|
||||
this->layer_name = BLI_strdup_null(name.c_str());
|
||||
}
|
||||
|
||||
LayerMask::LayerMask(const LayerMask &other) : LayerMask()
|
||||
{
|
||||
if (other.layer_name) {
|
||||
this->layer_name = BLI_strdup(other.layer_name);
|
||||
}
|
||||
this->layer_name = BLI_strdup_null(other.layer_name);
|
||||
this->flag = other.flag;
|
||||
}
|
||||
|
||||
|
@ -675,6 +674,7 @@ Layer::Layer()
|
|||
this->viewlayername = nullptr;
|
||||
|
||||
BLI_listbase_clear(&this->masks);
|
||||
this->active_mask_index = 0;
|
||||
|
||||
this->runtime = MEM_new<LayerRuntime>(__func__);
|
||||
}
|
||||
|
@ -688,7 +688,11 @@ Layer::Layer(const Layer &other) : Layer()
|
|||
{
|
||||
new (&this->base) TreeNode(other.base.wrap());
|
||||
|
||||
/* TODO: duplicate masks. */
|
||||
LISTBASE_FOREACH (GreasePencilLayerMask *, other_mask, &other.masks) {
|
||||
LayerMask *new_mask = MEM_new<LayerMask>(__func__, *reinterpret_cast<LayerMask *>(other_mask));
|
||||
BLI_addtail(&this->masks, reinterpret_cast<GreasePencilLayerMask *>(new_mask));
|
||||
}
|
||||
this->active_mask_index = other.active_mask_index;
|
||||
|
||||
this->blend_mode = other.blend_mode;
|
||||
this->opacity = other.opacity;
|
||||
|
@ -719,9 +723,9 @@ Layer::~Layer()
|
|||
MEM_SAFE_FREE(this->frames_storage.values);
|
||||
|
||||
LISTBASE_FOREACH_MUTABLE (GreasePencilLayerMask *, mask, &this->masks) {
|
||||
MEM_SAFE_FREE(mask->layer_name);
|
||||
MEM_freeN(mask);
|
||||
MEM_delete(reinterpret_cast<LayerMask *>(mask));
|
||||
}
|
||||
BLI_listbase_clear(&this->masks);
|
||||
|
||||
MEM_SAFE_FREE(this->parsubstr);
|
||||
MEM_SAFE_FREE(this->viewlayername);
|
||||
|
@ -2525,8 +2529,21 @@ void GreasePencil::rename_node(blender::bke::greasepencil::TreeNode &node,
|
|||
if (node.name() == new_name) {
|
||||
return;
|
||||
}
|
||||
node.set_name(node.is_layer() ? unique_layer_name(*this, new_name) :
|
||||
unique_layer_group_name(*this, new_name));
|
||||
std::string old_name = node.name();
|
||||
if (node.is_layer()) {
|
||||
node.set_name(unique_layer_name(*this, new_name));
|
||||
BKE_animdata_fix_paths_rename_all(&this->id, "layers", old_name.c_str(), node.name().c_str());
|
||||
for (bke::greasepencil::Layer *layer : this->layers_for_write()) {
|
||||
LISTBASE_FOREACH (GreasePencilLayerMask *, mask, &layer->masks) {
|
||||
if (STREQ(mask->layer_name, old_name.c_str())) {
|
||||
mask->layer_name = BLI_strdup(node.name().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (node.is_group()) {
|
||||
node.set_name(unique_layer_group_name(*this, new_name));
|
||||
}
|
||||
}
|
||||
|
||||
static void shrink_customdata(CustomData &data, const int index_to_remove, const int size)
|
||||
|
|
|
@ -400,6 +400,15 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b
|
|||
grease_pencil.id.properties = IDP_CopyProperty(gpd.id.properties);
|
||||
}
|
||||
|
||||
/** Convert Grease Pencil data flag. */
|
||||
SET_FLAG_FROM_TEST(
|
||||
grease_pencil.flag, (gpd.flag & GP_DATA_EXPAND) != 0, GREASE_PENCIL_ANIM_CHANNEL_EXPANDED);
|
||||
SET_FLAG_FROM_TEST(grease_pencil.flag,
|
||||
(gpd.flag & GP_DATA_AUTOLOCK_LAYERS) != 0,
|
||||
GREASE_PENCIL_AUTOLOCK_LAYERS);
|
||||
SET_FLAG_FROM_TEST(
|
||||
grease_pencil.flag, (gpd.draw_mode == GP_DRAWMODE_3D), GREASE_PENCIL_STROKE_ORDER_3D);
|
||||
|
||||
int num_drawings = 0;
|
||||
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd.layers) {
|
||||
num_drawings += BLI_listbase_count(&gpl->frames);
|
||||
|
@ -426,6 +435,8 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b
|
|||
SET_FLAG_FROM_TEST(new_layer.base.flag,
|
||||
(gpl->onion_flag & GP_LAYER_ONIONSKIN),
|
||||
GP_LAYER_TREE_NODE_USE_ONION_SKINNING);
|
||||
SET_FLAG_FROM_TEST(
|
||||
new_layer.base.flag, (gpl->flag & GP_LAYER_USE_MASK) == 0, GP_LAYER_TREE_NODE_HIDE_MASKS);
|
||||
|
||||
new_layer.blend_mode = int8_t(gpl->blend_mode);
|
||||
|
||||
|
@ -440,7 +451,7 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b
|
|||
|
||||
/* Convert the layer masks. */
|
||||
LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &gpl->mask_layers) {
|
||||
LayerMask *new_mask = MEM_new<LayerMask>(mask->name);
|
||||
LayerMask *new_mask = MEM_new<LayerMask>(__func__, mask->name);
|
||||
new_mask->flag = mask->flag;
|
||||
BLI_addtail(&new_layer.masks, new_mask);
|
||||
}
|
||||
|
|
|
@ -1190,7 +1190,7 @@ void blo_do_versions_290(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
|
||||
if (md->type == eModifierType_Boolean) {
|
||||
BooleanModifierData *bmd = (BooleanModifierData *)md;
|
||||
bmd->solver = eBooleanModifierSolver_Fast;
|
||||
bmd->solver = eBooleanModifierSolver_Float;
|
||||
bmd->flag = eBooleanModifierFlag_Object;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ void cryptomatte_clear_samples(FilmSample dst)
|
|||
int layer_len = imageSize(cryptomatte_img).z;
|
||||
for (int i = 0; i < layer_len; i++) {
|
||||
imageStore(cryptomatte_img, ivec3(dst.texel, i), vec4(0.0));
|
||||
/* Ensure stores are visible to later reads. */
|
||||
imageFence(cryptomatte_img);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,4 +73,6 @@ void cryptomatte_store_film_sample(FilmSample dst,
|
|||
imageStore(cryptomatte_img, img_co, sample_pair);
|
||||
break;
|
||||
}
|
||||
/* Ensure stores are visible to later reads. */
|
||||
imageFence(cryptomatte_img);
|
||||
}
|
||||
|
|
|
@ -61,6 +61,8 @@ void cryptomatte_store_samples(ivec2 texel, int layer, vec2 samples[CRYPTOMATTE_
|
|||
pass_sample.zw = samples[p * 2 + 1];
|
||||
imageStore(cryptomatte_img, ivec3(texel, p + layer_id), pass_sample);
|
||||
}
|
||||
/* Ensure stores are visible to later reads. */
|
||||
imageFence(cryptomatte_img);
|
||||
}
|
||||
|
||||
void main()
|
||||
|
|
|
@ -142,17 +142,10 @@ void film_sample_accum_combined(FilmSample samp, inout vec4 accum, inout float w
|
|||
weight_accum += weight;
|
||||
}
|
||||
|
||||
#ifdef GPU_METAL
|
||||
void film_sample_cryptomatte_accum(FilmSample samp,
|
||||
int layer,
|
||||
sampler2D tex,
|
||||
thread vec2 *crypto_samples)
|
||||
#else
|
||||
void film_sample_cryptomatte_accum(FilmSample samp,
|
||||
int layer,
|
||||
sampler2D tex,
|
||||
inout vec2 crypto_samples[4])
|
||||
#endif
|
||||
{
|
||||
float hash = texelFetch(tex, samp.texel, 0)[layer];
|
||||
/* Find existing entry. */
|
||||
|
@ -247,11 +240,7 @@ vec2 film_pixel_history_motion_vector(ivec2 texel_sample)
|
|||
/* \a t is inter-pixel position. 0 means perfectly on a pixel center.
|
||||
* Returns weights in both dimensions.
|
||||
* Multiply each dimension weights to get final pixel weights. */
|
||||
#ifdef GPU_METAL
|
||||
void film_get_catmull_rom_weights(vec2 t, thread vec2 *weights)
|
||||
#else
|
||||
void film_get_catmull_rom_weights(vec2 t, out vec2 weights[4])
|
||||
#endif
|
||||
{
|
||||
vec2 t2 = t * t;
|
||||
vec2 t3 = t2 * t;
|
||||
|
|
|
@ -136,6 +136,13 @@ SphericalHarmonicL1 lightprobe_irradiance_sample(
|
|||
#ifdef IRRADIANCE_GRID_SAMPLING
|
||||
float random = interlieved_gradient_noise(UTIL_TEXEL, 0.0, 0.0);
|
||||
random = fract(random + sampling_rng_1D_get(SAMPLING_LIGHTPROBE));
|
||||
#endif
|
||||
#ifdef GPU_METAL
|
||||
/* NOTE: Performs a chunked unroll to avoid the compiler unrolling the entire loop, avoiding
|
||||
* very high instruction counts and long compilation time. Full unroll results in 90k +
|
||||
* instructions. Chunked unroll is 5.1k instructions with reduced register pressure, while
|
||||
* retaining most of the benefits of unrolling. */
|
||||
# pragma clang loop unroll_count(16)
|
||||
#endif
|
||||
for (; i < IRRADIANCE_GRID_MAX; i++) {
|
||||
/* Last grid is tagged as invalid to stop the iteration. */
|
||||
|
|
|
@ -17,7 +17,7 @@ void main()
|
|||
|
||||
int frame = gl_VertexID + cacheStart;
|
||||
bool use_custom_color = customColor.x >= 0.0;
|
||||
finalColor = (use_custom_color) ? vec4(customColor, 1.0) : vec4(1.0);
|
||||
finalColor = (use_custom_color) ? vec4(customColor, 1.0) : colorVertex;
|
||||
|
||||
/* Bias to reduce z fighting with the path */
|
||||
gl_Position.z -= 1e-4;
|
||||
|
|
|
@ -221,27 +221,30 @@ AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
|
|||
|
||||
/* apart from strictly keyframe-related contexts, this shouldn't even happen */
|
||||
/* XXX: nla and channel here may not be necessary... */
|
||||
if (ELEM(ac->datatype,
|
||||
ANIMCONT_ACTION,
|
||||
ANIMCONT_SHAPEKEY,
|
||||
ANIMCONT_DOPESHEET,
|
||||
ANIMCONT_FCURVES,
|
||||
ANIMCONT_NLA,
|
||||
ANIMCONT_CHANNEL,
|
||||
ANIMCONT_TIMELINE))
|
||||
if (!ELEM(ac->datatype,
|
||||
ANIMCONT_ACTION,
|
||||
ANIMCONT_SHAPEKEY,
|
||||
ANIMCONT_DOPESHEET,
|
||||
ANIMCONT_FCURVES,
|
||||
ANIMCONT_NLA,
|
||||
ANIMCONT_CHANNEL,
|
||||
ANIMCONT_TIMELINE))
|
||||
{
|
||||
/* handling depends on the type of animation-context we've got */
|
||||
if (ale) {
|
||||
/* NLA Control Curves occur on NLA strips,
|
||||
* and shouldn't be subjected to this kind of mapping. */
|
||||
if (ale->type != ANIMTYPE_NLACURVE) {
|
||||
return ale->adt;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* cannot handle... */
|
||||
return nullptr;
|
||||
/* handling depends on the type of animation-context we've got */
|
||||
if (!ale) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* NLA Control Curves occur on NLA strips,
|
||||
* and shouldn't be subjected to this kind of mapping. */
|
||||
if (ale->type == ANIMTYPE_NLACURVE) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ale->adt;
|
||||
}
|
||||
|
||||
/* ------------------- */
|
||||
|
|
|
@ -524,6 +524,169 @@ static void GREASE_PENCIL_OT_layer_duplicate(wmOperatorType *ot)
|
|||
/* properties */
|
||||
RNA_def_boolean(ot->srna, "empty_keyframes", false, "Empty Keyframes", "Add Empty Keyframes");
|
||||
}
|
||||
|
||||
static int grease_pencil_layer_mask_add_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
using namespace ::blender::bke::greasepencil;
|
||||
Object *object = CTX_data_active_object(C);
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
|
||||
|
||||
if (!grease_pencil.has_active_layer()) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
Layer &active_layer = *grease_pencil.get_active_layer();
|
||||
|
||||
int mask_name_length;
|
||||
char *mask_name = RNA_string_get_alloc(op->ptr, "name", nullptr, 0, &mask_name_length);
|
||||
BLI_SCOPED_DEFER([&] { MEM_SAFE_FREE(mask_name); });
|
||||
|
||||
if (TreeNode *node = grease_pencil.find_node_by_name(mask_name)) {
|
||||
if (grease_pencil.is_layer_active(&node->as_layer())) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Cannot add active layer as mask");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if (BLI_findstring(&active_layer.masks,
|
||||
mask_name,
|
||||
offsetof(GreasePencilLayerMask, layer_name)) != nullptr)
|
||||
{
|
||||
BKE_report(op->reports, RPT_ERROR, "Layer already added");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
LayerMask *new_mask = MEM_new<LayerMask>(__func__, mask_name);
|
||||
BLI_addtail(&active_layer.masks, reinterpret_cast<GreasePencilLayerMask *>(new_mask));
|
||||
/* Make the newly added mask active. */
|
||||
active_layer.active_mask_index = BLI_listbase_count(&active_layer.masks) - 1;
|
||||
}
|
||||
else {
|
||||
BKE_report(op->reports, RPT_ERROR, "Unable to find layer to add");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, &grease_pencil);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void GREASE_PENCIL_OT_layer_mask_add(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Add New Mask Layer";
|
||||
ot->idname = "GREASE_PENCIL_OT_layer_mask_add";
|
||||
ot->description = "Add new layer as masking";
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = grease_pencil_layer_mask_add_exec;
|
||||
ot->poll = active_grease_pencil_layer_poll;
|
||||
|
||||
/* properties */
|
||||
RNA_def_string(ot->srna, "name", nullptr, 0, "Layer", "Name of the layer");
|
||||
}
|
||||
|
||||
static int grease_pencil_layer_mask_remove_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
using namespace ::blender::bke::greasepencil;
|
||||
Object *object = CTX_data_active_object(C);
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
|
||||
|
||||
if (!grease_pencil.has_active_layer()) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
Layer &active_layer = *grease_pencil.get_active_layer();
|
||||
if (GreasePencilLayerMask *mask = reinterpret_cast<GreasePencilLayerMask *>(
|
||||
BLI_findlink(&active_layer.masks, active_layer.active_mask_index)))
|
||||
{
|
||||
BLI_remlink(&active_layer.masks, mask);
|
||||
MEM_delete(reinterpret_cast<LayerMask *>(mask));
|
||||
active_layer.active_mask_index = std::max(active_layer.active_mask_index - 1, 0);
|
||||
}
|
||||
else {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, &grease_pencil);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void GREASE_PENCIL_OT_layer_mask_remove(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Remove Mask Layer";
|
||||
ot->idname = "GREASE_PENCIL_OT_layer_mask_remove";
|
||||
ot->description = "Remove Layer Mask";
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = grease_pencil_layer_mask_remove_exec;
|
||||
ot->poll = active_grease_pencil_layer_poll;
|
||||
}
|
||||
|
||||
enum class LayerMaskMoveDirection : int8_t { Up = -1, Down = 1 };
|
||||
|
||||
static int grease_pencil_layer_mask_reorder_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
using namespace ::blender::bke::greasepencil;
|
||||
Object *object = CTX_data_active_object(C);
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
|
||||
|
||||
if (!grease_pencil.has_active_layer()) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
Layer &active_layer = *grease_pencil.get_active_layer();
|
||||
const int direction = RNA_enum_get(op->ptr, "direction");
|
||||
|
||||
bool changed = false;
|
||||
if (GreasePencilLayerMask *mask = reinterpret_cast<GreasePencilLayerMask *>(
|
||||
BLI_findlink(&active_layer.masks, active_layer.active_mask_index)))
|
||||
{
|
||||
if (BLI_listbase_link_move(&active_layer.masks, mask, direction)) {
|
||||
active_layer.active_mask_index = std::max(active_layer.active_mask_index + direction, 0);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, &grease_pencil);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void GREASE_PENCIL_OT_layer_mask_reorder(wmOperatorType *ot)
|
||||
{
|
||||
static const EnumPropertyItem enum_direction[] = {
|
||||
{int(LayerMaskMoveDirection::Up), "UP", 0, "Up", ""},
|
||||
{int(LayerMaskMoveDirection::Down), "DOWN", 0, "Down", ""},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
/* identifiers */
|
||||
ot->name = "Reorder Grease Pencil Layer Mask";
|
||||
ot->idname = "GREASE_PENCIL_OT_layer_mask_reorder";
|
||||
ot->description = "Reorder the active Grease Pencil mask layer up/down in the list";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = grease_pencil_layer_mask_reorder_exec;
|
||||
ot->poll = active_grease_pencil_layer_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
ot->prop = RNA_def_enum(ot->srna, "direction", enum_direction, 0, "Direction", "");
|
||||
}
|
||||
|
||||
} // namespace blender::ed::greasepencil
|
||||
|
||||
void ED_operatortypes_grease_pencil_layers()
|
||||
|
@ -540,4 +703,8 @@ void ED_operatortypes_grease_pencil_layers()
|
|||
WM_operatortype_append(GREASE_PENCIL_OT_layer_duplicate);
|
||||
|
||||
WM_operatortype_append(GREASE_PENCIL_OT_layer_group_add);
|
||||
|
||||
WM_operatortype_append(GREASE_PENCIL_OT_layer_mask_add);
|
||||
WM_operatortype_append(GREASE_PENCIL_OT_layer_mask_remove);
|
||||
WM_operatortype_append(GREASE_PENCIL_OT_layer_mask_reorder);
|
||||
}
|
||||
|
|
|
@ -1441,6 +1441,10 @@ ARegion *UI_tooltip_create_from_button_or_extra_icon(
|
|||
}
|
||||
BLI_rcti_rctf_copy_round(&init_rect, &overlap_rect_fl);
|
||||
}
|
||||
else if (but->type == UI_BTYPE_LABEL && BLI_rctf_size_y(&but->rect) > UI_UNIT_Y) {
|
||||
init_position[0] = win->eventstate->xy[0];
|
||||
init_position[1] = win->eventstate->xy[1] - (UI_POPUP_MARGIN / 2);
|
||||
}
|
||||
else {
|
||||
init_position[0] = BLI_rctf_cent_x(&but->rect);
|
||||
init_position[1] = but->rect.ymin;
|
||||
|
|
|
@ -255,6 +255,27 @@ class LayerViewItem : public AbstractTreeViewItem {
|
|||
PointerRNA layer_ptr = RNA_pointer_create(&grease_pencil_.id, &RNA_GreasePencilLayer, &layer_);
|
||||
|
||||
uiBlock *block = uiLayoutGetBlock(&row);
|
||||
|
||||
const int icon = (layer_.base.flag & GP_LAYER_TREE_NODE_HIDE_MASKS) == 0 ? ICON_CLIPUV_DEHLT :
|
||||
ICON_CLIPUV_HLT;
|
||||
but = uiDefIconButR(block,
|
||||
UI_BTYPE_ICON_TOGGLE,
|
||||
0,
|
||||
icon,
|
||||
0,
|
||||
0,
|
||||
UI_UNIT_X,
|
||||
UI_UNIT_Y,
|
||||
&layer_ptr,
|
||||
"use_masks",
|
||||
0,
|
||||
0.0f,
|
||||
0.0f,
|
||||
nullptr);
|
||||
if (layer_.parent_group().use_masks()) {
|
||||
UI_but_flag_enable(but, UI_BUT_INACTIVE);
|
||||
}
|
||||
|
||||
but = uiDefIconButR(block,
|
||||
UI_BTYPE_ICON_TOGGLE,
|
||||
0,
|
||||
|
@ -359,6 +380,9 @@ class LayerGroupViewItem : public AbstractTreeViewItem {
|
|||
PointerRNA group_ptr = RNA_pointer_create(
|
||||
&grease_pencil_.id, &RNA_GreasePencilLayerGroup, &group_);
|
||||
|
||||
const int icon = (group_.base.flag & GP_LAYER_TREE_NODE_HIDE_MASKS) == 0 ? ICON_CLIPUV_DEHLT :
|
||||
ICON_CLIPUV_HLT;
|
||||
uiItemR(&row, &group_ptr, "use_masks", UI_ITEM_R_ICON_ONLY, nullptr, icon);
|
||||
uiItemR(&row, &group_ptr, "hide", UI_ITEM_R_ICON_ONLY, nullptr, ICON_NONE);
|
||||
uiItemR(&row, &group_ptr, "lock", UI_ITEM_R_ICON_ONLY, nullptr, ICON_NONE);
|
||||
}
|
||||
|
|
|
@ -457,10 +457,16 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op)
|
|||
|
||||
BKE_sculpt_mask_layers_ensure(nullptr, nullptr, ob, nullptr);
|
||||
|
||||
bool create_new_object = RNA_boolean_get(op->ptr, "new_object");
|
||||
bool fill_holes = RNA_boolean_get(op->ptr, "fill_holes");
|
||||
float mask_threshold = RNA_float_get(op->ptr, "mask_threshold");
|
||||
|
||||
Mesh *mesh = static_cast<Mesh *>(ob->data);
|
||||
Mesh *new_mesh = (Mesh *)BKE_id_copy(bmain, &mesh->id);
|
||||
|
||||
if (ob->mode == OB_MODE_SCULPT) {
|
||||
/* Fix for #87243 */
|
||||
/* Undo crashes when new object is created in the middle of a sculpt */
|
||||
if (ob->mode == OB_MODE_SCULPT && !create_new_object) {
|
||||
sculpt_paint::undo::geometry_begin(ob, op);
|
||||
}
|
||||
|
||||
|
@ -473,15 +479,14 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op)
|
|||
mesh_to_bm_params.calc_face_normal = true;
|
||||
BM_mesh_bm_from_me(bm, new_mesh, &mesh_to_bm_params);
|
||||
|
||||
slice_paint_mask(
|
||||
bm, false, RNA_boolean_get(op->ptr, "fill_holes"), RNA_float_get(op->ptr, "mask_threshold"));
|
||||
slice_paint_mask(bm, false, fill_holes, mask_threshold);
|
||||
BKE_id_free(bmain, new_mesh);
|
||||
BMeshToMeshParams bm_to_mesh_params{};
|
||||
bm_to_mesh_params.calc_object_remap = false;
|
||||
new_mesh = BKE_mesh_from_bmesh_nomain(bm, &bm_to_mesh_params, mesh);
|
||||
BM_mesh_free(bm);
|
||||
|
||||
if (RNA_boolean_get(op->ptr, "new_object")) {
|
||||
if (create_new_object) {
|
||||
ushort local_view_bits = 0;
|
||||
if (v3d && v3d->localvd) {
|
||||
local_view_bits = v3d->local_view_uid;
|
||||
|
@ -495,10 +500,7 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op)
|
|||
|
||||
BM_mesh_bm_from_me(bm, new_ob_mesh, &mesh_to_bm_params);
|
||||
|
||||
slice_paint_mask(bm,
|
||||
true,
|
||||
RNA_boolean_get(op->ptr, "fill_holes"),
|
||||
RNA_float_get(op->ptr, "mask_threshold"));
|
||||
slice_paint_mask(bm, true, fill_holes, mask_threshold);
|
||||
BKE_id_free(bmain, new_ob_mesh);
|
||||
new_ob_mesh = BKE_mesh_from_bmesh_nomain(bm, &bm_to_mesh_params, mesh);
|
||||
BM_mesh_free(bm);
|
||||
|
@ -524,7 +526,9 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op)
|
|||
const int next_face_set_id = sculpt_paint::face_set::find_next_available_id(*ob);
|
||||
sculpt_paint::face_set::initialize_none_to_id(mesh, next_face_set_id);
|
||||
}
|
||||
sculpt_paint::undo::geometry_end(ob);
|
||||
if (!create_new_object) {
|
||||
sculpt_paint::undo::geometry_end(ob);
|
||||
}
|
||||
}
|
||||
|
||||
BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL);
|
||||
|
|
|
@ -99,7 +99,7 @@ void enable_ex(Main *bmain, Depsgraph *depsgraph, Object *ob)
|
|||
BM_mesh_bm_from_me(ss->bm, mesh, &convert_params);
|
||||
triangulate(ss->bm);
|
||||
|
||||
BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
|
||||
BM_data_layer_ensure_named(ss->bm, &ss->bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
|
||||
|
||||
/* Make sure the data for existing faces are initialized. */
|
||||
if (mesh->faces_num != ss->bm->totface) {
|
||||
|
|
|
@ -1293,6 +1293,10 @@ void file_draw_list(const bContext *C, ARegion *region)
|
|||
nullptr);
|
||||
UI_but_dragflag_enable(drag_but, UI_BUT_DRAG_FULL_BUT);
|
||||
file_but_enable_drag(drag_but, sfile, file, path, nullptr, icon, UI_SCALE_FAC);
|
||||
UI_but_func_tooltip_custom_set(drag_but,
|
||||
file_draw_tooltip_custom_func,
|
||||
file_tooltip_data_create(sfile, file),
|
||||
MEM_freeN);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ set(INC
|
|||
.
|
||||
../blenkernel
|
||||
../blentranslation
|
||||
../bmesh
|
||||
../functions
|
||||
../makesrna
|
||||
../../../intern/eigen
|
||||
|
@ -124,6 +125,10 @@ if(WITH_GMP)
|
|||
list(APPEND INC_SYS
|
||||
${GMP_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
list(APPEND LIB
|
||||
${GMP_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
blender_add_lib(bf_geometry "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
||||
|
|
|
@ -6,29 +6,77 @@
|
|||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_mesh_boolean.hh"
|
||||
#include "BLI_span.hh"
|
||||
|
||||
struct Mesh;
|
||||
|
||||
namespace blender::meshintersect {
|
||||
namespace blender::geometry::boolean {
|
||||
|
||||
/** Specifies which solver to use. */
|
||||
enum class Solver {
|
||||
/**
|
||||
* The exact solver based on the Mesh Arrangments for Solid Geometry paper,
|
||||
* by Zhou, Grinspun, Zorin, and Jacobson.
|
||||
*/
|
||||
MeshArr = 0,
|
||||
/** The original BMesh floating point solver. */
|
||||
Float = 1,
|
||||
};
|
||||
|
||||
enum class Operation {
|
||||
Intersect = 0,
|
||||
Union = 1,
|
||||
Difference = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* Do a mesh boolean operation directly on meshes (without going back and forth from BMesh).
|
||||
* BooleanOpParameters bundles together the global parameters for the boolean operation.
|
||||
* As well as saying which particular operation (intersect, difference, union) is desired,
|
||||
* it also states some assumptions that the algorithm is allowed to make about the input
|
||||
* (e.g., whether or not there are any self intersections).
|
||||
*/
|
||||
struct BooleanOpParameters {
|
||||
Operation boolean_mode;
|
||||
/** Can we assume there are no self-intersections in any of the operands? */
|
||||
bool no_self_intersections = true;
|
||||
/** Can we assume there are no nested components (e.g., a box inside a box) in any of the
|
||||
* components? */
|
||||
bool no_nested_components = true;
|
||||
/** Can we assume the argument meshes are watertight volume enclosing? */
|
||||
bool watertight = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Do a mesh boolean operation directly on meshes.
|
||||
* Boolean operations operate on the volumes enclosed by the operands.
|
||||
* If is only one operand, the non-float versions will do self-intersection and remove
|
||||
* internal faces.
|
||||
* If there are more than two meshes, the first mesh is operand 0 and the rest of the
|
||||
* meshes are operand 1 (i.e., as if all of operands 1, ... are joined into one mesh.
|
||||
* The exact solvers assume that the meshes are PWN (piecewise winding number,
|
||||
* which approximately means that the meshes are enclosed watertight voluems,
|
||||
* and all edges are manifold, though there are allowable exceptions to that last condition).
|
||||
* If the meshes don't sastisfy those conditions, all solvers will try to use ray-shooting
|
||||
* to determine whether particular faces survive or not. This may or may not work
|
||||
* in the way the user hopes.
|
||||
*
|
||||
* \param meshes: The meshes that are operands of the boolean operation.
|
||||
* \param transforms: An array of transform matrices used for each mesh's positions.
|
||||
* \param target_transform: the result needs to be transformed by this.
|
||||
* \param material_remaps: An array of maps from material slot numbers in the corresponding mesh
|
||||
* to the material slot in the first mesh. It is OK for material_remaps or any of its constituent
|
||||
* arrays to be empty. A -1 value means that the original index should be used with no mapping.
|
||||
* \param r_intersecting_edges: Array to store indices of edges on the resulting mesh in. These
|
||||
* \param op_params: Specifies the boolean operation and assumptions we can make.
|
||||
* \param solver: which solver to use
|
||||
* \param r_intersecting_edges: Vector to store indices of edges on the resulting mesh in. These
|
||||
* 'new' edges are the result of the intersections.
|
||||
*/
|
||||
Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
|
||||
Span<float4x4> transforms,
|
||||
const float4x4 &target_transform,
|
||||
Span<Array<short>> material_remaps,
|
||||
bool use_self,
|
||||
bool hole_tolerant,
|
||||
int boolean_mode,
|
||||
Vector<int> *r_intersecting_edges);
|
||||
Mesh *mesh_boolean(Span<const Mesh *> meshes,
|
||||
Span<float4x4> transforms,
|
||||
const float4x4 &target_transform,
|
||||
Span<Array<short>> material_remaps,
|
||||
BooleanOpParameters op_params,
|
||||
Solver solver,
|
||||
Vector<int> *r_intersecting_edges);
|
||||
|
||||
} // namespace blender::meshintersect
|
||||
} // namespace blender::geometry::boolean
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
|
@ -25,9 +21,20 @@
|
|||
#include "BLI_task.hh"
|
||||
#include "BLI_virtual_array.hh"
|
||||
|
||||
#include "DNA_node_types.h"
|
||||
|
||||
#include "GEO_mesh_boolean.hh"
|
||||
|
||||
namespace blender::meshintersect {
|
||||
#include "bmesh.hh"
|
||||
#include "bmesh_tools.hh"
|
||||
#include "tools/bmesh_boolean.hh"
|
||||
#include "tools/bmesh_intersect.hh"
|
||||
|
||||
namespace blender::geometry::boolean {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Mesh Arrangements (Old Exact Boolean)
|
||||
* \{ */
|
||||
|
||||
#ifdef WITH_GMP
|
||||
|
||||
|
@ -78,9 +85,9 @@ class MeshesToIMeshInfo {
|
|||
Array<int> mesh_face_offset;
|
||||
/* For each Mesh vertex in all the meshes (with concatenated indexing),
|
||||
* what is the IMesh Vert* allocated for it in the input IMesh? */
|
||||
Array<const Vert *> mesh_to_imesh_vert;
|
||||
Array<const meshintersect::Vert *> mesh_to_imesh_vert;
|
||||
/* Similarly for each Mesh face. */
|
||||
Array<Face *> mesh_to_imesh_face;
|
||||
Array<meshintersect::Face *> mesh_to_imesh_face;
|
||||
/* Transformation matrix to transform a coordinate in the corresponding
|
||||
* Mesh to the local space of the first Mesh. */
|
||||
Array<float4x4> to_target_transform;
|
||||
|
@ -230,12 +237,12 @@ void MeshesToIMeshInfo::input_medge_for_orig_index(int orig_index,
|
|||
* correspondence between the Mesh MVerts/MPolys and the IMesh Verts/Faces.
|
||||
* All allocation of memory for the IMesh comes from `arena`.
|
||||
*/
|
||||
static IMesh meshes_to_imesh(Span<const Mesh *> meshes,
|
||||
Span<float4x4> obmats,
|
||||
Span<Array<short>> material_remaps,
|
||||
const float4x4 &target_transform,
|
||||
IMeshArena &arena,
|
||||
MeshesToIMeshInfo *r_info)
|
||||
static meshintersect::IMesh meshes_to_imesh(Span<const Mesh *> meshes,
|
||||
Span<float4x4> obmats,
|
||||
Span<Array<short>> material_remaps,
|
||||
const float4x4 &target_transform,
|
||||
meshintersect::IMeshArena &arena,
|
||||
MeshesToIMeshInfo *r_info)
|
||||
{
|
||||
int nmeshes = meshes.size();
|
||||
BLI_assert(nmeshes > 0);
|
||||
|
@ -272,7 +279,7 @@ static IMesh meshes_to_imesh(Span<const Mesh *> meshes,
|
|||
/* Put these Vectors here, with a size unlikely to need resizing,
|
||||
* so that the loop to make new Faces will likely not need to allocate
|
||||
* over and over. */
|
||||
Vector<const Vert *, estimated_max_facelen> face_vert;
|
||||
Vector<const meshintersect::Vert *, estimated_max_facelen> face_vert;
|
||||
Vector<int, estimated_max_facelen> face_edge_orig;
|
||||
|
||||
/* To convert the coordinates of meshes 1, 2, etc. into the local space
|
||||
|
@ -303,7 +310,7 @@ static IMesh meshes_to_imesh(Span<const Mesh *> meshes,
|
|||
* that would have a negative transform if you do that. */
|
||||
bool need_face_flip = r_info->has_negative_transform[mi] != r_info->has_negative_transform[0];
|
||||
|
||||
Vector<Vert *> verts(mesh->verts_num);
|
||||
Vector<meshintersect::Vert *> verts(mesh->verts_num);
|
||||
const Span<float3> vert_positions = mesh->vert_positions();
|
||||
const OffsetIndices faces = mesh->faces();
|
||||
const Span<int> corner_verts = mesh->corner_verts();
|
||||
|
@ -319,7 +326,7 @@ static IMesh meshes_to_imesh(Span<const Mesh *> meshes,
|
|||
float3 co = vert_positions[i];
|
||||
mpq3 mco = mpq3(co.x, co.y, co.z);
|
||||
double3 dco(mco[0].get_d(), mco[1].get_d(), mco[2].get_d());
|
||||
verts[i] = new Vert(mco, dco, NO_INDEX, i);
|
||||
verts[i] = new meshintersect::Vert(mco, dco, meshintersect::NO_INDEX, i);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -329,7 +336,7 @@ static IMesh meshes_to_imesh(Span<const Mesh *> meshes,
|
|||
float3 co = math::transform_point(r_info->to_target_transform[mi], vert_positions[i]);
|
||||
mpq3 mco = mpq3(co.x, co.y, co.z);
|
||||
double3 dco(mco[0].get_d(), mco[1].get_d(), mco[2].get_d());
|
||||
verts[i] = new Vert(mco, dco, NO_INDEX, i);
|
||||
verts[i] = new meshintersect::Vert(mco, dco, meshintersect::NO_INDEX, i);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -346,7 +353,7 @@ static IMesh meshes_to_imesh(Span<const Mesh *> meshes,
|
|||
for (int i = 0; i < flen; ++i) {
|
||||
const int corner_i = face[i];
|
||||
int mverti = r_info->mesh_vert_offset[mi] + corner_verts[corner_i];
|
||||
const Vert *fv = r_info->mesh_to_imesh_vert[mverti];
|
||||
const meshintersect::Vert *fv = r_info->mesh_to_imesh_vert[mverti];
|
||||
if (need_face_flip) {
|
||||
face_vert[flen - i - 1] = fv;
|
||||
int iedge = i < flen - 1 ? flen - i - 2 : flen - 1;
|
||||
|
@ -362,7 +369,7 @@ static IMesh meshes_to_imesh(Span<const Mesh *> meshes,
|
|||
}
|
||||
e += mesh->edges_num;
|
||||
}
|
||||
return IMesh(r_info->mesh_to_imesh_face);
|
||||
return meshintersect::IMesh(r_info->mesh_to_imesh_face);
|
||||
}
|
||||
|
||||
/* Copy vertex attributes, including customdata, from `orig_mv` to `mv`.
|
||||
|
@ -460,7 +467,7 @@ static void copy_edge_attributes(Mesh *dest_mesh,
|
|||
* For now, we only try to do this if `face` and `orig_face` have the same size.
|
||||
* Return the number of non-null MLoops filled in.
|
||||
*/
|
||||
static int fill_orig_loops(const Face *f,
|
||||
static int fill_orig_loops(const meshintersect::Face *f,
|
||||
const IndexRange orig_face,
|
||||
const Mesh *orig_me,
|
||||
int orig_me_index,
|
||||
|
@ -482,7 +489,7 @@ static int fill_orig_loops(const Face *f,
|
|||
* aligned loops is only an optimization to avoid some re-interpolation.
|
||||
*/
|
||||
int first_orig_v = f->vert[0]->orig;
|
||||
if (first_orig_v == NO_INDEX) {
|
||||
if (first_orig_v == meshintersect::NO_INDEX) {
|
||||
return 0;
|
||||
}
|
||||
/* It is possible that the original vert was merged with another in another mesh. */
|
||||
|
@ -509,20 +516,20 @@ static int fill_orig_loops(const Face *f,
|
|||
int orig_mp_loop_index = (mp_loop_index + offset) % orig_mplen;
|
||||
const int vert_i = orig_corner_verts[orig_face.start() + orig_mp_loop_index];
|
||||
int fv_orig = f->vert[mp_loop_index]->orig;
|
||||
if (fv_orig != NO_INDEX) {
|
||||
if (fv_orig != meshintersect::NO_INDEX) {
|
||||
fv_orig -= orig_me_vert_offset;
|
||||
if (fv_orig < 0 || fv_orig >= orig_me->verts_num) {
|
||||
fv_orig = NO_INDEX;
|
||||
fv_orig = meshintersect::NO_INDEX;
|
||||
}
|
||||
}
|
||||
if (vert_i == fv_orig) {
|
||||
const int vert_next =
|
||||
orig_corner_verts[orig_face.start() + ((orig_mp_loop_index + 1) % orig_mplen)];
|
||||
int fvnext_orig = f->vert[(mp_loop_index + 1) % orig_mplen]->orig;
|
||||
if (fvnext_orig != NO_INDEX) {
|
||||
if (fvnext_orig != meshintersect::NO_INDEX) {
|
||||
fvnext_orig -= orig_me_vert_offset;
|
||||
if (fvnext_orig < 0 || fvnext_orig >= orig_me->verts_num) {
|
||||
fvnext_orig = NO_INDEX;
|
||||
fvnext_orig = meshintersect::NO_INDEX;
|
||||
}
|
||||
}
|
||||
if (vert_next == fvnext_orig) {
|
||||
|
@ -562,7 +569,7 @@ static void get_poly2d_cos(const Mesh *mesh,
|
|||
* copy the Loop attributes from corresponding loops to corresponding loops.
|
||||
* Otherwise, interpolate the Loop attributes in the face `orig_face`. */
|
||||
static void copy_or_interp_loop_attributes(Mesh *dest_mesh,
|
||||
const Face *f,
|
||||
const meshintersect::Face *f,
|
||||
const IndexRange face,
|
||||
const IndexRange orig_face,
|
||||
const Mesh *orig_me,
|
||||
|
@ -701,7 +708,7 @@ static void merge_edge_customdata_layers(Mesh *target, MeshesToIMeshInfo &mim)
|
|||
* Convert the output IMesh im to a Blender Mesh,
|
||||
* using the information in mim to get all the attributes right.
|
||||
*/
|
||||
static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
|
||||
static Mesh *imesh_to_mesh(meshintersect::IMesh *im, MeshesToIMeshInfo &mim)
|
||||
{
|
||||
constexpr int dbg_level = 0;
|
||||
|
||||
|
@ -709,7 +716,7 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
|
|||
int out_totvert = im->vert_size();
|
||||
int out_faces_num = im->face_size();
|
||||
int out_totloop = 0;
|
||||
for (const Face *f : im->faces()) {
|
||||
for (const meshintersect::Face *f : im->faces()) {
|
||||
out_totloop += f->size();
|
||||
}
|
||||
/* Will calculate edges later. */
|
||||
|
@ -720,8 +727,8 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
|
|||
/* Set the vertex coordinate values and other data. */
|
||||
MutableSpan<float3> positions = result->vert_positions_for_write();
|
||||
for (int vi : im->vert_index_range()) {
|
||||
const Vert *v = im->vert(vi);
|
||||
if (v->orig != NO_INDEX) {
|
||||
const meshintersect::Vert *v = im->vert(vi);
|
||||
if (v->orig != meshintersect::NO_INDEX) {
|
||||
const Mesh *orig_me;
|
||||
int index_in_orig_me;
|
||||
mim.input_mvert_for_orig_index(v->orig, &orig_me, &index_in_orig_me);
|
||||
|
@ -739,7 +746,7 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
|
|||
MutableSpan<int> dst_corner_verts = result->corner_verts_for_write();
|
||||
MutableSpan<int> dst_face_offsets = result->face_offsets_for_write();
|
||||
for (int fi : im->face_index_range()) {
|
||||
const Face *f = im->face(fi);
|
||||
const meshintersect::Face *f = im->face(fi);
|
||||
const Mesh *orig_me;
|
||||
int index_in_orig_me;
|
||||
int orig_me_index;
|
||||
|
@ -747,7 +754,7 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
|
|||
f->orig, &orig_me, &orig_me_index, &index_in_orig_me);
|
||||
dst_face_offsets[fi] = cur_loop_index;
|
||||
for (int j : f->index_range()) {
|
||||
const Vert *vf = f->vert[j];
|
||||
const meshintersect::Vert *vf = f->vert[j];
|
||||
const int vfi = im->lookup_vert(vf);
|
||||
dst_corner_verts[cur_loop_index] = vfi;
|
||||
++cur_loop_index;
|
||||
|
@ -779,10 +786,10 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
|
|||
const OffsetIndices dst_polys = result->faces();
|
||||
const Span<int> dst_corner_edges = result->corner_edges();
|
||||
for (int fi : im->face_index_range()) {
|
||||
const Face *f = im->face(fi);
|
||||
const meshintersect::Face *f = im->face(fi);
|
||||
const IndexRange face = dst_polys[fi];
|
||||
for (int j : f->index_range()) {
|
||||
if (f->edge_orig[j] != NO_INDEX) {
|
||||
if (f->edge_orig[j] != meshintersect::NO_INDEX) {
|
||||
const Mesh *orig_me;
|
||||
int index_in_orig_me;
|
||||
mim.input_medge_for_orig_index(f->edge_orig[j], &orig_me, &index_in_orig_me);
|
||||
|
@ -798,18 +805,29 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
|
|||
return result;
|
||||
}
|
||||
|
||||
#endif // WITH_GMP
|
||||
|
||||
Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
|
||||
Span<float4x4> transforms,
|
||||
const float4x4 &target_transform,
|
||||
Span<Array<short>> material_remaps,
|
||||
const bool use_self,
|
||||
const bool hole_tolerant,
|
||||
const int boolean_mode,
|
||||
Vector<int> *r_intersecting_edges)
|
||||
static meshintersect::BoolOpType operation_to_mesh_arr_mode(const Operation operation)
|
||||
{
|
||||
switch (operation) {
|
||||
case Operation::Intersect:
|
||||
return meshintersect::BoolOpType::Intersect;
|
||||
case Operation::Union:
|
||||
return meshintersect::BoolOpType::Union;
|
||||
case Operation::Difference:
|
||||
return meshintersect::BoolOpType::Difference;
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return meshintersect::BoolOpType::None;
|
||||
}
|
||||
|
||||
static Mesh *mesh_boolean_mesh_arr(Span<const Mesh *> meshes,
|
||||
Span<float4x4> transforms,
|
||||
const float4x4 &target_transform,
|
||||
Span<Array<short>> material_remaps,
|
||||
const bool use_self,
|
||||
const bool hole_tolerant,
|
||||
const meshintersect::BoolOpType boolean_mode,
|
||||
Vector<int> *r_intersecting_edges)
|
||||
{
|
||||
#ifdef WITH_GMP
|
||||
BLI_assert(transforms.is_empty() || meshes.size() == transforms.size());
|
||||
BLI_assert(material_remaps.is_empty() || material_remaps.size() == meshes.size());
|
||||
if (meshes.size() <= 0) {
|
||||
|
@ -818,11 +836,12 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
|
|||
|
||||
const int dbg_level = 0;
|
||||
if (dbg_level > 0) {
|
||||
std::cout << "\nDIRECT_MESH_INTERSECT, nmeshes = " << meshes.size() << "\n";
|
||||
std::cout << "\nOLD_MESH_INTERSECT, nmeshes = " << meshes.size() << "\n";
|
||||
}
|
||||
MeshesToIMeshInfo mim;
|
||||
IMeshArena arena;
|
||||
IMesh m_in = meshes_to_imesh(meshes, transforms, material_remaps, target_transform, arena, &mim);
|
||||
meshintersect::IMeshArena arena;
|
||||
meshintersect::IMesh m_in = meshes_to_imesh(
|
||||
meshes, transforms, material_remaps, target_transform, arena, &mim);
|
||||
std::function<int(int)> shape_fn = [&mim](int f) {
|
||||
for (int mi = 0; mi < mim.mesh_face_offset.size() - 1; ++mi) {
|
||||
if (f < mim.mesh_face_offset[mi + 1]) {
|
||||
|
@ -831,14 +850,8 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
|
|||
}
|
||||
return int(mim.mesh_face_offset.size()) - 1;
|
||||
};
|
||||
IMesh m_out = boolean_mesh(m_in,
|
||||
static_cast<BoolOpType>(boolean_mode),
|
||||
meshes.size(),
|
||||
shape_fn,
|
||||
use_self,
|
||||
hole_tolerant,
|
||||
nullptr,
|
||||
&arena);
|
||||
meshintersect::IMesh m_out = boolean_mesh(
|
||||
m_in, boolean_mode, meshes.size(), shape_fn, use_self, hole_tolerant, nullptr, &arena);
|
||||
if (dbg_level > 0) {
|
||||
std::cout << m_out;
|
||||
write_obj_mesh(m_out, "m_out");
|
||||
|
@ -851,7 +864,7 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
|
|||
const OffsetIndices faces = result->faces();
|
||||
const Span<int> corner_edges = result->corner_edges();
|
||||
for (int fi : m_out.face_index_range()) {
|
||||
const Face &face = *m_out.face(fi);
|
||||
const meshintersect::Face &face = *m_out.face(fi);
|
||||
const IndexRange mesh_face = faces[fi];
|
||||
for (int i : face.index_range()) {
|
||||
if (face.is_intersect[i]) {
|
||||
|
@ -863,17 +876,318 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
|
|||
}
|
||||
|
||||
return result;
|
||||
#else // WITH_GMP
|
||||
UNUSED_VARS(meshes,
|
||||
transforms,
|
||||
material_remaps,
|
||||
target_transform,
|
||||
use_self,
|
||||
hole_tolerant,
|
||||
boolean_mode,
|
||||
r_intersecting_edges);
|
||||
return nullptr;
|
||||
#endif // WITH_GMP
|
||||
}
|
||||
|
||||
} // namespace blender::meshintersect
|
||||
#endif // WITH_GMP
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Float Boolean
|
||||
* \{ */
|
||||
|
||||
/* has no meaning for faces, do this so we can tell which face is which */
|
||||
#define BM_FACE_TAG BM_ELEM_DRAW
|
||||
|
||||
/**
|
||||
* Function use to say what operand a face is part of, based on the `BM_FACE_TAG`,`
|
||||
* which is set in `bm_mesh_create`.
|
||||
*/
|
||||
static int face_boolean_operand(BMFace *f, void * /*user_data*/)
|
||||
{
|
||||
return BM_elem_flag_test(f, BM_FACE_TAG) ? 0 : 1;
|
||||
}
|
||||
|
||||
/* Create a BMesh that is the concatenation of the given meshes.
|
||||
* The corresponding mesh-to-world transformations are also given,
|
||||
* as well as a target_tranform.
|
||||
* A triangulation is also calculated and returned in the last two
|
||||
* parameters.
|
||||
* The faces of the first mesh are tagged with BM_FACE_TAG so that the
|
||||
* face_boolean_operand() function can distinguish those faces from the
|
||||
* rest.
|
||||
* The caller is responsible for using `BM_mesh_free` on the returned
|
||||
* BMesh, and calling `MEM_freeN` on the returned looptris.
|
||||
*
|
||||
* TODO: maybe figure out how to use the join_geometries() function
|
||||
* to join all the meshes into one mesh first, and then convert
|
||||
* that single mesh to BMesh. Issues with that include needing
|
||||
* to apply the transforms and material remaps.
|
||||
*/
|
||||
static BMesh *mesh_bm_concat(Span<const Mesh *> meshes,
|
||||
Span<float4x4> transforms,
|
||||
const float4x4 &target_transform,
|
||||
Span<Array<short>> material_remaps,
|
||||
BMLoop *(**r_looptris)[3],
|
||||
int *r_looptris_tot)
|
||||
{
|
||||
const int meshes_num = meshes.size();
|
||||
BLI_assert(meshes_num >= 1);
|
||||
bool ok;
|
||||
float4x4 inv_target_mat = math::invert(target_transform, ok);
|
||||
if (!ok) {
|
||||
BLI_assert_unreachable();
|
||||
inv_target_mat = float4x4::identity();
|
||||
}
|
||||
Array<float4x4> to_target(meshes_num);
|
||||
Array<bool> is_negative_transform(meshes_num);
|
||||
Array<bool> is_flip(meshes_num);
|
||||
const int tsize = transforms.size();
|
||||
for (const int i : IndexRange(meshes_num)) {
|
||||
if (tsize > i) {
|
||||
to_target[i] = inv_target_mat * transforms[i];
|
||||
is_negative_transform[i] = math::is_negative(transforms[i]);
|
||||
is_flip[i] = is_negative_transform[i] != is_negative_transform[0];
|
||||
}
|
||||
else {
|
||||
to_target[i] = inv_target_mat;
|
||||
is_negative_transform[i] = false;
|
||||
is_flip[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make a BMesh that will be a concatenation of the elements of all the meshes */
|
||||
BMAllocTemplate allocsize;
|
||||
allocsize.totvert = 0;
|
||||
allocsize.totedge = 0;
|
||||
allocsize.totloop = 0;
|
||||
allocsize.totface = 0;
|
||||
for (const int i : meshes.index_range()) {
|
||||
allocsize.totvert += meshes[i]->verts_num;
|
||||
allocsize.totedge += meshes[i]->edges_num;
|
||||
allocsize.totloop += meshes[i]->corners_num;
|
||||
allocsize.totface += meshes[i]->faces_num;
|
||||
}
|
||||
|
||||
BMeshCreateParams bmesh_create_params{};
|
||||
BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params);
|
||||
|
||||
BM_mesh_copy_init_customdata_from_mesh_array(
|
||||
bm, const_cast<const Mesh **>(meshes.begin()), meshes_num, &allocsize);
|
||||
|
||||
BMeshFromMeshParams bmesh_from_mesh_params{};
|
||||
bmesh_from_mesh_params.calc_face_normal = true;
|
||||
bmesh_from_mesh_params.calc_vert_normal = true;
|
||||
|
||||
Array<int> verts_end(meshes_num);
|
||||
Array<int> faces_end(meshes_num);
|
||||
verts_end[0] = meshes[0]->verts_num;
|
||||
faces_end[0] = meshes[0]->faces_num;
|
||||
for (const int i : meshes.index_range()) {
|
||||
/* Append meshes[i] elements and data to bm. */
|
||||
BM_mesh_bm_from_me(bm, meshes[i], &bmesh_from_mesh_params);
|
||||
if (i > 0) {
|
||||
verts_end[i] = verts_end[i - 1] + meshes[i]->verts_num;
|
||||
faces_end[i] = faces_end[i - 1] + meshes[i]->faces_num;
|
||||
if (is_flip[i]) {
|
||||
/* Need to flip face normals to match that of mesh[0]. */
|
||||
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
|
||||
BM_mesh_elem_table_ensure(bm, BM_FACE);
|
||||
for (int j = faces_end[i - 1]; j < faces_end[i]; j++) {
|
||||
BMFace *efa = bm->ftable[j];
|
||||
BM_face_normal_flip_ex(bm, efa, cd_loop_mdisp_offset, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Make a triangulation of all polys before transforming vertices
|
||||
* so we can use the original normals. */
|
||||
const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
|
||||
BMLoop *(*looptris)[3] = (BMLoop * (*)[3])
|
||||
MEM_malloc_arrayN(looptris_tot, sizeof(*looptris), __func__);
|
||||
BM_mesh_calc_tessellation_beauty(bm, looptris);
|
||||
*r_looptris = looptris;
|
||||
*r_looptris_tot = looptris_tot;
|
||||
|
||||
/* Tranform the vertices that into the desired target_transform space. */
|
||||
BMIter iter;
|
||||
BMVert *eve;
|
||||
int i = 0;
|
||||
int mesh_index = 0;
|
||||
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
|
||||
copy_v3_v3(eve->co, math::transform_point(to_target[mesh_index], float3(eve->co)));
|
||||
++i;
|
||||
if (i == verts_end[mesh_index]) {
|
||||
mesh_index++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Transform face normals and tag the first-operand faces.
|
||||
* Also, apply material remaps. */
|
||||
BMFace *efa;
|
||||
i = 0;
|
||||
mesh_index = 0;
|
||||
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
|
||||
copy_v3_v3(efa->no, math::transform_direction(to_target[mesh_index], float3(efa->no)));
|
||||
if (is_negative_transform[mesh_index]) {
|
||||
negate_v3(efa->no);
|
||||
}
|
||||
normalize_v3(efa->no);
|
||||
|
||||
/* Temp tag used in `face_boolean_operand()` to test for operand 0. */
|
||||
if (i < faces_end[0]) {
|
||||
BM_elem_flag_enable(efa, BM_FACE_TAG);
|
||||
}
|
||||
|
||||
/* Remap material. */
|
||||
int cur_mat = efa->mat_nr;
|
||||
if (cur_mat < material_remaps[mesh_index].size()) {
|
||||
int new_mat = material_remaps[mesh_index][cur_mat];
|
||||
if (new_mat >= 0) {
|
||||
efa->mat_nr = material_remaps[mesh_index][cur_mat];
|
||||
}
|
||||
}
|
||||
|
||||
++i;
|
||||
if (i == faces_end[mesh_index]) {
|
||||
mesh_index++;
|
||||
}
|
||||
}
|
||||
|
||||
return bm;
|
||||
}
|
||||
|
||||
static int operation_to_float_mode(const Operation operation)
|
||||
{
|
||||
switch (operation) {
|
||||
case Operation::Intersect:
|
||||
return BMESH_ISECT_BOOLEAN_ISECT;
|
||||
case Operation::Union:
|
||||
return BMESH_ISECT_BOOLEAN_UNION;
|
||||
case Operation::Difference:
|
||||
return BMESH_ISECT_BOOLEAN_DIFFERENCE;
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return BMESH_ISECT_BOOLEAN_NONE;
|
||||
}
|
||||
|
||||
static Mesh *mesh_boolean_float(Span<const Mesh *> meshes,
|
||||
Span<float4x4> transforms,
|
||||
const float4x4 &target_transform,
|
||||
Span<Array<short>> material_remaps,
|
||||
const int boolean_mode,
|
||||
Vector<int> * /*r_intersecting_edges*/)
|
||||
{
|
||||
BLI_assert(meshes.size() == transforms.size() || transforms.size() == 0);
|
||||
BLI_assert(material_remaps.size() == 0 || material_remaps.size() == meshes.size());
|
||||
if (meshes.is_empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (meshes.size() == 1) {
|
||||
/* The float solver doesn't do self union. Just return nullptr, which will
|
||||
* cause geometry nodes to leave the input as is. */
|
||||
return BKE_mesh_copy_for_eval(meshes[0]);
|
||||
}
|
||||
|
||||
BMLoop *(*looptris)[3];
|
||||
int looptris_tot;
|
||||
if (meshes.size() == 2) {
|
||||
BMesh *bm = mesh_bm_concat(
|
||||
meshes, transforms, target_transform, material_remaps, &looptris, &looptris_tot);
|
||||
BM_mesh_intersect(bm,
|
||||
looptris,
|
||||
looptris_tot,
|
||||
face_boolean_operand,
|
||||
nullptr,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
boolean_mode,
|
||||
1e-6f);
|
||||
MEM_freeN(looptris);
|
||||
Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, meshes[0]);
|
||||
BM_mesh_free(bm);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Iteratively operate with each operand. */
|
||||
Array<const Mesh *> two_meshes = {meshes[0], meshes[1]};
|
||||
Array<float4x4> two_transforms = {transforms[0], transforms[1]};
|
||||
Array<Array<short>> two_remaps = {material_remaps[0], material_remaps[1]};
|
||||
Mesh *prev_result_mesh = nullptr;
|
||||
for (const int i : meshes.index_range().drop_back(1)) {
|
||||
BMesh *bm = mesh_bm_concat(
|
||||
two_meshes, two_transforms, float4x4::identity(), two_remaps, &looptris, &looptris_tot);
|
||||
BM_mesh_intersect(bm,
|
||||
looptris,
|
||||
looptris_tot,
|
||||
face_boolean_operand,
|
||||
nullptr,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
boolean_mode,
|
||||
1e-6f);
|
||||
MEM_freeN(looptris);
|
||||
Mesh *result_i_mesh = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, meshes[0]);
|
||||
BM_mesh_free(bm);
|
||||
if (prev_result_mesh != nullptr) {
|
||||
/* Except in the first iteration, two_meshes[0] holds the intermediate
|
||||
* mesh result from the previous iteraiton. */
|
||||
BKE_mesh_eval_delete(prev_result_mesh);
|
||||
}
|
||||
if (i < meshes.size() - 2) {
|
||||
two_meshes[0] = result_i_mesh;
|
||||
two_meshes[1] = meshes[i + 2];
|
||||
two_transforms[0] = float4x4::identity();
|
||||
two_transforms[1] = transforms[i + 2];
|
||||
two_remaps[0] = {};
|
||||
two_remaps[1] = material_remaps[i + 2];
|
||||
prev_result_mesh = result_i_mesh;
|
||||
}
|
||||
else {
|
||||
return result_i_mesh;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert_unreachable();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
Mesh *mesh_boolean(Span<const Mesh *> meshes,
|
||||
Span<float4x4> transforms,
|
||||
const float4x4 &target_transform,
|
||||
Span<Array<short>> material_remaps,
|
||||
BooleanOpParameters op_params,
|
||||
Solver solver,
|
||||
Vector<int> *r_intersecting_edges)
|
||||
{
|
||||
|
||||
switch (solver) {
|
||||
case Solver::Float:
|
||||
return mesh_boolean_float(meshes,
|
||||
transforms,
|
||||
target_transform,
|
||||
material_remaps,
|
||||
operation_to_float_mode(op_params.boolean_mode),
|
||||
r_intersecting_edges);
|
||||
case Solver::MeshArr:
|
||||
#ifdef WITH_GMP
|
||||
return mesh_boolean_mesh_arr(meshes,
|
||||
transforms,
|
||||
target_transform,
|
||||
material_remaps,
|
||||
!op_params.no_self_intersections,
|
||||
!op_params.watertight,
|
||||
operation_to_mesh_arr_mode(op_params.boolean_mode),
|
||||
r_intersecting_edges);
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace blender::geometry::boolean
|
||||
|
|
|
@ -366,6 +366,9 @@ struct SStruct {
|
|||
#define imageStore(_tex, _coord, _value) _texture_write_internal(_tex, _coord, _value)
|
||||
#define imageStoreFast(_tex, _coord, _value) _texture_write_internal_fast(_tex, _coord, _value)
|
||||
|
||||
/* Texture synchronization functions. */
|
||||
#define imageFence(image) image.texture->fence()
|
||||
|
||||
/* Singular return values from texture functions of type DEPTH are often indexed with either .r or
|
||||
* .x. This is a lightweight wrapper type for handling this syntax. */
|
||||
union _msl_return_float {
|
||||
|
|
|
@ -83,6 +83,9 @@
|
|||
#define isampler2DAtomic isampler2D
|
||||
#define isampler3DAtomic isampler3D
|
||||
|
||||
/* Pass through functions. */
|
||||
#define imageFence(image)
|
||||
|
||||
/* Backend Functions. */
|
||||
#define select(A, B, mask) mix(A, B, mask)
|
||||
|
||||
|
|
|
@ -648,6 +648,10 @@ ImBuf *IMB_dupImBuf(const ImBuf *ibuf1)
|
|||
tbuf.display_buffer_flags = nullptr;
|
||||
tbuf.colormanage_cache = nullptr;
|
||||
|
||||
/* GPU textures can not be easily copied, as it is not guaranteed that this function is called
|
||||
* from within an active GPU context. */
|
||||
tbuf.gpu.texture = nullptr;
|
||||
|
||||
*ibuf2 = tbuf;
|
||||
|
||||
return ibuf2;
|
||||
|
|
|
@ -448,7 +448,7 @@ static void colormanage_cache_handle_release(void *cache_handle)
|
|||
/** \name Initialization / De-initialization
|
||||
* \{ */
|
||||
|
||||
static void colormanage_role_color_space_name_get(OCIO_ConstConfigRcPtr *config,
|
||||
static bool colormanage_role_color_space_name_get(OCIO_ConstConfigRcPtr *config,
|
||||
char *colorspace_name,
|
||||
const char *role,
|
||||
const char *backup_role)
|
||||
|
@ -457,56 +457,56 @@ static void colormanage_role_color_space_name_get(OCIO_ConstConfigRcPtr *config,
|
|||
|
||||
ociocs = OCIO_configGetColorSpace(config, role);
|
||||
|
||||
if (!ociocs && backup_role) {
|
||||
if (ociocs == nullptr && backup_role) {
|
||||
ociocs = OCIO_configGetColorSpace(config, backup_role);
|
||||
}
|
||||
|
||||
if (ociocs) {
|
||||
const char *name = OCIO_colorSpaceGetName(ociocs);
|
||||
if (ociocs == nullptr) {
|
||||
/* Overall fallback role. */
|
||||
ociocs = OCIO_configGetColorSpace(config, "default");
|
||||
}
|
||||
|
||||
/* assume function was called with buffer properly allocated to MAX_COLORSPACE_NAME chars */
|
||||
BLI_strncpy(colorspace_name, name, MAX_COLORSPACE_NAME);
|
||||
OCIO_colorSpaceRelease(ociocs);
|
||||
}
|
||||
else {
|
||||
printf("Color management: Error could not find role %s role.\n", role);
|
||||
if (ociocs == nullptr) {
|
||||
printf("Color management: Error, could not find role \"%s\"\n", role);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *name = OCIO_colorSpaceGetName(ociocs);
|
||||
|
||||
/* assume function was called with buffer properly allocated to MAX_COLORSPACE_NAME chars */
|
||||
BLI_strncpy(colorspace_name, name, MAX_COLORSPACE_NAME);
|
||||
OCIO_colorSpaceRelease(ociocs);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
|
||||
static bool colormanage_load_config(OCIO_ConstConfigRcPtr *config)
|
||||
{
|
||||
int tot_colorspace, tot_display, tot_display_view, tot_looks;
|
||||
int index, viewindex, viewindex2;
|
||||
const char *name;
|
||||
bool ok = true;
|
||||
|
||||
/* get roles */
|
||||
colormanage_role_color_space_name_get(config, global_role_data, OCIO_ROLE_DATA, nullptr);
|
||||
colormanage_role_color_space_name_get(
|
||||
ok &= colormanage_role_color_space_name_get(config, global_role_data, OCIO_ROLE_DATA, nullptr);
|
||||
ok &= colormanage_role_color_space_name_get(
|
||||
config, global_role_scene_linear, OCIO_ROLE_SCENE_LINEAR, nullptr);
|
||||
colormanage_role_color_space_name_get(
|
||||
ok &= colormanage_role_color_space_name_get(
|
||||
config, global_role_color_picking, OCIO_ROLE_COLOR_PICKING, nullptr);
|
||||
colormanage_role_color_space_name_get(
|
||||
ok &= colormanage_role_color_space_name_get(
|
||||
config, global_role_texture_painting, OCIO_ROLE_TEXTURE_PAINT, nullptr);
|
||||
colormanage_role_color_space_name_get(
|
||||
ok &= colormanage_role_color_space_name_get(
|
||||
config, global_role_default_sequencer, OCIO_ROLE_DEFAULT_SEQUENCER, OCIO_ROLE_SCENE_LINEAR);
|
||||
colormanage_role_color_space_name_get(
|
||||
ok &= colormanage_role_color_space_name_get(
|
||||
config, global_role_default_byte, OCIO_ROLE_DEFAULT_BYTE, OCIO_ROLE_TEXTURE_PAINT);
|
||||
colormanage_role_color_space_name_get(
|
||||
ok &= colormanage_role_color_space_name_get(
|
||||
config, global_role_default_float, OCIO_ROLE_DEFAULT_FLOAT, OCIO_ROLE_SCENE_LINEAR);
|
||||
|
||||
/* load colorspaces */
|
||||
tot_colorspace = OCIO_configGetNumColorSpaces(config);
|
||||
for (index = 0; index < tot_colorspace; index++) {
|
||||
OCIO_ConstColorSpaceRcPtr *ocio_colorspace;
|
||||
const char *description;
|
||||
bool is_invertible, is_data;
|
||||
const int tot_colorspace = OCIO_configGetNumColorSpaces(config);
|
||||
for (int index = 0; index < tot_colorspace; index++) {
|
||||
const char *name = OCIO_configGetColorSpaceNameByIndex(config, index);
|
||||
|
||||
name = OCIO_configGetColorSpaceNameByIndex(config, index);
|
||||
|
||||
ocio_colorspace = OCIO_configGetColorSpace(config, name);
|
||||
description = OCIO_colorSpaceGetDescription(ocio_colorspace);
|
||||
is_invertible = OCIO_colorSpaceIsInvertible(ocio_colorspace);
|
||||
is_data = OCIO_colorSpaceIsData(ocio_colorspace);
|
||||
OCIO_ConstColorSpaceRcPtr *ocio_colorspace = OCIO_configGetColorSpace(config, name);
|
||||
const char *description = OCIO_colorSpaceGetDescription(ocio_colorspace);
|
||||
const bool is_invertible = OCIO_colorSpaceIsInvertible(ocio_colorspace);
|
||||
const bool is_data = OCIO_colorSpaceIsData(ocio_colorspace);
|
||||
|
||||
ColorSpace *colorspace = colormanage_colorspace_add(name, description, is_invertible, is_data);
|
||||
|
||||
|
@ -525,51 +525,49 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
|
|||
}
|
||||
|
||||
/* load displays */
|
||||
viewindex2 = 0;
|
||||
tot_display = OCIO_configGetNumDisplays(config);
|
||||
const int tot_display = OCIO_configGetNumDisplays(config);
|
||||
int viewindex2 = 0;
|
||||
|
||||
for (index = 0; index < tot_display; index++) {
|
||||
const char *displayname;
|
||||
ColorManagedDisplay *display;
|
||||
for (int index = 0; index < tot_display; index++) {
|
||||
const char *displayname = OCIO_configGetDisplay(config, index);
|
||||
|
||||
displayname = OCIO_configGetDisplay(config, index);
|
||||
|
||||
display = colormanage_display_add(displayname);
|
||||
ColorManagedDisplay *display = colormanage_display_add(displayname);
|
||||
|
||||
/* load views */
|
||||
tot_display_view = OCIO_configGetNumViews(config, displayname);
|
||||
for (viewindex = 0; viewindex < tot_display_view; viewindex++, viewindex2++) {
|
||||
const char *viewname;
|
||||
ColorManagedView *view;
|
||||
LinkData *display_view;
|
||||
|
||||
viewname = OCIO_configGetView(config, displayname, viewindex);
|
||||
const int tot_display_view = OCIO_configGetNumViews(config, displayname);
|
||||
for (int viewindex = 0; viewindex < tot_display_view; viewindex++, viewindex2++) {
|
||||
const char *viewname = OCIO_configGetView(config, displayname, viewindex);
|
||||
|
||||
/* first check if view transform with given name was already loaded */
|
||||
view = colormanage_view_get_named(viewname);
|
||||
ColorManagedView *view = colormanage_view_get_named(viewname);
|
||||
|
||||
if (!view) {
|
||||
view = colormanage_view_add(viewname);
|
||||
}
|
||||
|
||||
display_view = BLI_genericNodeN(view);
|
||||
LinkData *display_view = BLI_genericNodeN(view);
|
||||
|
||||
BLI_addtail(&display->views, display_view);
|
||||
}
|
||||
}
|
||||
|
||||
global_tot_display = tot_display;
|
||||
if (global_tot_display == 0) {
|
||||
printf("Color management: Error, could not find any displays\n");
|
||||
ok = false;
|
||||
}
|
||||
else if (global_tot_view == 0) {
|
||||
printf("Color management: Error, could not find any views\n");
|
||||
ok = false;
|
||||
}
|
||||
|
||||
/* load looks */
|
||||
tot_looks = OCIO_configGetNumLooks(config);
|
||||
const int tot_looks = OCIO_configGetNumLooks(config);
|
||||
colormanage_look_add("None", "", true);
|
||||
for (index = 0; index < tot_looks; index++) {
|
||||
OCIO_ConstLookRcPtr *ocio_look;
|
||||
const char *process_space;
|
||||
|
||||
name = OCIO_configGetLookNameByIndex(config, index);
|
||||
ocio_look = OCIO_configGetLook(config, name);
|
||||
process_space = OCIO_lookGetProcessSpace(ocio_look);
|
||||
for (int index = 0; index < tot_looks; index++) {
|
||||
const char *name = OCIO_configGetLookNameByIndex(config, index);
|
||||
OCIO_ConstLookRcPtr *ocio_look = OCIO_configGetLook(config, name);
|
||||
const char *process_space = OCIO_lookGetProcessSpace(ocio_look);
|
||||
OCIO_lookRelease(ocio_look);
|
||||
|
||||
colormanage_look_add(name, process_space, false);
|
||||
|
@ -587,6 +585,8 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
|
|||
|
||||
mul_m3_m3m3(imbuf_aces_to_scene_linear, imbuf_xyz_to_scene_linear, OCIO_ACES_TO_XYZ);
|
||||
invert_m3_m3(imbuf_scene_linear_to_aces, imbuf_aces_to_scene_linear);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void colormanage_free_config()
|
||||
|
@ -645,60 +645,61 @@ static void colormanage_free_config()
|
|||
/* free looks */
|
||||
BLI_freelistN(&global_looks);
|
||||
global_tot_looks = 0;
|
||||
|
||||
OCIO_exit();
|
||||
}
|
||||
|
||||
void colormanagement_init()
|
||||
{
|
||||
const char *ocio_env;
|
||||
char configfile[FILE_MAX];
|
||||
OCIO_ConstConfigRcPtr *config = nullptr;
|
||||
|
||||
OCIO_init();
|
||||
|
||||
ocio_env = BLI_getenv("OCIO");
|
||||
/* First try config from environment variable. */
|
||||
const char *ocio_env = BLI_getenv("OCIO");
|
||||
|
||||
if (ocio_env && ocio_env[0] != '\0') {
|
||||
config = OCIO_configCreateFromEnv();
|
||||
if (config != nullptr) {
|
||||
printf("Color management: Using %s as a configuration file\n", ocio_env);
|
||||
|
||||
OCIO_setCurrentConfig(config);
|
||||
const bool ok = colormanage_load_config(config);
|
||||
OCIO_configRelease(config);
|
||||
|
||||
if (!ok) {
|
||||
printf("Color management: Failed to load config from environment\n");
|
||||
colormanage_free_config();
|
||||
config = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Then try bunded config file. */
|
||||
if (config == nullptr) {
|
||||
const std::optional<std::string> configdir = BKE_appdir_folder_id(BLENDER_DATAFILES,
|
||||
"colormanagement");
|
||||
|
||||
if (configdir.has_value()) {
|
||||
char configfile[FILE_MAX];
|
||||
BLI_path_join(configfile, sizeof(configfile), configdir->c_str(), BCM_CONFIG_FILE);
|
||||
|
||||
config = OCIO_configCreateFromFile(configfile);
|
||||
|
||||
if (config != nullptr) {
|
||||
OCIO_setCurrentConfig(config);
|
||||
const bool ok = colormanage_load_config(config);
|
||||
OCIO_configRelease(config);
|
||||
|
||||
if (!ok) {
|
||||
printf("Color management: Failed to load bundled config\n");
|
||||
colormanage_free_config();
|
||||
config = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Then use fallback. */
|
||||
if (config == nullptr) {
|
||||
printf("Color management: using fallback mode for management\n");
|
||||
|
||||
config = OCIO_configCreateFallback();
|
||||
}
|
||||
|
||||
if (config) {
|
||||
OCIO_setCurrentConfig(config);
|
||||
|
||||
colormanage_load_config(config);
|
||||
|
||||
OCIO_configRelease(config);
|
||||
}
|
||||
|
||||
/* If there are no valid display/views, use fallback mode. */
|
||||
if (global_tot_display == 0 || global_tot_view == 0) {
|
||||
printf("Color management: no displays/views in the config, using fallback mode instead\n");
|
||||
|
||||
/* Free old config. */
|
||||
colormanage_free_config();
|
||||
|
||||
/* Initialize fallback config. */
|
||||
printf("Color management: Using fallback mode for management\n");
|
||||
config = OCIO_configCreateFallback();
|
||||
colormanage_load_config(config);
|
||||
}
|
||||
|
@ -730,6 +731,7 @@ void colormanagement_exit()
|
|||
memset(&global_color_picking_state, 0, sizeof(global_color_picking_state));
|
||||
|
||||
colormanage_free_config();
|
||||
OCIO_exit();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -240,6 +240,7 @@ typedef enum GreasePencilLayerTreeNodeFlag {
|
|||
GP_LAYER_TREE_NODE_USE_LIGHTS = (1 << 4),
|
||||
GP_LAYER_TREE_NODE_USE_ONION_SKINNING = (1 << 5),
|
||||
GP_LAYER_TREE_NODE_EXPANDED = (1 << 6),
|
||||
GP_LAYER_TREE_NODE_HIDE_MASKS = (1 << 7),
|
||||
} GreasePencilLayerTreeNodeFlag;
|
||||
|
||||
struct GreasePencilLayerTreeGroup;
|
||||
|
@ -292,6 +293,8 @@ typedef struct GreasePencilLayer {
|
|||
* List of `GreasePencilLayerMask`.
|
||||
*/
|
||||
ListBase masks;
|
||||
int active_mask_index;
|
||||
char _pad2[4];
|
||||
/**
|
||||
* Layer parent object. Can be an armature in which case the `parsubstr` is the bone name.
|
||||
*/
|
||||
|
@ -302,7 +305,7 @@ typedef struct GreasePencilLayer {
|
|||
* Use the functions is the `bke::greasepencil::Layer` class instead.
|
||||
*/
|
||||
float translation[3], rotation[3], scale[3];
|
||||
char _pad2[4];
|
||||
char _pad3[4];
|
||||
/** Name of the view layer used to filter render output. */
|
||||
char *viewlayername;
|
||||
/**
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
.collection = NULL, \
|
||||
.double_threshold = 1e-6f, \
|
||||
.operation = eBooleanModifierOp_Difference, \
|
||||
.solver = eBooleanModifierSolver_Exact, \
|
||||
.solver = eBooleanModifierSolver_Mesh_Arr, \
|
||||
.flag = eBooleanModifierFlag_Object, \
|
||||
.bm_flag = 0, \
|
||||
}
|
||||
|
|
|
@ -983,8 +983,8 @@ typedef enum {
|
|||
|
||||
/** #BooleanModifierData.solver */
|
||||
typedef enum {
|
||||
eBooleanModifierSolver_Fast = 0,
|
||||
eBooleanModifierSolver_Exact = 1,
|
||||
eBooleanModifierSolver_Float = 0,
|
||||
eBooleanModifierSolver_Mesh_Arr = 1,
|
||||
} BooleanModifierSolver;
|
||||
|
||||
/** #BooleanModifierData.flag */
|
||||
|
|
|
@ -2655,12 +2655,6 @@ typedef enum GeometryNodeProximityTargetType {
|
|||
GEO_NODE_PROX_TARGET_FACES = 2,
|
||||
} GeometryNodeProximityTargetType;
|
||||
|
||||
typedef enum GeometryNodeBooleanOperation {
|
||||
GEO_NODE_BOOLEAN_INTERSECT = 0,
|
||||
GEO_NODE_BOOLEAN_UNION = 1,
|
||||
GEO_NODE_BOOLEAN_DIFFERENCE = 2,
|
||||
} GeometryNodeBooleanOperation;
|
||||
|
||||
typedef enum GeometryNodeCurvePrimitiveCircleMode {
|
||||
GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS = 0,
|
||||
GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS = 1
|
||||
|
|
|
@ -64,6 +64,60 @@ static void rna_grease_pencil_dependency_update(Main *bmain, Scene * /*scene*/,
|
|||
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, rna_grease_pencil(ptr));
|
||||
}
|
||||
|
||||
static void rna_grease_pencil_layer_mask_name_get(PointerRNA *ptr, char *dst)
|
||||
{
|
||||
using namespace blender;
|
||||
GreasePencilLayerMask *mask = static_cast<GreasePencilLayerMask *>(ptr->data);
|
||||
if (mask->layer_name != nullptr) {
|
||||
strcpy(dst, mask->layer_name);
|
||||
}
|
||||
else {
|
||||
dst[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static int rna_grease_pencil_layer_mask_name_length(PointerRNA *ptr)
|
||||
{
|
||||
using namespace blender;
|
||||
GreasePencilLayerMask *mask = static_cast<GreasePencilLayerMask *>(ptr->data);
|
||||
if (mask->layer_name != nullptr) {
|
||||
return strlen(mask->layer_name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rna_grease_pencil_layer_mask_name_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
using namespace blender;
|
||||
GreasePencil *grease_pencil = rna_grease_pencil(ptr);
|
||||
GreasePencilLayerMask *mask = static_cast<GreasePencilLayerMask *>(ptr->data);
|
||||
|
||||
const std::string oldname(mask->layer_name);
|
||||
if (bke::greasepencil::TreeNode *node = grease_pencil->find_node_by_name(oldname)) {
|
||||
grease_pencil->rename_node(*node, value);
|
||||
}
|
||||
}
|
||||
|
||||
static int rna_grease_pencil_active_mask_index_get(PointerRNA *ptr)
|
||||
{
|
||||
GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(ptr->data);
|
||||
return layer->active_mask_index;
|
||||
}
|
||||
|
||||
static void rna_grease_pencil_active_mask_index_set(PointerRNA *ptr, int value)
|
||||
{
|
||||
GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(ptr->data);
|
||||
layer->active_mask_index = value;
|
||||
}
|
||||
|
||||
static void rna_grease_pencil_active_mask_index_range(
|
||||
PointerRNA *ptr, int *min, int *max, int * /*softmin*/, int * /*softmax*/)
|
||||
{
|
||||
GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(ptr->data);
|
||||
*min = 0;
|
||||
*max = max_ii(0, BLI_listbase_count(&layer->masks) - 1);
|
||||
}
|
||||
|
||||
static void rna_iterator_grease_pencil_layers_begin(CollectionPropertyIterator *iter,
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
|
@ -229,6 +283,60 @@ static int rna_iterator_grease_pencil_layer_groups_length(PointerRNA *ptr)
|
|||
|
||||
#else
|
||||
|
||||
static void rna_def_grease_pencil_layers_mask_api(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
RNA_def_property_srna(cprop, "GreasePencilLayerMasks");
|
||||
srna = RNA_def_struct(brna, "GreasePencilLayerMasks", nullptr);
|
||||
RNA_def_struct_sdna(srna, "GreasePencilLayer");
|
||||
RNA_def_struct_ui_text(
|
||||
srna, "Grease Pencil Mask Layers", "Collection of grease pencil masking layers");
|
||||
|
||||
prop = RNA_def_property(srna, "active_mask_index", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_int_funcs(prop,
|
||||
"rna_grease_pencil_active_mask_index_get",
|
||||
"rna_grease_pencil_active_mask_index_set",
|
||||
"rna_grease_pencil_active_mask_index_range");
|
||||
RNA_def_property_ui_text(prop, "Active Layer Mask Index", "Active index in layer mask array");
|
||||
}
|
||||
|
||||
static void rna_def_grease_pencil_layer_mask(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "GreasePencilLayerMask", nullptr);
|
||||
RNA_def_struct_sdna(srna, "GreasePencilLayerMask");
|
||||
RNA_def_struct_ui_text(srna, "Grease Pencil Masking Layers", "List of Mask Layers");
|
||||
// RNA_def_struct_path_func(srna, "rna_GreasePencilLayerMask_path");
|
||||
|
||||
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Layer", "Mask layer name");
|
||||
RNA_def_property_string_sdna(prop, nullptr, "layer_name");
|
||||
RNA_def_property_string_funcs(prop,
|
||||
"rna_grease_pencil_layer_mask_name_get",
|
||||
"rna_grease_pencil_layer_mask_name_length",
|
||||
"rna_grease_pencil_layer_mask_name_set");
|
||||
RNA_def_struct_name_property(srna, prop);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_RENAME, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GP_LAYER_MASK_HIDE);
|
||||
RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1);
|
||||
RNA_def_property_ui_text(prop, "Hide", "Set mask Visibility");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "invert", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GP_LAYER_MASK_INVERT);
|
||||
RNA_def_property_ui_icon(prop, ICON_SELECT_INTERSECT, 1);
|
||||
RNA_def_property_ui_text(prop, "Invert", "Invert mask");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
}
|
||||
|
||||
static void rna_def_grease_pencil_layer(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
|
@ -236,6 +344,15 @@ static void rna_def_grease_pencil_layer(BlenderRNA *brna)
|
|||
|
||||
static const float scale_defaults[3] = {1.0f, 1.0f, 1.0f};
|
||||
|
||||
static const EnumPropertyItem rna_enum_layer_blend_modes_items[] = {
|
||||
{GP_LAYER_BLEND_NONE, "REGULAR", 0, "Regular", ""},
|
||||
{GP_LAYER_BLEND_HARDLIGHT, "HARDLIGHT", 0, "Hard Light", ""},
|
||||
{GP_LAYER_BLEND_ADD, "ADD", 0, "Add", ""},
|
||||
{GP_LAYER_BLEND_SUBTRACT, "SUBTRACT", 0, "Subtract", ""},
|
||||
{GP_LAYER_BLEND_MULTIPLY, "MULTIPLY", 0, "Multiply", ""},
|
||||
{GP_LAYER_BLEND_DIVIDE, "DIVIDE", 0, "Divide", ""},
|
||||
{0, nullptr, 0, nullptr, nullptr}};
|
||||
|
||||
srna = RNA_def_struct(brna, "GreasePencilLayer", nullptr);
|
||||
RNA_def_struct_sdna(srna, "GreasePencilLayer");
|
||||
RNA_def_struct_ui_text(srna, "Grease Pencil Layer", "Collection of related drawings");
|
||||
|
@ -251,6 +368,13 @@ static void rna_def_grease_pencil_layer(BlenderRNA *brna)
|
|||
RNA_def_struct_name_property(srna, prop);
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_RENAME, "rna_grease_pencil_update");
|
||||
|
||||
/* Mask Layers */
|
||||
prop = RNA_def_property(srna, "mask_layers", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_collection_sdna(prop, nullptr, "masks", nullptr);
|
||||
RNA_def_property_struct_type(prop, "GreasePencilLayerMask");
|
||||
RNA_def_property_ui_text(prop, "Masks", "List of Masking Layers");
|
||||
rna_def_grease_pencil_layers_mask_api(brna, prop);
|
||||
|
||||
/* Visibility */
|
||||
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(
|
||||
|
@ -282,6 +406,16 @@ static void rna_def_grease_pencil_layer(BlenderRNA *brna)
|
|||
prop, "Onion Skinning", "Display onion skins before and after the current frame");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
|
||||
/* Use Masks. */
|
||||
prop = RNA_def_property(srna, "use_masks", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(
|
||||
prop, "GreasePencilLayerTreeNode", "flag", GP_LAYER_TREE_NODE_HIDE_MASKS);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Use Masks",
|
||||
"The visibility of drawings on this layer is affected by the layers in its masks list");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
|
||||
/* pass index for compositing and modifiers */
|
||||
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_ui_text(prop, "Pass Index", "Index number for the \"Layer Index\" pass");
|
||||
|
@ -332,6 +466,12 @@ static void rna_def_grease_pencil_layer(BlenderRNA *brna)
|
|||
prop,
|
||||
"ViewLayer",
|
||||
"Only include Layer in this View Layer render output (leave blank to include always)");
|
||||
|
||||
prop = RNA_def_property(srna, "blend_mode", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, nullptr, "blend_mode");
|
||||
RNA_def_property_enum_items(prop, rna_enum_layer_blend_modes_items);
|
||||
RNA_def_property_ui_text(prop, "Blend Mode", "Blend mode");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
}
|
||||
|
||||
static void rna_def_grease_pencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
|
@ -392,6 +532,16 @@ static void rna_def_grease_pencil_layer_group(BlenderRNA *brna)
|
|||
RNA_def_property_ui_text(
|
||||
prop, "Locked", "Protect group from further editing and/or frame changes");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
|
||||
/* Use Masks. */
|
||||
prop = RNA_def_property(srna, "use_masks", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(
|
||||
prop, "GreasePencilLayerTreeNode", "flag", GP_LAYER_TREE_NODE_HIDE_MASKS);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Use Masks",
|
||||
"The visibility of drawings in the layers in this group is affected by "
|
||||
"the layers in the masks lists");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
}
|
||||
|
||||
static void rna_def_grease_pencil_data(BlenderRNA *brna)
|
||||
|
@ -399,6 +549,16 @@ static void rna_def_grease_pencil_data(BlenderRNA *brna)
|
|||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
static EnumPropertyItem prop_stroke_depth_order_items[] = {
|
||||
{0, "2D", 0, "2D Layers", "Display strokes using grease pencil layers to define order"},
|
||||
{GREASE_PENCIL_STROKE_ORDER_3D,
|
||||
"3D",
|
||||
0,
|
||||
"3D Location",
|
||||
"Display strokes using real 3D position in 3D space"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
srna = RNA_def_struct(brna, "GreasePencilv3", "ID");
|
||||
RNA_def_struct_sdna(srna, "GreasePencil");
|
||||
RNA_def_struct_ui_text(srna, "Grease Pencil", "Grease Pencil data-block");
|
||||
|
@ -462,12 +622,23 @@ static void rna_def_grease_pencil_data(BlenderRNA *brna)
|
|||
"Auto-Lock Layers",
|
||||
"Automatically lock all layers except the active one to avoid accidental changes");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_autolock");
|
||||
|
||||
/* Uses a single flag, because the depth order can only be 2D or 3D. */
|
||||
prop = RNA_def_property(srna, "stroke_depth_order", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_bitflag_sdna(prop, nullptr, "flag");
|
||||
RNA_def_property_enum_items(prop, prop_stroke_depth_order_items);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Stroke Depth Order",
|
||||
"Defines how the strokes are ordered in 3D space (for objects not displayed 'In Front')");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
}
|
||||
|
||||
void RNA_def_grease_pencil(BlenderRNA *brna)
|
||||
{
|
||||
rna_def_grease_pencil_data(brna);
|
||||
rna_def_grease_pencil_layer(brna);
|
||||
rna_def_grease_pencil_layer_mask(brna);
|
||||
rna_def_grease_pencil_layer_group(brna);
|
||||
}
|
||||
|
||||
|
|
|
@ -3291,12 +3291,16 @@ static void rna_def_modifier_boolean(BlenderRNA *brna)
|
|||
};
|
||||
|
||||
static const EnumPropertyItem prop_solver_items[] = {
|
||||
{eBooleanModifierSolver_Fast,
|
||||
{eBooleanModifierSolver_Float,
|
||||
"FAST",
|
||||
0,
|
||||
"Fast",
|
||||
"Simple solver for the best performance, without support for overlapping geometry"},
|
||||
{eBooleanModifierSolver_Exact, "EXACT", 0, "Exact", "Advanced solver for the best result"},
|
||||
{eBooleanModifierSolver_Mesh_Arr,
|
||||
"EXACT",
|
||||
0,
|
||||
"Exact",
|
||||
"Advanced solver for the best result"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
|
@ -3363,7 +3367,7 @@ static void rna_def_modifier_boolean(BlenderRNA *brna)
|
|||
|
||||
prop = RNA_def_property(srna, "solver", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, prop_solver_items);
|
||||
RNA_def_property_enum_default(prop, eBooleanModifierSolver_Exact);
|
||||
RNA_def_property_enum_default(prop, eBooleanModifierSolver_Mesh_Arr);
|
||||
RNA_def_property_ui_text(prop, "Solver", "Method for calculating booleans");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
|
|
|
@ -952,6 +952,7 @@ void RNA_api_wm(StructRNA *srna)
|
|||
|
||||
parm = RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(parm, rna_operator_popup_icon_items);
|
||||
RNA_def_property_enum_default(parm, ALERT_ICON_NONE);
|
||||
RNA_def_property_ui_text(parm, "Icon", "Optional icon displayed in the dialog");
|
||||
|
||||
api_ui_item_common_translation(func);
|
||||
|
|
|
@ -84,7 +84,7 @@ static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_re
|
|||
}
|
||||
if (bmd->flag & eBooleanModifierFlag_Collection) {
|
||||
/* The Exact solver tolerates an empty collection. */
|
||||
return !col && bmd->solver != eBooleanModifierSolver_Exact;
|
||||
return !col && bmd->solver != eBooleanModifierSolver_Mesh_Arr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ static bool BMD_error_messages(const Object *ob, ModifierData *md)
|
|||
bool error_returns_result = false;
|
||||
|
||||
const bool operand_collection = (bmd->flag & eBooleanModifierFlag_Collection) != 0;
|
||||
const bool use_exact = bmd->solver == eBooleanModifierSolver_Exact;
|
||||
const bool use_exact = bmd->solver == eBooleanModifierSolver_Mesh_Arr;
|
||||
const bool operation_intersect = bmd->operation == eBooleanModifierOp_Intersect;
|
||||
|
||||
#ifndef WITH_GMP
|
||||
|
@ -478,14 +478,19 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
|
|||
|
||||
const bool use_self = (bmd->flag & eBooleanModifierFlag_Self) != 0;
|
||||
const bool hole_tolerant = (bmd->flag & eBooleanModifierFlag_HoleTolerant) != 0;
|
||||
Mesh *result = blender::meshintersect::direct_mesh_boolean(meshes,
|
||||
obmats,
|
||||
ctx->object->object_to_world(),
|
||||
material_remaps,
|
||||
use_self,
|
||||
hole_tolerant,
|
||||
bmd->operation,
|
||||
nullptr);
|
||||
blender::geometry::boolean::BooleanOpParameters op_params;
|
||||
op_params.boolean_mode = blender::geometry::boolean::Operation(bmd->operation);
|
||||
op_params.no_self_intersections = !use_self;
|
||||
op_params.watertight = !hole_tolerant;
|
||||
op_params.no_nested_components = false;
|
||||
Mesh *result = blender::geometry::boolean::mesh_boolean(
|
||||
meshes,
|
||||
obmats,
|
||||
ctx->object->object_to_world(),
|
||||
material_remaps,
|
||||
op_params,
|
||||
blender::geometry::boolean::Solver::MeshArr,
|
||||
nullptr);
|
||||
|
||||
if (material_mode == eBooleanModifierMaterialMode_Transfer) {
|
||||
MEM_SAFE_FREE(result->mat);
|
||||
|
@ -513,7 +518,7 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
|
|||
}
|
||||
|
||||
#ifdef WITH_GMP
|
||||
if (bmd->solver == eBooleanModifierSolver_Exact) {
|
||||
if (bmd->solver == eBooleanModifierSolver_Mesh_Arr) {
|
||||
return exact_boolean_mesh(bmd, ctx, mesh);
|
||||
}
|
||||
#endif
|
||||
|
@ -631,7 +636,7 @@ static void solver_options_panel_draw(const bContext * /*C*/, Panel *panel)
|
|||
uiLayout *layout = panel->layout;
|
||||
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr);
|
||||
|
||||
const bool use_exact = RNA_enum_get(ptr, "solver") == eBooleanModifierSolver_Exact;
|
||||
const bool use_exact = RNA_enum_get(ptr, "solver") == eBooleanModifierSolver_Mesh_Arr;
|
||||
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ class AntiAliasingOperation : public NodeOperation {
|
|||
* algorithm expects it in the [0, 10] range. */
|
||||
float get_local_contrast_adaptation_factor()
|
||||
{
|
||||
return node_storage(bnode()).threshold * 10.0f;
|
||||
return node_storage(bnode()).contrast_limit * 10.0f;
|
||||
}
|
||||
|
||||
/* Blender encodes the corner rounding factor in the float [0, 1] range, while the SMAA algorithm
|
||||
|
|
|
@ -30,12 +30,15 @@ static void node_declare(NodeDeclarationBuilder &b)
|
|||
b.add_input<decl::Bool>("Self Intersection");
|
||||
b.add_input<decl::Bool>("Hole Tolerant");
|
||||
b.add_output<decl::Geometry>("Mesh").propagate_all();
|
||||
b.add_output<decl::Bool>("Intersecting Edges").field_on_all();
|
||||
b.add_output<decl::Bool>("Intersecting Edges").field_on_all().make_available([](bNode &node) {
|
||||
node.custom2 = int16_t(geometry::boolean::Solver::MeshArr);
|
||||
});
|
||||
}
|
||||
|
||||
static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
|
||||
{
|
||||
uiItemR(layout, ptr, "operation", UI_ITEM_NONE, "", ICON_NONE);
|
||||
uiItemR(layout, ptr, "solver", UI_ITEM_NONE, "", ICON_NONE);
|
||||
}
|
||||
|
||||
struct AttributeOutputs {
|
||||
|
@ -44,27 +47,34 @@ struct AttributeOutputs {
|
|||
|
||||
static void node_update(bNodeTree *ntree, bNode *node)
|
||||
{
|
||||
GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)node->custom1;
|
||||
const geometry::boolean::Operation operation = geometry::boolean::Operation(node->custom1);
|
||||
const geometry::boolean::Solver solver = geometry::boolean::Solver(node->custom2);
|
||||
|
||||
bNodeSocket *geometry_1_socket = static_cast<bNodeSocket *>(node->inputs.first);
|
||||
bNodeSocket *geometry_2_socket = geometry_1_socket->next;
|
||||
|
||||
bNodeSocket *intersecting_edges_socket = static_cast<bNodeSocket *>(node->outputs.last);
|
||||
|
||||
switch (operation) {
|
||||
case GEO_NODE_BOOLEAN_INTERSECT:
|
||||
case GEO_NODE_BOOLEAN_UNION:
|
||||
case geometry::boolean::Operation::Intersect:
|
||||
case geometry::boolean::Operation::Union:
|
||||
bke::nodeSetSocketAvailability(ntree, geometry_1_socket, false);
|
||||
node_sock_label(geometry_2_socket, "Mesh");
|
||||
break;
|
||||
case GEO_NODE_BOOLEAN_DIFFERENCE:
|
||||
case geometry::boolean::Operation::Difference:
|
||||
bke::nodeSetSocketAvailability(ntree, geometry_1_socket, true);
|
||||
node_sock_label(geometry_2_socket, "Mesh 2");
|
||||
break;
|
||||
}
|
||||
|
||||
bke::nodeSetSocketAvailability(
|
||||
ntree, intersecting_edges_socket, solver == geometry::boolean::Solver::MeshArr);
|
||||
}
|
||||
|
||||
static void node_init(bNodeTree * /*tree*/, bNode *node)
|
||||
{
|
||||
node->custom1 = GEO_NODE_BOOLEAN_DIFFERENCE;
|
||||
node->custom1 = int16_t(geometry::boolean::Operation::Difference);
|
||||
node->custom2 = int16_t(geometry::boolean::Solver::Float);
|
||||
}
|
||||
|
||||
#ifdef WITH_GMP
|
||||
|
@ -82,7 +92,8 @@ static Array<short> calc_mesh_material_map(const Mesh &mesh, VectorSet<Material
|
|||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
#ifdef WITH_GMP
|
||||
GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)params.node().custom1;
|
||||
geometry::boolean::Operation operation = geometry::boolean::Operation(params.node().custom1);
|
||||
geometry::boolean::Solver solver = geometry::boolean::Solver(params.node().custom2);
|
||||
const bool use_self = params.get_input<bool>("Self Intersection");
|
||||
const bool hole_tolerant = params.get_input<bool>("Hole Tolerant");
|
||||
|
||||
|
@ -92,7 +103,7 @@ static void node_geo_exec(GeoNodeExecParams params)
|
|||
Vector<Array<short>> material_remaps;
|
||||
|
||||
GeometrySet set_a;
|
||||
if (operation == GEO_NODE_BOOLEAN_DIFFERENCE) {
|
||||
if (operation == geometry::boolean::Operation::Difference) {
|
||||
set_a = params.extract_input<GeometrySet>("Mesh 1");
|
||||
/* Note that it technically wouldn't be necessary to realize the instances for the first
|
||||
* geometry input, but the boolean code expects the first shape for the difference operation
|
||||
|
@ -153,18 +164,24 @@ static void node_geo_exec(GeoNodeExecParams params)
|
|||
}
|
||||
|
||||
AttributeOutputs attribute_outputs;
|
||||
attribute_outputs.intersecting_edges_id = params.get_output_anonymous_attribute_id_if_needed(
|
||||
"Intersecting Edges");
|
||||
if (solver == geometry::boolean::Solver::MeshArr) {
|
||||
attribute_outputs.intersecting_edges_id = params.get_output_anonymous_attribute_id_if_needed(
|
||||
"Intersecting Edges");
|
||||
}
|
||||
|
||||
Vector<int> intersecting_edges;
|
||||
Mesh *result = blender::meshintersect::direct_mesh_boolean(
|
||||
geometry::boolean::BooleanOpParameters op_params;
|
||||
op_params.boolean_mode = operation;
|
||||
op_params.no_self_intersections = !use_self;
|
||||
op_params.watertight = !hole_tolerant;
|
||||
op_params.no_nested_components = true; /* TODO: make this configurable. */
|
||||
Mesh *result = geometry::boolean::mesh_boolean(
|
||||
meshes,
|
||||
transforms,
|
||||
float4x4::identity(),
|
||||
material_remaps,
|
||||
use_self,
|
||||
hole_tolerant,
|
||||
operation,
|
||||
op_params,
|
||||
solver,
|
||||
attribute_outputs.intersecting_edges_id ? &intersecting_edges : nullptr);
|
||||
if (!result) {
|
||||
params.set_default_remaining_outputs();
|
||||
|
@ -203,19 +220,36 @@ static void node_geo_exec(GeoNodeExecParams params)
|
|||
static void node_rna(StructRNA *srna)
|
||||
{
|
||||
static const EnumPropertyItem rna_node_geometry_boolean_method_items[] = {
|
||||
{GEO_NODE_BOOLEAN_INTERSECT,
|
||||
{int(geometry::boolean::Operation::Intersect),
|
||||
"INTERSECT",
|
||||
0,
|
||||
"Intersect",
|
||||
"Keep the part of the mesh that is common between all operands"},
|
||||
{GEO_NODE_BOOLEAN_UNION, "UNION", 0, "Union", "Combine meshes in an additive way"},
|
||||
{GEO_NODE_BOOLEAN_DIFFERENCE,
|
||||
{int(geometry::boolean::Operation::Union),
|
||||
"UNION",
|
||||
0,
|
||||
"Union",
|
||||
"Combine meshes in an additive way"},
|
||||
{int(geometry::boolean::Operation::Difference),
|
||||
"DIFFERENCE",
|
||||
0,
|
||||
"Difference",
|
||||
"Combine meshes in a subtractive way"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
static const EnumPropertyItem rna_geometry_boolean_solver_items[] = {
|
||||
{int(geometry::boolean::Solver::MeshArr),
|
||||
"EXACT",
|
||||
0,
|
||||
"Exact",
|
||||
"Exact solver for the best results"},
|
||||
{int(geometry::boolean::Solver::Float),
|
||||
"FLOAT",
|
||||
0,
|
||||
"Float",
|
||||
"Simple solver for the best performance, without support for overlapping geometry"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
RNA_def_node_enum(srna,
|
||||
"operation",
|
||||
|
@ -223,7 +257,15 @@ static void node_rna(StructRNA *srna)
|
|||
"",
|
||||
rna_node_geometry_boolean_method_items,
|
||||
NOD_inline_enum_accessors(custom1),
|
||||
GEO_NODE_BOOLEAN_INTERSECT);
|
||||
int(geometry::boolean::Operation::Intersect));
|
||||
|
||||
RNA_def_node_enum(srna,
|
||||
"solver",
|
||||
"Solver",
|
||||
"",
|
||||
rna_geometry_boolean_solver_items,
|
||||
NOD_inline_enum_accessors(custom2),
|
||||
int(geometry::boolean::Solver::Float));
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
|
|
|
@ -195,7 +195,7 @@ PyDoc_STRVAR(
|
|||
" :arg id: The command identifier (must pass an ``str.isidentifier`` check).\n"
|
||||
"\n"
|
||||
" If the ``id`` is already registered, a warning is printed and "
|
||||
"the command is inaccessible to prevent accidents invoking the wrong command."
|
||||
"the command is inaccessible to prevent accidents invoking the wrong command.\n"
|
||||
" :type id: str\n"
|
||||
" :arg execute: Callback, taking a single list of strings and returns an int.\n"
|
||||
" The arguments are built from all command-line arguments following the command id.\n"
|
||||
|
|
|
@ -133,7 +133,8 @@ static float seq_cache_timeline_frame_to_frame_index(Scene *scene,
|
|||
/* With raw images, map timeline_frame to strip input media frame range. This means that static
|
||||
* images or extended frame range of movies will only generate one cache entry. No special
|
||||
* treatment in converting frame index to timeline_frame is needed. */
|
||||
if (ELEM(type, SEQ_CACHE_STORE_RAW, SEQ_CACHE_STORE_THUMBNAIL)) {
|
||||
bool is_effect = seq->type & SEQ_TYPE_EFFECT;
|
||||
if (!is_effect && ELEM(type, SEQ_CACHE_STORE_RAW, SEQ_CACHE_STORE_THUMBNAIL)) {
|
||||
return SEQ_give_frame_index(scene, seq, timeline_frame);
|
||||
}
|
||||
|
||||
|
|
|
@ -474,6 +474,11 @@ void WM_OT_circle_gesture(wmOperatorType *ot)
|
|||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Lasso Gesture
|
||||
* There are two types of lasso gesture:
|
||||
* 1. #WM_GESTURE_LASSO: A lasso that follows the mouse cursor with the enclosed area shaded.
|
||||
* 2. #WM_GESTURE_LINES: A lasso that follows the mouse cursor without the enclosed area shaded.
|
||||
*
|
||||
* The operator stores data in the "path" property as a series of screen space positions.
|
||||
* \{ */
|
||||
|
||||
int WM_gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
|
|
|
@ -153,6 +153,7 @@ static ImBuf *wm_block_splash_image(int width, int *r_height)
|
|||
}
|
||||
|
||||
if (ibuf) {
|
||||
ibuf->planes = 32; /* The image might not have an alpha channel. */
|
||||
height = (width * ibuf->y) / ibuf->x;
|
||||
if (width != ibuf->x || height != ibuf->y) {
|
||||
IMB_scaleImBuf(ibuf, width, height);
|
||||
|
|
|
@ -272,7 +272,7 @@ def words_from_text(text: str, check_type: str) -> List[Tuple[str, int]]:
|
|||
w_prev = w_lower
|
||||
w_prev_start = w_start
|
||||
else:
|
||||
assert False
|
||||
assert False, "unreachable"
|
||||
|
||||
return words
|
||||
|
||||
|
@ -551,7 +551,7 @@ def spell_check_file(
|
|||
# print(filepath + ":" + str(slineno + 1) + ":" + str(scol), w, "(duplicates)")
|
||||
yield (w, slineno, scol)
|
||||
else:
|
||||
assert False
|
||||
assert False, "unreachable"
|
||||
|
||||
|
||||
def spell_check_file_recursive(
|
||||
|
|
|
@ -772,7 +772,7 @@ class BlendFileHeader:
|
|||
elif pointer_size_id == b'_':
|
||||
self.pointer_size = 4
|
||||
else:
|
||||
assert 0
|
||||
assert False, "unreachable"
|
||||
endian_id = values[2]
|
||||
if endian_id == b'v':
|
||||
self.is_little_endian = True
|
||||
|
@ -783,7 +783,7 @@ class BlendFileHeader:
|
|||
self.endian_index = 1
|
||||
self.endian_str = b'>'
|
||||
else:
|
||||
assert 0
|
||||
assert False, "unreachable"
|
||||
|
||||
version_id = values[3]
|
||||
self.version = int(version_id)
|
||||
|
|
Loading…
Reference in New Issue