Exemple #1
0
def start_debug(host='localhost', port=REMOTE_PORT):
    NifLog.debug(f"Setting up debugger")
    try:
        pydev_src = os.environ['PYDEVDEBUG']
        NifLog.debug(f"Dev: Found: {pydev_src}")
        if sys.path.count(pydev_src) < 1:
            sys.path.append(pydev_src)
        NifLog.debug(f"Dev: Added to sys.path - {sys.path}")
    except KeyError:
        NifLog.info(f"Dev: Sys variable not set")
        return

    try:
        NifLog.debug(f"Attempting to load pydevd")
        from pydevd_pycharm import settrace
        NifLog.debug(f"Dev: Loaded pydevd")
    except ImportError:
        NifLog.debug(f"Dev: Import failed to find pydevd module.\nPython Remote Debugging Server not found")
        return

    try:
        NifLog.debug(f"Dev: Attempting to set a tracepoint in the stack")
        settrace(host=host, port=port, stdoutToServer=True, stderrToServer=True, suspend=True)
        NifLog.debug(f"Dev: Debugger was successfully detected")
    except Exception as e:
        NifLog.debug(f"Dev: Unable to connect to remote debugging server")
        NifLog.debug(e)
        return

    NifLog.debug("Debugger setup completed")
    def apply_skin_deformation(n_data):
        """ Process all geometries in NIF tree to apply their skin """
        # get all geometries with skin
        n_geoms = [
            g for g in n_data.get_global_iterator()
            if isinstance(g, NifFormat.NiGeometry) and g.is_skin()
        ]

        # make sure that each skin is applied only once to avoid distortions when a model is referred to twice
        for n_geom in set(n_geoms):
            NifLog.info('Applying skin deformation on geometry {0}'.format(
                n_geom.name))
            skininst = n_geom.skin_instance
            skindata = skininst.data
            if skindata.has_vertex_weights:
                vertices = n_geom.get_skin_deformation()[0]
            else:
                NifLog.info(
                    "PyFFI does not support this type of skinning, so here's a workaround..."
                )
                vertices = VertexGroup.get_skin_deformation_from_partition(
                    n_geom)

            # finally we can actually set the data
            for vold, vnew in zip(n_geom.data.vertices, vertices):
                vold.x = vnew.x
                vold.y = vnew.y
                vold.z = vnew.z
    def export_bsxflags_upb(self, root_block, root_objects):
        # TODO [object][property] Fixme
        NifLog.info("Checking collision")
        # activate oblivion/Fallout 3 collision and physics
        if bpy.context.scene.niftools_scene.game in ('OBLIVION', 'FALLOUT_3',
                                                     'SKYRIM'):
            b_obj = self.has_collision()
            if b_obj:
                # enable collision
                bsx = block_store.create_block("BSXFlags")
                bsx.name = 'BSX'
                root_block.add_extra_data(bsx)
                found_bsx = False
                for root_object in root_objects:
                    if root_object.niftools.bsxflags:
                        if found_bsx:
                            raise NifError(
                                "Multiple objects have BSXFlags. Only one onject may contain this data"
                            )
                        else:
                            found_bxs = True
                            bsx.integer_data = root_object.niftools.bsxflags

                # many Oblivion nifs have a UPB, but export is disabled as
                # they do not seem to affect anything in the game
                if b_obj.niftools.upb:
                    upb = block_store.create_block("NiStringExtraData")
                    upb.name = 'UPB'
                    if b_obj.niftools.upb == '':
                        upb.string_data = UPB_DEFAULT
                    else:
                        upb.string_data = b_obj.niftools.upb.encode()
                    root_block.add_extra_data(upb)
