# This importer is designed to be flexible with the use of regular expressions. # Enabling this importer to import a wider range of XSI formats might just require # changing a few of the regular expressions. # Here are the known limitations of this importer so far: # All frames should have a unique name. (In order to sync envelopes and animations with objects properly.) (Currently not supported, though.) # The parser can not read XSI files that do not have the opening brace on the same line as the section. Works on all stock XSI's I've tested on. # Note: Blender objects are name sorted, so the order of objects in your import may differ, # but they will retain their parent-child hierarchy. bl_info = { "name": "BZ2 XSI Model Format (.xsi)", "author": "The Vearidons (Stroket@hotmail.com)", "version": (1, 0, 2), "blender:": (2, 67, 0), "location": "File > Import > BZ2XSI (.xsi)", "description": "Import a BZ2 XSI model.", "warning": "Accept Jesus Christ as your personal saviour or burn in hell forever.", "wiki_url": "http://www.meatspin.cc/", "tracker_url": "http://www.bz2maps.us/phpBB/viewtopic.php?f=50&t=4395/", "category": "Import"} # os.path texture filename stuff. # time for Import Time info. import os.path, re, time try: # Executed if this is being ran by blender. import bpy from mathutils import Matrix, Vector, Color from bpy.props import StringProperty, BoolProperty from bpy_extras.io_utils import axis_conversion InBlender = True except: # Executed if being ran by python alone. # This is primarily for debugging parser data. print("Doing non-blender test run.") InBlender = False # Prefixes, postfixes, and other. RePrefix = r"(?i)\s*" ReSectionPrefix = RePrefix + r"(?:SI_)?" ReNameChars = r"[\w\.]" ReOpenBrace = r"\s*{\s*[\r\n]+" ReCloseBrace = r"\s*}" ReFloatOrInt = r"[-+]?\b[0-9e\-\+]*\.?[0-9e\-\+]+\b" ReFloat = r"[-+]?\b[0-9e\-\+]*\.[0-9e\-\+]+\b" ReInt = r"\b\d+\b" # Float/Int ReM_FloatOrInt = re.compile(ReFloatOrInt) ReM_Float = re.compile(ReFloat) ReM_Int = re.compile(ReInt) # Other ReM_StrContent = re.compile(r"\"[^\"\r\n]+\"") ReM_FileOnly = re.compile(r"[^\\/:*?\"<>|\r\n]+$") # Header ReM_SI_CoordinateSystem = re.compile(ReSectionPrefix + r"CoordinateSystem\s+(%s*)%s" % (ReNameChars, ReOpenBrace)) ReM_SI_Angle = re.compile(ReSectionPrefix + r"Angle%s" % ReOpenBrace) ReM_SI_Camera = re.compile(ReSectionPrefix + r"Camera(?:\s+(%s*))?%s" % (ReNameChars, ReOpenBrace)) ReM_SI_Ambience = re.compile(ReSectionPrefix + r"Ambience%s" % ReOpenBrace) ReM_SI_Light = re.compile(ReSectionPrefix + r"Light(?:\s+(%s*))?%s" % (ReNameChars, ReOpenBrace)) ReM_SI_Fog = re.compile(ReSectionPrefix + r"Fog%s" % ReOpenBrace) # Frame ReM_Frame = re.compile(ReSectionPrefix + r"Frame\s+(?:frm-)*(%s+)%s" % (ReNameChars, ReOpenBrace)) ReM_FrameTransformMatrix = re.compile(ReSectionPrefix + r"FrameTransformMatrix" + ReOpenBrace) ReM_SI_FrameBasePoseMatrix = re.compile(ReSectionPrefix + r"FrameBasePoseMatrix" + ReOpenBrace) ReM_Mesh = re.compile(ReSectionPrefix + r"Mesh(?:\s+(%s*))?%s" % (ReNameChars, ReOpenBrace)) # Frame > Mesh ReM_MeshMaterialList = re.compile(ReSectionPrefix + r"MeshMaterialList" + ReOpenBrace) ReM_SI_MeshNormals = re.compile(ReSectionPrefix + r"MeshNormals" + ReOpenBrace) ReM_SI_MeshTextureCoords = re.compile(ReSectionPrefix + r"MeshTextureCoords" + ReOpenBrace) ReM_SI_MeshVertexColors = re.compile(ReSectionPrefix + r"MeshVertexColors" + ReOpenBrace) # Frame > Mesh > MeshMaterialList ReM_SI_Material = re.compile(ReSectionPrefix + r"Material" + ReOpenBrace) # Frame > Mesh > MeshMaterialList > SI_Material ReM_SI_Texture2D = re.compile(ReSectionPrefix + r"Texture(?:2D)?(?:Filename)?" + ReOpenBrace) # AnimationSet ReM_AnimationSet = re.compile(ReSectionPrefix + r"AnimationSet" + ReOpenBrace) ReM_Animation = re.compile(ReSectionPrefix + r"Animation\s+(?:\s*anim-)?(%s+)%s" % (ReNameChars, ReOpenBrace)) ReM_AnimFrm = re.compile(ReSectionPrefix + r"{(?:\s*frm-)(%s+)\s*}" % ReNameChars) ReM_SI_AnimationKey = re.compile(ReSectionPrefix + "AnimationKey" + ReOpenBrace) # SI_EnvelopeList ReM_SI_EnvelopeList = re.compile(ReSectionPrefix + r"EnvelopeList" + ReOpenBrace) ReM_SI_Envelope = re.compile(ReSectionPrefix + r"Envelope" + ReOpenBrace) # This will be the most called function during the program, # Optimizing it may increase preformance significantly. # This is called for every line that isn't an opening/closing brace. def GetDataTypes(Str): Types = [] Values = [] Total = re.findall(ReM_FloatOrInt, Str) for Type in Total: if not "." in Type: Types += ["I"] Values += [int(Type)] else: Types += ["F"] Values += [float(Type)] return Types, Values # Used less commonly, when expecting lines like in SI_Texture2D, Animation, or SI_Envelope. def GetDataStr(Str): Data = re.findall(ReM_StrContent, Str) if Data: return Data[0][1:-1] return "" # XSI Frame. # One to unlimited instances exist per XSI_Importer. class XSIFrm: def __init__(self, name = "Obj", parent = None): # Basic self.parent = parent self.name = name # Matrix (list[4][4]) self.matrix = [] # Mesh (XSIMesh or None) self.Mesh = None # Animation keys. (XSIAnimationKey list.) self.Anim = [] # How do we know if this frame is a bone? # It will be referenced in the # second string of SI_Envelope. self.isBone = False # Created real blender object # is assigned to this later on. self.Obj = None # Autodetermined from name: UnderScr = 0 flags = "" for fl in self.name: if UnderScr == 2: flags += fl else: if fl == "_": UnderScr += 1 else: UnderScr = 0 self.isHardpoint = (self.name[0:3].lower() == "hp_") self.isCollision = ("c" in flags) self.isHidden = ("h" in flags) #~ self.is2Sided = ("2" in flags) #~ self.isGlowing = ("g" in flags) def GetParentCount(self): Count = 0 Frm = self while Frm.parent: Frm = Frm.parent Count += 1 return Count # XSI Mesh. # One or zero instances exist per XSIFrm. class XSIMesh: def __init__(self, name = ""): # Basic self.name = name # Mesh self.verts = [] self.faces = [] # Mesh Materials (faces) self.matInd = [] self.MatList = [] self.matCount = 0 # Mesh Normals #~ self.norm_coord = [] #~ self.norm_poly = [] # UV Mapping self.uvmap_coord = [] self.uvmap_poly = [] # Vertex Colors self.vcol_coord = [] self.vcol_poly = [] # Returns a new vertex list based # on vertice references in polygons. def GetFullVertList(verts, faces): NewVerts = [] for face in faces: for faceVert in face: NewVerts += [verts[faceVert]] return NewVerts # XSI SI_Material. # One to unlimited instances may exist as a list item in XSIMaterialList. class XSIMat: def __init__(self, textureName = "", diffuseRGBA = (1.0, 1.0, 1.0, 1.0), specularityHardness = 1.0, specularityRGB = (1.0, 1.0, 1.0)): self.textureName = textureName self.textureBaseName = os.path.basename(textureName) self.diffuseRGBA = diffuseRGBA self.specularityHardness = specularityHardness self.specularityRGB = specularityRGB self.localIndex = -1 self.index = -1 def __eq__(self, other): if (self.diffuseRGBA == other.diffuseRGBA and self.specularityHardness == other.specularityHardness and self.specularityRGB == other.specularityRGB and self.specularityRGB == other.specularityRGB and self.textureBaseName == other.textureBaseName): return True def __ne__(self, other): # Not sure if this is correct or pythonic, seems to work, though. return not self.__eq__(other) def __str__(self): return "MAT %d, Txtr=%s DiffRGBA=(%.2f, %.2f, %.2f, %.2f), SpecRGBH=(%.2f, %.2f, %.2f, %.2f)" % ( self.index, ("\""+self.textureBaseName+"\"")[0:16].ljust(16), self.diffuseRGBA[0], self.diffuseRGBA[1], self.diffuseRGBA[2], self.diffuseRGBA[3], self.specularityRGB[0], self.specularityRGB[1], self.specularityRGB[2], self.specularityHardness) # XSI MeshMaterialList. # One instance exist per XSI_Importer. class XSIMaterialList: def __init__(self): self.Material = [] def NewMaterial(self, NMat, Delete = True): # Check if an XSIMat identical to NMat already exists. # If it does, return that one, if not, add NMat and return it. index = 0 for Mat in self.Material: index += 1 if Mat == NMat: if Delete: del NMat return Mat self.Material += [NMat] NMat.index = index return NMat # XSI SI_Envelope. # One to unlimited instances exist in XSI_Importer as a list. class XSIEnvelope: def __init__(self, Frm = None, FrmBone = None): # XSIFrm self.Frm = Frm self.FrmBone = FrmBone # Vert # and Vert Weight self.vertWeight = [] def __str__(self): return "VertWeights=%s Bone=%s Object=%s" % ( str(len(self.vertWeight)).ljust(6), ("\""+self.FrmBone.name+"\"").ljust(22), ("\""+self.Frm.name+"\"") ) # XSI SI_AnimationKey. class XSIAnimationKey: def __init__(self, animType): # 0 = quaternion rotations # 1 = scaling # 2 = translation # 3 = Euler rotations self.animType = animType self.keyFrame = [] # Processes the XSI one line at a time. class XSI_Importer: def __init__(self, ImportFilePath, ImportHPMesh = False, TxtrRemovePath = True, OneMatPerTexture = False, EmulateFlags = True): # Options that are or will be settable in the import window: # Import HP's with their Mesh rather than as \"EMPTY\" objects. self.ImportHPMesh = ImportHPMesh # Remove file path from textureName. self.TxtrRemovePath = TxtrRemovePath # If multiple materials have the same texture, merge them into one material. self.OneMatPerTexture = OneMatPerTexture # Works for any combination of: *__h, *__c # Todo: *__2 (two-sided) self.EmulateFlags = EmulateFlags # Import animations? (Not yet supported.) self.importAnims = False # Default material settings self.Def_Diffuse = [0.7, 0.7, 0.7, 1.0] self.Def_Spec = [0.0, 0.0, 0.0] self.Def_Hardness = 0.0 # Start print("Importing BZ2 XSI: %s" % ImportFilePath) self.ImportFilePath = ImportFilePath self.File = open(ImportFilePath, "r") self.Frm = [None] self.Parse() self.File.close() if InBlender: bpy.context.scene.update() def Parse(self): # Debugging shit Timer = time.clock() Indnt = "| " LineNumber = 0 DebugOnNewSection = False # Determines the current brace we're in. InBrace = 0 InSection = ["N/A"] InSectionName = [""] IgnoreUntilBrace = 0 CurrentFrame = [None] # THA FROIMS, MOITE. Frm = [None] FrmDict = {} # Contains all materials we will use. MatList = XSIMaterialList() # Temporarily contains all materials in a MeshMaterialList. MeshMats = [] # Envelopes Envelopes = [] # Used for processing actual vertices/faces, etc... DataType = [] Data = [] DataIndex = 0 for ln in self.File: LineNumber += 1 if "{" in ln and not "}" in ln: # This line contains an opening brace; a new section. InBrace += 1 DataIndex = 0 PolyType = 0 SectionType, SectionName = self.SectionType(ln) InSection += [SectionType] InSectionName += [SectionName] # Debug if DebugOnNewSection: print("%s:%d:\tIN SEC %s%s"%(self.ImportFilePath, LineNumber, str(" ")*InBrace, SectionType+" "+SectionName)) # Set current frame to operate on. (Defined as last CurrentFrame, CurrentFrame[-1].) if SectionType == "Frame": Frm += [XSIFrm(SectionName, CurrentFrame[-1])] FrmDict[SectionName] = Frm[-1] CurrentFrame += [Frm[-1]] elif SectionType == "Mesh": CurrentFrame[-1].Mesh = XSIMesh(SectionName) elif SectionType == "MeshMaterialList": MeshMats = [] elif SectionType == "SI_Material": # Material Defaults Mat_Diffuse = [self.Def_Diffuse[0], self.Def_Diffuse[1], self.Def_Diffuse[2], self.Def_Diffuse[3]] Mat_Specularity = [self.Def_Spec[0], self.Def_Spec[1], self.Def_Spec[2]] Mat_Hardness = self.Def_Hardness Mat_Texture = "" elif SectionType == "SI_Envelope": EnvelopeObj = "" EnvelopeBone = "" elif "}" in ln and not "{" in ln: # This line contains a closing brace. # Are there imbalanced braces? if InBrace <= 0: print("! - ERROR: Found extra closing brace '}', see line below for more information.") print("%s:%d:See error above."%(self.ImportFilePath, LineNumber)) else: if InSection[-1] == "Frame": del CurrentFrame[-1] elif InSection[-1] == "SI_Material": MeshMats += [MatList.NewMaterial(XSIMat(Mat_Texture, Mat_Diffuse, Mat_Hardness, Mat_Specularity))] elif InSection[-1] == "MeshMaterialList": for matInd in CurrentFrame[-1].Mesh.matInd: CurrentFrame[-1].Mesh.MatList += [MeshMats[matInd]] del InSection[-1] del InSectionName[-1] InBrace -= 1 if InBrace <= IgnoreUntilBrace: # Stop skipping lines. IgnoreUntilBrace = 0 elif not IgnoreUntilBrace: # This line neither closes off nor opens any braces, # therfore potentially contains the meat & potatoes. if InSection[-1] == "Mesh": DataType, Data = GetDataTypes(ln) if DataType == ["I"]: DataIndex += 1 elif DataIndex == 1 and DataType == ["F", "F", "F"]: # 3 floats. CurrentFrame[-1].Mesh.verts += [Data] elif DataIndex == 2 and DataType[0:2] == ["I", "I"]: # Determine data storage type for faces. # 1 = [index], [count], [polygons...] # 2 = [count], [polygons...] if not PolyType: # If Data[0] is 0, it is an [index], and Data[1] will be a [count]. # [count] will never be 0, or if it is, the file isn't worth importing anyways. if Data[0] == 0: PolyType = 1 else: PolyType = 2 if PolyType == 1: CurrentFrame[-1].Mesh.faces += [Data[2:]] else: CurrentFrame[-1].Mesh.faces += [Data[1:]] # In Mesh elif len(InSection) >= 2 and InSection[-2] == "Mesh": DataType, Data = GetDataTypes(ln) # Last section is a "Mesh", one we're inside of. if InSection[-1] == "MeshMaterialList": if DataType == ["I"]: if DataIndex == 0: # Amount of different materials used. CurrentFrame[-1].Mesh.matCount = Data[0] DataIndex += 1 elif DataIndex == 1: # Amount of faces, skip. DataIndex += 1 else: CurrentFrame[-1].Mesh.matInd += Data elif InSection[-1] == "SI_MeshTextureCoords": if DataType == ["I"]: DataIndex += 1 elif DataIndex == 1 and DataType == ["F", "F"]: CurrentFrame[-1].Mesh.uvmap_coord += [Data] elif DataIndex == 2 and DataType[0:2] == ["I", "I"]: # Determine data storage type for faces. # 1 = [index], [count], [polygons...] # 2 = [count], [polygons...] if not PolyType: # If Data[0] is 0, it is an [index], and Data[1] will be a [count]. # [count] will never be 0, or if it is, the file isn't worth importing anyways. if Data[0] == 0: PolyType = 1 else: PolyType = 2 if PolyType == 1: CurrentFrame[-1].Mesh.uvmap_poly += [Data[2:]] else: CurrentFrame[-1].Mesh.uvmap_poly += [Data[1:]] elif InSection[-1] == "SI_MeshVertexColors": if DataType == ["I"]: DataIndex += 1 elif DataIndex == 1 and DataType[0:3] == ["F", "F", "F"]: CurrentFrame[-1].Mesh.vcol_coord += [Data] elif DataIndex == 2 and DataType[0:2] == ["I", "I"]: # Determine data storage type for faces. # 1 = [index], [count], [polygons...] # 2 = [count], [polygons...] if not PolyType: # If Data[0] is 0, it is an [index], and Data[1] will be a [count]. # [count] will never be 0, or if it is, the file isn't worth importing anyways. if Data[0] == 0: PolyType = 1 else: PolyType = 2 if PolyType == 1: CurrentFrame[-1].Mesh.vcol_poly += [Data[2:]] else: CurrentFrame[-1].Mesh.vcol_poly += [Data[1:]] elif InSection[-1] == "FrameTransformMatrix": DataType, Data = GetDataTypes(ln) if len(Data) == 4: Frm[-1].matrix += [[Data[0], Data[1], Data[2], Data[3]]] # In Mesh > MeshMaterialList elif len(InSection) >= 3 and InSection[-2] == "MeshMaterialList": if InSection[-1] == "SI_Material" and not self.OneMatPerTexture: DataType, Data = GetDataTypes(ln) if DataIndex == 0: # Diffuse RGBA if DataType == ["F", "F", "F", "F"]: Mat_Diffuse = Data DataIndex += 1 elif DataIndex == 1: # Specularity/Hardness if DataType == ["F"]: Mat_Hardness = Data[0] DataIndex += 1 elif DataIndex == 2: # Specularity RGB if DataType == ["F", "F", "F"]: Mat_Specularity = Data # In Mesh > MeshMaterialList > SI_Material elif len(InSection) >= 4 and InSection[-2] == "SI_Material": if InSection[-1] == "SI_Texture2D": Mat_Texture = GetDataStr(ln) if not self.TxtrRemovePath: Mat_Texture = re.findall(ReM_FileOnly, Mat_Texture)[0] # This is the only thing we get from SI_Texture2D. IgnoreUntilBrace = InBrace # Bone Envelopes... elif InSection[-1] == "SI_Envelope": if DataIndex == 0: EnvelopeObj = GetDataStr(ln).replace("frm-", "", 1) DataIndex += 1 elif DataIndex == 1: EnvelopeBone = GetDataStr(ln).replace("frm-", "", 1) DataIndex += 1 Envelopes += [XSIEnvelope(FrmDict[EnvelopeObj], FrmDict[EnvelopeBone])] FrmDict[EnvelopeBone].isBone = True elif DataIndex == 2: DataType, Data = GetDataTypes(ln) if DataType == ["I"]: DataIndex += 1 else: DataType, Data = GetDataTypes(ln) if DataType == ["I", "F"]: Envelopes[-1].vertWeight += [[Data[0], Data[1]]] # Animations... elif self.importAnims and len(InSection) >= 2 and InSection[-2] == "Animation": if InSection[-1] == "SI_AnimationKey": DataType, Data = GetDataTypes(ln) # print(InSectionName[-2]) if DataIndex == 0 and DataType == ["I"]: # Anim type. FrmDict[InSectionName[-2]].Anim = [XSIAnimationKey(Data[0])] DataIndex += 1 elif DataIndex == 1 and DataType == ["I"]: DataIndex += 1 else: FrmDict[InSectionName[-2]].Anim[-1].keyFrame += [Data] # Time. print("XSI Import Time: %f (%d lines processed.)" % (time.clock()-Timer, LineNumber)) # [0] being root "world" frame for file reading, no longer needed. del Frm[0] # Import if InBlender: self.BlenderImportFrames(Frm, MatList) else: self.PrintImportData(Frm, MatList, Envelopes, "| ") def PrintImportData(self, FrameList, XSI_MatList, EnvelopeList, Indnt): MatList = XSI_MatList.Material SOL = ["+", "-"] # I use this alternation for different highlighting in my editor's output. for Frm in FrameList: prefix = SOL[0]+": %s" % (Indnt*Frm.GetParentCount()) print(prefix+"frm-"+Frm.name) if Frm.Mesh: uvmap_coord_full = GetFullVertList(Frm.Mesh.uvmap_coord, Frm.Mesh.uvmap_poly) fullVerts = GetFullVertList(Frm.Mesh.verts, Frm.Mesh.faces) properties = ( ("Verts", len(Frm.Mesh.verts)), ("Faces", len(Frm.Mesh.faces)), ("Unique UV Verts", len(Frm.Mesh.uvmap_coord)), ("UV Polygons", len(Frm.Mesh.uvmap_poly)), ("UV Vert References", len(uvmap_coord_full)), ("Verts Referenced", len(fullVerts)) ) printLine = "" for prop in properties: printLine += " "+prop[0] print(prefix+printLine) printLine = "" for prop in properties: printLine += " "+str(prop[1]).ljust(len(prop[0])) print(prefix+printLine) #~ for index, face in enumerate(Frm.Mesh.faces): #~ print(index, face) SOL = SOL[::-1] # Materials print("Total Unique Materials: %d" % len(MatList)) for Index, Mat in enumerate(MatList): print(" %s" % Mat) # Envelopes print("Total Envelopes: %d" % len(EnvelopeList)) for Envelope in EnvelopeList: print(" %s" % Envelope) if False: for VertWeight in Envelope.vertWeight: print(" v%d:\tw%f" % (VertWeight[0], VertWeight[1])) def SectionType(self, Section): MatchType = {} MatchType["Frame"] = (ReM_Frame, True) MatchType["FrameTransformMatrix"] = (ReM_FrameTransformMatrix, False) MatchType["SI_FrameBasePoseMatrix"] = (ReM_SI_FrameBasePoseMatrix, False) MatchType["Mesh"] = (ReM_Mesh, True) MatchType["MeshMaterialList"] = (ReM_MeshMaterialList, False) MatchType["SI_MeshNormals"] = (ReM_SI_MeshNormals, False) MatchType["SI_MeshTextureCoords"] = (ReM_SI_MeshTextureCoords, False) MatchType["SI_MeshVertexColors"] = (ReM_SI_MeshVertexColors, False) MatchType["SI_Material"] = (ReM_SI_Material, False) MatchType["SI_Texture2D"] = (ReM_SI_Texture2D, False) MatchType["AnimationSet"] = (ReM_AnimationSet, False) MatchType["Animation"] = (ReM_Animation, True) #~ MatchType["AnimFrm"] = (ReM_AnimFrm, True) MatchType["SI_AnimationKey"] = (ReM_SI_AnimationKey, False) MatchType["SI_EnvelopeList"] = (ReM_SI_EnvelopeList, False) MatchType["SI_Envelope"] = (ReM_SI_Envelope, False) MatchType["SI_CoordinateSystem"] = (ReM_SI_CoordinateSystem, True) MatchType["SI_Angle"] = (ReM_SI_Angle, False) MatchType["SI_Camera"] = (ReM_SI_Camera, True) MatchType["SI_Ambience"] = (ReM_SI_Ambience, False) MatchType["SI_Light"] = (ReM_SI_Light, True) MatchType["SI_Fog"] = (ReM_SI_Fog, False) for Type in MatchType: Match = re.match(MatchType[Type][0], Section) if Match: if MatchType[Type][1]: return Type, Match.group(1) else: return Type, "" return "", "" def BlenderImportFrames(self, FrameList, XSI_MatList): axisConv = axis_conversion(from_forward="Z", from_up="Y").to_4x4() # Create materials first. BlendMatList = self.GetMaterials(XSI_MatList) # If bones exist, create a root armature object. #~ BoneList = [Fr for Fr in FrameList if Fr.isBone] #~ if BoneList: #~ Armature = bpy.data.armatures.new("Armature") #~ ArmatureObject = bpy.data.objects.new("Armature", Armature) #~ bpy.ops.object.mode_set(mode='EDIT') #~ else: #~ ArmatureObject = None #~ for Bone in BoneList: # --- # Create objects from frames. for Frm in FrameList: print("%s%s" % (("| "*Frm.GetParentCount()), Frm.name)) # Create the object in blender. if not Frm.isBone: if Frm.Mesh and not (not self.ImportHPMesh and Frm.isHardpoint): Mesh = self.GetMesh(Frm.Mesh, XSI_MatList, BlendMatList) Frm.Obj = bpy.data.objects.new(Frm.name, Mesh) else: Frm.Obj = bpy.data.objects.new(Frm.name, None) Frm.Obj.empty_draw_type = "SINGLE_ARROW" # Add the object attributes. Frm.Obj.name = Frm.name Frm.Obj.matrix_local = self.GetMatrix(Frm.matrix) else: # Lame retarded shit. No way to directly add bones by data, only by using the operator functions. # Absolutley retarded API. What the retarded stupid fuck. Dumb as cock-nigger shit with aids. # I didn't plan on doing stupid shit like "selecting objects, then setting them in edit mode, then # calling operator functions to preform GUI tasks on them.", and won't bother resorting to such. #~ Armature.edit_bones.new(Frm.name) Frm.Obj = bpy.data.objects.new(Frm.name, None) Frm.Obj.empty_draw_type = "SINGLE_ARROW" object_list = [] #~ bpy.context.scene.objects.link(ArmatureObject) # Set parenting: for Frm in FrameList: if Frm.parent: Frm.Obj.parent = Frm.parent.Obj else: Frm.Obj.matrix_local *= axisConv posy, posz = Frm.Obj.matrix_local[1][3], Frm.Obj.matrix_local[2][3] Frm.Obj.matrix_local[2][3] = posy Frm.Obj.matrix_local[1][3] = posz object_list += [Frm.Obj] # Done bpy.context.scene.objects.link(Frm.Obj) if Frm.isHardpoint and self.EmulateFlags: Frm.Obj.show_name = True if self.EmulateFlags: if Frm.isCollision: Frm.Obj.show_wire = True if Frm.isHidden: Frm.Obj.hide = True # Materials print("Total Unique Materials: %d" % len(XSI_MatList.Material)) for Index, Mat in enumerate(XSI_MatList.Material): print(" %s" % Mat) bpy.ops.object.select_all(action='DESELECT') for Obj in object_list: Obj.select = True def GetMatrix(self, mat): return Matrix(mat).transposed() def GetMesh(self, XSI_Mesh, XSI_MatList, BlendMatList): # Compile verts & faces into a blender mesh. Mesh = bpy.data.meshes.new(XSI_Mesh.name) verts = XSI_Mesh.verts faces = XSI_Mesh.faces # Create actual blender mesh. Mesh.from_pydata(verts, [], faces) # Make sure all materials used are applied to the object first. for Mat in XSI_MatList.Material: if Mat in XSI_Mesh.MatList: Mesh.materials.append(BlendMatList[Mat.index]) # UV Mapping: uvmap_coord2 = GetFullVertList(XSI_Mesh.uvmap_coord, XSI_Mesh.uvmap_poly) if uvmap_coord2: Mesh.uv_textures.new().data UVL = Mesh.uv_layers.active.data if len(uvmap_coord2) == len(UVL): for index in range(len(UVL)): UVL[index].uv = Vector((uvmap_coord2[index][0], uvmap_coord2[index][1])) else: print("! - ERROR in Mesh %r: XSI UV's (%d) != BLENDER UV's (%d)\n! - Could not import UV Coordinates for this mesh." % (XSI_Mesh.name, len(uvmap_coord2), len(UVL))) # Vertex Colors: vcol_coord2 = GetFullVertList(XSI_Mesh.vcol_coord, XSI_Mesh.vcol_poly) if vcol_coord2: vcol = self.GetVertColors(vcol_coord2) Mesh.vertex_colors.new() VCL = Mesh.vertex_colors.active.data if len(vcol) == len(VCL): for index in range(len(VCL)): VCL[index].color = Color((vcol[index][0], vcol[index][1], vcol[index][2])) else: print("! - ERROR in Mesh %r: XSI Vert Colors (%d) != BLENDER Vert Colors (%d)\n! - Could not import Vertex Colors for this mesh." % (XSI_Mesh.name, len(vcol), len(VCL))) # Face Materials: if len(XSI_Mesh.matInd) == len(Mesh.polygons): for index, MatFace in enumerate(XSI_Mesh.MatList): Mesh.polygons[index].material_index = XSI_Mesh.matInd[index] if Mesh.uv_textures: for index, MatFace in enumerate(XSI_Mesh.MatList): Mesh.uv_textures[0].data.values()[index].image = BlendMatList[MatFace.index].texture_slots[0].texture.image else: print("! - ERROR in Mesh %r: XSI MAT FACES (%d) != BLENDER POLYGONS (%d)\n! - Could not import Face Materials for this mesh." % (XSI_Mesh.name, len(XSI_Mesh.matInd), len(Mesh.polygons))) # Finish Mesh.validate() Mesh.update(1) return Mesh def GetMaterials(self, XSI_MatList): from bpy_extras.image_utils import load_image # Create textures. TexImg = {} Texture = [] for Mat in XSI_MatList.Material: if not Mat.textureBaseName in TexImg: Texture += [bpy.data.textures.new(Mat.textureName, type="IMAGE")] if not os.path.exists(Mat.textureName): Texture[-1].image = load_image(Mat.textureBaseName, bpy.context.user_preferences.filepaths.texture_directory, place_holder=False, recursive=True) else: Texture[-1].image = load_image(Mat.textureBaseName, os.path.dirname(Mat.textureName), place_holder=False, recursive=True) TexImg[Mat.textureName] = Texture[-1] else: Texture += [TexImg[Mat.textureName]] DebugByColor = [] #~ DebugByColor = ([1.000000, 1.000000, 1.000000], #~ [1.000000, 0.000000, 0.000000], [1.000000, 1.000000, 0.000000], [0.000000, 0.000000, 1.000000], #~ [0.431373, 0.000000, 1.000000], [0.000000, 0.529412, 0.482353], [1.000000, 0.454902, 0.000000], #~ [1.000000, 0.000000, 0.988235], [0.690196, 0.694118, 0.501961], [1.000000, 0.000000, 0.592157], #~ [0.486275, 0.486275, 0.486275], [0.670588, 0.674510, 0.305882], [0.305882, 0.596078, 0.674510], #~ [0.376471, 0.254902, 0.400000], [0.376471, 0.254902, 0.000000], [0.682353, 0.443137, 1.000000], #~ [0.698039, 0.000000, 1.000000], [0.556863, 0.309804, 0.470588], [0.741176, 1.000000, 0.403922]) #~ while len(DebugByColor) < len(XSI_MatList.Material): #~ DebugByColor += [0.000000, 0.000000, 0.000000] BlenderMat = [] for Mat in XSI_MatList.Material: if self.OneMatPerTexture and Mat.textureName: BlenderMat += [bpy.data.materials.new(Mat.textureName)] else: BlenderMat += [bpy.data.materials.new("Material %d" % Mat.index)] if Texture[Mat.index]: Tex = BlenderMat[-1].texture_slots.add() Tex.texture = Texture[Mat.index] Tex.texture_coords = "UV" # Tex.uv_layer = (...).["UVMap"] Tex.use_map_color_diffuse = True if DebugByColor: BlenderMat[-1].diffuse_color = Color((DebugByColor[Mat.index])) else: BlenderMat[-1].diffuse_color = Color((Mat.diffuseRGBA[0], Mat.diffuseRGBA[1], Mat.diffuseRGBA[2])) if Mat.diffuseRGBA[3] != 1.0: BlenderMat[-1].alpha = Mat.diffuseRGBA[3] BlenderMat[-1].use_transparency = True BlenderMat[-1].specular_color = Color((Mat.specularityRGB[0], Mat.specularityRGB[1], Mat.specularityRGB[2])) BlenderMat[-1].specular_hardness = Mat.specularityHardness return BlenderMat def GetVertColors(self, coordinates): # Convert [R, G, B, A] into [R*A, G*A, B*A], if needed. vcol = [] if coordinates: if len(coordinates[0]) > 3: for col in coordinates: vcol += [[col[0]*col[3], col[1]*col[3], col[2]*col[3]]] else: for col in coordinates: vcol += [[col[0], col[1], col[2]]] return vcol if InBlender: class BZ2XSI_Import(bpy.types.Operator): bl_idname = "import_scene.bz2xsi" bl_label = "Import BZ2XSI" filepath = StringProperty(subtype="FILE_PATH") ImportHPMesh = BoolProperty( name="Import HP Meshes", description="Import hardpoints as meshes instead of as empty objects.", default=True) OneMatPerTexture = BoolProperty( name="One Material Per Texture", description="Materials with the same texture are merged into one material.", default=False) EmulateFlags = BoolProperty( name="Emulate Frm Flags", description="Affects: hp_*, *__h, *__c.", default=False) TxtrRemovePath=True def execute(self, context): FilePath = bpy.path.ensure_ext(self.filepath, ".xsi") XSI_Importer(FilePath, self.ImportHPMesh, self.TxtrRemovePath, self.OneMatPerTexture, self.EmulateFlags) return {"FINISHED"} def invoke(self, context, event): WindowManager = context.window_manager WindowManager.fileselect_add(self) return {"RUNNING_MODAL"} else: #~ XSI_Importer(r"E:/backup/Battlezone II Related/BZ2 - Icecream Race Source Stuff/XSI/dbpowe00.xsi") XSI_Importer(r"E:/Program Files/Games/BZ2/DATA/XSI/mepool01.xsi") #~ XSI_Importer(r"E:/backup/Battlezone II Related/BZ2 - Icecream Race Source Stuff/XSI/dvmbike00.xsi") #~ XSI_Importer(r"E:/Program Files/Games/BZ2/DATA/XSI/cc111100.xsi") # Contains 2-sided objects. #~ XSI_Importer(r"C:/Users/Veary/Desktop/PyTest/Importer/ivtank00.xsi") # Contains vertex colors. #~ XSI_Importer(r"C:/Users/Veary/Desktop/PyTest/Importer/fvscout_skel.xsi") # Contains bones. #~ XSI_Importer(r"E:/Program Files/Games/BZ2/DATA/XSI/apgun00.xsi") # Contains multiple materials per mesh. #~ XSI_Importer(r"E:/Program Files/Games/BZ2/DATA/XSI/fblung00.xsi") # Contains simple animation. (Quaternion rotation) def addMenuItem(self, context): self.layout.operator(BZ2XSI_Import.bl_idname, text="BZ2XSI (.xsi)") def register(): bpy.utils.register_class(BZ2XSI_Import) bpy.types.INFO_MT_file_import.append(addMenuItem) def unregister(): bpy.utils.unregister_class(BZ2XSI_Import) bpy.types.INFO_MT_file_import.remove(addMenuItem)