.obj loading code

BlitzMax Modules Forums/MiniB3D/.obj loading code

The forum is locked. These are the original blitzbasic.com forums, kept so they can still be read. No new topics, replies or edits can be made here. To join in, head over to the Blitz3D+ forums.

I just whipped this up in a few minutes. It handles quads and polygons. I did not bother with materials, and the way it is used here is slightly different from the LoadMesh() convention:
Function LoadObj:Int(file:String,surf:TSurface)
	Local stream:TStream
	Local position:TBank=New TBank
	Local normal:TBank=New TBank
	Local texcoords:TBank=New TBank
	Local line:String[]
	Local indices:String[]
	Local sumindices:Int
	Local x#,y#,z#,s$,a,b,c,na,nb,nc
	Local nx#,ny#,nz#,tu#,tv#,v,m#
	Local currentsmoothgroup
	Local face:TObjFace,vert:TObjVert,face2:TObjFace
	Local n,avg#,n2
	
	stream=ReadFile(file)
	If Not stream Return
	While Not stream.Eof()
		
		s$=Trim(stream.ReadLine())
		If s="" Continue
		If Left(s,1)="#" Continue
		
		line=s.split("")
		If line.length=0 Continue
		
		Select Lower(line[0])
			Case "v"
				If line.length<3 Return
				AppendFloat position,Float(line[1])
				AppendFloat position,Float(line[2])
				AppendFloat position,Float(line[3])
			
			Case "vt"
				If line.length<2 Return
				AppendFloat texcoords,Float(line[1])
				AppendFloat texcoords,-Float(line[2])
			
			Case "vn"
				If line.length<3 Return
				nx=Float(line[1])
				ny=Float(line[2])
				nz=Float(line[3])
				m=Sqr(nx*nx+ny*ny+nz*nz)
				nx:/m
				ny:/m
				nz:/m
				AppendFloat normal,nx
				AppendFloat normal,ny
				AppendFloat normal,nz
			
			Case "s"
				If line.length>1
					currentsmoothgroup=Int(line[1])
				EndIf
				
			Case "f"
				Local indice[line.length-1]
				
				Local verts:TObjVert[indice.length]
				face=New TObjFace
				face.verts=verts
				face.smoothgroup=currentsmoothgroup
				
				For n=0 To indice.length-1
					indices=line[n+1].split("/")
					tu=0
					tv=0
					nx=0
					ny=0
					nz=0
					
					vert=New TObjVert
					
					v=Int(indices[0])-1
					x#=position.PeekFloat(v*12+0)
					y#=position.PeekFloat(v*12+4)
					z#=position.PeekFloat(v*12+8)
					If indices.length>1
						v=Int(indices[1])-1
						tu#=texcoords.PeekFloat(v*8+0)
						tv#=texcoords.PeekFloat(v*8+4)
						If indices.length>2
							v=Int(indices[2])-1
							nx#=normal.PeekFloat(v*12+0)
							ny#=normal.PeekFloat(v*12+4)
							nz#=normal.PeekFloat(v*12+8)
							vert.normalsdefined=True
						EndIf
					EndIf
					
					vert.x=x
					vert.y=y
					vert.z=z
					vert.nx=nx
					vert.ny=ny
					vert.nz=nz
					vert.u=tu
					vert.v=tv
					face.verts[n]=vert
				Next
				
				'For Local n=2 To indice.length-1
				'	surf.addtriangle indice[n],indice[0],indice[n-1]
				'	sumindices:+3
				'Next
				
		EndSelect
	Wend
	
	'Calculate face normals
	For face=EachIn TObjFace.list
		If face.verts.length<3 Continue
		TriangleNormal(face.verts[0].x,face.verts[0].y,face.verts[0].z,face.verts[1].x,face.verts[1].y,face.verts[1].z,face.verts[2].x,face.verts[2].y,face.verts[2].z)
		face.nx=vector_x
		face.ny=vector_y
		face.nz=vector_z
		For n=0 To face.verts.length-1
			If Not face.verts[n].normalsdefined ' use hard edges for verts with undefined normal
				face.verts[n].nx=face.nx
				face.verts[n].ny=face.ny
				face.verts[n].nz=face.nz
			EndIf
		Next
	Next
	
	For face=EachIn TObjFace.list
		If face.smoothgroup
			For n=0 To face.verts.length-1
				nx#=face.nx
				ny#=face.ny
				nz#=face.nz
				avg#=1.0
				For face2=EachIn TObjFace.list' this part is highly inefficient, but don't give a fuck
					If face=face2 Continue
					If face.smoothgroup<>face2.smoothgroup Continue
					For n2=0 To face2.verts.length-1
						If Abs(face.verts[n].x-face2.verts[n2].x)>0.01 Continue
						If Abs(face.verts[n].y-face2.verts[n2].y)>0.01 Continue
						If Abs(face.verts[n].z-face2.verts[n2].z)>0.01 Continue
						nx:+face2.nx
						ny:+face2.ny
						nz:+face2.nz
						avg:+1
						n2=face2.verts.length-1
					Next
				Next
				face.verts[n].nx=nx/avg
				face.verts[n].ny=ny/avg
				face.verts[n].nz=nz/avg
			Next
		EndIf
	Next
	
	'Add triangles
	For face=EachIn TObjFace.list
		For n=0 To face.verts.length-1
			face.verts[n].index=surf.FindVertex(face.verts[n].x,face.verts[n].y,face.verts[n].z,face.verts[n].nx,face.verts[n].ny,face.verts[n].nz,face.verts[n].u,face.verts[n].v)
			If n>1
				surf.addtriangle face.verts[n].index,face.verts[0].index,face.verts[n-1].index
				sumindices:+3
			EndIf
		Next
	Next
	
	Return sumindices+1
EndFunction

Type TObjVert
	Field x#,y#,z#
	Field nx#,ny#,nz#
	Field u#,v#
	Field index
	Field normalsdefined
EndType

Type TObjFace
	Global list:TList=New TList
	
	Method New()
		list.addfirst(Self)
	EndMethod
	
	Field nx#,ny#,nz#
	Field verts:TObjVert[]
	Field smoothgroup
EndType

Global VECTOR_x#
Global VECTOR_y#
Global VECTOR_z#

Function TriangleNormal(Ax#,Ay#,Az#,Bx#,By#,Bz#,Cx#,Cy#,Cz#)
	Local ux#,uy#,uz#,vx#,vy#,vz#,vec:TVec4
	ux#=bx-ax
	uy#=by-ay
	uz#=bz-az
	vx#=cx-bx
	vy#=cy-by
	vz#=cz-bz
	VECTOR_x=uy#*vz#-uz#*vy#
	VECTOR_y=uz#*vx#-ux#*vz#
	VECTOR_z=ux#*vy#-uy#*vx#
	Local m#=Sqr(VECTOR_x*VECTOR_x+VECTOR_y*VECTOR_y+VECTOR_z*VECTOR_z)
	VECTOR_x:/m
	VECTOR_y:/m
	VECTOR_z:/m
EndFunction