Exemple #4
0
    def export_root_node(self, root_objects, filebase):
        """ Exports a nif's root node; use blender root if there is only one, else create a meta root """
        # TODO [collsion] detect root collision -> root collision node (can be mesh or empty)
        #     self.nif_export.collisionhelper.export_collision(b_obj, n_parent)
        #     return None  # done; stop here
        self.n_root = None
        # there is only one root object so that will be our final root
        if len(root_objects) == 1:
            b_obj = root_objects[0]
            self.export_node(b_obj, None)

        # there is more than one root object so we create a meta root
        else:
            NifLog.info("Created meta root because blender scene had multiple root objects")
            self.n_root = types.create_ninode()
            self.n_root.name = "Scene Root"
            for b_obj in root_objects:
                self.export_node(b_obj, self.n_root)

        # TODO [object] How dow we know we are selecting the right node in the case of multi-root?
        # making root block a fade node
        root_type = b_obj.niftools.rootnode
        if bpy.context.scene.niftools_scene.game in ('FALLOUT_3', 'SKYRIM') and root_type == 'BSFadeNode':
            NifLog.info("Making root block a BSFadeNode")
            fade_root_block = NifFormat.BSFadeNode().deepcopy(self.n_root)
            fade_root_block.replace_global_node(self.n_root, fade_root_block)
            self.n_root = fade_root_block

        # various extra datas
        object_property = ObjectDataProperty()
        object_property.export_bsxflags_upb(self.n_root, root_objects)
        object_property.export_inventory_marker(self.n_root, root_objects)
        object_property.export_weapon_location(self.n_root, b_obj)
        types.export_furniture_marker(self.n_root, filebase)
        return self.n_root
    def execute(self):
        """Main import function."""

        try:
            dirname = os.path.dirname(NifOp.props.filepath)
            kf_files = [os.path.join(dirname, file.name) for file in NifOp.props.files if file.name.lower().endswith(".kf")]
            # if an armature is present, prepare the bones for all actions
            b_armature = math.get_armature()
            if b_armature:
                # the axes used for bone correction depend on the armature in our scene
                math.set_bone_orientation(b_armature.data.niftools.axis_forward, b_armature.data.niftools.axis_up)
                # get nif space bind pose of armature here for all anims
                self.transform_anim.get_bind_data(b_armature)
            for kf_file in kf_files:
                kfdata = KFFile.load_kf(kf_file)

                self.apply_scale(kfdata, NifOp.props.scale_correction)

                # calculate and set frames per second
                self.transform_anim.set_frames_per_second(kfdata.roots)
                for kf_root in kfdata.roots:
                    self.transform_anim.import_kf_root(kf_root, b_armature)

        except NifError:
            return {'CANCELLED'}

        NifLog.info("Finished successfully")
        return {'FINISHED'}
Exemple #6
0
    def export_text_keys(self, b_action):
        """Process b_action's pose markers and return an extra string data block."""
        if NifOp.props.animation == 'GEOM_NIF':
            # animation group extra data is not present in geometry only files
            return
        NifLog.info("Exporting animation groups")

        self.add_dummy_markers(b_action)

        # add a NiTextKeyExtraData block
        n_text_extra = block_store.create_block("NiTextKeyExtraData",
                                                b_action.pose_markers)

        # create a text key for each frame descriptor
        n_text_extra.num_text_keys = len(b_action.pose_markers)
        n_text_extra.text_keys.update_size()
        f0, f1 = b_action.frame_range
        for key, marker in zip(n_text_extra.text_keys, b_action.pose_markers):
            f = marker.frame
            if (f < f0) or (f > f1):
                NifLog.warn(
                    f"Marker out of animated range ({f} not between [{f0}, {f1}])"
                )

            key.time = f / self.fps
            key.value = marker.name.replace('/', '\r\n')

        return n_text_extra
    def import_material_uv_controller(self, b_material, n_geom):
        """Import UV controller data."""
        # search for the block
        n_ctrl = math.find_controller(n_geom, NifFormat.NiUVController)
        if not n_ctrl:
            return
        NifLog.info("Importing UV controller")

        b_mat_action = self.create_action(b_material, "MaterialAction")

        dtypes = ("offset", 0), ("offset", 1), ("scale", 0), ("scale", 1)
        for n_uvgroup, (data_path, array_ind) in zip(n_ctrl.data.uv_groups,
                                                     dtypes):
            if n_uvgroup.keys:
                interp = self.get_b_interp_from_n_interp(
                    n_uvgroup.interpolation)
                # in blender, UV offset is stored per n_texture slot
                # so we have to repeat the import for each used tex slot
                for i, texture_slot in enumerate(b_material.texture_slots):
                    if texture_slot:
                        fcurves = self.create_fcurves(
                            b_mat_action, f"texture_slots[{i}]." + data_path,
                            (array_ind, ), n_ctrl.flags)
                        for key in n_uvgroup.keys:
                            if "offset" in data_path:
                                self.add_key(fcurves, key.time, (-key.value, ),
                                             interp)
                            else:
                                self.add_key(fcurves, key.time, (key.value, ),
                                             interp)
