Example #1
0
def get_shader_preset(shader_presets_filepath, template_name):
    """Returns requested Shader Preset data from preset file.

    :param shader_presets_filepath: A file path to SCS shader preset file, can be absolute or relative
    :type shader_presets_filepath: str
    :param template_name: Preset name
    :type template_name: str
    :return: Preset data section
    :rtype: SectionData
    """
    # print('shader_presets_filepath: %r' % shader_presets_filepath)
    if shader_presets_filepath.startswith(str(os.sep + os.sep)):  # IF RELATIVE PATH, MAKE IT ABSOLUTE
        shader_presets_filepath = _path.get_abs_path(shader_presets_filepath)
    preset_section = None
    if os.path.isfile(shader_presets_filepath):
        presets_container = _pix_container.get_data_from_file(shader_presets_filepath, '    ')
        if presets_container:
            for section in presets_container:
                if section.type == "Shader":
                    for prop in section.props:
                        if prop[0] == "PresetName":
                            if prop[1] == template_name:
                                # print(' + template name: "%s"' % template_name)
                                preset_section = section
                                break
    else:
        lprint('\nW The file path "%s" is not valid!', (shader_presets_filepath,))
    return preset_section
Example #2
0
def update_traffic_rules_library_rel_path(scs_traffic_rules_inventory, traffic_rules_library_rel_path, readonly=False):
    """The function deletes and populates again a list of Traffic Rules names in inventory. It also updates corresponding record in config file.

    :param traffic_rules_library_rel_path: Relative path to the directory with Traffic Rules files
    :type traffic_rules_library_rel_path: str
    """
    traffic_rules_library_filepath = _path.get_abs_path(traffic_rules_library_rel_path)
    if traffic_rules_library_filepath:
        trul_container = _sii.get_data_from_file(traffic_rules_library_filepath)
        if trul_container:

            # CLEAR INVENTORY
            scs_traffic_rules_inventory.clear()

            # ADD ALL ITEMS FROM CONTAINER INTO INVENTORY
            for item in trul_container:
                if item.type == 'traffic_rule_data':
                    if item.id.startswith('traffic_rule.'):
                        traffic_rule_item = scs_traffic_rules_inventory.add()
                        traffic_rule_item.name = item.id[13:]
                        # traffic_rule_item.item_id = item.id[13:]

                        if 'rule' in item.props:
                            traffic_rule_item.rule = item.props['rule']

                        if 'num_params' in item.props:
                            traffic_rule_item.num_params = str(item.props['num_params'])

        else:
            print('   traffic_rules_library_rel_path: "%s"' % str(traffic_rules_library_rel_path))

    if not readonly:
        update_item_in_file('Paths.TrafficRulesRelFilePath', traffic_rules_library_rel_path)
Example #3
0
def update_matsubs_inventory(scs_matsubs_inventory, matsubs_library_rel_path, readonly=False):
    """The function deletes and populates again a list of Material Substance names in inventory. It also updates corresponding record in config file.

    :param matsubs_library_rel_path: Relative path to the directory with Material Substance files
    :type matsubs_library_rel_path: str
    """
    matsubs_library_filepath = _path_utils.get_abs_path(matsubs_library_rel_path)
    if matsubs_library_filepath:
        matsubs_container = _sii.get_data_from_file(matsubs_library_filepath)
        if matsubs_container:

            # CLEAR INVENTORY
            scs_matsubs_inventory.clear()

            # ADD "NONE" ITEM IN INVENTORY
            matsubs_item = scs_matsubs_inventory.add()
            matsubs_item.name = "None"
            matsubs_item.item_id = 'none'
            matsubs_item.item_description = "No Material Substance"

            # ADD ALL THE OTHER ITEMS FROM CONTAINER INTO INVENTORY
            for item in matsubs_container:
                if item.type == 'game_substance':
                    if item.id.startswith('.'):
                        if 'name' in item.props:
                            matsubs_name = item.props['name']
                        else:
                            continue
                        matsubs_item = scs_matsubs_inventory.add()
                        matsubs_item.name = matsubs_name
                        matsubs_item.item_id = item.id[1:]
                        # matsubs_item.item_description = ""

    if not readonly:
        update_item_in_file('Paths.MatSubsRelFilePath', matsubs_library_rel_path)
Example #4
0
def update_hookup_library_rel_path(scs_hookup_inventory, hookup_library_rel_path, readonly=False):
    """The function deletes and populates again a list of Hookup names in inventory. It also updates corresponding record in config file.

    :param hookup_library_rel_path: Relative path to the directory with Hookup files
    :type hookup_library_rel_path: str
    """
    abs_path = _path_utils.get_abs_path(hookup_library_rel_path, is_dir=True)
    if abs_path:

        # CLEAR INVENTORY
        scs_hookup_inventory.clear()

        # READ ALL "SII" FILES IN INVENTORY FOLDER
        for root, dirs, files in os.walk(abs_path):
            # print('   root: "%s"\n  dirs: "%s"\n files: "%s"' % (root, dirs, files))
            for file in files:
                if file.endswith(".sii"):
                    filepath = os.path.join(root, file)
                    # print('   filepath: "%s"' % str(filepath))
                    hookup_container = _sii.get_data_from_file(filepath)

                    # ADD ALL ITEMS FROM CONTAINER INTO INVENTORY
                    if hookup_container:
                        for item in hookup_container:
                            # if item.type == 'sign_model':
                            if item.id.startswith('_'):
                                continue
                            else:
                                hookup_file = scs_hookup_inventory.add()
                                hookup_file.name = str(item.type + " : " + item.id)
                                hookup_file.item_id = item.id

                                if 'model' in item.props:
                                    # if model is defined as array ( appears if additional lod models are defined )
                                    # then use first none lod model
                                    if isinstance(item.props['model'], type(list())):
                                        hookup_file.model = item.props['model'][0]
                                    else:
                                        hookup_file.model = item.props['model']

                                if 'brand_idx' in item.props:
                                    try:
                                        hookup_file.brand_idx = int(item.props['brand_idx'])
                                    except:
                                        pass

                                if 'dir_type' in item.props:
                                    hookup_file.dir_type = item.props['dir_type']

                                if 'low_poly_only' in item.props:
                                    if item.props['low_poly_only'] == 'true':
                                        hookup_file.low_poly_only = True

            if '.svn' in dirs:
                dirs.remove('.svn')  # ignore SVN

    if not readonly:
        update_item_in_file('Paths.HookupRelDirPath', hookup_library_rel_path)
Example #5
0
 def invoke(self, context, event):
     """Invoke a file path selector."""
     filepath = _get_scs_globals().shader_presets_filepath
     if filepath.startswith("//"):
         self.filepath = _path_utils.get_abs_path(filepath, skip_mod_check=True)
     else:
         self.filepath = filepath
     context.window_manager.fileselect_add(self)
     return {'RUNNING_MODAL'}
Example #6
0
def update_sign_library_rel_path(scs_sign_model_inventory, sign_library_rel_path, readonly=False):
    """The function deletes and populates again a list of Sign names in inventory. It also updates corresponding record in config file.

    :param sign_library_rel_path: Relative path to the directory with Sign files
    :type sign_library_rel_path: str
    """
    sign_library_filepath = _path_utils.get_abs_path(sign_library_rel_path)
    if sign_library_filepath:

        if _get_scs_globals().sign_library_use_infixed:
            sign_library_filepaths = _path_utils.get_all_infixed_file_paths(sign_library_filepath)
        else:
            sign_library_filepaths = [sign_library_filepath]

        # CLEAR INVENTORY
        scs_sign_model_inventory.clear()

        for sign_library_filepath in sign_library_filepaths:

            sign_container = _sii.get_data_from_file(sign_library_filepath)
            if sign_container:

                # ADD ALL ITEMS FROM CONTAINER INTO INVENTORY
                for item in sign_container:
                    if item.type == 'sign_model':
                        if item.id.startswith('sign.'):
                            if 'sign_name' in item.props:
                                sign_name = item.props['sign_name']
                            else:
                                continue

                            sign_item = scs_sign_model_inventory.add()
                            sign_item.name = sign_name + " : " + item.id[5:]
                            sign_item.item_id = item.id[5:]

                            if 'model_desc' in item.props:
                                sign_item.model_desc = item.props['model_desc']

                            if 'look_name' in item.props:
                                sign_item.look_name = item.props['look_name']

                            if 'category' in item.props:
                                sign_item.category = item.props['category']

                            if 'dynamic' in item.props:
                                if item.props['dynamic'] == 'true':
                                    sign_item.dynamic = True

    if not readonly:
        update_item_in_file('Paths.SignRelFilePath', sign_library_rel_path)
Example #7
0
def load(locator):
    """Makes a preview model for a locator and link it to it
    NOTE: locator preview model path must be set

    :param locator: locator object to which preview model should be set
    :type locator: bpy.types.Object
    :return: True if preview model was set; False otherwise
    :rtype: bool
    """

    load_model = True
    abs_filepath = ""
    if not locator.scs_props.locator_show_preview_model:
        load_model = False
    else:
        filepath = locator.scs_props.locator_preview_model_path
        if filepath:
            if filepath.lower().endswith(".pim"):
                abs_filepath = _path_utils.get_abs_path(filepath, skip_mod_check=True)
                if not os.path.isfile(abs_filepath):
                    lprint("W Locator %r has invalid path to Preview Model PIM file: %r", (locator.name, abs_filepath.replace("\\", "/")))
                    load_model = False
            else:
                lprint("W Locator %r has invalid path to Preview Model PIM file: %r", (locator.name, filepath.replace("\\", "/")))
                load_model = False
        else:
            load_model = False

    if load_model:

        unload(locator)

        prem_name = str("prem_" + locator.name)
        obj = _get_model_mesh(locator, prem_name)

        if not obj:
            from io_scs_tools.imp import pim as _pim_import

            obj = _pim_import.load_pim_file(bpy.context, abs_filepath, preview_model=True)
            obj.name = prem_name
            obj.data.name = prem_name
            obj.data.scs_props.locator_preview_model_path = locator.scs_props.locator_preview_model_path
            obj.select = False

        link(locator, obj)

        return True
    else:
        return False
