Exemple #1
0
def reload_tobj_settings(material, tex_type):
    """Relaods TOBJ settings on given texture type of material.
    If tobj doesn't exists it does nothing.

    :param material: material
    :type material: bpy.types.Material
    :param tex_type: texture type
    :type tex_type: str
    """

    shader_texture_str = "shader_texture_" + tex_type
    shader_texture_filepath = getattr(material.scs_props, shader_texture_str)

    tobj_file = _path.get_tobj_path_from_shader_texture(
        shader_texture_filepath)
    if tobj_file:

        settings, map_type = _tobj_imp.get_settings_and_type(tobj_file)

        # intentionally set ID property directly to avoid update function invoke
        material.scs_props[shader_texture_str + "_settings"] = int(settings, 2)

        setattr(material.scs_props, shader_texture_str + "_map_type", map_type)
        setattr(material.scs_props, shader_texture_str + "_tobj_load_time",
                str(os.path.getmtime(tobj_file)))
Exemple #2
0
def reload_tobj_settings(material, tex_type):
    """Relaods TOBJ settings on given texture type of material.
    If tobj doesn't exists it does nothing.

    :param material: material
    :type material: bpy.types.Material
    :param tex_type: texture type
    :type tex_type: str
    """

    shader_texture_str = "shader_texture_" + tex_type
    shader_texture_filepath = getattr(material.scs_props, shader_texture_str)

    tobj_file = _path.get_tobj_path_from_shader_texture(shader_texture_filepath)
    if tobj_file:

        settings, map_type = _tobj_imp.get_settings_and_type(tobj_file)

        # intentionally set ID property directly to avoid update function invoke
        material.scs_props[shader_texture_str + "_settings"] = int(settings, 2)

        setattr(material.scs_props, shader_texture_str + "_map_type", map_type)
        setattr(material.scs_props, shader_texture_str + "_tobj_load_time", str(os.path.getmtime(tobj_file)))