def start_debug(port=REMOTE_PORT):
    NifLog.debug("Setting up debugger")
    try:
        pydev_src = os.environ['PYDEVDEBUG']
        NifLog.debug(f"Found: {pydev_src}")
        if sys.path.count(pydev_src) < 1:
            sys.path.append(pydev_src)
    except KeyError:
        NifLog.info("Dev: Sys variable not set")
        return

    try:
        from pydevd_pycharm import settrace
    except ImportError:
        NifLog.debug("Dev: Import failed to find pydevd module.\nPython Remote Debugging Server not found")
        return

    try:
        settrace('localhost', port=port, stdoutToServer=True, stderrToServer=True, suspend=True)
    except Exception as e:
        NifLog.debug("Unable to connect to remote debugging server")
        NifLog.debug(e)
        return

    NifLog.debug("Debugger setup completed")
    def import_morph_controller(self, n_node, b_obj):
        """Import NiGeomMorpherController as shape keys for blender object."""

        n_morphCtrl = math.find_controller(n_node, NifFormat.NiGeomMorpherController)
        if n_morphCtrl:
            NifLog.debug("NiGeomMorpherController processed")
            b_mesh = b_obj.data
            morphData = n_morphCtrl.data
            if morphData.num_morphs:
                # get name for base key
                keyname = morphData.morphs[0].frame_name.decode()
                if not keyname:
                    keyname = 'Base'

                # insert base key at frame 1, using relative keys
                sk_basis = b_obj.shape_key_add(name=keyname)

                # get base vectors and import all morphs
                baseverts = morphData.morphs[0].vectors

                shape_action = self.create_action(b_obj.data.shape_keys, b_obj.name + "-Morphs")
                
                for idxMorph in range(1, morphData.num_morphs):
                    # get name for key
                    keyname = morphData.morphs[idxMorph].frame_name.decode()
                    if not keyname:
                        keyname = f'Key {idxMorph}'
                    NifLog.info(f"Inserting key '{keyname}'")
                    # get vectors
                    morph_verts = morphData.morphs[idxMorph].vectors
                    self.morph_mesh(b_mesh, baseverts, morph_verts)
                    shape_key = b_obj.shape_key_add(name=keyname, from_mix=False)

                    # first find the keys
                    # older versions store keys in the morphData
                    morph_data = morphData.morphs[idxMorph]
                    # newer versions store keys in the controller
                    if not morph_data.keys:
                        try:
                            if n_morphCtrl.interpolators:
                                morph_data = n_morphCtrl.interpolators[idxMorph].data.data
                            elif n_morphCtrl.interpolator_weights:
                                morph_data = n_morphCtrl.interpolator_weights[idxMorph].interpolator.data.data
                        except KeyError:
                            NifLog.info(f"Unsupported interpolator \"{type(n_morphCtrl.interpolator_weights['idxMorph'].interpolator)}\"")
                            continue
                        
                    # get the interpolation mode
                    interp = self.get_b_interp_from_n_interp( morph_data.interpolation)
                    fcu = self.create_fcurves(shape_action, "value", (0,), flags=n_morphCtrl.flags, keyname=shape_key.name)
                    
                    # set keyframes
                    for key in morph_data.keys:
                        self.add_key(fcu, key.time, (key.value,), interp)
 def add_dummy_markers(self, b_action):
     # if we exported animations, but no animation groups are defined,
     # define a default animation group
     NifLog.info("Checking action pose markers.")
     if not b_action.pose_markers:
         NifLog.info("Defining default action pose markers.")
         for frame, text in zip(b_action.frame_range,
                                ("Idle: Start/Idle: Loop Start",
                                 "Idle: Loop Stop/Idle: Stop")):
             marker = b_action.pose_markers.new(text)
             marker.frame = frame
Exemple #11
0
def get_version_data():
    """ Returns NifFormat.Data of the correct version and user versions """
    b_scene = bpy.context.scene.niftools_scene
    game = b_scene.game
    version = b_scene.nif_version
    NifLog.info(f"Writing NIF version 0x{version:08X}")

    # get user version and user version 2 for export
    user_version = b_scene.user_version if b_scene.user_version else b_scene.USER_VERSION.get(game, 0)
    user_version_2 = b_scene.user_version_2 if b_scene.user_version_2 else b_scene.USER_VERSION_2.get(game, 0)

    return version, NifFormat.Data(version, user_version, user_version_2)