Example #8
0
        def invoke(self, context, event):
            """Invoke a file path selector."""

            curr_texture_path = getattr(bpy.context.active_object.active_material.scs_props, self.shader_texture)

            extensions, curr_texture_path = _path_utils.get_texture_extens_and_strip_path(curr_texture_path)
            for ext in extensions:
                filepath = _path_utils.get_abs_path(curr_texture_path + ext)

                if os.path.isfile(filepath):
                    self.filepath = filepath
                    break
            else:
                self.filepath = _get_scs_globals().scs_project_path

            context.window_manager.fileselect_add(self)
            return {'RUNNING_MODAL'}
Example #9
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)

    if is_valid_shader_texture_path(shader_texture_filepath, tobj_check=True):

        tobj_file = _path.get_abs_path(shader_texture_filepath[:-4] + ".tobj")
        # intentionally set ID property directly to avoid update function invoke
        material.scs_props[shader_texture_str + "_settings"] = int(_tobj_imp.get_settings(tobj_file), 2)
        setattr(material.scs_props, shader_texture_str + "_tobj_load_time", str(os.path.getmtime(tobj_file)))
Example #10
0
def update_tsem_library_rel_path(scs_tsem_profile_inventory, tsem_library_rel_path, readonly=False):
    """The function deletes and populates again a list of Traffic Semaphore Profile names in inventory. It also updates corresponding record in
    config file.

    :param tsem_library_rel_path: Relative path to the directory with Traffic Semaphore Profile files
    :type tsem_library_rel_path: str
    """
    tsem_library_filepath = _path_utils.get_abs_path(tsem_library_rel_path)
    if tsem_library_filepath:

        if _get_scs_globals().tsem_library_use_infixed:
            tsem_library_filepaths = _path_utils.get_all_infixed_file_paths(tsem_library_filepath)
        else:
            tsem_library_filepaths = [tsem_library_filepath]

        # CLEAR INVENTORY
        scs_tsem_profile_inventory.clear()

        for tsem_library_filepath in tsem_library_filepaths:

            tsem_container = _sii.get_data_from_file(tsem_library_filepath)
            if tsem_container:

                # ADD ALL ITEMS FROM CONTAINER INTO INVENTORY
                for item in tsem_container:
                    if item.type == 'tr_semaphore_profile':
                        if item.id.startswith('tr_sem_prof.'):
                            if 'name' in item.props:
                                tsem_name = item.props['name']
                            else:
                                continue

                            tsem_item = scs_tsem_profile_inventory.add()
                            tsem_item.name = tsem_name + " : " + item.id[12:]
                            tsem_item.item_id = item.id[12:]

                            if 'model' in item.props:
                                tsem_item.model = item.props['model'][0]

    if not readonly:
        update_item_in_file('Paths.TSemProfileRelFilePath', tsem_library_rel_path)
Example #11
0
        def execute(self, context):

            material = context.active_object.active_material

            if material:
                shader_texture_filepath = getattr(material.scs_props, "shader_texture_" + self.texture_type)

                if _material_utils.is_valid_shader_texture_path(shader_texture_filepath):

                    tex_filepath = _path_utils.get_abs_path(shader_texture_filepath)

                    if tex_filepath and (tex_filepath.endswith(".tga") or tex_filepath.endswith(".png")):

                        if _tobj_exp.export(tex_filepath[:-4] + ".tobj", os.path.basename(tex_filepath), set()):

                            _material_utils.reload_tobj_settings(material, self.texture_type)

                else:
                    self.report({'ERROR'}, "Please load texture properly first!")

            return {'FINISHED'}
Example #12
0
def get_shader_presets_container(shader_presets_filepath):
    """Returns shader presets data continaer from given path.

    :param shader_presets_filepath: relative or absolute shader presets filepath
    :type shader_presets_filepath: str
    :return: data container if file is found; None otherwise
    :rtype: io_scs_tools.internals.structure.SectionData
    """

    presets_container = None

    if shader_presets_filepath.startswith("//"):  # IF RELATIVE PATH, MAKE IT ABSOLUTE
        shader_presets_filepath = _path.get_abs_path(shader_presets_filepath)

    if os.path.isfile(shader_presets_filepath):

        presets_container = _pix_container.get_data_from_file(shader_presets_filepath, '    ')

    else:
        lprint('\nW The file path "%s" is not valid!', (shader_presets_filepath,))

    return presets_container
Example #13
0
def __update_shader_texture_tobj_file__(self, context, tex_type):
    """Hookup function for updating TOBJ file on any texture type.

    :param context: Blender context
    :type context: bpy.types.Context
    :param tex_type: string representig texture type
    :type tex_type: str
    """

    # dummy context arg usage so IDE doesn't report it as unused
    if context == context:
        pass

    shader_texture_str = "shader_texture_" + tex_type
    if _material_utils.is_valid_shader_texture_path(getattr(self, shader_texture_str)):
        tex_filepath = _path_utils.get_abs_path(getattr(self, shader_texture_str))

        if tex_filepath and (tex_filepath.endswith(".tga") or tex_filepath.endswith(".png")):
            tobj_file = tex_filepath[:-4] + ".tobj"

            if _tobj_exp.export(tobj_file, os.path.basename(tex_filepath), getattr(self, shader_texture_str + "_settings")):
                self[shader_texture_str + "_tobj_load_time"] = str(os.path.getmtime(tobj_file))
Example #14
0
def is_valid_shader_texture_path(shader_texture, tobj_check=False):
    """It returns True if there is valid Shader Texture file, otherwise False.

    :param shader_texture: SCS texture path, can be absolute or relative
    :type shader_texture: str
    :return: True if there is valid Shader Texture file, otherwise False
    :rtype: bool
    """
    if shader_texture != "":

        if tobj_check and (shader_texture.endswith(".tga") or shader_texture.endswith(".png")):
            shader_texture = shader_texture[:-4] + ".tobj"

        if shader_texture.startswith("//"):  # RELATIVE PATH
            shader_texture_abs_path = _path.get_abs_path(shader_texture)
            if shader_texture_abs_path:
                if os.path.isfile(shader_texture_abs_path):
                    return True
        else:  # ABSOLUTE PATH
            if os.path.isfile(shader_texture):
                return True

    return False
Example #15
0
def update_trigger_actions_rel_path(scs_trigger_actions_inventory, trigger_actions_rel_path, readonly=False):
    """The function deletes and populates again a list of Trigger Actions in inventory. It also updates corresponding record in config file.

    :param trigger_actions_rel_path: Relative path to the directory with Trigger Action files
    :type trigger_actions_rel_path: str
    """
    trig_actions_path = _path_utils.get_abs_path(trigger_actions_rel_path)
    if trig_actions_path:

        if _get_scs_globals().trigger_actions_use_infixed:
            trig_actions_paths = _path_utils.get_all_infixed_file_paths(trig_actions_path)
        else:
            trig_actions_paths = [trig_actions_path]

        # CLEAR INVENTORY
        scs_trigger_actions_inventory.clear()

        for trig_actions_path in trig_actions_paths:

            trig_actions_container = _sii.get_data_from_file(trig_actions_path)
            if trig_actions_container:

                # ADD ALL ITEMS FROM CONTAINER INTO INVENTORY
                for item in trig_actions_container:
                    if item.type == 'trigger_action':
                        if item.id.startswith('trig_action.'):
                            if 'name' in item.props:
                                trg_action_name = item.props['name']
                            else:
                                continue

                            trig_item = scs_trigger_actions_inventory.add()
                            trig_item.name = trg_action_name + " : " + item.id[12:]
                            trig_item.item_id = item.id[12:]

    if not readonly:
        update_item_in_file('Paths.TriggerActionsRelFilePath', trigger_actions_rel_path)
Example #16
0
def update_shader_presets_path(scs_shader_presets_inventory, shader_presets_filepath):
    """The function deletes and populates again a list of Shader Preset items in inventory. It also updates corresponding record in config file.

    :param shader_presets_filepath: Absolute or relative path to the file with Shader Presets
    :type shader_presets_filepath: str
    """
    # print('shader_presets_filepath: %r' % shader_presets_filepath)
    if shader_presets_filepath.startswith("//"):  # RELATIVE PATH
        shader_presets_abs_path = _path.get_abs_path(shader_presets_filepath)
    else:
        shader_presets_abs_path = shader_presets_filepath

    # CLEAR INVENTORY
    scs_shader_presets_inventory.clear()

    if os.path.isfile(shader_presets_abs_path):

        # ADD DEFAULT PRESET ITEM "<none>" INTO INVENTORY
        new_shader_preset = scs_shader_presets_inventory.add()
        new_shader_preset.name = "<none>"
        presets_container = _pix.get_data_from_file(shader_presets_abs_path, '    ')

        # ADD ALL PRESET ITEMS FROM FILE INTO INVENTORY
        if presets_container:
            for section in presets_container:
                if section.type == "Shader":
                    for prop in section.props:
                        if prop[0] == "PresetName":
                            preset_name = prop[1]
                            # print(' + preset name: "%s"' % preset_name)
                            new_shader_preset = scs_shader_presets_inventory.add()
                            new_shader_preset.name = preset_name
    else:
        lprint('\nW The file path "%s" is not valid!', (shader_presets_abs_path,))

    update_item_in_file('Paths.ShaderPresetsFilePath', shader_presets_filepath)
