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
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")
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")
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[:]
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)
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]
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)
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
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