def locate_dependencies():
    # Python dependencies are bundled inside the io_scene_nif/dependencies folder
    global current_dir
    current_dir = os.path.dirname(__file__)
    _dependencies_path = os.path.join(current_dir, "dependencies")
    if _dependencies_path not in sys.path:
        sys.path.append(_dependencies_path)
    del _dependencies_path

    with open(os.path.join(current_dir, "VERSION.txt")) as version:
        NifLog.info(f"Loading: Blender Niftools Addon: {version.read()}")
        import pyffi
        NifLog.info(f"Loading: PyFFi: {pyffi.__version__}")
    def import_embedded_texture_source(self, source):

        fn, tex = self.generate_image_name()

        # save embedded texture as dds file
        with open(tex, "wb") as stream:
            try:
                NifLog.info(f"Saving embedded texture as {tex}")
                source.pixel_data.save_as_dds(stream)
            except ValueError:
                NifLog.warn(f"Pixel format not supported in embedded texture {tex}!")

        return self.load_image(tex)
    def import_visibility(self, n_node, b_obj):
        """Import vis controller for blender object."""

        n_vis_ctrl = math.find_controller(n_node, NifFormat.NiVisController)
        if not n_vis_ctrl:
            return
        NifLog.info("Importing vis controller")

        b_obj_action = self.create_action(b_obj, b_obj.name + "-Anim")

        fcurves = self.create_fcurves(b_obj_action, "hide", (0, ),
                                      n_vis_ctrl.flags)
        for key in n_vis_ctrl.data.keys:
            self.add_key(fcurves, key.time, (key.value, ), "CONSTANT")
    def register_block(self, block, b_obj=None):
        """Helper function to register a newly created block in the list of
        exported blocks and to associate it with a Blender object.

        @param block: The nif block.
        @param b_obj: The Blender object.
        @return: C{block}"""
        if b_obj is None:
            NifLog.info(f"Exporting {block.__class__.__name__} block")
        else:
            NifLog.info(
                f"Exporting {b_obj} as {block.__class__.__name__} block")
        self._block_to_obj[block] = b_obj
        return block
    def __init__(self, operator, context):
        """Common initialization functions for executing the import/export operators: """

        NifOp.init(operator, context)

        debugging.start_debug()

        # print scripts info
        from . import bl_info
        niftools_ver = (".".join(str(i) for i in bl_info["version"]))

        NifLog.info(
            f"Executing - Niftools : Blender Niftools Addon v{niftools_ver}"
            f"(running on Blender {bpy.app.version_string}, "
            f"PyFFI {pyffi.__version__})")
    def set_frames_per_second(roots):
        """Scan all blocks and set a reasonable number for FPS to this class and the scene."""
        # find all key times
        key_times = []
        for root in roots:
            for kfd in root.tree(block_type=NifFormat.NiKeyframeData):
                key_times.extend(key.time for key in kfd.translations.keys)
                key_times.extend(key.time for key in kfd.scales.keys)
                key_times.extend(key.time for key in kfd.quaternion_keys)
                key_times.extend(key.time for key in kfd.xyz_rotations[0].keys)
                key_times.extend(key.time for key in kfd.xyz_rotations[1].keys)
                key_times.extend(key.time for key in kfd.xyz_rotations[2].keys)

            for kfi in root.tree(block_type=NifFormat.NiBSplineInterpolator):
                if not kfi.basis_data:
                    # skip bsplines without basis data (eg bowidle.kf in Oblivion)
                    continue
                key_times.extend(
                    point * (kfi.stop_time - kfi.start_time) /
                    (kfi.basis_data.num_control_points - 2)
                    for point in range(kfi.basis_data.num_control_points - 2))

            for uv_data in root.tree(block_type=NifFormat.NiUVData):
                for uv_group in uv_data.uv_groups:
                    key_times.extend(key.time for key in uv_group.keys)

        # not animated, return a reasonable default
        if not key_times:
            return

        # calculate FPS
        key_times = sorted(set(key_times))
        fps = animation.FPS
        lowest_diff = sum(
            abs(int(time * fps + 0.5) - (time * fps)) for time in key_times)

        # for test_fps in range(1,120): #disabled, used for testing
        for test_fps in [20, 24, 25, 30, 35]:
            diff = sum(
                abs(int(time * test_fps + 0.5) - (time * test_fps))
                for time in key_times)
            if diff < lowest_diff:
                lowest_diff = diff
                fps = test_fps
        NifLog.info(f"Animation estimated at {fps} frames per second.")
        animation.FPS = fps
        bpy.context.scene.render.fps = fps
        bpy.context.scene.frame_set(0)
 def export_text_keys(self, b_action, n_text_extra):
     """Process b_action's pose markers and populate the extra string data block."""
     NifLog.info("Exporting animation groups")
     self.add_dummy_markers(b_action)
     # create a text key for each frame descriptor
     n_text_extra.num_text_keys = len(b_action.pose_markers)
     n_text_extra.text_keys.update_size()
     f0, f1 = b_action.frame_range
     for key, marker in zip(n_text_extra.text_keys, b_action.pose_markers):
         f = marker.frame
         if (f < f0) or (f > f1):
             NifLog.warn(
                 f"Marker out of animated range ({f} not between [{f0}, {f1}])"
             )
         key.time = f / self.fps
         key.value = marker.name.replace('/', '\r\n')