Example #17
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
Example #18
0
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)
Example #19
0
        def execute(self, context):

            material = context.material

            tex_raw_path = getattr(material.scs_props, "shader_texture_base",
                                   "")
            tex_raw_path = tex_raw_path.replace("\\", "/")

            is_aliased_directory = ("/material/road" in tex_raw_path
                                    or "/material/terrain" in tex_raw_path
                                    or "/material/custom" in tex_raw_path)

            # abort if empty texture or not aliased directory
            if not (tex_raw_path != "" and is_aliased_directory):

                self.report({
                    'ERROR'
                }, "Base texture is not from aliased directories, aliasing aborted!"
                            )
                return {'CANCELLED'}

            tex_abs_path = _path_utils.get_abs_path(tex_raw_path)
            mat_abs_path = tex_abs_path[:tex_abs_path.rfind(".")] + ".mat"

            # abort if aliasing material doesn't exists
            if not os.path.isfile(mat_abs_path):

                self.report({'ERROR'},
                            "Aliasing material not found, aliasing aborted!")
                return {'CANCELLED'}

            # finally try to do aliasing
            from io_scs_tools.internals.containers import mat as mat_container

            mat_cont = mat_container.get_data_from_file(mat_abs_path)

            # set attributes
            for attr_tuple in mat_cont.get_attributes().items():

                attr_key = attr_tuple[0]
                attr_val = attr_tuple[1]

                if attr_key == "substance":

                    if "substance" not in material.scs_props.keys():
                        continue

                    setattr(material.scs_props, "substance", attr_val)

                elif attr_key.startswith("aux"):

                    attr_key = attr_key.replace("[", "").replace("]", "")
                    auxiliary_prop = getattr(material.scs_props,
                                             "shader_attribute_" + attr_key,
                                             None)

                    if "shader_attribute_" + attr_key not in material.scs_props.keys(
                    ):
                        continue

                    for i, val in enumerate(attr_val):
                        auxiliary_prop[i].value = val

                else:

                    if "shader_attribute_" + attr_key not in material.scs_props.keys(
                    ):
                        continue

                    setattr(material.scs_props, "shader_attribute_" + attr_key,
                            attr_val)

            # set textures
            for tex_tuple in mat_cont.get_textures().items():

                if "shader_texture_" + tex_tuple[
                        0] not in material.scs_props.keys():
                    continue

                setattr(material.scs_props, "shader_texture_" + tex_tuple[0],
                        tex_tuple[1])

            # report success of aliasing
            if mat_cont.get_effect() == material.scs_props.mat_effect_name:

                self.report({'INFO'}, "Material fully aliased!")

            else:

                msg = (
                    "Aliased shader type doesn't match with current one, aliasing was not complete!\n"
                    + "Current shader type: %r\n" %
                    material.scs_props.mat_effect_name +
                    "Aliased shader type: %r\n\n" % mat_cont.get_effect() +
                    "If you want to alias values from aliased material completely,\n"
                    "select correct shader preset and flavor combination and execute aliasing again!"
                )

                bpy.ops.wm.show_warning_message(
                    "INVOKE_DEFAULT",
                    icon="INFO",
                    title="Aliasing partially successful!",
                    message=msg)

                self.report({'WARNING'}, "Aliased partially succeded!")

            return {'FINISHED'}