Exemple #3
0
def get_texture_path_from_material(material, texture_type, export_path):
    """Get's relative path for Texture section of tobj from given texture_type.
    If tobj is not yet created it also creates tobj for it.

    :param material: Blender material
    :type material: bpy.types.Material
    :param texture_type: type of texture which should be readed from material (example "texture_base")
    :type texture_type: str
    :return: relative path for Texture section data of PIT material
    :rtype: str
    """

    # overwrite tobj value directly if specified
    if getattr(material.scs_props, "shader_" + texture_type + "_use_imported",
               False):
        return getattr(material.scs_props,
                       "shader_" + texture_type + "_imported_tobj", "")

    # use tobj value from shader preset if texture is locked and has default value
    if "scs_shader_attributes" in material and "textures" in material[
            "scs_shader_attributes"]:
        for tex_entry in material["scs_shader_attributes"]["textures"].values(
        ):
            if "Tag" in tex_entry and texture_type in tex_entry["Tag"]:
                if "Lock" in tex_entry and tex_entry["Lock"] == "True":
                    if "Value" in tex_entry and tex_entry["Value"] != "":
                        return tex_entry["Value"]

    # CALCULATING TOBJ AND TEXTURE PATHS
    texture_raw_path = getattr(material.scs_props, "shader_" + texture_type,
                               "NO PATH")
    tobj_rel_filepath = tobj_abs_filepath = texture_abs_filepath = ""
    scs_project_path = _get_scs_globals().scs_project_path.rstrip("\\").rstrip(
        "/")

    extensions, texture_raw_path = _path_utils.get_texture_extens_and_strip_path(
        texture_raw_path)

    for ext in extensions:
        if texture_raw_path.startswith("//"):  # relative

            # search for relative path inside current scs project base and
            # possible dlc/mod parent folders; use first found
            for infix in ("", "../base/", "../../base/"):

                curr_path = os.path.join(scs_project_path,
                                         infix + texture_raw_path[2:] + ext)

                if os.path.isfile(curr_path):

                    tobj_rel_filepath = texture_raw_path.replace("//", "/")

                    # if tobj is used by user then get texture path from tobj
                    # otherwise get tobj path from texture path
                    if ext == ".tobj":
                        tobj_abs_filepath = curr_path
                        texture_abs_filepath = _path_utils.get_texture_path_from_tobj(
                            curr_path)
                    else:
                        tobj_abs_filepath = _path_utils.get_tobj_path_from_shader_texture(
                            curr_path, check_existance=False)
                        texture_abs_filepath = curr_path
                    break

            # break searching for texture if texture was found
            if tobj_rel_filepath != "":
                break

        elif ext != ".tobj" and os.path.isfile(texture_raw_path +
                                               ext):  # absolute

            texture_raw_path_with_ext = texture_raw_path + ext

            # if we are exporting somewhere into SCS Project Base Path texture still can be saved
            if scs_project_path != "" and _path_utils.startswith(
                    export_path, scs_project_path):

                tex_dir, tex_filename = os.path.split(
                    texture_raw_path_with_ext)
                tobj_filename = tex_filename + ".tobj"

                # copy texture beside exported files
                try:
                    shutil.copy2(texture_raw_path_with_ext,
                                 os.path.join(export_path, tex_filename))
                except OSError as e:
                    # ignore copying the same file
                    # NOTE: happens if absolute texture paths are used
                    # even if they are referring to texture inside scs project path
                    if type(e).__name__ != "SameFileError":
                        raise e

                # copy also TOBJ if exists
                texture_raw_tobj_path = str(tex_dir) + os.sep + tobj_filename
                if os.path.isfile(texture_raw_tobj_path):
                    shutil.copy2(texture_raw_tobj_path,
                                 os.path.join(export_path, tobj_filename))

                # get copied TOBJ relative path to current scs project path
                tobj_rel_filepath = ""
                if export_path != scs_project_path:
                    tobj_rel_filepath = os.sep + os.path.relpath(
                        export_path, scs_project_path)

                tobj_rel_filepath = tobj_rel_filepath + os.sep + tobj_filename[:
                                                                               -5]
                tobj_abs_filepath = os.path.join(export_path, tobj_filename)
                texture_abs_filepath = texture_raw_path_with_ext
                break

            else:
                lprint(
                    "E Can not properly export texture %r from material %r!\n\t   "
                    +
                    "Make sure you are exporting somewhere into Project Base Path and texture is properly set!",
                    (texture_raw_path, material.name))
                return ""

    else:
        lprint(
            "E Texture file %r from material %r doesn't exists inside current Project Base Path.\n\t   "
            +
            "TOBJ  won't be exported and reference will remain empty, expect problems!",
            (texture_raw_path, material.name))
        return ""

    # CREATE TOBJ FILE
    if not os.path.isfile(tobj_abs_filepath):  # only if it does not exists yet

        # export tobj only if file of texture exists
        if os.path.isfile(texture_abs_filepath):
            texture_name = os.path.basename(
                _path_utils.strip_sep(texture_abs_filepath))
            _tobj.export(tobj_abs_filepath, texture_name, set())
        else:
            lprint(
                "E Texture file %r from material %r doesn't exists, TOBJ can not be exported!",
                (texture_raw_path, material.name))

    # make sure that Windows users will export proper paths
    tobj_rel_filepath = tobj_rel_filepath.replace("\\", "/")

    return tobj_rel_filepath
