""" Copyright (C) 2023 Adobe. 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 . """ # file: sbsar/sbsar.py # brief: Substance class object definition # author Adobe - 3D & Immersive # copyright 2023 Adobe Inc. All rights reserved. from ..utils import SUBSTANCE_Utils from ..common import ( Code_InputType, Code_InputWidget, INPUT_DEFAULT_GROUP, INPUT_IMAGE_DEFAULT_GROUP, PRESET_CUSTOM, CLASS_GRAPH_INPUTS ) class SBS_EnumValue(): def __init__(self, enum): self.first = enum["first"] self.second = enum["second"] def to_json(self): _obj = { "first": self.first, "second": self.second, } return _obj class SBS_Input(): def __init__(self, index, input): if "index" in input: self.index = input["index"] else: self.index = index self.id = input["id"] self.graphID = input["graphID"] self.identifier = input["identifier"] self.label = input["label"] self.guiDescription = input["guiDescription"] if input["type"] == Code_InputType.image.name: self.guiGroup = INPUT_IMAGE_DEFAULT_GROUP elif len(input["guiGroup"]) == 0: self.guiGroup = INPUT_DEFAULT_GROUP else: self.guiGroup = input["guiGroup"] self.guiVisibleIf = input["guiVisibleIf"] self.userTag = input["userTag"] self.type = input["type"] self.guiWidget = input["guiWidget"] self.showAsPin = input["showAsPin"] self.useCache = input["useCache"] self.visibleIf = input["visibleIf"] self.isHeavyDuty = input["isHeavyDuty"] self.enumValues = [] if "labelFalse" in input: self.labelFalse = input["labelFalse"] if "labelTrue" in input: self.labelTrue = input["labelTrue"] if "sliderClamp" in input: self.sliderClamp = input["sliderClamp"] if "sliderStep" in input: self.sliderStep = input["sliderStep"] if "maxValue" in input: self.maxValue = input["maxValue"] if "minValue" in input: self.minValue = input["minValue"] if "defaultValue" in input: self.defaultValue = input["defaultValue"] if "value" in input: self.value = input["value"] if "channelUse" in input: self.channelUse = input["channelUse"] if "enumValues" in input: for _enum in input["enumValues"]: _new_enum = SBS_EnumValue(_enum) self.enumValues.append(_new_enum) def to_json(self): _obj = { "id": self.id, "graphID": self.graphID, "identifier": self.identifier, "label": self.label, "guiDescription": self.guiDescription, "guiGroup": self.guiGroup, "guiVisibleIf": self.guiVisibleIf, "userTag": self.userTag, "type": self.type, "guiWidget": self.guiWidget, "showAsPin": self.showAsPin, "useCache": self.useCache, "visibleIf": self.visibleIf, "isHeavyDuty": self.isHeavyDuty } if hasattr(self, "labelFalse"): _obj["labelFalse"] = self.labelFalse if hasattr(self, "labelTrue"): _obj["labelTrue"] = self.labelTrue if hasattr(self, "sliderClamp"): _obj["sliderClamp"] = self.sliderClamp if hasattr(self, "sliderStep"): _obj["sliderStep"] = self.sliderStep if hasattr(self, "maxValue"): _obj["maxValue"] = self.maxValue if hasattr(self, "minValue"): _obj["minValue"] = self.minValue if hasattr(self, "defaultValue"): _obj["defaultValue"] = self.defaultValue if hasattr(self, "value"): _obj["value"] = self.value if hasattr(self, "channelUse"): _obj["channelUse"] = self.channelUse if hasattr(self, "enumValues"): _obj["enumValues"] = self.enumValues return _obj class SBS_Output(): def __init__(self, output, index): self.id = output["id"] self.index = index self.graphID = output["graphID"] self.format = output["format"] self.mipmaps = output["mipmaps"] self.identifier = output["identifier"] self.label = output["label"] self.guiDescription = output["guiDescription"] self.group = output["group"] self.guiVisibleIf = output["guiVisibleIf"] self.userTag = output["userTag"] self.type = output["type"] self.guiType = output["guiType"] self.defaultChannelUse = output["defaultChannelUse"] self.enabled = output["enabled"] self.channelUseSpecified = output["channelUseSpecified"] self.channelUse = output["channelUse"] def to_json(self): _obj = { "id": self.id, "graphID": self.graphID, "format": self.format, "mipmaps": self.mipmaps, "identifier": self.identifier, "label": self.label, "guiDescription": self.guiDescription, "group": self.group, "guiVisibleIf": self.guiVisibleIf, "userTag": self.userTag, "type": self.type, "guiType": self.guiType, "defaultChannelUse": self.defaultChannelUse, "enabled": self.enabled, "channelUseSpecified": self.channelUseSpecified, "channelUse": self.channelUse } return _obj class SBS_Preset(): def __init__(self, preset, addon_prefs=None, inputs=None): self.index = str(preset["index"]) self.label = preset["label"] self.value = preset["value"] if "icon" in preset: self.icon = preset["icon"] else: self.icon = "LOCKED" if self.label != PRESET_CUSTOM else "UNLOCKED" if "embedded" in preset: self.embedded = preset["embedded"] else: self.embedded = True if self.label != PRESET_CUSTOM else False if addon_prefs is not None and inputs is not None: if "$outputsize" in inputs: self.value = SUBSTANCE_Utils.update_preset_outputsize( self.value, inputs["$outputsize"], Code_InputType.integer2.value, addon_prefs.default_resolution.get()) if "normal_format" in inputs: self.value = SUBSTANCE_Utils.update_preset_outputsize( self.value, inputs["normal_format"], Code_InputType.integer.value, 0 if addon_prefs.default_normal_format == "DirectX" else 1) def to_json(self): _obj = { "index": int(self.index), "label": self.label, "value": self.value, "icon": self.icon, "embedded": self.embedded } return _obj class SBS_Graph(): def __init__(self, unique_name, uuid, index, graph, multi_graph, addon_prefs=None): self.index = str(index) self.uid = str(graph["uid"]) self.label = graph["label"] self.identifier = graph["packageUrl"].replace("pkg://", "") self.packageUrl = graph["packageUrl"] if graph["physicalSize"][0] == 0 or graph["physicalSize"][1] == 0: self.physicalSize = (1/100, 1/100, 1/100) else: self.physicalSize = (graph["physicalSize"][0]/100, graph["physicalSize"][1]/100, graph["physicalSize"][2]/100) self.tiling = addon_prefs.default_tiling.get() self.inputs = {} self.inputs_groups = {} self.outputs = {} self.presets = [] if multi_graph: _material_name = "{}-{}".format(unique_name, graph["label"]).replace(" ", "_") _class_name = "{}-{}".format(uuid, self.uid) else: _material_name = "{}".format(unique_name).replace(" ", "_") _class_name = "{}".format(uuid) self.material = _material_name self.inputs_class_name = CLASS_GRAPH_INPUTS.format(_class_name) if len(graph["inputs"]) > 0 and "index" in graph["inputs"][0]: _sorted_inputs = sorted(graph["inputs"], key=lambda d: d['index']) else: _sorted_inputs = graph["inputs"] _input_index = 0 for _input in _sorted_inputs: if _input["guiWidget"] != Code_InputWidget.nowidget.value or _input["type"] != Code_InputType.string.name: if _input["type"] == Code_InputType.image.name: _group = INPUT_IMAGE_DEFAULT_GROUP else: _group = _input["guiGroup"] if len(_input["guiGroup"]) > 0 else INPUT_DEFAULT_GROUP if _group not in self.inputs_groups: self.inputs_groups[_group] = [_input["identifier"]] else: self.inputs_groups[_group].append(_input["identifier"]) _new_input = SBS_Input(_input_index, _input) _input_index += 1 self.inputs[_input["identifier"]] = _new_input for _idx, _output in enumerate(graph["outputs"]): _new_output = SBS_Output(_output, _idx) self.outputs[_output["identifier"]] = _new_output _pre_sort_presets = [] for _preset in graph["presets"]: _new_preset = SBS_Preset(_preset, addon_prefs, self.inputs) _pre_sort_presets.append(_new_preset) self.presets = sorted(_pre_sort_presets, key=lambda _preset: _preset.index, reverse=False) def to_json(self): _obj = { "uid": self.uid, "label": self.label, "physicalSize": self.physicalSize, "inputs": [], "outputs": [], "presets": [] } for _preset in self.presets: _obj["presets"].append(_preset.to_json()) for _key, _output in self.outputs.items(): _obj["outputs"].append(_output.to_json()) for _key, _input in self.inputs.items(): _obj["inputs"].append(_input.to_json()) return _obj def reset_presets(self, presets): self.presets = [] _pre_sort_presets = [] for _preset in presets: _new_preset = SBS_Preset(_preset) _pre_sort_presets.append(_new_preset) self.presets = sorted(_pre_sort_presets, key=lambda _preset: _preset.index, reverse=False) class SBSAR(): def __init__(self, unique_name, filename, data, addon_prefs=None): self.uuid = data["uuid"] self.version = data["version"] self.name = unique_name self.filename = filename self.filepath = data["filename"] self.graphs = [] _multi_graph = len(data["graphs"]) > 1 for _idx, _graph in enumerate(data["graphs"]): _new_graph = SBS_Graph(unique_name, self.uuid, _idx, _graph, _multi_graph, addon_prefs) self.graphs.append(_new_graph) def to_json(self): _obj = { "uuid": self.uuid, "name": self.name, "filename": self.filename, "filepath": self.filepath, "graphs": [] } for _graph in self.graphs: _obj["graphs"].append(_graph.to_json()) return _obj