Diese Erweiterung für MiniB3D ermöglicht es Meshes des .x-Formates zu laden, wie aus B3D bekannt. Damit kann man einfach über LoadMesh entsprechende Meshes laden.
Hinweis: Es werden nur .x Meshes im Text-Format geladen.
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN]
Private
Type XLoader_TreeNode Field children:TList Field content:String Field template:String Field name:String Method New() Self.children = New TList End Method Method Add(element:XLoader_TreeNode) Self.children.AddLast(element) End Method End Type
Public
Type TXLoader
Function LoadXMesh:TMesh(path:String, parent:TEntity = Null)
Local s:TStream = ReadFile(path) If Not s Then Return CreateCube() ; Local header:String = s.ReadString(4) Local version:String = s.ReadString(4) Local format:String = s.ReadString(4) Local floatsize:Int = Int(s.ReadString(4)) If header = "xof " If version = "0302" If format = "txt " Local submesh:TMesh = CreateMesh() While Not s.Eof() Local checkbyte:Int = s.ReadByte() s.Seek(s.Pos() - 1) If Not (XLoader_isWhitespace(Chr(checkbyte)) Or checkbyte = Asc("/") Or checkbyte = Asc("#")) Local read:String = s.ReadString(s.Size() - s.Pos()) read = XLoader_RemoveUnprintables(read) read = read.Replace(" {", "{") read = read.Replace("{ ", "{") read = read.Replace(" }", "}") read = read.Replace("} ", "}") Local tree:XLoader_TreeNode = XLoader_MakeTree(read) Local matlist:TList = XLoader_FindTreeElements(tree, "material") Local material:XLoader_TreeNode Local brushes:TBrush[matlist.Count()] Local brushnames:String[matlist.Count()] Local count:Int = 0 For material = EachIn matlist brushnames[count] = material.name Local brushrgba:String[] = material.content[..material.content.Find(";;")].Split(";") brushes[count] = CreateBrush(Float(brushrgba[0]) * 255.0, Float(brushrgba[1]) * 255.0, Float(brushrgba[2]) * 255.0) brushes[count].BrushAlpha(Float(brushrgba[3])) Local texturefilestart:Int = material.content.Find("~q") If texturefilestart <> - 1 Local texturefilename:String = material.content[texturefilestart + 1..material.content.Find("~q", texturefilestart + 1)] Local tex:TTexture = LoadTexture(XLoader_ExtractFilePath(path) + "/" + texturefilename) If tex <> Null Then brushes[count].BrushTexture(tex) End If count:+1 Next
Local framelist:TList = XLoader_FindTreeElements(tree, "frame") Local frametree:XLoader_TreeNode
For frametree = EachIn framelist If frametree.name.ToLower() <> "world" Local tmatlist:TList = XLoader_FindTreeElements(frametree, "FrameTransformMatrix") Local meshnodes:TList = XLoader_FindTreeElements(frametree, "mesh") Local meshnode:XLoader_TreeNode Local currentmeshnode:Int = 0 Local tformmat:TMatrix For meshnode = EachIn meshnodes Local meshlistelm:Object = tmatlist.ValueAtIndex(currentmeshnode) If meshlistelm <> Null Local tmat:String[] = XLoader_TreeNode(meshlistelm).content.Split(",") currentmeshnode:+1 tformmat:TMatrix = New TMatrix tformmat.LoadIdentity() Local maty:Int = -1 Local matx:Int = 0 For matx = 0 To 15 If matx Mod 4 = 0 Then maty:+1 tformmat.grid[matx - maty * 4, maty] = Float(tmat[matx]) Next EndIf Local surf:TSurface = CreateSurface(submesh) Local meshdata:String = meshnode.content.Trim() meshdata.Replace(" ", "") Local offset:Int = meshdata.Find(";") Local vertexcount:Int = Int(meshdata[..offset]) meshdata = meshdata[offset + 1..] offset = meshdata.Find(";;") Local vertexdata:String[] = meshdata[..offset].Replace(",", "").Split(";") Local vcount:Int = 0 For vcount = 0 To (vertexcount - 1) * 3 Step 3 Local vertx:Float = Float(vertexdata[vcount]) Local verty:Float = Float(vertexdata[vcount + 1]) Local vertz:Float = Float(vertexdata[vcount + 2]) Local x:Float = vertx * tformmat.grid[0, 0] + verty * tformmat.grid[0, 1] + vertz * tformmat.grid[0, 2] + tformmat.grid[0, 3] Local y:Float = vertx * tformmat.grid[1, 0] + verty * tformmat.grid[1, 1] + vertz * tformmat.grid[1, 2] + tformmat.grid[1, 3] Local z:Float = vertx * tformmat.grid[2, 0] + verty * tformmat.grid[2, 1] + vertz * tformmat.grid[2, 2] + tformmat.grid[2, 3] Local w:Float = tformmat.grid[3, 0] + tformmat.grid[3, 1] + tformmat.grid[3, 2] + tformmat.grid[3, 3] AddVertex(surf, x, y, z) Next meshdata = meshdata[offset + 2..] offset = meshdata.Find(";") Local facecount:Int = Int(meshdata[..offset]) meshdata = meshdata[offset + 1..] offset = meshdata.Find(";;") Local facedata:String[] = meshdata[..offset].Replace(";,", ";").Split(";") Local fcount:Int = 0 For fcount = 1 To facecount * 2 Step 2 Local faces:String[] = facedata[fcount].Split(",") If faces.Length = 3 surf.AddTriangle(Int(faces[0]), Int(faces[1]), Int(faces[2])) ElseIf faces.Length = 4 surf.AddTriangle(Int(faces[0]), Int(faces[1]), Int(faces[2])) surf.AddTriangle(Int(faces[2]), Int(faces[3]), Int(faces[0])) EndIf Next Local normals:TList = XLoader_FindTreeElements(meshnode, "meshnormals") If normals.IsEmpty() UpdateNormals(submesh) Else Local normaldata:String = XLoader_TreeNode(normals.ValueAtIndex(0)).content Local normalcount:Int = Int(normaldata[..normaldata.Find(";")]) normaldata = normaldata[normaldata.Find(";") + 1..normaldata.Find(";;")].Replace(",", "") Local normalbits:String[] = normaldata.Split(";") Local i:Int = 0 For i = 0 To normalcount - 1 surf.VertexNormal(i, Float(normalbits[i * 3]), Float(normalbits[i * 3 + 1]), Float(normalbits[i * 3 + 2])) Next EndIf Local textcoords:TList = XLoader_FindTreeElements(meshnode, "MeshTextureCoords") If Not textcoords.IsEmpty() Local texturecoordsdata:String = XLoader_TreeNode(textcoords.ValueAtIndex(0)).content Local texturecoordscount:Int = Int(texturecoordsdata[..texturecoordsdata.Find(";")]) texturecoordsdata = texturecoordsdata[texturecoordsdata.Find(";") + 1..texturecoordsdata.Find(";;")] Local tcoords:String[] = texturecoordsdata.Replace(",", "").Split(";") Local i:Int = 0 For i = 0 To texturecoordscount - 1 surf.VertexTexCoords(i, Float(tcoords[i * 2]), Float(tcoords[i * 2 + 1])) Next EndIf Local texlist:TList = XLoader_FindTreeElements(meshnode, "MeshMaterialList") If Not texlist.IsEmpty() Local texdata:String = XLoader_TreeNode(texlist.ValueAtIndex(0)).content texdata = texdata[texdata.Find(";;") + 3..] Local texname:String = texdata[..texdata.Find("}")] Local i:Int = 0 For i = 0 To brushnames.Length - 1 If brushnames[i] = texname Then surf.PaintSurface(brushes[i]) Next End If Next EndIf Next Else If XLoader_isWhitespace(checkbyte) s.Seek(s.Pos() + 1) Else s.ReadLine() End If EndIf Wend s.Close() Return submesh Else DebugLog "X Mesh Loader: Unsupported format '" + format + "'!" EndIf Else DebugLog "X Mesh Loader: Unsupported version '" + version + "'!" EndIf Else DebugLog "X Mesh Loader: Invalid x-mesh!" EndIf Return CreateCube() End Function
Function XLoader_ExtractFilePath:String(path:String) Local i : Int = 0 For i = Len(path)-1 To 0 Step -1 If Chr(path[i]) = "/" Or Chr(path[i]) = "\" Then Return path[..i] Next Return path End Function
Function XLoader_FindTreeElements:TList(tree:XLoader_TreeNode, template:String) Local l:TList = New TList If Lower(tree.template) = template l.AddLast(tree) EndIf Local element:XLoader_TreeNode
For element = EachIn tree.children If element.template = template Then l.AddLast(element) If Not element.children.IsEmpty() Then l = XLoader_JoinLists(l, XLoader_FindTreeElements(XLoader_TreeNode(element), template)) Next Return l End Function Function XLoader_JoinLists:TList(l1:TList, l2:TList) Local o:Object For o = EachIn l2 l1.AddLast(o) Next Return l1 End Function Function XLoader_MakeTree:XLoader_TreeNode(s:String, parent:XLoader_TreeNode = Null) Local root:XLoader_TreeNode = New XLoader_TreeNode Local pointer:Int = 0 Local find:Int = 0 s = s.Trim() While s.Length > 0 find = s.find("{", pointer) If find = -1 Then Exit Local header:String = s[pointer..find] Local bits:String[] = header.Split(" ") pointer = find + 1 root.template = bits[0] If bits.Length > 1 Then root.name = bits[1] Local frameend:Int = XLoader_FindBracketMatch(s[pointer..]) Local framecontent:String = s[pointer..frameend + pointer] root.content = framecontent s = s[pointer + 1 + frameend..] Select root.template.ToLower() Case "frame" Local newNode:XLoader_TreeNode = XLoader_MakeTree(framecontent, root) If newNode Then root.Add(newNode) Case "mesh" Local contentend:Int = XLoader_FindAlphaChar(framecontent) root.content = framecontent[..contentend] Local newNode:XLoader_TreeNode = XLoader_MakeTree(framecontent[contentend..], root) If newNode Then root.Add(newNode) Default Local newNode:XLoader_TreeNode = XLoader_MakeTree(s, root) If newNode Then root.Add(newNode) Exit
End Select pointer = 0 Wend Return root End Function Function XLoader_FindAlphaChar:Int(s:String) Local i:Int = 0 For i = 0 To s.Length - 1 If s[i] >= 65 And s[i] <= 90 Then Return i If s[i] >= 97 And s[i] <= 122 Then Return i Next Return - 1 End Function Function XLoader_FindBracketMatch:Int(s:String) Local index:Int = 1 Local i:Int = 0 Local ascbracket:Byte[2] ascbracket[0] = Asc("{") ascbracket[1] = Asc("}") For i = 0 To s.Length - 1 Select s[i] Case ascbracket[0] index:+1 Case ascbracket[1] index:-1 End Select If index = 0 Then Return i Next Return - 1 End Function Function XLoader_CharCount:Int(s:String, find:String) Local count:Int = 0 Local i:Int = 0 Local ascfind:Byte = Asc(find) For i = 0 To s.Length - 1 If s[i] = ascfind Then count:+1 Next Return count End Function Function XLoader_RemoveUnprintables:String(s:String) Local i:Int = 0 For i = 0 To 31 s = s.Replace(Chr(i), "") Next Return s End Function Function XLoader_isWhitespace:Byte(char:String) Return Asc(char) <= 32 End Function End Type
Installation:
Hinweis: Ab hier wird eine installierte und funktionierende Version von MiniB3D, sowie MinGW vorausgesetzt!
1. Den Sourcecode nach [i]TXLoader.bmx speichern und ins Verzeichnis mod/sidesign/minib3d/inc/ verschieben.
2. minib3d.bmx öffnen, folgenede Zeile bei den Includes hinzufügen:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Include "inc/TXLoader.bmx"
3. inc/TMesh.bmx öffnen, die Methode LoadAnimMesh finden, und folgende Zeile oben hinzufügen:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] If Right(String(file), 2) = ".x" Then Return TXLoader.LoadXMesh(file, parent_ent)
4. Das Modul neu Kompilieren - Fertig.
Getestet mit MiniB3D 0.53 und einer ganzen Palette verschiedenster Meshes, es sollte eigentlich reibungslos funktionieren. Ich hoffe, damit konnte ich noch jemand anderem außer mir selbst helfen.
MfG, ZaP
Edit (13.02.2012): Einige Sachen verbessert, siehe Changelog.
|