Example #20
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
Example #21
0
def export(root_object, used_parts, used_materials, scene, filepath):
    scs_globals = _get_scs_globals()
    output_type = scs_globals.output_type

    file_name = root_object.name

    print("\n************************************")
    print("**      SCS PIT Exporter          **")
    print("**      (c)2014 SCS Software      **")
    print("************************************\n")

    # DATA GATHERING
    look_list = []
    variant_list = []

    saved_active_look = root_object.scs_props.active_scs_look
    looks_inventory = root_object.scs_object_look_inventory
    looks_count = len(looks_inventory)
    if looks_count <= 0:
        looks_count = 1

    for i in range(0, looks_count):

        # apply each look from inventory first
        if len(looks_inventory) > 0:
            root_object.scs_props.active_scs_look = i

            # actually write values to material because Blender might not refresh data yet
            _looks.apply_active_look(root_object)

            curr_look_name = looks_inventory[i].name
        else:  # if no looks create default
            curr_look_name = "default"

        material_dict = {}
        material_list = []
        # get materials data
        for material in used_materials:
            if material is not None:
                # if material in ("_empty_slot_", "_empty_material_"):
                # NOTE: only workaround until module doesn't gets rewritten
                if material in bpy.data.materials:
                    material = bpy.data.materials[material]

                if isinstance(material, str):
                    material_name = str(material + "-_default_settings_")

                    # DEFAULT MATERIAL
                    material_export_data = _default_material(material_name)
                    material_list.append(material_name)

                else:
                    # print('material name: %r' % material.name)
                    material_name = material.name
                    material_list.append(material)

                    # SUBSTANCE
                    if material.scs_props.substance != 'None':
                        lprint('D material.name: %r\tmat.scs_props.substance: "%s"', (material.name, str(material.scs_props.substance)))
                        # TODO: Substance Export...

                    # MATERIAL EFFECT
                    # shader_data = material.get("scs_shader_attributes", {})
                    # effect_name = shader_data.get('effect', "NO EFFECT")
                    effect_name = material.scs_props.mat_effect_name

                    # CgFX SHADERS
                    # print("\n=== GET SHADER EXPORT DATA =======================") ## NOTE: The following code is OBSOLETE!!!
                    # cgfx_export_data = None
                    # print("  cgfx_export_data:\n%s" % str(cgfx_export_data))
                    # if cgfx_export_data:
                    # print("\nAttributes:")
                    # for attribute in cgfx_export_data['attributes']:
                    # if cgfx_export_data['attributes'][attribute]:
                    # print("  %s:" % str(attribute))
                    # for rec in cgfx_export_data['attributes'][attribute]:
                    # print("    %s: %s" % (str(rec), str(cgfx_export_data['attributes'][attribute][rec])))
                    # else:
                    # print("%s:\n  %s" % (str(attribute), cgfx_export_data['attributes'][attribute]))
                    # print("\nTextures:")
                    # for attribute in cgfx_export_data['textures']:
                    # if cgfx_export_data['textures'][attribute]:
                    # print("  %s:" % str(attribute))
                    # for rec in cgfx_export_data['textures'][attribute]:
                    # print("    %s: %s" % (str(rec), str(cgfx_export_data['textures'][attribute][rec])))
                    # else:
                    # print("%s:\n  %s" % (str(attribute), cgfx_export_data['textures'][attribute]))
                    # else:
                    # Print(1, 'E No CgFX data for material %r!' % material.name)
                    # print("==================================================")

                    # PRESET SHADERS
                    preset_found = False
                    alias = "NO SHADER"
                    def_cnt = attribute_cnt = texture_cnt = 0
                    def_sections = []
                    attribute_sections = []
                    texture_sections = []
                    active_shader_preset_name = material.scs_props.active_shader_preset_name
                    # print(' active_shader_preset_name: %r' % active_shader_preset_name)
                    for preset_i, preset in enumerate(scene.scs_shader_presets_inventory):
                        # print(' preset[%i]: %r' % (preset_i, preset.name))
                        if preset.name == active_shader_preset_name:
                            # print('   - material %r - %r' % (material.name, preset.name))

                            # LOAD PRESET
                            shader_presets_abs_path = _path_utils.get_abs_path(scs_globals.shader_presets_filepath)
                            # shader_presets_filepath = _get_scs_globals().shader_presets_filepath
                            # print('shader_presets_filepath: %r' % shader_presets_filepath)
                            # if shader_presets_filepath.startswith(str(os.sep + os.sep)): ## RELATIVE PATH
                            # shader_presets_abs_path = get_abs_path(shader_presets_filepath)
                            # else:
                            # shader_presets_abs_path = shader_presets_filepath

                            if os.path.isfile(shader_presets_abs_path):
                                presets_container = _pix_container.get_data_from_file(shader_presets_abs_path, '    ')

                                # FIND THE PRESET IN FILE
                                if presets_container:
                                    for section in presets_container:
                                        if section.type == "Shader":
                                            section_properties = _get_properties(section)
                                            if 'PresetName' in section_properties:
                                                preset_name = section_properties['PresetName']
                                                if preset_name == active_shader_preset_name:
                                                    alias = material.name
                                                    # print('   + preset name: %r' % preset_name)

                                                    # COLLECT ATTRIBUTES AND TEXTURES
                                                    for item in section.sections:

                                                        # DATA EXCHANGE FORMAT ATRIBUTE
                                                        if item.type == "DataExchangeFormat":
                                                            def_data = _SectionData("DataExchangeFormat")
                                                            for rec in item.props:
                                                                def_data.props.append((rec[0], rec[1]))
                                                            def_sections.append(def_data)
                                                            def_cnt += 1

                                                        # ATTRIBUTES
                                                        if item.type == "Attribute":
                                                            # print('     Attribute:')

                                                            attribute_data = _SectionData("Attribute")
                                                            for rec in item.props:
                                                                # print('       rec: %r' % str(rec))
                                                                if rec[0] == "Format":
                                                                    attribute_data.props.append((rec[0], rec[1]))
                                                                elif rec[0] == "Tag":
                                                                    # tag_prop = rec[1].replace("[", "").replace("]", "")
                                                                    # attribute_data.props.append((rec[0], tag_prop))
                                                                    attribute_data.props.append((rec[0], rec[1]))
                                                                elif rec[0] == "Value":
                                                                    format_prop = item.get_prop("Format")[1]
                                                                    tag_prop = item.get_prop("Tag")[1]
                                                                    tag_prop = tag_prop.replace("[", "").replace("]", "")
                                                                    # print('         format_prop: %r' % str(format_prop))
                                                                    # print('         tag_prop: %r' % str(tag_prop))
                                                                    if "aux" in tag_prop:
                                                                        aux_props = getattr(material.scs_props, "shader_attribute_" + tag_prop)
                                                                        value = []
                                                                        for aux_prop in aux_props:
                                                                            value.append(aux_prop.value)
                                                                    else:
                                                                        value = getattr(material.scs_props, "shader_attribute_" + tag_prop, "NO TAG")
                                                                    # print('         value: %s' % str(value))
                                                                    if format_prop == 'FLOAT':
                                                                        attribute_data.props.append((rec[0], ["&&", (value,)]))
                                                                    else:
                                                                        attribute_data.props.append((rec[0], ["i", tuple(value)]))
                                                            attribute_sections.append(attribute_data)
                                                            attribute_cnt += 1

                                                        # TEXTURES
                                                        elif item.type == "Texture":
                                                            # print('     Texture:')

                                                            texture_data = _SectionData("Texture")
                                                            for rec in item.props:
                                                                # print('       rec: %r' % str(rec))
                                                                if rec[0] == "Tag":
                                                                    tag_prop = rec[1].split(":")[1]
                                                                    tag = str("texture[" + str(texture_cnt) + "]:" + tag_prop)
                                                                    texture_data.props.append((rec[0], tag))
                                                                elif rec[0] == "Value":
                                                                    tag_prop = item.get_prop("Tag")[1].split(":")[1]
                                                                    # print('         tag_prop: %r' % str(tag_prop))

                                                                    # create and get path to tobj
                                                                    tobj_rel_path = _get_texture_path_from_material(material, tag_prop,
                                                                                                                    os.path.dirname(filepath))

                                                                    texture_data.props.append((rec[0], tobj_rel_path))

                                                            texture_sections.append(texture_data)
                                                            texture_cnt += 1

                                                    preset_found = True
                                                    break

                            else:
                                lprint('\nW The file path "%s" is not valid!', (shader_presets_abs_path,))
                        if preset_found:
                            break

                    if preset_found:

                        material_export_data = _SectionData("Material")
                        material_export_data.props.append(("Alias", alias))
                        material_export_data.props.append(("Effect", effect_name))
                        material_export_data.props.append(("Flags", 0))
                        if output_type.startswith('def'):
                            material_export_data.props.append(("DataExchangeFormatCount", def_cnt))
                        material_export_data.props.append(("AttributeCount", attribute_cnt))
                        material_export_data.props.append(("TextureCount", texture_cnt))
                        if output_type.startswith('def'):
                            for def_section in def_sections:
                                material_export_data.sections.append(def_section)
                        for attribute in attribute_sections:
                            material_export_data.sections.append(attribute)
                        for texture in texture_sections:
                            material_export_data.sections.append(texture)

                    elif active_shader_preset_name == "<imported>":

                        material_attributes = material['scs_shader_attributes']['attributes'].to_dict().values()
                        material_textures = material['scs_shader_attributes']['textures'].to_dict().values()

                        material_export_data = _SectionData("Material")
                        material_export_data.props.append(("Alias", material.name))
                        material_export_data.props.append(("Effect", effect_name))
                        material_export_data.props.append(("Flags", 0))
                        material_export_data.props.append(("AttributeCount", len(material_attributes)))
                        material_export_data.props.append(("TextureCount", len(material_textures)))

                        for attribute_dict in material_attributes:
                            attribute_section = _SectionData("Attribute")

                            format_value = ""
                            for attr_prop in sorted(attribute_dict.keys()):

                                # get the format of current attribute (we assume that "Format" attribute is before "Value" attribute in this for loop)
                                if attr_prop == "Format":
                                    format_value = attribute_dict[attr_prop]

                                if attr_prop == "Value" and ("FLOAT" in format_value or "STRING" in format_value):
                                    attribute_section.props.append((attr_prop, ["i", tuple(attribute_dict[attr_prop])]))
                                elif attr_prop == "Tag" and "aux" in attribute_dict[attr_prop]:
                                    attribute_section.props.append((attr_prop, "aux[" + attribute_dict[attr_prop][3:] + "]"))
                                else:
                                    attribute_section.props.append((attr_prop, attribute_dict[attr_prop]))

                            material_export_data.sections.append(attribute_section)

                        for texture_dict in material_textures:
                            texture_section = _SectionData("Texture")

                            tag_id_string = ""
                            for tex_prop in sorted(texture_dict.keys()):

                                if tex_prop == "Tag":
                                    tag_id_string = texture_dict[tex_prop].split(':')[1]

                                if tex_prop == "Value" and tag_id_string != "":

                                    tobj_rel_path = _get_texture_path_from_material(material, tag_id_string, os.path.dirname(filepath))
                                    texture_section.props.append((tex_prop, tobj_rel_path))

                                else:
                                    texture_section.props.append((tex_prop, texture_dict[tex_prop]))

                            material_export_data.sections.append(texture_section)

                    else:
                        # DEFAULT MATERIAL
                        material_name = str("_" + material_name + "_-_default_settings_")
                        material_export_data = _default_material(material_name)

                material_dict[material_name] = material_export_data

        # create materials sections for looks
        material_sections = _fill_material_sections(material_list, material_dict)
        look_data = {
            "name": curr_look_name,
            "material_sections": material_sections
        }
        look_list.append(look_data)

    # restore look applied before export
    root_object.scs_props.active_scs_look = saved_active_look

    # PARTS AND VARIANTS...
    part_list_cnt = len(used_parts.keys())
    if len(root_object.scs_object_variant_inventory) == 0:
        # If there is no Variant, add the Default one...
        part_list = _fill_part_list(root_object.scs_object_part_inventory, used_parts, all_parts=True)
        variant_list.append((_VARIANT_consts.default_name, part_list), )
    else:
        for variant in root_object.scs_object_variant_inventory:
            part_list = _fill_part_list(variant.parts, used_parts)
            variant_list.append((variant.name, part_list), )

    # DATA CREATION
    header_section = _fill_header_section(file_name, scs_globals.sign_export)
    look_section = _fill_look_sections(look_list)
    # part_sections = fill_part_section(part_list)
    variant_section = _fill_variant_sections(variant_list)
    comment_header_section = _fill_comment_header_section(look_list, variant_list)
    global_section = _fill_global_section(len(look_list), len(variant_list), part_list_cnt, len(used_materials))

    # DATA ASSEMBLING
    pit_container = [comment_header_section, header_section, global_section]
    for section in look_section:
        pit_container.append(section)
    for section in variant_section:
        pit_container.append(section)

    # FILE EXPORT
    ind = "    "
    pit_filepath = str(filepath + ".pit")
    result = _pix_container.write_data_to_file(pit_container, pit_filepath, ind)

    # print("************************************")
    return result