Exemple #4
0
def _draw_shader_texture(layout, mat, split_perc, texture, read_only):
    """Draws texture box with it's properties.

    :param layout: layout to draw attribute to
    :type layout: bpy.types.UILayout
    :param mat: material from which data should be displayed
    :type mat: bpy.types.Material
    :param split_perc: split percentage for attribute name/value
    :type split_perc: float
    :param texture: texture data
    :type texture: dict
    :param read_only: if texture should be read only
    :type read_only: bool
    """

    tag = texture.get('Tag', None)
    hide_state = texture.get('Hide', None)
    tag_id = tag.split(':')
    tag_id_string = tag_id[1]
    texture_type = tag_id_string[8:]
    shader_texture_id = str('shader_' + tag_id_string)

    if hide_state == 'True':
        return

    texture_box = layout.box().column(
    )  # create column for compact display with alignment

    header_split = texture_box.row(align=True).split(percentage=0.5)
    header_split.label(texture_type.title(), icon="TEXTURE_SHADED")

    if hasattr(mat.scs_props, shader_texture_id):

        shader_texture = mat.scs_props.get(shader_texture_id, "")
        # imported tobj boolean switch (only for imported shaders)
        use_imported_tobj = getattr(mat.scs_props,
                                    shader_texture_id + "_use_imported", False)
        if read_only:
            row = header_split.row(align=True)
            row.alignment = 'RIGHT'
            row.prop(mat.scs_props, shader_texture_id + "_use_imported")

            if use_imported_tobj:

                texture_row = texture_box.row(align=True)
                item_space = texture_row.split(percentage=split_perc,
                                               align=True)
                item_space.label("TOBJ Path:")

                item_space = item_space.split(
                    percentage=1 / (1 - split_perc + 0.000001) * 0.1,
                    align=True)
                props = item_space.operator("material.scs_looks_wt", text="WT")
                props.property_str = shader_texture_id
                item_space.prop(mat.scs_props,
                                shader_texture_id + "_imported_tobj",
                                text="")

        # disable whole texture layout if it's locked
        texture_box.enabled = not mat.scs_props.get(
            shader_texture_id + "_locked", False)

        texture_row = texture_box.row(align=True)
        item_space = texture_row.split(percentage=split_perc, align=True)

        # in case of custom tobj value texture is used only for preview
        if read_only and use_imported_tobj:
            item_space.label("Preview Tex:")
        else:
            item_space.label("Texture:")

        layout_box_col = item_space.column(align=True)
        layout_box_row = layout_box_col.row(align=True)

        if shader_texture:
            texture_icon = 'TEXTURE'
        else:
            texture_icon = 'MATPLANE'

        # MARK INVALID SLOTS
        if _path_utils.is_valid_shader_texture_path(shader_texture):
            layout_box_row.alert = False
        else:
            layout_box_row.alert = True
            texture_icon = 'NONE'  # info operator will have icon, so texture path should use none

        # MARK EMPTY SLOTS
        if shader_texture == "":
            layout_box_row.alert = True

        layout_box_row = layout_box_row.split(
            percentage=1 / (1 - split_perc + 0.000001) * 0.1, align=True)
        props = layout_box_row.operator("material.scs_looks_wt", text="WT")
        props.property_str = shader_texture_id

        layout_box_row = layout_box_row.row(align=True)
        layout_box_row.prop(mat.scs_props,
                            shader_texture_id,
                            text='',
                            icon=texture_icon)

        if layout_box_row.alert:  # add info operator when texture path is invalid
            _shared.draw_warning_operator(
                layout_box_row,
                title="Texture Not Found",
                message=
                "Texture with given path doesn't exists or SCS Project Base Path is not properly set!"
            )

        props = layout_box_row.operator(
            'material.scs_select_shader_texture_filepath',
            text='',
            icon='FILESEL')
        props.shader_texture = shader_texture_id  # DYNAMIC ID SAVE (FOR FILE REQUESTER)

        # ADDITIONAL TEXTURE SETTINGS
        if (not read_only or
            (read_only and not use_imported_tobj)) and texture_box.enabled:

            tobj_filepath = _path_utils.get_tobj_path_from_shader_texture(
                shader_texture)

            if not tobj_filepath:
                layout_box_inner_col = layout_box_col.row(align=True)
                item_space = layout_box_inner_col.column(align=True)
                props = item_space.operator("material.scs_create_tobj",
                                            icon="NEW",
                                            text="")
                props.texture_type = texture_type
                # creating extra column->row so it can be properly disabled as tobj doesn't exists
                item_space = layout_box_inner_col.column(align=True).row(
                    align=True)
            else:
                item_space = layout_box_col.row(align=True)

            # enable settings only if tobj exists and map type of the tobj is 2d
            item_space.enabled = tobj_filepath is not None and getattr(
                mat.scs_props, shader_texture_id + "_map_type", "") == "2d"

            if tobj_filepath:
                mtime = str(os.path.getmtime(tobj_filepath))
                item_space.alert = (mtime != getattr(
                    mat.scs_props, shader_texture_id + "_tobj_load_time",
                    "NOT FOUND"))
            else:
                item_space.alert = True

            props = item_space.operator("material.scs_reload_tobj",
                                        icon="LOAD_FACTORY",
                                        text="")
            props.texture_type = texture_type

            item_space.prop_menu_enum(
                mat.scs_props,
                str('shader_' + tag_id_string + '_settings'),
                icon='SETTINGS',
            )

        # UV LAYERS FOR TEXTURE
        uv_mappings = getattr(mat.scs_props, "shader_" + tag_id_string + "_uv",
                              None)

        if len(uv_mappings) > 0:

            texture_row = texture_box.row(align=True)
            item_space = texture_row.split(percentage=split_perc, align=True)
            if read_only:
                item_space.label("Preview UV Map:")
            else:
                item_space.label("Mapping:")
            layout_box_col = item_space.column(align=True)

            for mapping in uv_mappings:

                item_space_row = layout_box_col.row(align=True)

                # add info about normal map uv mapping property in case of imported shader
                if read_only and tag_id_string == "texture_nmap":
                    preview_nmap_msg = str(
                        "Maping value for normal maps is in the case of imported shader\n"
                        "also used for defining uv map layer for tangent calculations!\n"
                        "If the uv map is not provided first entry from Mappings list above will be used!"
                    )
                    _shared.draw_warning_operator(item_space_row,
                                                  "Mapping Info",
                                                  preview_nmap_msg,
                                                  icon="INFO")

                # add ensuring operator for norma map uv mapping
                if tag_id_string == "texture_nmap":
                    props = item_space_row.operator(
                        "mesh.scs_ensure_active_uv",
                        text="",
                        icon="FILE_REFRESH")
                    props.mat_name = mat.name
                    props.uv_layer = uv_mappings[0].value

                if mapping.value and mapping.value != "" and mapping.value in bpy.context.active_object.data.uv_layers:
                    icon = "GROUP_UVS"
                else:
                    icon = "ERROR"

                item_space_row.prop_search(
                    data=mapping,
                    property="value",
                    search_data=bpy.context.active_object.data,
                    search_property='uv_layers',
                    text="",
                    icon=icon,
                )

    else:
        texture_box.row().label('Unsupported Shader Texture Type!',
                                icon="ERROR")