Exemple #19
0
    def export_egm(self, key_blocks):
        EGMData.data = EgmFormat.Data(num_vertices=len(key_blocks[0].data))
        for key_block in key_blocks:
            if key_block.name.startswith("EGM SYM"):
                morph = EGMData.data.add_sym_morph()
            elif key_block.name.startswith("EGM ASYM"):
                morph = EGMData.data.add_asym_morph()
            else:
                continue
            NifLog.info(f"Exporting morph {key_block.name} to egm")
            relative_vertices = []

            # note: key_blocks[0] is base b_key
            for base_vert, key_vert in zip(key_blocks[0].data, key_block.data):
                relative_vertices.append(key_vert.co - base_vert.co)
            morph.set_relative_vertices(relative_vertices)
 def add_dummy_controllers(self):
     NifLog.info("Adding controllers and interpolators for skeleton")
     # note: block_store.block_to_obj changes during iteration, so need list copy
     for n_block in list(block_store.block_to_obj.keys()):
         if isinstance(
                 n_block,
                 NifFormat.NiNode) and n_block.name.decode() == "Bip01":
             for n_bone in n_block.tree(block_type=NifFormat.NiNode):
                 n_kfc, n_kfi = self.transform_anim.create_controller(
                     n_bone, n_bone.name.decode())
                 # todo [anim] use self.nif_export.animationhelper.set_flags_and_timing
                 n_kfc.flags = 12
                 n_kfc.frequency = 1.0
                 n_kfc.phase = 0.0
                 n_kfc.start_time = consts.FLOAT_MAX
                 n_kfc.stop_time = consts.FLOAT_MIN
    def import_material_alpha_controller(self, b_material, n_material):
        # find alpha controller
        n_alphactrl = math.find_controller(n_material,
                                           NifFormat.NiAlphaController)
        if not n_alphactrl:
            return
        NifLog.info("Importing alpha controller")

        b_mat_action = self.create_action(b_material, "MaterialAction")
        fcurves = self.create_fcurves(b_mat_action, "niftools.emissive_alpha",
                                      range(3), n_alphactrl.flags)
        interp = self.get_b_interp_from_n_interp(
            n_alphactrl.data.data.interpolation)
        for key in n_alphactrl.data.data.keys:
            self.add_key(fcurves, key.time, (key.value, key.value, key.value),
                         interp)
 def add_dummy_markers(self, b_action):
     # if we exported animations, but no animation groups are defined,
     # define a default animation group
     NifLog.info("Checking action pose markers.")
     if not b_action.pose_markers:
         # has_controllers = False
         # for block in block_store.block_to_obj:
         #     # has it a controller field?
         #     if isinstance(block, NifFormat.NiObjectNET):
         #         if block.controller:
         #             has_controllers = True
         #             break
         # if has_controllers:
         NifLog.info("Defining default action pose markers.")
         for frame, text in zip(b_action.frame_range,
                                ("Idle: Start/Idle: Loop Start",
                                 "Idle: Loop Stop/Idle: Stop")):
             marker = b_action.pose_markers.new(text)
             marker.frame = frame
Exemple #23
0
    def execute(self):
        """Main import function."""

        try:
            egm_path = NifOp.props.filepath

            if egm_path:
                EGMData.init(EGMFile.load_egm(egm_path))
                # scale the data
                EGMData.data.apply_scale(NifOp.props.scale_correction)
                # TODO [morph][egm] if there is an egm, the assumption is that there is only one mesh in the nif
                # grab the active object
                b_obj = bpy.context.view_layer.objects.active
                if b_obj and b_obj.type == "MESH":
                    self.morph_anim.import_egm_morphs(b_obj)
        except NifError:
            return {'CANCELLED'}

        NifLog.info("Finished successfully")
        return {'FINISHED'}