Example #22
0
def get_reflection_image(texture_path, report_invalid=False):
    """Gets reflection image for given texture path.

    1. gets all textures names and check existance
    2. create image objects for all planes
    3. setup scene, create planes, create camera projector and assign images
    4. render & save image
    5. cleanup & scene restoring
    6. load temp image and pack it
    7. set filepath to TOBJ

    :param texture_path: Texture path
    :type texture_path: 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
    """

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

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

    # return None on non-existing TOBJ
    if not abs_tobj_filepath or not os.path.isfile(abs_tobj_filepath):
        return None

    # check existance of this cubemap
    if teximag_id_name in bpy.data.images:

        if _path.get_abs_path(bpy.data.images[teximag_id_name].filepath) == abs_tobj_filepath:
            return bpy.data.images[teximag_id_name]

        bpy.data.images.remove(bpy.data.images[teximag_id_name])

    # 1. get all textures file paths and check their existance

    abs_texture_filepaths = _path.get_texture_paths_from_tobj(abs_tobj_filepath)

    # should be a cubemap with six images
    if not abs_texture_filepaths or len(abs_texture_filepaths) != 6:
        return None

    # all six images have to exist
    for abs_texture_filepath in abs_texture_filepaths:

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

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

            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)))

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

            return None

        elif not os.path.isfile(abs_texture_filepath):  # none existing file

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

            # take care of none existing paths referenced in tobj texture names
            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 None

    # 2. create image objects for all planes

    images = []
    for abs_texture_filepath in abs_texture_filepaths:
        images.append(bpy.data.images.load(abs_texture_filepath))

    # 3. setup scene, create planes, create camera projector and assign images

    old_scene = bpy.context.window.scene
    tmp_scene = bpy.data.scenes.new("cubemap")
    bpy.context.window.scene = tmp_scene

    meshes = []
    materials = []
    objects = []
    for i, plane in enumerate(("x+", "x-", "y+", "y-", "z+", "z-")):
        # mesh creation
        bm = bmesh.new(use_operators=True)

        bmesh.ops.create_grid(bm, x_segments=1, y_segments=1, size=1, calc_uvs=True)

        mesh = bpy.data.meshes.new(plane)
        bm.to_mesh(mesh)
        bm.free()

        mesh.uv_layers.new()

        meshes.append(mesh)

        # material creation
        material = bpy.data.materials.new(plane)
        material.use_nodes = True
        material.node_tree.nodes.clear()

        out_node = material.node_tree.nodes.new("ShaderNodeOutputMaterial")
        emission_node = material.node_tree.nodes.new("ShaderNodeEmission")
        tex_node = material.node_tree.nodes.new("ShaderNodeTexImage")
        tex_node.image = images[i]

        material.node_tree.links.new(emission_node.inputs['Color'], tex_node.outputs['Color'])
        material.node_tree.links.new(out_node.inputs['Surface'], emission_node.outputs['Emission'])

        mesh.materials.append(material)

        materials.append(material)

        # object creation
        obj = bpy.data.objects.new(mesh.name, mesh)
        obj.location = (0,) * 3
        obj.rotation_euler = (0,) * 3
        if plane == "x+":
            obj.rotation_euler.x = pi * 0.5
            obj.location.y = 1
        elif plane == "x-":
            obj.rotation_euler.x = pi * 0.5
            obj.rotation_euler.z = pi
            obj.location.y = -1
        elif plane == "y+":
            obj.rotation_euler.x = pi
            obj.rotation_euler.z = pi * 0.5
            obj.location.z = 1
        elif plane == "y-":
            obj.rotation_euler.z = pi * 0.5
            obj.location.z = -1
        elif plane == "z+":
            obj.rotation_euler.x = pi * 0.5
            obj.rotation_euler.z = pi * 0.5
            obj.location.x = -1
        elif plane == "z-":
            obj.rotation_euler.x = pi * 0.5
            obj.rotation_euler.z = -pi * 0.5
            obj.location.x = 1

        tmp_scene.collection.objects.link(obj)
        objects.append(obj)

    # camera creation
    camera = bpy.data.cameras.new("projector")
    camera.type = "PANO"
    camera.lens = 5
    camera.sensor_width = 32
    camera.cycles.panorama_type = "EQUIRECTANGULAR"
    camera.cycles.latitude_min = -pi * 0.5
    camera.cycles.latitude_max = pi * 0.5
    camera.cycles.longitude_min = pi
    camera.cycles.longitude_max = -pi

    cam_obj = bpy.data.objects.new(camera.name, camera)
    cam_obj.location = (0,) * 3
    cam_obj.rotation_euler = (pi * 0.5, 0, 0)

    tmp_scene.collection.objects.link(cam_obj)

    # 4. render & save image

    final_image_path = os.path.join(tempfile.gettempdir(), teximag_id_name + ".tga")

    tmp_scene.render.engine = "CYCLES"
    tmp_scene.cycles.samples = 1
    tmp_scene.camera = cam_obj
    tmp_scene.render.image_settings.file_format = "TARGA"
    tmp_scene.render.image_settings.color_mode = "RGBA"
    tmp_scene.render.resolution_percentage = 100
    tmp_scene.render.resolution_x = images[0].size[0] * 4
    tmp_scene.render.resolution_y = images[0].size[1] * 2
    tmp_scene.render.filepath = final_image_path
    bpy.ops.render.render(write_still=True, scene=tmp_scene.name)

    # 5. cleanup & scene restoring

    for obj in objects:
        bpy.data.objects.remove(obj)

    for mesh in meshes:
        bpy.data.meshes.remove(mesh)

    for material in materials:
        bpy.data.materials.remove(material)

    for image in images:
        bpy.data.images.remove(image)

    bpy.data.objects.remove(cam_obj)
    bpy.data.cameras.remove(camera)

    bpy.context.window.scene = old_scene
    bpy.data.scenes.remove(tmp_scene)

    # 6. load temp image and pack it

    final_image = bpy.data.images.load(final_image_path)
    final_image.name = teximag_id_name
    final_image.alpha_mode = 'CHANNEL_PACKED'
    final_image.pack()

    # 7. set filepath to original image
    final_image.filepath = abs_tobj_filepath

    return final_image
Example #23
0
        def execute(self, context):

            material = context.material

            tex_raw_path = getattr(material.scs_props, "shader_texture_base", "")
            tex_raw_path = tex_raw_path.replace("\\", "/")

            is_aliased_directory = ("/material/road" in tex_raw_path or
                                    "/material/terrain" in tex_raw_path or
                                    "/material/custom" in tex_raw_path)

            # abort if empty texture or not aliased directory
            if not (tex_raw_path != "" and is_aliased_directory):

                self.report({'ERROR'}, "Base texture is not from aliased directories, aliasing aborted!")
                return {'CANCELLED'}

            tex_abs_path = _path_utils.get_abs_path(tex_raw_path)
            mat_abs_path = tex_abs_path[:tex_abs_path.rfind(".")] + ".mat"

            # abort if aliasing material doesn't exists
            if not os.path.isfile(mat_abs_path):

                self.report({'ERROR'}, "Aliasing material not found, aliasing aborted!")
                return {'CANCELLED'}

            # finally try to do aliasing
            from io_scs_tools.internals.containers import mat as mat_container

            mat_cont = mat_container.get_data_from_file(mat_abs_path)

            # set attributes
            for attr_tuple in mat_cont.get_attributes().items():

                attr_key = attr_tuple[0]
                attr_val = attr_tuple[1]

                if attr_key == "substance":

                    if "substance" not in material.scs_props.keys():
                        continue

                    setattr(material.scs_props, "substance", attr_val)

                elif attr_key.startswith("aux"):

                    attr_key = attr_key.replace("[", "").replace("]", "")
                    auxiliary_prop = getattr(material.scs_props, "shader_attribute_" + attr_key, None)

                    if "shader_attribute_" + attr_key not in material.scs_props.keys():
                        continue

                    for i, val in enumerate(attr_val):
                        auxiliary_prop[i].value = val

                else:

                    if "shader_attribute_" + attr_key not in material.scs_props.keys():
                        continue

                    setattr(material.scs_props, "shader_attribute_" + attr_key, attr_val)

            # set textures
            for tex_tuple in mat_cont.get_textures().items():

                if "shader_texture_" + tex_tuple[0] not in material.scs_props.keys():
                    continue

                setattr(material.scs_props, "shader_texture_" + tex_tuple[0], tex_tuple[1])

            # report success of aliasing
            if mat_cont.get_effect() == material.scs_props.mat_effect_name:

                self.report({'INFO'}, "Material fully aliased!")

            else:

                msg = ("Aliased shader type doesn't match with current one, aliasing was not complete!\n" +
                       "Current shader type: %r\n" % material.scs_props.mat_effect_name +
                       "Aliased shader type: %r\n\n" % mat_cont.get_effect() +
                       "If you want to alias values from aliased material completely,\n"
                       "select correct shader preset and flavor combination and execute aliasing again!")

                bpy.ops.wm.show_warning_message("INVOKE_DEFAULT", icon="INFO", title="Aliasing partially successful!", message=msg)

                self.report({'WARNING'}, "Aliased partially succeded!")

            return {'FINISHED'}
Example #24
0
    def validate(self):
        """Validates content of TOBJ container. If any problem is found, validation is canceled
        and problems reported.

        :return: True if content is valid; False otherwise
        :rtype: bool
        """

        if self.map_type not in self.MAP_TYPES:
            lprint("E Unknown TOBJ map type %r, should be one of: %r.", (self.map_type, self.MAP_TYPES))
            return False

        tex_count = 6 if self.map_type == "cube" else 1  # only cube map has 6 textures
        if len(self.map_names) != tex_count:
            lprint("E Not enough textures referenced %s/%s in TOBJ.", (len(self.map_names), tex_count))
            return False

        for map_name in self.map_names:

            # use None string for invalid map names
            if map_name is None or len(map_name) < 1:
                tex_path = "None"
            elif map_name[0] == "/":
                tex_path = _path_utils.get_abs_path("//" + map_name[1:])
            else:
                tex_path = os.path.join(os.path.split(self.filepath)[0], map_name)

            if not os.path.isfile(tex_path):
                lprint("E Texture %r used in TOBJ doesn't exists.", (tex_path,))
                return False

        addr_count = 3 if self.map_type == "cube" else int(self.map_type[0])
        if len(self.addr) > 0:
            if len(self.addr) != addr_count:
                lprint("E Not enough address values %s/%s in TOBJ.", (len(self.addr), addr_count))
                return False

        for addr_entry in self.addr:
            if addr_entry not in self.ADDR_TYPES:
                lprint("E Unknown TOBJ texture address type: %r, should be one of: %r.", (addr_entry, self.ADDR_TYPES))
                return False

        if self.bias != -1:
            try:
                self.bias = int(self.bias)
            except ValueError:
                lprint("E Invalid TOBJ bias value: %r, should be non-negative integer.", (self.bias,))
                return False

        if len(self.filter) > 0:
            if len(self.filter) != 2:
                lprint("E Invalid number of filter values %s/2 in TOBJ.", (len(self.filter),))
                return False

            for i in range(2):
                if self.filter[i] not in self.FILTER_TYPES:
                    lprint("E Invalid TOBJ filter value: %s, should be one of: %r.", (self.filter[i], self.FILTER_TYPES))
                    return False

        if self.target not in self.TARGET_TYPES:
            lprint("E Invalid TOBJ target value: %s, should be one of: %r.", (self.target, self.TARGET_TYPES))
            return False

        if len(self.border_color) > 0:
            if len(self.border_color) != 4:
                lprint("E Not enough border color values %s/4 in TOBJ.", (len(self.border_color),))
                return False

            for i in range(4):

                try:
                    self.border_color[i] = float(self.border_color[i])
                except ValueError:
                    lprint("E Invalid TOBJ border color value: %s, should be float.", (self.border_color[i],))
                    return False

        if self.color_space not in self.COLOR_SPACE_TYPES:
            lprint("E Invalid TOBJ color_space value: %s, should be one of: %r.", (self.color_space, self.COLOR_SPACE_TYPES))
            return False

        if self.usage not in self.USAGE_TYPES:
            lprint("E Invalid TOBJ usage value: %s, should be one of: %r.", (self.usage, self.USAGE_TYPES))
            return False

        return True
