#!BPY """ Name: 'Gm' Blender: 242 Group: 'Export' Tooltip: 'POTC Geometry Exporter' """ #============================================================================# #Known Bugs: #bounding-box and bounding sphere have zero size #All Empties in the scene are saved as loacotrs with the selected mesh - should be only selected empties # #Current limitations: #No characters/ships (probably best for items) #only one material, one submesh per file #only one vertexbuffer, one texture per material (e.g., no bumpmapping) #material data simplified (color always white, no emissive) #no locators # #Notes: #The mesh to be exported must be selected # #The texture name that is exported is the name of the Blender datablock name, #(as shown in the Shading / Texture panel in the Buttons window), not the #image file name. # #Blender "Empty" objects are made into locators. #============================================================================# import Blender from Blender import * import struct from struct import * from Blender.BGL import * from Blender.Draw import * # Events EVENT_NOEVENT = 1 EVENT_EXPORT = 2 EVENT_QUIT = 3 def draw(): global EVENT_NOEVENT,EVENT_EXPORT,EVENT_QUIT glClear(GL_COLOR_BUFFER_BIT) y = 10 Button("Export",EVENT_EXPORT , 10, y, 70, 18) Button("Quit",EVENT_QUIT, 100, y, 70, 18) y += 20 y += 10 glRasterPos2d(10, y) Text("POTC gm Exporter") y += 20 def event(evt, val): if (evt == QKEY and not val): Exit() def bevent(evt): global EVENT_NOEVENT,EVENT_EXPORT,EVENT_QUIT ######### Manages GUI events if (evt == EVENT_QUIT): Exit() elif (evt== EVENT_EXPORT): fname = Blender.sys.makename(ext=".gm") Blender.Window.FileSelector(write, "Export", fname) #============================================================================# def triangulateNMesh(nm): #this is from Blender Wiki Book #use triangleToQuad() function instead? ''' Converts the meshes faces to tris, modifies the mesh in place. ''' #============================================================================# # Returns a new face that has the same properties as the origional face # # but with no verts # #============================================================================# def copyFace(face): newFace = NMesh.Face() # Copy some generic properties newFace.mode = face.mode if face.image != None: newFace.image = face.image newFace.flag = face.flag newFace.mat = face.mat newFace.smooth = face.smooth return newFace # 2 List comprehensions are a lot faster then 1 for loop. tris = [f for f in nm.faces if len(f) == 3] quads = [f for f in nm.faces if len(f) == 4] if quads: # Mesh may have no quads. has_uv = quads[0].uv has_vcol = quads[0].col for quadFace in quads: # Triangulate along the shortest edge if (quadFace.v[0].co - quadFace.v[2].co).length < (quadFace.v[1].co - quadFace.v[3].co).length: # Method 1 triA = 0,1,2 triB = 0,2,3 else: # Method 2 triA = 0,1,3 triB = 1,2,3 for tri1, tri2, tri3 in (triA, triB): newFace = copyFace(quadFace) newFace.v = [quadFace.v[tri1], quadFace.v[tri2], quadFace.v[tri3]] if has_uv: newFace.uv = [quadFace.uv[tri1], quadFace.uv[tri2], quadFace.uv[tri3]] if has_vcol: newFace.col = [quadFace.col[tri1], quadFace.col[tri2], quadFace.col[tri3]] nm.addEdge(quadFace.v[tri1], quadFace.v[tri3]) # Add an edge where the 2 tris are devided. tris.append(newFace) nm.faces = tris #============================================================================# def writeString(s): print(s) out.write(pack('i', len(s))) out.write(s) #============================================================================# #Globals numTextBytes = 0 texts = [] offsetTexts = [] offsetMaterialNames = [] offsetLocatorNames = [] offsetSubsetNames = [] offsetTextureNames = [] #============================================================================# def writeHeader(out, nmesh): global numTextBytes a = 0 #controls BSP and cullmode #ammo, islands, locations, items, ships, tornado:2 #characters, low characters, animals, heads, particles, swin goods, worldmap: 0 out.write(pack('4s', "50.1")) #Version out.write(pack('i', a)) out.write(pack('i', numTextBytes)) out.write(pack('i', len(texts))) out.write(pack('i', len(offsetTextureNames))) out.write(pack('i', len(nmesh.materials))) out.write(pack('i', 0)) #dZero out.write(pack('i', len(offsetLocatorNames))) out.write(pack('i', len(offsetSubsetNames))) #more than one subset not yet implemented out.write(pack('i', len(nmesh.faces))) out.write(pack('i', 1)) #NumVertexBuffers, more than one vertbuffer not yet implemented out.write(pack('3f', 0, 0, 0)) #size out.write(pack('4f', 0, 0, 0, 0)) #boundingSphere #============================================================================# def writeTexts(out): global texts global offsetTexts print("\nTexts") for text in texts: print(text) out.write(text) out.write(pack('B', 0)) for offset in offsetTexts: out.write(pack('i', offset)) #============================================================================# def writeTexturenames(out, nmesh): global offsetTextureNames print("\nTexturenames") for nameOffset in offsetTextureNames: print(nameOffset) out.write(pack('i', nameOffset)) #============================================================================# def writeMaterials(out, nmesh): global offsetMaterialNames print("\nMaterials") for (groupOffset, nameOffset) in offsetMaterialNames: out.write(pack('i', groupOffset)) out.write(pack('i', nameOffset)) out.write(pack('4B', 1, 1, 1, 1)) #diffuse out.write(pack('4B', 1, 1, 1, 1)) #specular out.write(pack('f', 2.0)) #specular power out.write(pack('4B', 0, 0, 0, 1)) #emissive out.write(pack('4i', 1, 0, 0, 0)) #texture flag out.write(pack('4i', 0, 0, 0, 0)) #texture number #============================================================================# def writeLocators(out, nmesh): global offsetLocatorNames print("\nLocators") for (groupOffset, nameOffset) in offsetLocatorNames: out.write(pack('i', groupOffset)) out.write(pack('i', nameOffset)) out.write(pack('4f', 1, 0, 0, 0)) #orientation out.write(pack('4f', 0, 1, 0, 0)) out.write(pack('4f', 0, 0, 1, 0)) out.write(pack('4f', 0, 0, 0, 1)) out.write(pack('2f', 0, 1)) #unknown out.write(pack('7i', 0,0,0,0,0,0,0)) #unknown #============================================================================# def writeSubsets(out, nmesh): global offsetSubsetNames print("\nSubsets") for (groupOffset, nameOffset) in offsetSubsetNames: out.write(pack('i', groupOffset)) out.write(pack('i', nameOffset)) out.write(pack('i', 3103)) out.write(pack('4f', 0, 0, 0, 0)) #boundingSphere out.write(pack('i', 0)) #oZero #AttributeRange out.write(pack('i', len(nmesh.faces))) #FaceCount out.write(pack('i', 0)) #FaceStart out.write(pack('i', len(nmesh.verts))) #VertexCount out.write(pack('i', 0)) #VertexStart out.write(pack('i', 0)) #MaterialID out.write(pack('8B',0,0,0,0,0,0,0,0)) #r1 - unknown out.write(pack('i', -1)) #sMinusOne out.write(pack('8B',0,0,0,0,0,0,0,0)) #t - unknown out.write(pack('8B',0,0,0,0,0,0,0,0)) #t out.write(pack('8B',0,0,0,0,0,0,0,0)) #t out.write(pack('8B',0,0,0,0,0,0,0,0)) #t out.write(pack('4B',0,0,0,0)) #t out.write(pack('i', len(nmesh.faces))) #nextFaceStart #============================================================================# def writeVertexbufferHeaders(out, nmesh): #more than one vertbuffer not yet implemented print("\nVertexbufferHeaders") u4 = 0 vertexStride = (3 * 4 + 3 * 4 + 1 * 4 + 2 * 4) #Position Normal Color Textcoord0 #texcoord1 for bump mapping not yet exported if u4 == 1 or u4 == 4: vertexStride += 8 sizeInBytes = len(nmesh.verts) * vertexStride out.write(pack('i', 0)) #u4 (4 for characters, not yet implemented) out.write(pack('i', sizeInBytes)) #============================================================================# def saveText(s): global numTextBytes global offsetTexts global texts offsetTexts.append(numTextBytes) texts.append(s) numTextBytes += len(s) + 1 #============================================================================# def processMaterials(nmesh): global numTextBytes global offsetMaterialNames global offsetTextureNames print("process Materials") offsetMaterialNames = [] offsetTextureNames = [] numTextBytes = 0 groupOffset = numTextBytes saveText("Unknown Material Group") for material in nmesh.materials: nameOffset = numTextBytes saveText(material.name) offsetMaterialNames.append((groupOffset, nameOffset)) for mtex in material.getTextures(): if mtex != None: if mtex.tex.type == Texture.Types.IMAGE: offsetTextureNames.append(numTextBytes) saveText(mtex.tex.image.name) #============================================================================# def processLocators(scn): global offsetLocatorNames print("process Locators") offsetLocatorNames = [] groupOffset = numTextBytes saveText("Unknown Locator Group") for o in scn.objects: if o.getType()=='Empty': nameOffset = numTextBytes saveText(o.name) offsetLocatorNames.append((groupOffset, nameOffset)) #============================================================================# def processSubsets(nmesh): global offsetSubsetNames print("process Subsets") offsetSubsetNames = [] #use getVertGroupNames to find subsets ? groupOffset = numTextBytes saveText("Unknown Subset Group") nameOffset = numTextBytes saveText("subset1") offsetSubsetNames.append((groupOffset, nameOffset)) #============================================================================# def write(filename): print("\nGm exporter") out = file(filename, "wb") scn = Blender.Scene.GetCurrent() object = scn.objects.active if object.getType()=='Mesh': nmesh = object.getData() triangulateNMesh(nmesh) processMaterials(nmesh) processLocators(scn) processSubsets(nmesh) writeHeader(out, nmesh) writeTexts(out) writeTexturenames(out, nmesh) writeMaterials(out, nmesh) writeLocators(out, nmesh) writeSubsets(out, nmesh) print("\nFaces") for f in nmesh.faces: out.write(pack('3H', f.v[0].index, f.v[1].index, f.v[2].index)) writeVertexbufferHeaders(out, nmesh) print("\nVertices") for v in nmesh.verts: out.write(pack('3f', v.co.x, v.co.y, v.co.z)) out.write(pack('3f', v.no.x, v.no.y, v.no.z)); out.write(pack('4B', 255, 255, 255, 255)); #vertex color? - not really used I think out.write(pack('2f', v.uvco.x, v.uvco.y)); #print(v.co); #print(v.no); #print(v.uvco) print("\ndone.") out.close() #============================================================================# # Einstiegspunkt # # # #============================================================================# #Einfachste Version: #write("test.sm") #Mit Dateiauswahl: #fname = Blender.sys.makename(ext=".gm") #Blender.Window.FileSelector(write, "Export", fname) #Mit Buttons: Register(draw, event, bevent)