Exemple #24
0
    def execute(self):
        """Main import function."""

        try:
            dirname = os.path.dirname(NifOp.props.filepath)
            kf_files = [
                os.path.join(dirname, file.name) for file in NifOp.props.files
                if file.name.lower().endswith(".kf")
            ]
            b_armature = math.get_armature()
            if not b_armature:
                raise NifError(
                    "No armature was found in scene, can not import KF animation!"
                )

            # the axes used for bone correction depend on the armature in our scene
            math.set_bone_orientation(b_armature.data.niftools.axis_forward,
                                      b_armature.data.niftools.axis_up)

            # get nif space bind pose of armature here for all anims
            bind_data = armature.get_bind_data(b_armature)
            for kf_file in kf_files:
                kfdata = KFFile.load_kf(kf_file)

                # use pyffi toaster to scale the tree
                toaster = pyffi.spells.nif.NifToaster()
                toaster.scale = NifOp.props.scale_correction
                pyffi.spells.nif.fix.SpellScale(data=kfdata,
                                                toaster=toaster).recurse()

                # calculate and set frames per second
                self.tranform_anim.set_frames_per_second(kfdata.roots)
                for kf_root in kfdata.roots:
                    self.tranform_anim.import_kf_root(kf_root, b_armature,
                                                      bind_data)

        except NifError:
            return {'CANCELLED'}

        NifLog.info("Finished successfully")
        return {'FINISHED'}
    def import_mesh(self, n_block, b_obj):
        """Creates and returns a raw mesh, or appends geometry data to group_mesh.

        :param n_block: The nif block whose mesh data to import.
        :type n_block: C{NiTriBasedGeom}
        :param b_obj: The mesh to which to append the geometry data. If C{None}, a new mesh is created.
        :type b_obj: A Blender object that has mesh data.
        """
        assert (isinstance(n_block, NifFormat.NiTriBasedGeom))

        node_name = n_block.name.decode()
        NifLog.info(f"Importing mesh data for geometry '{node_name}'")
        b_mesh = b_obj.data

        # shortcut for mesh geometry data
        n_tri_data = n_block.data
        if not n_tri_data:
            raise io_scene_niftools.utils.logging.NifError(f"No shape data in {node_name}")

        # create raw mesh from vertices and triangles
        b_mesh.from_pydata(n_tri_data.vertices, [], n_tri_data.get_triangles())
        b_mesh.update()

        # must set faces to smooth before setting custom normals, or the normals bug out!
        is_smooth = True if (n_tri_data.has_normals or n_block.skin_instance) else False
        self.set_face_smooth(b_mesh, is_smooth)

        # store additional data layers
        Vertex.map_uv_layer(b_mesh, n_tri_data)
        Vertex.map_vertex_colors(b_mesh, n_tri_data)
        Vertex.map_normals(b_mesh, n_tri_data)

        self.mesh_prop_processor.process_property_list(n_block, b_obj)

        # import skinning info, for meshes affected by bones
        VertexGroup.import_skin(n_block, b_obj)

        # import morph controller
        if NifOp.props.animation:
            self.morph_anim.import_morph_controller(n_block, b_obj)
    def import_material_color_controller(self, b_material, n_material,
                                         b_channel, n_target_color):
        # find material color controller with matching target color
        for ctrl in n_material.get_controllers():
            if isinstance(ctrl, NifFormat.NiMaterialColorController):
                if ctrl.get_target_color() == n_target_color:
                    n_matcolor_ctrl = ctrl
                    break
        else:
            return
        NifLog.info(
            f"Importing material color controller for target color {n_target_color} into blender channel {b_channel}"
        )

        # import data as curves
        b_mat_action = self.create_action(b_material, "MaterialAction")

        fcurves = self.create_fcurves(b_mat_action, b_channel, range(3),
                                      n_matcolor_ctrl.flags)
        interp = self.get_b_interp_from_n_interp(
            n_matcolor_ctrl.data.data.interpolation)
        for key in n_matcolor_ctrl.data.data.keys:
            self.add_key(fcurves, key.time, key.value.as_list(), interp)
