Esempio n. 1
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
Esempio n. 2
0
def get_texture(texture_path, texture_type, report_invalid=False):
    """Creates and setup Texture and Image data on active Material.

    :param texture_path: Texture path
    :type texture_path: str
    :param texture_type: Texture type keyword
    :type texture_type: str
    :param report_invalid: flag indicating if invalid texture should be reported in 3d view
    :type report_invalid: bool
    """

    # CREATE TEXTURE/IMAGE ID NAME
    teximag_id_name = _path.get_filename(texture_path, with_ext=False)

    # CREATE ABSOLUTE FILEPATH
    abs_texture_filepath = _path.get_abs_path(texture_path)

    # return None on non-existing texture file path
    if not abs_texture_filepath or not os.path.isfile(abs_texture_filepath):
        return None

    if abs_texture_filepath.endswith(".tobj"):
        abs_texture_filepath = _path.get_texture_path_from_tobj(abs_texture_filepath)

        # if not existing or none supported file
        if abs_texture_filepath is None or abs_texture_filepath[-4:] not in (".tga", ".png", ".dds"):

            if report_invalid:
                lprint("", report_warnings=-1, report_errors=-1)

            # take care of none existing paths referenced in tobj texture names
            if abs_texture_filepath:

                lprint("W Texture can't be displayed as TOBJ file: %r is referencing non texture file:\n\t   %r",
                       (texture_path, _path.readable_norm(abs_texture_filepath)))

            else:

                lprint("W Texture can't be displayed as TOBJ file: %r is referencing non existing texture file.",
                       (texture_path,))

            if report_invalid:
                lprint("", report_warnings=1, report_errors=1)

            return None

    texture = None
    if abs_texture_filepath and os.path.isfile(abs_texture_filepath):

        # find existing texture with this image
        if teximag_id_name in bpy.data.textures:

            # reuse existing image texture if possible
            postfix = 0
            postfixed_tex = teximag_id_name
            while postfixed_tex in bpy.data.textures:

                img_exists = bpy.data.textures[postfixed_tex].image is not None
                if img_exists and _path.repair_path(bpy.data.textures[postfixed_tex].image.filepath) == _path.repair_path(abs_texture_filepath):
                    texture = bpy.data.textures[postfixed_tex]
                    break

                postfix += 1
                postfixed_tex = teximag_id_name + "." + str(postfix).zfill(3)

        # if texture wasn't found create new one
        if not texture:

            texture = bpy.data.textures.new(teximag_id_name, 'IMAGE')
            image = None

            # reuse existing image if possible
            postfix = 0
            postfixed_img = teximag_id_name
            while postfixed_img in bpy.data.images:

                if _path.repair_path(bpy.data.images[postfixed_img].filepath) == _path.repair_path(abs_texture_filepath):
                    image = bpy.data.images[postfixed_img]
                    break

                postfix += 1
                postfixed_img = teximag_id_name + "." + str(postfix).zfill(3)

            # if image wasn't found load it
            if not image:
                image = bpy.data.images.load(abs_texture_filepath)
                image.name = teximag_id_name

                # try to get relative path to the Blender file and set it to the image
                if bpy.data.filepath != '':  # empty file path means blender file is not saved
                    try:
                        rel_path = _path.relative_path(os.path.dirname(bpy.data.filepath), abs_texture_filepath)
                    except ValueError:  # catch different mount paths: "path is on mount 'C:', start on mount 'E:'"
                        rel_path = None

                    if rel_path:
                        image.filepath = rel_path

            # finally link image to texture
            texture.image = image
            image.use_alpha = True

        # set proper color space depending on texture type
        if texture_type == "nmap":
            # For TGA normal maps texture use Non-Color color space as it should be,
            # but for 16-bits PNG normal maps texture sRGB has to be used
            # otherwise Blender completely messes up normals calculation
            if texture.image.filepath.endswith(".tga"):
                texture.image.colorspace_settings.name = "Non-Color"
            else:
                texture.image.colorspace_settings.name = "sRGB"
        else:
            texture.image.colorspace_settings.name = "sRGB"

        # set usage of normal map if texture type is correct
        texture.use_normal_map = (texture_type == "nmap")

    if texture is None and texture_path.endswith(".tobj"):
        if report_invalid:
            lprint("", report_warnings=-1, report_errors=-1)

        lprint("W Texture can't be displayed as TOBJ file: %r is referencing non existing texture file:\n\t   %r",
               (texture_path, _path.readable_norm(abs_texture_filepath)))

        if report_invalid:
            lprint("", report_warnings=1, report_errors=1)

    return texture
