diff --git a/blender/addons/io_scene_foundry/managed_blam/object.py b/blender/addons/io_scene_foundry/managed_blam/object.py index 3a4b9f52..4e084c02 100644 --- a/blender/addons/io_scene_foundry/managed_blam/object.py +++ b/blender/addons/io_scene_foundry/managed_blam/object.py @@ -36,7 +36,6 @@ def set_model_tag_path(self, new_path: str): self.tag_has_changes = True def get_change_colors(self, variant="") -> list: - print("CC VARIANT: ", variant) change_colors = [tuple((1, 1, 1, 1)), tuple((1, 1, 1, 1)), tuple((1, 1, 1, 1)), tuple((1, 1, 1, 1))] if not variant: variant = self.default_variant.GetStringData() diff --git a/blender/addons/io_scene_foundry/managed_blam/render_method_definition.py b/blender/addons/io_scene_foundry/managed_blam/render_method_definition.py index 1315220d..7b638a25 100644 --- a/blender/addons/io_scene_foundry/managed_blam/render_method_definition.py +++ b/blender/addons/io_scene_foundry/managed_blam/render_method_definition.py @@ -23,13 +23,15 @@ def get_categories(self): return categories - def get_default_bitmaps(self): + def get_defaults(self): defaults = {} + parameter_types = {} for element in self.block_categories.Elements: for sub_element in element.Fields[1].Elements: option_path = sub_element.Fields[1].Path if option_path is not None: with RenderMethodOptionTag(path=option_path) as render_method_option: defaults.update(render_method_option.read_default_bitmaps()) + parameter_types.update(render_method_option.read_parameter_types()) - return defaults \ No newline at end of file + return defaults, parameter_types \ No newline at end of file diff --git a/blender/addons/io_scene_foundry/managed_blam/render_method_option.py b/blender/addons/io_scene_foundry/managed_blam/render_method_option.py index d36ecfdb..956647c1 100644 --- a/blender/addons/io_scene_foundry/managed_blam/render_method_option.py +++ b/blender/addons/io_scene_foundry/managed_blam/render_method_option.py @@ -14,6 +14,9 @@ def read_options(self): parameters[e.SelectField('parameter name').GetStringData()] = [e.SelectField('parameter ui override name').GetStringData(), e.SelectField('parameter type').Value] return parameters + def read_parameter_types(self): + return {element.Fields[0].GetStringData(): element.Fields[2].Value for element in self.block_parameters.Elements} + def read_default_bitmaps(self) -> dict: """Returns a dict of parameter names and their default bitmaps""" return {element.Fields[0].GetStringData(): element.Fields[4].Path for element in self.block_parameters.Elements} \ No newline at end of file diff --git a/blender/addons/io_scene_foundry/managed_blam/shader.py b/blender/addons/io_scene_foundry/managed_blam/shader.py index 2c9351d2..e5166e84 100644 --- a/blender/addons/io_scene_foundry/managed_blam/shader.py +++ b/blender/addons/io_scene_foundry/managed_blam/shader.py @@ -18,6 +18,7 @@ global_render_method_definition = None last_group_node = None default_parameter_bitmaps = None +shader_parameters = None class ChannelType(Enum): DEFAULT = 0 @@ -142,15 +143,16 @@ def _read_fields(self): self.reference = self.render_method.SelectField('reference') self.definition = self.render_method.SelectField('definition') - def _get_default_bitmaps(self): + def _get_info(self): global default_parameter_bitmaps + global shader_parameters if default_parameter_bitmaps is None: def_path = self.definition.Path if def_path is None: default_parameter_bitmaps = {} return with RenderMethodDefinitionTag(path=def_path) as render_method_definition: - default_parameter_bitmaps = render_method_definition.get_default_bitmaps() + default_parameter_bitmaps, shader_parameters = render_method_definition.get_defaults() def write_tag(self, blender_material, linked_to_blender, material_shader=''): self.blender_material = blender_material @@ -448,11 +450,11 @@ def _source_from_input_and_parameter_type(self, input, parameter_type): # READING - def to_nodes(self, blender_material, change_colors=None): + def to_nodes(self, blender_material): shader_path: str = blender_material.nwo.shader_path - self._get_default_bitmaps() + self._get_info() if self.group_supported: - self._to_nodes_group(blender_material, change_colors) + self._to_nodes_group(blender_material) else: self._to_nodes_bsdf(blender_material) @@ -467,7 +469,6 @@ def _option_value_from_index(self, index): return option_enum def _mapping_from_parameter_name(self, name, mapping={}): - the_one = name == "bump_detail_map" and self.tag_path.RelativePathWithExtension == r"objects\characters\spartans\shaders\spartan_rubber_suit.shader" if type(name) == str: element = self._Element_from_field_value(self.block_parameters, 'parameter name', name) else: @@ -502,8 +503,9 @@ def _mapping_from_parameter_name(self, name, mapping={}): with ShaderTag(path=self.reference.Path) as shader: shader._mapping_from_parameter_name(name, mapping) - def _image_from_parameter_name(self, name, blue_channel_fix=False, default_bitmap=None): + def _image_from_parameter_name(self, name, blue_channel_fix=False): """Saves an image (or gets the already existing one) from a shader parameter element""" + bitmap_path = None if type(name) == str: element = self._Element_from_field_value(self.block_parameters, 'parameter name', name) else: @@ -515,9 +517,12 @@ def _image_from_parameter_name(self, name, blue_channel_fix=False, default_bitma with ShaderTag(path=self.reference.Path) as shader: return shader._image_from_parameter_name(name) else: - return - - bitmap_path = element.SelectField('bitmap').Path + bitmap_path = default_parameter_bitmaps.get(name) + if bitmap_path is None: + return + + if bitmap_path is None: + bitmap_path = element.SelectField('bitmap').Path if bitmap_path is None: if not self.corinth and self.reference.Path: @@ -525,8 +530,7 @@ def _image_from_parameter_name(self, name, blue_channel_fix=False, default_bitma result = shader._image_from_parameter_name(name) if result is not None: return result - bitmap_path = default_bitmap - if bitmap_path is None: + else: bitmap_path = default_parameter_bitmaps.get(name) if bitmap_path is None: return @@ -577,7 +581,6 @@ def _normal_type_from_parameter_name(self, name): return NormalType.OPENGL def _color_from_parameter_name(self, name): - color = [1, 1, 1, 1] if type(name) == str: element = self._Element_from_field_value(self.block_parameters, 'parameter name', name) else: @@ -590,20 +593,21 @@ def _color_from_parameter_name(self, name): return shader._color_from_parameter_name(name) else: return - - block_animated_parameters = element.SelectField(self.function_parameters) - color_element = self._Element_from_field_value(block_animated_parameters, 'type', 1) - if color_element: - game_color = color_element.SelectField(self.animated_function).Value.GetColor(0) - if game_color.ColorMode == 1: # Is HSV - game_color = game_color.ToRgb() - - color = [game_color.Red, game_color.Green, game_color.Blue, game_color.Alpha] - - return color + else: + block_animated_parameters = element.SelectField(self.function_parameters) + color_element = self._Element_from_field_value(block_animated_parameters, 'type', 1) + if color_element: + game_color = color_element.SelectField(self.animated_function).Value.GetColor(0) + if game_color.ColorMode == 1: # Is HSV + game_color = game_color.ToRgb() + + return [game_color.Red, game_color.Green, game_color.Blue, game_color.Alpha] + else: + if not self.corinth and self.reference.Path: + with ShaderTag(path=self.reference.Path) as shader: + return shader._color_from_parameter_name(name) def _value_from_parameter_name(self, name): - value = 0 if type(name) == str: element = self._Element_from_field_value(self.block_parameters, 'parameter name', name) else: @@ -616,17 +620,15 @@ def _value_from_parameter_name(self, name): return shader._value_from_parameter_name(name) else: return - - block_animated_parameters = element.SelectField(self.function_parameters) - color_element = self._Element_from_field_value(block_animated_parameters, 'type', 1) - if color_element: - game_color = color_element.SelectField(self.animated_function).Value.GetColor(0) - if game_color.ColorMode == 1: # Is HSV - game_color = game_color.ToRgb() - - color = [game_color.Red, game_color.Green, game_color.Blue, game_color.Alpha] - - return value + else: + block_animated_parameters = element.SelectField(self.function_parameters) + value_element = self._Element_from_field_value(block_animated_parameters, 'type', 0) + if value_element: + return value_element.SelectField(self.animated_function).Value.ClampRangeMin + else: + if not self.corinth and self.reference.Path: + with ShaderTag(path=self.reference.Path) as shader: + return shader._value_from_parameter_name(name) def _set_alpha(self, alpha_type, blender_material): if alpha_type == 'blend': @@ -746,8 +748,8 @@ def get_diffuse_bitmap_data_for_granny(self) -> None | tuple: with BitmapTag(path=bitmap_path) as bitmap: return bitmap.get_granny_data(fill_alpha, calc_blue) - def group_set_image(self, tree: bpy.types.NodeTree, node: bpy.types.Node, parameter_name: str, vector: Vector, channel_type=ChannelType.DEFAULT, normal_type: NormalType = None, return_image_node=False, default_bitmap=None): - data = self._image_from_parameter_name(parameter_name, normal_type is not None, default_bitmap=default_bitmap) + def group_set_image(self, tree: bpy.types.NodeTree, node: bpy.types.Node, parameter_name: str, vector: Vector, channel_type=ChannelType.DEFAULT, normal_type: NormalType = None, return_image_node=False): + data = self._image_from_parameter_name(parameter_name, normal_type is not None) if data is None: if return_image_node: @@ -875,7 +877,7 @@ def _add_group_material_model(self, tree: bpy.types.NodeTree, nodes: bpy.types.N node_material_model.location = location return node_material_model - def _to_nodes_group(self, blender_material: bpy.types.Material, change_colors: list = None): + def _to_nodes_group(self, blender_material: bpy.types.Material): # Get options e_albedo = Albedo(self._option_value_from_index(0)) @@ -919,12 +921,32 @@ def _to_nodes_group(self, blender_material: bpy.types.Material, change_colors: l node_albedo = self._add_group_node(tree, nodes, f"albedo - {utils.game_str(e_albedo.name)}", Vector((node_material_model.location.x - 300, node_material_model.location.y + 500))) - if e_albedo in {Albedo.FOUR_CHANGE_COLOR, Albedo.FOUR_CHANGE_COLOR_APPLYING_TO_SPECULAR, Albedo.TWO_CHANGE_COLOR} and change_colors: - node_albedo.inputs["Primary Color"].default_value = change_colors[0] - node_albedo.inputs["Secondary Color"].default_value = change_colors[1] + if e_albedo in {Albedo.FOUR_CHANGE_COLOR, Albedo.FOUR_CHANGE_COLOR_APPLYING_TO_SPECULAR, Albedo.TWO_CHANGE_COLOR}: + node_cc_primary = nodes.new(type="ShaderNodeAttribute") + node_cc_primary.attribute_name = "nwo.cc_primary" + node_cc_primary.attribute_type = 'OBJECT' + node_cc_primary.location.x = node_albedo.location.x - 300 + node_cc_primary.location.y = node_albedo.location.y + 200 + tree.links.new(input=node_albedo.inputs["Primary Color"], output=node_cc_primary.outputs[0]) + node_cc_secondary = nodes.new(type="ShaderNodeAttribute") + node_cc_secondary.attribute_name = "nwo.cc_secondary" + node_cc_secondary.attribute_type = 'OBJECT' + node_cc_secondary.location.x = node_albedo.location.x - 300 + node_cc_secondary.location.y = node_albedo.location.y + tree.links.new(input=node_albedo.inputs["Secondary Color"], output=node_cc_secondary.outputs[0]) if e_albedo != Albedo.TWO_CHANGE_COLOR: - node_albedo.inputs["Tertiary Color"].default_value = change_colors[2] - node_albedo.inputs["Quaternary Color"].default_value = change_colors[3] + node_cc_tertiary = nodes.new(type="ShaderNodeAttribute") + node_cc_tertiary.attribute_name = "nwo.cc_tertiary" + node_cc_tertiary.attribute_type = 'OBJECT' + node_cc_tertiary.location.x = node_albedo.location.x - 300 + node_cc_tertiary.location.y = node_albedo.location.y - 200 + tree.links.new(input=node_albedo.inputs["Tertiary Color"], output=node_cc_tertiary.outputs[0]) + node_cc_quaternary = nodes.new(type="ShaderNodeAttribute") + node_cc_quaternary.attribute_name = "nwo.cc_quaternary" + node_cc_quaternary.attribute_type = 'OBJECT' + node_cc_quaternary.location.x = node_albedo.location.x - 300 + node_cc_quaternary.location.y = node_albedo.location.y - 400 + tree.links.new(input=node_albedo.inputs["Quaternary Color"], output=node_cc_quaternary.outputs[0]) tree.links.new(input=node_material_model.inputs[0], output=node_albedo.outputs[0]) if e_material_model.value > 0: # Diffuse only does not have alpha input @@ -986,37 +1008,13 @@ def _to_nodes_group(self, blender_material: bpy.types.Material, change_colors: l tree.links.new(input=node_output.inputs[0], output=final_node.outputs[0]) def group_set_color(self, tree: bpy.types.NodeTree, node: bpy.types.Node, parameter_name: str): - element = self._Element_from_field_value(self.block_parameters, 'parameter name', parameter_name) - if element is None: - if not self.corinth and self.reference.Path: - with ShaderTag(path=self.reference.Path) as shader: - return shader.group_set_color(parameter_name) - else: - return - - block_animated_parameters = element.SelectField(self.function_parameters) - color_element = self._Element_from_field_value(block_animated_parameters, 'type', 1) - if color_element: - game_color = color_element.SelectField(self.animated_function).Value.GetColor(0) - if game_color.ColorMode == 1: # Is HSV - game_color = game_color.ToRgb() - - color = [game_color.Red, game_color.Green, game_color.Blue, game_color.Alpha] + color = self._color_from_parameter_name(parameter_name) + if color is not None: node.inputs[parameter_name].default_value = color def group_set_value(self, tree: bpy.types.NodeTree, node: bpy.types.Node, parameter_name: str): - element = self._Element_from_field_value(self.block_parameters, 'parameter name', parameter_name) - if element is None: - if not self.corinth and self.reference.Path: - with ShaderTag(path=self.reference.Path) as shader: - return shader.group_set_value(parameter_name) - else: - return - - block_animated_parameters = element.SelectField(self.function_parameters) - value_element = self._Element_from_field_value(block_animated_parameters, 'type', 0) - if value_element: - value = value_element.SelectField(self.animated_function).Value.ClampRangeMin + value = self._value_from_parameter_name(parameter_name) + if value is not None: node.inputs[parameter_name].default_value = value def group_set_flag(self, tree: bpy.types.NodeTree, node: bpy.types.Node, parameter_name: str): @@ -1041,12 +1039,7 @@ def populate_chiefster_node(self, tree: bpy.types.NodeTree, node: bpy.types.Node tree.links.new(input=alpha_input, output=last_input_node.outputs[1]) else: parameter_type = self._parameter_type_from_name(parameter_name) - default_bitmap = None - if parameter_type == ParameterType.NONE: - default_bitmap = default_parameter_bitmaps.get(parameter_name) - if default_bitmap is None: - last_parameter_name = None - continue + parameter_type = ParameterType(shader_parameters.get(parameter_name, -1)) match parameter_type: case ParameterType.COLOR | ParameterType.ARGB_COLOR: @@ -1055,11 +1048,11 @@ def populate_chiefster_node(self, tree: bpy.types.NodeTree, node: bpy.types.Node self.group_set_value(tree, node, parameter_name) case _: if ".rgb" in input.name: - location, last_input_node = self.group_set_image(tree, node, parameter_name, location, ChannelType.RGB, return_image_node=True, default_bitmap=default_bitmap) + location, last_input_node = self.group_set_image(tree, node, parameter_name, location, ChannelType.RGB, return_image_node=True) elif ".a" in input.name: - location, last_input_node = self.group_set_image(tree, node, parameter_name, location, ChannelType.ALPHA, return_image_node=True, default_bitmap=default_bitmap) + location, last_input_node = self.group_set_image(tree, node, parameter_name, location, ChannelType.ALPHA, return_image_node=True) else: - location, last_input_node = self.group_set_image(tree, node, parameter_name, location, ChannelType.DEFAULT, return_image_node=True, default_bitmap=default_bitmap) + location, last_input_node = self.group_set_image(tree, node, parameter_name, location, ChannelType.DEFAULT, return_image_node=True) last_parameter_name = parameter_name diff --git a/blender/addons/io_scene_foundry/props/material.py b/blender/addons/io_scene_foundry/props/material.py index 5fa1e4fe..ff5f8a53 100644 --- a/blender/addons/io_scene_foundry/props/material.py +++ b/blender/addons/io_scene_foundry/props/material.py @@ -23,7 +23,7 @@ def update_shader(self, context): options=set(), ) - prev_shader_path: StringProperty() + prev_shader_path: StringProperty(options={'HIDDEN'}) def recursive_image_search_object(self, tree_owner, object): nodes = tree_owner.node_tree.nodes diff --git a/blender/addons/io_scene_foundry/props/object.py b/blender/addons/io_scene_foundry/props/object.py index aa246331..20bc7a87 100644 --- a/blender/addons/io_scene_foundry/props/object.py +++ b/blender/addons/io_scene_foundry/props/object.py @@ -609,6 +609,47 @@ def poop_pathfinding_items(self, context): min=0.0, max=1.0, ) + + cc_primary: bpy.props.FloatVectorProperty( + name="Change Color Primary", + options=set(), + description="", + size=4, + default=(1, 1, 1, 1.0), + subtype="COLOR", + min=0.0, + max=1.0, + ) + cc_secondary: bpy.props.FloatVectorProperty( + name="Change Color Secondary", + options=set(), + description="", + size=4, + default=(1, 1, 1, 1.0), + subtype="COLOR", + min=0.0, + max=1.0, + ) + cc_tertiary: bpy.props.FloatVectorProperty( + name="Change Color Tertiary", + options=set(), + description="", + size=4, + default=(1, 1, 1, 1.0), + subtype="COLOR", + min=0.0, + max=1.0, + ) + cc_quaternary: bpy.props.FloatVectorProperty( + name="Change Color Quaternary", + options=set(), + description="", + size=4, + default=(1, 1, 1, 1.0), + subtype="COLOR", + min=0.0, + max=1.0, + ) def fog_clean_tag_path(self, context): self["fog_appearance_tag"] = utils.clean_tag_path( diff --git a/blender/addons/io_scene_foundry/tools/importer.py b/blender/addons/io_scene_foundry/tools/importer.py index 22c69e06..718e7bc7 100644 --- a/blender/addons/io_scene_foundry/tools/importer.py +++ b/blender/addons/io_scene_foundry/tools/importer.py @@ -355,7 +355,6 @@ def execute(self, context): self.nothing_imported = False self.user_cancelled = False utils.set_object_mode(context) - change_colors = None if self.tag_variant == "all_variants": self.tag_variant = "" if self.tag_zone_set == "all_zone_sets": @@ -455,9 +454,8 @@ def execute(self, context): importer.tag_animation = False importer.tag_variant = self.tag_variant.lower() importer.tag_state = State[self.tag_state].value - self.tag_state object_files = importer.sorted_filepaths["object"] - imported_object_objects, change_colors = importer.import_object(object_files) + imported_object_objects = importer.import_object(object_files) if needs_scaling: utils.transform_scene(context, scale_factor, from_x_rot, 'x', context.scene.nwo.forward_direction, objects=imported_object_objects, actions=[]) @@ -515,7 +513,7 @@ def execute(self, context): if needs_scaling: utils.transform_scene(context, scale_factor, from_x_rot, 'x', context.scene.nwo.forward_direction, objects=[existing_armature], actions=imported_animations) - if self.context.scene.nwo.asset_type in {'model', 'animation'}: + if context.scene.nwo.asset_type in {'model', 'animation'}: self.context.scene.nwo.active_animation_index = len(self.context.scene.nwo.animations) - 1 if 'scenario' in importer.extensions: @@ -592,7 +590,7 @@ def execute(self, context): for mat in new_materials: shader_path = mat.nwo.shader_path if shader_path: - tag_to_nodes(corinth, mat, shader_path, change_colors) + tag_to_nodes(corinth, mat, shader_path) if 'bitmap' in importer.extensions: bitmap_files = importer.sorted_filepaths["bitmap"] @@ -1147,6 +1145,12 @@ def import_object(self, paths): self.context.scene.collection.children.link(model_collection) if render: render_objects, armature = self.import_render_model(render, model_collection, None, allowed_region_permutations) + for ob in render_objects: + ob.nwo.cc_primary = change_colors[0] + ob.nwo.cc_secondary = change_colors[1] + ob.nwo.cc_tertiary = change_colors[2] + ob.nwo.cc_quaternary = change_colors[3] + imported_objects.extend(render_objects) for ob in render_objects: if ob.type == 'ARMATURE': @@ -1155,7 +1159,7 @@ def import_object(self, paths): if temp_variant == self.tag_variant: ob.nwo.cinematic_variant = temp_variant - return imported_objects, change_colors + return imported_objects def import_render_model(self, file, model_collection, existing_armature, allowed_region_permutations, skip_print=False): if not skip_print: diff --git a/blender/addons/io_scene_foundry/tools/shader_reader.py b/blender/addons/io_scene_foundry/tools/shader_reader.py index 78be21dd..ebd7b261 100644 --- a/blender/addons/io_scene_foundry/tools/shader_reader.py +++ b/blender/addons/io_scene_foundry/tools/shader_reader.py @@ -35,7 +35,7 @@ def execute(self, context): tag_to_nodes(utils.is_corinth(context), mat, shader_path) return {"FINISHED"} -def tag_to_nodes(corinth: bool, mat: bpy.types.Material, tag_path: str, change_colors=None): +def tag_to_nodes(corinth: bool, mat: bpy.types.Material, tag_path: str): """Turns a shader/material tag into blender material nodes""" if corinth: with MaterialTag(path=tag_path) as material: @@ -45,10 +45,10 @@ def tag_to_nodes(corinth: bool, mat: bpy.types.Material, tag_path: str, change_c match shader_type: case 'shader': with ShaderTag(path=tag_path) as shader: - shader.to_nodes(mat, change_colors) + shader.to_nodes(mat) case 'shader_decal': with ShaderDecalTag(path=tag_path) as shader: - shader.to_nodes(mat, change_colors) + shader.to_nodes(mat) case 'shader_terrain': with ShaderTerrainTag(path=tag_path) as shader: - shader.to_nodes(mat, change_colors) \ No newline at end of file + shader.to_nodes(mat) \ No newline at end of file