3DS questions.

BlitzMax Forums/BlitzMax Programming/3DS questions.

AntonyWells(Posted 2005) [#1]
I'm doing a 3ds loader for v2, and have a question..

The loader is working fine, but I've got to the final stage where I need to make sure of face mapping data(I.e the list of faces present for each material)
Do I apply linearly to the loaded faces(I.e regardless of which object they're a part of) or is it simply restricted to the parent object chunk?

Also, real reason for this post really is this little 'wierdity', the code for the loader thus far is below, and if you look for the Case $A200 construct, where it is supposed to load the texture name, you see I had to severly kludge that paticulary part because it seems there is in all 3ds an alien chunk before it, int value of 48.
Without the kludge it just fails to work...but I'm worried about this not being a common to all 3ds (And therefore making my loader incompatible with them)...Any ideas what the chunk's for?


Type Loader3DS Extends Loader
	
	Field LastSurf:Surface
	
	Method New()
	
		SetAuthor( "Antony Wells" )
		SetCopyright( "Antony Wells" )	
		SetVersion( "V1.0" )
		SetExt( "3ds" )
	
	End Method
	Method Delete()
		stream = Null
	End Method
	
	'Internal
	Function GetNewLoader:Loader3DS()
		Return New Loader3DS
	End Function
	
	Method RequestNew:Object()
	
		Local Out:Object = GetNewLoader()
		Return Object( Out ) 
	
	End Method
	
			
	Method ParseStream ()
		Local Name:String
		Local MatList:TList = CreateList()
		Local LastMat:Material
		Local vBase:Int,iBase:Int
		Local U:Float,V:Float
		Local V0:Int,V1:Int,V2:Int
		Local Face:Int,X:Float,Y:Float,Z:Float
		While Not Eof (Stream)
			LastId = Int(ReadShort( Stream ))
			LastLen = Readint( Stream )
		
			DebugLog "Chunk Hex>"+Hex( lastId )+" Len>"+LastLen				
			Select LastId
				
				Case MainChunk
				
			'		Main_Error.Invoke "Reached Main Chunk Len:"+LastLen,0
				
				Case EditorChunk
				
			'		Main_Error.Invoke "Reached Editor Chunk",0
				
				Case ObjectBlock
				
					Name = Self.ReadStr()
					DebugLog name+" Obj name"
			'		Main_Error.Invoke "Name >"+Name,0
					
				'	If Root = Null 
					
					'	Root = New TMesh
					'	Root.RenderState= False 
					'	Root.Name = Name
					'	vBase = 0
					'	iBase = 0
						
				'	End If
					Root.Name=Name	
					
				Case TriangularMesh
				
				Case MaterialBlock
				
			'		Main_Error.Invoke "Reached Material Block>",0
					LastMat = New Material
																	
				Case MaterialName	
					
					Local MatName:String = Self.ReadStr()
					DebugLog "Material Name>"+MatName
					
				Case $A010
				
				Case $A020
				
			
				Case $A200
							
					Local TexFile:String			
					'Local texfile:String = self.readstr(lastLen)
					lastid = Int(ReadShort( stream ))
					'While StreamPos( stream )<sstream+lastLen
					For Local j=1 To 4
						lastId = Int(ReadShort( stream ))
						lastLen = Readint( stream )
						If lastId = $a300
							texFile= self.readStr()
							Exit
						EndIf
						'			DebugLog "Id>"+LastId+" Hex>"+Hex(lastId)
						self.skipchunk()
					Next
					
					DebugLog "Loaded Texture >"+texfile
					
					'DebugStop
				
				Case $A300
				
					
						
					
				Case VerticesList
					
			'		Main_Error.Invoke "Reached Vertices List",0
					Local VertC = ReadShort( Stream )
			'		Main_Error.Invoke "Vertices:"+VertC,0
					'This prevents any other threads from accessing.
								
				
					LastSurf:Surface = Surface.create( vertC*3 )
								
																	
					For Local Vert:Int = 0 To VertC-1
						
						X = ReadFloat( Stream ) 
					 	Y = ReadFloat( Stream )
						Z = ReadFloat( Stream )
						
						LastSurf.AddVertex( Vertex.Create(X,Y,Z) )
						FlushMem
				
					Next
					
					Root.AddSurface( LastSurf )
					
								
				Case FacesList
				
			'		Main_Error.Invoke "Reached Faces List",0
					Local TriC = ReadShort( Stream )
			'		Main_Error.Invoke "Faces:"+TriC,0
					
					If LastSurf = Null Throw "No surface to add triangles to"
					
					For Local Tri:Int = 0 To TriC-1
						
						Local Va0:Int = ReadShort( Stream )
						Local Va1:Int = ReadShort( Stream )
						Local Va2:Int = ReadShort( Stream )
						Local Faace:Int = ReadShort( Stream)
						'If va1>lastsurf.vertcount Or v2>lastsurf.vertcount Or v0>lastsurf.vertcount
					'		Throw "Vertex ID>"+V0+" 1>"+V1+" 2>"+v2+" Max>"+lastsurf.vertcount
					'	EndIf								
						LastSurf.AddTriangle( Triangle.Create( lastsurf.getVertex(Va0),lastsurf.getVertex(Va1),lastsurf.getvertex(Va2) ))
						
						FlushMem
									
					Next
				
				Case CoordList
					
			'		Main_Error.Invoke "Reached Coords List",0
					Local CoordC:Int = ReadShort( Stream )
			'		Main_Error.Invoke "Coords:"+CoordC,0
				
					If LastSurf = Null Throw "No surface defined in 3ds prior to coord set"
					
					If coordC<>lastsurf.vertCount Throw "Coords>"+coordC+" Verts>"+lastsurf.vertcount
					
					For Local vert:vertex = EachIn lastsurf.verts
						
						
						U = ReadFloat( Stream )
						V = ReadFloat( Stream )
						
						
						vert.SetCoords( U,V,0 )
					
						FlushMem
						
					Next
					
				Case $4130
				
					Local matIs:String
					matIs = self.readStr()
					DebugLog "face map for :"+MatIs
					Local faceCount:Int = Int(ReadShort(stream))
					DebugLog "faceCount >"+FaceCount
					
					For Local j=0 To faceCount-1
						Local Face:Int = ReadShort(stream)
					Next
													
												
				Default
			
					SeekStream stream,StreamPos( Stream ) + (LastLen-6)
					FlushMem
			End Select
			
		Wend
	
		
	End Method
	
	Method SkipThis()
		SeekStream stream,StreamPos( Stream ) + (LastLen-6)
	End Method
	
	
	
	Method ReadStr:String(ReadBytes = 0)
		
		If LastID =0 Or LastLen = 0
	
			Throw "No Data to read in 3DS"
	
		End If
		
		Local Out:String,Char:String
		Local By:Byte
		
		If ReadBytes =0
		Repeat
		
			If Eof( Stream ) Throw "Unexpectly reached end of file while reading string in Loader3DS.ReadStr()"
			By=ReadByte( Stream ) 
			If By = 0 Exit
			Out=out + Chr( By )
		
		Forever
		Else
		Local fI:Short=0
		Repeat
		
			If Eof(stream) Throw "Unable to read that many bytes"
			by=ReadByte( stream )
			fi:+1
			out=out+Chr( by)
		Until fi=readBytes
		
		EndIf
		
		Return Out
				
	End Method
	
	Function NewMesh:Mesh()
		Return New Mesh
	End Function
	

	Method StreamLoad:Mesh( File:String) Final
		
	'	RequestLock( L3D_Lock )
			
	'	LoadThread:TThread = TThread.Create( Loader3DS_Parse )
	'	Stream = ReadFile( file )
	'	If Stream = Null Throw "Unable to read file File:"+file
	'	Root = Loader3DS.NewMesh()
	'	Root.Lock()
	'	Root.RenderState = False
	'	ActiveLoader =Loader3DS ( Self )
	'	LoadThread.Run() 'Thread unlocks L3d_Lock, this prevents cross thread 'boogy'
	'	Return Root
				
	End Method
	
	Method Load:Mesh( File:String ) Final
				
		'Main_Error.Invoke( FileSize( File ) , False )
		Stream = OpenStream( File,True,False )
		Root = New Mesh
		If Stream=Null Throw "Unable to read file File:"+File
		Self.ParseStream()
		If Root = Null Throw "Parse Finished without Mesh as result in Loader3DS.Load"
		Return Root
				
	End Method
	

	Method Reset()
	
		If Stream = Null Throw "No stream in Reset()"
		
		SeekStream Stream,0
			
	End Method
	
	Method Save:Mesh( File:String ) Final

	End Method
	
	Method EndStream:Int()
		
		If Stream = Null Throw "No Stream in Loader3DS.EndStream"
		Return Eof( Stream )
	
	End Method
	
	Method FindChunk:Int( ID:Int ,WrapStream:Int = False,ZeroStream:Int=False)
		
		Local WrapPoint:Int = StreamPos( Stream )
		Local EndPoint:Int = StreamSize( Stream ) 
		
		If ZeroStream
			SeekStream Stream,0
			WrapPoint = 0
		End If
		
		
		'Throw "Chunks:"+Self.CountChunks()
				
		Repeat
	
			While StreamPos( Stream ) < EndPoint
			
				Self.ReadChunk()
				If LastID = ID 
					Return True
				End If
				
				Self.SkipChunk()
									
			Wend
			If WrapStream 
				
				SeekStream Stream,0
				EndPoint = WrapPoint
				WrapStream = False 
			'	Main_Error.Invoke "Wrapped Stream"
				Continue
			'	Main_Error.Invoke "Uh...shit!"						
			End If
			
		'	Main_Error.Invoke "Fuck nuts!"
			
			Return False
			
		Forever
			
	End Method
	
	Method CountChunks:Int()
		Local Count:Int
		
		Self.SavePos()
		SeekStream Stream,0
		
		While Not EndStream()
			
			Self.ReadChunk()
			Self.SkipChunk()
			Count:+1
			
		Wend
		
		Self.LoadPos()
		
		Return Count
				
	End Method
	
	Method SavePos()
		
		If Stream = Null Throw "Stream not found in SavePos()"
		
		OldPos = StreamPos ( Stream)
		
	End Method
	
	Method LoadPos()
	
		If Stream = Null Throw "Stream not found In LoadPos()"
	
		SeekStream Stream,OldPos
		
	End Method
	
		
	Method ValidateChunk:Int()
	 Return True 'legacy. remove.
	End Method
		
	Method ParseChunk()
	
		Self.SkipChunk()
	
	End Method
	
	Method ReadChunk:Int( Count:Int = 1 )
		
		While Count > 0 
		
			If Stream = Null Throw "No Stream in Loader3DS.ReadChunk()"	
		
			LastID = ReadShort( Stream )
	
			LastLen = Readint( Stream ) 
		'	Main_Error.invoke "Chunk ID>"+LastID+" Length>"+LastLen
	
			Self.ValidateChunk()
			
			Count:-1
			
		Wend
		
	End Method
	
	Method SkipChunk()
		
		If lastId =0 Return 
		If lastId =8 Return 
		If LastLen=0 Throw "Cannot skip null chunk LastId:"+LastId
		If Stream = Null Throw "No Stream in Loader3DS.SkipChunk"
		
		SeekStream ( Stream, StreamPos( Stream )+LastLen )
	
	End Method
				
	Field LastID:Int,LastLen:Int
	'Field LoadThread:TThread
	Field Root:Mesh,OldPos:Int
	

End Type

Global Loader_3DS:Loader = New Loader3DS
FileIO.RegisterLoader( Loader_3DS )

Global ActiveLoader:Loader3DS
'Global ActiveLock = CreateLock()

Global L3D_Stack:Loader3DS[5000]
Global L3D_SLock[5000]
Global L3D_Index:Int =0 
'Global L3d_lock = Createlock()



Function Loader3DS_Parse:Int( bb_func:Byte Ptr)
Rem	
	If ActiveLoader = Null Throw "No active loader registered, unable to spawn thread"
	Local TLoad:Loader3DS = ActiveLoader
	ActiveLoader = Null 
	ReleaseLock( L3D_Lock )
	Local Ms=MilliSecs()
	TLoad.ParseStream()
	'Print "Stream took >"+String(MilliSecs()-Ms)+" Millisecs"
	
	RequestLock( TLoad.Root.RenderMutex )
	TLoad.Root.RenderState = True
	ReleaseLock( TLoad.Root.RenderMutex )
	
	TLoad.Root.Unlock()
	TLoad = Null

	Repeat
		Delay 5000
	Forever
	
End Rem
End Function


Private
Const MAINCHUNK=$4D4D
Const EDITORCHUNK=$3D3D
Const ObjectBLOCK=$4000
Const TRIANGULARMESH=$4100
Const VERTICESLIST=$4110
Const FacesList=$4120
Const FACESMATERIAL=$4130
Const CoordList =$4140
Const SMOOTHINGGROUPLIST=$4150
Const COORDINATESSYSTEM=$4160
Const LightChunk=$4600
Const SPOTLightChunk =$4610
Const CameraChunk =$4700
Const MATERIALBLOCK =$AFFF
Const MATERIALNAME =$A000
Const AMBIENTCOLOR =$A010
Const DIFFUSECOLOR =$A020
Const SPECULARCOLOR =$A030
Const TEXTUREMAP =$A200
Const BUMPMAP =$A230
Const REFLECTIONMAP=$A220
Const TextureMap1 =$A300
Const MAPPINGPARAMETERS =$A351
Const KEYFRAMERCHUNK =$B000
Const MESHINFORMATIONBLOCK =$B002
Const SPOTLightChunkINFORMATIONBLOCK =$B007
Const FramePoint =$B008
Const ObjectNAME =$B010
Const ObjectPIVOTPOINT =$B013
Const POSITIONTRACK =$B020
Const ROTATIONTRACK =$B021
Const SCALETRACK =$B022
Const HIERARCHYPOSITION =$B030