Example #25
0
    def validate(self):
        """Validates content of TOBJ container. If any problem is found, validation is canceled
        and problems reported.

        :return: True if content is valid; False otherwise
        :rtype: bool
        """

        if self.map_type not in self.MAP_TYPES:
            lprint("E Unknown TOBJ map type %r, should be one of: %r.",
                   (self.map_type, self.MAP_TYPES))
            return False

        tex_count = 6 if self.map_type == "cube" else 1  # only cube map has 6 textures
        if len(self.map_names) != tex_count:
            lprint("E Not enough textures referenced %s/%s in TOBJ.",
                   (len(self.map_names), tex_count))
            return False

        for map_name in self.map_names:

            # use None string for invalid map names
            if map_name is None or len(map_name) < 1:
                tex_path = "None"
            elif map_name[0] == "/":
                tex_path = _path_utils.get_abs_path("//" + map_name[1:])
            else:
                tex_path = os.path.join(
                    os.path.split(self.filepath)[0], map_name)

            if not os.path.isfile(tex_path):
                lprint("E Texture %r used in TOBJ doesn't exists.",
                       (tex_path, ))
                return False

        addr_count = 3 if self.map_type == "cube" else int(self.map_type[0])
        if len(self.addr) > 0:
            if len(self.addr) != addr_count:
                lprint("E Not enough address values %s/%s in TOBJ.",
                       (len(self.addr), addr_count))
                return False

        for addr_entry in self.addr:
            if addr_entry not in self.ADDR_TYPES:
                lprint(
                    "E Unknown TOBJ texture address type: %r, should be one of: %r.",
                    (addr_entry, self.ADDR_TYPES))
                return False

        if self.bias != -1:
            try:
                self.bias = int(self.bias)
            except ValueError:
                lprint(
                    "E Invalid TOBJ bias value: %r, should be non-negative integer.",
                    (self.bias, ))
                return False

        if len(self.filter) > 0:
            if len(self.filter) != 2:
                lprint("E Invalid number of filter values %s/2 in TOBJ.",
                       (len(self.filter), ))
                return False

            for i in range(2):
                if self.filter[i] not in self.FILTER_TYPES:
                    lprint(
                        "E Invalid TOBJ filter value: %s, should be one of: %r.",
                        (self.filter[i], self.FILTER_TYPES))
                    return False

        if self.target not in self.TARGET_TYPES:
            lprint("E Invalid TOBJ target value: %s, should be one of: %r.",
                   (self.target, self.TARGET_TYPES))
            return False

        if len(self.border_color) > 0:
            if len(self.border_color) != 4:
                lprint("E Not enough border color values %s/4 in TOBJ.",
                       (len(self.border_color), ))
                return False

            for i in range(4):

                try:
                    self.border_color[i] = float(self.border_color[i])
                except ValueError:
                    lprint(
                        "E Invalid TOBJ border color value: %s, should be float.",
                        (self.border_color[i], ))
                    return False

        if self.color_space not in self.COLOR_SPACE_TYPES:
            lprint(
                "E Invalid TOBJ color_space value: %s, should be one of: %r.",
                (self.color_space, self.COLOR_SPACE_TYPES))
            return False

        if self.usage not in self.USAGE_TYPES:
            lprint("E Invalid TOBJ usage value: %s, should be one of: %r.",
                   (self.usage, self.USAGE_TYPES))
            return False

        return True
Example #26
0
def update_shader_presets_path(scs_shader_presets_inventory, shader_presets_filepath):
    """The function deletes and populates again a list of Shader Preset items in inventory. It also updates corresponding record in config file.

    :param shader_presets_filepath: Absolute or relative path to the file with Shader Presets
    :type shader_presets_filepath: str
    """
    # print('shader_presets_filepath: %r' % shader_presets_filepath)
    if shader_presets_filepath.startswith("//"):  # RELATIVE PATH
        shader_presets_abs_path = _path_utils.get_abs_path(shader_presets_filepath)
    else:
        shader_presets_abs_path = shader_presets_filepath

    # CLEAR INVENTORY AND CACHE
    scs_shader_presets_inventory.clear()
    _shader_presets_cache.clear()

    if os.path.isfile(shader_presets_abs_path):

        # ADD DEFAULT PRESET ITEM "<none>" INTO INVENTORY
        new_shader_preset = scs_shader_presets_inventory.add()
        new_shader_preset.name = "<none>"
        presets_container = _pix.get_data_from_file(shader_presets_abs_path, '    ')

        # ADD ALL SHADER PRESET ITEMS FROM FILE INTO INVENTORY
        if presets_container:

            # sort sections to shaders and flavors
            shaders = []
            flavors = {}
            for section in presets_container:
                if section.type == "Shader":
                    shaders.append(section)
                elif section.type == "Flavor":
                    flavors[section.get_prop_value("Type")] = section

            for shader in shaders:
                unique_names = []
                shader_flavors = shader.get_prop_value("Flavors")

                # create new preset item
                new_shader_preset = scs_shader_presets_inventory.add()
                new_shader_preset.name = shader.get_prop_value("PresetName")
                new_shader_preset.effect = shader.get_prop_value("Effect")

                unique_names.append("")
                _shader_presets_cache.add_section(new_shader_preset, "", shader)

                if shader_flavors:

                    for j, flavor_types in enumerate(shader_flavors):

                        # create new flavor item
                        flavor_item = new_shader_preset.flavors.add()

                        new_unique_names = []
                        for i, flavor_type in enumerate(flavor_types.split("|")):

                            if flavor_type not in flavors:
                                lprint("D Flavor used by shader preset, but not defined: %s", (flavor_type,))
                                continue

                            # create new flavor variant item
                            flavor_variant = flavor_item.variants.add()
                            flavor_variant.name = flavors[flavor_type].get_prop_value("Name")
                            flavor_variant.preset_name = new_shader_preset.name

                            # modify and save section as string into cache
                            for unique_name in unique_names:

                                section = _shader_presets_cache.get_section(new_shader_preset, unique_name)

                                for flavor_section in flavors[flavor_type].sections:

                                    flavor_section_tag = flavor_section.get_prop_value("Tag")
                                    # check if current flavor section already exists in section,
                                    # then override props and sections directly otherwise add flavor section
                                    for subsection in section.sections:

                                        subsection_tag = subsection.get_prop_value("Tag")
                                        if subsection_tag and subsection_tag == flavor_section_tag:

                                            subsection.props = flavor_section.props
                                            subsection.sections = flavor_section.sections
                                            break

                                    else:
                                        section.sections.append(flavor_section)

                                new_unique_names.append(unique_name + "." + flavors[flavor_type].get_prop_value("Name"))
                                assert section.set_prop_value("Effect", new_shader_preset.effect + new_unique_names[-1])
                                _shader_presets_cache.add_section(new_shader_preset, new_unique_names[-1], section)

                        unique_names.extend(new_unique_names)

    update_item_in_file('Paths.ShaderPresetsFilePath', shader_presets_filepath)
Example #27
0
def get_texture(texture_path, texture_type):
    """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
    """
    # print(' texture_path: %s' % str(texture_path))

    # 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)

    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:

                if _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

        # normal map related settings
        if texture_type == "nmap":
            texture.image.colorspace_settings.name = "Raw"
            texture.use_normal_map = True
        else:
            texture.image.colorspace_settings.name = "sRGB"
            texture.use_normal_map = False

    return texture
Example #28
0
 def invoke(self, context, event):
     """Invoke a file path selector."""
     self.filepath = _path_utils.get_abs_path(
         _get_scs_globals().matsubs_library_rel_path)
     context.window_manager.fileselect_add(self)
     return {'RUNNING_MODAL'}
Example #29
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"]

    # TEXTURE PATH
    texture_raw_path = getattr(material.scs_props, "shader_" + texture_type, "NO PATH")
    texture_abs_filepath = _path_utils.get_abs_path(texture_raw_path)

    # TOBJ PATH
    scs_project_path = _get_scs_globals().scs_project_path.rstrip("\\").rstrip("/")
    if os.path.isfile(scs_project_path + os.sep + texture_raw_path):  # relative within base

        tobj_rel_filepath = os.path.splitext(texture_raw_path)[0][1:]
        tobj_abs_filepath = str(os.path.splitext(texture_abs_filepath)[0] + ".tobj")

    elif os.path.isfile(texture_raw_path):  # absolute

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

            tex_dir, tex_filename = os.path.split(texture_raw_path)
            tobj_filename = tex_filename.rsplit(".", 1)[0] + ".tobj"

            # copy texture beside exported files
            shutil.copy2(texture_raw_path, os.path.join(export_path, tex_filename))

            # copy also TOBJ if exists
            texture_raw_tobj_path = 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))

            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)

        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, TOBJ can not be exported!",
               (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):
            settings = getattr(material.scs_props, "shader_" + texture_type + "_settings", set())
            texture_name = os.path.basename(_path_utils.strip_sep(texture_raw_path))
            _tobj.export(tobj_abs_filepath, texture_name, settings)
        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
