def import_armature(self, n_armature):
        """Scans an armature hierarchy, and returns a whole armature.
        This is done outside the normal node tree scan to allow for positioning
        of the bones before skins are attached."""

        armature_name = self.nif_import.import_name(n_armature)
        b_armature_data = bpy.data.armatures.new(armature_name)
        b_armature_data.draw_type = 'STICK'
        b_armature_obj = create_b_obj(armature_name, b_armature_data)
        b_armature_obj.show_x_ray = True

        # make armature editable and create bones
        bpy.ops.object.mode_set(mode='EDIT', toggle=False)
        for n_child in n_armature.children:
            self.import_bone(n_child, b_armature_data, n_armature)
        self.fix_bone_lengths(b_armature_data)
        bpy.ops.object.mode_set(mode='OBJECT', toggle=False)

        # The armature has been created in editmode,
        # now we are ready to set the bone keyframes.
        if NifOp.props.animation:
            self.nif_import.animationhelper.create_action(
                b_armature_obj, armature_name + "-Anim")
            for bone_name, b_posebone in b_armature_obj.pose.bones.items():
                if bone_name in self.nif_import.dict_blocks:
                    n_block = self.nif_import.dict_blocks[bone_name]
                    self.nif_import.animationhelper.armature_animation.import_bone_animation(
                        n_block, b_armature_obj, bone_name)
                else:
                    NifLog.info(
                        "'%s' can not be found in the NIF - unable to import animation. This likely means your NIF structure duplicated bones"
                        .format(bone_name))
        return b_armature_obj
    def import_texture_extra_shader(self, b_mat, n_texture_prop, extra_datas):
        # extra texture shader slots
        for shader_tex_desc in n_texture_prop.shader_textures:

            if not shader_tex_desc.is_used:
                continue

            # it is used, figure out the slot it is used for
            for extra in extra_datas:
                if extra.integer_data == shader_tex_desc.map_index:
                    shader_name = extra.name
                    break
            else:
                NifLog.warn("No slot for shader texture {0}.".format(
                    shader_tex_desc.texture_data.source.file_name))
                continue
            try:
                extra_shader_index = (
                    self.nif_import.EXTRA_SHADER_TEXTURES.index(shader_name))
            except ValueError:
                # shader_name not in self.EXTRA_SHADER_TEXTURES
                NifLog.warn("No slot for shader texture {0}.".format(
                    shader_tex_desc.texture_data.source.file_name))
                continue

            self.import_shader_by_type(shader_tex_desc, extra_shader_index)
    def import_kf_standalone(self, kf_root, b_armature_obj, bind_data):
        """
        Import a kf animation. Needs a suitable armature in blender scene.
        """

        NifLog.info("Importing KF tree")

        # check that this is an Oblivion style kf file
        if not isinstance(kf_root, NifFormat.NiControllerSequence):
            raise nif_utils.NifError("non-Oblivion .kf import not supported")

        # import text keys
        self.nif_import.animationhelper.import_text_keys(kf_root)
        
        self.nif_import.animationhelper.create_action(b_armature_obj, kf_root.name.decode() )
        # go over all controlled blocks (NiKeyframeController)
        for controlledblock in kf_root.controlled_blocks:
            # get bone name
            bone_name = armature.get_bone_name_for_blender( controlledblock.target_name )
            # import bone priority
            b_bone = b_armature_obj.data.bones[bone_name]
            b_bone.niftools_bone.bonepriority = controlledblock.priority
            # import animation
            if bone_name in bind_data:
                niBone_bind_scale, niBone_bind_rot_inv, niBone_bind_trans = bind_data[bone_name]
                kfc = controlledblock.controller
                if kfc:
                    self.import_keyframe_controller(kfc, b_armature_obj, bone_name, niBone_bind_scale, niBone_bind_rot_inv, niBone_bind_trans)
    def get_extend_from_flags(self, flags):
        if flags & 6 == 4: # 0b100
            return "CONST"
        elif flags & 6 == 0: # 0b000
            return "CYCLIC"

        NifLog.warn("Unsupported cycle mode in nif, using clamped.")
        return "CONST"
 def get_b_interp_from_n_interp(self, n_ipol):
     if n_ipol in (NifFormat.KeyType.LINEAR_KEY, NifFormat.KeyType.XYZ_ROTATION_KEY):
         return "LINEAR"
     elif n_ipol == NifFormat.KeyType.QUADRATIC_KEY:
         return "BEZIER"
     elif n_ipol == 0:
         # guessing, not documented in nif.xml
         return "CONSTANT"
     NifLog.warn("Unsupported interpolation mode ({0}) in nif, using quadratic/bezier.".format(n_ipol))
     return "BEZIER"
 def import_object_animation(self, n_block, b_obj):
     """
     Loads an animation attached to a nif block (non-skeletal).
     Becomes the object level animation of the blender object.
     """
     NifLog.debug('Importing animation for object %s'.format(b_obj.name))
     
     kfc = nif_utils.find_controller(n_block, NifFormat.NiKeyframeController)
     if kfc:
         self.nif_import.animationhelper.create_action(b_obj, b_obj.name+"-Anim" )
         self.import_keyframe_controller(kfc, b_obj)
    def import_morph_controller(self, n_node, b_obj, v_map):
        """Import NiGeomMorpherController as shape keys for blender object."""
        
        morphCtrl = nif_utils.find_controller(n_node, NifFormat.NiGeomMorpherController)
        if morphCtrl:
            b_mesh = b_obj.data
            morphData = morphCtrl.data
            if morphData.num_morphs:
                b_obj_action = self.nif_import.animationhelper.create_action( b_obj, b_obj.name + "-Morphs")
                fps = bpy.context.scene.render.fps
                # 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(keyname)
                
                # get base vectors and import all morphs
                baseverts = morphData.morphs[0].vectors
                
                for idxMorph in range(1, morphData.num_morphs):
                    # get name for key
                    keyname = morphData.morphs[idxMorph].frame_name.decode()
                    if not keyname:
                        keyname = 'Key %i' % idxMorph
                    NifLog.info("Inserting key '{0}'".format(keyname))
                    # get vectors
                    morphverts = morphData.morphs[idxMorph].vectors
                    self.morph_mesh(b_mesh, baseverts, morphverts, v_map)
                    shape_key = b_obj.shape_key_add(keyname, from_mix=False)

                    # first find the keys
                    # older versions store keys in the morphData
                    morphdata = morphData.morphs[idxMorph]
                    # newer versions store keys in the controller
                    if not morphdata.keys:
                        try:
                            if morphCtrl.interpolators:
                                morphdata = morphCtrl.interpolators[idxMorph].data.data
                            elif morphCtrl.interpolator_weights:
                                morphdata = morphCtrl.interpolator_weights[idxMorph].interpolator.data.data
                        except:
                            NifLog.info("Unsupported interpolator '{0}'".format( type(morphCtrl.interpolator_weights[idxMorph].interpolator) ))
                            continue
                    # TODO [anim] can we create the fcurve manually - does not seem to work here?
                    # as b_obj.data.shape_keys.animation_data is read-only
                    
                    # FYI shape_key = b_mesh.shape_keys.key_blocks[-1]
                    # set keyframes
                    for key in morphdata.keys:
                        shape_key.value = key.value
                        shape_key.keyframe_insert(data_path="value", frame=round(key.time * fps))
 def import_material_alpha_controller(self, b_material, n_material):
     # find alpha controller
     n_alphactrl = nif_utils.find_controller(n_material, NifFormat.NiAlphaController)
     if not(n_alphactrl and n_alphactrl.data):
         return
     NifLog.info("Importing alpha controller")
     
     b_mat_action = self.nif_import.animationhelper.create_action( b_material, "MaterialAction")
     fcurves = self.nif_import.animationhelper.create_fcurves(b_mat_action, "alpha", (0,), n_alphactrl.flags)
     interp = self.nif_import.animationhelper.get_b_interp_from_n_interp( n_alphactrl.data.data.interpolation)
     for key in n_alphactrl.data.data.keys:
         self.nif_import.animationhelper.add_key(fcurves, key.time, (key.value, ), interp)
    def set_alpha(self, b_mat, ShaderProperty, n_alpha_prop):
        NifLog.debug("Alpha prop detected")
        b_mat.use_transparency = True
        if hasattr(ShaderProperty, 'alpha'):
            b_mat.alpha = (1 - ShaderProperty.alpha)
        else:
            b_mat.alpha = 0
        b_mat.transparency_method = 'Z_TRANSPARENCY'  # enable z-buffered transparency
        b_mat.offset_z = n_alpha_prop.threshold  # Transparency threshold
        b_mat.niftools_alpha.alphaflag = n_alpha_prop.flags

        return b_mat
    def get_n_interp_from_b_interp(self, b_ipol):
        if b_ipol == "LINEAR":
            return NifFormat.KeyType.LINEAR_KEY
        elif b_ipol == "BEZIER":
            return NifFormat.KeyType.QUADRATIC_KEY
        elif b_ipol == "CONSTANT":
            return NifFormat.KeyType.CONST_KEY

        NifLog.warn(
            "Unsupported interpolation mode ({0}) in blend, using quadratic/bezier."
            .format(b_ipol))
        return NifFormat.KeyType.QUADRATIC_KEY