Esempio n. 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
Esempio n. 4
0
def get_texture(texture_path, texture_type, report_invalid=False):
    """Creates and setup Texture and Image data on active Material.

    :param texture_path: Texture path
    :type texture_path: str
    :param texture_type: Texture type keyword
    :type texture_type: str
    :param report_invalid: flag indicating if invalid texture should be reported in 3d view
    :type report_invalid: bool
    """

    # CREATE TEXTURE/IMAGE ID NAME
    teximag_id_name = _path.get_filename(texture_path, with_ext=False)

    # CREATE ABSOLUTE FILEPATH
    abs_texture_filepath = _path.get_abs_path(texture_path)

    # return None on non-existing texture file path
    if not abs_texture_filepath or not os.path.isfile(abs_texture_filepath):
        return None

    if abs_texture_filepath.endswith(".tobj"):
        abs_texture_filepath = _path.get_texture_path_from_tobj(
            abs_texture_filepath)

        # if not existing or none supported file
        if abs_texture_filepath is None or abs_texture_filepath[-4:] not in (
                ".tga", ".png", ".dds"):

            if report_invalid:
                lprint("", report_warnings=-1, report_errors=-1)

            # take care of none existing paths referenced in tobj texture names
            if abs_texture_filepath:

                lprint(
                    "W Texture can't be displayed as TOBJ file: %r is referencing non texture file:\n\t   %r",
                    (texture_path, _path.readable_norm(abs_texture_filepath)))

            else:

                lprint(
                    "W Texture can't be displayed as TOBJ file: %r is referencing non existing texture file.",
                    (texture_path, ))

            if report_invalid:
                lprint("", report_warnings=1, report_errors=1)

            return None

    texture = None
    if abs_texture_filepath and os.path.isfile(abs_texture_filepath):

        # find existing texture with this image
        if teximag_id_name in bpy.data.textures:

            # reuse existing image texture if possible
            postfix = 0
            postfixed_tex = teximag_id_name
            while postfixed_tex in bpy.data.textures:

                img_exists = bpy.data.textures[postfixed_tex].image is not None
                if img_exists and _path.repair_path(
                        bpy.data.textures[postfixed_tex].image.filepath
                ) == _path.repair_path(abs_texture_filepath):
                    texture = bpy.data.textures[postfixed_tex]
                    break

                postfix += 1
                postfixed_tex = teximag_id_name + "." + str(postfix).zfill(3)

        # if texture wasn't found create new one
        if not texture:

            texture = bpy.data.textures.new(teximag_id_name, 'IMAGE')
            image = None

            # reuse existing image if possible
            postfix = 0
            postfixed_img = teximag_id_name
            while postfixed_img in bpy.data.images:

                if _path.repair_path(
                        bpy.data.images[postfixed_img].filepath
                ) == _path.repair_path(abs_texture_filepath):
                    image = bpy.data.images[postfixed_img]
                    break

                postfix += 1
                postfixed_img = teximag_id_name + "." + str(postfix).zfill(3)

            # if image wasn't found load it
            if not image:
                image = bpy.data.images.load(abs_texture_filepath)
                image.name = teximag_id_name

                # try to get relative path to the Blender file and set it to the image
                if bpy.data.filepath != '':  # empty file path means blender file is not saved
                    try:
                        rel_path = _path.relative_path(
                            os.path.dirname(bpy.data.filepath),
                            abs_texture_filepath)
                    except ValueError:  # catch different mount paths: "path is on mount 'C:', start on mount 'E:'"
                        rel_path = None

                    if rel_path:
                        image.filepath = rel_path

            # finally link image to texture
            texture.image = image
            image.use_alpha = True

        # set proper color space depending on texture type
        if texture_type == "nmap":
            # For TGA normal maps texture use Non-Color color space as it should be,
            # but for 16-bits PNG normal maps texture sRGB has to be used
            # otherwise Blender completely messes up normals calculation
            if texture.image.filepath.endswith(".tga"):
                texture.image.colorspace_settings.name = "Non-Color"
            else:
                texture.image.colorspace_settings.name = "sRGB"
        else:
            texture.image.colorspace_settings.name = "sRGB"

        # set usage of normal map if texture type is correct
        texture.use_normal_map = (texture_type == "nmap")

    if texture is None and texture_path.endswith(".tobj"):
        if report_invalid:
            lprint("", report_warnings=-1, report_errors=-1)

        lprint(
            "W Texture can't be displayed as TOBJ file: %r is referencing non existing texture file:\n\t   %r",
            (texture_path, _path.readable_norm(abs_texture_filepath)))

        if report_invalid:
            lprint("", report_warnings=1, report_errors=1)

    return texture