Exemple #5
0
def _get_texture_path_from_material(material, texture_type, export_path):
    """Get's relative path for Texture section of tobj from given texture_type.
    If tobj is not yet created it also creates tobj for it.

    :param material: Blender material
    :type material: bpy.types.Material
    :param texture_type: type of texture which should be readed from material (example "texture_base")
    :type texture_type: str
    :return: relative path for Texture section data of PIT material
    :rtype: str
    """

    # overwrite tobj value directly if specified
    if getattr(material.scs_props, "shader_" + texture_type + "_use_imported", False):
        return getattr(material.scs_props, "shader_" + texture_type + "_imported_tobj", "")

    # use tobj value from shader preset if texture is locked and has default value
    if "scs_shader_attributes" in material and "textures" in material["scs_shader_attributes"]:
        for tex_entry in material["scs_shader_attributes"]["textures"].values():
            if "Tag" in tex_entry and texture_type in tex_entry["Tag"]:
                if "Lock" in tex_entry and tex_entry["Lock"] == "True":
                    if "Value" in tex_entry and tex_entry["Value"] != "":
                        return tex_entry["Value"]

    # CALCULATING TOBJ AND TEXTURE PATHS
    texture_raw_path = getattr(material.scs_props, "shader_" + texture_type, "NO PATH")
    tobj_rel_filepath = tobj_abs_filepath = texture_abs_filepath = ""
    scs_project_path = _get_scs_globals().scs_project_path.rstrip("\\").rstrip("/")

    extensions, texture_raw_path = _path_utils.get_texture_extens_and_strip_path(texture_raw_path)

    for ext in extensions:
        if texture_raw_path.startswith("//"):  # relative

            # search for relative path inside current scs project base and
            # possible dlc/mod parent folders; use first found
            for infix in ("", "../base/", "../../base/"):

                curr_path = os.path.join(scs_project_path, infix + texture_raw_path[2:] + ext)

                if os.path.isfile(curr_path):

                    tobj_rel_filepath = texture_raw_path.replace("//", "/")

                    # if tobj is used by user then get texture path from tobj
                    # otherwise get tobj path from texture path
                    if ext == ".tobj":
                        tobj_abs_filepath = curr_path
                        texture_abs_filepath = _path_utils.get_texture_path_from_tobj(curr_path)
                    else:
                        tobj_abs_filepath = _path_utils.get_tobj_path_from_shader_texture(curr_path, check_existance=False)
                        texture_abs_filepath = curr_path
                    break

            # break searching for texture if texture was found
            if tobj_rel_filepath != "":
                break

        elif ext != ".tobj" and os.path.isfile(texture_raw_path + ext):  # absolute

            texture_raw_path_with_ext = texture_raw_path + ext

            # if we are exporting somewhere into SCS Project Base Path texture still can be saved
            if scs_project_path != "" and _path_utils.startswith(export_path, scs_project_path):

                tex_dir, tex_filename = os.path.split(texture_raw_path_with_ext)
                tobj_filename = tex_filename + ".tobj"

                # copy texture beside exported files
                try:
                    shutil.copy2(texture_raw_path_with_ext, os.path.join(export_path, tex_filename))
                except OSError as e:
                    # ignore copying the same file
                    # NOTE: happens if absolute texture paths are used
                    # even if they are referring to texture inside scs project path
                    if type(e).__name__ != "SameFileError":
                        raise e

                # copy also TOBJ if exists
                texture_raw_tobj_path = str(tex_dir) + os.sep + tobj_filename
                if os.path.isfile(texture_raw_tobj_path):
                    shutil.copy2(texture_raw_tobj_path, os.path.join(export_path, tobj_filename))

                # get copied TOBJ relative path to current scs project path
                tobj_rel_filepath = ""
                if export_path != scs_project_path:
                    tobj_rel_filepath = os.sep + os.path.relpath(export_path, scs_project_path)

                tobj_rel_filepath = tobj_rel_filepath + os.sep + tobj_filename[:-5]
                tobj_abs_filepath = os.path.join(export_path, tobj_filename)
                texture_abs_filepath = texture_raw_path_with_ext
                break

            else:
                lprint("E Can not properly export texture %r from material %r!\n\t   " +
                       "Make sure you are exporting somewhere into Project Base Path and texture is properly set!",
                       (texture_raw_path, material.name))
                return ""

    else:
        lprint("E Texture file %r from material %r doesn't exists inside current Project Base Path.\n\t   " +
               "TOBJ  won't be exported and reference will remain empty, expect problems!",
               (texture_raw_path, material.name))
        return ""

    # CREATE TOBJ FILE
    if not os.path.isfile(tobj_abs_filepath):  # only if it does not exists yet

        # export tobj only if file of texture exists
        if os.path.isfile(texture_abs_filepath):
            texture_name = os.path.basename(_path_utils.strip_sep(texture_abs_filepath))
            _tobj.export(tobj_abs_filepath, texture_name, set())
        else:
            lprint("E Texture file %r from material %r doesn't exists, TOBJ can not be exported!",
                   (texture_raw_path, material.name))

    # make sure that Windows users will export proper paths
    tobj_rel_filepath = tobj_rel_filepath.replace("\\", "/")

    return tobj_rel_filepath
