Yes i wrote one, didnt finish animation though >_>. Sorry theres pretty much no comments, as this was really just me messing around designing a 3d engine, its pretty hacking'ly done to... But it should give you a basic idea of the structure of the file.
Type TB3DLoader Extends TModelLoader Field MeshFileURL:String, MeshStream:TStream Field CompleteMesh:TMesh Field ChunkName:String, ChunkStart:Int, ChunkLength:Int Field LastSurface:TSurface, LastBrush:TBrush, LastTexture:TTexture, LastBrushID:Int Field BrushList:Tlist = CreateList(), TextureList:Tlist = CreateList() Method New() Header = "BB3D" End Method Method Load(Mesh:TMesh,Stream:TStream,URL:String = "") ' Seutp variables CompleteMesh = Mesh MeshFileURL = URL MeshStream = Stream ' Recursivly read chunks While Not Eof(MeshStream) ReadChunk() Wend ' Remove references CompleteMesh = Null MeshStream = Null ClearList(BrushList) ClearList(TextureList) End Method Method ReadChunk() ' Read header ChunkName = ReadString(MeshStream,4) ChunkLength = ReadInt(MeshStream) ChunkStart = StreamPos(MeshStream) ' Check what type of chunk it is Select ChunkName Case "BB3D" Local Version:Int = ReadInt(MeshStream) If Version / 100 > 1 / 100 Then Throw "Unsupported version ("+Version+") of b3d file" Case "NODE" Local Name:String = ReadNTString(MeshStream) CompleteMesh.Position[0] = ReadFloat(MeshStream) CompleteMesh.Position[1] = ReadFloat(MeshStream) CompleteMesh.Position[2] = ReadFloat(MeshStream) CompleteMesh.Scale[0] = ReadFloat(MeshStream) CompleteMesh.Scale[1] = ReadFloat(MeshStream) CompleteMesh.Scale[2] = ReadFloat(MeshStream) Local WRot:Float = ReadFloat(MeshStream) CompleteMesh.Rotation[0] = ReadFloat(MeshStream) CompleteMesh.Rotation[1] = ReadFloat(MeshStream) CompleteMesh.Rotation[1] = ReadFloat(MeshStream) Case "TEXS" While Not EOC() LastTexture = New TTexture Local FileURL:String = ReadNTString(MeshStream) Local Flags:Int = ReadInt(MeshStream) LastTexture.Blend = ReadInt(MeshStream) LastTexture.Position[0] = ReadFloat(MeshStream) LastTexture.Position[1] = ReadFloat(MeshStream) LastTexture.Scale[0] = ReadFloat(MeshStream) LastTexture.Scale[1] = ReadFloat(MeshStream) LastTexture.Rotation = ReadFloat(MeshStream) If FileType(FileURL) = 1 LastTexture.Load(FileURL) ElseIf FileType(ExtractDir(MeshFileURL)+""+StripDir(FileURL)) = 1 LastTexture.Load(ExtractDir(MeshFileURL)+""+StripDir(FileURL)) EndIf ListAddLast(TextureList,LastTexture) Wend Case "BRUS" Local TexCount:Int = ReadInt(MeshStream) While Not EOC() LastBrush = New TBrush LastBrush.Name = ReadNTString(MeshStream) LastBrush.Color[0] = ReadFloat(MeshStream) LastBrush.Color[1] = ReadFloat(MeshStream) LastBrush.Color[2] = ReadFloat(MeshStream) LastBrush.Color[3] = ReadFloat(MeshStream) LastBrush.Shininess = ReadFloat(MeshStream) LastBrush.Blend = ReadInt(MeshStream) LastBrush.FX = ReadInt(MeshStream) For Local Tex:Int = 1 To TexCount Local ID:Int = ReadInt(MeshStream) If ID <> -1 Then LastBrush.Texture = TTexture(TextureList.ValueAtIndex(ID)) Next ListAddLast(BrushList,LastBrush) Wend Case "MESH" LastBrushID = ReadInt(meshStream) If LastBrushID <> -1 Then TBrush(BrushList.ValueAtIndex(LastBrushID)).ApplyToMesh(CompleteMesh) Case "TRIS" LastSurface = CompleteMesh.AddSurface(0) LastBrushID = ReadInt(meshStream) If LastBrushID <> -1 Then TBrush(BrushList.ValueAtIndex(LastBrushID)).ApplyToSurface(LastSurface) Local V0:Int, V1:Int, V2:Int Local VSize:Int = 0 Local ParseStart:Int = StreamPos(MeshStream) While Not EOC() ReadInt(MeshStream) ; ReadInt(MeshStream) ; ReadInt(MeshStream) VSize:+1 Wend SeekStream(MeshStream,ParseStart) LastSurface.ResizePolygonList(LastSurface.PolyList.Length + VSize + 1) Local TChanger:Int = True While Not EOC() V0 = ReadInt(MeshStream) V1 = ReadInt(MeshStream) V2 = ReadInt(MeshStream) LastSurface.AddTriangle(CompleteMesh.GetVertex(V0),CompleteMesh.GetVertex(V1),CompleteMesh.GetVertex(V2)) Wend Case "VRTS" Local Flags:Int = ReadInt(MeshStream) Local TexCoordSet:Int = ReadInt(MeshStream) Local TexCoordCount:Int = ReadInt(MeshStream) Local VX:Float, VY:Float, VZ:Float, VNX:Float, VNY:Float, VNZ:Float Local VR:Float = 255, VG:Float = 255, VB:Float = 255, VA:Float = 1 Local VSize:Int = 0 Local ParseStart:Int = StreamPos(MeshStream) While Not EOC() ReadFloat(MeshStream) ; ReadFloat(MeshStream) ; ReadFloat(MeshStream) If Flags & 1 Then ReadFloat(MeshStream) ; ReadFloat(MeshStream) ; ReadFloat(MeshStream) If Flags & 2 Then ReadFloat(MeshStream) ; ReadFloat(MeshStream) ; ReadFloat(MeshStream) For Local Set:Int = 1 To TexCoordSet For Local Size:Int = 1 To TexCoordCount ReadFloat(MeshStream) Next Next VSize:+1 Wend SeekStream(MeshStream,ParseStart) CompleteMesh.ResizeVertexList(CompleteMesh.VertexList.Length + VSize + 1) While Not EOC() Local Vertex:TVertex = CompleteMesh.AddVertex(0,0,0) Vertex.Position[0] = ReadFloat(MeshStream) Vertex.Position[1] = ReadFloat(MeshStream) Vertex.Position[2] = ReadFloat(MeshStream) If Flags & 1 Vertex.Normal[0] = ReadFloat(MeshStream) Vertex.Normal[1] = ReadFloat(MeshStream) Vertex.Normal[2] = ReadFloat(MeshStream) EndIf If Flags & 2 Vertex.Color[0] = ReadFloat(MeshStream) Vertex.Color[1] = ReadFloat(MeshStream) Vertex.Color[2] = ReadFloat(MeshStream) Vertex.Color[3] = ReadFloat(MeshStream) EndIf For Local Set:Int = 1 To TexCoordSet For Local Size:Int = 1 To TexCoordCount Local Temp:Float = ReadFloat(MeshStream) If Set = 1 If Size = 1 Vertex.TextureCoords[0] = Temp ElseIf Size = 2 Vertex.TextureCoords[1] = Temp EndIf EndIf Next Next Wend Default NextChunk() End Select End Method Method NextChunk(Offset:Int = 0) SeekStream(MeshStream,ChunkStart + ChunkLength + Offset) End Method Method EOC:Int() If StreamPos(MeshStream) >= ChunkStart + ChunkLength Then Return True Return False End Method End Type