FBX IO: Export normals matching the mesh's normals_domain #104976

Merged
Thomas Barlow merged 4 commits from Mysteryem/blender-addons:fbx_update_for_auto_smooth into main 2023-11-03 16:42:29 +01:00
17 changed files with 268 additions and 438 deletions
Showing only changes of commit 408b8b8e23 - Show all commits

View File

@ -5,8 +5,8 @@
bl_info = {
"name": "AnimAll",
"author": "Daniel Salazar (ZanQdo), Damien Picard (pioverfour)",
"version": (0, 9, 6),
"blender": (3, 3, 0),
"version": (0, 10, 0),
"blender": (4, 0, 0),
"location": "3D View > Toolbox > Animation tab > AnimAll",
"description": "Allows animation of mesh, lattice, curve and surface data",
"warning": "",
@ -22,6 +22,7 @@ from bpy.app.translations import (pgettext_iface as iface_,
pgettext_data as data_)
from . import translations
import re
# Property Definitions
class AnimallProperties(bpy.types.PropertyGroup):
@ -49,10 +50,12 @@ class AnimallProperties(bpy.types.PropertyGroup):
name="Vertex Bevel",
description="Insert keyframes on vertex bevel weight",
default=False)
# key_vertex_crease: BoolProperty(
# name="Vertex Crease",
# description="Insert keyframes on vertex crease weight",
# default=False)
key_vertex_crease: BoolProperty(
name="Vertex Crease",
description="Insert keyframes on vertex crease weight",
default=False)
key_vertex_group: BoolProperty(
name="Vertex Group",
description="Insert keyframes on active vertex group values",
@ -67,8 +70,8 @@ class AnimallProperties(bpy.types.PropertyGroup):
description="Insert keyframes on edge creases",
default=False)
key_attribute: BoolProperty(
name="Attribute",
key_active_attribute: BoolProperty(
name="Active Attribute",
description="Insert keyframes on active attribute values",
default=False)
key_uvs: BoolProperty(
@ -115,6 +118,55 @@ def delete_key(data, key):
pass
def get_attribute(data, name, type=None, domain=None):
if name in data.attributes:
return data.attributes[name]
if type is not None and domain is not None:
return data.attributes.new(name, type, domain)
def get_attribute_paths(data, attribute, key_selected):
# Cannot animate string attributes?
if attribute.data_type == 'STRING':
yield ("", "")
if attribute.data_type in {'FLOAT', 'INT', 'BOOLEAN', 'INT8'}:
attribute_key = "value"
elif attribute.data_type in {'FLOAT_COLOR', 'BYTE_COLOR'}:
attribute_key = "color"
elif attribute.data_type in {'FLOAT_VECTOR', 'FLOAT2'}:
attribute_key = "vector"
if attribute.domain == 'POINT':
group = data_("Vertex %s")
elif attribute.domain == 'EDGE':
group = data_("Edge %s")
elif attribute.domain == 'FACE':
group = data_("Face %s")
elif attribute.domain == 'CORNER':
group = data_("Loop %s")
for e_i, _attribute_data in enumerate(attribute.data):
if (not key_selected
or attribute.domain == 'POINT' and data.vertices[e_i].select
or attribute.domain == 'EDGE' and data.edges[e_i].select
or attribute.domain == 'FACE' and data.polygons[e_i].select
or attribute.domain == 'CORNER' and is_selected_vert_loop(data, e_i)):
yield (f'attributes["{attribute.name}"].data[{e_i}].{attribute_key}', group % e_i)
def insert_attribute_key(data, attribute, key_selected):
for path, group in get_attribute_paths(data, attribute, key_selected):
if path:
insert_key(data, path, group=group)
def delete_attribute_key(data, attribute, key_selected):
for path, group in get_attribute_paths(data, attribute, key_selected):
if path:
delete_key(data, path)
def is_selected_vert_loop(data, loop_i):
"""Get selection status of vertex corresponding to a loop"""
vertex_index = data.loops[loop_i].vertex_index
@ -126,7 +178,7 @@ def is_selected_vert_loop(data, loop_i):
class VIEW3D_PT_animall(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = "Animate"
bl_category = "Animation"
bl_label = ''
@classmethod
@ -137,7 +189,7 @@ class VIEW3D_PT_animall(Panel):
layout = self.layout
row = layout.row()
row.label (text = 'AnimAll', icon = 'ARMATURE_DATA')
row.label(text='AnimAll', icon='ARMATURE_DATA')
def draw(self, context):
obj = context.active_object
@ -161,6 +213,7 @@ class VIEW3D_PT_animall(Panel):
col = layout.column(heading="Points", align=True)
col.prop(animall_properties, "key_point_location")
col.prop(animall_properties, "key_vertex_bevel", text="Bevel")
col.prop(animall_properties, "key_vertex_crease", text="Crease")
col.prop(animall_properties, "key_vertex_group")
col = layout.column(heading="Edges", align=True)
@ -171,7 +224,7 @@ class VIEW3D_PT_animall(Panel):
col.prop(animall_properties, "key_material_index")
col = layout.column(heading="Others", align=True)
col.prop(animall_properties, "key_attribute")
col.prop(animall_properties, "key_active_attribute")
col.prop(animall_properties, "key_uvs")
col.prop(animall_properties, "key_shape_key")
@ -179,10 +232,10 @@ class VIEW3D_PT_animall(Panel):
if (obj.data.animation_data is not None
and obj.data.animation_data.action is not None):
for fcurve in context.active_object.data.animation_data.action.fcurves:
if fcurve.data_path.startswith("vertex_colors"):
if bpy.ops.anim.update_attribute_animation_animall.poll():
col = layout.column(align=True)
col.label(text="Object includes old-style vertex colors. Consider updating them.", icon="ERROR")
col.operator("anim.update_vertex_color_animation_animall", icon="FILE_REFRESH")
col.label(text="Object includes old-style attributes. Consider updating them.", icon="ERROR")
col.operator("anim.update_attribute_animation_animall", icon="FILE_REFRESH")
break
elif obj.type in {'CURVE', 'SURFACE'}:
@ -315,13 +368,12 @@ class ANIM_OT_insert_keyframe_animall(Operator):
insert_key(vert, 'co', group=data_("Vertex %s") % v_i)
if animall_properties.key_vertex_bevel:
for v_i, vert in enumerate(data.vertices):
if not animall_properties.key_selected or vert.select:
insert_key(vert, 'bevel_weight', group=data_("Vertex %s") % v_i)
# if animall_properties.key_vertex_crease:
# for v_i, vert in enumerate(data.vertices):
# if not animall_properties.key_selected or vert.select:
# insert_key(vert, 'crease', group=data_("Vertex %s") % v_i)
attribute = get_attribute(data, "bevel_weight_vert", 'FLOAT', 'POINT')
insert_attribute_key(data, attribute, animall_properties.key_selected)
if animall_properties.key_vertex_crease:
attribute = get_attribute(data, "crease_vert", 'FLOAT', 'POINT')
insert_attribute_key(data, attribute, animall_properties.key_selected)
if animall_properties.key_vertex_group:
for v_i, vert in enumerate(data.vertices):
@ -330,55 +382,31 @@ class ANIM_OT_insert_keyframe_animall(Operator):
insert_key(group, 'weight', group=data_("Vertex %s") % v_i)
if animall_properties.key_edge_bevel:
for e_i, edge in enumerate(data.edges):
if not animall_properties.key_selected or edge.select:
insert_key(edge, 'bevel_weight', group=data_("Edge %s") % e_i)
attribute = get_attribute(data, "bevel_weight_edge", 'FLOAT', 'EDGE')
insert_attribute_key(data, attribute, animall_properties.key_selected)
if animall_properties.key_edge_crease:
for e_i, edge in enumerate(data.edges):
if not animall_properties.key_selected or edge.select:
insert_key(edge, 'crease', group=data_("Edge %s") % e_i)
attribute = get_attribute(data, "crease_edge", 'FLOAT', 'EDGE')
insert_attribute_key(data, attribute, animall_properties.key_selected)
if animall_properties.key_material_index:
for p_i, polygon in enumerate(data.polygons):
if not animall_properties.key_selected or polygon.select:
insert_key(polygon, 'material_index', group=data_("Face %s") % p_i)
if animall_properties.key_attribute:
if animall_properties.key_active_attribute:
if data.attributes.active is not None:
attribute = data.attributes.active
if attribute.data_type != 'STRING':
# Cannot animate string attributes?
if attribute.data_type in {'FLOAT', 'INT', 'BOOLEAN', 'INT8'}:
attribute_key = "value"
elif attribute.data_type in {'FLOAT_COLOR', 'BYTE_COLOR'}:
attribute_key = "color"
elif attribute.data_type in {'FLOAT_VECTOR', 'FLOAT2'}:
attribute_key = "vector"
if attribute.domain == 'POINT':
group = data_("Vertex %s")
elif attribute.domain == 'EDGE':
group = data_("Edge %s")
elif attribute.domain == 'FACE':
group = data_("Face %s")
elif attribute.domain == 'CORNER':
group = data_("Loop %s")
for e_i, _attribute_data in enumerate(attribute.data):
if (not animall_properties.key_selected
or attribute.domain == 'POINT' and data.vertices[e_i].select
or attribute.domain == 'EDGE' and data.edges[e_i].select
or attribute.domain == 'FACE' and data.polygons[e_i].select
or attribute.domain == 'CORNER' and is_selected_vert_loop(data, e_i)):
insert_key(data, f'attributes["{attribute.name}"].data[{e_i}].{attribute_key}',
group=group % e_i)
for path, group in get_attribute_paths(
data, data.attributes.active,
animall_properties.key_selected):
if path:
insert_key(data, path, group=group)
if animall_properties.key_uvs:
if data.uv_layers.active is not None:
for uv_i, uv in enumerate(data.uv_layers.active.data):
if not animall_properties.key_selected or uv.select:
insert_key(uv, 'uv', group=data_("UV layer %s") % uv_i)
insert_key(uv, 'uv', group=data_("UV Layer %s") % uv_i)
if animall_properties.key_shape_key:
if obj.active_shape_key_index > 0:
@ -402,9 +430,15 @@ class ANIM_OT_insert_keyframe_animall(Operator):
if obj.active_shape_key_index > 0:
CV = obj.active_shape_key.data[global_spline_index]
insert_key(CV, 'co', group=data_("%s Spline %s CV %s") % (sk_name, s_i, v_i))
insert_key(CV, 'handle_left', group=data_("%s Spline %s CV %s") % (sk_name, s_i, v_i))
insert_key(CV, 'handle_right', group=data_("%s Spline %s CV %s") % (sk_name, s_i, v_i))
insert_key(CV, 'radius', group=data_("%s Spline %s CV %s") % (sk_name, s_i, v_i))
insert_key(
CV, 'handle_left', group=data_("%s Spline %s CV %s") %
(sk_name, s_i, v_i))
insert_key(
CV, 'handle_right', group=data_("%s Spline %s CV %s") %
(sk_name, s_i, v_i))
insert_key(
CV, 'radius', group=data_("%s Spline %s CV %s") %
(sk_name, s_i, v_i))
insert_key(CV, 'tilt', group=data_("%s Spline %s CV %s") % (sk_name, s_i, v_i))
global_spline_index += 1
@ -414,7 +448,8 @@ class ANIM_OT_insert_keyframe_animall(Operator):
if obj.active_shape_key_index > 0:
CV = obj.active_shape_key.data[global_spline_index]
insert_key(CV, 'co', group=data_("%s Spline %s CV %s") % (sk_name, s_i, v_i))
insert_key(CV, 'radius', group=data_("%s Spline %s CV %s") % (sk_name, s_i, v_i))
insert_key(
CV, 'radius', group=data_("%s Spline %s CV %s") % (sk_name, s_i, v_i))
insert_key(CV, 'tilt', group=data_("%s Spline %s CV %s") % (sk_name, s_i, v_i))
global_spline_index += 1
@ -443,15 +478,22 @@ class ANIM_OT_delete_keyframe_animall(Operator):
for obj in objects:
data = obj.data
if obj.type == 'MESH':
bpy.ops.object.mode_set(mode='OBJECT')
if animall_properties.key_point_location:
for vert in data.vertices:
if not animall_properties.key_selected or vert.select:
delete_key(vert, 'co')
if animall_properties.key_vertex_bevel:
for vert in data.vertices:
if not animall_properties.key_selected or vert.select:
delete_key(vert, 'bevel_weight')
attribute = get_attribute(data, "bevel_weight_vert", 'FLOAT', 'POINT')
if attribute is not None:
delete_attribute_key(data, attribute, animall_properties.key_selected)
if animall_properties.key_vertex_crease:
attribute = get_attribute(data, "crease_vert", 'FLOAT', 'POINT')
if attribute is not None:
delete_attribute_key(data, attribute, animall_properties.key_selected)
if animall_properties.key_vertex_group:
for vert in data.vertices:
@ -459,20 +501,20 @@ class ANIM_OT_delete_keyframe_animall(Operator):
for group in vert.groups:
delete_key(group, 'weight')
# if animall_properties.key_vertex_crease:
# for vert in data.vertices:
# if not animall_properties.key_selected or vert.select:
# delete_key(vert, 'crease')
if animall_properties.key_edge_bevel:
for edge in data.edges:
if not animall_properties.key_selected or edge.select:
delete_key(edge, 'bevel_weight')
attribute = get_attribute(data, "bevel_weight_edge", 'FLOAT', 'EDGE')
if attribute is not None:
delete_attribute_key(data, attribute, animall_properties.key_selected)
if animall_properties.key_edge_crease:
for edge in data.edges:
if not animall_properties.key_selected or vert.select:
delete_key(edge, 'crease')
attribute = get_attribute(data, "crease_edge", 'FLOAT', 'EDGE')
if attribute is not None:
delete_attribute_key(data, attribute, animall_properties.key_selected)
if animall_properties.key_material_index:
for p_i, polygon in enumerate(data.polygons):
if not animall_properties.key_selected or polygon.select:
delete_key(polygon, 'material_index')
if animall_properties.key_shape_key:
if obj.active_shape_key:
@ -486,25 +528,15 @@ class ANIM_OT_delete_keyframe_animall(Operator):
if not animall_properties.key_selected or uv.select:
delete_key(uv, 'uv')
if animall_properties.key_attribute:
if animall_properties.key_active_attribute:
if data.attributes.active is not None:
attribute = data.attributes.active
if attribute.data_type != 'STRING':
# Cannot animate string attributes?
if attribute.data_type in {'FLOAT', 'INT', 'BOOLEAN', 'INT8'}:
attribute_key = "value"
elif attribute.data_type in {'FLOAT_COLOR', 'BYTE_COLOR'}:
attribute_key = "color"
elif attribute.data_type in {'FLOAT_VECTOR', 'FLOAT2'}:
attribute_key = "vector"
for path, _group in get_attribute_paths(
data, data.attributes.active,
animall_properties.key_selected):
if path:
delete_key(data, path)
for e_i, _attribute_data in enumerate(attribute.data):
if (not animall_properties.key_selected
or attribute.domain == 'POINT' and data.vertices[e_i].select
or attribute.domain == 'EDGE' and data.edges[e_i].select
or attribute.domain == 'FACE' and data.polygons[e_i].select
or attribute.domain == 'CORNER' and is_selected_vert_loop(data, e_i)):
delete_key(data, f'attributes["{attribute.name}"].data[{e_i}].{attribute_key}')
bpy.ops.object.mode_set(mode=mode)
elif obj.type == 'LATTICE':
if animall_properties.key_shape_key:
@ -588,12 +620,20 @@ class ANIM_OT_clear_animation_animall(Operator):
return {'FINISHED'}
class ANIM_OT_update_vertex_color_animation_animall(Operator):
bl_label = "Update Vertex Color Animation"
bl_idname = "anim.update_vertex_color_animation_animall"
bl_description = "Update old vertex color channel formats from pre-3.3 versions"
class ANIM_OT_update_attribute_animation_animall(Operator):
bl_label = "Update Attribute Animation"
bl_idname = "anim.update_attribute_animation_animall"
bl_description = "Update attributes from the old format"
bl_options = {'REGISTER', 'UNDO'}
path_re = re.compile(r"^vertex_colors|(vertices|edges)\[([0-9]+)\]\.(bevel_weight|crease)")
attribute_map = {
("vertices", "bevel_weight"): ("bevel_weight_vert", "FLOAT", "POINT"),
("edges", "bevel_weight"): ("bevel_weight_edge", "FLOAT", "POINT"),
("vertices", "crease"): ("crease_vert", "FLOAT", "EDGE"),
("edges", "crease"): ("crease_edge", "FLOAT", "EDGE"),
}
@classmethod
def poll(self, context):
if (context.active_object is None
@ -602,21 +642,30 @@ class ANIM_OT_update_vertex_color_animation_animall(Operator):
or context.active_object.data.animation_data.action is None):
return False
for fcurve in context.active_object.data.animation_data.action.fcurves:
if fcurve.data_path.startswith("vertex_colors"):
if self.path_re.match(fcurve.data_path):
return True
def execute(self, context):
for fcurve in context.active_object.data.animation_data.action.fcurves:
if fcurve.data_path.startswith("vertex_colors"):
# Update pre-3.3 vertex colors
fcurve.data_path = fcurve.data_path.replace("vertex_colors", "attributes")
else:
# Update pre-4.0 attributes
match = self.path_re.match(fcurve.data_path)
if match is None:
continue
domain, index, src_attribute = match.groups()
attribute, type, domain = self.attribute_map[(domain, src_attribute)]
get_attribute(context.active_object.data, attribute, type, domain)
fcurve.data_path = f'attributes["{attribute}"].data[{index}].value'
return {'FINISHED'}
# Add-ons Preferences Update Panel
# Define Panel classes for updating
panels = [
VIEW3D_PT_animall
]
panels = [VIEW3D_PT_animall]
def update_panel(self, context):
@ -643,7 +692,7 @@ class AnimallAddonPreferences(AddonPreferences):
category: StringProperty(
name="Tab Category",
description="Choose a name for the category of the panel",
default="Animate",
default="Animation",
update=update_panel
)
@ -658,7 +707,7 @@ class AnimallAddonPreferences(AddonPreferences):
register_classes, unregister_classes = bpy.utils.register_classes_factory(
(AnimallProperties, VIEW3D_PT_animall, ANIM_OT_insert_keyframe_animall,
ANIM_OT_delete_keyframe_animall, ANIM_OT_clear_animation_animall,
ANIM_OT_update_vertex_color_animation_animall, AnimallAddonPreferences))
ANIM_OT_update_attribute_animation_animall, AnimallAddonPreferences))
def register():
register_classes()

View File

@ -12,10 +12,10 @@
translations_tuple = (
(("*", ""),
((), ()),
("fr_FR", "Project-Id-Version: AnimAll 0.9.6 (0)\n",
("fr_FR", "Project-Id-Version: AnimAll 0.10.0 (0)\n",
(False,
("Blender's translation file (po format).",
"Copyright (C) 2022 The Blender Foundation.",
"Copyright (C) 2022-2023 The Blender Foundation.",
"This file is distributed under the same license as the Blender package.",
"Damien Picard <dam.pic@free.fr>, 2022."))),
),
@ -59,7 +59,7 @@ translations_tuple = (
(("Operator", "Delete Key"),
(("bpy.types.ANIM_OT_delete_keyframe_animall",),
()),
("fr_FR", "Supprimer image clé",
("fr_FR", "Supprimer limage clé",
(False, ())),
),
(("*", "Delete a Keyframe"),
@ -68,16 +68,16 @@ translations_tuple = (
("fr_FR", "Supprimer une image clé",
(False, ())),
),
(("Operator", "Update Vertex Color Animation"),
(("bpy.types.ANIM_OT_update_vertex_color_animation_animall",),
(("Operator", "Update Attribute Animation"),
(("bpy.types.ANIM_OT_update_attribute_animation_animall",),
()),
("fr_FR", "Mettre à jour lanimation des couleurs de sommets",
("fr_FR", "Mettre à jour lanimation des attributs",
(False, ())),
),
(("*", "Update old vertex color channel formats from pre-3.3 versions"),
(("bpy.types.ANIM_OT_update_vertex_color_animation_animall",),
(("*", "Update attributes from the old format"),
(("bpy.types.ANIM_OT_update_attribute_animation_animall",),
()),
("fr_FR", "Mettre à jour les formats des canaux depuis les versions antérieures à la 3.3",
("fr_FR", "Mettre à jour les attributs depuis lancien format",
(False, ())),
),
(("*", "Animate"),
@ -87,7 +87,7 @@ translations_tuple = (
(False, ())),
),
(("*", "Insert keyframes on active attribute values"),
(("bpy.types.AnimallProperties.key_attribute",),
(("bpy.types.AnimallProperties.key_active_attribute",),
()),
("fr_FR", "Insérer des clés sur lattribut actif",
(False, ())),
@ -98,6 +98,12 @@ translations_tuple = (
("fr_FR", "Insérer des clés sur les poids de biseau darête",
(False, ())),
),
(("*", "Edge Crease"),
(("bpy.types.AnimallProperties.key_edge_crease",),
()),
("fr_FR", "Plis darêtes",
(False, ())),
),
(("*", "Insert keyframes on edge creases"),
(("bpy.types.AnimallProperties.key_edge_crease",),
()),
@ -158,6 +164,12 @@ translations_tuple = (
("fr_FR", "Insérer des clés sur les poids de biseau des sommets",
(False, ())),
),
(("*", "Insert keyframes on vertex crease weight"),
(("bpy.types.AnimallProperties.key_vertex_crease",),
()),
("fr_FR", "Insérer des clés sur les plis de sommets",
(False, ())),
),
(("*", "Insert keyframes on active vertex group values"),
(("bpy.types.AnimallProperties.key_vertex_group",),
()),
@ -165,190 +177,187 @@ translations_tuple = (
(False, ())),
),
(("*", "AnimAll"),
(("scripts/addons/animation_animall/__init__.py:138",
"Add-on AnimAll info: name"),
(("Add-on AnimAll info: name",),
()),
("fr_FR", "AnimAll",
(False, ())),
),
(("*", "Key:"),
(("scripts/addons/animation_animall/__init__.py:146",),
(("scripts/addons/animation_animall/__init__.py:200",),
()),
("fr_FR", "Insérer:",
(False, ())),
),
(("*", "Tab Category:"),
(("scripts/addons/animation_animall/__init__.py:653",),
(("scripts/addons/animation_animall/__init__.py:704",),
()),
("fr_FR", "Catégorie donglet :",
(False, ())),
),
(("*", "Points"),
(("scripts/addons/animation_animall/__init__.py:152",
"scripts/addons/animation_animall/__init__.py:159",
"scripts/addons/animation_animall/__init__.py:188"),
(("scripts/addons/animation_animall/__init__.py:206",
"scripts/addons/animation_animall/__init__.py:213",
"scripts/addons/animation_animall/__init__.py:243"),
()),
("fr_FR", "Points",
(False, ())),
),
(("*", "Others"),
(("scripts/addons/animation_animall/__init__.py:155",
"scripts/addons/animation_animall/__init__.py:171",
"scripts/addons/animation_animall/__init__.py:196"),
(("scripts/addons/animation_animall/__init__.py:209",
"scripts/addons/animation_animall/__init__.py:226",
"scripts/addons/animation_animall/__init__.py:251"),
()),
("fr_FR", "Autres",
(False, ())),
),
(("*", "Bevel"),
(("scripts/addons/animation_animall/__init__.py:161",
"scripts/addons/animation_animall/__init__.py:165"),
(("scripts/addons/animation_animall/__init__.py:215",
"scripts/addons/animation_animall/__init__.py:220"),
()),
("fr_FR", "Biseau",
(False, ())),
),
(("*", "Edges"),
(("scripts/addons/animation_animall/__init__.py:164",),
(("scripts/addons/animation_animall/__init__.py:219",),
()),
("fr_FR", "Arêtes",
(False, ())),
),
(("*", "Crease"),
(("scripts/addons/animation_animall/__init__.py:166",),
(("scripts/addons/animation_animall/__init__.py:216",
"scripts/addons/animation_animall/__init__.py:221",),
()),
("fr_FR", "Plis",
(False, ())),
),
(("*", "Faces"),
(("scripts/addons/animation_animall/__init__.py:168",),
(("scripts/addons/animation_animall/__init__.py:223",),
()),
("fr_FR", "Faces",
(False, ())),
),
(("*", "\"Location\" and \"Shape Key\" are redundant?"),
(("scripts/addons/animation_animall/__init__.py:218",),
(("scripts/addons/animation_animall/__init__.py:273",),
()),
("fr_FR", "\"Position\" et \"Clé de forme\" sont redondants?",
(False, ())),
),
(("*", "Splines"),
(("scripts/addons/animation_animall/__init__.py:193",),
(("scripts/addons/animation_animall/__init__.py:248",),
()),
("fr_FR", "Splines",
(False, ())),
),
(("*", "Maybe set \"%s\" to 1.0?"),
(("scripts/addons/animation_animall/__init__.py:209",
"scripts/addons/animation_animall/__init__.py:209"),
(("scripts/addons/animation_animall/__init__.py:264"),
()),
("fr_FR", "Essayez de mettre « %s » à 1.0?",
(False, ())),
),
(("*", "Cannot key on Basis Shape"),
(("scripts/addons/animation_animall/__init__.py:212",),
(("scripts/addons/animation_animall/__init__.py:267",),
()),
("fr_FR", "Impossible dajouter une clé sur la forme de base",
(False, ())),
),
(("*", "No active Shape Key"),
(("scripts/addons/animation_animall/__init__.py:215",),
(("scripts/addons/animation_animall/__init__.py:270",),
()),
("fr_FR", "Pas de clé de forme active",
(False, ())),
),
(("*", "Clear Animation could not be performed"),
(("scripts/addons/animation_animall/__init__.py:581",),
(("scripts/addons/animation_animall/__init__.py:615",),
()),
("fr_FR", "La suppression de lanimation na pas pu aboutir",
(False, ())),
),
(("*", "Object includes old-style vertex colors. Consider updating them."),
(("scripts/addons/animation_animall/__init__.py:182",),
(("*", "Object includes old-style attributes. Consider updating them."),
(("scripts/addons/animation_animall/__init__.py:237",),
()),
("fr_FR", "Lobjet contient des couleurs de sommets à lancien format. Veuillez les mettre à jour",
("fr_FR", "Lobjet contient des attributs à lancien format. Veuillez les mettre à jour.",
(False, ())),
),
(("*", "Vertex %s"),
(("scripts/addons/animation_animall/__init__.py:358",
"scripts/addons/animation_animall/__init__.py:313",
"scripts/addons/animation_animall/__init__.py:318",
"scripts/addons/animation_animall/__init__.py:328"),
(("scripts/addons/animation_animall/__init__.py:141",
"scripts/addons/animation_animall/__init__.py:368",
"scripts/addons/animation_animall/__init__.py:382",
"scripts/addons/animation_animall/__init__.py:416"),
()),
("fr_FR", "Sommet %s",
(False, ())),
),
(("*", "Edge %s"),
(("scripts/addons/animation_animall/__init__.py:360",
"scripts/addons/animation_animall/__init__.py:333",
"scripts/addons/animation_animall/__init__.py:338"),
(("scripts/addons/animation_animall/__init__.py:143"),
()),
("fr_FR", "Arête %s",
(False, ())),
),
(("*", "Point %s"),
(("scripts/addons/animation_animall/__init__.py:265",),
(("scripts/addons/animation_animall/__init__.py:320",),
()),
("fr_FR", "Point %s",
(False, ())),
),
(("*", "Spline %s"),
(("scripts/addons/animation_animall/__init__.py:273",),
(("scripts/addons/animation_animall/__init__.py:328",),
()),
("fr_FR", "Spline %s",
(False, ())),
),
(("*", "Face %s"),
(("scripts/addons/animation_animall/__init__.py:343",
"scripts/addons/animation_animall/__init__.py:362"),
(("scripts/addons/animation_animall/__init__.py:145",
"scripts/addons/animation_animall/__init__.py:395"),
()),
("fr_FR", "Face %s",
(False, ())),
),
(("*", "%s Point %s"),
(("scripts/addons/animation_animall/__init__.py:260",),
(("scripts/addons/animation_animall/__init__.py:315",),
()),
("fr_FR", "%s Point %s",
(False, ())),
),
(("*", "Loop %s"),
(("scripts/addons/animation_animall/__init__.py:364",),
(("scripts/addons/animation_animall/__init__.py:147",),
()),
("fr_FR", "Boucle %s",
(False, ())),
),
(("*", "UV layer %s"),
(("scripts/addons/animation_animall/__init__.py:379",),
(("*", "UV Layer %s"),
(("scripts/addons/animation_animall/__init__.py:409",),
()),
("fr_FR", "Calque UV %s",
(False, ())),
),
(("*", "%s Vertex %s"),
(("scripts/addons/animation_animall/__init__.py:386",),
(("scripts/addons/animation_animall/__init__.py:416",),
()),
("fr_FR", "%s Sommet %s",
(False, ())),
),
(("*", "Spline %s CV %s"),
(("scripts/addons/animation_animall/__init__.py:283",
"scripts/addons/animation_animall/__init__.py:284",
"scripts/addons/animation_animall/__init__.py:285",
"scripts/addons/animation_animall/__init__.py:288",
"scripts/addons/animation_animall/__init__.py:291",
"scripts/addons/animation_animall/__init__.py:297",
"scripts/addons/animation_animall/__init__.py:300",
"scripts/addons/animation_animall/__init__.py:303"),
(("scripts/addons/animation_animall/__init__.py:338",
"scripts/addons/animation_animall/__init__.py:339",
"scripts/addons/animation_animall/__init__.py:340",
"scripts/addons/animation_animall/__init__.py:343",
"scripts/addons/animation_animall/__init__.py:346",
"scripts/addons/animation_animall/__init__.py:352",
"scripts/addons/animation_animall/__init__.py:355",
"scripts/addons/animation_animall/__init__.py:358"),
()),
("fr_FR", "Spline %s Point %s",
(False, ())),
),
(("*", "%s Spline %s CV %s"),
(("scripts/addons/animation_animall/__init__.py:402",
"scripts/addons/animation_animall/__init__.py:403",
"scripts/addons/animation_animall/__init__.py:404",
"scripts/addons/animation_animall/__init__.py:405",
"scripts/addons/animation_animall/__init__.py:406",
"scripts/addons/animation_animall/__init__.py:414",
"scripts/addons/animation_animall/__init__.py:415",
"scripts/addons/animation_animall/__init__.py:416"),
(("scripts/addons/animation_animall/__init__.py:432",
"scripts/addons/animation_animall/__init__.py:434",
"scripts/addons/animation_animall/__init__.py:437",
"scripts/addons/animation_animall/__init__.py:440",
"scripts/addons/animation_animall/__init__.py:442",
"scripts/addons/animation_animall/__init__.py:450",
"scripts/addons/animation_animall/__init__.py:452",
"scripts/addons/animation_animall/__init__.py:453"),
()),
("fr_FR", "%s Spline %s Point %s",
(False, ())),

View File

@ -628,8 +628,11 @@ def make_material_texture_chunk(chunk_id, texslots, pct):
mat_sub_mapflags.add_variable("mapflags", _3ds_ushort(mapflags))
mat_sub.add_subchunk(mat_sub_mapflags)
mat_sub_texblur = _3ds_chunk(MAT_MAP_TEXBLUR) # Based on observation this is usually 1.0
mat_sub_texblur.add_variable("maptexblur", _3ds_float(1.0))
texblur = 0.0
mat_sub_texblur = _3ds_chunk(MAT_MAP_TEXBLUR)
if texslot.socket_dst.identifier in {'Base Color', 'Specular Tint'}:
texblur = texslot.node_dst.inputs['Sheen Weight'].default_value
mat_sub_texblur.add_variable("maptexblur", _3ds_float(round(texblur, 6)))
mat_sub.add_subchunk(mat_sub_texblur)
mat_sub_uscale = _3ds_chunk(MAT_MAP_USCALE)
@ -1306,9 +1309,9 @@ def make_object_node(ob, translation, rotation, scale, name_id):
obj_node_header_chunk.add_variable("flags1", _3ds_ushort(0x0040))
# Flag 0x01 display path 0x02 use autosmooth 0x04 object frozen 0x10 motion blur 0x20 material morph 0x40 mesh morph
if ob.type == 'MESH' and 'Smooth by Angle' in ob.modifiers:
ob_node_header_chunk.add_variable("flags2", _3ds_ushort(0x02))
obj_node_header_chunk.add_variable("flags2", _3ds_ushort(0x02))
else:
ob_node_header_chunk.add_variable("flags2", _3ds_ushort(0))
obj_node_header_chunk.add_variable("flags2", _3ds_ushort(0))
obj_node_header_chunk.add_variable("parent", _3ds_ushort(ROOT_OBJECT))
'''

View File

@ -90,6 +90,7 @@ MAT_SHIN_MAP = 0xA33C # This is a header for a new roughness map
MAT_SELFI_MAP = 0xA33D # This is a header for a new emission map
MAT_MAP_FILEPATH = 0xA300 # This holds the file name of the texture
MAT_MAP_TILING = 0xA351 # 2nd bit (from LSB) is mirror UV flag
MAT_MAP_TEXBLUR = 0xA353 # Texture blurring factor (float 0-1)
MAT_MAP_USCALE = 0xA354 # U axis scaling
MAT_MAP_VSCALE = 0xA356 # V axis scaling
MAT_MAP_UOFFSET = 0xA358 # U axis offset
@ -559,6 +560,8 @@ def process_next_chunk(context, file, previous_chunk, imported_objects, CONSTRAI
elif temp_chunk.ID == MAT_BUMP_PERCENT:
contextWrapper.normalmap_strength = (float(read_short(temp_chunk) / 100))
elif mapto in {'COLOR', 'SPECULARITY'} and temp_chunk.ID == MAT_MAP_TEXBLUR:
contextWrapper.node_principled_bsdf.inputs['Sheen Weight'].default_value = float(read_float(temp_chunk))
elif temp_chunk.ID == MAT_MAP_TILING:
"""Control bit flags, where 0x1 activates decaling, 0x2 activates mirror,
@ -645,7 +648,7 @@ def process_next_chunk(context, file, previous_chunk, imported_objects, CONSTRAI
hyp = math.sqrt(pow(plane.x,2) + pow(plane.y,2))
dia = math.sqrt(pow(hyp,2) + pow(plane.z,2))
yaw = math.atan2(math.copysign(hyp, sign_xy), axis_xy)
bow = math.acos(hyp / dia)
bow = math.acos(hyp / dia) if dia != 0 else 0
turn = angle - yaw if check_sign else angle + yaw
tilt = angle - bow if loca.z > target.z else angle + bow
pan = yaw if check_axes else turn
@ -1002,7 +1005,7 @@ def process_next_chunk(context, file, previous_chunk, imported_objects, CONSTRAI
elif new_chunk.ID == MAT_XPFALL:
read_chunk(file, temp_chunk)
if temp_chunk.ID == PCT_SHORT:
contextTransmission = float(read_short(temp_chunk) / 100)
contextTransmission = float(abs(read_short(temp_chunk) / 100))
else:
skip_to_end(file, temp_chunk)
new_chunk.bytes_read += temp_chunk.bytes_read

View File

@ -5,7 +5,7 @@
bl_info = {
"name": "FBX format",
"author": "Campbell Barton, Bastien Montagne, Jens Restemeier, @Mysteryem",
"version": (5, 8, 11),
"version": (5, 9, 1),
"blender": (4, 1, 0),
"location": "File > Import-Export",
"description": "FBX IO meshes, UVs, vertex colors, materials, textures, cameras, lamps and actions",

View File

@ -629,7 +629,7 @@ def _transformation_curves_gen(item, values_arrays, channel_keys):
# Create matrices/euler from the initial transformation values of this item.
# These variables will be updated in-place as we iterate through each frame.
lcl_translation_mat = Matrix.Translation(transform_data.loc)
lcl_rotation_eul = Euler(transform_data.rot, transform_data.rot_ord)
lcl_rotation_eul = Euler(convert_deg_to_rad_iter(transform_data.rot), transform_data.rot_ord)
lcl_scaling_mat = Matrix()
lcl_scaling_mat[0][0], lcl_scaling_mat[1][1], lcl_scaling_mat[2][2] = transform_data.sca

View File

@ -5,7 +5,7 @@
bl_info = {
'name': 'glTF 2.0 format',
'author': 'Julien Duroure, Scurest, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
"version": (4, 1, 17),
"version": (4, 1, 20),
'blender': (4, 1, 0),
'location': 'File > Import-Export',
'description': 'Import-Export as glTF 2.0',

View File

@ -53,13 +53,16 @@ def __gather_scene(blender_scene, export_settings):
vtree = gltf2_blender_gather_tree.VExportTree(export_settings)
vtree.construct(blender_scene)
vtree.search_missing_armature() # In case armature are no parented correctly
vtree.bake_armature_bone_list() # Used in case we remove the armature
vtree.check_if_we_can_remove_armature() # Check if we can remove the armatures objects
if export_settings['gltf_armature_object_remove'] is True:
vtree.check_if_we_can_remove_armature() # Check if we can remove the armatures objects
export_user_extensions('vtree_before_filter_hook', export_settings, vtree)
# Now, we can filter tree if needed
vtree.filter()
vtree.bake_armature_bone_list() # Used in case we remove the armature. Doing it after filter, as filter can remove some bones
if export_settings['gltf_flatten_bones_hierarchy'] is True:
vtree.break_bone_hierarchy()
if export_settings['gltf_flatten_obj_hierarchy'] is True:

View File

@ -25,3 +25,4 @@ def get_object_from_datapath(blender_object, data_path: str):
# path_attr = data_path
return prop

View File

@ -167,14 +167,14 @@ def __gather_extensions(blender_material, emissive_factor, export_settings):
clearcoat_extension, uvmap_info = export_clearcoat(blender_material, export_settings)
if clearcoat_extension:
extensions["KHR_materials_clearcoat"] = clearcoat_extension
uvmap_infos.update(uvmap_infos)
uvmap_infos.update(uvmap_info)
# KHR_materials_transmission
transmission_extension, uvmap_info = export_transmission(blender_material, export_settings)
if transmission_extension:
extensions["KHR_materials_transmission"] = transmission_extension
uvmap_infos.update(uvmap_infos)
uvmap_infos.update(uvmap_info)
# KHR_materials_emissive_strength
if any([i>1.0 for i in emissive_factor or []]):

View File

@ -347,7 +347,8 @@ def get_texture_transform_from_mapping_node(mapping_node):
return None
mapping_transform = {}
mapping_transform["offset"] = [mapping_node.node.inputs['Location'].default_value[0], mapping_node.node.inputs['Location'].default_value[1]]
if mapping_node.node.vector_type != "VECTOR":
mapping_transform["offset"] = [mapping_node.node.inputs['Location'].default_value[0], mapping_node.node.inputs['Location'].default_value[1]]
mapping_transform["rotation"] = mapping_node.node.inputs['Rotation'].default_value[2]
mapping_transform["scale"] = [mapping_node.node.inputs['Scale'].default_value[0], mapping_node.node.inputs['Scale'].default_value[1]]

View File

@ -20,10 +20,6 @@ def drawlayout(context, layout, mode='non-panel'):
col.menu(NWMergeNodesMenu.bl_idname)
col.separator()
col = layout.column(align=True)
col.menu(NWSwitchNodeTypeMenu.bl_idname, text="Switch Node Type")
col.separator()
if tree_type == 'ShaderNodeTree':
col = layout.column(align=True)
col.operator(operators.NWAddTextureSetup.bl_idname, text="Add Texture Setup", icon='NODE_SEL')
@ -385,32 +381,8 @@ class NWSwitchNodeTypeMenu(Menu, NWBase):
def draw(self, context):
layout = self.layout
categories = [c for c in node_categories_iter(context)
if c.name not in ['Group', 'Script']]
for cat in categories:
idname = f"NODE_MT_nw_switch_{cat.identifier}_submenu"
if hasattr(bpy.types, idname):
layout.menu(idname)
else:
layout.label(text="Unable to load altered node lists.")
layout.label(text="Please re-enable Node Wrangler.")
break
def draw_switch_category_submenu(self, context):
layout = self.layout
if self.category.name == 'Layout':
for node in self.category.items(context):
if node.nodetype != 'NodeFrame':
props = layout.operator(operators.NWSwitchNodeType.bl_idname, text=node.label)
props.to_type = node.nodetype
else:
for node in self.category.items(context):
if isinstance(node, NodeItemCustom):
node.draw(self, layout, context)
continue
props = layout.operator(operators.NWSwitchNodeType.bl_idname, text=node.label)
props.to_type = node.nodetype
layout.label(text="This operator is removed due to the changes of node menus.", icon='ERROR')
layout.label(text="A native implementation of the function is expected in the future.")
#
# APPENDAGES TO EXISTING UI

View File

@ -914,195 +914,6 @@ class NWReloadImages(Operator):
return {'CANCELLED'}
class NWSwitchNodeType(Operator, NWBase):
"""Switch type of selected nodes """
bl_idname = "node.nw_swtch_node_type"
bl_label = "Switch Node Type"
bl_options = {'REGISTER', 'UNDO'}
to_type: StringProperty(
name="Switch to type",
default='',
)
def execute(self, context):
to_type = self.to_type
if len(to_type) == 0:
return {'CANCELLED'}
nodes, links = get_nodes_links(context)
# Those types of nodes will not swap.
src_excludes = ('NodeFrame')
# Those attributes of nodes will be copied if possible
attrs_to_pass = ('color', 'hide', 'label', 'mute', 'parent',
'show_options', 'show_preview', 'show_texture',
'use_alpha', 'use_clamp', 'use_custom_color', 'location'
)
selected = [n for n in nodes if n.select]
reselect = []
for node in [n for n in selected if
n.rna_type.identifier not in src_excludes and
n.rna_type.identifier != to_type]:
new_node = nodes.new(to_type)
for attr in attrs_to_pass:
if hasattr(node, attr) and hasattr(new_node, attr):
setattr(new_node, attr, getattr(node, attr))
# set image datablock of dst to image of src
if hasattr(node, 'image') and hasattr(new_node, 'image'):
if node.image:
new_node.image = node.image
# Special cases
if new_node.type == 'SWITCH':
new_node.hide = True
# Dictionaries: src_sockets and dst_sockets:
# 'INPUTS': input sockets ordered by type (entry 'MAIN' main type of inputs).
# 'OUTPUTS': output sockets ordered by type (entry 'MAIN' main type of outputs).
# in 'INPUTS' and 'OUTPUTS':
# 'SHADER', 'RGBA', 'VECTOR', 'VALUE' - sockets of those types.
# socket entry:
# (index_in_type, socket_index, socket_name, socket_default_value, socket_links)
src_sockets = {
'INPUTS': {'SHADER': [], 'RGBA': [], 'VECTOR': [], 'VALUE': [], 'MAIN': None},
'OUTPUTS': {'SHADER': [], 'RGBA': [], 'VECTOR': [], 'VALUE': [], 'MAIN': None},
}
dst_sockets = {
'INPUTS': {'SHADER': [], 'RGBA': [], 'VECTOR': [], 'VALUE': [], 'MAIN': None},
'OUTPUTS': {'SHADER': [], 'RGBA': [], 'VECTOR': [], 'VALUE': [], 'MAIN': None},
}
types_order_one = 'SHADER', 'RGBA', 'VECTOR', 'VALUE'
types_order_two = 'SHADER', 'VECTOR', 'RGBA', 'VALUE'
# check src node to set src_sockets values and dst node to set dst_sockets dict values
for sockets, nd in ((src_sockets, node), (dst_sockets, new_node)):
# Check node's inputs and outputs and fill proper entries in "sockets" dict
for in_out, in_out_name in ((nd.inputs, 'INPUTS'), (nd.outputs, 'OUTPUTS')):
# enumerate in inputs, then in outputs
# find name, default value and links of socket
for i, socket in enumerate(in_out):
the_name = socket.name
dval = None
# Not every socket, especially in outputs has "default_value"
if hasattr(socket, 'default_value'):
dval = socket.default_value
socket_links = []
for lnk in socket.links:
socket_links.append(lnk)
# check type of socket to fill proper keys.
for the_type in types_order_one:
if socket.type == the_type:
# create values for sockets['INPUTS'][the_type] and sockets['OUTPUTS'][the_type]
# entry structure: (index_in_type, socket_index, socket_name,
# socket_default_value, socket_links)
sockets[in_out_name][the_type].append(
(len(sockets[in_out_name][the_type]), i, the_name, dval, socket_links))
# Check which of the types in inputs/outputs is considered to be "main".
# Set values of sockets['INPUTS']['MAIN'] and sockets['OUTPUTS']['MAIN']
for type_check in types_order_one:
if sockets[in_out_name][type_check]:
sockets[in_out_name]['MAIN'] = type_check
break
matches = {
'INPUTS': {'SHADER': [], 'RGBA': [], 'VECTOR': [], 'VALUE_NAME': [], 'VALUE': [], 'MAIN': []},
'OUTPUTS': {'SHADER': [], 'RGBA': [], 'VECTOR': [], 'VALUE_NAME': [], 'VALUE': [], 'MAIN': []},
}
for inout, soctype in (
('INPUTS', 'MAIN',),
('INPUTS', 'SHADER',),
('INPUTS', 'RGBA',),
('INPUTS', 'VECTOR',),
('INPUTS', 'VALUE',),
('OUTPUTS', 'MAIN',),
('OUTPUTS', 'SHADER',),
('OUTPUTS', 'RGBA',),
('OUTPUTS', 'VECTOR',),
('OUTPUTS', 'VALUE',),
):
if src_sockets[inout][soctype] and dst_sockets[inout][soctype]:
if soctype == 'MAIN':
sc = src_sockets[inout][src_sockets[inout]['MAIN']]
dt = dst_sockets[inout][dst_sockets[inout]['MAIN']]
else:
sc = src_sockets[inout][soctype]
dt = dst_sockets[inout][soctype]
# start with 'dt' to determine number of possibilities.
for i, soc in enumerate(dt):
# if src main has enough entries - match them with dst main sockets by indexes.
if len(sc) > i:
matches[inout][soctype].append(((sc[i][1], sc[i][3]), (soc[1], soc[3])))
# add 'VALUE_NAME' criterion to inputs.
if inout == 'INPUTS' and soctype == 'VALUE':
for s in sc:
if s[2] == soc[2]: # if names match
# append src (index, dval), dst (index, dval)
matches['INPUTS']['VALUE_NAME'].append(((s[1], s[3]), (soc[1], soc[3])))
# When src ['INPUTS']['MAIN'] is 'VECTOR' replace 'MAIN' with matches VECTOR if possible.
# This creates better links when relinking textures.
if src_sockets['INPUTS']['MAIN'] == 'VECTOR' and matches['INPUTS']['VECTOR']:
matches['INPUTS']['MAIN'] = matches['INPUTS']['VECTOR']
# Pass default values and RELINK:
for tp in ('MAIN', 'SHADER', 'RGBA', 'VECTOR', 'VALUE_NAME', 'VALUE'):
# INPUTS: Base on matches in proper order.
for (src_i, src_dval), (dst_i, dst_dval) in matches['INPUTS'][tp]:
# pass dvals
if src_dval and dst_dval and tp in {'RGBA', 'VALUE_NAME'}:
new_node.inputs[dst_i].default_value = src_dval
# Special case: switch to math
if node.type in {'MIX_RGB', 'ALPHAOVER', 'ZCOMBINE'} and\
new_node.type == 'MATH' and\
tp == 'MAIN':
new_dst_dval = max(src_dval[0], src_dval[1], src_dval[2])
new_node.inputs[dst_i].default_value = new_dst_dval
if node.type == 'MIX_RGB':
if node.blend_type in [o[0] for o in operations]:
new_node.operation = node.blend_type
# Special case: switch from math to some types
if node.type == 'MATH' and\
new_node.type in {'MIX_RGB', 'ALPHAOVER', 'ZCOMBINE'} and\
tp == 'MAIN':
for i in range(3):
new_node.inputs[dst_i].default_value[i] = src_dval
if new_node.type == 'MIX_RGB':
if node.operation in [t[0] for t in blend_types]:
new_node.blend_type = node.operation
# Set Fac of MIX_RGB to 1.0
new_node.inputs[0].default_value = 1.0
# make link only when dst matching input is not linked already.
if node.inputs[src_i].links and not new_node.inputs[dst_i].links:
in_src_link = node.inputs[src_i].links[0]
in_dst_socket = new_node.inputs[dst_i]
connect_sockets(in_src_link.from_socket, in_dst_socket)
links.remove(in_src_link)
# OUTPUTS: Base on matches in proper order.
for (src_i, src_dval), (dst_i, dst_dval) in matches['OUTPUTS'][tp]:
for out_src_link in node.outputs[src_i].links:
out_dst_socket = new_node.outputs[dst_i]
connect_sockets(out_dst_socket, out_src_link.to_socket)
# relink rest inputs if possible, no criteria
for src_inp in node.inputs:
for dst_inp in new_node.inputs:
if src_inp.links and not dst_inp.links:
src_link = src_inp.links[0]
connect_sockets(src_link.from_socket, dst_inp)
links.remove(src_link)
# relink rest outputs if possible, base on node kind if any left.
for src_o in node.outputs:
for out_src_link in src_o.links:
for dst_o in new_node.outputs:
if src_o.type == dst_o.type:
connect_sockets(dst_o, out_src_link.to_socket)
# relink rest outputs no criteria if any left. Link all from first output.
for src_o in node.outputs:
for out_src_link in src_o.links:
if new_node.outputs:
connect_sockets(new_node.outputs[0], out_src_link.to_socket)
nodes.remove(node)
force_update(context)
return {'FINISHED'}
class NWMergeNodes(Operator, NWBase):
bl_idname = "node.nw_merge_nodes"
bl_label = "Merge Nodes"
@ -2976,7 +2787,6 @@ classes = (
NWPreviewNode,
NWFrameSelected,
NWReloadImages,
NWSwitchNodeType,
NWMergeNodes,
NWBatchChangeNodes,
NWChangeMixFactor,

View File

@ -162,7 +162,6 @@ class NWNodeWrangler(bpy.types.AddonPreferences):
#
# REGISTER/UNREGISTER CLASSES AND KEYMAP ITEMS
#
switch_category_menus = []
addon_keymaps = []
# kmi_defs entry: (identifier, key, action, CTRL, SHIFT, ALT, props, nice name)
# props entry: (property name, property value)
@ -392,28 +391,8 @@ def register():
setattr(kmi.properties, prop, value)
addon_keymaps.append((km, kmi))
# switch submenus
switch_category_menus.clear()
for cat in node_categories_iter(None):
if cat.name not in ['Group', 'Script']:
idname = f"NODE_MT_nw_switch_{cat.identifier}_submenu"
switch_category_type = type(idname, (bpy.types.Menu,), {
"bl_space_type": 'NODE_EDITOR',
"bl_label": cat.name,
"category": cat,
"poll": cat.poll,
"draw": interface.draw_switch_category_submenu,
})
switch_category_menus.append(switch_category_type)
bpy.utils.register_class(switch_category_type)
def unregister():
for cat_types in switch_category_menus:
bpy.utils.unregister_class(cat_types)
switch_category_menus.clear()
# keymaps
for km, kmi in addon_keymaps:

View File

@ -6,8 +6,8 @@ bl_info = {
"name": "Collection Manager",
"description": "Manage collections and their objects",
"author": "Ryan Inch",
"version": (2, 24, 8),
"blender": (3, 0, 0),
"version": (2, 24, 9),
"blender": (4, 0, 0),
"location": "View3D - Object Mode (Shortcut - M)",
"warning": '', # used for warning icon and text in addons panel
"doc_url": "{BLENDER_MANUAL_URL}/addons/interface/collection_manager.html",

View File

@ -50,7 +50,7 @@ def get_tool_text(self):
return self["tool_text_color"]
else:
color = bpy.context.preferences.themes[0].user_interface.wcol_tool.text
self["tool_text_color"] = color.r, color.g, color.b
self["tool_text_color"] = color[0], color[1], color[2]
return self["tool_text_color"]
def set_tool_text(self, values):
@ -62,7 +62,7 @@ def get_tool_text_sel(self):
return self["tool_text_sel_color"]
else:
color = bpy.context.preferences.themes[0].user_interface.wcol_tool.text_sel
self["tool_text_sel_color"] = color.r, color.g, color.b
self["tool_text_sel_color"] = color[0], color[1], color[2]
return self["tool_text_sel_color"]
def set_tool_text_sel(self, values):
@ -98,11 +98,11 @@ def get_tool_outline(self):
return self["tool_outline_color"]
else:
color = bpy.context.preferences.themes[0].user_interface.wcol_tool.outline
self["tool_outline_color"] = color.r, color.g, color.b
self["tool_outline_color"] = color[0], color[1], color[2], color[3]
return self["tool_outline_color"]
def set_tool_outline(self, values):
self["tool_outline_color"] = values[0], values[1], values[2]
self["tool_outline_color"] = values[0], values[1], values[2], values[3]
def get_menu_back_text(self):
@ -110,7 +110,7 @@ def get_menu_back_text(self):
return self["menu_back_text_color"]
else:
color = bpy.context.preferences.themes[0].user_interface.wcol_menu_back.text
self["menu_back_text_color"] = color.r, color.g, color.b
self["menu_back_text_color"] = color[0], color[1], color[2]
return self["menu_back_text_color"]
def set_menu_back_text(self, values):
@ -134,11 +134,11 @@ def get_menu_back_outline(self):
return self["menu_back_outline_color"]
else:
color = bpy.context.preferences.themes[0].user_interface.wcol_menu_back.outline
self["menu_back_outline_color"] = color.r, color.g, color.b
self["menu_back_outline_color"] = color[0], color[1], color[2], color[3]
return self["menu_back_outline_color"]
def set_menu_back_outline(self, values):
self["menu_back_outline_color"] = values[0], values[1], values[2]
self["menu_back_outline_color"] = values[0], values[1], values[2], values[3]
def get_tooltip_text(self):
@ -146,7 +146,7 @@ def get_tooltip_text(self):
return self["tooltip_text_color"]
else:
color = bpy.context.preferences.themes[0].user_interface.wcol_tooltip.text
self["tooltip_text_color"] = color.r, color.g, color.b
self["tooltip_text_color"] = color[0], color[1], color[2]
return self["tooltip_text_color"]
def set_tooltip_text(self, values):
@ -170,11 +170,11 @@ def get_tooltip_outline(self):
return self["tooltip_outline_color"]
else:
color = bpy.context.preferences.themes[0].user_interface.wcol_tooltip.outline
self["tooltip_outline_color"] = color.r, color.g, color.b
self["tooltip_outline_color"] = color[0], color[1], color[2], color[3]
return self["tooltip_outline_color"]
def set_tooltip_outline(self, values):
self["tooltip_outline_color"] = values[0], values[1], values[2]
self["tooltip_outline_color"] = values[0], values[1], values[2], values[3]
class CMPreferences(AddonPreferences):

View File

@ -771,7 +771,7 @@ def draw_callback_px(self, context):
main_window = self.areas["Main Window"]
outline_color = addon_prefs.qcd_ogl_widget_menu_back_outline
background_color = addon_prefs.qcd_ogl_widget_menu_back_inner
draw_rounded_rect(main_window, line_shader, outline_color[:] + (1,), outline=True)
draw_rounded_rect(main_window, line_shader, outline_color[:], outline=True)
draw_rounded_rect(main_window, shader, background_color)
# draw window title
@ -852,7 +852,7 @@ def draw_callback_px(self, context):
# draw button
outline_color = addon_prefs.qcd_ogl_widget_tool_outline
draw_rounded_rect(button_area, line_shader, outline_color[:] + (1,), tl, tr, bl, br, outline=True)
draw_rounded_rect(button_area, line_shader, outline_color[:], tl, tr, bl, br, outline=True)
draw_rounded_rect(button_area, shader, button_color, tl, tr, bl, br)
# ACTIVE OBJECT
@ -979,7 +979,7 @@ def draw_tooltip(self, context, shader, line_shader, message):
outline_color = addon_prefs.qcd_ogl_widget_tooltip_outline
background_color = addon_prefs.qcd_ogl_widget_tooltip_inner
draw_rounded_rect(tooltip, line_shader, outline_color[:] + (1,), outline=True)
draw_rounded_rect(tooltip, line_shader, outline_color[:], outline=True)
draw_rounded_rect(tooltip, shader, background_color)
line_pos = padding + line_height