March 05, 2021, 07:32:48 AM

Author Topic: [bmx] BSP Parser by N [ 1+ years ago ]  (Read 638 times)

Offline BlitzBot

[bmx] BSP Parser by N [ 1+ years ago ]
« on: June 29, 2017, 12:28:40 AM »
Title : BSP Parser
Author : N
Posted : 1+ years ago

Description : 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 <a href="http://graphics.cs.brown.edu/games/quake/quake3.html" target="_blank">here[/url] and <a href="http://graphics.stanford.edu/~kekoa/q3/" target="_blank">here[/url].


Code :
Code: BlitzMax
  1. Strict
  2.  
  3. Import Brl.Blitz
  4. Import Brl.Stream
  5. Import Brl.Bank
  6. Import Brl.BankStream
  7. 'Import Cower.Math3D
  8. Import "resource.bmx"
  9.  
  10. Private
  11.  
  12. Const MAGIC_BSP% = $50534249
  13.  
  14. Const BSP_ENTITIES% = 0
  15. Const BSP_TEXTURES% = 1
  16. Const BSP_PLANES% = 2
  17. Const BSP_NODES% = 3
  18. Const BSP_LEAVES% = 4
  19. Const BSP_LEAFFACES% = 5
  20. Const BSP_LEAFBRUSHES% = 6
  21. Const BSP_MODELS% = 7
  22. Const BSP_BRUSHES% = 8
  23. Const BSP_BRUSHSIDES% = 9
  24. Const BSP_VERTICES% = 10
  25. Const BSP_MESHVERTS% = 11
  26. Const BSP_EFFECTS% = 12
  27. Const BSP_FACES% = 12
  28. Const BSP_LIGHTMAPS% = 14
  29. Const BSP_LIGHTVOLS% = 15
  30. Const BSP_VIS% = 16
  31.  
  32. Type bsplump
  33.     Field offset%
  34.     Field length%
  35. End Type
  36.  
  37. Public
  38.  
  39. Type bspdata
  40.     Field entities:bspentity[]
  41.     Field textures:bsptexture[]
  42.     Field planes:bspplane[]
  43.     Field nodes:bspnode[]
  44.     Field leaves:bspleaf[]
  45.     Field leaffaces%[]
  46.     Field leafbrushes%[]
  47.     Field models:bspmodel[]
  48.     Field brushes:bspbrush[]
  49.     Field brushsides:bspbrushside[]
  50.     Field vertices:bspvertex[]
  51.     Field meshverts%[]
  52.     Field effects:bspeffect[]
  53.     Field faces:bspface[]
  54.     Field lightmaps:TBank[]
  55.     Field lightvols:bsplightvol[]
  56.     Field vis:bspvis
  57. End Type
  58.  
  59. Function LoadBSP:bspdata( url:Object )
  60.     Rem
  61.     Local res:TBank = GetResource( StripExt(n)+".bsp" )
  62.     If res = Null Then
  63.         Debuglog "BSP file does not exist"
  64.         Return
  65.     EndIf
  66.    
  67.     If res.PeekInt( 0 ) <> MAGIC_BSP Or res.PeekInt( 4 ) <> $2E Then
  68.         Debuglog "Resource is not a valid BSP, version: "+res.PeekInt( 4 )+"  magic: "+res.PeekInt( 0 )
  69.         Return
  70.     EndIf
  71.    
  72.     Local s:TStream = ReadStream( res )
  73.     s.Seek( 8 )
  74.     EndRem  ' code from indigo, won't work unless you've got the engine
  75.     Local s:TStream = OpenStream( url, True, False )
  76.     If s.ReadInt( ) <> MAGIC_BSP Then
  77.         Debuglog "Resource is not a valid BSP - magic int didn't match"
  78.         s.Close( )
  79.         Return Null
  80.     EndIf
  81.    
  82.     If s.ReadInt( ) <> $2E Then
  83.         Debuglog "BSP version is not supported"
  84.         s.Close( )
  85.         Return Null
  86.     EndIf
  87.    
  88.     s.Seek( 8 ) ' Just in case
  89.     Local lumps:bsplump[17]
  90.     For Local i:Int = 0 To 16
  91.         lumps[i] = New bsplump
  92.         s.ReadBytes( Varptr lumps[i].offset, 8 )
  93.         Debuglog "  lump: "+i+"  offset: "+lumps[i].offset+"  length: "+lumps[i].length
  94.     Next
  95.    
  96.     Local bsp:bspdata = New bspdata
  97.     bsp.entities = BSP_ParseEntities( s, lumps[BSP_ENTITIES] )
  98.     bsp.textures = BSP_ParseTextures( s, lumps[BSP_TEXTURES] )
  99.     bsp.planes = BSP_ParsePlanes( s, lumps[BSP_PLANES] )
  100.     bsp.nodes = BSP_ParseNodes( s, lumps[BSP_NODES] )
  101.     bsp.leaves = BSP_ParseLeaves( s, lumps[BSP_LEAVES] )
  102.     bsp.leaffaces = BSP_ParseLeafFaces( s, lumps[BSP_LEAFFACES] )
  103.     bsp.leafbrushes = BSP_ParseLeafBrushes( s, lumps[BSP_LEAFBRUSHES] )
  104.     bsp.models = BSP_ParseModels( s, lumps[BSP_MODELS] )
  105.     bsp.brushes = BSP_ParseBrushes( s, lumps[BSP_BRUSHES] )
  106.     bsp.brushsides = BSP_ParseBrushSides( s, lumps[BSP_BRUSHSIDES] )
  107.     bsp.vertices = BSP_ParseVertices( s, lumps[BSP_VERTICES] )
  108.     bsp.meshverts = BSP_ParseMeshVertices( s, lumps[BSP_MESHVERTS] )
  109.     bsp.effects = BSP_ParseEffects( s, lumps[BSP_EFFECTS] )
  110.     bsp.faces = BSP_ParseFaces( s, lumps[BSP_FACES] )
  111.     bsp.lightmaps = BSP_ParseLightmaps( s, lumps[BSP_LIGHTMAPS] )
  112.     bsp.lightvols = BSP_ParseLightVols( s, lumps[BSP_LIGHTVOLS] )
  113.     bsp.vis = BSP_ParseVisData( s, lumps[BSP_VIS] )
  114.    
  115.     s.Close( )
  116.     Return bsp
  117. End Function
  118.  
  119. '-------------- entities
  120. Type bspkey
  121.     Field name$
  122.     Field value$
  123. End Type
  124.  
  125. Type bspentity
  126.     Field keys:TList = New TList
  127.    
  128.     Method GetKey$( name$, _default$="" )
  129.         For Local i:bspkey = EachIn keys
  130.             If i.name = name Then Return i.value
  131.         Next
  132.         Local i:bspkey = New bspkey
  133.         keys.AddLast( i )
  134.         i.name = name
  135.         i.value = _default
  136.         Return _default
  137.     End Method
  138. End Type
  139.  
  140. Private
  141.  
  142. Function BSP_ParseEntities:bspentity[]( s:TStream, lump:bsplump )
  143.     s.Seek( lump.offset )
  144.     Local entityString$ = s.ReadString( lump.Length )
  145.     Local entities:TList = New TList
  146.     Local c$, state%, val$, nam$, ent:bspentity
  147.     For Local i:Int = 0 To entityString.Length-1
  148.         c = Chr(entityString[i])
  149.        
  150.         Select c
  151.             Case "{"
  152.                 Debuglog "new entity opened"
  153.                 ent = New bspentity
  154.                 entities.AddLast( ent )
  155.             Case "}"
  156.                 ent = Null
  157.             Case "~q"
  158.                 If state < 3 Then
  159.                     state :+ 1
  160.                 ElseIf state = 3 Then
  161.                     Local k:bspkey = New bspkey
  162.                     k.name = nam
  163.                     k.value = val
  164.                     ent.keys.AddLast( k )
  165.                     Debuglog "  adding bspkey to entity, name: "+nam+"  value: "+val
  166.                     k = Null
  167.                     nam = ""
  168.                     val = ""
  169.                     state = 0
  170.                 EndIf
  171.             Default
  172.                 Select state
  173.                     Case 1
  174.                         nam :+ c
  175.                     Case 3
  176.                         val :+ c
  177.                 End Select
  178.         End Select
  179.     Next
  180.     Return bspentity[](entities.ToArray( ))
  181. End Function
  182.  
  183.  
  184. '------------- textures
  185. Public
  186. Type bsptexture
  187.     Field name$
  188.     Field flags%
  189.     Field content%
  190. End Type
  191.  
  192. Private
  193. Function BSP_ParseTextures:bsptexture[]( s:TStream, lump:bsplump )
  194.     s.Seek( lump.offset )
  195.     Local textures:bsptexture[lump.length/72]
  196.    
  197.     For Local i:Int = 0 To textures.Length-1
  198.         Local name$ = s.ReadString( 64 ).Trim( )
  199.         Local flags% = s.ReadInt( )
  200.         Local content% = s.ReadInt( )
  201.         Local tex:bsptexture = New bsptexture
  202.         tex.name = name
  203.         tex.flags = flags
  204.         tex.content = content
  205.         textures[i] = tex
  206.         Debuglog "  texture name: "+name+"  flags: "+flags+"  content: "+content
  207.     Next
  208.     Return textures
  209. End Function
  210.  
  211.  
  212. '------------------- planes
  213. Public
  214. Type bspplane
  215.     Field x#,y#,z#,d#
  216. End Type
  217.  
  218. Private
  219. Function BSP_ParsePlanes:bspplane[]( s:TStream, lump:bsplump )
  220.     s.Seek( lump.offset )
  221.     Local planes:bspplane[lump.length/12]
  222.     For Local i:Int = 0 To planes.Length-1
  223.         planes[i] = New bspplane
  224.         s.ReadBytes( Varptr planes[i].x, 12 )
  225.         Debuglog "  plane: "+planes[i].x+", "+planes[i].y+", "+planes[i].z+", "+planes[i].d
  226.     Next
  227.     Return planes
  228. End Function
  229.  
  230.  
  231. '------------- nodes
  232. Public
  233. Type bspnode
  234.     Field planei%
  235.     Field childa%
  236.     Field childb%
  237.     Field minx%
  238.     Field miny%
  239.     Field minz%
  240.     Field maxx%
  241.     Field maxy%
  242.     Field maxz%
  243. End Type
  244.  
  245. Private
  246. Function BSP_ParseNodes:bspnode[]( s:TStream, lump:bsplump )
  247.     s.Seek( lump.offset )
  248.     Local nodes:bspnode[lump.length/36]
  249.     For Local i:Int = 0 To nodes.Length-1
  250.         nodes[i] = New bspnode
  251.         s.ReadBytes( Varptr nodes[i].planei, 36 )
  252.     Next
  253.     Return nodes
  254. End Function
  255.  
  256.  
  257. '------------- leaves
  258. Public
  259. Type bspleaf
  260.     Field cluster%
  261.     Field area%
  262.     Field minx%, miny%, minz%
  263.     Field maxx%, maxy%, maxz%
  264.     Field face%, faces%
  265.     Field brush%, brushes%
  266. End Type
  267.  
  268. Private
  269. Function BSP_ParseLeaves:bspleaf[]( s:TStream, lump:bsplump )
  270.     s.Seek( lump.offset )
  271.     Local leaves:bspleaf[lump.length/Sizeof(bspleaf)]
  272.     For Local i:Int = 0 To leaves.Length-1
  273.         leaves[i] = New bspleaf
  274.         s.ReadBytes( Varptr leaves[i].cluster, Sizeof(bspleaf) )
  275.     Next
  276.     Return leaves
  277. End Function
  278.  
  279.  
  280. '---------------- leaf faces
  281. Private
  282. Function BSP_ParseLeafFaces%[]( s:TStream, lump:bsplump )
  283.     Local arr%[lump.Length/4]
  284.     s.Seek( lump.offset )
  285.     s.ReadBytes( arr, lump.length )
  286.     Return arr
  287. End Function
  288.  
  289.  
  290. '--------------- leaf brushes
  291. Private
  292. Function BSP_ParseLeafBrushes%[]( s:TStream, lump:bsplump )
  293.     Local arr%[lump.Length/4]
  294.     s.Seek( lump.offset )
  295.     s.ReadBytes( arr, lump.length )
  296.     Return arr
  297. End Function
  298.  
  299.  
  300. '--------------- models
  301. Public
  302. Type bspmodel
  303.     Field minx#, miny#, minz#
  304.     Field maxx#, maxy#, maxz#
  305.     Field face%, faces%
  306.     Field brush%, brushes%
  307. End Type
  308.  
  309. Private
  310. Function BSP_ParseModels:bspmodel[]( s:TStream, lump:bsplump )
  311.     s.Seek( lump.offset )
  312.     Local models:bspmodel[lump.length/Sizeof(bspmodel)]
  313.     For Local i:Int = 0 To models.Length-1
  314.         models[i] = New bspmodel
  315.         s.ReadBytes( Varptr models[i].minx, Sizeof(bspmodel) )
  316.     Next
  317.     Return models
  318. End Function
  319.  
  320.  
  321. '---------------- brushes
  322. Public
  323. Type bspbrush
  324.     Field side%, sides%
  325.     Field texture%
  326. End Type
  327.  
  328. Private
  329. Function BSP_ParseBrushes:bspbrush[]( s:TStream, lump:bsplump )
  330.     s.Seek( lump.offset )
  331.     Local brushes:bspbrush[lump.length/Sizeof(bspbrush)]
  332.     For Local i:Int = 0 To brushes.Length-1
  333.         brushes[i] = New bspbrush
  334.         s.ReadBytes( Varptr brushes[i].side, Sizeof(bspbrush) )
  335.     Next
  336.     Return brushes
  337. End Function
  338.  
  339.  
  340. '--------------- brush sides
  341. Public
  342. Type bspbrushside
  343.     Field planei%
  344.     Field texture%
  345. End Type
  346.  
  347. Private
  348. Function BSP_ParseBrushSides:bspbrushside[]( s:TStream, lump:bsplump )
  349.     s.Seek( lump.offset )
  350.     Local sides:bspbrushside[lump.length/Sizeof(bspbrushside)]
  351.     For Local i:Int = 0 To sides.Length-1
  352.         sides[i] = New bspbrushside
  353.         s.ReadBytes( Varptr sides[i].planei, Sizeof(bspbrushside) )
  354.     Next
  355.     Return sides
  356. End Function
  357.  
  358.  
  359. '-------------- vertices
  360. Public
  361. Type bspvertex
  362.     Field x#,y#,z#
  363.     Field su#,sv#
  364.     Field lu#,lv#
  365.     Field nx#, ny#, nz#
  366.     Field r@, g@, b@, a@
  367. End Type
  368.  
  369. Private
  370. Function BSP_ParseVertices:bspvertex[]( s:TStream, lump:bsplump )
  371.     s.Seek( lump.offset )
  372.     Local vertices:bspvertex[lump.length/Sizeof(bspvertex)]
  373.     For Local i:Int = 0 To vertices.Length-1
  374.         vertices[i] = New bspvertex
  375.         s.ReadBytes( Varptr vertices[i].x, Sizeof(bspvertex) )
  376.     Next
  377.     Return vertices
  378. End Function
  379.  
  380.  
  381. '---------------- meshverts
  382. Private
  383. Function BSP_ParseMeshVertices%[]( s:TStream, lump:bsplump )
  384.     Local arr%[lump.Length/4]
  385.     s.Seek( lump.offset )
  386.     s.ReadBytes( arr, lump.length )
  387.     Return arr
  388. End Function
  389.  
  390.  
  391. '---------------- effects
  392. Public
  393. Type bspeffect
  394.     Field name$
  395.     Field brush%
  396.     Field unknown%
  397. End Type
  398.  
  399. Private
  400. Function BSP_ParseEffects:bspeffect[]( s:TStream, lump:bsplump )
  401.     s.Seek( lump.offset )
  402.     Local effects:bspeffect[lump.length/Sizeof(bspeffect)]
  403.     For Local i:Int = 0 To effects.Length-1
  404.         effects[i] = New bspeffect
  405.         effects[i].name = s.ReadString(64).Trim( )
  406.         s.ReadBytes( Varptr effects[i].brush, 8 )
  407.     Next
  408.     Return effects
  409. End Function
  410.  
  411.  
  412. '------------------ faces
  413. Public
  414. Type bspface
  415.     Field texture%
  416.     Field effect%
  417.     Field _type%
  418.     Field vertex%
  419.     Field vertices%
  420.     Field meshvert%
  421.     Field meshverts%
  422.     Field lightmap%
  423.     Field lmx%, lmy%
  424.     Field lmw%, lmh%
  425.     Field lmox#, lmoy#, lmoz#
  426.     Field lmsx#, lmsy#, lmsz#
  427.     Field lmtx#, lmty#, lmtz#
  428.     Field nx#, ny#, nz#
  429.     Field pw%, ph%
  430. End Type
  431.  
  432. Private
  433. Function BSP_ParseFaces:bspface[]( s:TStream, lump:bsplump )
  434.     s.Seek( lump.offset )
  435.     Local faces:bspface[lump.length/Sizeof(bspface)]
  436.     For Local i:Int = 0 To faces.Length-1
  437.         faces[i] = New bspface
  438.         s.ReadBytes( Varptr faces[i].texture, Sizeof(bspface) )
  439.     Next
  440.     Return faces
  441. End Function
  442.  
  443.  
  444. '----------------- lightmaps
  445. Private
  446. Function BSP_ParseLightmaps:TBank[]( s:TStream, lump:bsplump )
  447.     s.Seek( lump.offset )
  448.     Local lm:TBank[lump.Length/49152]
  449.     For Local i:Int = 0 To lm.Length - 1
  450.         lm[i] = TBank.Create( 49152 )
  451.         s.ReadBytes( lm[i].Buf( ), 49152 )
  452.     Next
  453.     Return lm
  454. End Function
  455.  
  456.  
  457. '----------------- light vols
  458. Public
  459. Type bsplightvol
  460.     Field ar@, ag@, ab@
  461.     Field dr@, dg@, db@
  462.     Field du@, dv@
  463. End Type
  464.  
  465. Private
  466. Function BSP_ParseLightVols:bsplightvol[]( s:TStream, lump:bsplump )
  467.     s.Seek( lump.offset )
  468.     Local lv:bsplightvol[lump.length/8]
  469.     For Local i:Int = 0 To lv.Length-1
  470.         lv[i] = New bsplightvol
  471.         s.ReadBytes( Varptr lv[i].ar, 8 )
  472.     Next
  473.     Return lv
  474. End Function
  475.  
  476.  
  477. '----------------- vis
  478. Public
  479. Type bspvis
  480.     Field n_vecs%
  481.     Field sz_vecs%
  482.     Field vecs@ Ptr
  483.    
  484.     Method Delete( )
  485.         If vecs Then MemFree( vecs )
  486.     End Method
  487. End Type
  488.  
  489. Private
  490. Function BSP_ParseVisData:bspvis( s:TStream, lump:bsplump )
  491.     s.Seek( lump.offset )
  492.     Local vis:bspvis = New bspvis
  493.     vis.n_vecs = s.ReadInt( )
  494.     vis.sz_vecs = s.ReadInt( )
  495.     Debuglog "  vis size: "+(vis.n_vecs*vis.sz_vecs)
  496.     If vis.n_vecs > 0 And vis.sz_vecs > 0 Then
  497.         vis.vecs = MemAlloc( vis.n_vecs*vis.sz_vecs )
  498.         s.ReadBytes( vis.vecs, vis.n_vecs*vis.sz_vecs )
  499.     EndIf
  500.     Return vis
  501. End Function


Comments : none...

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal