/*
	Lan Wars.
	Copyright (c) 2009, Darragh Coy.
	All rights reserved.
	Original work(s), source code & author(s) details available at: http://www.darraghcoy.com

	Redistribution and use in source and binary forms, with or without modification, are permitted 
	provided that the following conditions are met:

		* 	Redistributions of source code must retain the above copyright notice, this list of 
			conditions and the following disclaimer.
		* 	Redistributions in binary form must reproduce the above copyright notice, this list of 
			conditions and the following disclaimer in the documentation.
		* 	Neither the name of the author nor the names of contributors may be used to endorse or 
			promote products derived from this software without specific prior written permission.
		* 	The use of any third party libraries, modules or data files provided with the source 
			form of the program must follow and respect the individual licensing terms of these 
			components. You do not have permission to modify or circumvent the licensing terms for 
			provided third party components unless the third party licenses specifically allow this. 
			If you do not agree to the terms of provided third party components then you do not have 
			permission to use them in your derived work(s).
		* 	The terms of this license do not apply to separate (but related) distributions if supplied 
			by the author(s), only to the contents of this source distribution, derived works, and the 
			binaries produced by either modified or unmodified versions of the source code. The terms 
			of this license do not also apply to any third party libraries or components provided with 
			the source distribution. Such third party elements are licensed under their own separate 
			agreements.

	THIS SOFTWARE IS PROVIDED BY DARRAGH COY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
	BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
	ARE DISCLAIMED. IN NO EVENT SHALL DARRAGH COY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
	OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
	IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef GAME_DOOM_LEVEL_H
#define GAME_DOOM_LEVEL_H

//=====================================================================================================================
//=====================================================================================================================

#include "Graphics/PixelShader.h"
#include "Graphics/VertexShader.h"
#include "Graphics/ShaderUniform.h"
#include "Graphics/Texture.h"
#include "Graphics/VertexFormat.h"
#include "Doom/DoomLinedef.h"
#include "Doom/DoomSidedef.h"
#include "Doom/DoomVertex.h"
#include "Doom/DoomThing.h"
#include "Doom/DoomSector.h"
#include "Doom/DoomTriangle.h"
#include "Doom/DoomGLVertexV2.h"
#include "Doom/DoomGLNodeV2.h"
#include "Doom/DoomGLSegV2.h"
#include "Doom/DoomGLSubsectorV2.h"
#include "Doom/DoomPPNode.h"
#include "Doom/DoomPPSeg.h"
#include "Doom/DoomCollision.h"

//=====================================================================================================================
//=====================================================================================================================

namespace Game
{
	//=================================================================================================================
	//=================================================================================================================
	
	class DiskFile;
	class Camera3D;
	class DoomCollision;
	
	//=================================================================================================================
	/// @brief		Represents a doom level, loaded from a WAD file. This class only loads the first level in a wad
	///				file, it does not load further levels. This loader is also only able to process WADS that have been
	///				processed with the glBSP tool or similar tools that produce BSP information in a triangle friendly
	///				GL-NODEs format. Such tools are used with all modern Doom source ports. The version of GL-NODES
	///				supported is VERSION 2 only. Other versions are not supported. 
	//=================================================================================================================

	class DoomLevel
	{
		public:

			//=========================================================================================================
			// Functions
			//=========================================================================================================
			
				/// Creates the doom level from the given WAD file
				
				DoomLevel( const char * wad_file );
				
				/// Destructor. Free's all resources.
				
				~DoomLevel();
				
				/// Draws the level:
				
				void Draw( Camera3D * camera );
				
				//=====================================================================================================================
				/// @brief		Returns the collision helper for the level.
				/// @returns	The level collision helper.
				//=====================================================================================================================
				
				inline const DoomCollision & GetCollision() const { return * m_collision; }
				
				//=====================================================================================================================
				/// @brief		Returns the root node in the bsp tree
				/// @returns	The root bsp tree node
				/// @pre		There must be nodes in the tree
				//=====================================================================================================================
				
				inline const DoomPPNode & GetRootNode() const
				{ 
					// Make sure ok
					
					ENSURE( m_gl_node_count >= 1 , "There must be nodes in the tree" )
					
					// Return it:
					
					return m_pp_nodes[ m_gl_node_count - 1 ];
				}
				
				//=====================================================================================================================
				/// @brief		Returns if there are any nodes in the level's BSP tree.
				/// @returns	True if there are BSP tree nodes
				/// @pre		There must be nodes in the tree
				//=====================================================================================================================
				
				inline bool HasRootNode() const { return m_gl_node_count > 0; }
				
				//=====================================================================================================================
				/// @brief		Tells if the seg is a mini-seg that was created by BSP splits and not linedefs. Minisegs do not have
				///				any renderable walls and are never collideable.
				/// @returns	True if the given seg is a miniseg
				//=====================================================================================================================
				
				static inline bool IsMiniseg( DoomPPSeg & seg ){ return seg.m_linedef == 0; }	
				
				//=====================================================================================================================
				/// @brief		Returns the number of segs in the level
				/// @returns	The number of segs in the level
				//=====================================================================================================================
				
				inline unsigned GetSegCount() const { return m_gl_seg_count; }
				
				//=====================================================================================================================
				/// @brief		Returns the requested line seg
				/// @param		i - index of the object being requested
				/// @returns	The requested seg
				/// @pre		The requested seg must be in range
				//=====================================================================================================================
				
				inline const DoomPPSeg & GetSeg( unsigned i ) const
				{ 
					ENSURE( i < m_gl_seg_count , "The requested seg must be in range" ); return m_pp_segs[i]; 
				}
				
				//=====================================================================================================================
				/// @brief		Returns the number of linedefs in the level
				/// @returns	The number of linedefs in the level
				//=====================================================================================================================
				
				inline unsigned GetLinedefCount() const { return m_linedef_count; }
				
				//=====================================================================================================================
				/// @brief		Returns the requested linedef
				/// @param		i - index of the object being requested
				/// @returns	The requested linedef
				/// @pre		The requested linedef must be in range
				//=====================================================================================================================
				
				inline const DoomLinedef & GetLinedef( unsigned i ) const
				{ 
					ENSURE( i < m_linedef_count , "The requested linedef must be in range" ); return m_linedefs[i]; 
				}				
				
				//=====================================================================================================================
				/// @brief		Returns the number of sidedefs in the level
				/// @returns	The number of sidedefs in the level
				//=====================================================================================================================
				
				inline unsigned GetSidedefCount() const { return m_sidedef_count; }				
				
				//=====================================================================================================================
				/// @brief		Returns the requested sidedef
				/// @param		i - index of the object being requested
				/// @returns	The requested sidedef
				/// @pre		The requested sidedef must be in range
				//=====================================================================================================================
				
				inline const DoomSidedef & GetSidedef( unsigned i ) const
				{ 
					ENSURE( i < m_sidedef_count , "The requested sidedef must be in range" ); return m_sidedefs[i]; 
				}
				
				//=====================================================================================================================
				/// @brief		Returns the number of vertices in the level
				/// @returns	The number of vertices in the level
				//=====================================================================================================================
				
				inline unsigned GetVertexCount() const { return m_gl_vertex_count + m_vertex_count; }
				
				//=====================================================================================================================
				/// @brief		Returns the requested vertex
				/// @returns	The requested vertex
				/// @pre		The requested vertex must be in range
				/// @returns	The 2D coords of the vertex are returned
				//=====================================================================================================================
				
				inline const Vec2f GetVertex( unsigned i ) const
				{ 
					ENSURE( i < GetVertexCount() , "The requested vertex must be in range" );
					
					// See if it is in the gl_vertices array or the normal doom vertices array:
					
					if ( i < m_vertex_count )
					{
						// Return the vertex:
						
						return Vec2f( m_vertices[i].m_x , m_vertices[i].m_z );
					} 
					else
					{
						// In the gl vertices array: get the index in this array
						
						i -= m_vertex_count;
						
						// Get the fp x and z positions:
						
						int fp_x = m_gl_vertices[i].m_x;
						int fp_z = m_gl_vertices[i].m_z;
						
						// See which ones are negative:
						
						bool fp_x_neg = fp_x < 0;
						bool fp_z_neg = fp_z < 0;
						
						if ( fp_x_neg ) fp_x = -fp_x;
						if ( fp_z_neg ) fp_z = -fp_z;
						
						// Get the whole part and save:
						
						Vec2f v = Vec2f
						(
							float(fp_x >> 16),
							float(fp_z >> 16)
						);
						
						// Negate where necessary:
						
						if ( fp_x_neg ) v.x *= -1;
						if ( fp_z_neg ) v.y *= -1;
						
						// Return the vertex
						
						return v;
					}
				}
				
				//=====================================================================================================================
				/// @brief		Returns the number of sectors in the level
				/// @returns	The number of vertices in the level
				//=====================================================================================================================
				
				inline unsigned GetSectorCount() const { return m_sector_count; }
				
				//=====================================================================================================================
				/// @brief		Returns the requested sector
				/// @param		i - index of the object being requested
				/// @returns	The requested sector
				/// @pre		The requested sector must be in range
				//=====================================================================================================================
				
				inline const DoomSector & GetSector( unsigned i ) const
				{ 
					ENSURE( i < m_sector_count , "The requested sector must be in range" ); return m_sectors[i]; 
				}				

				//=====================================================================================================================
				/// @brief		Returns the number of subsectors in the level
				/// @returns	The number of subsectors in the level
				//=====================================================================================================================
				
				inline unsigned GetSubsectorCount() const { return m_gl_subsector_count; }
				
				//=====================================================================================================================
				/// @brief		Returns the requested subsector
				/// @param		i - index of the object being requested
				/// @returns	The requested subsector
				/// @pre		The requested subsector must be in range
				//=====================================================================================================================
				
				inline const DoomGLSubsectorV2 & GetSubsector( unsigned i )
				{ 
					ENSURE( i < m_gl_subsector_count , "The requested subsector must be in range" ); return m_gl_subsectors[i]; 
				}					

				//=====================================================================================================================
				/// @brief		Returns the number of things in the level
				/// @returns	The number of things in the level
				//=====================================================================================================================
				
				inline unsigned GetThingCount() const { return m_thing_count; }
				
				//=====================================================================================================================
				/// @brief		Returns the requested thing
				/// @param		i - index of the object being requested
				/// @returns	The requested thing
				/// @pre		The requested thing must be in range
				//=====================================================================================================================
				
				inline const DoomThing & GetThing( unsigned i ) const
				{ 
					ENSURE( i < m_thing_count , "The requested thing must be in range" ); return m_things[i]; 
				}

				//=====================================================================================================================
				/// @brief		Returns the reject map for the level
				/// @returns	The reject map for the level, which is a bit table telling which sectors are visible from the current 
				///				sector.
				//=====================================================================================================================
				
				inline const unsigned char * GetRejectMap() const { return m_reject_map; }
				
				//=====================================================================================================================
				/// @brief		Returns the size of the reject map in bytes
				/// @returns	Size of the reject map in bytes
				//=====================================================================================================================
				
				inline unsigned GetRejectMapSize() const { return m_reject_map_size; }

				//=====================================================================================================================
				/// @brief		Returns the current subsector a given 2D point (representing X and Z coords) is in.
				/// @param		p - point to check
				/// @returns	The subsector the point is in or null if it is outside the map bounds
				//=====================================================================================================================

				const DoomGLSubsectorV2 * GetSubsector( const Vec2f & p ) const;

				//=====================================================================================================================
				/// @brief		Returns the current subsector a given 3D point is in.
				/// @param		p - point to check
				/// @returns	The subsector the point is in or null if it is outside the map bounds
				//=====================================================================================================================

				inline const DoomGLSubsectorV2 * GetSubsector( const Vec3f & p ) const { return GetSubsector( Vec2f(p.x,p.z) ); }
				
				//=====================================================================================================================
				/// @brief		Returns the requested subsector.
				/// @param		i - index of the subsector to return
				/// @pre		The given index must be in range
				//=====================================================================================================================
				
				inline const DoomGLSubsectorV2 & GetSubsector( unsigned i ) const 
				{
					ENSURE( i < m_gl_subsector_count , "The given index must be in range" ); return m_gl_subsectors[i]; 
				}
				
				//=====================================================================================================================
				/// @param		Tells if the given segment is a so called 'Miniseg'. Minisegs are segments that are not created from
				///				linedefs, rather through BSP splits during the tree generation process. Minisegs have no parent
				///				Linedefs and are never rendered (they have no lower or upper walss). They only exist for the purposes
				///				of rendering, so we can triangulate the level via fully formed convex subsectors.
				/// @param		seg - seg to tell if it is a miniseg
				/// @returns	True if the given segment is a miniseg
				//=====================================================================================================================
				
				inline bool IsMiniseg( const DoomPPSeg & seg ) const 
				{
					// If the parent lindef is null then it is a miniseg:
					
					if ( seg.m_linedef == 0 ) return false; else return true;
				}
				
				//=====================================================================================================================
				/// @brief		Returns the lower texture for a given sidedef.
				/// @param		sidedef - the sidedef to get the texture for
				/// @returns	The name of the lower sidedef texture
				//=====================================================================================================================
				
				inline const std::string GetLowerTexture( const DoomSidedef & sidedef ) const
				{
					// Save it here:
					
					char buffer[12]; memset(buffer,0,12); memcpy(buffer,sidedef.m_tex_l_name,8);
					
					// Convert to string:
					
					return std::string(buffer);
				}
				
				//=====================================================================================================================
				/// @brief		Returns the upper texture for a given sidedef.
				/// @param		sidedef - the sidedef to get the texture for
				/// @returns	The name of the upper sidedef texture
				//=====================================================================================================================
				
				inline const std::string GetUpperTexture( const DoomSidedef & sidedef ) const
				{
					// Save it here:
					
					char buffer[12]; memset(buffer,0,12); memcpy(buffer,sidedef.m_tex_u_name,8);
					
					// Convert to string:
					
					return std::string(buffer);
				}				
				
				//=====================================================================================================================
				/// @brief		Returns the middle texture for a given sidedef.
				/// @param		sidedef - the sidedef to get the texture for
				/// @returns	The name of the middle sidedef texture
				//=====================================================================================================================
				
				inline const std::string GetMiddleTexture( const DoomSidedef & sidedef ) const
				{
					// Save it here:
					
					char buffer[12]; memset(buffer,0,12); memcpy(buffer,sidedef.m_tex_m_name,8);
					
					// Convert to string:
					
					return std::string(buffer);
				}
				
				//=====================================================================================================================
				/// @brief		Returns the parent sector for a given subsector
				/// @param		subsector - subsector to get the parent sector for
				/// @returns	The sector the segment belongs to, or null on failure if the subsector could not be determined
				/// @pre		The subsector given must belong to the level. I.E it must be resident in level memory.
				//=====================================================================================================================
				
				inline const DoomSector & GetSector( const DoomGLSubsectorV2 & subsector ) const
				{
					// Get the location of this in the subsector array:

					unsigned index = ( unsigned(&subsector) - unsigned(m_gl_subsectors) ) / sizeof(DoomGLSubsectorV2);

					// Make sure ok:

					ENSURE( index < m_gl_subsector_count , "The subsector must be part of the level structure" )				
				
					// Return it:
					
					return * m_subsector_sectors[index];
				}
				
				//=====================================================================================================
				/// @brief		Get the texture name for the floor of the sector:
				/// @param		sector - sector to get the floor texture name for.
				/// @returns	The name of the floor texture in string format
				//=====================================================================================================
				
				inline std::string GetFloorTexture( const DoomSector & sector ) const
				{
					// Save it here:
					
					char buffer[12]; memset(buffer,0,12); memcpy(buffer,sector.m_tex_floor,8);
					
					// Convert to string:
					
					return std::string(buffer);
				}
				
				//=====================================================================================================
				/// @brief		Get the texture name for the ceiling of the sector:
				/// @param		sector - sector to get the floor texture name for.
				/// @returns	The name of the floor texture in string format
				//=====================================================================================================				
				
				std::string GetCeilingTexture( const DoomSector & sector ) const 
				{
					// Save it here:
					
					char buffer[12]; memset(buffer,0,12); memcpy(buffer,sector.m_tex_ceiling,8);
					
					// Convert to string:
					
					return std::string(buffer);
				}

				//=====================================================================================================
				/// @brief		Gets which sector number the given sector is in the level.
				/// @param		sector - sector to check what it's sector number is.
				/// @returns	Which number this particular sector is
				/// @pre		The given sector must be part of the level
				//=====================================================================================================

				unsigned GetSectorNumber( const DoomSector & sector ) const
				{
					// Calculate the sector number from the memory address:

					unsigned sector_num = ( ((unsigned)(&sector)) - ((unsigned)(m_sectors)) ) / sizeof(DoomSector);

					// Make sure ok:

					ENSURE( sector_num < m_sector_count , "The given sector must be part of the level" )

					// Return the sector number

					return sector_num;
				}
				
				//=====================================================================================================
				/// @brief		Gets which subsector number the given subsector is in the level.
				/// @param		subsector - subsector to check what it's subsector number is.
				/// @returns	Which number this particular subsector is
				/// @pre		The given subsector must be part of the level
				//=====================================================================================================

				unsigned GetSubsectorNumber( const DoomGLSubsectorV2 & subsector ) const
				{
					// Calculate the subsector number from the memory address:

					unsigned subsector_num = ( ((unsigned)(&subsector)) - ((unsigned)(m_gl_subsectors)) ) / sizeof(DoomGLSubsectorV2);

					// Make sure ok:

					ENSURE( subsector_num < m_gl_subsector_count , "The given subsector must be part of the level" )

					// Return the subsector number

					return subsector_num;
				}
				
		private:
		
			//=========================================================================================================				
			// Structs
			//=========================================================================================================
			
				//=====================================================================================================
				/// @brief		This is the header for the wad file
				//=====================================================================================================
				
				volatile struct WadHeader
				{
					/// Id of the wad file. Either PWAD or IWAD in ASCII.
					
					char m_id[4];
					
					/// Contains the number of lumps in the wad file
					
					unsigned m_lump_count;
					
					/// Offset of the directory table, which contains descriptions for all the lumps in the WAD
					
					unsigned m_directory_offset;
				};
				
				//=====================================================================================================
				/// @brief		Holds information about a lump in the directory table. The level data in WAD files is
				///				organised into a series of lumps catogorised by the type of data in that lump
				//=====================================================================================================
				
				volatile struct WadLump
				{
					/// Offset of the lump in the wad file
					
					unsigned m_offset;
					
					/// Size of the lump in bytes
					
					unsigned m_size;
					
					/// Name of the lump
					
					char m_name[8];
				};		
				
				//=====================================================================================================
				/// @brief		This is the structure that a vertex in the map takes in the vertex array.
				//=====================================================================================================
				
				volatile struct RenderVertex
				{
					/// The position of the vertex
					
					Vec3f m_pos;
					
					/// The texture coordinate of the vertex
					
					Vec2f m_tex;
					
					/// The color of the vertex
					
					Color m_col;
					
					/// The normal of the vertex
					
					Vec3f m_nor;
				};
				
				//=====================================================================================================
				/// @brief		This represents a list of triangles that will be rendered in one go whilst the 
				///				level is being drawn.
				//=====================================================================================================
				
				volatile struct TriangleList
				{
					/// This is the number of triangles in the vertex array
					
					unsigned m_num_triangles;
					
					/// This is the vertex array for the triangles:
					
					RenderVertex * m_vertices;
					
					/// This is the texture used to render
					
					Texture * m_texture;
				};				
				
			//=========================================================================================================
			// Functions
			//=========================================================================================================
			
				/// Reads the headers for each lump in the WAD
				
				void ReadLumpHeaders( DiskFile & file );
			
				/// Reads all of the different lumps in the WAD
				
				void ReadAllLumps( DiskFile & file );
				
				/// Returns the offset of the given lump name in the file
				
				unsigned GetLumpOffset( const char * name );
				
				/// Returns the size of the given lump name in the file
				
				unsigned GetLumpSize( const char * name );				
				
				/// Loads all graphics resources such as pixel shaders to render the level
				
				void LoadGraphicsResources();
				
				/// Builds the level geometry for level rendering and sorts all triangles by texture number
				 
				void BuildRenderGeometry( std::map< std::string , std::list<DoomTriangle> > & output );
				
				/// Preps the level geometry for level rendering, putting all the triangles into m_triangle_lists field
				
				void PrepareRenderGeometry( std::map< std::string , std::list<DoomTriangle> > & input );
				
				/// Triangulates the floors and ceilings for a given subsegment 
				
				void TriangulateFlats( const DoomGLSubsectorV2 & subsector , std::map< std::string , std::list<DoomTriangle> > & output );
				
				/// Triangulates either upper or lower walls as necessary for the given two sided-seg
				
				void TriangulateTwoSidedWalls
				( 
					const DoomPPSeg & seg , const DoomSector & sector, std::map< std::string , std::list<DoomTriangle> > & output 
				);
						
			//=========================================================================================================
			// Variables:
			//=========================================================================================================
			
				/// This is the header for the wad file:
				
				WadHeader m_header;
				
				//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
				/// This is a map from lump names to lump descriptions. Since lumps of the same name might exist, the 
				/// lumps are stored in list format. The names are case sensitive and should be given in uppercase format
				/// when searching for lumps.					
				//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
				
				std::map<std::string,WadLump> m_lumps;
				
				/// This array holds the things (or entities) for the level:
				
				DoomThing * m_things;
				
				/// This holds the number of things in the level:
				
				unsigned m_thing_count;
				
				/// This array holds all of the sectors for the level
				
				DoomSector * m_sectors;
				
				/// This holds the number of sectors in the level:
				
				unsigned m_sector_count;
				
				/// This holds all of the vertices for the level:
				
				DoomVertex * m_vertices;
				
				/// This is the number of vertices in the level
				
				unsigned m_vertex_count;
				
				/// This holds all of the linedefs for the level:
				
				DoomLinedef * m_linedefs;
				
				/// This is the number of linedefs in the level:
				
				unsigned m_linedef_count;				
				
				/// This holds all of the sidedefs for the level:
				
				DoomSidedef * m_sidedefs;
				
				/// This is the number of sidedefs in the level:
				
				unsigned m_sidedef_count;			
				
				/// This holds all of the gl vertices for the level:
				
				DoomGLVertexV2 * m_gl_vertices;
				
				/// This is the number of gl vertices in the level:
				
				unsigned m_gl_vertex_count;
				
				/// This holds all of the gl segs for the level:
				
				DoomGLSegV2 * m_gl_segs;
				
				/// This is the number of gl segs:
				
				unsigned m_gl_seg_count;

				/// This structure holds which segs belong to which subsectors.

				DoomGLSubsectorV2 ** m_seg_subsectors;

				/// This structure holds which segs belong to which sectors.

				DoomSector ** m_seg_sectors;
				
				/// This holds all of the gl nodes for the level:
				
				DoomGLNodeV2 * m_gl_nodes;
				
				/// This is the number of gl nodes:
				
				unsigned m_gl_node_count;
				
				/// This holds all of the gl subsectors for the level:
				
				DoomGLSubsectorV2 * m_gl_subsectors;
				
				/// This is the number of gl subsectors
				
				unsigned m_gl_subsector_count;
				
				/// This holds an index of the parent sector for each subsector
				
				DoomSector ** m_subsector_sectors;
				
				//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
				/// This is the reject map for determining which sectors are visible from other ones. This is a bit
				/// table which is square in dimensions and maps from one sector to another.
				//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
				
				unsigned char * m_reject_map;
				
				/// This is the size of the reject map in bytes
				
				unsigned m_reject_map_size;
				
				/// This is an array of preprocessed BSP tree nodes that have extra information added to them for our use
				
				DoomPPNode * m_pp_nodes;
				
				/// This is an array of preprocessed segs with extra information for our own use
				
				DoomPPSeg * m_pp_segs;
				
				/// These are the lists of triangles to be drawn to render the level
				
				std::vector<TriangleList> m_triangle_lists;
				
				/// Helper object for doing raycasts with the level
				
				DoomCollision * m_collision;
				
				/// This is our vertex format
				
				VertexFormat m_vf;
				
				/// This is the pixel shader we use to render
				
				VertexShader m_vs;
				
				/// This is the vertex shader we use to render
				
				PixelShader m_ps;
				
				/// This is the transform uniform on the vertex format
				
				ShaderUniform m_u_transform;
				
				/// This is the camera position in the pixel shader
				
				ShaderUniform m_u_camera_position;
				
				/// Fog distance for rendering
				
				ShaderUniform m_u_fog_distance;

				/// Fog color for rendering
				
				ShaderUniform m_u_fog_color;
				
				/// This is true if all our rendering resources are valid (except possibly textures in the level)
				
				bool m_valid_resources;
	};
};

#endif