Beispiel #11
0
    def get_n_apply_mode_from_b_blend_type(self, b_blend_type):
        if b_blend_type == "LIGHTEN":
            return NifFormat.ApplyMode.APPLY_HILIGHT
        elif b_blend_type == "MULTIPLY":
            return NifFormat.ApplyMode.APPLY_HILIGHT2
        elif b_blend_type == "MIX":
            return NifFormat.ApplyMode.APPLY_MODULATE

        NifLog.warn(
            "Unsupported blend type ({0}) in material, using apply mode APPLY_MODULATE"
            .format(b_blend_type))
        return NifFormat.ApplyMode.APPLY_MODULATE
    def export_tex_desc(self, texdesc=None, uvlayers=None, b_mat_texslot=None):
        """Helper function for export_texturing_property to export each texture
        slot."""
        try:
            texdesc.uv_set = uvlayers.index(
                b_mat_texslot.uv_layer) if b_mat_texslot.uv_layer else 0
        except ValueError:  # mtex.uv_layer not in uvlayers list
            NifLog.warn(
                "Bad uv layer name '{0}' in texture '{1}'. Using first uv layer"
                .format(b_mat_texslot.uv_layer, b_mat_texslot.texture.name))
            texdesc.uv_set = 0  # assume 0 is active layer

        texdesc.source = self.export_source_texture(b_mat_texslot.texture)
 def import_bone_animation(self, n_block, b_armature_obj, bone_name):
     """
     Loads an animation attached to a nif block (skeletal).
     Becomes the pose bone level animation of the blender object.
     """
     NifLog.debug('Importing animation for bone %s'.format(bone_name))
     
     kfc = nif_utils.find_controller(n_block, NifFormat.NiKeyframeController)
     if kfc:
         bone_bm = nif_utils.import_matrix(n_block) # base pose
         niBone_bind_scale, niBone_bind_rot, niBone_bind_trans = nif_utils.decompose_srt(bone_bm)
         niBone_bind_rot_inv = niBone_bind_rot.to_4x4().inverted()
         self.import_keyframe_controller(kfc, b_armature_obj, bone_name, niBone_bind_scale, niBone_bind_rot_inv, niBone_bind_trans)
    def import_object_vis_controller(self, n_node, b_obj ):
        """Import vis controller for blender object."""
        
        n_vis_ctrl = nif_utils.find_controller(n_node, NifFormat.NiVisController)
        if not(n_vis_ctrl and n_vis_ctrl.data):
            return
        NifLog.info("Importing vis controller")
        
        b_obj_action = self.nif_import.animationhelper.create_action( b_obj, b_obj.name + "-Anim")

        fcurves = self.nif_import.animationhelper.create_fcurves(b_obj_action, "hide", (0,), n_vis_ctrl.flags)
        for key in n_vis_ctrl.data.keys:
            self.nif_import.animationhelper.add_key(fcurves, key.time, (key.value, ), "CONSTANT")