Esempio n. 5
0
def get_texture_image(texture_path, texture_type, report_invalid=False):
    """Creates and returns image for given texture path and type.

    :param texture_path: Texture path
    :type texture_path: str
    :param texture_type: Texture type keyword
    :type texture_type: str
    :param report_invalid: flag indicating if invalid texture should be reported in 3d view
    :type report_invalid: bool
    :return: loaded image datablock to be used in SCS material
    :rtype: bpy.types.Image
    """

    # get reflection image texture
    if texture_path.endswith(".tobj") and texture_type == "reflection":
        return get_reflection_image(texture_path, report_invalid=report_invalid)

    # CREATE TEXTURE/IMAGE ID NAME
    teximag_id_name = _path.get_filename(texture_path, with_ext=False)

    # CREATE ABSOLUTE FILEPATH
    abs_texture_filepath = _path.get_abs_path(texture_path)

    # return None on non-existing texture file path
    if not abs_texture_filepath or not os.path.isfile(abs_texture_filepath):
        return None

    if abs_texture_filepath.endswith(".tobj"):
        abs_texture_filepath = _path.get_texture_path_from_tobj(abs_texture_filepath)

        # if not existing or none supported file
        if abs_texture_filepath is None or abs_texture_filepath[-4:] not in (".tga", ".png", ".dds"):

            if report_invalid:
                lprint("", report_warnings=-1, report_errors=-1)

            # take care of none existing paths referenced in tobj texture names
            if abs_texture_filepath:

                lprint("W Texture can't be displayed as TOBJ file: %r is referencing non texture file:\n\t   %r",
                       (texture_path, _path.readable_norm(abs_texture_filepath)))

            else:

                lprint("W Texture can't be displayed as TOBJ file: %r is referencing non existing texture file.",
                       (texture_path,))

            if report_invalid:
                lprint("", report_warnings=1, report_errors=1)

            return None

    image = None
    if abs_texture_filepath and os.path.isfile(abs_texture_filepath):

        # reuse existing image texture if possible
        postfix = 0
        postfixed_tex = teximag_id_name
        while postfixed_tex in bpy.data.images:

            img_exists = postfixed_tex in bpy.data.images
            if img_exists and _path.repair_path(bpy.data.images[postfixed_tex].filepath) == _path.repair_path(abs_texture_filepath):
                image = bpy.data.images[postfixed_tex]
                break

            postfix += 1
            postfixed_tex = teximag_id_name + "." + str(postfix).zfill(3)

        # if image wasn't found create new one
        if not image:

            image = None

            # reuse existing image if possible
            postfix = 0
            postfixed_img = teximag_id_name
            while postfixed_img in bpy.data.images:

                if _path.repair_path(bpy.data.images[postfixed_img].filepath) == _path.repair_path(abs_texture_filepath):
                    image = bpy.data.images[postfixed_img]
                    break

                postfix += 1
                postfixed_img = teximag_id_name + "." + str(postfix).zfill(3)

            # if image wasn't found load it
            if not image:
                image = bpy.data.images.load(abs_texture_filepath)
                image.name = teximag_id_name
                image.alpha_mode = 'CHANNEL_PACKED'

                # try to get relative path to the Blender file and set it to the image
                if bpy.data.filepath != '':  # empty file path means blender file is not saved
                    try:
                        rel_path = _path.relative_path(os.path.dirname(bpy.data.filepath), abs_texture_filepath)
                    except ValueError:  # catch different mount paths: "path is on mount 'C:', start on mount 'E:'"
                        rel_path = None

                    if rel_path:
                        image.filepath = rel_path

    if image is None and texture_path.endswith(".tobj"):
        if report_invalid:
            lprint("", report_warnings=-1, report_errors=-1)

        lprint("W Texture can't be displayed as TOBJ file: %r is referencing non existing texture file:\n\t   %r",
               (texture_path, _path.readable_norm(abs_texture_filepath)))

        if report_invalid:
            lprint("", report_warnings=1, report_errors=1)

    return image