Loading 3D Models in OpenGL

BlitzMax Forums/BlitzMax OpenGL Programming/Loading 3D Models in OpenGL

Hi I was wondering, if there's an openGL command to load in a 3D Model?

Or if theres any way to load in ASCII data, from either Milkshapes own format, or 3DS. Or in fact from a mesh file, be it 3DS, .X, .LWO etc. As I've had loads of problems with exporting many B3D meshes from milkshape as they export out all oddly, and the textures dont load at all. (From the samples with BMAX and the excellent Exron / Nehe tutorial lessons)

Many thanks,
THUMBZ

Nehe Tutorial 31 is Model loading with Milkshape model.

Thing with MS3D is though. that I'd need to rehack the material name reader so that it can find the textures if they're not in the same folder stated with saving in Milkshape. Shouldnt be too much of a chore.

Also worth noting, when using Exrons excellent MS3D loader - it doesnt like textures that are not in 128,256,512 sizes. Took me a while to phathom why the textures weren't showing.

Terrabits 3D level demo (in the showcase I think) has a basic B3D loader, though the code's a bit tricky to follow :)

I'm gonna have to bite the bullit and make one myself, I've been putting it off too long.

Would it be too difficult to load MD2 models, and 3ds models?
That would be great to be able to do.

were still having trouble with trinity's B3d loader, antony scaled the mesh -1 in one direction (not sure which) but as far as I can tell the actual local pivot doesn't get flipped. So any transforms end up being messed up and rotations done in max end up being in the wrong direction etc.

Hoping he get's it fixed tonight, If he doesn't maybe someone here who knows more about left hamded and right handed coordinate systems can help him out. It's a bit confusing at the moment heh lol.

(Mental Note:NDAs are a good thing.)

lol

heh, what NDA. If anyone's been there before we might save ourselves a lot of trouble finding what were doing wrong :)

So long as we can make sense of whats is wrong.