Beispiel #15
0
    def import_texture_source(self, source):
        """Convert a NiSourceTexture block, or simply a path string,
        to a Blender Texture object, return the Texture object and
        stores it in the self.nif_import.dict_textures dictionary to avoid future
        duplicate imports.
        """
        # if the source block is not linked then return None
        if not source:
            return None

        # calculate the texture hash key
        texture_hash = self.get_texture_hash(source)

        try:
            # look up the texture in the dictionary of imported textures
            # and return it if found
            return self.nif_import.dict_textures[texture_hash]
        except KeyError:
            pass

        b_image = None

        if (isinstance(source, NifFormat.NiSourceTexture)
                and not source.use_external):
            fn, b_image = self.import_embedded_texture_source(source)
        else:
            fn, b_image = self.import_source(source)

        # create a stub image if the image could not be loaded

        b_text_name = os.path.basename(fn)
        if not b_image:
            NifLog.warn(
                "Texture '{0}' not found or not supported and no alternate available"
                .format(fn))
            b_image = bpy.data.images.new(name=b_text_name,
                                          width=1,
                                          height=1,
                                          alpha=False)
            b_image.filepath = fn

        # create a texture
        b_texture = bpy.data.textures.new(name=b_text_name, type='IMAGE')
        b_texture.image = b_image
        b_texture.use_interpolation = True
        b_texture.use_mipmap = True

        # save texture to avoid duplicate imports, and return it
        self.nif_import.dict_textures[texture_hash] = b_texture
        return b_texture
    def import_shader_by_type(self, b_mat, shader_tex_desc,
                              extra_shader_index):
        if extra_shader_index == 0:
            # EnvironmentMapIndex
            if shader_tex_desc.texture_data.source.file_name.lower(
            ).startswith("rrt_engine_env_map"):
                # sid meier's railroads: env map generated by engine
                # we can skip this
                NifLog.info(
                    "Skipping environment map texture. Env Map is generated by Engine"
                )
            envTexDesc = shader_tex_desc.texture_data
            self.has_envtex = True
            self.env_map = self.import_image_texture(b_mat, envTexDesc)

        elif extra_shader_index == 1:
            # NormalMapIndex
            bumpTexDesc = shader_tex_desc.texture_data
            self.has_bumptex = True
            self.bump_map = self.import_image_texture(b_mat, bumpTexDesc)

        elif extra_shader_index == 2:
            # SpecularIntensityIndex
            glossTexDesc = shader_tex_desc.texture_data
            self.has_glosstex = True
            self.gloss_map = self.import_image_texture(b_mat, glossTexDesc)

        elif extra_shader_index == 3:
            # EnvironmentIntensityIndex (this is reflection)
            refTexDesc = shader_tex_desc.texture_data
            self.has_reftex = True
            self.reflection_map = self.reflection_map = self.import_image_texture(
                b_mat, refTexDesc)

        elif extra_shader_index == 4:
            # LightCubeMapIndex
            if shader_tex_desc.texture_data.source.file_name.lower(
            ).startswith("rrt_cube_light_map"):
                # sid meier's railroads: light map generated by engine
                # we can skip this
                NifLog.info("Ignoring Env Map as generated by Engine")
            NifLog.warn("Skipping light cube texture.")

        elif extra_shader_index == 5:
            # ShadowTextureIndex
            NifLog.warn("Skipping shadow texture.")

        else:
            NifLog.warn("Unknown texture type found in extra_shader_index")
