Code archives/File Utilities/BSP Parser
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
What the title says. This will parse and read the data of a BSP file into memory in the manner it was meant to be organized in. Unfortunately, since there is no standard 3D engine (yet?), this is the best I can offer without open sourcing the rest of my code (which has yet to be determined). If you have an engine and want to add BSP support to it, this is probably a good start at the least for figuring out what data is in a BSP (and isolating specific parts of it without writing your own parser). Anyhow, all details were gathered from here and here. | |||||
Strict Import Brl.Blitz Import Brl.Stream Import Brl.Bank Import Brl.BankStream 'Import Cower.Math3D Import "resource.bmx" Private Const MAGIC_BSP% = $50534249 Const BSP_ENTITIES% = 0 Const BSP_TEXTURES% = 1 Const BSP_PLANES% = 2 Const BSP_NODES% = 3 Const BSP_LEAVES% = 4 Const BSP_LEAFFACES% = 5 Const BSP_LEAFBRUSHES% = 6 Const BSP_MODELS% = 7 Const BSP_BRUSHES% = 8 Const BSP_BRUSHSIDES% = 9 Const BSP_VERTICES% = 10 Const BSP_MESHVERTS% = 11 Const BSP_EFFECTS% = 12 Const BSP_FACES% = 12 Const BSP_LIGHTMAPS% = 14 Const BSP_LIGHTVOLS% = 15 Const BSP_VIS% = 16 Type bsplump Field offset% Field length% End Type Public Type bspdata Field entities:bspentity[] Field textures:bsptexture[] Field planes:bspplane[] Field nodes:bspnode[] Field leaves:bspleaf[] Field leaffaces%[] Field leafbrushes%[] Field models:bspmodel[] Field brushes:bspbrush[] Field brushsides:bspbrushside[] Field vertices:bspvertex[] Field meshverts%[] Field effects:bspeffect[] Field faces:bspface[] Field lightmaps:TBank[] Field lightvols:bsplightvol[] Field vis:bspvis End Type Function LoadBSP:bspdata( url:Object ) Rem Local res:TBank = GetResource( StripExt(n)+".bsp" ) If res = Null Then Debuglog "BSP file does not exist" Return EndIf If res.PeekInt( 0 ) <> MAGIC_BSP Or res.PeekInt( 4 ) <> $2E Then Debuglog "Resource is not a valid BSP, version: "+res.PeekInt( 4 )+" magic: "+res.PeekInt( 0 ) Return EndIf Local s:TStream = ReadStream( res ) s.Seek( 8 ) EndRem ' code from indigo, won't work unless you've got the engine Local s:TStream = OpenStream( url, True, False ) If s.ReadInt( ) <> MAGIC_BSP Then Debuglog "Resource is not a valid BSP - magic int didn't match" s.Close( ) Return Null EndIf If s.ReadInt( ) <> $2E Then Debuglog "BSP version is not supported" s.Close( ) Return Null EndIf s.Seek( 8 ) ' Just in case Local lumps:bsplump[17] For Local i:Int = 0 To 16 lumps[i] = New bsplump s.ReadBytes( Varptr lumps[i].offset, 8 ) Debuglog " lump: "+i+" offset: "+lumps[i].offset+" length: "+lumps[i].length Next Local bsp:bspdata = New bspdata bsp.entities = BSP_ParseEntities( s, lumps[BSP_ENTITIES] ) bsp.textures = BSP_ParseTextures( s, lumps[BSP_TEXTURES] ) bsp.planes = BSP_ParsePlanes( s, lumps[BSP_PLANES] ) bsp.nodes = BSP_ParseNodes( s, lumps[BSP_NODES] ) bsp.leaves = BSP_ParseLeaves( s, lumps[BSP_LEAVES] ) bsp.leaffaces = BSP_ParseLeafFaces( s, lumps[BSP_LEAFFACES] ) bsp.leafbrushes = BSP_ParseLeafBrushes( s, lumps[BSP_LEAFBRUSHES] ) bsp.models = BSP_ParseModels( s, lumps[BSP_MODELS] ) bsp.brushes = BSP_ParseBrushes( s, lumps[BSP_BRUSHES] ) bsp.brushsides = BSP_ParseBrushSides( s, lumps[BSP_BRUSHSIDES] ) bsp.vertices = BSP_ParseVertices( s, lumps[BSP_VERTICES] ) bsp.meshverts = BSP_ParseMeshVertices( s, lumps[BSP_MESHVERTS] ) bsp.effects = BSP_ParseEffects( s, lumps[BSP_EFFECTS] ) bsp.faces = BSP_ParseFaces( s, lumps[BSP_FACES] ) bsp.lightmaps = BSP_ParseLightmaps( s, lumps[BSP_LIGHTMAPS] ) bsp.lightvols = BSP_ParseLightVols( s, lumps[BSP_LIGHTVOLS] ) bsp.vis = BSP_ParseVisData( s, lumps[BSP_VIS] ) s.Close( ) Return bsp End Function '-------------- entities Type bspkey Field name$ Field value$ End Type Type bspentity Field keys:TList = New TList Method GetKey$( name$, _default$="" ) For Local i:bspkey = EachIn keys If i.name = name Then Return i.value Next Local i:bspkey = New bspkey keys.AddLast( i ) i.name = name i.value = _default Return _default End Method End Type Private Function BSP_ParseEntities:bspentity[]( s:TStream, lump:bsplump ) s.Seek( lump.offset ) Local entityString$ = s.ReadString( lump.Length ) Local entities:TList = New TList Local c$, state%, val$, nam$, ent:bspentity For Local i:Int = 0 To entityString.Length-1 c = Chr(entityString[i]) Select c Case "{" Debuglog "new entity opened" ent = New bspentity entities.AddLast( ent ) Case "}" ent = Null Case "~q" If state < 3 Then state :+ 1 ElseIf state = 3 Then Local k:bspkey = New bspkey k.name = nam k.value = val ent.keys.AddLast( k ) Debuglog " adding bspkey to entity, name: "+nam+" value: "+val k = Null nam = "" val = "" state = 0 EndIf Default Select state Case 1 nam :+ c Case 3 val :+ c End Select End Select Next Return bspentity[](entities.ToArray( )) End Function '------------- textures Public Type bsptexture Field name$ Field flags% Field content% End Type Private Function BSP_ParseTextures:bsptexture[]( s:TStream, lump:bsplump ) s.Seek( lump.offset ) Local textures:bsptexture[lump.length/72] For Local i:Int = 0 To textures.Length-1 Local name$ = s.ReadString( 64 ).Trim( ) Local flags% = s.ReadInt( ) Local content% = s.ReadInt( ) Local tex:bsptexture = New bsptexture tex.name = name tex.flags = flags tex.content = content textures[i] = tex Debuglog " texture name: "+name+" flags: "+flags+" content: "+content Next Return textures End Function '------------------- planes Public Type bspplane Field x#,y#,z#,d# End Type Private Function BSP_ParsePlanes:bspplane[]( s:TStream, lump:bsplump ) s.Seek( lump.offset ) Local planes:bspplane[lump.length/12] For Local i:Int = 0 To planes.Length-1 planes[i] = New bspplane s.ReadBytes( Varptr planes[i].x, 12 ) Debuglog " plane: "+planes[i].x+", "+planes[i].y+", "+planes[i].z+", "+planes[i].d Next Return planes End Function '------------- nodes Public Type bspnode Field planei% Field childa% Field childb% Field minx% Field miny% Field minz% Field maxx% Field maxy% Field maxz% End Type Private Function BSP_ParseNodes:bspnode[]( s:TStream, lump:bsplump ) s.Seek( lump.offset ) Local nodes:bspnode[lump.length/36] For Local i:Int = 0 To nodes.Length-1 nodes[i] = New bspnode s.ReadBytes( Varptr nodes[i].planei, 36 ) Next Return nodes End Function '------------- leaves Public Type bspleaf Field cluster% Field area% Field minx%, miny%, minz% Field maxx%, maxy%, maxz% Field face%, faces% Field brush%, brushes% End Type Private Function BSP_ParseLeaves:bspleaf[]( s:TStream, lump:bsplump ) s.Seek( lump.offset ) Local leaves:bspleaf[lump.length/Sizeof(bspleaf)] For Local i:Int = 0 To leaves.Length-1 leaves[i] = New bspleaf s.ReadBytes( Varptr leaves[i].cluster, Sizeof(bspleaf) ) Next Return leaves End Function '---------------- leaf faces Private Function BSP_ParseLeafFaces%[]( s:TStream, lump:bsplump ) Local arr%[lump.Length/4] s.Seek( lump.offset ) s.ReadBytes( arr, lump.length ) Return arr End Function '--------------- leaf brushes Private Function BSP_ParseLeafBrushes%[]( s:TStream, lump:bsplump ) Local arr%[lump.Length/4] s.Seek( lump.offset ) s.ReadBytes( arr, lump.length ) Return arr End Function '--------------- models Public Type bspmodel Field minx#, miny#, minz# Field maxx#, maxy#, maxz# Field face%, faces% Field brush%, brushes% End Type Private Function BSP_ParseModels:bspmodel[]( s:TStream, lump:bsplump ) s.Seek( lump.offset ) Local models:bspmodel[lump.length/Sizeof(bspmodel)] For Local i:Int = 0 To models.Length-1 models[i] = New bspmodel s.ReadBytes( Varptr models[i].minx, Sizeof(bspmodel) ) Next Return models End Function '---------------- brushes Public Type bspbrush Field side%, sides% Field texture% End Type Private Function BSP_ParseBrushes:bspbrush[]( s:TStream, lump:bsplump ) s.Seek( lump.offset ) Local brushes:bspbrush[lump.length/Sizeof(bspbrush)] For Local i:Int = 0 To brushes.Length-1 brushes[i] = New bspbrush s.ReadBytes( Varptr brushes[i].side, Sizeof(bspbrush) ) Next Return brushes End Function '--------------- brush sides Public Type bspbrushside Field planei% Field texture% End Type Private Function BSP_ParseBrushSides:bspbrushside[]( s:TStream, lump:bsplump ) s.Seek( lump.offset ) Local sides:bspbrushside[lump.length/Sizeof(bspbrushside)] For Local i:Int = 0 To sides.Length-1 sides[i] = New bspbrushside s.ReadBytes( Varptr sides[i].planei, Sizeof(bspbrushside) ) Next Return sides End Function '-------------- vertices Public Type bspvertex Field x#,y#,z# Field su#,sv# Field lu#,lv# Field nx#, ny#, nz# Field r@, g@, b@, a@ End Type Private Function BSP_ParseVertices:bspvertex[]( s:TStream, lump:bsplump ) s.Seek( lump.offset ) Local vertices:bspvertex[lump.length/Sizeof(bspvertex)] For Local i:Int = 0 To vertices.Length-1 vertices[i] = New bspvertex s.ReadBytes( Varptr vertices[i].x, Sizeof(bspvertex) ) Next Return vertices End Function '---------------- meshverts Private Function BSP_ParseMeshVertices%[]( s:TStream, lump:bsplump ) Local arr%[lump.Length/4] s.Seek( lump.offset ) s.ReadBytes( arr, lump.length ) Return arr End Function '---------------- effects Public Type bspeffect Field name$ Field brush% Field unknown% End Type Private Function BSP_ParseEffects:bspeffect[]( s:TStream, lump:bsplump ) s.Seek( lump.offset ) Local effects:bspeffect[lump.length/Sizeof(bspeffect)] For Local i:Int = 0 To effects.Length-1 effects[i] = New bspeffect effects[i].name = s.ReadString(64).Trim( ) s.ReadBytes( Varptr effects[i].brush, 8 ) Next Return effects End Function '------------------ faces Public Type bspface Field texture% Field effect% Field _type% Field vertex% Field vertices% Field meshvert% Field meshverts% Field lightmap% Field lmx%, lmy% Field lmw%, lmh% Field lmox#, lmoy#, lmoz# Field lmsx#, lmsy#, lmsz# Field lmtx#, lmty#, lmtz# Field nx#, ny#, nz# Field pw%, ph% End Type Private Function BSP_ParseFaces:bspface[]( s:TStream, lump:bsplump ) s.Seek( lump.offset ) Local faces:bspface[lump.length/Sizeof(bspface)] For Local i:Int = 0 To faces.Length-1 faces[i] = New bspface s.ReadBytes( Varptr faces[i].texture, Sizeof(bspface) ) Next Return faces End Function '----------------- lightmaps Private Function BSP_ParseLightmaps:TBank[]( s:TStream, lump:bsplump ) s.Seek( lump.offset ) Local lm:TBank[lump.Length/49152] For Local i:Int = 0 To lm.Length - 1 lm[i] = TBank.Create( 49152 ) s.ReadBytes( lm[i].Buf( ), 49152 ) Next Return lm End Function '----------------- light vols Public Type bsplightvol Field ar@, ag@, ab@ Field dr@, dg@, db@ Field du@, dv@ End Type Private Function BSP_ParseLightVols:bsplightvol[]( s:TStream, lump:bsplump ) s.Seek( lump.offset ) Local lv:bsplightvol[lump.length/8] For Local i:Int = 0 To lv.Length-1 lv[i] = New bsplightvol s.ReadBytes( Varptr lv[i].ar, 8 ) Next Return lv End Function '----------------- vis Public Type bspvis Field n_vecs% Field sz_vecs% Field vecs@ Ptr Method Delete( ) If vecs Then MemFree( vecs ) End Method End Type Private Function BSP_ParseVisData:bspvis( s:TStream, lump:bsplump ) s.Seek( lump.offset ) Local vis:bspvis = New bspvis vis.n_vecs = s.ReadInt( ) vis.sz_vecs = s.ReadInt( ) Debuglog " vis size: "+(vis.n_vecs*vis.sz_vecs) If vis.n_vecs > 0 And vis.sz_vecs > 0 Then vis.vecs = MemAlloc( vis.n_vecs*vis.sz_vecs ) s.ReadBytes( vis.vecs, vis.n_vecs*vis.sz_vecs ) EndIf Return vis End Function |
Comments
None.
Code Archives Forum