Exemple #6
0
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", "queue_bias"):

            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_settings = {}
    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

                        # if mesh is corrupted then tex aliases won't be filled in properly in material from PIM importer,
                        # so report error and skip creation of texture mapping for current tex_coord.
                        if str(tex_coord) not in material["scs_tex_aliases"]:
                            lprint("E Material %r is missing texture coordinate aliases, some UV mappings in Material Textures will remain empty!",
                                   (material.name,))
                            continue

                        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_image(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_image(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,))

        # now try to retrive settings for the textures from TOBJ
        if tex_type in created_textures and created_textures[tex_type]:
            final_tex_str = getattr(material.scs_props, "shader_texture_" + tex_type, "")
            tobj_abs_path = _path.get_tobj_path_from_shader_texture(final_tex_str)
            settings, map_type = _tobj_imp.get_settings_and_type(tobj_abs_path)
            created_tex_settings[tex_type] = settings

    # 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_settings, 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])
Exemple #7
0
def _draw_shader_texture(layout, mat, split_perc, texture, read_only):
    """Draws texture box with it's properties.

    :param layout: layout to draw attribute to
    :type layout: bpy.types.UILayout
    :param mat: material from which data should be displayed
    :type mat: bpy.types.Material
    :param split_perc: split percentage for attribute name/value
    :type split_perc: float
    :param texture: texture data
    :type texture: dict
    :param read_only: if texture should be read only
    :type read_only: bool
    """

    tag = texture.get('Tag', None)
    hide_state = texture.get('Hide', None)
    tag_id = tag.split(':')
    tag_id_string = tag_id[1]
    texture_type = tag_id_string[8:]
    shader_texture_id = str('shader_' + tag_id_string)

    if hide_state == 'True':
        return

    texture_box = layout.box().column()  # create column for compact display with alignment

    header_split = texture_box.row(align=True).split(percentage=0.5)
    header_split.label(texture_type.title(), icon="TEXTURE_SHADED")

    if hasattr(mat.scs_props, shader_texture_id):

        shader_texture = mat.scs_props.get(shader_texture_id, "")
        # imported tobj boolean switch (only for imported shaders)
        use_imported_tobj = getattr(mat.scs_props, shader_texture_id + "_use_imported", False)
        if read_only:
            row = header_split.row(align=True)
            row.alignment = 'RIGHT'
            row.prop(mat.scs_props, shader_texture_id + "_use_imported")

            if use_imported_tobj:

                texture_row = texture_box.row(align=True)
                item_space = texture_row.split(percentage=split_perc, align=True)
                item_space.label("TOBJ Path:")

                item_space = item_space.split(percentage=1 / (1 - split_perc + 0.000001) * 0.1, align=True)
                props = item_space.operator("material.scs_looks_wt", text="WT")
                props.property_str = shader_texture_id
                item_space.prop(mat.scs_props, shader_texture_id + "_imported_tobj", text="")

        # disable whole texture layout if it's locked
        texture_box.enabled = not mat.scs_props.get(shader_texture_id + "_locked", False)

        texture_row = texture_box.row(align=True)
        item_space = texture_row.split(percentage=split_perc, align=True)

        # in case of custom tobj value texture is used only for preview
        if read_only and use_imported_tobj:
            item_space.label("Preview Tex:")
        else:
            item_space.label("Texture:")

        layout_box_col = item_space.column(align=True)
        layout_box_row = layout_box_col.row(align=True)

        if shader_texture:
            texture_icon = 'TEXTURE'
        else:
            texture_icon = 'MATPLANE'

        # MARK INVALID SLOTS
        if _path_utils.is_valid_shader_texture_path(shader_texture):
            layout_box_row.alert = False
        else:
            layout_box_row.alert = True
            texture_icon = 'ERROR'

        # MARK EMPTY SLOTS
        if shader_texture == "":
            layout_box_row.alert = True

        layout_box_row = layout_box_row.split(percentage=1 / (1 - split_perc + 0.000001) * 0.1, align=True)
        props = layout_box_row.operator("material.scs_looks_wt", text="WT")
        props.property_str = shader_texture_id

        layout_box_row = layout_box_row.row(align=True)
        layout_box_row.prop(mat.scs_props, shader_texture_id, text='', icon=texture_icon)
        props = layout_box_row.operator('material.scs_select_shader_texture_filepath', text='', icon='FILESEL')
        props.shader_texture = shader_texture_id  # DYNAMIC ID SAVE (FOR FILE REQUESTER)

        # ADDITIONAL TEXTURE SETTINGS
        if (not read_only or (read_only and not use_imported_tobj)) and texture_box.enabled:

            tobj_filepath = _path_utils.get_tobj_path_from_shader_texture(shader_texture)

            if not tobj_filepath:
                layout_box_inner_col = layout_box_col.row(align=True)
                item_space = layout_box_inner_col.column(align=True)
                props = item_space.operator("material.scs_create_tobj", icon="NEW", text="")
                props.texture_type = texture_type
                # creating extra column->row so it can be properly disabled as tobj doesn't exists
                item_space = layout_box_inner_col.column(align=True).row(align=True)
            else:
                item_space = layout_box_col.row(align=True)

            # enable settings only if tobj exists and map type of the tobj is 2d
            item_space.enabled = tobj_filepath is not None and getattr(mat.scs_props, shader_texture_id + "_map_type", "") == "2d"

            if tobj_filepath:
                mtime = str(os.path.getmtime(tobj_filepath))
                item_space.alert = (mtime != getattr(mat.scs_props, shader_texture_id + "_tobj_load_time", "NOT FOUND"))
            else:
                item_space.alert = True

            props = item_space.operator("material.scs_reload_tobj", icon="LOAD_FACTORY", text="")
            props.texture_type = texture_type

            item_space.prop_menu_enum(
                mat.scs_props,
                str('shader_' + tag_id_string + '_settings'),
                icon='SETTINGS',
            )

        # UV LAYERS FOR TEXTURE
        uv_mappings = getattr(mat.scs_props, "shader_" + tag_id_string + "_uv", None)

        if len(uv_mappings) > 0:

            texture_row = texture_box.row(align=True)
            item_space = texture_row.split(percentage=split_perc, align=True)
            if read_only:
                item_space.label("Preview UV Map:")
            else:
                item_space.label("Mapping:")
            layout_box_col = item_space.column(align=True)

            for mapping in uv_mappings:

                item_space_row = layout_box_col.row(align=True)

                # add info about normal map uv mapping property in case of imported shader
                if read_only and tag_id_string == "texture_nmap":
                    preview_nmap_msg = str("Maping value for normal maps is in the case of imported shader\n"
                                           "also used for defining uv map layer for tangent calculations!\n"
                                           "If the uv map is not provided first entry from Mappings list above will be used!")
                    _shared.draw_warning_operator(item_space_row, "Mapping Info", preview_nmap_msg, icon="INFO")

                # add ensuring operator for norma map uv mapping
                if tag_id_string == "texture_nmap":
                    props = item_space_row.operator("mesh.scs_ensure_active_uv", text="", icon="FILE_REFRESH")
                    props.mat_name = mat.name
                    props.uv_layer = uv_mappings[0].value

                if mapping.value and mapping.value != "" and mapping.value in bpy.context.active_object.data.uv_layers:
                    icon = "GROUP_UVS"
                else:
                    icon = "ERROR"

                item_space_row.prop_search(
                    data=mapping,
                    property="value",
                    search_data=bpy.context.active_object.data,
                    search_property='uv_layers',
                    text="",
                    icon=icon,
                )

    else:
        texture_box.row().label('Unsupported Shader Texture Type!', icon="ERROR")