Beispiel #17
0
    def __init__(self, operator):
        """Common initialization functions for executing the import/export operators: """

        NifOp.init(operator)

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

        NifLog.info(
            "Executing - Niftools : Blender Nif Plugin v{0} (running on Blender {1}, PyFFI {2})"
            .format(niftools_ver, bpy.app.version_string, pyffi.__version__))

        # find and store this list now of selected objects as creating new objects adds them to the selection list
        self.selected_objects = bpy.context.selected_objects[:]
Beispiel #18
0
    def import_bhk_shape(self, bhkshape):
        """Imports any supported collision shape as list of blender meshes."""

        if self.nif_import.data._user_version_value_._value == 12:
            if self.nif_import.data._user_version_2_value_._value == 83:
                self.HAVOK_SCALE = self.nif_import.HAVOK_SCALE * 10
            else:
                self.HAVOK_SCALE = self.nif_import.HAVOK_SCALE

        if isinstance(bhkshape, NifFormat.bhkTransformShape):
            return self.import_bhktransform(bhkshape)

        elif isinstance(bhkshape, NifFormat.bhkRigidBody):
            return self.import_bhkridgidbody(bhkshape)

        elif isinstance(bhkshape, NifFormat.bhkBoxShape):
            return self.import_bhkbox_shape(bhkshape)

        elif isinstance(bhkshape, NifFormat.bhkSphereShape):
            return self.import_bhksphere_shape(bhkshape)

        elif isinstance(bhkshape, NifFormat.bhkCapsuleShape):
            return self.import_bhkcapsule_shape(bhkshape)

        elif isinstance(bhkshape, NifFormat.bhkConvexVerticesShape):
            return self.import_bhkconvex_vertices_shape(bhkshape)

        elif isinstance(bhkshape, NifFormat.bhkPackedNiTriStripsShape):
            return self.import_bhkpackednitristrips_shape(bhkshape)

        elif isinstance(bhkshape, NifFormat.bhkNiTriStripsShape):
            self.havok_mat = bhkshape.material
            return reduce(operator.add,
                          (self.import_bhk_shape(strips)
                           for strips in bhkshape.strips_data))

        elif isinstance(bhkshape, NifFormat.NiTriStripsData):
            return self.import_nitristrips(bhkshape)

        elif isinstance(bhkshape, NifFormat.bhkMoppBvTreeShape):
            return self.import_bhk_shape(bhkshape.shape)

        elif isinstance(bhkshape, NifFormat.bhkListShape):
            return reduce(operator.add, ( self.import_bhk_shape(subshape)
                                          for subshape in bhkshape.sub_shapes ))

        NifLog.warn("Unsupported bhk shape {0}".format(bhkshape.__class__.__name__))
        return []
 def get_b_blend_type_from_n_apply_mode(self, n_apply_mode):
     # TODO: - Check out n_apply_modes
     if n_apply_mode == NifFormat.ApplyMode.APPLY_MODULATE:
         return "MIX"
     elif n_apply_mode == NifFormat.ApplyMode.APPLY_REPLACE:
         return "COLOR"
     elif n_apply_mode == NifFormat.ApplyMode.APPLY_DECAL:
         return "OVERLAY"
     elif n_apply_mode == NifFormat.ApplyMode.APPLY_HILIGHT:
         return "LIGHTEN"
     elif n_apply_mode == NifFormat.ApplyMode.APPLY_HILIGHT2:  # used by Oblivion for parallax
         return "MULTIPLY"
     else:
         NifLog.warn(
             "Unknown apply mode (%i) in material, using blend type 'MIX'".
             format(n_apply_mode))
         return "MIX"
 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("Importing material color controller for target color {0} into blender channel {0}".format(n_target_color, b_channel))
     # import data as curves
     b_mat_action = self.nif_import.animationhelper.create_action( b_material, "MaterialAction")
     
     fcurves = self.nif_import.animationhelper.create_fcurves(b_mat_action, b_channel, range(3), n_matcolor_ctrl.flags)
     interp = self.nif_import.animationhelper.get_b_interp_from_n_interp( n_matcolor_ctrl.data.data.interpolation)
     for key in n_matcolor_ctrl.data.data.keys:
         self.nif_import.animationhelper.add_key(fcurves, key.time, key.value.as_list(), interp)
 def populate_bone_tree(self, skelroot):
     """Add all of skelroot's bones to its dict_armatures list.
     """
     for bone in skelroot.tree():
         if bone is skelroot:
             continue
         if not isinstance(bone, NifFormat.NiNode):
             continue
         if isinstance(bone, NifFormat.NiLODNode):
             # LOD nodes are never bones
             continue
         if self.nif_import.is_grouping_node(bone):
             continue
         if bone not in self.dict_armatures[skelroot]:
             self.dict_armatures[skelroot].append(bone)
             NifLog.debug(
                 "'{0}' marked as extra bone of armature '{1}'".format(
                     bone.name, skelroot.name))
    def export_source_texture(self, texture=None, filename=None):
        """Export a NiSourceTexture.

        :param texture: The texture object in blender to be exported.
        :param filename: The full or relative path to the texture file
            (this argument is used when exporting NiFlipControllers
            and when exporting default shader slots that have no use in
            being imported into Blender).
        :return: The exported NiSourceTexture block.
        """

        # create NiSourceTexture
        srctex = NifFormat.NiSourceTexture()
        srctex.use_external = True
        if not filename is None:
            # preset filename
            srctex.file_name = filename
        elif not texture is None:
            srctex.file_name = self.export_texture_filename(texture)
        else:
            # this probably should not happen
            NifLog.warn(
                "Exporting source texture without texture or filename (bug?).")

        # fill in default values (TODO: can we use 6 for everything?)
        if bpy.context.scene.niftools_scene.nif_version >= 0x0A000100:
            srctex.pixel_layout = 6
        else:
            srctex.pixel_layout = 5
        srctex.use_mipmaps = 1
        srctex.alpha_format = 3
        srctex.unknown_byte = 1

        # search for duplicate
        for block in self.nif_export.nif_export.dict_blocks:
            if isinstance(block, NifFormat.NiSourceTexture) and block.get_hash(
            ) == srctex.get_hash():
                return block

        # no identical source texture found, so use and register
        # the new one
        return self.nif_export.nif_export.objecthelper.register_block(
            srctex, texture)
 def set_frames_per_second(self, 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 uvdata in root.tree(block_type=NifFormat.NiUVData):
             for uvgroup in uvdata.uv_groups:
                 key_times.extend(key.time for key in uvgroup.keys)
     fps = self.fps
     # not animated, return a reasonable default
     if not key_times:
         return
     # calculate FPS
     key_times = sorted(set(key_times))
     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("Animation estimated at %i frames per second." % fps)
     self.fps = fps
     bpy.context.scene.render.fps = fps
     bpy.context.scene.frame_set(0)
    def export_collision(self, b_obj, parent_block):
        """Main function for adding collision object b_obj to a node."""
        if NifOp.props.game == 'MORROWIND':
            if b_obj.game.collision_bounds_type != 'TRIANGLE_MESH':
                raise nif_utils.NifError(
                    "Morrowind only supports Triangle Mesh collisions.")
            node = self.objecthelper.create_block("RootCollisionNode", b_obj)
            parent_block.add_child(node)
            node.flags = 0x0003  # default
            self.objecthelper.set_object_matrix(b_obj, node)
            for child in b_obj.children:
                self.objecthelper.export_node(child, node, None)

        elif NifOp.props.game in ('OBLIVION', 'FALLOUT_3', 'SKYRIM'):

            nodes = [parent_block]
            nodes.extend([
                block for block in parent_block.children
                if block.name[:14] == 'collisiondummy'
            ])
            for node in nodes:
                try:
                    self.bhkshapehelper.export_collision_helper(b_obj, node)
                    break
                except ValueError:  # adding collision failed
                    continue
            else:  # all nodes failed so add new one
                node = self.objecthelper.create_ninode(b_obj)
                node.set_transform(self.IDENTITY44)
                node.name = 'collisiondummy%i' % parent_block.num_children
                if b_obj.niftools.objectflags != 0:
                    node_flag_hex = hex(b_obj.niftools.objectflags)
                else:
                    node_flag_hex = 0x000E  # default
                node.flags = node_flag_hex
                parent_block.add_child(node)
                self.bhkshapehelper.export_collision_helper(b_obj, node)

        else:
            NifLog.warn(
                "Only Morrowind, Oblivion, and Fallout 3 collisions are supported, skipped collision object '{0}'"
                .format(b_obj.name))
 def complete_bone_tree(self, bone, skelroot):
     """Make sure that the complete hierarchy from skelroot down to bone is marked in dict_armatures.
     """
     # we must already have marked this one as a bone
     assert skelroot in self.dict_armatures  # debug
     assert bone in self.dict_armatures[skelroot]  # debug
     # get the node parent, this should be marked as an armature or as a bone
     boneparent = bone._parent
     if boneparent != skelroot:
         # parent is not the skeleton root
         if boneparent not in self.dict_armatures[skelroot]:
             # neither is it marked as a bone: so mark the parent as a bone
             self.dict_armatures[skelroot].append(boneparent)
             # store the coordinates for realignement autodetection
             NifLog.debug("'{0}' is a bone of armature '{1}'".format(
                 boneparent.name, skelroot.name))
         # now the parent is marked as a bone
         # recursion: complete the bone tree,
         # this time starting from the parent bone
         self.complete_bone_tree(boneparent, skelroot)
Beispiel #26
0
def decompose_srt(matrix):
    """Decompose Blender transform matrix as a scale, rotation matrix, and
    translation vector."""

    # get matrix components
    trans_vec, rot_quat, scale_vec = matrix.decompose()

    #obtain a combined scale and rotation matrix to test determinate
    rotmat = rot_quat.to_matrix()
    scalemat = mathutils.Matrix(
        ((scale_vec[0], 0.0, 0.0), (0.0, scale_vec[1], 0.0), (0.0, 0.0,
                                                              scale_vec[2])))
    scale_rot = scalemat * rotmat

    # and fix their sign
    if (scale_rot.determinant() < 0): scale_vec.negate()
    # only uniform scaling
    # allow rather large error to accomodate some nifs
    if abs(scale_vec[0] - scale_vec[1]) + abs(scale_vec[1] -
                                              scale_vec[2]) > 0.02:
        NifLog.warn("Non-uniform scaling not supported." +
                    " Workaround: apply size and rotation (CTRL-A).")
    return [scale_vec[0], rotmat, trans_vec]
Beispiel #27
0
    def import_embedded_texture_source(self, source):
        fn = None

        # find a file name (but avoid overwriting)
        n = 0
        while True:
            fn = "image%03i.dds" % n
            tex = os.path.join(os.path.dirname(NifOp.props.filepath), fn)
            if not os.path.exists(tex):
                break
            n += 1
        if self.nif_import.IMPORT_EXPORTEMBEDDEDTEXTURES:
            # save embedded texture as dds file
            stream = open(tex, "wb")
            try:
                NifLog.info("Saving embedded texture as {0}".format(tex))
                source.pixel_data.save_as_dds(stream)
            except ValueError:
                # value error means that the pixel format is not supported
                b_image = None
            else:
                # saving dds succeeded so load the file
                b_image = bpy.ops.image.open(tex)
                # Blender will return an image object even if the
                # file format is not supported,
                # so to check if the image is actually loaded an error
                # is forced via "b_image.size"
                try:
                    b_image.size
                except:  # RuntimeError: couldn't load image data in Blender
                    b_image = None  # not supported, delete image object
            finally:
                stream.close()
        else:
            b_image = None
        return [fn, b_image]
 def import_material_uv_controller(self, b_material, n_geom):
     """Import UV controller data."""
     # search for the block
     n_ctrl = nif_utils.find_controller(n_geom, NifFormat.NiUVController)
     if not(n_ctrl and n_ctrl.data):
         return
     NifLog.info("Importing UV controller")
     
     b_mat_action = self.nif_import.animationhelper.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.nif_import.animationhelper.get_b_interp_from_n_interp( n_uvgroup.interpolation )
             #in blender, UV offset is stored per 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.nif_import.animationhelper.create_fcurves(b_mat_action, "texture_slots["+str(i)+"]."+data_path, (array_ind,), n_ctrl.flags )
                     for key in n_uvgroup.keys:
                         if "offset" in data_path:
                             self.nif_import.animationhelper.add_key(fcurves, key.time, (-key.value, ), interp)
                         else:
                             self.nif_import.animationhelper.add_key(fcurves, key.time, (key.value, ), interp)
Beispiel #29
0
    def load_egm(file_path):
        """Loads an egm file from the given path"""
        NifLog.info("Loading {0}".format(file_path))

        egm_file = EgmFormat.Data()

        # open keyframe file for binary reading
        with open(file_path, "rb") as egm_stream:
            # check if nif file is valid
            egm_file.inspect_quick(egm_stream)
            if egm_file.version >= 0:
                # it is valid, so read the file
                NifLog.info("EGM file version: {0}".format(
                    egm_file.version, "x"))
                NifLog.info("Reading FaceGen egm file")
                egm_file.read(egm_stream)
            elif egm_file.version == -1:
                raise NifError("Unsupported EGM version.")
            else:
                raise NifError("Not a EGM file.")

        return egm_file
Beispiel #30
0
    def load_kf(file_path):
        """Loads a Kf file from the given path"""
        NifLog.info("Loading {0}".format(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("KF file version: {0}".format(
                    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