Exemple #27
0
    def export_bsxflags_upb(self, root_block):
        # TODO [object][property] Fixme
        NifLog.info("Checking collision")
        # activate oblivion/Fallout 3 collision and physics
        if bpy.context.scene.niftools_scene.game in ('OBLIVION', 'FALLOUT_3',
                                                     'SKYRIM'):
            b_obj = self.has_collision()
            if b_obj:
                # enable collision
                bsx = block_store.create_block("BSXFlags")
                bsx.name = 'BSX'
                bsx.integer_data = b_obj.niftools.bsxflags
                root_block.add_extra_data(bsx)

                # many Oblivion nifs have a UPB, but export is disabled as
                # they do not seem to affect anything in the game
                if b_obj.niftools.upb:
                    upb = block_store.create_block("NiStringExtraData")
                    upb.name = 'UPB'
                    if b_obj.niftools.upb == '':
                        upb.string_data = 'Mass = 0.000000\r\nEllasticity = 0.300000\r\nFriction = 0.300000\r\nUnyielding = 0\r\nSimulation_Geometry = 2\r\nProxy_Geometry = <None>\r\nUse_Display_Proxy = 0\r\nDisplay_Children = 1\r\nDisable_Collisions = 0\r\nInactive = 0\r\nDisplay_Proxy = <None>\r\n'
                    else:
                        upb.string_data = b_obj.niftools.upb.encode()
                    root_block.add_extra_data(upb)
Exemple #28
0
    def execute(self):
        """Main export function."""

        NifLog.info(f"Exporting {NifOp.props.filepath}")

        # extract directory, base name, extension
        directory = os.path.dirname(NifOp.props.filepath)
        filebase, fileext = os.path.splitext(
            os.path.basename(NifOp.props.filepath))

        if bpy.context.scene.niftools_scene.game == 'NONE':
            raise NifError(
                "You have not selected a game. Please select a game in the scene tab."
            )

        prefix = "x" if bpy.context.scene.niftools_scene.game in (
            'MORROWIND', ) else ""
        self.version, data = scene.get_version_data()
        # todo[anim] - change to KfData, but create_controller() [and maybe more] has to be updated first
        NifData.init(data)

        b_armature = math.get_armature()
        # some scenes may not have an armature, so nothing to do here
        if b_armature:
            math.set_bone_orientation(b_armature.data.niftools.axis_forward,
                                      b_armature.data.niftools.axis_up)

        NifLog.info("Creating keyframe tree")
        kf_root = self.transform_anim.export_kf_root(b_armature)

        # write kf (and xkf if asked)
        ext = ".kf"
        NifLog.info(f"Writing {prefix}{ext} file")

        data.roots = [kf_root]
        data.neosteam = (bpy.context.scene.niftools_scene.game == 'NEOSTEAM')

        # scale correction for the skeleton
        self.apply_scale(data, round(1 / NifOp.props.scale_correction))

        kffile = os.path.join(directory, prefix + filebase + ext)
        with open(kffile, "wb") as stream:
            data.write(stream)

        NifLog.info("Finished successfully")
        return {'FINISHED'}
Exemple #29
0
    def load_kf(file_path):
        """Loads a Kf file from the given path"""
        NifLog.info(f"Loading {file_path}")

        kf_file = NifFormat.Data()

        # open keyframe file for binary reading
        with open(file_path, "rb") as kf_stream:
            # check if nif file is valid
            kf_file.inspect_version_only(kf_stream)
            if kf_file.version >= 0:
                # it is valid, so read the file
                NifLog.info(f"KF file version: {kf_file.version:x}")
                NifLog.info("Reading keyframe file")
                kf_file.read(kf_stream)
            elif kf_file.version == -1:
                raise NifError("Unsupported KF version.")
            else:
                raise NifError("Not a KF file.")

        return kf_file
Exemple #30
0
    def load_nif(file_path):
        """Loads a nif from the given file path"""
        NifLog.info(f"Importing {file_path}")

        data = NifFormat.Data()

        # open file for binary reading
        with open(file_path, "rb") as nif_stream:
            # check if nif file is valid
            data.inspect_version_only(nif_stream)
            if data.version >= 0:
                # it is valid, so read the file
                NifLog.info(f"NIF file version: {data.version:x}")
                NifLog.info("Reading file")
                data.read(nif_stream)
            elif data.version == -1:
                raise NifError("Unsupported NIF version.")
            else:
                raise NifError("Not a NIF file.")

        return data