'///////////////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
'// Quake 3 .BSP File loader v.01 \\
'// By John Onyon a.k.a Unseen Machine \\
'///////////////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
'///////////////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
'// File path
Root$ = "C:\qb64\3d Programs\bsp" '// BSP Directory
CHDIR Root$
'// Change directory to where our stuff is
'///////////////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
'// Load the level
DIM SHARED Level
AS Level
'// DIM the memory for the level
DIM SHARED KB
(1) AS KeyBoardState
, Mouse
(1) AS MouseState
'// Input handlers
SLEEP 1 '// Give the screen time to be created
InitGl = True
AllowGL = True
'CLS
'// Input
GDK_Keyboard_GetState KB(0)
GDK_Mouse_GetState Mouse(0)
'// Logic
'_DISPLAY
_DELAY .005 '// Give the CPU Breather
'// Copy input handlers
Mouse(1) = Mouse(0)
KB(1) = KB(0)
'///////////////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
'///////////////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
'// GDK_GL - New type definition for handling .bsp levels. \\
ID
AS _BYTE '// Signifies the type of level (currently irrelevant as we dont support any other level formats) HeaderPntr
AS _MEM '// Level information header DataPntr
AS _MEM '// Level data - verts, normals, texture names etc... TexturePntr
AS _MEM '// A series of _unsigned longs of loaded textures
'///////////////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
'// BSP_Float2/3, BSP_Int2/3, BSP_RGBA, BSP_LM_VEC and BSP_Light are used where arrays inside types are needed.
Start
AS LONG '// Offset into file Size
AS LONG '// How big (number of bytes) it is
Magic
AS STRING * 4 '// Magic number. Always "IBSP". Version
AS LONG '// 0x2e for the BSP files distributed with Quake 3. DirEntries
AS _MEM '// Lump directory, seventeen entries of type BSP_DirEntry
Plane
AS LONG '// Plane index. Children
AS BSP_Int2
'// Children indices. Negative numbers are leaf indices: -(leaf+1). Mins
AS BSP_Int3
'// LONG bounding box min coord.
Cluster
AS LONG '// Visdata cluster index. Area
AS LONG '// Areaportal area. Mins
AS BSP_Int3
'// LONG bounding box min coord. Maxs
AS BSP_Int3
'// LONG bounding box max coord. LeafFace
AS LONG '// First leafface for leaf. NumLeafFaces
AS LONG '// Number of leaffaces for leaf. LeafBrush
AS LONG '// First leafbrush for leaf. NumLeafBrushes
AS LONG '// Number of leafbrushes for leaf.
Brush
AS LONG '// Brush index.
Mins
AS BSP_Float3
'// Bounding box min coord. Maxs
AS BSP_Float3
'// Bounding box max coord. Face
AS LONG '// First face for model. NumFaces
AS LONG '// Number of faces for model. Brush
AS LONG '// First brush for model. NumBrushes
AS LONG '// Number of brushes for model.
BrushSide
AS LONG '// First brushside for brush. NumBrushSides
AS LONG '// Number of brushsides for brush. Texture
AS LONG '// Texture index.
Plane
AS LONG '// Plane index. Texture
AS LONG '// Texture index.
Position
AS BSP_Float3
'// Vertex position. TexCoord_Surface
AS BSP_Float2
'// Vertex texture coordinates. 0=surface, 1=lightmap. TexCoord_Lightmap
AS BSP_Float2
Normal
AS BSP_Float3
'// Vertex normal. Color AS BSP_RGBA
'// Vertex color. RGBA.
Offset
AS LONG '// Vertex index offset, relative to first vertex of corresponding face.
Brush
AS LONG '// Brush that generated this effect. Unknown
AS LONG 'Always 5, except in q3dm8, which has one effect with -1.
Texture
AS LONG '// Texture index. Effect
AS LONG '// Index into lump 12 (Effects), or -1. FaceType
AS LONG '// Face type. 1=polygon, 2=patch, 3=mesh, 4=billboard Vertex
AS LONG '// Index of first vertex. NumVertexes
AS LONG '// Number of vertices. MeshVert
AS LONG '// Index of first meshvert. NumMeshVerts
AS LONG '// Number of meshverts. LMIndex
AS LONG '// Lightmap index. LMStart
AS BSP_Int2
'// Corner of this face's lightmap image in lightmap. LMSize
AS BSP_Int2
'// Size of this face's lightmap image in lightmap. LMOrigin
AS BSP_Float3
'// World space origin of lightmap. LMVecs
AS BSP_LM_Vec
'// World space lightmap s and t unit vectors. Normal
AS BSP_Float3
'// Surface normal. Size
AS BSP_Int2
'// Patch dimensions.
Ambient
AS BSP_Light
'// Ambient color component. RGB. Directional
AS BSP_Light
'// Directional color component. RGB.
NumVecs
AS LONG '// Number of vectors. SizeVecs
AS LONG '// Size of each vector, in bytes. Vecs
AS _MEM 'ubyte[numvecs * sizevecs] vecs '// Visibility data. One bit per cluster per vector.
'///////////////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
'// Master function returns true (-1) if all was ok, or false (0) if failiure.
InFile
= FREEFILE '// Get a free file handle
BytePos& = 1 '// Byte position variable
'// DIM header
GET #InFile
, BytePos&
, Header.Magic
'// Get the id, if not "IBSP" then failiure IF Header.Magic
= "IBSP" THEN '// Valid file BytePos&
= BytePos&
+ LEN(Header.Magic
) '// Byte position increment GET #InFile
, BytePos&
, Header.Version
'// Get the version id IF Header.Version
= 46 THEN '// Valid format (Quake 3 level) BytePos&
= BytePos&
+ LEN(Header.Version
) '// Byte position increment
DIM Entry
(16) AS BSP_DirEntry
GET #InFile
, BytePos&
, Entry
() '// Load all the offsets
Level.HeaderPntr
= _MEMNEW(LEN(Header.Magic
) + LEN(Header.Version
) + (LEN(Entry
(0)) * 17)) '// Allocate memory _MEMPUT Level.HeaderPntr
, Level.HeaderPntr.OFFSET
, Header.Magic
MemOffset&
= LEN(Header.Magic
) _MEMPUT Level.HeaderPntr
, Level.HeaderPntr.OFFSET
+ MemOffset&
, Header.Version
MemOffset&
= MemOffset&
+ LEN(Header.Version
) _MEMPUT Level.HeaderPntr
, Level.HeaderPntr.OFFSET
+ MemOffset&
, Entry
()
'///////////////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
'// We dont care about certain things in the file for now, we just want rendering and clipping data
'// Need to calculate required memory block and then load data
'// Create single defintions of each required type to use in caluation
'// Add up size of all the arrays and create _MEM block
IF i%
> 0 AND i%
<> 14 THEN '// Ignore blocks we dont want to load MemSize = MemSize + Entry(i%).Size '// Add up the size of all the memory blocks
'///////////////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
'// Load all the bits n pieces
BytePos& = Entry(Index&).Start '// Offset of where data starts
CASE 0 '// Entities Game-related object descriptions. - We are not gonna worry about these for now CASE 1 '// Textures Surface descriptions.
DIM Tmp_Texture
AS BSP_Texture
NumTXRecs&
= Entry
(Index&
).Size
/ LEN(Tmp_Texture
) DIM Texture
(NumTXRecs&
- 1) AS BSP_Texture
GET #InFile
, BytePos&
, Texture
() _MEMPUT Level.DataPntr
, Level.DataPntr.OFFSET
+ MemOffset
, Texture
()
FOR i&
= 0 TO NumTXRecs&
- 1 FName$
= BSP_File_Conform
(Texture
(i&
).
Name) NumTx% = NumTx% + 1
NumTx% = NumTx% + 1
' PRINT "File not found!"
'// Load all the texture files???
FOR i&
= 0 TO NumTXRecs&
- 1 FName$
= BSP_File_Conform
(Texture
(i&
).
Name) TxtHnd(FCnt%) = GDK_GL_LOAD_TEXTURE(FName$ + ".jpg")
FCnt% = FCnt% + 1
FCnt% = FCnt% + 1
' PRINT "File not found!"
CASE 2 '// Planes Planes used by map geometry.
DIM TmpPlane
AS BSP_Plane
NumPLRecs&
= Entry
(Index&
).Size
/ LEN(TmpPlane
) DIM Plane
(NumPLRecs&
- 1) AS BSP_Plane
GET #InFile
, BytePos&
, Plane
() _MEMPUT Level.DataPntr
, Level.DataPntr.OFFSET
+ MemOffset
, Plane
()
CASE 3 '// Nodes BSP tree nodes.
NumNodeRecs&
= Entry
(Index&
).Size
/ LEN(TmpNode
) DIM Node
(NumNodeRecs&
- 1) AS BSP_Node
GET #InFile
, BytePos&
, Node
() _MEMPUT Level.DataPntr
, Level.DataPntr.OFFSET
+ MemOffset
, Node
()
CASE 4 '// Leafs BSP tree leaves.
NumLeafRecs&
= Entry
(Index&
).Size
/ LEN(TmpLeaf
) DIM Leaf
(NumLeafRecs&
- 1) AS BSP_Leaf
GET #InFile
, BytePos&
, Leaf
() _MEMPUT Level.DataPntr
, Level.DataPntr.OFFSET
+ MemOffset
, Leaf
()
CASE 5 '// Leaffaces Lists of face indices, one list per leaf.
DIM TmpLF
AS BSP_LeafFace
NumLFRecs&
= Entry
(Index&
).Size
/ LEN(TmpLF
) DIM LeafFace
(NumLFRecs&
- 1) AS BSP_LeafFace
GET #InFile
, BytePos&
, LeafFace
() _MEMPUT Level.DataPntr
, Level.DataPntr.OFFSET
+ MemOffset
, LeafFace
()
CASE 6 '// Leafbrushes Lists of brush indices, one list per leaf.
DIM TmpLB
AS BSP_LeafBrush
NumLBRecs&
= Entry
(Index&
).Size
/ LEN(TmpLB
) DIM LeafBrush
(NumLBRecs&
- 1) AS BSP_LeafBrush
GET #InFile
, BytePos&
, LeafBrush
() _MEMPUT Level.DataPntr
, Level.DataPntr.OFFSET
+ MemOffset
, LeafBrush
()
CASE 7 '// Models Descriptions of rigid world geometry in map.
NumMDLRecs&
= Entry
(Index&
).Size
/ LEN(TmpMDL
) DIM BSPMDL
(NumMDLRecs&
- 1) AS BSP_Model
GET #InFile
, BytePos&
, BSPMDL
() _MEMPUT Level.DataPntr
, Level.DataPntr.OFFSET
+ MemOffset
, BSPMDL
()
CASE 8 '// Brushes Convex polyhedra used to describe solid space.
DIM TmpBrush
AS BSP_Brush
NumBRecs&
= Entry
(Index&
).Size
/ LEN(TmpBrush
) DIM Brush
(NumBRecs&
- 1) AS BSP_Brush
GET #InFile
, BytePos&
, Brush
() _MEMPUT Level.DataPntr
, Level.DataPntr.OFFSET
+ MemOffset
, Brush
()
CASE 9 '// Brushsides Brush surfaces.
DIM TmpBS
AS BSP_BrushSide
NumBSRecs&
= Entry
(Index&
).Size
/ LEN(TmpBS
) DIM BrushSide
(NumBSRecs&
- 1) AS BSP_BrushSide
GET #InFile
, BytePos&
, BrushSide
() _MEMPUT Level.DataPntr
, Level.DataPntr.OFFSET
+ MemOffset
, BrushSide
()
CASE 10 '// Vertexes Vertices used to describe faces.
DIM TmpVert
AS BSP_Vertex
NumVRecs&
= Entry
(Index&
).Size
/ LEN(TmpVert
) DIM Vertex
(NumVRecs&
- 1) AS BSP_Vertex
GET #InFile
, BytePos&
, Vertex
() _MEMPUT Level.DataPntr
, Level.DataPntr.OFFSET
+ MemOffset
, Vertex
()
CASE 11 '// Meshverts Lists of offsets, one list per mesh.
DIM TmpMVert
AS BSP_MeshVert
NumMVRecs&
= Entry
(Index&
).Size
/ LEN(TmpMVert
) DIM MeshVertex
(NumMVRecs&
- 1) AS BSP_MeshVert
GET #InFile
, BytePos&
, MeshVertex
() _MEMPUT Level.DataPntr
, Level.DataPntr.OFFSET
+ MemOffset
, MeshVertex
()
CASE 12 '// Effects List of special map effects.
DIM TmpEffect
AS BSP_Effect
NumEFRecs&
= Entry
(Index&
).Size
/ LEN(TmpEffect
) DIM Effect
(NumEFRecs&
- 1) AS BSP_Effect
GET #InFile
, BytePos&
, Effect
() _MEMPUT Level.DataPntr
, Level.DataPntr.OFFSET
+ MemOffset
, Effect
()
CASE 13 '// Faces Surface geometry.
NumFaceRecs&
= Entry
(Index&
).Size
/ LEN(TmpFace
) DIM Face
(NumFaceRecs&
- 1) AS BSP_Face
GET #InFile
, BytePos&
, Face
() _MEMPUT Level.DataPntr
, Level.DataPntr.OFFSET
+ MemOffset
, Face
()
CASE 14 '// Lightmaps Packed lightmap data.
'// array of (127,127,3) Using RGB
'// Gonna ignore this for now
CASE 15 '// Lightvols Local illumination data.
DIM TmpLVols
AS BSP_LightVol
NumLVRecs&
= Entry
(Index&
).Size
/ LEN(TmpLVols
) DIM LightVol
(NumLVRecs&
- 1) AS BSP_LightVol
GET #InFile
, BytePos&
, LightVol
() _MEMPUT Level.DataPntr
, Level.DataPntr.OFFSET
+ MemOffset
, LightVol
()
CASE 16 '// Visdata Cluster-cluster visibility data.
NumVDRecs&
= Entry
(Index&
).Size
/ LEN(TmpVD
) DIM VD
(NumVDRecs&
- 1) AS BSP_VisData
GET #InFile
, BytePos&
, VD
() _MEMPUT Level.DataPntr
, Level.DataPntr.OFFSET
+ MemOffset
, VD
()
IF Index&
> 0 AND Index&
<> 14 THEN '// Ignore blocks we dont use MemOffset = MemOffset + Entry(Index&).Size '// increase memory offset
BSP_Load = True '// All good!
BSP_Load = False '// bad file or unsupported format
BSP_Load = False '// bad file or unsupported format
'// All done now so close the file
'///////////////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
FUNCTION BSP_File_Conform$
(File$
) '// Changes file names so we can use them
Allowed$ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_\/"
Ltr$
= MID$(File$
, i%
, 1) FName$ = FName$ + "\"
FName$ = FName$ + Ltr$
BSP_File_Conform$ = FName$
'///////////////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
SUB BSP_Draw
(Level
AS Level
)
'///////////////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
IF BSP_Load
(Level
, "maps\q3Dead1.bsp") = True
THEN '// Load the level data, if it returns true then run renderer
InitGl = False
'// It not work!
BSP_Draw Level
'///////////////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
_glClear _GL_COLOR_BUFFER_BIT
OR _GL_DEPTH_BUFFER_BIT
'// Clear screen and depth buffers
'########################################################################################################################
'Texturing
'########################################################################################################################
GET (0, 0)-(Sx%
- 1, Sy%
- 1), LoadTexture_Buffer
(0) clr& = LoadTexture_Buffer(PXCnt&)
LoadTexture_Buffer2
(PXCnt&
) = ((clr& \
65536) + 255) + (clr&
AND &HFF00&
) + ((clr&
AND 255) * 65536) LoadTexture_Buffer2
(PXCnt&
) = ((clr& \
65536) AND 255) + (clr&
AND &HFF00&
) + ((clr&
AND 255) * 65536) PXCnt& = PXCnt& + 1
gluBuild2DMipmaps _GL_TEXTURE_2D, _GL_RGBA, Sx%, Sy%, _GL_RGBA, _GL_UNSIGNED_BYTE, LoadTexture_Buffer2(0)
_glTexParameteri _GL_TEXTURE_2D
, _GL_TEXTURE_MIN_FILTER
, _GL_LINEAR_MIPMAP_LINEAR
GDK_GL_MAKE_TEXTURE = h
'########################################################################################################################
FUNCTION GDK_GL_LOAD_TEXTURE
(FileName$
) GET (0, 0)-(Sx%
- 1, Sy%
- 1), LoadTexture_Buffer
(0) clr& = LoadTexture_Buffer(PXCnt&)
LoadTexture_Buffer2
(PXCnt&
) = ((clr& \
65536) + 255) + (clr&
AND &HFF00&
) + ((clr&
AND 255) * 65536) LoadTexture_Buffer2
(PXCnt&
) = ((clr& \
65536) AND 255) + (clr&
AND &HFF00&
) + ((clr&
AND 255) * 65536) PXCnt& = PXCnt& + 1
gluBuild2DMipmaps _GL_TEXTURE_2D, _GL_RGBA, Sx%, Sy%, _GL_RGBA, _GL_UNSIGNED_BYTE, LoadTexture_Buffer2(0)
_glTexParameteri _GL_TEXTURE_2D
, _GL_TEXTURE_MIN_FILTER
, _GL_LINEAR_MIPMAP_LINEAR
GDK_GL_LOAD_TEXTURE = h
GDK_GL_LOAD_TEXTURE = 0