def name_update(self, context): lprint("D SCS Look inventory name update: %s", (self.name, )) # convert name to game engine like name tokenized_name = _name_utils.tokenize_name(self.name) if self.name != tokenized_name: self.name = tokenized_name # always get scs root to have access to look inventory scs_root_obj = _object_utils.get_scs_root(context.active_object) # if there is more of variants with same name, make postfixed name (this will cause another name update) if len( _inventory.get_indices(scs_root_obj.scs_object_look_inventory, self.name)) == 2: # duplicate i = 1 new_name = _name_utils.tokenize_name(self.name + "_" + str(i).zfill(2)) while _inventory.get_index(scs_root_obj.scs_object_look_inventory, new_name) != -1: new_name = _name_utils.tokenize_name(self.name + "_" + str(i).zfill(2)) i += 1 if new_name != self.name: self.name = new_name
def name_update(self, context): lprint("D SCS Part inventory name update: %s", (self.name, )) # convert name to game engine like name tokenized_name = _name_utils.tokenize_name( self.name, default_name=_PART_consts.default_name) if self.name != tokenized_name: self.name = tokenized_name # always get scs root because we allow editing of parts in any child scs_root_obj = _object_utils.get_scs_root(context.active_object) # if there is more of parts with same name, make postfixed name (this will cause another name update) if len( _inventory.get_indices(scs_root_obj.scs_object_part_inventory, self.name)) == 2: # duplicate i = 1 new_name = _name_utils.tokenize_name(self.name + "_" + str(i).zfill(2)) while _inventory.get_index(scs_root_obj.scs_object_part_inventory, new_name) != -1: new_name = _name_utils.tokenize_name(self.name + "_" + str(i).zfill(2)) i += 1 if new_name != self.name: self.name = new_name if "scs_part_old_name" in self: if scs_root_obj: # fix part name in all children of current root children = _object_utils.get_children(scs_root_obj) for child in children: # fix part name in child with existing old name if child.scs_props.scs_part == self["scs_part_old_name"]: child.scs_props.scs_part = self.name # rename parts in all variants also variant_inventory = scs_root_obj.scs_object_variant_inventory for variant in variant_inventory: for part in variant.parts: if part.name == self["scs_part_old_name"]: part.name = self.name break # backup current name for checking children on next renaming self["scs_part_old_name"] = self.name
def name_update(self, context): lprint("D SCS Part inventory name update: %s", (self.name,)) # convert name to game engine like name tokenized_name = _name_utils.tokenize_name(self.name, default_name=_PART_consts.default_name) if self.name != tokenized_name: self.name = tokenized_name # always get scs root because we allow editing of parts in any child scs_root_obj = _object_utils.get_scs_root(context.active_object) # if there is more of parts with same name, make postfixed name (this will cause another name update) if len(_inventory.get_indices(scs_root_obj.scs_object_part_inventory, self.name)) == 2: # duplicate i = 1 new_name = _name_utils.tokenize_name(self.name + "_" + str(i).zfill(2)) while _inventory.get_index(scs_root_obj.scs_object_part_inventory, new_name) != -1: new_name = _name_utils.tokenize_name(self.name + "_" + str(i).zfill(2)) i += 1 if new_name != self.name: self.name = new_name if "scs_part_old_name" in self: if scs_root_obj: # fix part name in all children of current root children = _object_utils.get_children(scs_root_obj) for child in children: # fix part name in child with existing old name if child.scs_props.scs_part == self["scs_part_old_name"]: child.scs_props.scs_part = self.name # rename parts in all variants also variant_inventory = scs_root_obj.scs_object_variant_inventory for variant in variant_inventory: for part in variant.parts: if part.name == self["scs_part_old_name"]: part.name = self.name break # backup current name for checking children on next renaming self["scs_part_old_name"] = self.name
def update_name(self, context): __update_look__(self, context) if hasattr(context, "active_object") and hasattr(context.active_object, "active_material"): material = context.active_object.active_material if material: custom_maps = material.scs_props.custom_tex_coord_maps # force prescribed pattern for name ("tex_coord_X" where X is unsigned integer) and avoid duplicates if not re.match("\Atex_coord_\d+\Z", self.name) or len(_inventory.get_indices(custom_maps, self.name)) == 2: i = 0 new_name = "tex_coord_" + str(i) while _inventory.get_index(custom_maps, new_name) != -1: i += 1 new_name = "tex_coord_" + str(i) if self.name != new_name: self.name = new_name
def update_name(self, context): if hasattr(context, "active_object") and hasattr( context.active_object, "active_material"): material = context.active_object.active_material if material: custom_maps = material.scs_props.shader_custom_tex_coord_maps # force prescribed pattern for name ("tex_coord_X" where X is unsigned integer) and avoid duplicates if not re.match("\Atex_coord_\d+\Z", self.name) or len( _inventory.get_indices(custom_maps, self.name)) == 2: i = 0 new_name = "tex_coord_" + str(i) while _inventory.get_index(custom_maps, new_name) != -1: i += 1 new_name = "tex_coord_" + str(i) if self.name != new_name: self.name = new_name
def name_update(self, context): lprint("D SCS Look inventory name update: %s", (self.name,)) # convert name to game engine like name tokenized_name = _name_utils.tokenize_name(self.name) if self.name != tokenized_name: self.name = tokenized_name # always get scs root to have access to look inventory scs_root_obj = _object_utils.get_scs_root(context.active_object) # if there is more of variants with same name, make postfixed name (this will cause another name update) if len(_inventory.get_indices(scs_root_obj.scs_object_look_inventory, self.name)) == 2: # duplicate i = 1 new_name = _name_utils.tokenize_name(self.name + "_" + str(i).zfill(2)) while _inventory.get_index(scs_root_obj.scs_object_look_inventory, new_name) != -1: new_name = _name_utils.tokenize_name(self.name + "_" + str(i).zfill(2)) i += 1 if new_name != self.name: self.name = new_name
def active_scs_part_get(self): """Getting active index in SCS Parts list. On active object change active index of the list is altered with the index of part belonging to new active object. """ if not "active_scs_part_old_active" in self: self["active_scs_part_old_active"] = "" if not "active_scs_part_value" in self: self["active_scs_part_value"] = 0 scs_root_object = _object_utils.get_scs_root(bpy.context.active_object) if scs_root_object and bpy.context.active_object != scs_root_object: # if old active object is different than current # set the value for active part index from it if self["active_scs_part_old_active"] != bpy.context.active_object.name: self["active_scs_part_value"] = _inventory.get_index(scs_root_object.scs_object_part_inventory, bpy.context.active_object.scs_props.scs_part) self["active_scs_part_old_active"] = bpy.context.active_object.name return self["active_scs_part_value"]
def set_shader_data_to_material(material, section, is_import=False, override_back_data=True): """Used to set up material properties from given shader data even via UI or on import. :param material: blender material to which section data should be set :type material: bpy.types.Material :param section: new material data presented with Material section of PIX files :type section: io_scs_tools.internals.structure.SectionData :param is_import: flag indication if shader data are set from import process :type is_import: bool :param override_back_data: flag indication if back data for UI shall be overwritten :type override_back_data: bool """ preset_effect = section.get_prop_value("Effect") # check shader flags for attr in section.props: if attr[0] == "Flags": material.scs_props.enable_aliasing = not attr[1] == 1 # Flags: 1 #DISABLE ALIASING break attributes = {} textures = {} attribute_i = 0 texture_i = 0 used_attribute_types = {} # attribute types used by current shader used_texture_types = {} # texture types used by current shader and should be overlooked during clearing of texture slots for item in section.sections: if item.type == "Attribute": attribute_data = {} for prop in item.props: key, value = prop # # GETTING RID OF "[" AND "]" CHARS... if type(value) is str: value = value.replace("[", "").replace("]", "") attribute_data[key] = value attribute_type = attribute_data['Tag'] attributes[str(attribute_i)] = attribute_data attribute_i += 1 used_attribute_types[attribute_type] = attribute_data elif item.type == "Texture": texture_data = {} for prop in item.props: # print(' prop: "%s"' % str(prop)) texture_data[prop[0]] = prop[1] # APPLY SECTION TEXTURE VALUES texture_type = texture_data['Tag'].split(':')[1] tex_type = texture_type[8:] used_texture_types[tex_type] = texture_data textures[str(texture_i)] = texture_data texture_i += 1 scs_props_keys = material.scs_props.keys() # if overriding back data also make sure to clear attribute values for current shader # to prevent storing of unused values from blend data block # NOTE: looks also takes into account that all the unused properties are omitted from scs_props dict if override_back_data: for key in scs_props_keys: is_key_used = False if key.startswith("shader_attribute"): for used_attribute in used_attribute_types: if used_attribute in key[16:]: is_key_used = True if key.startswith("shader_texture"): for used_tex_type in used_texture_types: if used_tex_type in key[14:]: is_key_used = True # delete only unused shader keys everything else should stay in the place # as those keys might be used in some other way if not is_key_used and key.startswith("shader_"): lprint("D Unsetting property from material in set_shader_data %s:", (key,)) material.scs_props.property_unset(key) # apply used attributes created_attributes = {} for attribute_type in used_attribute_types.keys(): attribute_data = used_attribute_types[attribute_type] # acquire old attribute value if exists and not importing old_value = None if "shader_attribute_" + attribute_type in scs_props_keys and not is_import: old_value = getattr(material.scs_props, "shader_attribute_" + attribute_type) if attribute_type in ("diffuse", "specular", "env_factor", "fresnel", "tint"): if not old_value: material.scs_props["shader_attribute_" + attribute_type] = attribute_data['Value'] created_attributes[attribute_type] = material.scs_props["shader_attribute_" + attribute_type] elif attribute_type in ("shininess", "add_ambient", "reflection", "reflection2", "shadow_bias", "tint_opacity"): if not old_value: material.scs_props["shader_attribute_" + attribute_type] = attribute_data['Value'][0] created_attributes[attribute_type] = material.scs_props["shader_attribute_" + attribute_type] elif attribute_type.startswith("aux") and hasattr(material.scs_props, "shader_attribute_" + attribute_type): auxiliary_prop = getattr(material.scs_props, "shader_attribute_" + attribute_type, None) # NOTE : invalidate old value if size of existing auxiliary property is different # then size of new one overwrite it anyway, because otherwise we will might access # values that doesn't exists but they should, for example: # switching from "eut2.dif.spec.weight.mult2" to "eut2.dif.spec.weight.mult2.weight2" if len(auxiliary_prop) != len(attribute_data['Value']): old_value = None if not old_value: # clean old values possible left from previous shader while len(auxiliary_prop) > 0: auxiliary_prop.remove(0) for val in attribute_data['Value']: item = auxiliary_prop.add() item['value'] = val item['aux_type'] = attribute_type created_attributes[attribute_type] = material.scs_props["shader_attribute_" + attribute_type] elif attribute_type == "substance": if not old_value: material.scs_props.substance = attribute_data['Value'][0] # if shader attribute properties are still unset reset it to default if material.scs_props.substance == _MAT_consts.unset_substance and "substance" not in material.scs_props.keys(): material.scs_props.substance = "None" # collect old uv mappings per tex_coord values and delete them from material (they will be set back later) # NOTE: we have to create extra iteration for uv mappings collecting # as multiple texture types can use same tex coord and we have to make sure # to collect them before we apply any texture data back to material. old_texture_mappings = {} for tex_type in used_texture_types: texture_mappings = getattr(material.scs_props, "shader_texture_" + tex_type + "_uv") if override_back_data: while len(texture_mappings) > 0: # save only set uv mapping tex_cord:value pairs if texture_mappings[0].value != "": old_texture_mappings[texture_mappings[0].tex_coord] = texture_mappings[0].value texture_mappings.remove(0) # apply used textures created_textures = {} created_tex_mappings = [] for tex_type in used_texture_types: # skip unknown texture type if tex_type not in material.scs_props.get_texture_types().keys(): lprint("D Trying to apply unknown texture type to SCS material: %r", (tex_type,)) continue texture_data = used_texture_types[tex_type] # always set texture lock attribute # important to set it always as some texture might get unlocked in preset and # selecting same present again has to unlock that texture texture_locked = False if "Lock" in texture_data: texture_locked = bool(texture_data["Lock"]) setattr(material.scs_props, "shader_texture_" + tex_type + "_locked", texture_locked) texture_mappings = getattr(material.scs_props, "shader_texture_" + tex_type + "_uv") # if shader is imported try to create custom tex coord mappings on material if material.scs_props.active_shader_preset_name == "<imported>" and "scs_tex_aliases" in material: custom_maps = material.scs_props.custom_tex_coord_maps for tex_coord_key in sorted(material["scs_tex_aliases"].keys()): if _invetory.get_index(custom_maps, "tex_coord_" + tex_coord_key) == -1: new_map = custom_maps.add() new_map.name = "tex_coord_" + tex_coord_key new_map.value = material["scs_tex_aliases"][tex_coord_key] # add one mapping field for using it as a preview uv layer in case of imported shader mapping = texture_mappings.add() mapping.texture_type = tex_type mapping.tex_coord = -1 # if there is an info about mapping in shader use it (in case of imported material this condition will fall!) elif "TexCoord" in texture_data: for tex_coord_i, tex_coord in enumerate(texture_data['TexCoord']): tex_coord = int(tex_coord) if tex_coord != -1: mapping = texture_mappings.add() mapping['texture_type'] = tex_type mapping['tex_coord'] = tex_coord # apply uv mappings either from imported data or from old mappings of previous shader if "scs_tex_aliases" in material: # scs_tex_aliases are present only on import mapping['value'] = material["scs_tex_aliases"][str(tex_coord)] created_tex_mappings.append((tex_type, mapping.value, tex_coord)) elif tex_coord in old_texture_mappings: mapping['value'] = old_texture_mappings[tex_coord] created_tex_mappings.append((tex_type, mapping.value, tex_coord)) # set texture file to current texture scs_texture_str = _path.get_scs_texture_str(texture_data['Value']) # apply texture path if not empty and not yet set, except if import is going on # NOTE: during import bitmap has to be applied even if empty # because otherwise texture from previous look might be applied if (scs_texture_str != "" and getattr(material.scs_props, "shader_texture_" + tex_type, "") == "") or is_import: material.scs_props["shader_texture_" + tex_type] = scs_texture_str created_textures[tex_type] = get_texture(scs_texture_str, tex_type) if is_import: # only if shader is imported then make sure that by default imported values will be used if material.scs_props.active_shader_preset_name == "<imported>": setattr(material.scs_props, "shader_texture_" + tex_type + "_use_imported", True) setattr(material.scs_props, "shader_texture_" + tex_type + "_imported_tobj", texture_data['Value']) # if property is still unset reset it to empty if getattr(material.scs_props, "shader_texture_" + tex_type, "") == _MAT_consts.unset_bitmap_filepath: material.scs_props["shader_texture_" + tex_type] = "" else: final_tex_str = getattr(material.scs_props, "shader_texture_" + tex_type, "") created_textures[tex_type] = get_texture(final_tex_str, tex_type) if is_import and not override_back_data: if created_textures[tex_type] is None: lprint("E Can't find texture nor TOBJ inside SCS Project Base Path: %r", (final_tex_str,)) # override shader data for identifying used attributes and textures in UI if override_back_data: shader_data = {'effect': preset_effect, 'attributes': attributes, 'textures': textures} material["scs_shader_attributes"] = shader_data # setup nodes for 3D view visualization _shader.setup_nodes(material, preset_effect, created_attributes, created_textures, override_back_data) # setup uv mappings to nodes later trough dedicated function, so proper validation is made on tex coord bindings for mapping_data in created_tex_mappings: # data[0] = texture type; # data[1] = uv mapping value; # data[2] = tex coord value _shader.set_uv(material, mapping_data[0], mapping_data[1], mapping_data[2])
def set_shader_data_to_material(material, section, is_import=False, override_back_data=True): """Used to set up material properties from given shader data even via UI or on import. :param material: blender material to which section data should be set :type material: bpy.types.Material :param section: new material data presented with Material section of PIX files :type section: io_scs_tools.internals.structure.SectionData :param is_import: flag indication if shader data are set from import process :type is_import: bool :param override_back_data: flag indication if back data for UI shall be overwritten :type override_back_data: bool """ preset_effect = section.get_prop_value("Effect") # check shader flags for attr in section.props: if attr[0] == "Flags": material.scs_props.enable_aliasing = not attr[ 1] == 1 # Flags: 1 #DISABLE ALIASING break attributes = {} textures = {} attribute_i = 0 texture_i = 0 used_attribute_types = {} # attribute types used by current shader used_texture_types = { } # texture types used by current shader and should be overlooked during clearing of texture slots for item in section.sections: if item.type == "Attribute": attribute_data = {} for prop in item.props: key, value = prop # # GETTING RID OF "[" AND "]" CHARS... if type(value) is str: value = value.replace("[", "").replace("]", "") attribute_data[key] = value attribute_type = attribute_data['Tag'] attributes[str(attribute_i)] = attribute_data attribute_i += 1 used_attribute_types[attribute_type] = attribute_data elif item.type == "Texture": texture_data = {} for prop in item.props: # print(' prop: "%s"' % str(prop)) texture_data[prop[0]] = prop[1] # APPLY SECTION TEXTURE VALUES texture_type = texture_data['Tag'].split(':')[1] tex_type = texture_type[8:] used_texture_types[tex_type] = texture_data textures[str(texture_i)] = texture_data texture_i += 1 scs_props_keys = material.scs_props.keys() # if overriding back data also make sure to clear attribute values for current shader # to prevent storing of unused values from blend data block # NOTE: looks also takes into account that all the unused properties are omitted from scs_props dict if override_back_data: for key in scs_props_keys: is_key_used = False if key.startswith("shader_attribute"): for used_attribute in used_attribute_types: if used_attribute in key[16:]: is_key_used = True if key.startswith("shader_texture"): for used_tex_type in used_texture_types: if used_tex_type in key[14:]: is_key_used = True # delete only unused shader keys everything else should stay in the place # as those keys might be used in some other way if not is_key_used and key.startswith("shader_"): lprint( "D Unsetting property from material in set_shader_data %s:", (key, )) material.scs_props.property_unset(key) # apply used attributes created_attributes = {} for attribute_type in used_attribute_types.keys(): attribute_data = used_attribute_types[attribute_type] # acquire old attribute value if exists and not importing old_value = None if "shader_attribute_" + attribute_type in scs_props_keys and not is_import: old_value = getattr(material.scs_props, "shader_attribute_" + attribute_type) if attribute_type in ("diffuse", "specular", "env_factor", "fresnel", "tint"): if not old_value: material.scs_props["shader_attribute_" + attribute_type] = attribute_data['Value'] created_attributes[attribute_type] = material.scs_props[ "shader_attribute_" + attribute_type] elif attribute_type in ("shininess", "add_ambient", "reflection", "reflection2", "shadow_bias", "tint_opacity"): if not old_value: material.scs_props["shader_attribute_" + attribute_type] = attribute_data['Value'][0] created_attributes[attribute_type] = material.scs_props[ "shader_attribute_" + attribute_type] elif attribute_type.startswith("aux") and hasattr( material.scs_props, "shader_attribute_" + attribute_type): auxiliary_prop = getattr(material.scs_props, "shader_attribute_" + attribute_type, None) # NOTE : invalidate old value if size of existing auxiliary property is different # then size of new one overwrite it anyway, because otherwise we will might access # values that doesn't exists but they should, for example: # switching from "eut2.dif.spec.weight.mult2" to "eut2.dif.spec.weight.mult2.weight2" if len(auxiliary_prop) != len(attribute_data['Value']): old_value = None if not old_value: # clean old values possible left from previous shader while len(auxiliary_prop) > 0: auxiliary_prop.remove(0) for val in attribute_data['Value']: item = auxiliary_prop.add() item['value'] = val item['aux_type'] = attribute_type created_attributes[attribute_type] = material.scs_props[ "shader_attribute_" + attribute_type] elif attribute_type == "substance": if not old_value: material.scs_props.substance = attribute_data['Value'][0] # if shader attribute properties are still unset reset it to default if material.scs_props.substance == _MAT_consts.unset_substance and "substance" not in material.scs_props.keys( ): material.scs_props.substance = "None" # collect old uv mappings per tex_coord values and delete them from material (they will be set back later) # NOTE: we have to create extra iteration for uv mappings collecting # as multiple texture types can use same tex coord and we have to make sure # to collect them before we apply any texture data back to material. old_texture_mappings = {} for tex_type in used_texture_types: texture_mappings = getattr(material.scs_props, "shader_texture_" + tex_type + "_uv") if override_back_data: while len(texture_mappings) > 0: # save only set uv mapping tex_cord:value pairs if texture_mappings[0].value != "": old_texture_mappings[texture_mappings[0]. tex_coord] = texture_mappings[0].value texture_mappings.remove(0) # apply used textures created_textures = {} created_tex_mappings = [] for tex_type in used_texture_types: # skip unknown texture type if tex_type not in material.scs_props.get_texture_types().keys(): lprint( "D Trying to apply unknown texture type to SCS material: %r", (tex_type, )) continue texture_data = used_texture_types[tex_type] # always set texture lock attribute # important to set it always as some texture might get unlocked in preset and # selecting same present again has to unlock that texture texture_locked = False if "Lock" in texture_data: texture_locked = bool(texture_data["Lock"]) setattr(material.scs_props, "shader_texture_" + tex_type + "_locked", texture_locked) texture_mappings = getattr(material.scs_props, "shader_texture_" + tex_type + "_uv") # if shader is imported try to create custom tex coord mappings on material if material.scs_props.active_shader_preset_name == "<imported>" and "scs_tex_aliases" in material: custom_maps = material.scs_props.custom_tex_coord_maps for tex_coord_key in sorted(material["scs_tex_aliases"].keys()): if _invetory.get_index(custom_maps, "tex_coord_" + tex_coord_key) == -1: new_map = custom_maps.add() new_map.name = "tex_coord_" + tex_coord_key new_map.value = material["scs_tex_aliases"][tex_coord_key] # add one mapping field for using it as a preview uv layer in case of imported shader mapping = texture_mappings.add() mapping.texture_type = tex_type mapping.tex_coord = -1 # if there is an info about mapping in shader use it (in case of imported material this condition will fall!) elif "TexCoord" in texture_data: for tex_coord_i, tex_coord in enumerate(texture_data['TexCoord']): tex_coord = int(tex_coord) if tex_coord != -1: mapping = texture_mappings.add() mapping['texture_type'] = tex_type mapping['tex_coord'] = tex_coord # apply uv mappings either from imported data or from old mappings of previous shader if "scs_tex_aliases" in material: # scs_tex_aliases are present only on import mapping['value'] = material["scs_tex_aliases"][str( tex_coord)] created_tex_mappings.append( (tex_type, mapping.value, tex_coord)) elif tex_coord in old_texture_mappings: mapping['value'] = old_texture_mappings[tex_coord] created_tex_mappings.append( (tex_type, mapping.value, tex_coord)) # set texture file to current texture scs_texture_str = _path.get_scs_texture_str(texture_data['Value']) # apply texture path if not empty and not yet set, except if import is going on # NOTE: during import bitmap has to be applied even if empty # because otherwise texture from previous look might be applied if (scs_texture_str != "" and getattr(material.scs_props, "shader_texture_" + tex_type, "") == "") or is_import: material.scs_props["shader_texture_" + tex_type] = scs_texture_str created_textures[tex_type] = get_texture(scs_texture_str, tex_type) if is_import: # only if shader is imported then make sure that by default imported values will be used if material.scs_props.active_shader_preset_name == "<imported>": setattr(material.scs_props, "shader_texture_" + tex_type + "_use_imported", True) setattr(material.scs_props, "shader_texture_" + tex_type + "_imported_tobj", texture_data['Value']) # if property is still unset reset it to empty if getattr(material.scs_props, "shader_texture_" + tex_type, "") == _MAT_consts.unset_bitmap_filepath: material.scs_props["shader_texture_" + tex_type] = "" else: final_tex_str = getattr(material.scs_props, "shader_texture_" + tex_type, "") created_textures[tex_type] = get_texture(final_tex_str, tex_type) if is_import and not override_back_data: if created_textures[tex_type] is None: lprint( "E Can't find texture nor TOBJ inside SCS Project Base Path: %r", (final_tex_str, )) # override shader data for identifying used attributes and textures in UI if override_back_data: shader_data = { 'effect': preset_effect, 'attributes': attributes, 'textures': textures } material["scs_shader_attributes"] = shader_data # setup nodes for 3D view visualization _shader.setup_nodes(material, preset_effect, created_attributes, created_textures, override_back_data) # setup uv mappings to nodes later trough dedicated function, so proper validation is made on tex coord bindings for mapping_data in created_tex_mappings: # data[0] = texture type; # data[1] = uv mapping value; # data[2] = tex coord value _shader.set_uv(material, mapping_data[0], mapping_data[1], mapping_data[2])
def set_shader_data_to_material(material, section, preset_effect, is_import=False, override_back_data=True): """Used to set up material properties from given shader data even via UI or on import. :param material: :type material: bpy.types.Material :param section: :param preset_effect: :return: """ attributes = {} textures = {} attribute_i = 0 texture_i = 0 used_attribute_types = {} # attribute types used by current shader used_texture_types = {} # texture types used by current shader and should be overlooked during clearing of texture slots for item in section.sections: if item.type == "Attribute": attribute_data = {} for prop in item.props: key, value = prop # # GETTING RID OF "[" AND "]" CHARS... if type(value) is str: value = value.replace("[", "").replace("]", "") attribute_data[key] = value attribute_type = attribute_data['Tag'] attributes[str(attribute_i)] = attribute_data attribute_i += 1 used_attribute_types[attribute_type] = attribute_data elif item.type == "Texture": texture_data = {} for prop in item.props: # print(' prop: "%s"' % str(prop)) texture_data[prop[0]] = prop[1] # APPLY SECTION TEXTURE VALUES texture_type = texture_data['Tag'].split(':')[1] tex_type = texture_type[8:] used_texture_types[tex_type] = texture_data textures[str(texture_i)] = texture_data texture_i += 1 # clear attribute values for current shader to be stored in blend data block # NOTE: looks also takes into account that all the unused properties are omitted from scs_props dict scs_props_keys = material.scs_props.keys() for key in scs_props_keys: is_key_used = False if key.startswith("shader_attribute"): for used_attribute in used_attribute_types: if used_attribute in key[16:]: is_key_used = True if key.startswith("shader_texture"): for used_tex_type in used_texture_types: if used_tex_type in key[14:]: is_key_used = True # delete only unused shader keys everything else should stay in the place # as those keys might be used in some other way if not is_key_used and key.startswith("shader_"): lprint("D Unsetting property from material in set_shader_data %s:", (key,)) material.scs_props.property_unset(key) # apply used attributes created_attributes = {} for attribute_type in used_attribute_types.keys(): attribute_data = used_attribute_types[attribute_type] if attribute_type in ("diffuse", "specular", "env_factor", "fresnel", "tint"): material.scs_props["shader_attribute_" + attribute_type] = attribute_data['Value'] created_attributes[attribute_type] = material.scs_props["shader_attribute_" + attribute_type] elif attribute_type in ("shininess", "add_ambient", "reflection", "reflection2", "shadow_bias", "tint_opacity"): material.scs_props["shader_attribute_" + attribute_type] = attribute_data['Value'][0] created_attributes[attribute_type] = material.scs_props["shader_attribute_" + attribute_type] elif attribute_type.startswith("aux") and hasattr(material.scs_props, "shader_attribute_" + attribute_type): auxiliary_prop = getattr(material.scs_props, "shader_attribute_" + attribute_type, None) # clean old values possible left from previous shader while len(auxiliary_prop) > 0: auxiliary_prop.remove(0) for val in attribute_data['Value']: item = auxiliary_prop.add() item['value'] = val item['aux_type'] = attribute_type created_attributes[attribute_type] = material.scs_props["shader_attribute_" + attribute_type] elif attribute_type == "substance": material.scs_props.substance = attribute_data['Value'][0] # if shader attribute properties are still unset reset it to default if material.scs_props.substance == _MAT_consts.unset_substance and "substance" not in material.scs_props.keys(): material.scs_props.substance = "None" # apply used textures created_textures = {} created_tex_uvs = {} for tex_type in used_texture_types: texture_data = used_texture_types[tex_type] if tex_type in material.scs_props.get_texture_types().keys(): if "Lock" in texture_data: setattr(material.scs_props, "shader_texture_" + tex_type + "_locked", bool(texture_data["Lock"])) texture_mappings = getattr(material.scs_props, "shader_texture_" + tex_type + "_uv") # clear all texture mapping for current texture from previous shader if override_back_data: while len(texture_mappings) > 0: texture_mappings.remove(0) # if shader is imported try to create custom tex coord mappings on material if material.scs_props.active_shader_preset_name == "<imported>" and "scs_tex_aliases" in material: custom_maps = material.scs_props.custom_tex_coord_maps for tex_coord_key in sorted(material["scs_tex_aliases"].keys()): if _invetory.get_index(custom_maps, "tex_coord_" + tex_coord_key) == -1: new_map = custom_maps.add() new_map.name = "tex_coord_" + tex_coord_key new_map.value = material["scs_tex_aliases"][tex_coord_key] # add one mapping field for using it as a preview uv layer in case of imported shader mapping = texture_mappings.add() mapping.texture_type = tex_type mapping.tex_coord = -1 # if there is an info about mapping in shader use it (in case of imported material this condition will fall!) elif "TexCoord" in texture_data: for tex_coord in texture_data['TexCoord']: tex_coord = int(tex_coord) if tex_coord != -1: mapping = texture_mappings.add() mapping.texture_type = tex_type mapping.tex_coord = tex_coord if "scs_tex_aliases" in material: mapping.value = material["scs_tex_aliases"][str(tex_coord)] # for now make sure to use only first coord mapping info for shader if len(texture_mappings) == 1: created_tex_uvs[tex_type] = mapping.value # set bitmap file to current texture bitmap_filepath = _path.get_bitmap_filepath(texture_data['Value']) # apply texture path if not empty, except if import is going on # NOTE: during import bitmap has to be applied even if empty # because otherwise texture from previous look might be applied if (bitmap_filepath and bitmap_filepath != "") or is_import: material.scs_props["shader_texture_" + tex_type] = bitmap_filepath created_textures[tex_type] = get_texture(bitmap_filepath, tex_type) if is_import: # only if shader is imported then make sure that by default imported values will be used if material.scs_props.active_shader_preset_name == "<imported>": setattr(material.scs_props, "shader_texture_" + tex_type + "_use_imported", True) setattr(material.scs_props, "shader_texture_" + tex_type + "_imported_tobj", texture_data['Value']) # if property is still unset reset it to empty if getattr(material.scs_props, "shader_texture_" + tex_type, "") == _MAT_consts.unset_bitmap_filepath: material.scs_props["shader_texture_" + tex_type] = "" else: bitmap_filepath = _path.get_abs_path(getattr(material.scs_props, "shader_texture_" + tex_type, "")) created_textures[tex_type] = get_texture(bitmap_filepath, tex_type) # override shader data for identifying used attributes and textures in UI if override_back_data: shader_data = {'effect': preset_effect, 'attributes': attributes, 'textures': textures} material["scs_shader_attributes"] = shader_data # setup nodes for 3D view visualization _shader.setup_nodes(material, preset_effect, created_attributes, created_textures, created_tex_uvs, override_back_data)
def set_shader_data_to_material(material, section, preset_effect, is_import=False, override_back_data=True): """ :param material: :type material: bpy.types.Material :param section: :param preset_effect: :return: """ defined_tex_types = ("base", "flakenoise", "iamod", "lightmap", "mask", "mult", "oclu", "over", "paintjob", "reflection", "nmap") material.use_transparency = preset_effect.endswith(".a") _object.set_attr_if_different(material, "transparency_method", "MASK") attributes = {} textures = {} attribute_i = 0 texture_i = 0 # dictionary for listing of texture types which are used and should be overlooked during clearing of texture slots used_texture_types = {} for item in section.sections: if item.type == "Attribute": attribute_data = {} for prop in item.props: key, value = prop # # GETTING RID OF "[" AND "]" CHARS... if type(value) is str: value = value.replace("[", "").replace("]", "") attribute_data[key] = value attribute_type = attribute_data['Tag'] # APPLY PRESET ATTRIBUTE VALUES FROM PRESET if attribute_type == 'diffuse': material.scs_props.shader_attribute_diffuse = attribute_data['Value'] if is_import: material.scs_props.update_diffuse(material) elif attribute_type == 'specular': material.scs_props.shader_attribute_specular = attribute_data['Value'] if is_import: material.scs_props.update_specular(material) elif attribute_type == 'shininess': material.scs_props.shader_attribute_shininess = attribute_data['Value'][0] if is_import: material.scs_props.update_shininess(material) elif attribute_type == 'add_ambient': material.scs_props.shader_attribute_add_ambient = attribute_data['Value'][0] if is_import: material.scs_props.update_add_ambient(material) elif attribute_type == 'reflection': material.scs_props.shader_attribute_reflection = attribute_data['Value'][0] if is_import: material.scs_props.update_reflection(material) elif attribute_type == 'reflection2': material.scs_props.shader_attribute_reflection2 = attribute_data['Value'][0] if is_import: material.scs_props.update_reflection(material) elif attribute_type == 'shadow_bias': material.scs_props.shader_attribute_shadow_bias = attribute_data['Value'][0] if is_import: material.scs_props.update_shadow_bias(material) elif attribute_type == 'env_factor': material.scs_props.shader_attribute_env_factor = attribute_data['Value'] if is_import: material.scs_props.update_env_factor(material) elif attribute_type == 'fresnel': material.scs_props.shader_attribute_fresnel = attribute_data['Value'] elif attribute_type == 'tint': material.scs_props.shader_attribute_tint = attribute_data['Value'] elif attribute_type == 'tint_opacity': material.scs_props.shader_attribute_tint_opacity = attribute_data['Value'][0] elif attribute_type in ("aux3", "aux5", "aux6", "aux7", "aux8"): auxiliary_prop = getattr(material.scs_props, "shader_attribute_" + attribute_type, None) # clean old values possible left from previous shader while len(auxiliary_prop) > 0: auxiliary_prop.remove(0) for val in attribute_data['Value']: item = auxiliary_prop.add() item.value = val attributes[str(attribute_i)] = attribute_data attribute_i += 1 elif item.type == "Texture": texture_data = {} for prop in item.props: # print(' prop: "%s"' % str(prop)) texture_data[prop[0]] = prop[1] # APPLY SECTION TEXTURE VALUES texture_type = texture_data['Tag'].split(':')[1] slot_id = texture_type[8:] # set only defined textures if slot_id in defined_tex_types: texture_mappings = getattr(material.scs_props, "shader_texture_" + slot_id + "_uv") # clear all texture mapping for current texture from previous shader if override_back_data: while len(texture_mappings) > 0: texture_mappings.remove(0) # if shader is imported try to create custom tex coord mappings on material if material.scs_props.active_shader_preset_name == "<imported>" and "scs_tex_aliases" in material: custom_maps = material.scs_props.shader_custom_tex_coord_maps for tex_coord_key in sorted(material["scs_tex_aliases"].keys()): if _invetory.get_index(custom_maps, "tex_coord_" + tex_coord_key) == -1: new_map = custom_maps.add() new_map.name = "tex_coord_" + tex_coord_key new_map.value = material["scs_tex_aliases"][tex_coord_key] # add one mapping field for using it as a preview uv layer in case of imported shader mapping = texture_mappings.add() mapping.texture_type = slot_id mapping.tex_coord = -1 # if there is an info about mapping in shader use it (in case of imported material this condition will fall!) elif "TexCoord" in texture_data: for tex_coord in texture_data['TexCoord']: tex_coord = int(tex_coord) if tex_coord != -1: mapping = texture_mappings.add() mapping.texture_type = slot_id mapping.tex_coord = tex_coord if "scs_tex_aliases" in material: mapping.value = material["scs_tex_aliases"][str(tex_coord)] used_texture_types[slot_id] = 1 bitmap_filepath = _path.get_bitmap_filepath(texture_data['Value']) if bitmap_filepath and bitmap_filepath != "": setattr(material.scs_props, "shader_texture_" + slot_id, bitmap_filepath) if is_import: update_texture_slots(material, bitmap_filepath, slot_id) # only if shader is imported then make sure that by default imported values will be used if material.scs_props.active_shader_preset_name == "<imported>": setattr(material.scs_props, "shader_texture_" + slot_id + "_use_imported", True) setattr(material.scs_props, "shader_texture_" + slot_id + "_imported_tobj", texture_data['Value']) texture_slot = get_texture_slot(material, slot_id) if slot_id == 'base' and texture_slot: set_diffuse(texture_slot, material, material.scs_props.shader_attribute_diffuse) elif slot_id == 'reflection' and texture_slot: set_env_factor(texture_slot, material.scs_props.shader_attribute_env_factor) textures[str(texture_i)] = texture_data texture_i += 1 if override_back_data: # clear texture slots for unused textures from previous preset for tex_type in defined_tex_types: if tex_type not in used_texture_types: # delete unused texture slots clear_texture_slots(material, tex_type) shader_data = {'effect': preset_effect, 'attributes': attributes, 'textures': textures} material["scs_shader_attributes"] = shader_data