Here, my loader. It's basically like Terrabit's loader but rewritten. In my opinion it's a little more obvious, if you can figure out what you'd have to change to make it work (I'm using my own Vertex, Triangle and Mesh types). But I think that should be easier than writing it on your own. If you have questions don't hesitate to ask or look at http://www.blitzbasic.com/sdkspecs/sdkspecs/userlibs_specs.txt .

Todo-List:
- Multiply all vertices with the local Node matrix (or the other way, you'll have to try)
- Brushes
- Bones / Animations

Global B3DL:B3DLoader Private

Public Type B3DLoader
	
	'#Region Fields
	
	Field File:Int
	
	Field Mesh:eeMesh
	
	Field Index:Int[]
	Field Vertex:eeVertex[]
	
	Field ChunkName:String
	Field ChunkSize:Int
	Field ChunkStart:Int
	Field FileEnd:Int
	
	Field LocalMatrix:Float[16]
	'#End Region
	
	Function LoadMesh:eeMesh ( Path:String ) Public
		B3DL = New B3DLoader
		
		B3DL.File:Int = OpenFile("littleendian::" + Path)
		If Not B3DL.File Then Return Null
		
		B3DL.Mesh = New eeMesh
		
		B3DL.ReadChunk
		B3DL.FileEnd = B3DL.ChunkStart + B3DL.ChunkSize
		
		Readint(B3DL.File) 'version
		
		Local start = MilliSecs()
		B3DL.Parse
		
		Local CompleteMesh:eeMesh = B3DL.Mesh
		
		Local Vert:Int = 0
		
		B3DL.Mesh.TriangleData = B3DL.Mesh.TriangleData[..B3DL.Mesh.TriangleCount]
		
		For Local T:Int = 0 To B3DL.Index.Length/3 -1
			Local Tri:eeTriangle = New eeTriangle
			Tri.V[0] = B3DL.Vertex[B3DL.Index[Vert+0]]
			Tri.V[1] = B3DL.Vertex[B3DL.Index[Vert+1]]
			Tri.V[2] = B3DL.Vertex[B3DL.Index[Vert+2]]
			Vert :+ 3
			B3DL.Mesh.TriangleData[T] = Tri
		Next
		
		Release B3DL
		
		Return CompleteMesh
		
	End Function
	
	Method ReadChunk ( ) Private
		Self.ChunkName = ""
		For Local i = 1 To 4
			Self.ChunkName = Self.ChunkName + Chr( ReadByte(Self.File) )
		Next
		Self.ChunkSize = Readint(Self.File)
		Self.ChunkStart = StreamPos(Self.File)
	End Method
	
	Method Parse ( ) Private
		While StreamPos(Self.File) < Self.FileEnd
			Self.ReadChunk
			Select ChunkName
				Case "NODE"
					Local Name:String = ReadString(Self.File)
					
					Local XPos:Float = ReadFloat(Self.File)
					Local YPos:Float = ReadFloat(Self.File)
					Local ZPos:Float = ReadFloat(Self.File)
					
					Local XScl:Float = ReadFloat(Self.File)
					Local YScl:Float = ReadFloat(Self.File)
					Local ZScl:Float = ReadFloat(Self.File)

					Local WRot:Float = ReadFloat(Self.File)
					Local XRot:Float = ReadFloat(Self.File)
					Local YRot:Float = ReadFloat(Self.File)
					Local ZRot:Float = ReadFloat(Self.File)
					
					Local CurrentMatrixMode:Int
					glGetIntegerv(GL_MATRIX_MODE, Varptr CurrentMatrixMode)
					glMatrixMode(GL_MODELVIEW)
					glPushMatrix
						glLoadIdentity
						glTranslatef XPos, YPos, ZPos
						glRotatef    XRot, 1.0,0.0,0.0
						glRotatef    YRot, 0.0,1.0,0.0
						glRotatef    ZRot, 0.0,0.0,1.0
						glScalef     XScl, YScl, ZScl
						glGetFloatv(GL_MODELVIEW_MATRIX, Self.LocalMatrix)
					glPopMatrix
					glMatrixMode(CurrentMatrixMode)
					' (localmatrix) * (each vertex)
					
					Self.Parse
					
				Case "MESH"
					Local BrushID:Int = Readint(Self.File)
					Self.Parse
					
				Case "TRIS"
					Local BrushID:Int = Readint(Self.File)
					Local V0:Int, V1:Int, V2:Int
					Self.Index = New Int[65535]
					Local IndexCount:Int = 0
					While StreamPos(Self.File) < (Self.ChunkStart + Self.ChunkSize)
						V0 = Readint(Self.File)
						V1 = Readint(Self.File)
						V2 = Readint(Self.File)
						Self.Index[IndexCount+0] = V2
						Self.Index[IndexCount+1] = V1
						Self.Index[IndexCount+2] = V0
						IndexCount :+ 3
						Self.Mesh.TriangleCount :+ 1
					Wend
					Self.Index = Self.Index[..IndexCount]
				
				Case "VRTS"
					Local Flags:Int = Readint(Self.File)
					Local TexCoordSets:Int = Readint(Self.File)
					Local TexCoordCount:Int = Readint(Self.File)
					Local VertCount:Int = 0
					If (Self.Mesh.TriangleCount <> 0) Then
						Self.Vertex = New eeVertex[3*Self.Mesh.TriangleCount]
					Else
						Self.Vertex = New eeVertex[65535]
					EndIf
					
					While StreamPos(Self.File) < (Self.ChunkStart + Self.ChunkSize)
						
						Self.Vertex[VertCount] = New eeVertex
						
						Local Vert:eeVertex = Self.Vertex[VertCount]
						
						Vert.X = ReadFloat(Self.File)
						Vert.Y = ReadFloat(Self.File)
						Vert.Z = ReadFloat(Self.File)
						
						If (Flags&1) Then
							Vert.NX = ReadFloat(Self.File)
							Vert.NY = ReadFloat(Self.File)
							Vert.NZ = ReadFloat(Self.File)
						EndIf
						
						If (Flags&2) Then
							Vert.Color[0] = ReadFloat(Self.File)
							Vert.Color[1] = ReadFloat(Self.File)
							Vert.Color[2] = ReadFloat(Self.File)
							Vert.Alpha = ReadFloat(Self.File)
						EndIf
						
						For Local Set:Int = 1 To TexCoordSets
							For Local Size:Int = 1 To TexCoordCount
								Local Temp:Float = ReadFloat(Self.File)
								If Set = 1 Then
									If Size = 1 Then Vert.U = Temp
									If Size = 2 Then Vert.V = Temp
								EndIf
							Next
						Next
						
						VertCount :+ 1
						
					Wend
					Self.Vertex = Self.Vertex[..VertCount]
					
			End Select
			SeekStream(Self.File, ChunkStart+ChunkSize)
		Wend
	End Method
	
End Type

Function ReadString:String ( In:TStream ) Private
Local Char:Byte, S:String
Repeat
	Char = ReadByte(In)
	If Char = 0 Return S$
	S = S + Chr(Char)
Forever
End Function


By the way a nice site for file formats is http://www.wotsit.org/search.asp?s=3d

Evak, yeah but no but yeah but no...(It's a little british thing. :) )

heh, anyway your almost there Ant, the last version you sent just needs to get the local pivot rotation orientation right and your done. If I account for that in max it's perfect :)

thanks eizdealer, I'm sure we will get the animation done soon too since were that close it isn't funny.

where can i found the class eeMesh, eeVertex.

The code don't compile :(