Example #30
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()

    header_split = texture_box.row().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()
                item_space = texture_row.split(percentage=split_perc,
                                               align=True)
                item_space.label("TOBJ Path:")

                item_space = item_space.split(percentage=(1 - split_perc) *
                                              0.2,
                                              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()
        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 _material_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 - split_perc) *
                                              0.2,
                                              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('scene.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_exists = _material_utils.is_valid_shader_texture_path(
                shader_texture, True)

            if not tobj_exists:
                item_split = layout_box_col.split(percentage=(1 - split_perc) *
                                                  0.2,
                                                  align=True)

                item_space = item_split.row(align=True)
                props = item_space.operator("material.scs_create_tobj",
                                            icon="NEW",
                                            text="")
                props.texture_type = texture_type

                item_space = item_split.row(align=True)
            else:
                item_space = layout_box_col.row(align=True)

            item_space.enabled = tobj_exists

            if tobj_exists:
                mtime = str(
                    os.path.getmtime(
                        _path_utils.get_abs_path(shader_texture[:-4] +
                                                 ".tobj")))
                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()
            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")
Example #31
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()

    header_split = texture_box.row().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()
                item_space = texture_row.split(percentage=split_perc, align=True)
                item_space.label("TOBJ Path:")

                item_space = item_space.split(percentage=(1 - split_perc) * 0.2, 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()
        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 _material_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 - split_perc) * 0.2, 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('scene.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_exists = _material_utils.is_valid_shader_texture_path(shader_texture, True)

            if not tobj_exists:
                item_split = layout_box_col.split(percentage=(1 - split_perc) * 0.2, align=True)

                item_space = item_split.row(align=True)
                props = item_space.operator("material.scs_create_tobj", icon="NEW", text="")
                props.texture_type = texture_type

                item_space = item_split.row(align=True)
            else:
                item_space = layout_box_col.row(align=True)

            item_space.enabled = tobj_exists

            if tobj_exists:
                mtime = str(os.path.getmtime(_path_utils.get_abs_path(shader_texture[:-4] + ".tobj")))
                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()
            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":
                    item_space_row.operator("material.show_normal_maps_mapping_info", text="", 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")
Example #32
0
def load(locator):
    """Makes a preview model for a locator and link it to it
    NOTE: locator preview model path must be set

    :param locator: locator object to which preview model should be set
    :type locator: bpy.types.Object
    :return: True if preview model was set; False otherwise
    :rtype: bool
    """

    load_model = True
    abs_filepath = ""
    if not locator.scs_props.locator_show_preview_model:
        load_model = False
    else:
        filepath = locator.scs_props.locator_preview_model_path
        if filepath:
            if filepath.lower().endswith(".pim"):
                abs_filepath = _path_utils.get_abs_path(filepath,
                                                        skip_mod_check=True)
                if not os.path.isfile(abs_filepath):
                    lprint(
                        "W Locator %r has invalid path to Preview Model PIM file: %r",
                        (locator.name,
                         _path_utils.readable_norm(abs_filepath)))
                    load_model = False
            else:
                lprint(
                    "W Locator %r has invalid path to Preview Model PIM file: %r",
                    (locator.name, _path_utils.readable_norm(filepath)))
                load_model = False
        else:
            load_model = False

    if load_model:

        unload(locator)

        prem_name = str("prem_" + locator.name)
        obj = _get_model_mesh(locator, prem_name)

        if not obj:
            from io_scs_tools.imp import pim as _pim_import

            obj = _pim_import.load_pim_file(bpy.context,
                                            abs_filepath,
                                            preview_model=True)

            # in case used preview model doesn't have any mesh, abort loading, report error and reset path
            # Path has to be reset to prevent loading preview model over and over again
            # from possible callbacks trying to fix not present preview model
            if not obj:
                message = "Selected PIM model doesn't have any mesh inside, so it can not be used as a preview model."
                bpy.ops.wm.show_warning_message(
                    'INVOKE_DEFAULT',
                    is_modal=True,
                    title="Preview Model Load Error!",
                    message=message,
                    width=500,
                    height=100)
                lprint("E " + message)
                locator.scs_props.locator_preview_model_path = ""
                return False

            obj.name = prem_name
            obj.data.name = prem_name
            obj.data.scs_props.locator_preview_model_path = locator.scs_props.locator_preview_model_path
            obj.select = False

        link(locator, obj)

        return True
    else:
        return False
Example #33
0
def load(locator):
    """Makes a preview model for a locator and link it to it
    NOTE: locator preview model path must be set

    :param locator: locator object to which preview model should be set
    :type locator: bpy.types.Object
    :return: True if preview model was set; False otherwise
    :rtype: bool
    """

    load_model = True
    abs_filepath = ""
    if not locator.scs_props.locator_show_preview_model:
        load_model = False
    else:
        filepath = locator.scs_props.locator_preview_model_path
        if filepath:
            if filepath.lower().endswith(".pim"):
                abs_filepath = _path_utils.get_abs_path(filepath)
                if not os.path.isfile(abs_filepath):
                    lprint(
                        "W Locator %r has invalid path to Preview Model PIM file: %r",
                        (locator.name, abs_filepath.replace("\\", "/")))
                    load_model = False
            else:
                lprint(
                    "W Locator %r has invalid path to Preview Model PIM file: %r",
                    (locator.name, filepath.replace("\\", "/")))
                load_model = False
        else:
            load_model = False

    if load_model:

        unload(locator)

        prem_name = str("prem_" + locator.name)
        obj = _get_model_mesh(locator, prem_name)

        if not obj:
            from io_scs_tools.imp import pim as _pim_import

            obj = _pim_import.load_pim_file(
                bpy.context,
                abs_filepath,
                preview_model=True,
                looks_and_materials=False,
                textures=False,
                uv=False,
                vc=False,
                vg=False,
                weld_smoothed=False,
                bones=False,
                shadow_casters=False,
                create_locators=False,
                parts_and_variants=False,
            )
            obj.name = prem_name
            obj.data.name = prem_name
            obj.data.scs_props.locator_preview_model_path = locator.scs_props.locator_preview_model_path
            obj.select = False

        link(locator, obj)

        return True
    else:
        return False
Example #34
0
def update_shader_presets_path(scs_shader_presets_inventory, shader_presets_filepath):
    """The function deletes and populates again a list of Shader Preset items in inventory. It also updates corresponding record in config file.

    :param shader_presets_filepath: Absolute or relative path to the file with Shader Presets
    :type shader_presets_filepath: str
    """
    # print('shader_presets_filepath: %r' % shader_presets_filepath)
    if shader_presets_filepath.startswith("//"):  # RELATIVE PATH
        shader_presets_abs_path = _path_utils.get_abs_path(shader_presets_filepath)
    else:
        shader_presets_abs_path = shader_presets_filepath

    # CLEAR INVENTORY AND CACHE
    scs_shader_presets_inventory.clear()
    _shader_presets_cache.clear()

    if os.path.isfile(shader_presets_abs_path):

        # ADD DEFAULT PRESET ITEM "<none>" INTO INVENTORY
        new_shader_preset = scs_shader_presets_inventory.add()
        new_shader_preset.name = "<none>"
        presets_container = _pix.get_data_from_file(shader_presets_abs_path, '    ')

        # ADD ALL SHADER PRESET ITEMS FROM FILE INTO INVENTORY
        if presets_container:

            # sort sections to shaders and flavors
            shaders = []
            flavors = {}
            for section in presets_container:
                if section.type == "Shader":
                    shaders.append(section)
                elif section.type == "Flavor":
                    flavors[section.get_prop_value("Type")] = section

            for shader in shaders:
                unique_names = []
                shader_flavors = shader.get_prop_value("Flavors")

                # create new preset item
                new_shader_preset = scs_shader_presets_inventory.add()
                new_shader_preset.name = shader.get_prop_value("PresetName")
                new_shader_preset.effect = shader.get_prop_value("Effect")

                unique_names.append("")
                _shader_presets_cache.add_section(new_shader_preset, "", shader)

                if shader_flavors:

                    for j, flavor_types in enumerate(shader_flavors):

                        # create new flavor item
                        flavor_item = new_shader_preset.flavors.add()

                        new_unique_names = []
                        for i, flavor_type in enumerate(flavor_types.split("|")):

                            if flavor_type not in flavors:
                                lprint("D Flavor used by shader preset, but not defined: %s", (flavor_type,))
                                continue

                            # create new flavor variant item
                            flavor_variant = flavor_item.variants.add()
                            flavor_variant.name = flavors[flavor_type].get_prop_value("Name")
                            flavor_variant.preset_name = new_shader_preset.name

                            # modify and save section as string into cache
                            for unique_name in unique_names:

                                section = _shader_presets_cache.get_section(new_shader_preset, unique_name)

                                for flavor_section in flavors[flavor_type].sections:

                                    flavor_section_tag = flavor_section.get_prop_value("Tag")
                                    # check if current flavor section already exists in section,
                                    # then override props and sections directly otherwise add flavor section
                                    for subsection in section.sections:

                                        subsection_tag = subsection.get_prop_value("Tag")
                                        if subsection_tag and subsection_tag == flavor_section_tag:

                                            subsection.props = flavor_section.props
                                            subsection.sections = flavor_section.sections
                                            break

                                    else:
                                        section.sections.append(flavor_section)

                                new_unique_names.append(unique_name + "." + flavors[flavor_type].get_prop_value("Name"))
                                assert section.set_prop_value("Effect", new_shader_preset.effect + new_unique_names[-1])
                                _shader_presets_cache.add_section(new_shader_preset, new_unique_names[-1], section)

                        unique_names.extend(new_unique_names)

    update_item_in_file('Paths.ShaderPresetsFilePath', shader_presets_filepath)
Example #35
0
 def invoke(self, context, event):
     """Invoke a file path selector."""
     self.filepath = _path_utils.get_abs_path(_get_scs_globals().matsubs_library_rel_path)
     context.window_manager.fileselect_add(self)
     return {'RUNNING_MODAL'}
Example #36
0
def update_texture_slots(material, texture_path, texture_type):
    """Creates and setup Texture and Image data on active Material.

    :param material: Blender material
    :type material: Material
    :param texture_path: Texture path
    :type texture_path: str
    :param texture_type: Texture type keyword
    :type texture_type: str
    """
    # print(' texture_path: %s' % str(texture_path))

    # CREATE TEXTURE/IMAGE ID NAME
    teximag_id_name = str("scs_" + texture_type + "_" + os.path.splitext(os.path.basename(texture_path))[0])
    # print(' teximag_id_name: %r' % str(teximag_id_name))

    # PROVIDE A TEXTURE SLOT
    slot_found = None
    texture_slots = material.texture_slots

    # A. Check all Texture slots for existing Image Textures (OLD WAY)
    # NOTE: This method often results in arbitrary order of Image Textures
    # within Texture Slots. In such circumstances it is very hard to ensure
    # uniform way of Material appearance in 3D viewport, because of
    # different mixing order of Textures.
    # for texture_slot_i, texture_slot in enumerate(texture_slots):

    # B. Fixed slots for Textures...
    fixed_slots_dict = {'base': 5, 'reflection': 6, 'over': 7, 'oclu': 8,
                        'mask': 9, 'mult': 10, 'iamod': 11, 'lightmap': 12,
                        'paintjob': 13, 'flakenoise': 14, 'nmap': 15}
    if texture_type in fixed_slots_dict:
        texture_slot_i = fixed_slots_dict[texture_type]
        texture_slot = texture_slots[texture_slot_i]
        # print('  texture_slot[%.2i]: %s' % (texture_slot_i, str(texture_slot)))

        if texture_slot:
            # print('   texture_slot.name: %r' % str(texture_slot.name))
            if texture_slot.name.startswith(str("scs_" + texture_type + "_")):
                if texture_slot.name == teximag_id_name:
                    slot_found = texture_slot
                else:
                    texture_slots.clear(texture_slot_i)
                    # break # Needed for "A. Method" above...

    # CREATE ABSOLUT FILEPATH
    abs_texture_filepath = _path.get_abs_path(texture_path)
    # print(' Set texture base filepath: %r' % abs_texture_filepath)

    if abs_texture_filepath and os.path.isfile(abs_texture_filepath):
        # IF SLOT EXISTS, INSPECT IT FOR VALIDITY
        # NOTE: If Blend file contains Image links from another,
        # currently unexisting location, it is needed to correct these links.
        if slot_found:
            # print(' "SLOT_FOUND" - texture_path: %r' % str(texture_path))
            # print(' "SLOT_FOUND" - abs_texture_filepath:\n\t%r' % str(abs_texture_filepath))
            # print(' "SLOT_FOUND" - teximag_id_name: %r' % str(teximag_id_name))
            # print(' "SLOT_FOUND" - texture_slot:\n\t%r' % str(texture_slot))
            correct_image_filepath(texture_slot, abs_texture_filepath)

            return

        # CREATE/FIND NEW TEXTURE
        if teximag_id_name in bpy.data.textures:

            if os.path.abspath(bpy.data.textures[teximag_id_name].image.filepath) == abs_texture_filepath:
                # REUSE EXISTING IMAGE TEXTURE
                new_texture = bpy.data.textures[teximag_id_name]
            else:  # also check all the duplicates
                postfix = 1
                postfixed_tex = teximag_id_name + "." + str(postfix).zfill(3)
                while postfixed_tex in bpy.data.textures:

                    if os.path.abspath(bpy.data.textures[postfixed_tex].image.filepath) == abs_texture_filepath:
                        # REUSE EXISTING IMAGE TEXTURE
                        new_texture = bpy.data.textures[postfixed_tex]
                        break

                    postfix += 1
                    postfixed_tex = teximag_id_name + "." + str(postfix).zfill(3)
                else:
                    # CREATE NEW IMAGE TEXTURE
                    new_texture = bpy.data.textures.new(teximag_id_name, 'IMAGE')
        else:
            # CREATE NEW IMAGE TEXTURE
            new_texture = bpy.data.textures.new(teximag_id_name, 'IMAGE')
        # print('   new_texture: %s' % str(new_texture))

        # CREATE/FIND NEW IMAGE
        if teximag_id_name in bpy.data.images.keys() and os.path.abspath(bpy.data.images[teximag_id_name].filepath) == abs_texture_filepath:
            # REUSE EXISTING IMAGE
            new_image = bpy.data.images[teximag_id_name]
        else:
            # CREATE NEW IMAGE
            new_image = bpy.data.images.load(abs_texture_filepath)
            new_image.name = teximag_id_name
        # print('   new_image: %s' % str(new_image))

        # LINK IMAGE TO IMAGE TEXTURE
        new_texture.image = new_image

        # CREATE AND SETUP NEW TEXTURE SLOT
        # for texture_slot_i, texture_slot in enumerate(texture_slots):  # Needed for "A. Method" above...
        # print('  texture_slot[%.2i]: %s' % (texture_slot_i, str(texture_slot)))
        # if not texture_slot:

        new_texture_slot = texture_slots.create(texture_slot_i)

        # LINK IMAGE TEXTURE TO TEXTURE SLOT
        new_texture_slot.texture = new_texture

        # MAKE VISUAL SETTINGS
        new_texture_slot.color = (1.0, 1.0, 1.0)
        new_image.use_alpha = False

        texture_mappings = getattr(material.scs_props, "shader_texture_" + texture_type + "_uv")
        if texture_mappings and len(texture_mappings) > 0:
            new_texture_slot.uv_layer = texture_mappings[0].value

        if texture_type == 'base':
            new_texture_slot.texture_coords = 'UV'
            new_texture_slot.use_map_color_diffuse = True

            if material.scs_props.mat_effect_name.endswith(".a"):
                new_texture_slot.use_map_alpha = True
                new_image.use_alpha = True

        else:
            new_texture_slot.use_map_color_diffuse = False

        if texture_type == 'reflection':
            new_texture_slot.texture_coords = 'REFLECTION'
            new_texture_slot.use_map_emit = True

        if texture_type == "mult":
            new_texture_slot.use_map_color_diffuse = True
            new_texture_slot.blend_type = "MULTIPLY"

        if texture_type == 'nmap':
            new_texture_slot.texture_coords = 'UV'
            new_texture_slot.use_map_normal = True
            new_texture_slot.normal_map_space = 'TANGENT'
            new_texture.use_normal_map = True
Example #37
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
Example #38
0
def update_hookup_library_rel_path(scs_hookup_inventory,
                                   hookup_library_rel_path,
                                   readonly=False):
    """The function deletes and populates again a list of Hookup names in inventory. It also updates corresponding record in config file.

    :param hookup_library_rel_path: Relative path to the directory with Hookup files
    :type hookup_library_rel_path: str
    """
    abs_path = _path_utils.get_abs_path(hookup_library_rel_path, is_dir=True)
    if abs_path:

        # CLEAR INVENTORY
        scs_hookup_inventory.clear()

        # READ ALL "SII" FILES IN INVENTORY FOLDER
        for root, dirs, files in os.walk(abs_path):
            # print('   root: "%s"\n  dirs: "%s"\n files: "%s"' % (root, dirs, files))
            for file in files:
                if file.endswith(".sii"):
                    filepath = os.path.join(root, file)
                    # print('   filepath: "%s"' % str(filepath))
                    hookup_container = _sii.get_data_from_file(filepath)

                    # ADD ALL ITEMS FROM CONTAINER INTO INVENTORY
                    if hookup_container:
                        for item in hookup_container:
                            # if item.type == 'sign_model':
                            if item.id.startswith('_'):
                                continue
                            else:
                                hookup_file = scs_hookup_inventory.add()
                                hookup_file.name = str(item.type + " : " +
                                                       item.id)
                                hookup_file.item_id = item.id

                                if 'model' in item.props:
                                    # if model is defined as array ( appears if additional lod models are defined )
                                    # then use first none lod model
                                    if isinstance(item.props['model'],
                                                  type(list())):
                                        hookup_file.model = item.props[
                                            'model'][0]
                                    else:
                                        hookup_file.model = item.props['model']

                                if 'brand_idx' in item.props:
                                    try:
                                        hookup_file.brand_idx = int(
                                            item.props['brand_idx'])
                                    except:
                                        pass

                                if 'dir_type' in item.props:
                                    hookup_file.dir_type = item.props[
                                        'dir_type']

                                if 'low_poly_only' in item.props:
                                    if item.props['low_poly_only'] == 'true':
                                        hookup_file.low_poly_only = True

            if '.svn' in dirs:
                dirs.remove('.svn')  # ignore SVN

    if not readonly:
        update_item_in_file('Paths.HookupRelDirPath', hookup_library_rel_path)