feat: added initial nodegroup support

This commit is contained in:
Swann 2020-11-11 14:09:57 +01:00
parent 4391510d7b
commit 30d734c2c1
No known key found for this signature in database
GPG Key ID: E1D3641A7C43AACB
5 changed files with 113 additions and 9 deletions

View File

@ -37,7 +37,8 @@ __all__ = [
'bl_speaker',
'bl_font',
'bl_sound',
'bl_file'
'bl_file',
'bl_node_group'
] # Order here defines execution order
from . import *

View File

@ -40,11 +40,15 @@ def load_node(node_data, node_tree):
target_node.select = False
loader.load(target_node, node_data)
image_uuid = node_data.get('image_uuid', None)
node_tree_uuid = node_data.get('node_tree_uuid', None)
if image_uuid and not target_node.image:
target_node.image = get_datablock_from_uuid(image_uuid, None)
if node_tree_uuid:
target_node.node_tree = get_datablock_from_uuid(node_tree_uuid, None)
for idx, inpt in enumerate(node_data["inputs"]):
for idx, inpt in enumerate(node_data['inputs']):
if hasattr(target_node.inputs[idx], "default_value"):
try:
target_node.inputs[idx].default_value = inpt["default_value"]
@ -52,7 +56,7 @@ def load_node(node_data, node_tree):
logging.error(
f"Material {inpt.keys()} parameter not supported, skipping")
for idx, output in enumerate(node_data["outputs"]):
for idx, output in enumerate(node_data['outputs']):
if hasattr(target_node.outputs[idx], "default_value"):
try:
target_node.outputs[idx].default_value = output["default_value"]
@ -148,6 +152,9 @@ def dump_node(node):
io_dumper.depth = 2
io_dumper.include_filter = ["default_value"]
if node.type in ['GROUP_INPUT', 'GROUP_OUTPUT']:
io_dumper.include_filter.extend(['name','type'])
for idx, inpt in enumerate(node.inputs):
if hasattr(inpt, 'default_value'):
dumped_node['inputs'].append(io_dumper.dump(inpt))
@ -178,6 +185,8 @@ def dump_node(node):
dumped_node['mapping'] = curve_dumper.dump(node.mapping)
if hasattr(node, 'image') and getattr(node, 'image'):
dumped_node['image_uuid'] = node.image.uuid
if hasattr(node, 'node_tree') and getattr(node, 'node_tree'):
dumped_node['node_tree_uuid'] = node.node_tree.uuid
return dumped_node
@ -188,11 +197,19 @@ def dump_shader_node_tree(node_tree:bpy.types.ShaderNodeTree)->dict:
:type node_tree: bpy.types.ShaderNodeTree
:return: dict
"""
return {
node_tree_data = {
'nodes': {node.name: dump_node(node) for node in node_tree.nodes},
'links': dump_links(node_tree.links)
'links': dump_links(node_tree.links),
'name': node_tree.name,
'type': type(node_tree).__name__
}
if node_tree.inputs:
node_tree_data['inputs'] = [(i.name, i.bl_socket_idname, i.identifier) for i in node_tree.inputs]
if node_tree.outputs:
node_tree_data['outputs'] = [(o.name, o.bl_socket_idname)for o in node_tree.outputs]
return node_tree_data
def load_shader_node_tree(node_tree_data:dict, target_node_tree:bpy.types.ShaderNodeTree)->dict:
"""
@ -205,6 +222,35 @@ def load_shader_node_tree(node_tree_data:dict, target_node_tree:bpy.types.Shader
# TODO: load only required nodes
target_node_tree.nodes.clear()
if not target_node_tree.is_property_readonly('name'):
target_node_tree.name = node_tree_data['name']
if 'inputs' in node_tree_data:
for inpt in target_node_tree.inputs:
if not [i for i in node_tree_data['inputs'] if inpt.identifier == i[2]]:
target_node_tree.inputs.remove(inpt)
for idx, socket_data in enumerate(node_tree_data['inputs']):
try:
checked_input = target_node_tree.inputs[idx]
if checked_input.name != socket_data[0]:
checked_input.name = socket_data[0]
except Exception:
target_node_tree.inputs.new(socket_data[1], socket_data[0])
if 'outputs' in node_tree_data:
for inpt in target_node_tree.outputs:
if not [o for o in node_tree_data['outputs'] if inpt.identifier == o[2]]:
target_node_tree.outputs.remove(inpt)
for idx, socket_data in enumerate(node_tree_data['outputs']):
try:
checked_outputs = target_node_tree.outputs[idx]
if checked_outputs.name != socket_data[0]:
checked_outputs.name = socket_data[0]
except Exception:
target_node_tree.outputs.new(socket_data[1], socket_data[0])
# Load nodes
for node in node_tree_data["nodes"]:
load_node(node_tree_data["nodes"][node], target_node_tree)
@ -218,8 +264,17 @@ def load_shader_node_tree(node_tree_data:dict, target_node_tree:bpy.types.Shader
def get_node_tree_dependencies(node_tree: bpy.types.NodeTree) -> list:
has_image = lambda node : (node.type in ['TEX_IMAGE', 'TEX_ENVIRONMENT'] and node.image)
has_node_group = lambda node : (hasattr(node,'node_tree') and node.node_tree)
return [node.image for node in node_tree.nodes if has_image(node)]
deps = []
for node in node_tree.nodes:
if has_image(node):
deps.append(node.image)
elif has_node_group(node):
deps.append(node.node_tree)
return deps
class BlMaterial(BlDatablock):

View File

@ -0,0 +1,47 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# ##### END GPL LICENSE BLOCK #####
import bpy
import mathutils
from .dump_anything import Dumper, Loader, np_dump_collection, np_load_collection
from .bl_datablock import BlDatablock
from .bl_material import (dump_shader_node_tree,
load_shader_node_tree,
get_node_tree_dependencies)
class BlNodeGroup(BlDatablock):
bl_id = "node_groups"
bl_class = bpy.types.ShaderNodeTree
bl_delay_refresh = 1
bl_delay_apply = 1
bl_automatic_push = True
bl_check_common = False
bl_icon = 'NODETREE'
def _construct(self, data):
return bpy.data.node_groups.new(data["name"], data["type"])
def _load_implementation(self, data, target):
load_shader_node_tree(data, target)
def _dump_implementation(self, data, instance=None):
return dump_shader_node_tree(instance)
def _resolve_deps_implementation(self):
return get_node_tree_dependencies(self.instance)

View File

@ -166,7 +166,8 @@ class SessionStartOperator(bpy.types.Operator):
# init the factory with supported types
for type in bl_types.types_to_register():
type_module = getattr(bl_types, type)
type_impl_name = f"Bl{type.split('_')[1].capitalize()}"
name = [e.capitalize() for e in type.split('_')[1:]]
type_impl_name = 'Bl'+''.join(name)
type_module_class = getattr(type_module, type_impl_name)
supported_bl_types.append(type_module_class.bl_id)

View File

@ -462,9 +462,9 @@ class SessionPrefs(bpy.types.AddonPreferences):
new_db = self.supported_datablocks.add()
type_module = getattr(bl_types, type)
type_impl_name = f"Bl{type.split('_')[1].capitalize()}"
name = [e.capitalize() for e in type.split('_')[1:]]
type_impl_name = 'Bl'+''.join(name)
type_module_class = getattr(type_module, type_impl_name)
new_db.name = type_impl_name
new_db.type_name = type_impl_name
new_db.bl_delay_refresh = type_module_class.bl_delay_refresh